📄 htftp.c
字号:
return (*input->isa->put_block)(input, HTChunk_data(ctrl->cmd), len);}/* HTFTPParseURL** -------------** Scan URL for uid and passwd, and any data type indication. The** expected format is [user[:password]@]host[:port].** If no values are found then use defaults.** Returns YES if OK, else NO*/PRIVATE BOOL HTFTPParseURL (HTRequest * request, char *url, ftp_ctrl *ctrl, ftp_data *data){ char *login = HTParse(url, "", PARSE_HOST); char *path = HTParse(url, "", PARSE_PATH+PARSE_PUNCTUATION); char *ptr = strchr(login, '@'); if (ptr) { /* Uid and/or passwd specified */ char *passwd; *ptr = '\0'; if ((passwd = strchr(login, ':'))) { /* Passwd specified */ *passwd++ = '\0'; HTUnEscape(passwd); StrAllocCopy(ctrl->passwd, passwd); } HTUnEscape(login); StrAllocCopy(ctrl->uid, login); } else if (g_FTPControlMode & FTP_ALWAYS_ASK_UID_PW) {/* Added by Marek Nagy. */ ctrl->uid=NULL; ctrl->passwd=NULL;/* End of adding. */ } else { /* Use anonymous */ HTUserProfile * up = HTRequest_userProfile(request); const char * mailaddress = HTUserProfile_email(up); StrAllocCopy(ctrl->uid, "anonymous"); if (mailaddress) StrAllocCopy(ctrl->passwd, mailaddress); else StrAllocCopy(ctrl->passwd, WWW_FTP_CLIENT); }/* begin _GM_ *//* Note: libwww bug ID: GM6 */ {/* char tempParams[512]; sprintf(tempParams, "Username='%s', Password='%s'", ctrl->uid, ctrl->passwd); HTRequest_addError(request, ERR_INFO, NO, HTERR_OK, tempParams, strlen(tempParams), "HTFTPParseURL");*/ }/* end _GM_ */ HTTRACE(PROT_TRACE, "FTPParse.... uid `%s\' pw `%s\'\n" _ ctrl->uid ? ctrl->uid : "<null>" _ ctrl->passwd ? ctrl->passwd : "<null>"); ptr = strchr(path, ';'); if (ptr) { *ptr = '\0'; if (strncasecomp(ptr, ";type=", 6)) /* Look for type */ data->type = TOUPPER(*(ptr+6)); else if (*(ptr-1) == '/') data->type = 'N'; } else if (*(path+strlen(path)-1) == '/') { *(path+strlen(path)-1) = '\0'; data->type = 'N'; } HTTRACE(PROT_TRACE, "FTPParse.... Datatype %c\n" _ data->type ? data->type : '?'); StrAllocCopy(data->file, path); data->offset = data->file; HT_FREE(login); HT_FREE(path); return YES;}/* Use LIST or NLST** ----------------** This function sets the type field for what type of list we can use** Returns YES if OK, else NO*/PRIVATE BOOL FTPListType (ftp_data * data, FTPServerType type){ if (!data) return NO; switch (type) { case FTP_GENERIC: data->type='N'; break; case FTP_MACHTEN: data->type='L'; break; case FTP_UNIX: data->type='L'; break; case FTP_VMS: data->type='L'; break; case FTP_CMS: data->type='N'; break; case FTP_DCTS: data->type='N'; break; case FTP_TCPC: data->type='N'; break; case FTP_PETER_LEWIS: data->type='L'; break; case FTP_NCSA: data->type='N'; break; case FTP_WINNT: data->type='L'; break; default: data->type='N'; break; } return YES;}/* Open a Data socket for listening on** -----------------------------------** Set up a port to listen for data** Returns YES if OK, else NO*/PRIVATE BOOL ListenSocket (HTNet *cnet, HTNet *dnet, ftp_data *data){#ifdef FTP_POLL_PORTS unsigned short old_DataPort = DataPort; for (DataPort=old_DataPort+1;; DataPort++) { if (DataPort > LAST_TCP_PORT) DataPort = FIRST_TCP_PORT; if (DataPort == old_DataPort) { HTTRACE(PROT_TRACE, "FTP......... No data port found\n"); return NO; } if (HTDoListen(dnet, DataPort, 1) == HT_OK) break;#if 0 if (HTNet_socket(dnet) != INVSOC) { NETCLOSE(HTNet_socket(dnet)); HTNet_socket(dnet) = INVSOC; }#else HTDoClose(dnet);#endif }#else if (HTDoListen(dnet, 0, HTNet_socket(cnet), 1) != HT_OK) return NO;#endif /* FTP_POLL_PORTS */ /* Now we must find out who we are to tell the other guy */ { SockA local_addr; int addr_size = sizeof(local_addr); memset((void *) &local_addr, '\0', sizeof(local_addr)); if (getsockname(HTNet_socket(dnet), (struct sockaddr *) &local_addr, &addr_size) < 0) { HTRequest_addSystemError(HTNet_request(dnet), ERR_FATAL, socerrno, NO, "getsockname"); return NO; } HTTRACE(PROT_TRACE, "FTP......... This host is `%s\'\n" _ HTInetString(&local_addr)); { u_long addr = local_addr.sin_addr.s_addr; u_short port = local_addr.sin_port; sprintf(data->host, "%d,%d,%d,%d,%d,%d", (int)*((unsigned char *)(&addr)+0), (int)*((unsigned char *)(&addr)+1), (int)*((unsigned char *)(&addr)+2), (int)*((unsigned char *)(&addr)+3), (int)*((unsigned char *)(&port)+0), (int)*((unsigned char *)(&port)+1)); } } return YES;}/* HTFTPLogin** -----------** This function makes a login to a ftp-server. It takes the user name** and passwd specified in ctrl->user and if that fails or an additional** account is needed, the user is prompted.** Returns HT_OK, HT_ERROR, or HT_WOULD_BLOCK*/PRIVATE int HTFTPLogin (HTRequest *request, HTNet *cnet, ftp_ctrl *ctrl){ int status; typedef enum _state { SUB_ERROR = -2, SUB_SUCCESS = -1, NEED_SELECT = 0, NEED_GREETING, NEED_REIN, NEED_UID, NEED_PASSWD, NEED_ACCOUNT, PROMPT_USER } state; /* Jump into a second level state machine */ while (1) { switch ((state) ctrl->substate) { case NEED_SELECT: { HTAlertCallback * cbf = HTAlert_find(HT_PROG_LOGIN); if (cbf) (*cbf)(request, HT_PROG_LOGIN, HT_MSG_NULL, NULL, NULL, NULL); HTTRACE(PROT_TRACE, "FTP Login.. now in state NEED_SELECT\n"); ctrl->substate = ctrl->reset ? NEED_REIN : NEED_GREETING; } break; case NEED_GREETING: HTTRACE(PROT_TRACE, "FTP Login.. now in state NEED_GREETING\n"); 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 = (ctrl->uid && *ctrl->uid) ? NEED_UID : PROMPT_USER; } else { ctrl->substate = SUB_ERROR; } } else { ctrl->substate = SUB_ERROR; } break; case NEED_REIN: HTTRACE(PROT_TRACE, "FTP Login.. now in state NEED_REIN\n"); if (!ctrl->sent) { status = SendCommand(request, ctrl, "REIN", 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) {/* begin _GM_ *//* Note: libwww bug ID: GM8 */ /* if (ctrl->repcode/100 == 2) { */ /* If the FTP server doesn't support the REIN command, then the return code will be 502 */ if ((ctrl->repcode/100 == 2) || (ctrl->repcode == 502)) {/* end _GM_ */ ctrl->substate = (ctrl->uid && *ctrl->uid) ? NEED_UID : PROMPT_USER; } else { ctrl->substate = SUB_SUCCESS; /* hope the best */ } } else { ctrl->substate = SUB_ERROR; } ctrl->sent = NO; } break; case NEED_UID: HTTRACE(PROT_TRACE, "FTP Login.. now in state NEED_UID\n"); if (!ctrl->sent) { status = SendCommand(request, ctrl, "USER", ctrl->uid); 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/100; if (code == 2) /* Logged in w/o passwd! */ ctrl->substate = SUB_SUCCESS; else if (code == 3) { /* Password demanded */ ctrl->substate = (ctrl->passwd && *ctrl->passwd) ? NEED_PASSWD : PROMPT_USER;/* begin _GM_ *//* Note: libwww bug ID: GM3 */ /* } else if (ctrl->repcode == 530) */ /* ctrl->substate = PROMPT_USER;*/ /* User unknown */ } else if (ctrl->repcode == 530) { if (ctrl->alreadyLoggedIn == YES) { ctrl->substate = SUB_SUCCESS; HTTRACE(PROT_TRACE, "FTP Login.. Already logged in\n"); } else { ctrl->substate = PROMPT_USER; HTTRACE(PROT_TRACE, "FTP Login.. User Unknown\n"); } }/* end _GM_ */ else ctrl->substate = SUB_ERROR; } else ctrl->substate = SUB_ERROR; ctrl->sent = NO; } break; case NEED_PASSWD: HTTRACE(PROT_TRACE, "FTP Login.. now in state NEED_PASSWD\n"); if (!ctrl->sent) { status = SendCommand(request, ctrl, "PASS", ctrl->passwd); 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/100; if (code == 2) /* Logged in with passwd */ ctrl->substate = SUB_SUCCESS; else if (code == 3) { /* Account required */ HTAlertCallback *cbf = HTAlert_find(HT_A_PROMPT); HTAlertPar * reply = HTAlert_newReply(); if (cbf && (*cbf)(request, HT_A_PROMPT, HT_MSG_ACCOUNT, NULL, NULL, reply)) { ctrl->account = HTAlert_replyMessage(reply); ctrl->substate = NEED_ACCOUNT; } else ctrl->substate = SUB_ERROR; HTAlert_deleteReply(reply); } else if (ctrl->repcode == 530) ctrl->substate = PROMPT_USER; else ctrl->substate = SUB_ERROR; } else ctrl->substate = SUB_ERROR; ctrl->sent = NO; } break; case NEED_ACCOUNT: HTTRACE(PROT_TRACE, "FTP Login.. now in state NEED_ACCOUNT\n"); if (!ctrl->sent) { status = SendCommand(request, ctrl, "ACCT", ctrl->account); 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/100; if (code == 2) /* Logged in with account */ ctrl->substate = SUB_SUCCESS; else ctrl->substate = SUB_ERROR; /* hopeless */ } else ctrl->substate = SUB_ERROR; ctrl->sent = NO; } break; case PROMPT_USER: HTTRACE(PROT_TRACE, "FTP Login.. now in state PROMPT_USER\n"); { HTAlertCallback *cbf = HTAlert_find(HT_A_USER_PW); HTAlertPar * reply = HTAlert_newReply(); HT_FREE(ctrl->uid); HT_FREE(ctrl->passwd); if (cbf && (*cbf)(request, HT_A_USER_PW, HT_MSG_FTP_UID, NULL, NULL, reply)){ ctrl->uid = HTAlert_replyMessage(reply); ctrl->passwd = HTAlert_replySecret(reply); } HTAlert_deleteReply(reply); if (ctrl->uid && *ctrl->uid && ctrl->passwd && *ctrl->passwd) ctrl->substate = NEED_UID; else ctrl->substate = SUB_ERROR; } break; case SUB_ERROR: HTTRACE(PROT_TRACE, "FTP Login.. now in state SUB_ERROR\n"); HTRequest_addError(request, ERR_FATAL, NO, HTERR_FTP_LOGIN_FAILURE, NULL, 0, "HTFTPLogin"); HTTRACE(PROT_TRACE, "FTP......... Login failed\n"); ctrl->substate = 0; return HT_ERROR; break; case SUB_SUCCESS: HTTRACE(PROT_TRACE, "FTP Login.. now in state SUB_SUCCESS\n"); HTTRACE(PROT_TRACE, "FTP......... Logged in as `%s\'\n" _ ctrl->uid); ctrl->substate = 0; return HT_OK; break; } }}/* HTFTPDataConnection** -------------------** Prepares a data connection to the server and initializes the** transfer mode.** Returns HT_OK, HT_ERROR, or HT_WOULD_BLOCK*/PRIVATE int HTFTPDataConnection (HTRequest * request, HTNet *cnet, ftp_ctrl *ctrl, ftp_data *data){ int status; HTNet *dnet = ctrl->dnet; typedef enum _state { SUB_ERROR = -2, SUB_SUCCESS = -1, NEED_TYPE = 0, NEED_SELECT, NEED_PASV, NEED_PORT } state; /* Jump into a second level state machine */ while (1) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -