This is FtpSubThread.m in view mode; [Download] [Up]
//#define TERM #ifdef TERM #import "termnet.h" #endif // TERM #import "FtpConnection.h" #import "FtpSubThread.h" #import "FtpDirectory.h" #import "NXmystd.h" #import <remote/NXProxy.h> #import <netdb.h> #import <stdarg.h> #import <ctype.h> #import <sys/timeb.h> #define DEFAULTPORT 7358 #define MAXPORT 8000 NXLock *chdirLock = nil; void ftime(struct timeb *tp); // This is defined nowhere in the headers ! int my_chdir(const char *path) { if (!chdirLock) chdirLock = [[NXLock alloc] init]; [chdirLock lock]; return chdir (path); } void my_unchdir() { chdir("/"); [chdirLock unlock]; } FILE *my_fopen(const char *path,const char *name,const char *mode) { FILE *fp; my_chdir (path); fp = fopen(name,mode); my_unchdir(); return fp; } @implementation FtpSubThread - (void oneway) setFtpConnection:obj; { //malloc_debug(7); conn = obj; [[conn connectionForProxy] registerForInvalidationNotification:self]; // init recvpos = 0; recvfullpos = 0; } - senderIsInvalid:sender; { //LOGF("%p",sender); return self; } - (void oneway) connectToHost:(const char *)name; { struct sockaddr_in addr; struct hostent *ent; char buf[1000]; int len; [conn show:"creating socket"]; [self closeConnection]; sock = socket(PF_INET,SOCK_STREAM,0); if(sock < 0) { [conn connectFailed:"couldnt create socket"]; return; } memset((char *)&addr, 0, sizeof(struct sockaddr)); addr . sin_family = AF_INET; addr . sin_port = htons(21); ent = gethostbyname((char *)name); if (ent == NULL) { if( (addr . sin_addr.s_addr = inet_addr((char *)name)) == -1) { [conn connectFailed:"no such host !"]; return; } } else // ToDo: should try EVERY address !! { //printf(ent -> h_name); memcpy( (void *)&(addr . sin_addr), ent -> h_addr, ent -> h_length); } sprintf(buf,"trying %s...", inet_ntoa(addr.sin_addr)); [conn show:buf]; if( (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)) { [conn connectFailed:"connect failed !!!"]; perror("connectToHost: connect"); return; } len = sizeof (dataaddr); if (getsockname(sock, (struct sockaddr *)&dataaddr, &len) < 0) { [conn connectFailed:"getsockname failed !!!"]; perror("connectToHost: getsockname"); return; } //printf("sock = %d,ent = %p,\n",sock,ent); if ([self getResult] == 220) [conn connected]; else [conn connectFailed:"remote host refused connection"]; } - (void oneway) closeConnection; { if (sock) { //[self putCommand:"QUIT"]; close(sock); sock = -1; } } - free; { [self closeConnection]; return [super free]; } - (void oneway) loginAsUser:(const char *)user withPassword:(const char *)pass; { int res; [self putCommand:"USER":user]; if ([self getResult] != 331) { sprintf(line,"user %s: access denied",user); [conn loginFailed:line]; return; } [self putCommand:"PASS":pass]; if ([self getResult] != 230) { sprintf(line,"wrong password for user: %s",user); [conn loginFailed:line]; return; } [self putCommand:"TYPE" :"A"]; res = [self getResult]; if (res != 200) { [conn connectionLost:"TYPE failed"]; return; } #ifdef DEBUG [self putCommand:"SITE IDLE 30"]; res = [self getResult]; if (res != 200) { [conn connectionLost:"SITE IDLE failed"]; return; } #endif transfermode = ASCII_MODE; currentdir = NXUniqueString("nosuchdir"); [conn loggedIn]; } - (void oneway) listDir:dir; { NXAtom path = [dir path]; int res; int connectsock,datasock; char *s; //LOGF("path = %s",path); if (transfermode != ASCII_MODE) { [self putCommand:"TYPE" :"A"]; res = [self getResult]; if (res != 200) { [conn connectionLost:"TYPE failed"]; return; } transfermode = ASCII_MODE; } if (currentdir != path) { [self putCommand:"CWD" :path]; res = [self getResult]; if (res != 250 && res != 200) { [conn transferError:dir:"CWD failed"]; return; } currentdir = path; } //if (![dir shouldTransferAlways] //&& ![dir needsUpdate] ) if (0) { char *s1,*s2; //LOGF("STATting %s\n",[dir path]); [conn checkingDir:dir]; [self putCommand:"STAT" :"-dLl"]; res = [self getResult]; if (res != 211) // 502 STAT not implemented { [dir setShouldTransferAlways]; goto transfer; // break out of the if //[conn transferError:dir:"STAT failed"]; //return; } s1 = strchr(line,'\n'); s2 = strrchr(line,'\n'); if (s2) { *s2 = '\0'; s2 = strrchr(line,'\n'); } if (s2) { *s2 = '\0'; s2 = strrchr(line,' '); } if (s1 && s2) { *s2 = '\0'; s1++; if (![dir compareStatusString:s1]) // it changed { if ([dir shouldTransferIfNeeded]) [dir setShouldTransferAlways]; [dir setStatusString:s1]; //LOGF("set statusline to:|%s|",s1); } } else { ERRORF("illegal stat:|%s|",line); if ([dir shouldTransferIfNeeded]) [dir setShouldTransferAlways]; } } transfer: // oink oink if ([dir shouldTransferIfNeeded]) [dir setShouldTransferAlways]; //LOGF("listingdir"); //LOGF("line = <%s>",line); if ([dir shouldTransferAlways] || [dir needsUpdate]) { //LOGF("RETRieving %s\n",[dir path]); [conn listingDir:dir]; //LOGF("line = |%s|",line); connectsock = [self createPort]; if (connectsock < 0) { [conn socketError:"couldn't create socket"]; [self closeConnection]; return; } //printf("createt socker:%d\n", connectsock); [self putCommand:"NLST":"-lL"]; res = [self getResult]; if (res != 150) { close (connectsock); connectsock = -1; [conn transferError:dir:"NLST failed"]; return; } datasock = [self acceptPort:connectsock]; close(connectsock); connectsock = -1; if (datasock < 0) { [conn socketError:"couldn't create socket"]; [self closeConnection]; return; } //printf("accepted socker:%d\n", datasock); [dir beginUpdate]; // all this is definitely stupid, but it seems to work, somehow... while((s=[self getLineFrom:datasock]) != NULL) { int len = strlen(s)-1; // withut newline int i; id theNewFile; char statline[1000]; enum {FTP_DIR,FTP_FILE,FTP_LINK,FTP_OTHER} filetype; long size; // I cant use flex for this, cause it isnt multithreaded and // reentrant, BLAECH s[len] = '\0'; // remove the newline //LOGF("s=|%s|",s); //LOGF("len = %d",len); if (len < 35) continue; strcpy(statline,s); // save for later compareStatusString; i = 0; if (s[0] == 'd') filetype = FTP_DIR; else if (s[0] == 'l') filetype = FTP_LINK; else if (s[0] == '-') filetype = FTP_FILE; else filetype = FTP_OTHER; i = 10; while(!isdigit(s[i])) i++; // linkcount while(isdigit(s[i])) i++; while(isspace(s[i])) i++; // UID while(!isspace(s[i])) i++; while(isspace(s[i])) i++; // Now comes the tricky part... // the next one is either the group, or the filesize // but we cant tell yet size = atol(s+i); // Just save it for later reference... while(!isspace(s[i])) i++; while(isspace(s[i])) i++; // Now we are either on the filesize, or already on the month // and now we can tell :) if (isdigit(s[i])) { // Its the size size = atol(s+i); // and skip it while(!isspace(s[i])) i++; while(isspace(s[i])) i++; } // Month while(!isspace(s[i])) i++; while(isspace(s[i])) i++; // day while(!isspace(s[i])) i++; while(isspace(s[i])) i++; // time or year while(!isspace(s[i])) i++; while(isspace(s[i])) i++; // filename !! //LOGF("size = %d",size); if (filetype == FTP_LINK) // hackhack... { char *tmp = strstr(s+i," -> "); if (tmp) *tmp = '\0'; filetype = FTP_DIR; } //LOGF("update:|%s|\n",s); theNewFile = [dir update:s+i withSize:size isFile:filetype == FTP_FILE]; //LOGF("theNewFile = %p,isDir = %s",theNewFile,[theNewFile isDir]?"DIR":"FILE"); if (theNewFile) { char *s = strrchr(statline,' '); if (s) *s = '\0'; if ([theNewFile isDir] && ![theNewFile compareStatusString:statline]) { //puts("mist"); [theNewFile setNeedsUpdate]; [theNewFile setStatusString:statline]; LOGF("dir setStatusString:|%s|",statline); } else if ([theNewFile isDir]) { [theNewFile setNeedsNoUpdate]; } } else { ERRORF("theNewFile == NULL"); } //LOGF("elihw"); #if 0 // This is the old routine len--; if (s[len] == '@') { s[len--] = '\0'; } if (s[len] == '/') // NO else !! { isFile = NO; s[len--] = '\0'; } else if (s[len] == '*') // else !! { s[len--] = '\0'; } #endif } close(datasock); datasock=-1; [dir endUpdate]; if ([self getResult] != 226) { [conn transferError:dir:"directory listing failed"]; return; } } else [dir endUpdate]; //LOGF("dirlisted"); [conn dirListed:dir]; } - (void oneway) getFile:file; { NXAtom path; int res,len; long siz; int connectsock,datasock; unsigned char buf[16384]; FILE *localfp=NULL; BOOL aborted = NO; long nowtime; struct timeb tp; lastshouldstoptime = 0; //printf("subthread: localPath = %s\n",[file localPath]); //LOGF("getfilename = |%s|,localName = %s",[file name],[file localName]); //LOGF("unique getfilename = |%s|",NXUniqueString([file name])); path = [[file parentDir] path]; siz = 0; if ([file shouldReget]) { //LOGF("regetting file=%s",[file name]); localfp = my_fopen([file localPath],[file localName],"r"); if (localfp == NULL) { sprintf(buf,"couldnt find %s/%s, creating",[file localPath],[file localName]); [conn show:buf]; } else { fseek(localfp,0,SEEK_END); siz = ftell(localfp); fclose(localfp); localfp = my_fopen([file localPath],[file localName],"a"); if (localfp == NULL) { sprintf(buf,"couldnt create %s/%s",[file localPath],[file localName]); [conn transferError:file:buf]; return; } } } if (!localfp) { //LOGF("replacing file=%s",[file name]); localfp = my_fopen([file localPath],[file localName],"w"); if (localfp == NULL) { sprintf(buf,"couldnt create %s/%s",[file localPath],[file localName]); [conn transferError:file:buf]; return; } } //LOGF("siz = %d",siz); if (transfermode != BINARY_MODE) { [self putCommand:"TYPE" :"I"]; res = [self getResult]; if (res != 200) { [conn connectionLost:"TYPE failed"]; goto getfile_error; } transfermode = BINARY_MODE; } if (currentdir != path) { [self putCommand:"CWD" :path]; res = [self getResult]; if (res != 250 && res != 200) { [conn transferError:file:"CWD failed"]; goto getfile_error; } currentdir = path; } [self putCommand:"SIZE" :[file name]]; res = [self getResult]; if (res != 213) // 500 SIZE not implemented { //[file setFileSize:-1]; //[conn transferError:file:"SIZE failed"]; //goto getfile_error; } else { if (strlen(line) >=4) { long newsize = atol(line+4); if (newsize != [file fileSize]) { [file setFileSize:newsize]; [[file parentDir] setNeedsUpdate]; } } //else // [file setFileSize:-1]; } [conn retrievingFile:file]; connectsock = [self createPort]; if (connectsock < 0) { [conn socketError:"couldn't create socket"]; goto getfile_error; } //printf("createt socker:%d\n", connectsock); if (siz) { sprintf(buf,"%ld",siz); [self putCommand:"REST":buf]; res = [self getResult]; if (res != 350) { close (connectsock); connectsock = -1; [conn transferError:file:"RESTart failed"]; goto getfile_error; } } [self putCommand:"RETR":[file name]]; res = [self getResult]; if (res != 150) { close (connectsock); connectsock = -1; [conn transferError:file:"RETRieve failed"]; goto getfile_error; } datasock = [self acceptPort:connectsock]; close(connectsock); connectsock = -1; if (datasock < 0) { [conn socketError:"accept socket failed"]; goto getfile_error; } //printf("accepted socker:%d\n", datasock); //printf("sizeof buf:%ld\n",sizeof(buf)); [file setShouldReget:YES]; [conn shouldStopAtPosition:siz]; // just to set the progress views while(TRUE) { LOGF("datasock = %d",datasock); len = recv(datasock,buf,sizeof(buf),0); LOGF("len = %d",len); if (len == -1) { perror("getFile: recv failed"); close(datasock); datasock = -1; [conn connectionLost:"recv from socket failed!!!!"]; fclose(localfp); [file setShouldReget:YES]; return; } if (len == 0) { //puts("len = 0: file transfer finished"); break; } res = fwrite(buf,sizeof(unsigned char),len,localfp); //printf("len:%d,res:%d\n",len,res); if (res != len) { [conn transferError:file:"write to local file failed"]; close(datasock); datasock = -1; fclose(localfp); return; } siz+=len; //printf("siz = %d,len = %ld\n",siz,len); //[conn shouldStopAtPosition:siz]; ftime(&tp); nowtime = tp.time*1000 + tp.millitm; if (nowtime > lastshouldstoptime + 100) { [[conn connectionForProxy] setInTimeout:500]; [[conn connectionForProxy] setOutTimeout:0]; NX_DURING if ([conn shouldStopAtPosition:siz] && !aborted) { [conn show:"aborting..."]; sprintf(buf,"%c%c%c%c",(u_char)0xff,(u_char)0xf4,(u_char)0xff,(u_char)0xf2); send(sock,"\0xff\0xf4",2, MSG_OOB); send(sock,"\0xff",1,MSG_OOB); send(sock,"\0xf2",1, MSG_OOB); [conn show:"aborting2..."]; [self putCommand:"ABOR"]; [conn show:"trying to interrupt transfer..."]; aborted = YES; //shutdown(datasock,2); } NX_HANDLER //LOGF("message did not go through !"); NX_ENDHANDLER [[conn connectionForProxy] setInTimeout:-1]; [[conn connectionForProxy] setOutTimeout:-1]; } lastshouldstoptime = nowtime; } [conn shouldStopAtPosition:siz]; // just to set the progress views if (aborted) [conn show:"aborting4..."]; fclose(localfp); close(datasock); datasock = -1; if (!aborted) { [file setShouldReget:NO]; [file setLocalName:NULL]; } res = [self getResult]; if (res == 226) { [conn fileRetrieved:file]; } else if (!aborted || res != 426) { [conn transferError:file:"RETR failed2"]; } if (aborted) { res = [self getResult]; if (res == 225 || res == 500) { [conn show:"aborted !"]; [conn fileInterrupted:file]; } else { [conn transferError:file:"ABORt failed"]; } } return; getfile_error: fclose(localfp); sprintf(buf,"%s/%s",[file localPath],[file localName]); unlink(buf); [file setShouldReget:NO]; [file setLocalName:NULL]; return; } - (int) createPort; { int datasock; char buf[1000]; char *a = (char *) &dataaddr.sin_addr; char *p = (char *) &dataaddr.sin_port; int len = sizeof(dataaddr); datasock = socket(AF_INET,SOCK_STREAM,0); if(datasock < 0) { return datasock; } #define UC(b) (((int)b)&0xff) //printf("%d,%d,%d,%d:%d,%d\n",UC(a[0]),UC(a[1]),UC(a[2]),UC(a[3]),UC(p[0]),UC(p[1])); dataaddr . sin_port = 0; //htons(listenport); if( (bind(datasock, (struct sockaddr *)&dataaddr, sizeof(dataaddr)) < 0)) { ERRORF("sock = %d,datasock = %d\n",sock,datasock); perror("createPort: bind"); return -1; } if (getsockname(datasock, (struct sockaddr *)&dataaddr, &len) < 0) { ERRORF("sock = %d,datasock = %d\n",sock,datasock); perror("createPort: getsockname"); return -1; } listen(datasock, 0); if (listen(datasock, 0) < 0) { ERRORF("sock = %d,datasock = %d\n",sock,datasock); perror("createPort: listen"); return -1; } //printf("%d,%d,%d,%d:%d,%d\n", UC(a[0]),UC(a[1]),UC(a[2]),UC(a[3]),UC(p[0]),UC(p[1])); sprintf(buf,"PORT %d,%d,%d,%d,%d,%d", UC(a[0]),UC(a[1]),UC(a[2]),UC(a[3]),UC(p[0]),UC(p[1])); [self putCommand:buf]; [self getResult]; return datasock; } - (int) acceptPort:(int) datasock { struct sockaddr_in addr; int len = sizeof(addr); int newsock; memset((char *)&addr, 0, sizeof(struct sockaddr)); newsock = accept(datasock, (struct sockaddr *) &addr, &len); //printf("acceptsocket: oldsock = %d,newsock = %d\n",datasock,newsock); return newsock; } // get and put Methods...= - (int) getResult; { char *s,*l; int result; s = [self getLineFrom:sock]; if (!s) { [conn console:"421 remote closed...\n"]; [conn connectionLost:"remote server closed connection"]; puts("421 remote closed..."); return 421; } strncpy(line,s,sizeof(line)-1); line[sizeof(line)-1]='\0'; l = line + strlen(s); if (strlen(s) < 4) { //printf("len = %ld, s = |%s|\n",strlen(s),s); [conn connectionLost:"illegal response"]; return -1; } result = ((s[0]-'0')*10+s[1]-'0')*10+s[2]-'0'; //LOGF("sock=%d,result=%d,line=|%s|",sock,result,line); if (s[3] == '-') { while (1) { s=[self getLineFrom:sock]; if (!s) { [conn console:"421 remote closed...\n"]; [conn connectionLost:"remote server closed connection"]; puts("421 remote closed..."); return 421; } LOGF("sock=%d,line=|%s|",sock,s); if (l < line+sizeof(line)) { strncpy(l,s,sizeof(line)-(l-line)-1); line[sizeof(line)-1]='\0'; l = l + strlen(s); } if (s[3] == ' ' && isdigit(s[0]) && isdigit(s[1]) && isdigit(s[2]) && ((s[0]-'0')*10+s[1]-'0')*10+s[2]-'0' == result ) { break; } } } if (421 == result) { [conn connectionLost:line]; close(sock); sock = -1; } return result; } #if 1 // get data from the given socket until the next '\n' - (char *) getLineFrom:(int) mysock; { int i; int len; char c=0; i=0; do { // /*if (mysock <0)*/ LOGF("mysock = %d",mysock); len = recv(mysock, &c,1,0); // /*if (len <1)*/ LOGF("len = %d,c=%c (%d)",len,c,(int)c); if (len == 0) { //printf("got 0 len from socket %d\n",mysock); return NULL; } else if (len != 1) { perror("recv failed"); close(mysock); mysock = -1; [conn connectionLost:"recv failed"]; return NULL; } if (c == '\r') continue; //printf("got [%d]\n",(int) c); if (c == '\n') { c = '\n'; break; } resbuf[i++] = c; } while(1); resbuf[i] = '\n'; resbuf[i+1] = '\0'; //printf("<%s>\n",resbuf); if (mysock == sock) { [conn console:resbuf]; } return resbuf; } #else - (char *) getLineFrom:(int) mysock; { int resbufi; char c; LOGF("pos=%d,fullpos=%d",recvpos,recvfullpos); LOGF("socket:%d,recvbuf:\n|%.*s|",mysock,recvfullpos-recvpos,recvbuf+recvpos); for(resbufi=0; resbufi<sizeof(resbuf)-1;recvpos++) { if (recvpos >= recvfullpos) { int len; LOGF("trying to receive"); len = recv(mysock, recvbuf,sizeof(recvbuf),0); recvpos=0; recvfullpos = len; if (len == 0) { LOGF("got 0 len from socket %d\n",mysock); return NULL; } else if (len < 0) { perror("recv failed"); close(mysock); mysock = -1; [conn connectionLost:"recv failed"]; return NULL; } LOGF("received %d new bytes. buf:\n|%.*s|",len,len,recvbuf); } c = recvbuf[recvpos]; //LOGF("pos=%d,fullpos=%d,char=|%c|",recvpos,recvfullpos,c); if (c == '\r') continue; //printf("got [%d]\n",(int) c); if (c == '\n') break; resbuf[resbufi++] = c; } recvpos++; resbuf[resbufi++] = '\n'; resbuf[resbufi] = '\0'; LOGF("returning:\n|%s|",resbuf); if (mysock == sock) { [conn console:resbuf]; } return resbuf; } #endif - (int) putCommand:(const char *)s; { int len; char buf[1000]; strcpy(buf,s); if ( buf[strlen(buf)-1] != '\n') strcat(buf,"\n"); LOGF("len=%d,buf=|%s|",strlen(buf),buf); LOGF("sock = %d",sock); len = send(sock, buf, strlen(buf), 0); LOGF("len = %d",len); if (len < 0) { [conn connectionLost:"send failed"]; close (sock); sock = -1; return -1; } //[conn console:">>> "]; //[conn console:buf]; LOGF(">>> %s",buf); return 0; } - (int) putCommand:(const char *)s1:(const char *)s2; { char buf[1000]; sprintf(buf,"%s %s\n",s1,s2); return [self putCommand:buf]; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.