pop3: Introduced a custom SMTP structure for per-request data
[platform/upstream/curl.git] / lib / smtp.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at http://curl.haxx.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  * RFC1870 SMTP Service Extension for Message Size
22  * RFC2195 CRAM-MD5 authentication
23  * RFC2831 DIGEST-MD5 authentication
24  * RFC3207 SMTP over TLS
25  * RFC4422 Simple Authentication and Security Layer (SASL)
26  * RFC4616 PLAIN authentication
27  * RFC4954 SMTP Authentication
28  * RFC5321 SMTP protocol
29  *
30  ***************************************************************************/
31
32 #include "curl_setup.h"
33
34 #ifndef CURL_DISABLE_SMTP
35
36 #ifdef HAVE_NETINET_IN_H
37 #include <netinet/in.h>
38 #endif
39 #ifdef HAVE_ARPA_INET_H
40 #include <arpa/inet.h>
41 #endif
42 #ifdef HAVE_UTSNAME_H
43 #include <sys/utsname.h>
44 #endif
45 #ifdef HAVE_NETDB_H
46 #include <netdb.h>
47 #endif
48 #ifdef __VMS
49 #include <in.h>
50 #include <inet.h>
51 #endif
52
53 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
54 #undef in_addr_t
55 #define in_addr_t unsigned long
56 #endif
57
58 #include <curl/curl.h>
59 #include "urldata.h"
60 #include "sendf.h"
61 #include "if2ip.h"
62 #include "hostip.h"
63 #include "progress.h"
64 #include "transfer.h"
65 #include "escape.h"
66 #include "http.h" /* for HTTP proxy tunnel stuff */
67 #include "socks.h"
68 #include "smtp.h"
69
70 #include "strtoofft.h"
71 #include "strequal.h"
72 #include "sslgen.h"
73 #include "connect.h"
74 #include "strerror.h"
75 #include "select.h"
76 #include "multiif.h"
77 #include "url.h"
78 #include "rawstr.h"
79 #include "curl_gethostname.h"
80 #include "curl_sasl.h"
81 #include "warnless.h"
82
83 #define _MPRINTF_REPLACE /* use our functions only */
84 #include <curl/mprintf.h>
85
86 #include "curl_memory.h"
87 /* The last #include file should be: */
88 #include "memdebug.h"
89
90 /* Local API functions */
91 static CURLcode smtp_regular_transfer(struct connectdata *conn, bool *done);
92 static CURLcode smtp_do(struct connectdata *conn, bool *done);
93 static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
94                           bool premature);
95 static CURLcode smtp_connect(struct connectdata *conn, bool *done);
96 static CURLcode smtp_disconnect(struct connectdata *conn, bool dead);
97 static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done);
98 static int smtp_getsock(struct connectdata *conn, curl_socket_t *socks,
99                         int numsocks);
100 static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done);
101 static CURLcode smtp_setup_connection(struct connectdata *conn);
102
103 /*
104  * SMTP protocol handler.
105  */
106
107 const struct Curl_handler Curl_handler_smtp = {
108   "SMTP",                           /* scheme */
109   smtp_setup_connection,            /* setup_connection */
110   smtp_do,                          /* do_it */
111   smtp_done,                        /* done */
112   ZERO_NULL,                        /* do_more */
113   smtp_connect,                     /* connect_it */
114   smtp_multi_statemach,             /* connecting */
115   smtp_doing,                       /* doing */
116   smtp_getsock,                     /* proto_getsock */
117   smtp_getsock,                     /* doing_getsock */
118   ZERO_NULL,                        /* domore_getsock */
119   ZERO_NULL,                        /* perform_getsock */
120   smtp_disconnect,                  /* disconnect */
121   ZERO_NULL,                        /* readwrite */
122   PORT_SMTP,                        /* defport */
123   CURLPROTO_SMTP,                   /* protocol */
124   PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */
125 };
126
127 #ifdef USE_SSL
128 /*
129  * SMTPS protocol handler.
130  */
131
132 const struct Curl_handler Curl_handler_smtps = {
133   "SMTPS",                          /* scheme */
134   smtp_setup_connection,            /* setup_connection */
135   smtp_do,                          /* do_it */
136   smtp_done,                        /* done */
137   ZERO_NULL,                        /* do_more */
138   smtp_connect,                     /* connect_it */
139   smtp_multi_statemach,             /* connecting */
140   smtp_doing,                       /* doing */
141   smtp_getsock,                     /* proto_getsock */
142   smtp_getsock,                     /* doing_getsock */
143   ZERO_NULL,                        /* domore_getsock */
144   ZERO_NULL,                        /* perform_getsock */
145   smtp_disconnect,                  /* disconnect */
146   ZERO_NULL,                        /* readwrite */
147   PORT_SMTPS,                       /* defport */
148   CURLPROTO_SMTP | CURLPROTO_SMTPS, /* protocol */
149   PROTOPT_CLOSEACTION | PROTOPT_SSL
150   | PROTOPT_NOURLQUERY              /* flags */
151 };
152 #endif
153
154 #ifndef CURL_DISABLE_HTTP
155 /*
156  * HTTP-proxyed SMTP protocol handler.
157  */
158
159 static const struct Curl_handler Curl_handler_smtp_proxy = {
160   "SMTP",                               /* scheme */
161   ZERO_NULL,                            /* setup_connection */
162   Curl_http,                            /* do_it */
163   Curl_http_done,                       /* done */
164   ZERO_NULL,                            /* do_more */
165   ZERO_NULL,                            /* connect_it */
166   ZERO_NULL,                            /* connecting */
167   ZERO_NULL,                            /* doing */
168   ZERO_NULL,                            /* proto_getsock */
169   ZERO_NULL,                            /* doing_getsock */
170   ZERO_NULL,                            /* domore_getsock */
171   ZERO_NULL,                            /* perform_getsock */
172   ZERO_NULL,                            /* disconnect */
173   ZERO_NULL,                            /* readwrite */
174   PORT_SMTP,                            /* defport */
175   CURLPROTO_HTTP,                       /* protocol */
176   PROTOPT_NONE                          /* flags */
177 };
178
179 #ifdef USE_SSL
180 /*
181  * HTTP-proxyed SMTPS protocol handler.
182  */
183
184 static const struct Curl_handler Curl_handler_smtps_proxy = {
185   "SMTPS",                              /* scheme */
186   ZERO_NULL,                            /* setup_connection */
187   Curl_http,                            /* do_it */
188   Curl_http_done,                       /* done */
189   ZERO_NULL,                            /* do_more */
190   ZERO_NULL,                            /* connect_it */
191   ZERO_NULL,                            /* connecting */
192   ZERO_NULL,                            /* doing */
193   ZERO_NULL,                            /* proto_getsock */
194   ZERO_NULL,                            /* doing_getsock */
195   ZERO_NULL,                            /* domore_getsock */
196   ZERO_NULL,                            /* perform_getsock */
197   ZERO_NULL,                            /* disconnect */
198   ZERO_NULL,                            /* readwrite */
199   PORT_SMTPS,                           /* defport */
200   CURLPROTO_HTTP,                       /* protocol */
201   PROTOPT_NONE                          /* flags */
202 };
203 #endif
204 #endif
205
206 #ifdef USE_SSL
207 static void smtp_to_smtps(struct connectdata *conn)
208 {
209   conn->handler = &Curl_handler_smtps;
210 }
211 #else
212 #define smtp_to_smtps(x) Curl_nop_stmt
213 #endif
214
215 /* Function that checks for an ending SMTP status code at the start of the
216    given string, but also detects various capabilities from the EHLO response
217    including the supported authentication mechanisms. */
218 static bool smtp_endofresp(struct connectdata *conn, char *line, size_t len,
219                            int *resp)
220 {
221   struct smtp_conn *smtpc = &conn->proto.smtpc;
222   bool result = FALSE;
223   size_t wordlen;
224
225   if(len < 4 || !ISDIGIT(line[0]) || !ISDIGIT(line[1]) || !ISDIGIT(line[2]))
226     return FALSE;       /* Nothing for us */
227
228   /* Do we have a command response? */
229   result = (line[3] == ' ') ? TRUE : FALSE;
230   if(result)
231     *resp = curlx_sltosi(strtol(line, NULL, 10));
232
233   /* Are we processing EHLO command data? */
234   if(smtpc->state == SMTP_EHLO && (!result || (result && *resp/100 == 2))) {
235     line += 4;
236     len -= 4;
237
238     /* Does the server support the STARTTLS capability? */
239     if(len >= 8 && !memcmp(line, "STARTTLS", 8))
240       smtpc->tls_supported = TRUE;
241
242     /* Does the server support the SIZE capability? */
243     else if(len >= 4 && !memcmp(line, "SIZE", 4))
244       smtpc->size_supported = TRUE;
245
246     /* Do we have the authentication mechanism list? */
247     else if(len >= 5 && !memcmp(line, "AUTH ", 5)) {
248       line += 5;
249       len -= 5;
250
251       /* Loop through the data line */
252       for(;;) {
253         while(len &&
254               (*line == ' ' || *line == '\t' ||
255                *line == '\r' || *line == '\n')) {
256
257           line++;
258           len--;
259         }
260
261         if(!len)
262           break;
263
264         /* Extract the word */
265         for(wordlen = 0; wordlen < len && line[wordlen] != ' ' &&
266               line[wordlen] != '\t' && line[wordlen] != '\r' &&
267               line[wordlen] != '\n';)
268           wordlen++;
269
270         /* Test the word for a matching authentication mechanism */
271         if(wordlen == 5 && !memcmp(line, "LOGIN", 5))
272           smtpc->authmechs |= SASL_MECH_LOGIN;
273         else if(wordlen == 5 && !memcmp(line, "PLAIN", 5))
274           smtpc->authmechs |= SASL_MECH_PLAIN;
275         else if(wordlen == 8 && !memcmp(line, "CRAM-MD5", 8))
276           smtpc->authmechs |= SASL_MECH_CRAM_MD5;
277         else if(wordlen == 10 && !memcmp(line, "DIGEST-MD5", 10))
278           smtpc->authmechs |= SASL_MECH_DIGEST_MD5;
279         else if(wordlen == 6 && !memcmp(line, "GSSAPI", 6))
280           smtpc->authmechs |= SASL_MECH_GSSAPI;
281         else if(wordlen == 8 && !memcmp(line, "EXTERNAL", 8))
282           smtpc->authmechs |= SASL_MECH_EXTERNAL;
283         else if(wordlen == 4 && !memcmp(line, "NTLM", 4))
284           smtpc->authmechs |= SASL_MECH_NTLM;
285
286         line += wordlen;
287         len -= wordlen;
288       }
289     }
290   }
291
292   return result;
293 }
294
295 /* This is the ONLY way to change SMTP state! */
296 static void state(struct connectdata *conn, smtpstate newstate)
297 {
298   struct smtp_conn *smtpc = &conn->proto.smtpc;
299 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
300   /* for debug purposes */
301   static const char * const names[] = {
302     "STOP",
303     "SERVERGREET",
304     "EHLO",
305     "HELO",
306     "STARTTLS",
307     "UPGRADETLS",
308     "AUTH_PLAIN",
309     "AUTH_LOGIN",
310     "AUTH_LOGIN_PASSWD",
311     "AUTH_CRAMMD5",
312     "AUTH_DIGESTMD5",
313     "AUTH_DIGESTMD5_RESP",
314     "AUTH_NTLM",
315     "AUTH_NTLM_TYPE2MSG",
316     "AUTH",
317     "MAIL",
318     "RCPT",
319     "DATA",
320     "POSTDATA",
321     "QUIT",
322     /* LAST */
323   };
324
325   if(smtpc->state != newstate)
326     infof(conn->data, "SMTP %p state change from %s to %s\n",
327           smtpc, names[smtpc->state], names[newstate]);
328 #endif
329
330   smtpc->state = newstate;
331 }
332
333 static CURLcode smtp_state_ehlo(struct connectdata *conn)
334 {
335   CURLcode result = CURLE_OK;
336   struct smtp_conn *smtpc = &conn->proto.smtpc;
337
338   smtpc->authmechs = 0;         /* No known authentication mechanisms yet */
339   smtpc->authused = 0;          /* Clear the authentication mechanism used
340                                    for esmtp connections */
341   smtpc->tls_supported = FALSE; /* Clear the TLS capability */
342
343   /* Send the EHLO command */
344   result = Curl_pp_sendf(&smtpc->pp, "EHLO %s", smtpc->domain);
345
346   if(result)
347     return result;
348
349   state(conn, SMTP_EHLO);
350
351   return CURLE_OK;
352 }
353
354 static CURLcode smtp_state_helo(struct connectdata *conn)
355 {
356   CURLcode result = CURLE_OK;
357   struct smtp_conn *smtpc = &conn->proto.smtpc;
358
359   smtpc->authused = 0;          /* No authentication mechanism used in smtp
360                                    connections */
361
362   /* Send the HELO command */
363   result = Curl_pp_sendf(&smtpc->pp, "HELO %s", smtpc->domain);
364
365   if(result)
366     return result;
367
368   state(conn, SMTP_HELO);
369
370   return CURLE_OK;
371 }
372
373 static CURLcode smtp_state_starttls(struct connectdata *conn)
374 {
375   CURLcode result = CURLE_OK;
376
377   /* Send the STARTTLS command */
378   result = Curl_pp_sendf(&conn->proto.smtpc.pp, "STARTTLS");
379
380   if(!result)
381     state(conn, SMTP_STARTTLS);
382
383   return result;
384 }
385
386 static CURLcode smtp_state_upgrade_tls(struct connectdata *conn)
387 {
388   CURLcode result = CURLE_OK;
389   struct smtp_conn *smtpc = &conn->proto.smtpc;
390
391   /* Start the SSL connection */
392   result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &smtpc->ssldone);
393
394   if(!result) {
395     if(smtpc->state != SMTP_UPGRADETLS)
396       state(conn, SMTP_UPGRADETLS);
397
398     if(smtpc->ssldone) {
399       smtp_to_smtps(conn);
400       result = smtp_state_ehlo(conn);
401     }
402   }
403
404   return result;
405 }
406
407 static CURLcode smtp_authenticate(struct connectdata *conn)
408 {
409   CURLcode result = CURLE_OK;
410   struct smtp_conn *smtpc = &conn->proto.smtpc;
411   const char *mech = NULL;
412   char *initresp = NULL;
413   size_t len = 0;
414   smtpstate state1 = SMTP_STOP;
415   smtpstate state2 = SMTP_STOP;
416
417   /* Check we have a username and password to authenticate with and end the
418      connect phase if we don't */
419   if(!conn->bits.user_passwd) {
420     state(conn, SMTP_STOP);
421
422     return result;
423   }
424
425   /* Calculate the supported authentication mechanism, by decreasing order of
426      security, as well as the initial response where appropriate */
427 #ifndef CURL_DISABLE_CRYPTO_AUTH
428   if(smtpc->authmechs & SASL_MECH_DIGEST_MD5) {
429     mech = "DIGEST-MD5";
430     state1 = SMTP_AUTH_DIGESTMD5;
431     smtpc->authused = SASL_MECH_DIGEST_MD5;
432   }
433   else if(smtpc->authmechs & SASL_MECH_CRAM_MD5) {
434     mech = "CRAM-MD5";
435     state1 = SMTP_AUTH_CRAMMD5;
436     smtpc->authused = SASL_MECH_CRAM_MD5;
437   }
438   else
439 #endif
440 #ifdef USE_NTLM
441   if(smtpc->authmechs & SASL_MECH_NTLM) {
442     mech = "NTLM";
443     state1 = SMTP_AUTH_NTLM;
444     state2 = SMTP_AUTH_NTLM_TYPE2MSG;
445     smtpc->authused = SASL_MECH_NTLM;
446     result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
447                                                  &conn->ntlm,
448                                                  &initresp, &len);
449   }
450   else
451 #endif
452   if(smtpc->authmechs & SASL_MECH_LOGIN) {
453     mech = "LOGIN";
454     state1 = SMTP_AUTH_LOGIN;
455     state2 = SMTP_AUTH_LOGIN_PASSWD;
456     smtpc->authused = SASL_MECH_LOGIN;
457     result = Curl_sasl_create_login_message(conn->data, conn->user,
458                                             &initresp, &len);
459   }
460   else if(smtpc->authmechs & SASL_MECH_PLAIN) {
461     mech = "PLAIN";
462     state1 = SMTP_AUTH_PLAIN;
463     state2 = SMTP_AUTH;
464     smtpc->authused = SASL_MECH_PLAIN;
465     result = Curl_sasl_create_plain_message(conn->data, conn->user,
466                                             conn->passwd, &initresp, &len);
467   }
468   else {
469     /* Other mechanisms not supported */
470     infof(conn->data, "No known authentication mechanisms supported!\n");
471     result = CURLE_LOGIN_DENIED;
472   }
473
474   if(!result) {
475     /* Perform SASL based authentication */
476     if(initresp &&
477        strlen(mech) + len <= 512 - 8) { /* AUTH <mech> ...<crlf> */
478        result = Curl_pp_sendf(&smtpc->pp, "AUTH %s %s", mech, initresp);
479
480       if(!result)
481         state(conn, state2);
482     }
483     else {
484       result = Curl_pp_sendf(&smtpc->pp, "AUTH %s", mech);
485
486       if(!result)
487         state(conn, state1);
488     }
489
490     Curl_safefree(initresp);
491   }
492
493   return result;
494 }
495
496 /* For the initial server greeting */
497 static CURLcode smtp_state_servergreet_resp(struct connectdata *conn,
498                                             int smtpcode,
499                                             smtpstate instate)
500 {
501   CURLcode result = CURLE_OK;
502   struct SessionHandle *data = conn->data;
503
504   (void)instate; /* no use for this yet */
505
506   if(smtpcode/100 != 2) {
507     failf(data, "Got unexpected smtp-server response: %d", smtpcode);
508     return CURLE_FTP_WEIRD_SERVER_REPLY;
509   }
510
511   result = smtp_state_ehlo(conn);
512
513   return result;
514 }
515
516 /* For STARTTLS responses */
517 static CURLcode smtp_state_starttls_resp(struct connectdata *conn,
518                                          int smtpcode,
519                                          smtpstate instate)
520 {
521   CURLcode result = CURLE_OK;
522   struct SessionHandle *data = conn->data;
523
524   (void)instate; /* no use for this yet */
525
526   if(smtpcode != 220) {
527     if(data->set.use_ssl != CURLUSESSL_TRY) {
528       failf(data, "STARTTLS denied. %c", smtpcode);
529       result = CURLE_USE_SSL_FAILED;
530     }
531     else
532       result = smtp_authenticate(conn);
533   }
534   else
535     result = smtp_state_upgrade_tls(conn);
536
537   return result;
538 }
539
540 /* For EHLO responses */
541 static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode,
542                                      smtpstate instate)
543 {
544   CURLcode result = CURLE_OK;
545   struct SessionHandle *data = conn->data;
546   struct smtp_conn *smtpc = &conn->proto.smtpc;
547
548   (void)instate; /* no use for this yet */
549
550   if(smtpcode/100 != 2) {
551     if((data->set.use_ssl <= CURLUSESSL_TRY || conn->ssl[FIRSTSOCKET].use) &&
552      !conn->bits.user_passwd)
553       result = smtp_state_helo(conn);
554     else {
555       failf(data, "Remote access denied: %d", smtpcode);
556       result = CURLE_REMOTE_ACCESS_DENIED;
557     }
558   }
559   else if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
560     /* We don't have a SSL/TLS connection yet, but SSL is requested */
561     if(smtpc->tls_supported)
562       /* Switch to TLS connection now */
563       result = smtp_state_starttls(conn);
564     else if(data->set.use_ssl == CURLUSESSL_TRY)
565       /* Fallback and carry on with authentication */
566       result = smtp_authenticate(conn);
567     else {
568       failf(data, "STARTTLS not supported.");
569       result = CURLE_USE_SSL_FAILED;
570     }
571   }
572   else
573     result = smtp_authenticate(conn);
574
575   return result;
576 }
577
578 /* For HELO responses */
579 static CURLcode smtp_state_helo_resp(struct connectdata *conn, int smtpcode,
580                                      smtpstate instate)
581 {
582   CURLcode result = CURLE_OK;
583   struct SessionHandle *data = conn->data;
584
585   (void)instate; /* no use for this yet */
586
587   if(smtpcode/100 != 2) {
588     failf(data, "Remote access denied: %d", smtpcode);
589     result = CURLE_REMOTE_ACCESS_DENIED;
590   }
591   else
592     /* End of connect phase */
593     state(conn, SMTP_STOP);
594
595   return result;
596 }
597
598 /* For AUTH PLAIN (without initial response) responses */
599 static CURLcode smtp_state_auth_plain_resp(struct connectdata *conn,
600                                            int smtpcode,
601                                            smtpstate instate)
602 {
603   CURLcode result = CURLE_OK;
604   struct SessionHandle *data = conn->data;
605   size_t len = 0;
606   char *plainauth = NULL;
607
608   (void)instate; /* no use for this yet */
609
610   if(smtpcode != 334) {
611     failf(data, "Access denied: %d", smtpcode);
612     result = CURLE_LOGIN_DENIED;
613   }
614   else {
615     /* Create the authorisation message */
616     result = Curl_sasl_create_plain_message(conn->data, conn->user,
617                                             conn->passwd, &plainauth, &len);
618
619     /* Send the message */
620     if(!result) {
621       if(plainauth) {
622         result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", plainauth);
623
624         if(!result)
625           state(conn, SMTP_AUTH);
626       }
627
628       Curl_safefree(plainauth);
629     }
630   }
631
632   return result;
633 }
634
635 /* For AUTH LOGIN (without initial response) responses */
636 static CURLcode smtp_state_auth_login_resp(struct connectdata *conn,
637                                            int smtpcode,
638                                            smtpstate instate)
639 {
640   CURLcode result = CURLE_OK;
641   struct SessionHandle *data = conn->data;
642   size_t len = 0;
643   char *authuser = NULL;
644
645   (void)instate; /* no use for this yet */
646
647   if(smtpcode != 334) {
648     failf(data, "Access denied: %d", smtpcode);
649     result = CURLE_LOGIN_DENIED;
650   }
651   else {
652     /* Create the user message */
653     result = Curl_sasl_create_login_message(conn->data, conn->user,
654                                             &authuser, &len);
655
656     /* Send the user */
657     if(!result) {
658       if(authuser) {
659         result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authuser);
660
661         if(!result)
662           state(conn, SMTP_AUTH_LOGIN_PASSWD);
663       }
664
665       Curl_safefree(authuser);
666     }
667   }
668
669   return result;
670 }
671
672 /* For AUTH LOGIN user entry responses */
673 static CURLcode smtp_state_auth_login_password_resp(struct connectdata *conn,
674                                                     int smtpcode,
675                                                     smtpstate instate)
676 {
677   CURLcode result = CURLE_OK;
678   struct SessionHandle *data = conn->data;
679   size_t len = 0;
680   char *authpasswd = NULL;
681
682   (void)instate; /* no use for this yet */
683
684   if(smtpcode != 334) {
685     failf(data, "Access denied: %d", smtpcode);
686     result = CURLE_LOGIN_DENIED;
687   }
688   else {
689     /* Create the password message */
690     result = Curl_sasl_create_login_message(conn->data, conn->passwd,
691                                             &authpasswd, &len);
692
693     /* Send the password */
694     if(!result) {
695       if(authpasswd) {
696         result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authpasswd);
697
698         if(!result)
699           state(conn, SMTP_AUTH);
700       }
701
702       Curl_safefree(authpasswd);
703     }
704   }
705
706   return result;
707 }
708
709 #ifndef CURL_DISABLE_CRYPTO_AUTH
710 /* For AUTH CRAM-MD5 responses */
711 static CURLcode smtp_state_auth_cram_resp(struct connectdata *conn,
712                                           int smtpcode,
713                                           smtpstate instate)
714 {
715   CURLcode result = CURLE_OK;
716   struct SessionHandle *data = conn->data;
717   char *chlg64 = data->state.buffer;
718   size_t len = 0;
719   char *rplyb64 = NULL;
720
721   (void)instate; /* no use for this yet */
722
723   if(smtpcode != 334) {
724     failf(data, "Access denied: %d", smtpcode);
725     return CURLE_LOGIN_DENIED;
726   }
727
728   /* Get the challenge */
729   for(chlg64 += 4; *chlg64 == ' ' || *chlg64 == '\t'; chlg64++)
730     ;
731
732   /* Terminate the challenge */
733   if(*chlg64 != '=') {
734     for(len = strlen(chlg64); len--;)
735       if(chlg64[len] != '\r' && chlg64[len] != '\n' && chlg64[len] != ' ' &&
736          chlg64[len] != '\t')
737         break;
738
739     if(++len) {
740       chlg64[len] = '\0';
741     }
742   }
743
744   /* Create the response message */
745   result = Curl_sasl_create_cram_md5_message(data, chlg64, conn->user,
746                                              conn->passwd, &rplyb64, &len);
747
748   /* Send the response */
749   if(!result) {
750     if(rplyb64) {
751       result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", rplyb64);
752
753       if(!result)
754         state(conn, SMTP_AUTH);
755     }
756
757     Curl_safefree(rplyb64);
758   }
759
760   return result;
761 }
762
763 /* For AUTH DIGEST-MD5 challenge responses */
764 static CURLcode smtp_state_auth_digest_resp(struct connectdata *conn,
765                                             int smtpcode,
766                                             smtpstate instate)
767 {
768   CURLcode result = CURLE_OK;
769   struct SessionHandle *data = conn->data;
770   char *chlg64 = data->state.buffer;
771   size_t len = 0;
772   char *rplyb64 = NULL;
773
774   (void)instate; /* no use for this yet */
775
776   if(smtpcode != 334) {
777     failf(data, "Access denied: %d", smtpcode);
778     return CURLE_LOGIN_DENIED;
779   }
780
781   /* Get the challenge */
782   for(chlg64 += 4; *chlg64 == ' ' || *chlg64 == '\t'; chlg64++)
783     ;
784
785   /* Create the response message */
786   result = Curl_sasl_create_digest_md5_message(data, chlg64, conn->user,
787                                                conn->passwd, "smtp",
788                                                &rplyb64, &len);
789
790   /* Send the response */
791   if(!result) {
792     if(rplyb64) {
793       result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", rplyb64);
794
795       if(!result)
796         state(conn, SMTP_AUTH_DIGESTMD5_RESP);
797     }
798
799     Curl_safefree(rplyb64);
800   }
801
802   return result;
803 }
804
805 /* For AUTH DIGEST-MD5 challenge-response responses */
806 static CURLcode smtp_state_auth_digest_resp_resp(struct connectdata *conn,
807                                                  int smtpcode,
808                                                  smtpstate instate)
809 {
810   CURLcode result = CURLE_OK;
811   struct SessionHandle *data = conn->data;
812
813   (void)instate; /* no use for this yet */
814
815   if(smtpcode != 334) {
816     failf(data, "Authentication failed: %d", smtpcode);
817     result = CURLE_LOGIN_DENIED;
818   }
819   else {
820     /* Send an empty response */
821     result = Curl_pp_sendf(&conn->proto.smtpc.pp, "");
822
823     if(!result)
824       state(conn, SMTP_AUTH);
825   }
826
827   return result;
828 }
829
830 #endif
831
832 #ifdef USE_NTLM
833 /* For AUTH NTLM (without initial response) responses */
834 static CURLcode smtp_state_auth_ntlm_resp(struct connectdata *conn,
835                                           int smtpcode,
836                                           smtpstate instate)
837 {
838   CURLcode result = CURLE_OK;
839   struct SessionHandle *data = conn->data;
840   char *type1msg = NULL;
841   size_t len = 0;
842
843   (void)instate; /* no use for this yet */
844
845   if(smtpcode != 334) {
846     failf(data, "Access denied: %d", smtpcode);
847     result = CURLE_LOGIN_DENIED;
848   }
849   else {
850     /* Create the type-1 message */
851     result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
852                                                  &conn->ntlm,
853                                                  &type1msg, &len);
854
855     /* Send the message */
856     if(!result) {
857       if(type1msg) {
858         result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", type1msg);
859
860         if(!result)
861           state(conn, SMTP_AUTH_NTLM_TYPE2MSG);
862       }
863
864       Curl_safefree(type1msg);
865     }
866   }
867
868   return result;
869 }
870
871 /* For NTLM type-2 responses (sent in reponse to our type-1 message) */
872 static CURLcode smtp_state_auth_ntlm_type2msg_resp(struct connectdata *conn,
873                                                    int smtpcode,
874                                                    smtpstate instate)
875 {
876   CURLcode result = CURLE_OK;
877   struct SessionHandle *data = conn->data;
878   char *type3msg = NULL;
879   size_t len = 0;
880
881   (void)instate; /* no use for this yet */
882
883   if(smtpcode != 334) {
884     failf(data, "Access denied: %d", smtpcode);
885     result = CURLE_LOGIN_DENIED;
886   }
887   else {
888     /* Create the type-3 message */
889     result = Curl_sasl_create_ntlm_type3_message(data,
890                                                  data->state.buffer + 4,
891                                                  conn->user, conn->passwd,
892                                                  &conn->ntlm,
893                                                  &type3msg, &len);
894
895     /* Send the message */
896     if(!result) {
897       if(type3msg) {
898         result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", type3msg);
899
900         if(!result)
901           state(conn, SMTP_AUTH);
902       }
903
904       Curl_safefree(type3msg);
905     }
906   }
907
908   return result;
909 }
910 #endif
911
912 /* For the final responses to the AUTH sequence */
913 static CURLcode smtp_state_auth_final_resp(struct connectdata *conn,
914                                            int smtpcode,
915                                            smtpstate instate)
916 {
917   CURLcode result = CURLE_OK;
918   struct SessionHandle *data = conn->data;
919
920   (void)instate; /* no use for this yet */
921
922   if(smtpcode != 235) {
923     failf(data, "Authentication failed: %d", smtpcode);
924     result = CURLE_LOGIN_DENIED;
925   }
926   else
927     /* End of connect phase */
928     state(conn, SMTP_STOP);
929
930   return result;
931 }
932
933 /* Start the DO phase */
934 static CURLcode smtp_mail(struct connectdata *conn)
935 {
936   char *from = NULL;
937   char *auth = NULL;
938   char *size = NULL;
939   CURLcode result = CURLE_OK;
940   struct SessionHandle *data = conn->data;
941
942   /* Calculate the FROM parameter */
943   if(!data->set.str[STRING_MAIL_FROM])
944     /* Null reverse-path, RFC-2821, sect. 3.7 */
945     from = strdup("<>");
946   else if(data->set.str[STRING_MAIL_FROM][0] == '<')
947     from = aprintf("%s", data->set.str[STRING_MAIL_FROM]);
948   else
949     from = aprintf("<%s>", data->set.str[STRING_MAIL_FROM]);
950
951   if(!from)
952     return CURLE_OUT_OF_MEMORY;
953
954   /* Calculate the optional AUTH parameter */
955   if(data->set.str[STRING_MAIL_AUTH] && conn->proto.smtpc.authused) {
956     if(data->set.str[STRING_MAIL_AUTH][0] != '\0')
957       auth = aprintf("%s", data->set.str[STRING_MAIL_AUTH]);
958     else
959       /* Empty AUTH, RFC-2554, sect. 5 */
960       auth = strdup("<>");
961
962     if(!auth) {
963       Curl_safefree(from);
964
965       return CURLE_OUT_OF_MEMORY;
966     }
967   }
968
969   /* calculate the optional SIZE parameter */
970   if(conn->proto.smtpc.size_supported && conn->data->set.infilesize > 0) {
971     size = aprintf("%" FORMAT_OFF_T, data->set.infilesize);
972
973     if(!size) {
974       Curl_safefree(from);
975       Curl_safefree(auth);
976
977       return CURLE_OUT_OF_MEMORY;
978     }
979   }
980
981   /* Send the MAIL command */
982   if(!auth && !size)
983     result = Curl_pp_sendf(&conn->proto.smtpc.pp,
984                            "MAIL FROM:%s", from);
985   else if(auth && !size)
986     result = Curl_pp_sendf(&conn->proto.smtpc.pp,
987                            "MAIL FROM:%s AUTH=%s", from, auth);
988   else if(auth && size)
989     result = Curl_pp_sendf(&conn->proto.smtpc.pp,
990                            "MAIL FROM:%s AUTH=%s SIZE=%s", from, auth, size);
991   else
992     result = Curl_pp_sendf(&conn->proto.smtpc.pp,
993                            "MAIL FROM:%s SIZE=%s", from, size);
994
995   Curl_safefree(from);
996   Curl_safefree(auth);
997   Curl_safefree(size);
998
999   if(result)
1000     return result;
1001
1002   state(conn, SMTP_MAIL);
1003
1004   return result;
1005 }
1006
1007 static CURLcode smtp_rcpt_to(struct connectdata *conn)
1008 {
1009   CURLcode result = CURLE_OK;
1010   struct smtp_conn *smtpc = &conn->proto.smtpc;
1011
1012   /* Send the RCPT TO command */
1013   if(smtpc->rcpt) {
1014     if(smtpc->rcpt->data[0] == '<')
1015       result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:%s",
1016                              smtpc->rcpt->data);
1017     else
1018       result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:<%s>",
1019                              smtpc->rcpt->data);
1020     if(!result)
1021       state(conn, SMTP_RCPT);
1022   }
1023
1024   return result;
1025 }
1026
1027 /* For MAIL responses */
1028 static CURLcode smtp_state_mail_resp(struct connectdata *conn, int smtpcode,
1029                                      smtpstate instate)
1030 {
1031   CURLcode result = CURLE_OK;
1032   struct SessionHandle *data = conn->data;
1033
1034   (void)instate; /* no use for this yet */
1035
1036   if(smtpcode/100 != 2) {
1037     failf(data, "MAIL failed: %d", smtpcode);
1038     result = CURLE_SEND_ERROR;
1039     state(conn, SMTP_STOP);
1040   }
1041   else {
1042     struct smtp_conn *smtpc = &conn->proto.smtpc;
1043     smtpc->rcpt = data->set.mail_rcpt;
1044
1045     result = smtp_rcpt_to(conn);
1046   }
1047
1048   return result;
1049 }
1050
1051 /* For RCPT responses */
1052 static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, int smtpcode,
1053                                      smtpstate instate)
1054 {
1055   CURLcode result = CURLE_OK;
1056   struct SessionHandle *data = conn->data;
1057
1058   (void)instate; /* no use for this yet */
1059
1060   if(smtpcode/100 != 2) {
1061     failf(data, "RCPT failed: %d", smtpcode);
1062     result = CURLE_SEND_ERROR;
1063     state(conn, SMTP_STOP);
1064   }
1065   else {
1066     struct smtp_conn *smtpc = &conn->proto.smtpc;
1067
1068     if(smtpc->rcpt) {
1069       smtpc->rcpt = smtpc->rcpt->next;
1070       result = smtp_rcpt_to(conn);
1071
1072       /* If we failed or still are sending RCPT data then return */
1073       if(result || smtpc->rcpt)
1074         return result;
1075     }
1076
1077     /* Send the DATA command */
1078     result = Curl_pp_sendf(&conn->proto.smtpc.pp, "DATA");
1079
1080     if(result)
1081       return result;
1082
1083     state(conn, SMTP_DATA);
1084   }
1085
1086   return result;
1087 }
1088
1089 /* For DATA response */
1090 static CURLcode smtp_state_data_resp(struct connectdata *conn, int smtpcode,
1091                                      smtpstate instate)
1092 {
1093   struct SessionHandle *data = conn->data;
1094   struct SMTP *smtp = data->state.proto.smtp;
1095
1096   (void)instate; /* no use for this yet */
1097
1098   if(smtpcode != 354) {
1099     state(conn, SMTP_STOP);
1100     return CURLE_SEND_ERROR;
1101   }
1102
1103   /* SMTP upload */
1104   Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
1105                       FIRSTSOCKET, smtp->bytecountp);
1106
1107   /* End of do phase */
1108   state(conn, SMTP_STOP);
1109
1110   return CURLE_OK;
1111 }
1112
1113 /* For POSTDATA responses, which are received after the entire DATA
1114    part has been sent to the server */
1115 static CURLcode smtp_state_postdata_resp(struct connectdata *conn,
1116                                          int smtpcode,
1117                                          smtpstate instate)
1118 {
1119   CURLcode result = CURLE_OK;
1120
1121   (void)instate; /* no use for this yet */
1122
1123   if(smtpcode != 250)
1124     result = CURLE_RECV_ERROR;
1125
1126   /* End of done phase */
1127   state(conn, SMTP_STOP);
1128
1129   return result;
1130 }
1131
1132 static CURLcode smtp_statemach_act(struct connectdata *conn)
1133 {
1134   CURLcode result = CURLE_OK;
1135   curl_socket_t sock = conn->sock[FIRSTSOCKET];
1136   struct SessionHandle *data = conn->data;
1137   int smtpcode;
1138   struct smtp_conn *smtpc = &conn->proto.smtpc;
1139   struct pingpong *pp = &smtpc->pp;
1140   size_t nread = 0;
1141
1142   /* Busy upgrading the connection; right now all I/O is SSL/TLS, not SMTP */
1143   if(smtpc->state == SMTP_UPGRADETLS)
1144     return smtp_state_upgrade_tls(conn);
1145
1146   /* Flush any data that needs to be sent */
1147   if(pp->sendleft)
1148     return Curl_pp_flushsend(pp);
1149
1150   /* Read the response from the server */
1151   result = Curl_pp_readresp(sock, pp, &smtpcode, &nread);
1152   if(result)
1153     return result;
1154
1155   /* Store the latest response for later retrieval */
1156   if(smtpc->state != SMTP_QUIT)
1157     data->info.httpcode = smtpcode;
1158
1159   if(smtpcode) {
1160     /* We have now received a full SMTP server response */
1161     switch(smtpc->state) {
1162     case SMTP_SERVERGREET:
1163       result = smtp_state_servergreet_resp(conn, smtpcode, smtpc->state);
1164       break;
1165
1166     case SMTP_EHLO:
1167       result = smtp_state_ehlo_resp(conn, smtpcode, smtpc->state);
1168       break;
1169
1170     case SMTP_HELO:
1171       result = smtp_state_helo_resp(conn, smtpcode, smtpc->state);
1172       break;
1173
1174     case SMTP_STARTTLS:
1175       result = smtp_state_starttls_resp(conn, smtpcode, smtpc->state);
1176       break;
1177
1178     case SMTP_AUTH_PLAIN:
1179       result = smtp_state_auth_plain_resp(conn, smtpcode, smtpc->state);
1180       break;
1181
1182     case SMTP_AUTH_LOGIN:
1183       result = smtp_state_auth_login_resp(conn, smtpcode, smtpc->state);
1184       break;
1185
1186     case SMTP_AUTH_LOGIN_PASSWD:
1187       result = smtp_state_auth_login_password_resp(conn, smtpcode,
1188                                                    smtpc->state);
1189       break;
1190
1191 #ifndef CURL_DISABLE_CRYPTO_AUTH
1192     case SMTP_AUTH_CRAMMD5:
1193       result = smtp_state_auth_cram_resp(conn, smtpcode, smtpc->state);
1194       break;
1195
1196     case SMTP_AUTH_DIGESTMD5:
1197       result = smtp_state_auth_digest_resp(conn, smtpcode, smtpc->state);
1198       break;
1199
1200     case SMTP_AUTH_DIGESTMD5_RESP:
1201       result = smtp_state_auth_digest_resp_resp(conn, smtpcode, smtpc->state);
1202       break;
1203 #endif
1204
1205 #ifdef USE_NTLM
1206     case SMTP_AUTH_NTLM:
1207       result = smtp_state_auth_ntlm_resp(conn, smtpcode, smtpc->state);
1208       break;
1209
1210     case SMTP_AUTH_NTLM_TYPE2MSG:
1211       result = smtp_state_auth_ntlm_type2msg_resp(conn, smtpcode,
1212                                                   smtpc->state);
1213       break;
1214 #endif
1215
1216     case SMTP_AUTH:
1217       result = smtp_state_auth_final_resp(conn, smtpcode, smtpc->state);
1218       break;
1219
1220     case SMTP_MAIL:
1221       result = smtp_state_mail_resp(conn, smtpcode, smtpc->state);
1222       break;
1223
1224     case SMTP_RCPT:
1225       result = smtp_state_rcpt_resp(conn, smtpcode, smtpc->state);
1226       break;
1227
1228     case SMTP_DATA:
1229       result = smtp_state_data_resp(conn, smtpcode, smtpc->state);
1230       break;
1231
1232     case SMTP_POSTDATA:
1233       result = smtp_state_postdata_resp(conn, smtpcode, smtpc->state);
1234       break;
1235
1236     case SMTP_QUIT:
1237       /* fallthrough, just stop! */
1238     default:
1239       /* internal error */
1240       state(conn, SMTP_STOP);
1241       break;
1242     }
1243   }
1244
1245   return result;
1246 }
1247
1248 /* Called repeatedly until done from multi.c */
1249 static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done)
1250 {
1251   CURLcode result = CURLE_OK;
1252   struct smtp_conn *smtpc = &conn->proto.smtpc;
1253
1254   if((conn->handler->flags & PROTOPT_SSL) && !smtpc->ssldone)
1255     result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &smtpc->ssldone);
1256   else
1257     result = Curl_pp_statemach(&smtpc->pp, FALSE);
1258
1259   *done = (smtpc->state == SMTP_STOP) ? TRUE : FALSE;
1260
1261   return result;
1262 }
1263
1264 static CURLcode smtp_block_statemach(struct connectdata *conn)
1265 {
1266   CURLcode result = CURLE_OK;
1267   struct smtp_conn *smtpc = &conn->proto.smtpc;
1268
1269   while(smtpc->state != SMTP_STOP) {
1270     result = Curl_pp_statemach(&smtpc->pp, TRUE);
1271     if(result)
1272       break;
1273   }
1274
1275   return result;
1276 }
1277
1278 /* Allocate and initialize the SMTP struct for the current SessionHandle if
1279    required */
1280 static CURLcode smtp_init(struct connectdata *conn)
1281 {
1282   struct SessionHandle *data = conn->data;
1283   struct SMTP *smtp = data->state.proto.smtp;
1284
1285   if(!smtp) {
1286     smtp = data->state.proto.smtp = calloc(sizeof(struct SMTP), 1);
1287     if(!smtp)
1288       return CURLE_OUT_OF_MEMORY;
1289   }
1290
1291   /* Get some initial data into the smtp struct */
1292   smtp->bytecountp = &data->req.bytecount;
1293
1294   /* No need to duplicate user+password, the connectdata struct won't change
1295      during a session, but we re-init them here since on subsequent inits
1296      since the conn struct may have changed or been replaced.
1297   */
1298   smtp->user = conn->user;
1299   smtp->passwd = conn->passwd;
1300
1301   return CURLE_OK;
1302 }
1303
1304 /* For the SMTP "protocol connect" and "doing" phases only */
1305 static int smtp_getsock(struct connectdata *conn, curl_socket_t *socks,
1306                         int numsocks)
1307 {
1308   return Curl_pp_getsock(&conn->proto.smtpc.pp, socks, numsocks);
1309 }
1310
1311 /***********************************************************************
1312  *
1313  * smtp_connect()
1314  *
1315  * This function should do everything that is to be considered a part of
1316  * the connection phase.
1317  *
1318  * The variable pointed to by 'done' will be TRUE if the protocol-layer
1319  * connect phase is done when this function returns, or FALSE if not. When
1320  * called as a part of the easy interface, it will always be TRUE.
1321  */
1322 static CURLcode smtp_connect(struct connectdata *conn, bool *done)
1323 {
1324   CURLcode result = CURLE_OK;
1325   struct smtp_conn *smtpc = &conn->proto.smtpc;
1326   struct pingpong *pp = &smtpc->pp;
1327   const char *path = conn->data->state.path;
1328   char localhost[HOSTNAME_MAX + 1];
1329
1330   *done = FALSE; /* default to not done yet */
1331
1332   /* If there already is a protocol-specific struct allocated for this
1333      sessionhandle, deal with it */
1334   Curl_reset_reqproto(conn);
1335
1336   /* Initialise the SMTP layer */
1337   result = smtp_init(conn);
1338   if(result)
1339     return result;
1340
1341   /* We always support persistent connections in SMTP */
1342   conn->bits.close = FALSE;
1343
1344   /* Set the default response time-out */
1345   pp->response_time = RESP_TIMEOUT;
1346   pp->statemach_act = smtp_statemach_act;
1347   pp->endofresp = smtp_endofresp;
1348   pp->conn = conn;
1349
1350   /* Initialise the pingpong layer */
1351   Curl_pp_init(pp);
1352
1353   /* Calculate the path if necessary */
1354   if(!*path) {
1355     if(!Curl_gethostname(localhost, sizeof(localhost)))
1356       path = localhost;
1357     else
1358       path = "localhost";
1359   }
1360
1361   /* URL decode the path and use it as the domain in our EHLO */
1362   result = Curl_urldecode(conn->data, path, 0, &smtpc->domain, NULL, TRUE);
1363   if(result)
1364     return result;
1365
1366   /* Start off waiting for the server greeting response */
1367   state(conn, SMTP_SERVERGREET);
1368
1369   result = smtp_multi_statemach(conn, done);
1370
1371   return result;
1372 }
1373
1374 /***********************************************************************
1375  *
1376  * smtp_done()
1377  *
1378  * The DONE function. This does what needs to be done after a single DO has
1379  * performed.
1380  *
1381  * Input argument is already checked for validity.
1382  */
1383 static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
1384                           bool premature)
1385 {
1386   CURLcode result = CURLE_OK;
1387   struct SessionHandle *data = conn->data;
1388   struct SMTP *smtp = data->state.proto.smtp;
1389   ssize_t bytes_written;
1390
1391   (void)premature;
1392
1393   if(!smtp)
1394     /* When the easy handle is removed from the multi while libcurl is still
1395      * trying to resolve the host name, it seems that the SMTP struct is not
1396      * yet initialized, but the removal action calls Curl_done() which calls
1397      * this function. So we simply return success if no SMTP pointer is set.
1398      */
1399     return CURLE_OK;
1400
1401   if(status) {
1402     conn->bits.close = TRUE; /* marked for closure */
1403     result = status;         /* use the already set error code */
1404   }
1405   else if(!data->set.connect_only) {
1406     struct smtp_conn *smtpc = &conn->proto.smtpc;
1407     struct pingpong *pp = &smtpc->pp;
1408
1409     /* Send the end of block data */
1410     result = Curl_write(conn,
1411                         conn->writesockfd,  /* socket to send to */
1412                         SMTP_EOB,           /* buffer pointer */
1413                         SMTP_EOB_LEN,       /* buffer size */
1414                         &bytes_written);    /* actually sent away */
1415
1416     if(result)
1417       return result;
1418
1419     if(bytes_written != SMTP_EOB_LEN) {
1420       /* The whole chunk was not sent so keep it around and adjust the
1421          pingpong structure accordingly */
1422       pp->sendthis = strdup(SMTP_EOB);
1423       pp->sendsize = SMTP_EOB_LEN;
1424       pp->sendleft = SMTP_EOB_LEN - bytes_written;
1425     }
1426     else
1427       /* Successfully sent so adjust the response timeout relative to now */
1428       pp->response = Curl_tvnow();
1429
1430     state(conn, SMTP_POSTDATA);
1431
1432     /* Run the state-machine
1433
1434        TODO: when the multi interface is used, this _really_ should be using
1435        the smtp_multi_statemach function but we have no general support for
1436        non-blocking DONE operations, not in the multi state machine and with
1437        Curl_done() invokes on several places in the code!
1438     */
1439     result = smtp_block_statemach(conn);
1440   }
1441
1442   /* Clear the transfer mode for the next request */
1443   smtp->transfer = FTPTRANSFER_BODY;
1444
1445   return result;
1446 }
1447
1448 /***********************************************************************
1449  *
1450  * smtp_perform()
1451  *
1452  * This is the actual DO function for SMTP. Get a file/directory according to
1453  * the options previously setup.
1454  */
1455 static CURLcode smtp_perform(struct connectdata *conn, bool *connected,
1456                              bool *dophase_done)
1457 {
1458   /* This is SMTP and no proxy */
1459   CURLcode result = CURLE_OK;
1460
1461   DEBUGF(infof(conn->data, "DO phase starts\n"));
1462
1463   if(conn->data->set.opt_no_body) {
1464     /* Requested no body means no transfer */
1465     struct SMTP *smtp = conn->data->state.proto.smtp;
1466     smtp->transfer = FTPTRANSFER_INFO;
1467   }
1468
1469   *dophase_done = FALSE; /* not done yet */
1470
1471   /* Start the first command in the DO phase */
1472   result = smtp_mail(conn);
1473   if(result)
1474     return result;
1475
1476   /* run the state-machine */
1477   result = smtp_multi_statemach(conn, dophase_done);
1478
1479   *connected = conn->bits.tcpconnect[FIRSTSOCKET];
1480
1481   if(*dophase_done)
1482     DEBUGF(infof(conn->data, "DO phase is complete\n"));
1483
1484   return result;
1485 }
1486
1487 /***********************************************************************
1488  *
1489  * smtp_do()
1490  *
1491  * This function is registered as 'curl_do' function. It decodes the path
1492  * parts etc as a wrapper to the actual DO function (smtp_perform).
1493  *
1494  * The input argument is already checked for validity.
1495  */
1496 static CURLcode smtp_do(struct connectdata *conn, bool *done)
1497 {
1498   CURLcode result = CURLE_OK;
1499
1500   *done = FALSE; /* default to false */
1501
1502   /*
1503     Since connections can be re-used between SessionHandles, this might be a
1504     connection already existing but on a fresh SessionHandle struct so we must
1505     make sure we have a good 'struct SMTP' to play with. For new connections,
1506     the struct SMTP is allocated and setup in the smtp_connect() function.
1507   */
1508   Curl_reset_reqproto(conn);
1509   result = smtp_init(conn);
1510   if(result)
1511     return result;
1512
1513   result = smtp_regular_transfer(conn, done);
1514
1515   return result;
1516 }
1517
1518 /***********************************************************************
1519  *
1520  * smtp_quit()
1521  *
1522  * This should be called before calling sclose().  We should then wait for the
1523  * response from the server before returning. The calling code should then try
1524  * to close the connection.
1525  */
1526 static CURLcode smtp_quit(struct connectdata *conn)
1527 {
1528   CURLcode result = CURLE_OK;
1529
1530   result = Curl_pp_sendf(&conn->proto.smtpc.pp, "QUIT");
1531   if(result)
1532     return result;
1533
1534   state(conn, SMTP_QUIT);
1535
1536   result = smtp_block_statemach(conn);
1537
1538   return result;
1539 }
1540
1541 /***********************************************************************
1542  *
1543  * smtp_disconnect()
1544  *
1545  * Disconnect from an SMTP server. Cleanup protocol-specific per-connection
1546  * resources. BLOCKING.
1547  */
1548 static CURLcode smtp_disconnect(struct connectdata *conn,
1549                                 bool dead_connection)
1550 {
1551   struct smtp_conn *smtpc = &conn->proto.smtpc;
1552
1553   /* We cannot send quit unconditionally. If this connection is stale or
1554      bad in any way, sending quit and waiting around here will make the
1555      disconnect wait in vain and cause more problems than we need to */
1556
1557   /* The SMTP session may or may not have been allocated/setup at this
1558      point! */
1559   if(!dead_connection && smtpc->pp.conn)
1560     (void)smtp_quit(conn); /* ignore errors on QUIT */
1561
1562   /* Disconnect from the server */
1563   Curl_pp_disconnect(&smtpc->pp);
1564
1565   /* Cleanup the SASL module */
1566   Curl_sasl_cleanup(conn, smtpc->authused);
1567
1568   /* Cleanup our connection based variables */
1569   Curl_safefree(smtpc->domain);
1570
1571   return CURLE_OK;
1572 }
1573
1574 /* Call this when the DO phase has completed */
1575 static CURLcode smtp_dophase_done(struct connectdata *conn, bool connected)
1576 {
1577   struct SMTP *smtp = conn->data->state.proto.smtp;
1578
1579   (void)connected;
1580
1581   if(smtp->transfer != FTPTRANSFER_BODY)
1582     /* no data to transfer */
1583     Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1584
1585   return CURLE_OK;
1586 }
1587
1588 /* Called from multi.c while DOing */
1589 static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done)
1590 {
1591   CURLcode result = smtp_multi_statemach(conn, dophase_done);
1592
1593   if(result)
1594     DEBUGF(infof(conn->data, "DO phase failed\n"));
1595   else {
1596     if(*dophase_done) {
1597       result = smtp_dophase_done(conn, FALSE /* not connected */);
1598
1599       DEBUGF(infof(conn->data, "DO phase is complete\n"));
1600     }
1601   }
1602
1603   return result;
1604 }
1605
1606 /***********************************************************************
1607  *
1608  * smtp_regular_transfer()
1609  *
1610  * The input argument is already checked for validity.
1611  *
1612  * Performs all commands done before a regular transfer between a local and a
1613  * remote host.
1614  */
1615 static CURLcode smtp_regular_transfer(struct connectdata *conn,
1616                                       bool *dophase_done)
1617 {
1618   CURLcode result = CURLE_OK;
1619   bool connected = FALSE;
1620   struct SessionHandle *data = conn->data;
1621
1622   /* Make sure size is unknown at this point */
1623   data->req.size = -1;
1624
1625   Curl_pgrsSetUploadCounter(data, 0);
1626   Curl_pgrsSetDownloadCounter(data, 0);
1627   Curl_pgrsSetUploadSize(data, 0);
1628   Curl_pgrsSetDownloadSize(data, 0);
1629
1630   result = smtp_perform(conn, &connected, dophase_done);
1631
1632   if(!result) {
1633     if(!*dophase_done)
1634       /* The DO phase has not completed yet */
1635       return CURLE_OK;
1636
1637     result = smtp_dophase_done(conn, connected);
1638   }
1639
1640   return result;
1641 }
1642
1643 static CURLcode smtp_setup_connection(struct connectdata *conn)
1644 {
1645   struct SessionHandle *data = conn->data;
1646
1647   if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
1648     /* Unless we have asked to tunnel SMTP operations through the proxy, we
1649        switch and use HTTP operations only */
1650 #ifndef CURL_DISABLE_HTTP
1651     if(conn->handler == &Curl_handler_smtp)
1652       conn->handler = &Curl_handler_smtp_proxy;
1653     else {
1654 #ifdef USE_SSL
1655       conn->handler = &Curl_handler_smtps_proxy;
1656 #else
1657       failf(data, "SMTPS not supported!");
1658       return CURLE_UNSUPPORTED_PROTOCOL;
1659 #endif
1660     }
1661
1662     /* We explicitly mark this connection as persistent here as we're doing
1663        SMTP over HTTP and thus we accidentally avoid setting this value
1664        otherwise */
1665     conn->bits.close = FALSE;
1666 #else
1667     failf(data, "SMTP over http proxy requires HTTP support built-in!");
1668     return CURLE_UNSUPPORTED_PROTOCOL;
1669 #endif
1670   }
1671
1672   data->state.path++;   /* don't include the initial slash */
1673
1674   return CURLE_OK;
1675 }
1676
1677 CURLcode Curl_smtp_escape_eob(struct connectdata *conn, ssize_t nread)
1678 {
1679   /* When sending a SMTP payload we must detect CRLF. sequences making sure
1680      they are sent as CRLF.. instead, as a . on the beginning of a line will
1681      be deleted by the server when not part of an EOB terminator and a
1682      genuine CRLF.CRLF which isn't escaped will wrongly be detected as end of
1683      data by the server.
1684   */
1685   ssize_t i;
1686   ssize_t si;
1687   struct smtp_conn *smtpc = &conn->proto.smtpc;
1688   struct SessionHandle *data = conn->data;
1689
1690   /* Do we need to allocate the scatch buffer? */
1691   if(!data->state.scratch) {
1692     data->state.scratch = malloc(2 * BUFSIZE);
1693
1694     if(!data->state.scratch) {
1695       failf (data, "Failed to alloc scratch buffer!");
1696       return CURLE_OUT_OF_MEMORY;
1697     }
1698   }
1699
1700   /* This loop can be improved by some kind of Boyer-Moore style of
1701      approach but that is saved for later... */
1702   for(i = 0, si = 0; i < nread; i++) {
1703     if(SMTP_EOB[smtpc->eob] == data->req.upload_fromhere[i])
1704       smtpc->eob++;
1705     else if(smtpc->eob) {
1706       /* A previous substring matched so output that first */
1707       memcpy(&data->state.scratch[si], SMTP_EOB, smtpc->eob);
1708       si += smtpc->eob;
1709
1710       /* Then compare the first byte */
1711       if(SMTP_EOB[0] == data->req.upload_fromhere[i])
1712         smtpc->eob = 1;
1713       else
1714         smtpc->eob = 0;
1715     }
1716
1717     /* Do we have a match for CRLF. as per RFC-2821, sect. 4.5.2 */
1718     if(SMTP_EOB_FIND_LEN == smtpc->eob) {
1719       /* Copy the replacement data to the target buffer */
1720       memcpy(&data->state.scratch[si], SMTP_EOB_REPL, SMTP_EOB_REPL_LEN);
1721       si += SMTP_EOB_REPL_LEN;
1722       smtpc->eob = 0;
1723     }
1724     else if(!smtpc->eob)
1725       data->state.scratch[si++] = data->req.upload_fromhere[i];
1726   }
1727
1728   if(smtpc->eob) {
1729     /* A substring matched before processing ended so output that now */
1730     memcpy(&data->state.scratch[si], SMTP_EOB, smtpc->eob);
1731     si += smtpc->eob;
1732     smtpc->eob = 0;
1733   }
1734
1735   if(si != nread) {
1736     /* Only use the new buffer if we replaced something */
1737     nread = si;
1738
1739     /* Upload from the new (replaced) buffer instead */
1740     data->req.upload_fromhere = data->state.scratch;
1741
1742     /* Set the new amount too */
1743     data->req.upload_present = nread;
1744   }
1745
1746   return CURLE_OK;
1747 }
1748
1749 #endif /* CURL_DISABLE_SMTP */