📄 htftp.c
字号:
switch ((state) ctrl->substate) { case NEED_TYPE: HTTRACE(PROT_TRACE, "FTP Data.... now in state NEED_TYPE\n"); if(!data->type|| data->pasv || data->type=='N' || data->type=='L'){ ctrl->substate = NEED_SELECT; break; } if (!ctrl->sent) { char type[2]; *type = data->type; *(type+1) = '\0'; status = SendCommand(request, ctrl, "TYPE", type); if (status == HT_WOULD_BLOCK) return HT_WOULD_BLOCK; else if (status == HT_ERROR) ctrl->substate = SUB_ERROR; ctrl->sent = YES; } else { status = HTHost_read(HTNet_host(cnet), cnet); if (status == HT_WOULD_BLOCK) return HT_WOULD_BLOCK; else if (status == HT_LOADED) { if (ctrl->repcode/100 == 2) ctrl->substate = NEED_SELECT; else ctrl->substate = SUB_ERROR; } else ctrl->substate = SUB_ERROR; ctrl->sent = NO; } break; case NEED_SELECT: HTTRACE(PROT_TRACE, "FTP Data.... now in state NEED_SELECT\n"); if (FTPMode & FTP_DATA_PASV && !data->pasv) ctrl->substate = NEED_PASV; else if (ListenSocket(cnet, dnet, data)) ctrl->substate = NEED_PORT; else ctrl->substate = SUB_ERROR; break; case NEED_PASV: HTTRACE(PROT_TRACE, "FTP Data.... now in state NEED_PASV\n"); if (!ctrl->sent) { status = SendCommand(request, ctrl, "PASV", NULL); if (status == HT_WOULD_BLOCK) return HT_WOULD_BLOCK; else if (status == HT_ERROR) ctrl->substate = SUB_ERROR; ctrl->sent = YES; } else { status = HTHost_read(HTNet_host(cnet), cnet); if (status == HT_WOULD_BLOCK) return HT_WOULD_BLOCK; else if (status == HT_LOADED) { if (ctrl->repcode == 227) { /* ** If succes, we have to scan for the returned number. ** As the format for the response isn't standard, ** the best thing to do is to scan for the first digit ** after the status code, see RFC1123 */ char *host = ctrl->reply; int h0, h1, h2, h3, p0=0, p1=0; while (*host && !isdigit((int) *host++)); if (!*host || sscanf(--host, "%d,%d,%d,%d,%d,%d", &h0,&h1,&h2,&h3,&p0,&p1) < 6) { HTTRACE(PROT_TRACE, "FTP Data.... PASV No addr\n"); ctrl->substate = SUB_ERROR; break; } else { int port = (p0<<8)+p1; sprintf(data->host, "ftp://%d.%d.%d.%d:%d/", h0, h1, h2, h3, port); data->pasv = YES; ctrl->substate = SUB_SUCCESS; } } else { ctrl->substate = ListenSocket(cnet, dnet, data) ? NEED_PORT : SUB_ERROR; } } else ctrl->substate = SUB_ERROR; ctrl->sent = NO; } break; case NEED_PORT: HTTRACE(PROT_TRACE, "FTP Data.... now in state NEED_PORT\n"); if (!ctrl->sent) { status = SendCommand(request, ctrl, "PORT", data->host); if (status == HT_WOULD_BLOCK) return HT_WOULD_BLOCK; else if (status == HT_ERROR) ctrl->substate = SUB_ERROR; ctrl->sent = YES; } else { status = HTHost_read(HTNet_host(cnet), cnet); if (status == HT_WOULD_BLOCK) return HT_WOULD_BLOCK; else if (status == HT_LOADED) { data->pasv = NO; ctrl->substate = (ctrl->repcode/100 == 2) ? SUB_SUCCESS : SUB_ERROR; } else ctrl->substate = SUB_ERROR; ctrl->sent = NO; } break; case SUB_ERROR: HTTRACE(PROT_TRACE, "FTP Data.... now in state SUB_ERROR\n"); HTTRACE(PROT_TRACE, "FTP Data.... Can't setup data connection\n"); ctrl->substate = 0; return HT_ERROR; break; case SUB_SUCCESS: HTTRACE(PROT_TRACE, "FTP Data.... now in state SUB_SUCCESS\n"); HTTRACE(PROT_TRACE, "FTP Data.... Data connection negotiated\n"); ctrl->substate = 0; return HT_OK; break; } }}/* HTFTPServerInfo** ---------------** This function finds out what server we are talking to.** Maybe we can upgrade from NLST to LIST.** Returns HT_OK, HT_ERROR, or HT_WOULD_BLOCK** Thanks to James.W.Matthews@Dartmouth.EDU (James W. Matthews) for making** his code available.*/PRIVATE int HTFTPServerInfo (HTRequest *request, HTNet *cnet, ftp_ctrl *ctrl, ftp_data *data){ int status; typedef enum _state { SUB_ERROR = -2, SUB_SUCCESS = -1, NEED_SYST = 0, CHECK_SYST, NEED_PWD, CHECK_PWD } state; /* Jump into a second level state machine */ while (1) { switch ((state) ctrl->substate) { case NEED_SYST: HTTRACE(PROT_TRACE, "FTP Server.. now in state NEED_SYST\n"); if (!ctrl->sent) { if (ctrl->server != FTP_UNSURE) { FTPListType(data, ctrl->server); return HT_OK; } status = SendCommand(request, ctrl, "SYST", NULL); if (status == HT_WOULD_BLOCK) return HT_WOULD_BLOCK; else if (status == HT_ERROR) ctrl->substate = SUB_ERROR; ctrl->sent = YES; } else { status = HTHost_read(HTNet_host(cnet), cnet); if (status == HT_WOULD_BLOCK) return HT_WOULD_BLOCK; else if (status == HT_LOADED) { ctrl->substate=ctrl->repcode==215 ? CHECK_SYST : NEED_PWD; } else ctrl->substate = SUB_ERROR; ctrl->sent = NO; } break; case CHECK_SYST: HTTRACE(PROT_TRACE, "FTP Server.. now in state CHECK_SYST\n"); { char *reply = ctrl->reply; if (!*reply) { HTTRACE(PROT_TRACE, "FTP Server.. No server info?\n"); ctrl->substate = NEED_PWD; break; } if (strncmp(reply, "UNIX Type: L8MAC-OSMachTen", 28) == 0) { ctrl->server = FTP_MACHTEN; } else if (strstr(reply, "UNIX") != NULL) { ctrl->server = FTP_UNIX; } else if (strncmp(reply, "VMS", 3) == 0) { ctrl->server = FTP_VMS; } else if ((strncmp(reply, "VM/CMS", 6) == 0) || (strncmp(reply, "VM", 2) == 0)) { ctrl->server = FTP_CMS; } else if (strncmp(reply, "DCTS", 4) == 0) { ctrl->server = FTP_DCTS; } else if (strstr(reply, "MAC-OS TCP/ConnectII") != NULL) { /* Check old versions of TCP/C using / in pathnames */ ctrl->server = FTP_TCPC + FTP_UNSURE; } else if (strncmp(reply, "MACOS Peter's Server", 20) == 0) { ctrl->server = FTP_PETER_LEWIS; } else if (strncmp(reply, "Windows_NT", 10) == 0) { ctrl->server = FTP_WINNT; } /* If we are unsure, try PWD to get more information */ if (ctrl->server & FTP_UNSURE) ctrl->substate = NEED_PWD; else ctrl->substate = SUB_SUCCESS; } break; case NEED_PWD: HTTRACE(PROT_TRACE, "FTP Server.. now in state NEED_PWD\n"); if (!ctrl->sent) { status = SendCommand(request, ctrl, "PWD", NULL); if (status == HT_WOULD_BLOCK) return HT_WOULD_BLOCK; else if (status == HT_ERROR) ctrl->substate = SUB_ERROR; ctrl->sent = YES; } else { status = HTHost_read(HTNet_host(cnet), cnet); if (status == HT_WOULD_BLOCK) return HT_WOULD_BLOCK; else if (status == HT_LOADED) { ctrl->substate = (ctrl->repcode/100 == 2) ? CHECK_PWD : SUB_ERROR; } else ctrl->substate = SUB_ERROR; ctrl->sent = NO; } break; case CHECK_PWD: HTTRACE(PROT_TRACE, "FTP Server.. now in state CHECK_PWD\n"); { char *start = strchr(ctrl->reply, '"'); char *end; if (!start || (end = strchr(++start, '"')) == NULL) { HTTRACE(PROT_TRACE, "FTP Server.. No current directory?\n"); ctrl->server = FTP_GENERIC; } else { *end = '\0'; if (ctrl->server & FTP_TCPC) { ctrl->server = *start == '/' ? FTP_NCSA : FTP_TCPC; } else if (*start == '/') { /* path names starting with / imply Unix, right? */ ctrl->server = FTP_UNIX; } else if (*(end-1) == ']') { /* path names ending with ] imply VMS, right? */ ctrl->server = FTP_VMS; } else ctrl->server = FTP_GENERIC; } ctrl->substate = SUB_SUCCESS; } break; case SUB_ERROR: HTTRACE(PROT_TRACE, "FTP Server.. now in state SUB_ERROR\n"); HTTRACE(PROT_TRACE, "FTP Server.. Can't get server information\n"); ctrl->substate = 0; ctrl->server = FTP_GENERIC; return HT_ERROR; break; case SUB_SUCCESS: HTTRACE(PROT_TRACE, "FTP Server.. now in state SUB_SUCCESS\n"); { HTHost * host = HTNet_host(cnet); HTTRACE(PROT_TRACE, "FTP Server.. Guessed type %d\n" _ ctrl->server); HTHost_setVersion(host, ctrl->server); FTPListType(data, ctrl->server); ctrl->substate = 0; return HT_OK; break; } } }}/* HTFTPGetData** ------------** This function asks for the file or a directory. First we try in one go,** but if that doesn't work, then we use CWD for each segment and then** try to retrieve it. If that also fails, then we try if it is a** directory.** Returns HT_OK, HT_LOADED, HT_ERROR, or HT_WOULD_BLOCK*/PRIVATE int HTFTPGetData (HTRequest *request, HTNet *cnet, SOCKET sockfd, ftp_ctrl *ctrl, ftp_data *data){ int status; char *segment = NULL; HTNet *dnet = ctrl->dnet; BOOL data_is_active = (sockfd == HTNet_socket(dnet)); typedef enum _state { SUB_ERROR = -2, SUB_SUCCESS = -1, NEED_SELECT = 0, NEED_CONNECT, NEED_ACCEPT, NEED_ACTION, NEED_CWD, NEED_SEGMENT, NEED_STREAM, NEED_BODY } state; /* Jump into a second level state machine */ while (1) { switch ((state) ctrl->substate) { case NEED_SELECT: HTTRACE(PROT_TRACE, "FTP Get Data now in state NEED_SELECT\n"); ctrl->substate = data->pasv ? NEED_CONNECT : NEED_ACTION; break; case NEED_CONNECT: HTTRACE(PROT_TRACE, "FTP Get Data now in state NEED_CONNECT\n"); status = HTHost_connect(HTNet_host(dnet), dnet, data->host, FTP_DATA); if (status == HT_WOULD_BLOCK) return HT_WOULD_BLOCK; else if (status == HT_OK) { HTTRACE(PROT_TRACE, "FTP Get Data.... Active data socket %d\n" _ HTNet_socket(dnet));#if 0 /* HTNet_setPersistent(dnet, YES, HT_TP_INTERLEAVE); */ HTNet_setPersistent(dnet, YES, HT_TP_SINGLE);#endif ctrl->substate = NEED_ACTION; } else { /* Swap to PORT on the fly */ NETCLOSE(HTNet_socket(dnet)); HTNet_setSocket(dnet, INVSOC); HTTRACE(PROT_TRACE, "FTP Get Data Swap to PORT on the fly\n"); ctrl->substate = NEED_SELECT; HT_FREE(segment); return HT_OK; } break; case NEED_ACCEPT: HTTRACE(PROT_TRACE, "FTP Get Data now in state NEED_ACCEPT\n"); { status = HTDoAccept(ctrl->dnet, &ctrl->dnet); dnet = ctrl->dnet; if (status == HT_WOULD_BLOCK) return HT_WOULD_BLOCK; else if (status == HT_OK) { HTTRACE(PROT_TRACE, "FTP Get Data.... Passive data socket %d\n" _ HTNet_socket(dnet)); ctrl->substate = NEED_STREAM; } else ctrl->substate = SUB_ERROR; } break; case NEED_ACTION: HTTRACE(PROT_TRACE, "FTP Get Data now in state NEED_ACTION\n"); if (!ctrl->sent) { char *cmd = (data->type=='L') ? "LIST" : (data->type=='N') ? "NLST" : "RETR"; StrAllocCopy(segment, data->offset); HTUnEscape(segment); HTCleanTelnetString(segment); status = SendCommand(request, ctrl, cmd, segment); HT_FREE(segment); if (status == HT_WOULD_BLOCK) return HT_WOULD_BLOCK; else if (status == HT_ERROR) ctrl->substate = SUB_ERROR; ctrl->sent = YES; } else { status = HTHost_read(HTNet_host(cnet), cnet); if (status == HT_WOULD_BLOCK) return HT_WOULD_BLOCK; else if (status == HT_LOADED) { int code = ctrl->repcode; if (code==125 || code==150 || code==225) ctrl->substate = data->pasv ? NEED_STREAM : NEED_ACCEPT; else if (code/100==5 && !ctrl->cwd) ctrl->substate = NEED_SEGMENT;/* begin _GM_ *//* Note: libwww bug ID: GM9 */ /* else */ /* ctrl->substate = SUB_ERROR; */ else { if (ctrl->repcode == 550) { HTTRACE(PROT_TRACE, "FTP Get Data no such file or directory\n"); data->stream_error = YES; } ctrl->substate = SUB_ERROR; }/* end _GM_ */ } else ctrl->substate = SUB_ERROR; ctrl->sent = NO; } break; case NEED_SEGMENT:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -