/*********************************************************************** * * smtp_perform() * * This is the actual DO function for SMTP. Get a file/directory according to * the options previously setup. */ static CURLcode smtp_perform(struct connectdata *conn, bool *connected, bool *dophase_done) { /* This is SMTP and no proxy */ CURLcode result = CURLE_OK; DEBUGF(infof(conn->data, "DO phase starts\n")); if(conn->data->set.opt_no_body) { /* Requested no body means no transfer */ struct FTP *smtp = conn->data->state.proto.smtp; smtp->transfer = FTPTRANSFER_INFO; } *dophase_done = FALSE; /* not done yet */ /* Start the first command in the DO phase */ result = smtp_mail(conn); if(result) return result; /* Run the state-machine */ if(conn->data->state.used_interface == Curl_if_multi) result = smtp_multi_statemach(conn, dophase_done); else { result = smtp_easy_statemach(conn); *dophase_done = TRUE; /* with the easy interface we are done here */ } *connected = conn->bits.tcpconnect[FIRSTSOCKET]; if(*dophase_done) DEBUGF(infof(conn->data, "DO phase is complete\n")); return result; }
/*********************************************************************** * * smtp_done() * * The DONE function. This does what needs to be done after a single DO has * performed. * * Input argument is already checked for validity. */ static CURLcode smtp_done(struct connectdata *conn, CURLcode status, bool premature) { struct SessionHandle *data = conn->data; struct FTP *smtp = data->state.proto.smtp; CURLcode result = CURLE_OK; ssize_t bytes_written; (void)premature; if(!smtp) /* When the easy handle is removed from the multi while libcurl is still * trying to resolve the host name, it seems that the smtp struct is not * yet initialized, but the removal action calls Curl_done() which calls * this function. So we simply return success if no smtp pointer is set. */ return CURLE_OK; if(status) { conn->bits.close = TRUE; /* marked for closure */ result = status; /* use the already set error code */ } else /* TODO: make this work even when the socket is EWOULDBLOCK in this call! */ /* write to socket (send away data) */ result = Curl_write(conn, conn->writesockfd, /* socket to send to */ SMTP_EOB, /* buffer pointer */ SMTP_EOB_LEN, /* buffer size */ &bytes_written); /* actually sent away */ if(status == CURLE_OK) { struct smtp_conn *smtpc = &conn->proto.smtpc; struct pingpong *pp = &smtpc->pp; pp->response = Curl_tvnow(); /* timeout relative now */ state(conn, SMTP_POSTDATA); /* run the state-machine TODO: when the multi interface is used, this _really_ should be using the smtp_multi_statemach function but we have no general support for non-blocking DONE operations, not in the multi state machine and with Curl_done() invokes on several places in the code! */ result = smtp_easy_statemach(conn); } /* clear these for next connection */ smtp->transfer = FTPTRANSFER_BODY; return result; }
/*********************************************************************** * * smtp_quit() * * This should be called before calling sclose(). We should then wait for the * response from the server before returning. The calling code should then try * to close the connection. * */ static CURLcode smtp_quit(struct connectdata *conn) { CURLcode result = CURLE_OK; result = Curl_pp_sendf(&conn->proto.smtpc.pp, "QUIT"); if(result) return result; state(conn, SMTP_QUIT); result = smtp_easy_statemach(conn); return result; }
/* * smtp_connect() should do everything that is to be considered a part of * the connection phase. * * The variable 'done' points to will be TRUE if the protocol-layer connect * phase is done when this function returns, or FALSE is not. When called as * a part of the easy interface, it will always be TRUE. */ static CURLcode smtp_connect(struct connectdata *conn, bool *done) /* see description above */ { CURLcode result; struct smtp_conn *smtpc = &conn->proto.smtpc; struct SessionHandle *data=conn->data; struct pingpong *pp=&smtpc->pp; const char *path = conn->data->state.path; int len; char localhost[1024 + 1]; *done = FALSE; /* default to not done yet */ /* If there already is a protocol-specific struct allocated for this sessionhandle, deal with it */ Curl_reset_reqproto(conn); result = smtp_init(conn); if(CURLE_OK != result) return result; /* We always support persistant connections on smtp */ conn->bits.close = FALSE; pp->response_time = RESP_TIMEOUT; /* set default response time-out */ pp->statemach_act = smtp_statemach_act; pp->endofresp = smtp_endofresp; pp->conn = conn; #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_PROXY) if(conn->bits.tunnel_proxy && conn->bits.httpproxy) { /* for SMTP over HTTP proxy */ struct HTTP http_proxy; struct FTP *smtp_save; /* BLOCKING */ /* We want "seamless" SMTP operations through HTTP proxy tunnel */ /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member * conn->proto.http; we want SMTP through HTTP and we have to change the * member temporarily for connecting to the HTTP proxy. After * Curl_proxyCONNECT we have to set back the member to the original struct * SMTP pointer */ smtp_save = data->state.proto.smtp; memset(&http_proxy, 0, sizeof(http_proxy)); data->state.proto.http = &http_proxy; result = Curl_proxyCONNECT(conn, FIRSTSOCKET, conn->host.name, conn->remote_port); data->state.proto.smtp = smtp_save; if(CURLE_OK != result) return result; } #endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_PROXY */ if(conn->protocol & PROT_SMTPS) { /* BLOCKING */ /* SMTPS is simply smtp with SSL for the control channel */ /* now, perform the SSL initialization for this socket */ result = Curl_ssl_connect(conn, FIRSTSOCKET); if(result) return result; } Curl_pp_init(pp); /* init the response reader stuff */ pp->response_time = RESP_TIMEOUT; /* set default response time-out */ pp->statemach_act = smtp_statemach_act; pp->endofresp = smtp_endofresp; pp->conn = conn; if(!*path) { if(!Curl_gethostname(localhost, sizeof localhost)) path = localhost; else path = "localhost"; } /* url decode the path and use it as domain with EHLO */ smtpc->domain = curl_easy_unescape(conn->data, path, 0, &len); if(!smtpc->domain) return CURLE_OUT_OF_MEMORY; /* When we connect, we start in the state where we await the server greeting */ state(conn, SMTP_SERVERGREET); if(data->state.used_interface == Curl_if_multi) result = smtp_multi_statemach(conn, done); else { result = smtp_easy_statemach(conn); if(!result) *done = TRUE; } return result; }
/*********************************************************************** * * smtp_done() * * The DONE function. This does what needs to be done after a single DO has * performed. * * Input argument is already checked for validity. */ static CURLcode smtp_done(struct connectdata *conn, CURLcode status, bool premature) { struct SessionHandle *data = conn->data; struct FTP *smtp = data->state.proto.smtp; CURLcode result = CURLE_OK; ssize_t bytes_written; (void)premature; if(!smtp) /* When the easy handle is removed from the multi while libcurl is still * trying to resolve the host name, it seems that the smtp struct is not * yet initialized, but the removal action calls Curl_done() which calls * this function. So we simply return success if no smtp pointer is set. */ return CURLE_OK; if(status) { conn->bits.close = TRUE; /* marked for closure */ result = status; /* use the already set error code */ } else if(!data->set.connect_only) { struct smtp_conn *smtpc = &conn->proto.smtpc; struct pingpong *pp = &smtpc->pp; /* Send the end of block data */ result = Curl_write(conn, conn->writesockfd, /* socket to send to */ SMTP_EOB, /* buffer pointer */ SMTP_EOB_LEN, /* buffer size */ &bytes_written); /* actually sent away */ if(result) return result; if(bytes_written != SMTP_EOB_LEN) { /* The whole chunk was not sent so keep it around and adjust the pingpong structure accordingly */ pp->sendthis = strdup(SMTP_EOB); pp->sendsize = SMTP_EOB_LEN; pp->sendleft = SMTP_EOB_LEN - bytes_written; } else /* Successfully sent so adjust the response timeout relative to now */ pp->response = Curl_tvnow(); state(conn, SMTP_POSTDATA); /* Run the state-machine TODO: when the multi interface is used, this _really_ should be using the smtp_multi_statemach function but we have no general support for non-blocking DONE operations, not in the multi state machine and with Curl_done() invokes on several places in the code! */ result = smtp_easy_statemach(conn); } /* Clear the transfer mode for the next connection */ smtp->transfer = FTPTRANSFER_BODY; return result; }
/*********************************************************************** * * smtp_connect() * * This function should do everything that is to be considered a part of * the connection phase. * * The variable pointed to by 'done' will be TRUE if the protocol-layer * connect phase is done when this function returns, or FALSE if not. When * called as a part of the easy interface, it will always be TRUE. */ static CURLcode smtp_connect(struct connectdata *conn, bool *done) { CURLcode result; struct smtp_conn *smtpc = &conn->proto.smtpc; struct SessionHandle *data = conn->data; struct pingpong *pp = &smtpc->pp; const char *path = conn->data->state.path; char localhost[HOSTNAME_MAX + 1]; *done = FALSE; /* default to not done yet */ /* If there already is a protocol-specific struct allocated for this sessionhandle, deal with it */ Curl_reset_reqproto(conn); result = smtp_init(conn); if(CURLE_OK != result) return result; /* We always support persistent connections on smtp */ conn->bits.close = FALSE; pp->response_time = RESP_TIMEOUT; /* set default response time-out */ pp->statemach_act = smtp_statemach_act; pp->endofresp = smtp_endofresp; pp->conn = conn; if((conn->handler->protocol & CURLPROTO_SMTPS) && data->state.used_interface != Curl_if_multi) { /* SMTPS is simply smtp with SSL for the control channel */ /* so perform the SSL initialization for this socket */ result = Curl_ssl_connect(conn, FIRSTSOCKET); if(result) return result; } /* Initialise the response reader stuff */ Curl_pp_init(pp); /* Set the default response time-out */ pp->response_time = RESP_TIMEOUT; pp->statemach_act = smtp_statemach_act; pp->endofresp = smtp_endofresp; pp->conn = conn; /* Calculate the path if necessary */ if(!*path) { if(!Curl_gethostname(localhost, sizeof(localhost))) path = localhost; else path = "localhost"; } /* URL decode the path and use it as the domain in our EHLO */ result = Curl_urldecode(conn->data, path, 0, &smtpc->domain, NULL, TRUE); if(result) return result; /* Start off waiting for the server greeting response */ state(conn, SMTP_SERVERGREET); if(data->state.used_interface == Curl_if_multi) result = smtp_multi_statemach(conn, done); else { result = smtp_easy_statemach(conn); if(!result) *done = TRUE; } return result; }