Imported Upstream version 7.59.0
[platform/upstream/curl.git] / lib / smtp.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2018, 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 https://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  * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism
28  * RFC4954 SMTP Authentication
29  * RFC5321 SMTP protocol
30  * RFC6749 OAuth 2.0 Authorization Framework
31  * Draft   SMTP URL Interface   <draft-earhart-url-smtp-00.txt>
32  * Draft   LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
33  *
34  ***************************************************************************/
35
36 #include "curl_setup.h"
37
38 #ifndef CURL_DISABLE_SMTP
39
40 #ifdef HAVE_NETINET_IN_H
41 #include <netinet/in.h>
42 #endif
43 #ifdef HAVE_ARPA_INET_H
44 #include <arpa/inet.h>
45 #endif
46 #ifdef HAVE_UTSNAME_H
47 #include <sys/utsname.h>
48 #endif
49 #ifdef HAVE_NETDB_H
50 #include <netdb.h>
51 #endif
52 #ifdef __VMS
53 #include <in.h>
54 #include <inet.h>
55 #endif
56
57 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
58 #undef in_addr_t
59 #define in_addr_t unsigned long
60 #endif
61
62 #include <curl/curl.h>
63 #include "urldata.h"
64 #include "sendf.h"
65 #include "hostip.h"
66 #include "progress.h"
67 #include "transfer.h"
68 #include "escape.h"
69 #include "http.h" /* for HTTP proxy tunnel stuff */
70 #include "mime.h"
71 #include "socks.h"
72 #include "smtp.h"
73 #include "strtoofft.h"
74 #include "strcase.h"
75 #include "vtls/vtls.h"
76 #include "connect.h"
77 #include "strerror.h"
78 #include "select.h"
79 #include "multiif.h"
80 #include "url.h"
81 #include "curl_gethostname.h"
82 #include "curl_sasl.h"
83 #include "warnless.h"
84 /* The last 3 #include files should be in this order */
85 #include "curl_printf.h"
86 #include "curl_memory.h"
87 #include "memdebug.h"
88
89 /* Local API functions */
90 static CURLcode smtp_regular_transfer(struct connectdata *conn, bool *done);
91 static CURLcode smtp_do(struct connectdata *conn, bool *done);
92 static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
93                           bool premature);
94 static CURLcode smtp_connect(struct connectdata *conn, bool *done);
95 static CURLcode smtp_disconnect(struct connectdata *conn, bool dead);
96 static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done);
97 static int smtp_getsock(struct connectdata *conn, curl_socket_t *socks,
98                         int numsocks);
99 static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done);
100 static CURLcode smtp_setup_connection(struct connectdata *conn);
101 static CURLcode smtp_parse_url_options(struct connectdata *conn);
102 static CURLcode smtp_parse_url_path(struct connectdata *conn);
103 static CURLcode smtp_parse_custom_request(struct connectdata *conn);
104 static CURLcode smtp_perform_auth(struct connectdata *conn, const char *mech,
105                                   const char *initresp);
106 static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp);
107 static void smtp_get_message(char *buffer, char **outptr);
108
109 /*
110  * SMTP protocol handler.
111  */
112
113 const struct Curl_handler Curl_handler_smtp = {
114   "SMTP",                           /* scheme */
115   smtp_setup_connection,            /* setup_connection */
116   smtp_do,                          /* do_it */
117   smtp_done,                        /* done */
118   ZERO_NULL,                        /* do_more */
119   smtp_connect,                     /* connect_it */
120   smtp_multi_statemach,             /* connecting */
121   smtp_doing,                       /* doing */
122   smtp_getsock,                     /* proto_getsock */
123   smtp_getsock,                     /* doing_getsock */
124   ZERO_NULL,                        /* domore_getsock */
125   ZERO_NULL,                        /* perform_getsock */
126   smtp_disconnect,                  /* disconnect */
127   ZERO_NULL,                        /* readwrite */
128   ZERO_NULL,                        /* connection_check */
129   PORT_SMTP,                        /* defport */
130   CURLPROTO_SMTP,                   /* protocol */
131   PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */
132   PROTOPT_URLOPTIONS
133 };
134
135 #ifdef USE_SSL
136 /*
137  * SMTPS protocol handler.
138  */
139
140 const struct Curl_handler Curl_handler_smtps = {
141   "SMTPS",                          /* scheme */
142   smtp_setup_connection,            /* setup_connection */
143   smtp_do,                          /* do_it */
144   smtp_done,                        /* done */
145   ZERO_NULL,                        /* do_more */
146   smtp_connect,                     /* connect_it */
147   smtp_multi_statemach,             /* connecting */
148   smtp_doing,                       /* doing */
149   smtp_getsock,                     /* proto_getsock */
150   smtp_getsock,                     /* doing_getsock */
151   ZERO_NULL,                        /* domore_getsock */
152   ZERO_NULL,                        /* perform_getsock */
153   smtp_disconnect,                  /* disconnect */
154   ZERO_NULL,                        /* readwrite */
155   ZERO_NULL,                        /* connection_check */
156   PORT_SMTPS,                       /* defport */
157   CURLPROTO_SMTPS,                  /* protocol */
158   PROTOPT_CLOSEACTION | PROTOPT_SSL
159   | PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS /* flags */
160 };
161 #endif
162
163 /* SASL parameters for the smtp protocol */
164 static const struct SASLproto saslsmtp = {
165   "smtp",                     /* The service name */
166   334,                        /* Code received when continuation is expected */
167   235,                        /* Code to receive upon authentication success */
168   512 - 8,                    /* Maximum initial response length (no max) */
169   smtp_perform_auth,          /* Send authentication command */
170   smtp_continue_auth,         /* Send authentication continuation */
171   smtp_get_message            /* Get SASL response message */
172 };
173
174 #ifdef USE_SSL
175 static void smtp_to_smtps(struct connectdata *conn)
176 {
177   /* Change the connection handler */
178   conn->handler = &Curl_handler_smtps;
179
180   /* Set the connection's upgraded to TLS flag */
181   conn->tls_upgraded = TRUE;
182 }
183 #else
184 #define smtp_to_smtps(x) Curl_nop_stmt
185 #endif
186
187 /***********************************************************************
188  *
189  * smtp_endofresp()
190  *
191  * Checks for an ending SMTP status code at the start of the given string, but
192  * also detects various capabilities from the EHLO response including the
193  * supported authentication mechanisms.
194  */
195 static bool smtp_endofresp(struct connectdata *conn, char *line, size_t len,
196                            int *resp)
197 {
198   struct smtp_conn *smtpc = &conn->proto.smtpc;
199   bool result = FALSE;
200
201   /* Nothing for us */
202   if(len < 4 || !ISDIGIT(line[0]) || !ISDIGIT(line[1]) || !ISDIGIT(line[2]))
203     return FALSE;
204
205   /* Do we have a command response? This should be the response code followed
206      by a space and optionally some text as per RFC-5321 and as outlined in
207      Section 4. Examples of RFC-4954 but some e-mail servers ignore this and
208      only send the response code instead as per Section 4.2. */
209   if(line[3] == ' ' || len == 5) {
210     result = TRUE;
211     *resp = curlx_sltosi(strtol(line, NULL, 10));
212
213     /* Make sure real server never sends internal value */
214     if(*resp == 1)
215       *resp = 0;
216   }
217   /* Do we have a multiline (continuation) response? */
218   else if(line[3] == '-' &&
219           (smtpc->state == SMTP_EHLO || smtpc->state == SMTP_COMMAND)) {
220     result = TRUE;
221     *resp = 1;  /* Internal response code */
222   }
223
224   return result;
225 }
226
227 /***********************************************************************
228  *
229  * smtp_get_message()
230  *
231  * Gets the authentication message from the response buffer.
232  */
233 static void smtp_get_message(char *buffer, char **outptr)
234 {
235   size_t len = strlen(buffer);
236   char *message = NULL;
237
238   if(len > 4) {
239     /* Find the start of the message */
240     len -= 4;
241     for(message = buffer + 4; *message == ' ' || *message == '\t';
242         message++, len--)
243       ;
244
245     /* Find the end of the message */
246     for(; len--;)
247       if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
248          message[len] != '\t')
249         break;
250
251     /* Terminate the message */
252     if(++len) {
253       message[len] = '\0';
254     }
255   }
256   else
257     /* junk input => zero length output */
258     message = &buffer[len];
259
260   *outptr = message;
261 }
262
263 /***********************************************************************
264  *
265  * state()
266  *
267  * This is the ONLY way to change SMTP state!
268  */
269 static void state(struct connectdata *conn, smtpstate newstate)
270 {
271   struct smtp_conn *smtpc = &conn->proto.smtpc;
272 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
273   /* for debug purposes */
274   static const char * const names[] = {
275     "STOP",
276     "SERVERGREET",
277     "EHLO",
278     "HELO",
279     "STARTTLS",
280     "UPGRADETLS",
281     "AUTH",
282     "COMMAND",
283     "MAIL",
284     "RCPT",
285     "DATA",
286     "POSTDATA",
287     "QUIT",
288     /* LAST */
289   };
290
291   if(smtpc->state != newstate)
292     infof(conn->data, "SMTP %p state change from %s to %s\n",
293           (void *)smtpc, names[smtpc->state], names[newstate]);
294 #endif
295
296   smtpc->state = newstate;
297 }
298
299 /***********************************************************************
300  *
301  * smtp_perform_ehlo()
302  *
303  * Sends the EHLO command to not only initialise communication with the ESMTP
304  * server but to also obtain a list of server side supported capabilities.
305  */
306 static CURLcode smtp_perform_ehlo(struct connectdata *conn)
307 {
308   CURLcode result = CURLE_OK;
309   struct smtp_conn *smtpc = &conn->proto.smtpc;
310
311   smtpc->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanism yet */
312   smtpc->sasl.authused = SASL_AUTH_NONE;  /* Clear the authentication mechanism
313                                              used for esmtp connections */
314   smtpc->tls_supported = FALSE;           /* Clear the TLS capability */
315   smtpc->auth_supported = FALSE;          /* Clear the AUTH capability */
316
317   /* Send the EHLO command */
318   result = Curl_pp_sendf(&smtpc->pp, "EHLO %s", smtpc->domain);
319
320   if(!result)
321     state(conn, SMTP_EHLO);
322
323   return result;
324 }
325
326 /***********************************************************************
327  *
328  * smtp_perform_helo()
329  *
330  * Sends the HELO command to initialise communication with the SMTP server.
331  */
332 static CURLcode smtp_perform_helo(struct connectdata *conn)
333 {
334   CURLcode result = CURLE_OK;
335   struct smtp_conn *smtpc = &conn->proto.smtpc;
336
337   smtpc->sasl.authused = SASL_AUTH_NONE; /* No authentication mechanism used
338                                             in smtp connections */
339
340   /* Send the HELO command */
341   result = Curl_pp_sendf(&smtpc->pp, "HELO %s", smtpc->domain);
342
343   if(!result)
344     state(conn, SMTP_HELO);
345
346   return result;
347 }
348
349 /***********************************************************************
350  *
351  * smtp_perform_starttls()
352  *
353  * Sends the STLS command to start the upgrade to TLS.
354  */
355 static CURLcode smtp_perform_starttls(struct connectdata *conn)
356 {
357   CURLcode result = CURLE_OK;
358
359   /* Send the STARTTLS command */
360   result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "STARTTLS");
361
362   if(!result)
363     state(conn, SMTP_STARTTLS);
364
365   return result;
366 }
367
368 /***********************************************************************
369  *
370  * smtp_perform_upgrade_tls()
371  *
372  * Performs the upgrade to TLS.
373  */
374 static CURLcode smtp_perform_upgrade_tls(struct connectdata *conn)
375 {
376   CURLcode result = CURLE_OK;
377   struct smtp_conn *smtpc = &conn->proto.smtpc;
378
379   /* Start the SSL connection */
380   result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &smtpc->ssldone);
381
382   if(!result) {
383     if(smtpc->state != SMTP_UPGRADETLS)
384       state(conn, SMTP_UPGRADETLS);
385
386     if(smtpc->ssldone) {
387       smtp_to_smtps(conn);
388       result = smtp_perform_ehlo(conn);
389     }
390   }
391
392   return result;
393 }
394
395 /***********************************************************************
396  *
397  * smtp_perform_auth()
398  *
399  * Sends an AUTH command allowing the client to login with the given SASL
400  * authentication mechanism.
401  */
402 static CURLcode smtp_perform_auth(struct connectdata *conn,
403                                   const char *mech,
404                                   const char *initresp)
405 {
406   CURLcode result = CURLE_OK;
407   struct smtp_conn *smtpc = &conn->proto.smtpc;
408
409   if(initresp) {                                  /* AUTH <mech> ...<crlf> */
410     /* Send the AUTH command with the initial response */
411     result = Curl_pp_sendf(&smtpc->pp, "AUTH %s %s", mech, initresp);
412   }
413   else {
414     /* Send the AUTH command */
415     result = Curl_pp_sendf(&smtpc->pp, "AUTH %s", mech);
416   }
417
418   return result;
419 }
420
421 /***********************************************************************
422  *
423  * smtp_continue_auth()
424  *
425  * Sends SASL continuation data or cancellation.
426  */
427 static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp)
428 {
429   struct smtp_conn *smtpc = &conn->proto.smtpc;
430
431   return Curl_pp_sendf(&smtpc->pp, "%s", resp);
432 }
433
434 /***********************************************************************
435  *
436  * smtp_perform_authentication()
437  *
438  * Initiates the authentication sequence, with the appropriate SASL
439  * authentication mechanism.
440  */
441 static CURLcode smtp_perform_authentication(struct connectdata *conn)
442 {
443   CURLcode result = CURLE_OK;
444   struct smtp_conn *smtpc = &conn->proto.smtpc;
445   saslprogress progress;
446
447   /* Check we have enough data to authenticate with, and the
448      server supports authentiation, and end the connect phase if not */
449   if(!smtpc->auth_supported ||
450      !Curl_sasl_can_authenticate(&smtpc->sasl, conn)) {
451     state(conn, SMTP_STOP);
452     return result;
453   }
454
455   /* Calculate the SASL login details */
456   result = Curl_sasl_start(&smtpc->sasl, conn, FALSE, &progress);
457
458   if(!result) {
459     if(progress == SASL_INPROGRESS)
460       state(conn, SMTP_AUTH);
461     else {
462       /* Other mechanisms not supported */
463       infof(conn->data, "No known authentication mechanisms supported!\n");
464       result = CURLE_LOGIN_DENIED;
465     }
466   }
467
468   return result;
469 }
470
471 /***********************************************************************
472  *
473  * smtp_perform_command()
474  *
475  * Sends a SMTP based command.
476  */
477 static CURLcode smtp_perform_command(struct connectdata *conn)
478 {
479   CURLcode result = CURLE_OK;
480   struct Curl_easy *data = conn->data;
481   struct SMTP *smtp = data->req.protop;
482
483   /* Send the command */
484   if(smtp->rcpt)
485     result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s %s",
486                            smtp->custom && smtp->custom[0] != '\0' ?
487                            smtp->custom : "VRFY",
488                            smtp->rcpt->data);
489   else
490     result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s",
491                            smtp->custom && smtp->custom[0] != '\0' ?
492                            smtp->custom : "HELP");
493
494   if(!result)
495     state(conn, SMTP_COMMAND);
496
497   return result;
498 }
499
500 /***********************************************************************
501  *
502  * smtp_perform_mail()
503  *
504  * Sends an MAIL command to initiate the upload of a message.
505  */
506 static CURLcode smtp_perform_mail(struct connectdata *conn)
507 {
508   char *from = NULL;
509   char *auth = NULL;
510   char *size = NULL;
511   CURLcode result = CURLE_OK;
512   struct Curl_easy *data = conn->data;
513
514   /* Calculate the FROM parameter */
515   if(!data->set.str[STRING_MAIL_FROM])
516     /* Null reverse-path, RFC-5321, sect. 3.6.3 */
517     from = strdup("<>");
518   else if(data->set.str[STRING_MAIL_FROM][0] == '<')
519     from = aprintf("%s", data->set.str[STRING_MAIL_FROM]);
520   else
521     from = aprintf("<%s>", data->set.str[STRING_MAIL_FROM]);
522
523   if(!from)
524     return CURLE_OUT_OF_MEMORY;
525
526   /* Calculate the optional AUTH parameter */
527   if(data->set.str[STRING_MAIL_AUTH] && conn->proto.smtpc.sasl.authused) {
528     if(data->set.str[STRING_MAIL_AUTH][0] != '\0')
529       auth = aprintf("%s", data->set.str[STRING_MAIL_AUTH]);
530     else
531       /* Empty AUTH, RFC-2554, sect. 5 */
532       auth = strdup("<>");
533
534     if(!auth) {
535       free(from);
536
537       return CURLE_OUT_OF_MEMORY;
538     }
539   }
540
541   /* Prepare the mime data if some. */
542   if(data->set.mimepost.kind != MIMEKIND_NONE) {
543     /* Use the whole structure as data. */
544     data->set.mimepost.flags &= ~MIME_BODY_ONLY;
545
546     /* Add external headers and mime version. */
547     curl_mime_headers(&data->set.mimepost, data->set.headers, 0);
548     result = Curl_mime_prepare_headers(&data->set.mimepost, NULL,
549                                        NULL, MIMESTRATEGY_MAIL);
550
551     if(!result)
552       if(!Curl_checkheaders(conn, "Mime-Version"))
553         result = Curl_mime_add_header(&data->set.mimepost.curlheaders,
554                                       "Mime-Version: 1.0");
555
556     /* Make sure we will read the entire mime structure. */
557     if(!result)
558       result = Curl_mime_rewind(&data->set.mimepost);
559
560     if(result) {
561       free(from);
562       free(auth);
563       return result;
564     }
565
566     data->state.infilesize = Curl_mime_size(&data->set.mimepost);
567
568     /* Read from mime structure. */
569     data->state.fread_func = (curl_read_callback) Curl_mime_read;
570     data->state.in = (void *) &data->set.mimepost;
571   }
572
573   /* Calculate the optional SIZE parameter */
574   if(conn->proto.smtpc.size_supported && data->state.infilesize > 0) {
575     size = aprintf("%" CURL_FORMAT_CURL_OFF_T, data->state.infilesize);
576
577     if(!size) {
578       free(from);
579       free(auth);
580
581       return CURLE_OUT_OF_MEMORY;
582     }
583   }
584
585   /* Send the MAIL command */
586   if(!auth && !size)
587     result = Curl_pp_sendf(&conn->proto.smtpc.pp,
588                            "MAIL FROM:%s", from);
589   else if(auth && !size)
590     result = Curl_pp_sendf(&conn->proto.smtpc.pp,
591                            "MAIL FROM:%s AUTH=%s", from, auth);
592   else if(auth && size)
593     result = Curl_pp_sendf(&conn->proto.smtpc.pp,
594                            "MAIL FROM:%s AUTH=%s SIZE=%s", from, auth, size);
595   else
596     result = Curl_pp_sendf(&conn->proto.smtpc.pp,
597                            "MAIL FROM:%s SIZE=%s", from, size);
598
599   free(from);
600   free(auth);
601   free(size);
602
603   if(!result)
604     state(conn, SMTP_MAIL);
605
606   return result;
607 }
608
609 /***********************************************************************
610  *
611  * smtp_perform_rcpt_to()
612  *
613  * Sends a RCPT TO command for a given recipient as part of the message upload
614  * process.
615  */
616 static CURLcode smtp_perform_rcpt_to(struct connectdata *conn)
617 {
618   CURLcode result = CURLE_OK;
619   struct Curl_easy *data = conn->data;
620   struct SMTP *smtp = data->req.protop;
621
622   /* Send the RCPT TO command */
623   if(smtp->rcpt->data[0] == '<')
624     result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:%s",
625                            smtp->rcpt->data);
626   else
627     result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:<%s>",
628                            smtp->rcpt->data);
629   if(!result)
630     state(conn, SMTP_RCPT);
631
632   return result;
633 }
634
635 /***********************************************************************
636  *
637  * smtp_perform_quit()
638  *
639  * Performs the quit action prior to sclose() being called.
640  */
641 static CURLcode smtp_perform_quit(struct connectdata *conn)
642 {
643   CURLcode result = CURLE_OK;
644
645   /* Send the QUIT command */
646   result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "QUIT");
647
648   if(!result)
649     state(conn, SMTP_QUIT);
650
651   return result;
652 }
653
654 /* For the initial server greeting */
655 static CURLcode smtp_state_servergreet_resp(struct connectdata *conn,
656                                             int smtpcode,
657                                             smtpstate instate)
658 {
659   CURLcode result = CURLE_OK;
660   struct Curl_easy *data = conn->data;
661
662   (void)instate; /* no use for this yet */
663
664   if(smtpcode/100 != 2) {
665     failf(data, "Got unexpected smtp-server response: %d", smtpcode);
666     result = CURLE_WEIRD_SERVER_REPLY;
667   }
668   else
669     result = smtp_perform_ehlo(conn);
670
671   return result;
672 }
673
674 /* For STARTTLS responses */
675 static CURLcode smtp_state_starttls_resp(struct connectdata *conn,
676                                          int smtpcode,
677                                          smtpstate instate)
678 {
679   CURLcode result = CURLE_OK;
680   struct Curl_easy *data = conn->data;
681
682   (void)instate; /* no use for this yet */
683
684   if(smtpcode != 220) {
685     if(data->set.use_ssl != CURLUSESSL_TRY) {
686       failf(data, "STARTTLS denied, code %d", smtpcode);
687       result = CURLE_USE_SSL_FAILED;
688     }
689     else
690       result = smtp_perform_authentication(conn);
691   }
692   else
693     result = smtp_perform_upgrade_tls(conn);
694
695   return result;
696 }
697
698 /* For EHLO responses */
699 static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode,
700                                      smtpstate instate)
701 {
702   CURLcode result = CURLE_OK;
703   struct Curl_easy *data = conn->data;
704   struct smtp_conn *smtpc = &conn->proto.smtpc;
705   const char *line = data->state.buffer;
706   size_t len = strlen(line);
707   size_t wordlen;
708
709   (void)instate; /* no use for this yet */
710
711   if(smtpcode/100 != 2 && smtpcode != 1) {
712     if(data->set.use_ssl <= CURLUSESSL_TRY || conn->ssl[FIRSTSOCKET].use)
713       result = smtp_perform_helo(conn);
714     else {
715       failf(data, "Remote access denied: %d", smtpcode);
716       result = CURLE_REMOTE_ACCESS_DENIED;
717     }
718   }
719   else {
720     line += 4;
721     len -= 4;
722
723     /* Does the server support the STARTTLS capability? */
724     if(len >= 8 && !memcmp(line, "STARTTLS", 8))
725       smtpc->tls_supported = TRUE;
726
727     /* Does the server support the SIZE capability? */
728     else if(len >= 4 && !memcmp(line, "SIZE", 4))
729       smtpc->size_supported = TRUE;
730
731     /* Does the server support authentication? */
732     else if(len >= 5 && !memcmp(line, "AUTH ", 5)) {
733       smtpc->auth_supported = TRUE;
734
735       /* Advance past the AUTH keyword */
736       line += 5;
737       len -= 5;
738
739       /* Loop through the data line */
740       for(;;) {
741         size_t llen;
742         unsigned int mechbit;
743
744         while(len &&
745               (*line == ' ' || *line == '\t' ||
746                *line == '\r' || *line == '\n')) {
747
748           line++;
749           len--;
750         }
751
752         if(!len)
753           break;
754
755         /* Extract the word */
756         for(wordlen = 0; wordlen < len && line[wordlen] != ' ' &&
757               line[wordlen] != '\t' && line[wordlen] != '\r' &&
758               line[wordlen] != '\n';)
759           wordlen++;
760
761         /* Test the word for a matching authentication mechanism */
762         mechbit = Curl_sasl_decode_mech(line, wordlen, &llen);
763         if(mechbit && llen == wordlen)
764           smtpc->sasl.authmechs |= mechbit;
765
766         line += wordlen;
767         len -= wordlen;
768       }
769     }
770
771     if(smtpcode != 1) {
772       if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
773         /* We don't have a SSL/TLS connection yet, but SSL is requested */
774         if(smtpc->tls_supported)
775           /* Switch to TLS connection now */
776           result = smtp_perform_starttls(conn);
777         else if(data->set.use_ssl == CURLUSESSL_TRY)
778           /* Fallback and carry on with authentication */
779           result = smtp_perform_authentication(conn);
780         else {
781           failf(data, "STARTTLS not supported.");
782           result = CURLE_USE_SSL_FAILED;
783         }
784       }
785       else
786         result = smtp_perform_authentication(conn);
787     }
788   }
789
790   return result;
791 }
792
793 /* For HELO responses */
794 static CURLcode smtp_state_helo_resp(struct connectdata *conn, int smtpcode,
795                                      smtpstate instate)
796 {
797   CURLcode result = CURLE_OK;
798   struct Curl_easy *data = conn->data;
799
800   (void)instate; /* no use for this yet */
801
802   if(smtpcode/100 != 2) {
803     failf(data, "Remote access denied: %d", smtpcode);
804     result = CURLE_REMOTE_ACCESS_DENIED;
805   }
806   else
807     /* End of connect phase */
808     state(conn, SMTP_STOP);
809
810   return result;
811 }
812
813 /* For SASL authentication responses */
814 static CURLcode smtp_state_auth_resp(struct connectdata *conn,
815                                      int smtpcode,
816                                      smtpstate instate)
817 {
818   CURLcode result = CURLE_OK;
819   struct Curl_easy *data = conn->data;
820   struct smtp_conn *smtpc = &conn->proto.smtpc;
821   saslprogress progress;
822
823   (void)instate; /* no use for this yet */
824
825   result = Curl_sasl_continue(&smtpc->sasl, conn, smtpcode, &progress);
826   if(!result)
827     switch(progress) {
828     case SASL_DONE:
829       state(conn, SMTP_STOP);  /* Authenticated */
830       break;
831     case SASL_IDLE:            /* No mechanism left after cancellation */
832       failf(data, "Authentication cancelled");
833       result = CURLE_LOGIN_DENIED;
834       break;
835     default:
836       break;
837     }
838
839   return result;
840 }
841
842 /* For command responses */
843 static CURLcode smtp_state_command_resp(struct connectdata *conn, int smtpcode,
844                                         smtpstate instate)
845 {
846   CURLcode result = CURLE_OK;
847   struct Curl_easy *data = conn->data;
848   struct SMTP *smtp = data->req.protop;
849   char *line = data->state.buffer;
850   size_t len = strlen(line);
851
852   (void)instate; /* no use for this yet */
853
854   if((smtp->rcpt && smtpcode/100 != 2 && smtpcode != 553 && smtpcode != 1) ||
855      (!smtp->rcpt && smtpcode/100 != 2 && smtpcode != 1)) {
856     failf(data, "Command failed: %d", smtpcode);
857     result = CURLE_RECV_ERROR;
858   }
859   else {
860     /* Temporarily add the LF character back and send as body to the client */
861     if(!data->set.opt_no_body) {
862       line[len] = '\n';
863       result = Curl_client_write(conn, CLIENTWRITE_BODY, line, len + 1);
864       line[len] = '\0';
865     }
866
867     if(smtpcode != 1) {
868       if(smtp->rcpt) {
869         smtp->rcpt = smtp->rcpt->next;
870
871         if(smtp->rcpt) {
872           /* Send the next command */
873           result = smtp_perform_command(conn);
874         }
875         else
876           /* End of DO phase */
877           state(conn, SMTP_STOP);
878       }
879       else
880         /* End of DO phase */
881         state(conn, SMTP_STOP);
882     }
883   }
884
885   return result;
886 }
887
888 /* For MAIL responses */
889 static CURLcode smtp_state_mail_resp(struct connectdata *conn, int smtpcode,
890                                      smtpstate instate)
891 {
892   CURLcode result = CURLE_OK;
893   struct Curl_easy *data = conn->data;
894
895   (void)instate; /* no use for this yet */
896
897   if(smtpcode/100 != 2) {
898     failf(data, "MAIL failed: %d", smtpcode);
899     result = CURLE_SEND_ERROR;
900   }
901   else
902     /* Start the RCPT TO command */
903     result = smtp_perform_rcpt_to(conn);
904
905   return result;
906 }
907
908 /* For RCPT responses */
909 static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, int smtpcode,
910                                      smtpstate instate)
911 {
912   CURLcode result = CURLE_OK;
913   struct Curl_easy *data = conn->data;
914   struct SMTP *smtp = data->req.protop;
915
916   (void)instate; /* no use for this yet */
917
918   if(smtpcode/100 != 2) {
919     failf(data, "RCPT failed: %d", smtpcode);
920     result = CURLE_SEND_ERROR;
921   }
922   else {
923     smtp->rcpt = smtp->rcpt->next;
924
925     if(smtp->rcpt)
926       /* Send the next RCPT TO command */
927       result = smtp_perform_rcpt_to(conn);
928     else {
929       /* Send the DATA command */
930       result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "DATA");
931
932       if(!result)
933         state(conn, SMTP_DATA);
934     }
935   }
936
937   return result;
938 }
939
940 /* For DATA response */
941 static CURLcode smtp_state_data_resp(struct connectdata *conn, int smtpcode,
942                                      smtpstate instate)
943 {
944   CURLcode result = CURLE_OK;
945   struct Curl_easy *data = conn->data;
946
947   (void)instate; /* no use for this yet */
948
949   if(smtpcode != 354) {
950     failf(data, "DATA failed: %d", smtpcode);
951     result = CURLE_SEND_ERROR;
952   }
953   else {
954     /* Set the progress upload size */
955     Curl_pgrsSetUploadSize(data, data->state.infilesize);
956
957     /* SMTP upload */
958     Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL);
959
960     /* End of DO phase */
961     state(conn, SMTP_STOP);
962   }
963
964   return result;
965 }
966
967 /* For POSTDATA responses, which are received after the entire DATA
968    part has been sent to the server */
969 static CURLcode smtp_state_postdata_resp(struct connectdata *conn,
970                                          int smtpcode,
971                                          smtpstate instate)
972 {
973   CURLcode result = CURLE_OK;
974
975   (void)instate; /* no use for this yet */
976
977   if(smtpcode != 250)
978     result = CURLE_RECV_ERROR;
979
980   /* End of DONE phase */
981   state(conn, SMTP_STOP);
982
983   return result;
984 }
985
986 static CURLcode smtp_statemach_act(struct connectdata *conn)
987 {
988   CURLcode result = CURLE_OK;
989   curl_socket_t sock = conn->sock[FIRSTSOCKET];
990   struct Curl_easy *data = conn->data;
991   int smtpcode;
992   struct smtp_conn *smtpc = &conn->proto.smtpc;
993   struct pingpong *pp = &smtpc->pp;
994   size_t nread = 0;
995
996   /* Busy upgrading the connection; right now all I/O is SSL/TLS, not SMTP */
997   if(smtpc->state == SMTP_UPGRADETLS)
998     return smtp_perform_upgrade_tls(conn);
999
1000   /* Flush any data that needs to be sent */
1001   if(pp->sendleft)
1002     return Curl_pp_flushsend(pp);
1003
1004   do {
1005     /* Read the response from the server */
1006     result = Curl_pp_readresp(sock, pp, &smtpcode, &nread);
1007     if(result)
1008       return result;
1009
1010     /* Store the latest response for later retrieval if necessary */
1011     if(smtpc->state != SMTP_QUIT && smtpcode != 1)
1012       data->info.httpcode = smtpcode;
1013
1014     if(!smtpcode)
1015       break;
1016
1017     /* We have now received a full SMTP server response */
1018     switch(smtpc->state) {
1019     case SMTP_SERVERGREET:
1020       result = smtp_state_servergreet_resp(conn, smtpcode, smtpc->state);
1021       break;
1022
1023     case SMTP_EHLO:
1024       result = smtp_state_ehlo_resp(conn, smtpcode, smtpc->state);
1025       break;
1026
1027     case SMTP_HELO:
1028       result = smtp_state_helo_resp(conn, smtpcode, smtpc->state);
1029       break;
1030
1031     case SMTP_STARTTLS:
1032       result = smtp_state_starttls_resp(conn, smtpcode, smtpc->state);
1033       break;
1034
1035     case SMTP_AUTH:
1036       result = smtp_state_auth_resp(conn, smtpcode, smtpc->state);
1037       break;
1038
1039     case SMTP_COMMAND:
1040       result = smtp_state_command_resp(conn, smtpcode, smtpc->state);
1041       break;
1042
1043     case SMTP_MAIL:
1044       result = smtp_state_mail_resp(conn, smtpcode, smtpc->state);
1045       break;
1046
1047     case SMTP_RCPT:
1048       result = smtp_state_rcpt_resp(conn, smtpcode, smtpc->state);
1049       break;
1050
1051     case SMTP_DATA:
1052       result = smtp_state_data_resp(conn, smtpcode, smtpc->state);
1053       break;
1054
1055     case SMTP_POSTDATA:
1056       result = smtp_state_postdata_resp(conn, smtpcode, smtpc->state);
1057       break;
1058
1059     case SMTP_QUIT:
1060       /* fallthrough, just stop! */
1061     default:
1062       /* internal error */
1063       state(conn, SMTP_STOP);
1064       break;
1065     }
1066   } while(!result && smtpc->state != SMTP_STOP && Curl_pp_moredata(pp));
1067
1068   return result;
1069 }
1070
1071 /* Called repeatedly until done from multi.c */
1072 static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done)
1073 {
1074   CURLcode result = CURLE_OK;
1075   struct smtp_conn *smtpc = &conn->proto.smtpc;
1076
1077   if((conn->handler->flags & PROTOPT_SSL) && !smtpc->ssldone) {
1078     result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &smtpc->ssldone);
1079     if(result || !smtpc->ssldone)
1080       return result;
1081   }
1082
1083   result = Curl_pp_statemach(&smtpc->pp, FALSE);
1084   *done = (smtpc->state == SMTP_STOP) ? TRUE : FALSE;
1085
1086   return result;
1087 }
1088
1089 static CURLcode smtp_block_statemach(struct connectdata *conn)
1090 {
1091   CURLcode result = CURLE_OK;
1092   struct smtp_conn *smtpc = &conn->proto.smtpc;
1093
1094   while(smtpc->state != SMTP_STOP && !result)
1095     result = Curl_pp_statemach(&smtpc->pp, TRUE);
1096
1097   return result;
1098 }
1099
1100 /* Allocate and initialize the SMTP struct for the current Curl_easy if
1101    required */
1102 static CURLcode smtp_init(struct connectdata *conn)
1103 {
1104   CURLcode result = CURLE_OK;
1105   struct Curl_easy *data = conn->data;
1106   struct SMTP *smtp;
1107
1108   smtp = data->req.protop = calloc(sizeof(struct SMTP), 1);
1109   if(!smtp)
1110     result = CURLE_OUT_OF_MEMORY;
1111
1112   return result;
1113 }
1114
1115 /* For the SMTP "protocol connect" and "doing" phases only */
1116 static int smtp_getsock(struct connectdata *conn, curl_socket_t *socks,
1117                         int numsocks)
1118 {
1119   return Curl_pp_getsock(&conn->proto.smtpc.pp, socks, numsocks);
1120 }
1121
1122 /***********************************************************************
1123  *
1124  * smtp_connect()
1125  *
1126  * This function should do everything that is to be considered a part of
1127  * the connection phase.
1128  *
1129  * The variable pointed to by 'done' will be TRUE if the protocol-layer
1130  * connect phase is done when this function returns, or FALSE if not.
1131  */
1132 static CURLcode smtp_connect(struct connectdata *conn, bool *done)
1133 {
1134   CURLcode result = CURLE_OK;
1135   struct smtp_conn *smtpc = &conn->proto.smtpc;
1136   struct pingpong *pp = &smtpc->pp;
1137
1138   *done = FALSE; /* default to not done yet */
1139
1140   /* We always support persistent connections in SMTP */
1141   connkeep(conn, "SMTP default");
1142
1143   /* Set the default response time-out */
1144   pp->response_time = RESP_TIMEOUT;
1145   pp->statemach_act = smtp_statemach_act;
1146   pp->endofresp = smtp_endofresp;
1147   pp->conn = conn;
1148
1149   /* Initialize the SASL storage */
1150   Curl_sasl_init(&smtpc->sasl, &saslsmtp);
1151
1152   /* Initialise the pingpong layer */
1153   Curl_pp_init(pp);
1154
1155   /* Parse the URL options */
1156   result = smtp_parse_url_options(conn);
1157   if(result)
1158     return result;
1159
1160   /* Parse the URL path */
1161   result = smtp_parse_url_path(conn);
1162   if(result)
1163     return result;
1164
1165   /* Start off waiting for the server greeting response */
1166   state(conn, SMTP_SERVERGREET);
1167
1168   result = smtp_multi_statemach(conn, done);
1169
1170   return result;
1171 }
1172
1173 /***********************************************************************
1174  *
1175  * smtp_done()
1176  *
1177  * The DONE function. This does what needs to be done after a single DO has
1178  * performed.
1179  *
1180  * Input argument is already checked for validity.
1181  */
1182 static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
1183                           bool premature)
1184 {
1185   CURLcode result = CURLE_OK;
1186   struct Curl_easy *data = conn->data;
1187   struct SMTP *smtp = data->req.protop;
1188   struct pingpong *pp = &conn->proto.smtpc.pp;
1189   char *eob;
1190   ssize_t len;
1191   ssize_t bytes_written;
1192
1193   (void)premature;
1194
1195   if(!smtp || !pp->conn)
1196     return CURLE_OK;
1197
1198   /* Cleanup our per-request based variables */
1199   Curl_safefree(smtp->custom);
1200
1201   if(status) {
1202     connclose(conn, "SMTP done with bad status"); /* marked for closure */
1203     result = status;         /* use the already set error code */
1204   }
1205   else if(!data->set.connect_only && data->set.mail_rcpt &&
1206           (data->set.upload || data->set.mimepost.kind)) {
1207     /* Calculate the EOB taking into account any terminating CRLF from the
1208        previous line of the email or the CRLF of the DATA command when there
1209        is "no mail data". RFC-5321, sect. 4.1.1.4.
1210
1211        Note: As some SSL backends, such as OpenSSL, will cause Curl_write() to
1212        fail when using a different pointer following a previous write, that
1213        returned CURLE_AGAIN, we duplicate the EOB now rather than when the
1214        bytes written doesn't equal len. */
1215     if(smtp->trailing_crlf || !conn->data->state.infilesize) {
1216       eob = strdup(SMTP_EOB + 2);
1217       len = SMTP_EOB_LEN - 2;
1218     }
1219     else {
1220       eob = strdup(SMTP_EOB);
1221       len = SMTP_EOB_LEN;
1222     }
1223
1224     if(!eob)
1225       return CURLE_OUT_OF_MEMORY;
1226
1227     /* Send the end of block data */
1228     result = Curl_write(conn, conn->writesockfd, eob, len, &bytes_written);
1229     if(result) {
1230       free(eob);
1231       return result;
1232     }
1233
1234     if(bytes_written != len) {
1235       /* The whole chunk was not sent so keep it around and adjust the
1236          pingpong structure accordingly */
1237       pp->sendthis = eob;
1238       pp->sendsize = len;
1239       pp->sendleft = len - bytes_written;
1240     }
1241     else {
1242       /* Successfully sent so adjust the response timeout relative to now */
1243       pp->response = Curl_now();
1244
1245       free(eob);
1246     }
1247
1248     state(conn, SMTP_POSTDATA);
1249
1250     /* Run the state-machine
1251
1252        TODO: when the multi interface is used, this _really_ should be using
1253        the smtp_multi_statemach function but we have no general support for
1254        non-blocking DONE operations!
1255     */
1256     result = smtp_block_statemach(conn);
1257   }
1258
1259   /* Clear the transfer mode for the next request */
1260   smtp->transfer = FTPTRANSFER_BODY;
1261
1262   return result;
1263 }
1264
1265 /***********************************************************************
1266  *
1267  * smtp_perform()
1268  *
1269  * This is the actual DO function for SMTP. Transfer a mail, send a command
1270  * or get some data according to the options previously setup.
1271  */
1272 static CURLcode smtp_perform(struct connectdata *conn, bool *connected,
1273                              bool *dophase_done)
1274 {
1275   /* This is SMTP and no proxy */
1276   CURLcode result = CURLE_OK;
1277   struct Curl_easy *data = conn->data;
1278   struct SMTP *smtp = data->req.protop;
1279
1280   DEBUGF(infof(conn->data, "DO phase starts\n"));
1281
1282   if(data->set.opt_no_body) {
1283     /* Requested no body means no transfer */
1284     smtp->transfer = FTPTRANSFER_INFO;
1285   }
1286
1287   *dophase_done = FALSE; /* not done yet */
1288
1289   /* Store the first recipient (or NULL if not specified) */
1290   smtp->rcpt = data->set.mail_rcpt;
1291
1292   /* Initial data character is the first character in line: it is implicitly
1293      preceded by a virtual CRLF. */
1294   smtp->trailing_crlf = TRUE;
1295   smtp->eob = 2;
1296
1297   /* Start the first command in the DO phase */
1298   if((data->set.upload || data->set.mimepost.kind) && data->set.mail_rcpt)
1299     /* MAIL transfer */
1300     result = smtp_perform_mail(conn);
1301   else
1302     /* SMTP based command (VRFY, EXPN, NOOP, RSET or HELP) */
1303     result = smtp_perform_command(conn);
1304
1305   if(result)
1306     return result;
1307
1308   /* Run the state-machine */
1309   result = smtp_multi_statemach(conn, dophase_done);
1310
1311   *connected = conn->bits.tcpconnect[FIRSTSOCKET];
1312
1313   if(*dophase_done)
1314     DEBUGF(infof(conn->data, "DO phase is complete\n"));
1315
1316   return result;
1317 }
1318
1319 /***********************************************************************
1320  *
1321  * smtp_do()
1322  *
1323  * This function is registered as 'curl_do' function. It decodes the path
1324  * parts etc as a wrapper to the actual DO function (smtp_perform).
1325  *
1326  * The input argument is already checked for validity.
1327  */
1328 static CURLcode smtp_do(struct connectdata *conn, bool *done)
1329 {
1330   CURLcode result = CURLE_OK;
1331
1332   *done = FALSE; /* default to false */
1333
1334   /* Parse the custom request */
1335   result = smtp_parse_custom_request(conn);
1336   if(result)
1337     return result;
1338
1339   result = smtp_regular_transfer(conn, done);
1340
1341   return result;
1342 }
1343
1344 /***********************************************************************
1345  *
1346  * smtp_disconnect()
1347  *
1348  * Disconnect from an SMTP server. Cleanup protocol-specific per-connection
1349  * resources. BLOCKING.
1350  */
1351 static CURLcode smtp_disconnect(struct connectdata *conn, bool dead_connection)
1352 {
1353   struct smtp_conn *smtpc = &conn->proto.smtpc;
1354
1355   /* We cannot send quit unconditionally. If this connection is stale or
1356      bad in any way, sending quit and waiting around here will make the
1357      disconnect wait in vain and cause more problems than we need to. */
1358
1359   /* The SMTP session may or may not have been allocated/setup at this
1360      point! */
1361   if(!dead_connection && smtpc->pp.conn && smtpc->pp.conn->bits.protoconnstart)
1362     if(!smtp_perform_quit(conn))
1363       (void)smtp_block_statemach(conn); /* ignore errors on QUIT */
1364
1365   /* Disconnect from the server */
1366   Curl_pp_disconnect(&smtpc->pp);
1367
1368   /* Cleanup the SASL module */
1369   Curl_sasl_cleanup(conn, smtpc->sasl.authused);
1370
1371   /* Cleanup our connection based variables */
1372   Curl_safefree(smtpc->domain);
1373
1374   return CURLE_OK;
1375 }
1376
1377 /* Call this when the DO phase has completed */
1378 static CURLcode smtp_dophase_done(struct connectdata *conn, bool connected)
1379 {
1380   struct SMTP *smtp = conn->data->req.protop;
1381
1382   (void)connected;
1383
1384   if(smtp->transfer != FTPTRANSFER_BODY)
1385     /* no data to transfer */
1386     Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1387
1388   return CURLE_OK;
1389 }
1390
1391 /* Called from multi.c while DOing */
1392 static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done)
1393 {
1394   CURLcode result = smtp_multi_statemach(conn, dophase_done);
1395
1396   if(result)
1397     DEBUGF(infof(conn->data, "DO phase failed\n"));
1398   else if(*dophase_done) {
1399     result = smtp_dophase_done(conn, FALSE /* not connected */);
1400
1401     DEBUGF(infof(conn->data, "DO phase is complete\n"));
1402   }
1403
1404   return result;
1405 }
1406
1407 /***********************************************************************
1408  *
1409  * smtp_regular_transfer()
1410  *
1411  * The input argument is already checked for validity.
1412  *
1413  * Performs all commands done before a regular transfer between a local and a
1414  * remote host.
1415  */
1416 static CURLcode smtp_regular_transfer(struct connectdata *conn,
1417                                       bool *dophase_done)
1418 {
1419   CURLcode result = CURLE_OK;
1420   bool connected = FALSE;
1421   struct Curl_easy *data = conn->data;
1422
1423   /* Make sure size is unknown at this point */
1424   data->req.size = -1;
1425
1426   /* Set the progress data */
1427   Curl_pgrsSetUploadCounter(data, 0);
1428   Curl_pgrsSetDownloadCounter(data, 0);
1429   Curl_pgrsSetUploadSize(data, -1);
1430   Curl_pgrsSetDownloadSize(data, -1);
1431
1432   /* Carry out the perform */
1433   result = smtp_perform(conn, &connected, dophase_done);
1434
1435   /* Perform post DO phase operations if necessary */
1436   if(!result && *dophase_done)
1437     result = smtp_dophase_done(conn, connected);
1438
1439   return result;
1440 }
1441
1442 static CURLcode smtp_setup_connection(struct connectdata *conn)
1443 {
1444   struct Curl_easy *data = conn->data;
1445   CURLcode result;
1446
1447   /* Clear the TLS upgraded flag */
1448   conn->tls_upgraded = FALSE;
1449
1450   /* Initialise the SMTP layer */
1451   result = smtp_init(conn);
1452   if(result)
1453     return result;
1454
1455   data->state.path++;   /* don't include the initial slash */
1456
1457   return CURLE_OK;
1458 }
1459
1460 /***********************************************************************
1461  *
1462  * smtp_parse_url_options()
1463  *
1464  * Parse the URL login options.
1465  */
1466 static CURLcode smtp_parse_url_options(struct connectdata *conn)
1467 {
1468   CURLcode result = CURLE_OK;
1469   struct smtp_conn *smtpc = &conn->proto.smtpc;
1470   const char *ptr = conn->options;
1471
1472   smtpc->sasl.resetprefs = TRUE;
1473
1474   while(!result && ptr && *ptr) {
1475     const char *key = ptr;
1476     const char *value;
1477
1478     while(*ptr && *ptr != '=')
1479       ptr++;
1480
1481     value = ptr + 1;
1482
1483     while(*ptr && *ptr != ';')
1484       ptr++;
1485
1486     if(strncasecompare(key, "AUTH=", 5))
1487       result = Curl_sasl_parse_url_auth_option(&smtpc->sasl,
1488                                                value, ptr - value);
1489     else
1490       result = CURLE_URL_MALFORMAT;
1491
1492     if(*ptr == ';')
1493       ptr++;
1494   }
1495
1496   return result;
1497 }
1498
1499 /***********************************************************************
1500  *
1501  * smtp_parse_url_path()
1502  *
1503  * Parse the URL path into separate path components.
1504  */
1505 static CURLcode smtp_parse_url_path(struct connectdata *conn)
1506 {
1507   /* The SMTP struct is already initialised in smtp_connect() */
1508   struct Curl_easy *data = conn->data;
1509   struct smtp_conn *smtpc = &conn->proto.smtpc;
1510   const char *path = data->state.path;
1511   char localhost[HOSTNAME_MAX + 1];
1512
1513   /* Calculate the path if necessary */
1514   if(!*path) {
1515     if(!Curl_gethostname(localhost, sizeof(localhost)))
1516       path = localhost;
1517     else
1518       path = "localhost";
1519   }
1520
1521   /* URL decode the path and use it as the domain in our EHLO */
1522   return Curl_urldecode(conn->data, path, 0, &smtpc->domain, NULL, TRUE);
1523 }
1524
1525 /***********************************************************************
1526  *
1527  * smtp_parse_custom_request()
1528  *
1529  * Parse the custom request.
1530  */
1531 static CURLcode smtp_parse_custom_request(struct connectdata *conn)
1532 {
1533   CURLcode result = CURLE_OK;
1534   struct Curl_easy *data = conn->data;
1535   struct SMTP *smtp = data->req.protop;
1536   const char *custom = data->set.str[STRING_CUSTOMREQUEST];
1537
1538   /* URL decode the custom request */
1539   if(custom)
1540     result = Curl_urldecode(data, custom, 0, &smtp->custom, NULL, TRUE);
1541
1542   return result;
1543 }
1544
1545 CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread)
1546 {
1547   /* When sending a SMTP payload we must detect CRLF. sequences making sure
1548      they are sent as CRLF.. instead, as a . on the beginning of a line will
1549      be deleted by the server when not part of an EOB terminator and a
1550      genuine CRLF.CRLF which isn't escaped will wrongly be detected as end of
1551      data by the server
1552   */
1553   ssize_t i;
1554   ssize_t si;
1555   struct Curl_easy *data = conn->data;
1556   struct SMTP *smtp = data->req.protop;
1557   char *scratch = data->state.scratch;
1558   char *newscratch = NULL;
1559   char *oldscratch = NULL;
1560   size_t eob_sent;
1561
1562   /* Do we need to allocate a scratch buffer? */
1563   if(!scratch || data->set.crlf) {
1564     oldscratch = scratch;
1565
1566     scratch = newscratch = malloc(2 * data->set.buffer_size);
1567     if(!newscratch) {
1568       failf(data, "Failed to alloc scratch buffer!");
1569
1570       return CURLE_OUT_OF_MEMORY;
1571     }
1572   }
1573
1574   /* Have we already sent part of the EOB? */
1575   eob_sent = smtp->eob;
1576
1577   /* This loop can be improved by some kind of Boyer-Moore style of
1578      approach but that is saved for later... */
1579   for(i = 0, si = 0; i < nread; i++) {
1580     if(SMTP_EOB[smtp->eob] == data->req.upload_fromhere[i]) {
1581       smtp->eob++;
1582
1583       /* Is the EOB potentially the terminating CRLF? */
1584       if(2 == smtp->eob || SMTP_EOB_LEN == smtp->eob)
1585         smtp->trailing_crlf = TRUE;
1586       else
1587         smtp->trailing_crlf = FALSE;
1588     }
1589     else if(smtp->eob) {
1590       /* A previous substring matched so output that first */
1591       memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent);
1592       si += smtp->eob - eob_sent;
1593
1594       /* Then compare the first byte */
1595       if(SMTP_EOB[0] == data->req.upload_fromhere[i])
1596         smtp->eob = 1;
1597       else
1598         smtp->eob = 0;
1599
1600       eob_sent = 0;
1601
1602       /* Reset the trailing CRLF flag as there was more data */
1603       smtp->trailing_crlf = FALSE;
1604     }
1605
1606     /* Do we have a match for CRLF. as per RFC-5321, sect. 4.5.2 */
1607     if(SMTP_EOB_FIND_LEN == smtp->eob) {
1608       /* Copy the replacement data to the target buffer */
1609       memcpy(&scratch[si], &SMTP_EOB_REPL[eob_sent],
1610              SMTP_EOB_REPL_LEN - eob_sent);
1611       si += SMTP_EOB_REPL_LEN - eob_sent;
1612       smtp->eob = 0;
1613       eob_sent = 0;
1614     }
1615     else if(!smtp->eob)
1616       scratch[si++] = data->req.upload_fromhere[i];
1617   }
1618
1619   if(smtp->eob - eob_sent) {
1620     /* A substring matched before processing ended so output that now */
1621     memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent);
1622     si += smtp->eob - eob_sent;
1623   }
1624
1625   /* Only use the new buffer if we replaced something */
1626   if(si != nread) {
1627     /* Upload from the new (replaced) buffer instead */
1628     data->req.upload_fromhere = scratch;
1629
1630     /* Save the buffer so it can be freed later */
1631     data->state.scratch = scratch;
1632
1633     /* Free the old scratch buffer */
1634     free(oldscratch);
1635
1636     /* Set the new amount too */
1637     data->req.upload_present = si;
1638   }
1639   else
1640     free(newscratch);
1641
1642   return CURLE_OK;
1643 }
1644
1645 #endif /* CURL_DISABLE_SMTP */