📄 htftp.c
字号:
HTTRACE(PROT_TRACE, "FTP Get Data now in state NEED_SEGMENT\n"); { char *ptr; if (data->offset == data->file) { if (ctrl->server == FTP_VMS) { /* Change to root */ if ((segment = (char *) HT_MALLOC(strlen(ctrl->uid)+3)) == NULL) HT_OUTOFMEM("segment "); sprintf(segment, "[%s]", ctrl->uid); } else StrAllocCopy(segment, "/"); data->offset++; ctrl->substate = NEED_CWD; } else { if ((ptr = strchr(data->offset, '/'))) { *ptr='\0'; StrAllocCopy(segment, data->offset); *ptr='/'; data->offset = ++ptr; HTUnEscape(segment); HTCleanTelnetString(segment); ctrl->substate = NEED_CWD; } else ctrl->substate = NEED_ACTION; } } break; case NEED_CWD: HTTRACE(PROT_TRACE, "FTP Get Data now in state NEED_CWD\n"); if (!ctrl->sent) { status = SendCommand(request, ctrl, "CWD", segment); HT_FREE(segment); if (status == HT_WOULD_BLOCK) return HT_WOULD_BLOCK; else if (status == HT_ERROR) ctrl->substate = SUB_ERROR; ctrl->cwd = YES; 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_SEGMENT; else ctrl->substate = SUB_ERROR; } else ctrl->substate = SUB_ERROR; ctrl->sent = NO; } break; case NEED_STREAM: HTTRACE(PROT_TRACE, "FTP Get Data now in state NEED_STREAM\n"); /* ** Create the stream pipe FROM the channel to the application. ** The target for the input stream pipe is set up using the ** stream stack. */ { HTStream * target = FTP_DIR(data) ? HTFTPDir_new(request, ctrl->server, data->type) : HTStreamStack(HTAnchor_format(HTRequest_anchor(request)), HTRequest_outputFormat(request), HTRequest_outputStream(request), request, YES); HTNet_setReadStream(dnet, target); } HTRequest_setOutputConnected(request, YES); data_is_active = YES; ctrl->substate = NEED_BODY; break; case NEED_BODY: HTTRACE(PROT_TRACE, "FTP Get Data now in state NEED_BODY\n"); if (data_is_active) { status = HTHost_read(HTNet_host(dnet), dnet); if (status == HT_WOULD_BLOCK) return HT_WOULD_BLOCK; else if (status == HT_LOADED || status == HT_CLOSED) { data->complete |= 1; if (data->complete >= 3) ctrl->substate = SUB_SUCCESS; else data_is_active = NO; } else { ctrl->substate = SUB_ERROR; data->stream_error = YES; } } else { status = HTHost_read(HTNet_host(cnet), cnet); if (status == HT_WOULD_BLOCK) return HT_WOULD_BLOCK; else if (status == HT_LOADED || status == HT_CLOSED) { if (ctrl->repcode/100 == 2) { data->complete |= 2; if (data->complete >= 3) ctrl->substate = SUB_SUCCESS; else data_is_active = YES; } else ctrl->substate = SUB_ERROR; } else ctrl->substate = SUB_ERROR; } break; case SUB_ERROR: HTTRACE(PROT_TRACE, "FTP Get Data now in state SUB_ERROR\n"); HTRequest_addError(request, ERR_FATAL, NO, HTERR_NOT_FOUND, NULL, 0, "HTFTPGetData"); ctrl->substate = 0; HT_FREE(segment); return HT_ERROR; break; case SUB_SUCCESS: HTTRACE(PROT_TRACE, "FTP Get Data now in state SUB_SUCCESS\n"); ctrl->substate = 0; HT_FREE(segment); return HT_LOADED; break; } }}/* ------------------------------------------------------------------------- *//* Retrieve File from Server as an atomic action. ** -----------------------------------------------** Given a hypertext address, this routine loads a document.**** On entry,** request This is the request structure** returns HT_ERROR Error has occured in call back** HT_OK Call back was OK*/PRIVATE int FTPEvent (SOCKET soc, void * pVoid, HTEventType type);PUBLIC int HTLoadFTP (SOCKET soc, HTRequest * request){ HTNet * cnet = HTRequest_net(request); ftp_ctrl * ctrl = NULL; ftp_data * data = NULL; HTParentAnchor * anchor = HTRequest_anchor(request); char * url = HTAnchor_physical(anchor); /* ** Initiate a new FTP ctrl and data structure and bind to request structure ** This is actually state FTP_BEGIN, but it can't be in the state ** machine as we need the structure first. */ HTTRACE(PROT_TRACE, "FTP......... Looking for `%s\'\n" _ url); if ((ctrl = (ftp_ctrl *) HT_CALLOC(1, sizeof(ftp_ctrl))) == NULL || (data = (ftp_data *) HT_CALLOC(1, sizeof(ftp_data))) == NULL) HT_OUTOFMEM("HTLoadFTP"); ctrl->cmd = HTChunk_new(128); ctrl->state = FTP_BEGIN; ctrl->server = FTP_UNSURE; ctrl->dnet = HTNet_dup(cnet); ctrl->cnet = cnet; HTNet_setContext(cnet, ctrl); HTNet_setEventCallback(cnet, FTPEvent); HTNet_setEventParam(cnet, ctrl); HTNet_setRawBytesCount(ctrl->dnet, YES); /* for now, the dnet comes back to the same place ** - vestigial from when the callback was from the request object */ HTNet_setContext(ctrl->dnet, data); HTNet_setEventCallback(ctrl->dnet, FTPEvent); HTNet_setEventParam(ctrl->dnet, ctrl); return FTPEvent(soc, ctrl, HTEvent_BEGIN);}PRIVATE int FTPEvent (SOCKET soc, void * pVoid, HTEventType type){ ftp_ctrl * ctrl = (ftp_ctrl *) pVoid; ftp_data * data = (ftp_data *) HTNet_context(ctrl->dnet); int status = HT_ERROR; HTNet * cnet = ctrl->cnet; HTRequest * request = HTNet_request(cnet); HTParentAnchor * anchor = HTRequest_anchor(request); char * url = HTAnchor_physical(anchor); HTHost *host = HTNet_host(cnet); if (type == HTEvent_CLOSE) { /* Interrupted */ if (soc == HTNet_socket(cnet)) FTPCleanup(request, HT_INTERRUPTED); else FTPCleanup(request, HT_LOADED); return HT_OK; } else if (type == HTEvent_TIMEOUT) { HTRequest_addError(request, ERR_FATAL, NO, HTERR_TIME_OUT, NULL, 0, "HTLoadHTTP"); FTPCleanup(request, HT_TIMEOUT); return HT_OK; } else { ctrl = (ftp_ctrl *) HTNet_context(cnet); /* Get existing copy */ data = (ftp_data *) HTNet_context(ctrl->dnet); } /* Now jump into the machine. We know the state from the previous run */ while (1) { switch (ctrl->state) { case FTP_BEGIN: HTTRACE(PROT_TRACE, "FTP Event... now in state FTP_BEGIN\n"); /* Only handle GET requests for now */ if (HTRequest_method(request) != METHOD_GET) { HTTRACE(PROT_TRACE, "FTP Event... This module only supports the GET method\n"); ctrl->state = FTP_ERROR; break; } HTFTPParseURL(request, url, ctrl, data); /* The following is added by Neil Griffin, GAIN Software */ /* ** If the user hasn't specified a permanent transfer type, then ** use the transfer type specified at the end of the URL. */ if (g_FTPTransferMode == FTP_DEFAULT_TRANSFER_MODE) { switch (data->type) { case 'a' : data->type = 'A'; break; case 'A' : data->type = 'A'; break; case 'i' : data->type = 'I'; break; case 'I' : data->type = 'I'; break; case 'd' : FTPListType(data, ctrl->server); break; case 'D' : FTPListType(data, ctrl->server); break; default : data->type = 'I'; break; } /* Otherwise, use the permanent transfer type specified by the user. */ } else { switch (g_FTPTransferMode) { case FTP_ASCII_TRANSFER_MODE : data->type = 'A'; break; case FTP_BINARY_TRANSFER_MODE : data->type = 'I'; break; case FTP_DIR_TRANSFER_MODE : FTPListType(data, ctrl->server); break; default : data->type = 'I'; break; } } HTTRACE(PROT_TRACE, "FTP Event... Transfer mode set to '%c'\n" _ data->type); /* ** See if we can get any hints to what we might expect content wise. */ if (!FTP_DIR(data)) HTBind_getAnchorBindings(anchor); /* Ready for next state */ ctrl->state = FTP_NEED_CCON; break; case FTP_NEED_CCON: HTTRACE(PROT_TRACE, "FTP Event... now in state FTP_NEED_CONN\n"); status = HTHost_connect(host, cnet, url, FTP_PORT); host = HTNet_host(cnet); if (status == HT_OK) { /* ** Check the protocol class to see if we have connected to a ** the right class of server, in this case HTTP. */ { char * s_class = HTHost_class(host); if (s_class && strcasecomp(s_class, "ftp")) { HTRequest_addError(request, ERR_FATAL, NO, HTERR_CLASS, NULL, 0, "HTLoadNews"); ctrl->state = FTP_ERROR; break; } HTHost_setClass(host, "ftp"); } /* Check persistent connection */ if (HTNet_persistent(cnet)) { ctrl->server = HTHost_version(host); HTTRACE(PROT_TRACE, "FTP Server.. Cache says type %d server\n" _ ctrl->server); ctrl->reset = 1; } else HTNet_setPersistent(cnet, YES, HT_TP_SINGLE); /* ** Create the stream pipe FROM the channel to the application. ** The target for the input stream pipe is set up using the ** stream stack. */ { HTStream * readstream = FTPStatus_new(request, ctrl, host); HTNet_setReadStream(cnet, readstream); } /* ** Create the stream pipe TO the channel from the application ** and hook it up to the request object */ { HTOutputStream * output = HTNet_getOutput(cnet, NULL, 0); HTRequest_setInputStream(request, (HTStream *) output); } /* ** Set up concurrent read/write if this request isn't the ** source for a PUT or POST. As source we don't start reading ** before all destinations are ready. If destination then ** register the input stream and get ready for read */ if (HTRequest_isPostWeb(request)) { HTEvent * event = HTNet_event(cnet); HTEvent_register(HTNet_socket(cnet), HTEvent_READ, event); HTRequest_linkDestination(request); } ctrl->state = FTP_NEED_LOGIN; } else if (status == HT_WOULD_BLOCK || status == HT_PENDING) return HT_OK; else ctrl->state = FTP_ERROR; /* Error or interrupt */ break; case FTP_NEED_LOGIN: HTTRACE(PROT_TRACE, "FTP Event... now in state FTP_NEED_LOGIN\n"); status = HTFTPLogin(request, cnet, ctrl); if (status == HT_WOULD_BLOCK) return HT_OK; ctrl->state = (status == HT_OK) ? FTP_NEED_DCON : FTP_ERROR; break; case FTP_NEED_DCON: HTTRACE(PROT_TRACE, "FTP Event... now in state FTP_NEED_DCON\n"); status = HTFTPDataConnection(request, cnet, ctrl, data); if (status == HT_WOULD_BLOCK) return HT_OK; if (status == HT_OK) ctrl->state = (data->type=='N') ? FTP_NEED_SERVER : FTP_NEED_DATA; else ctrl->state = FTP_ERROR; break; case FTP_NEED_DATA: HTTRACE(PROT_TRACE, "FTP Event... now in state FTP_NEED_DATA\n"); status = HTFTPGetData(request, cnet, soc, ctrl, data); if (status == HT_WOULD_BLOCK) return HT_OK; if (status == HT_LOADED) ctrl->state = FTP_SUCCESS; else if (status == HT_OK) ctrl->state = FTP_NEED_DCON; else if (!FTP_DIR(data) && !data->stream_error) { FTPListType(data, ctrl->server); ctrl->state = FTP_NEED_SERVER; /* Try a dir instead? */ } else ctrl->state = FTP_ERROR; break; case FTP_NEED_SERVER: HTTRACE(PROT_TRACE, "FTP Event... now in state FTP_NEED_SERVER\n"); status = HTFTPServerInfo(request, cnet, ctrl, data); if (status == HT_WOULD_BLOCK) return HT_OK; ctrl->state = FTP_NEED_DATA; break; case FTP_SUCCESS: HTTRACE(PROT_TRACE, "FTP Event... now in state FTP_SUCCESS\n"); FTPCleanup(request, HT_LOADED); return HT_OK; break; case FTP_ERROR: HTTRACE(PROT_TRACE, "FTP Event... now in state FTP_ERROR\n"); FTPCleanup(request, HT_ERROR); return HT_OK; break; } } /* End of while(1) */}PUBLIC void HTFTP_setTransferMode(FTPTransferMode mode){ g_FTPTransferMode = mode;}PUBLIC FTPTransferMode HTFTP_transferMode (void){ return g_FTPTransferMode;}PUBLIC void HTFTP_setControlMode (FTPControlMode mode){ g_FTPControlMode = mode;}PUBLIC FTPControlMode HTFTP_controlMode (void){ return g_FTPControlMode;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -