imap.c
Go to the documentation of this file.
1 /***************************************************************************
2  * _ _ ____ _
3  * Project ___| | | | _ \| |
4  * / __| | | | |_) | |
5  * | (__| |_| | _ <| |___
6  * \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2017, 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  * RFC2195 CRAM-MD5 authentication
22  * RFC2595 Using TLS with IMAP, POP3 and ACAP
23  * RFC2831 DIGEST-MD5 authentication
24  * RFC3501 IMAPv4 protocol
25  * RFC4422 Simple Authentication and Security Layer (SASL)
26  * RFC4616 PLAIN authentication
27  * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism
28  * RFC4959 IMAP Extension for SASL Initial Client Response
29  * RFC5092 IMAP URL Scheme
30  * RFC6749 OAuth 2.0 Authorization Framework
31  * Draft LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
32  *
33  ***************************************************************************/
34 
35 #include "curl_setup.h"
36 
37 #ifndef CURL_DISABLE_IMAP
38 
39 #ifdef HAVE_NETINET_IN_H
40 #include <netinet/in.h>
41 #endif
42 #ifdef HAVE_ARPA_INET_H
43 #include <arpa/inet.h>
44 #endif
45 #ifdef HAVE_UTSNAME_H
46 #include <sys/utsname.h>
47 #endif
48 #ifdef HAVE_NETDB_H
49 #include <netdb.h>
50 #endif
51 #ifdef __VMS
52 #include <in.h>
53 #include <inet.h>
54 #endif
55 
56 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
57 #undef in_addr_t
58 #define in_addr_t unsigned long
59 #endif
60 
61 #include <curl/curl.h>
62 #include "urldata.h"
63 #include "sendf.h"
64 #include "hostip.h"
65 #include "progress.h"
66 #include "transfer.h"
67 #include "escape.h"
68 #include "http.h" /* for HTTP proxy tunnel stuff */
69 #include "socks.h"
70 #include "imap.h"
71 #include "mime.h"
72 #include "strtoofft.h"
73 #include "strcase.h"
74 #include "vtls/vtls.h"
75 #include "connect.h"
76 #include "strerror.h"
77 #include "select.h"
78 #include "multiif.h"
79 #include "url.h"
80 #include "strcase.h"
81 #include "curl_sasl.h"
82 #include "warnless.h"
83 
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 imap_regular_transfer(struct connectdata *conn, bool *done);
91 static CURLcode imap_do(struct connectdata *conn, bool *done);
92 static CURLcode imap_done(struct connectdata *conn, CURLcode status,
93  bool premature);
94 static CURLcode imap_connect(struct connectdata *conn, bool *done);
95 static CURLcode imap_disconnect(struct connectdata *conn, bool dead);
96 static CURLcode imap_multi_statemach(struct connectdata *conn, bool *done);
97 static int imap_getsock(struct connectdata *conn, curl_socket_t *socks,
98  int numsocks);
99 static CURLcode imap_doing(struct connectdata *conn, bool *dophase_done);
100 static CURLcode imap_setup_connection(struct connectdata *conn);
101 static char *imap_atom(const char *str, bool escape_only);
102 static CURLcode imap_sendf(struct connectdata *conn, const char *fmt, ...);
103 static CURLcode imap_parse_url_options(struct connectdata *conn);
104 static CURLcode imap_parse_url_path(struct connectdata *conn);
105 static CURLcode imap_parse_custom_request(struct connectdata *conn);
107  const char *mech,
108  const char *initresp);
110  const char *resp);
111 static void imap_get_message(char *buffer, char **outptr);
112 
113 /*
114  * IMAP protocol handler.
115  */
116 
118  "IMAP", /* scheme */
119  imap_setup_connection, /* setup_connection */
120  imap_do, /* do_it */
121  imap_done, /* done */
122  ZERO_NULL, /* do_more */
123  imap_connect, /* connect_it */
124  imap_multi_statemach, /* connecting */
125  imap_doing, /* doing */
126  imap_getsock, /* proto_getsock */
127  imap_getsock, /* doing_getsock */
128  ZERO_NULL, /* domore_getsock */
129  ZERO_NULL, /* perform_getsock */
130  imap_disconnect, /* disconnect */
131  ZERO_NULL, /* readwrite */
132  ZERO_NULL, /* connection_check */
133  PORT_IMAP, /* defport */
134  CURLPROTO_IMAP, /* protocol */
135  PROTOPT_CLOSEACTION| /* flags */
137 };
138 
139 #ifdef USE_SSL
140 /*
141  * IMAPS protocol handler.
142  */
143 
144 const struct Curl_handler Curl_handler_imaps = {
145  "IMAPS", /* scheme */
146  imap_setup_connection, /* setup_connection */
147  imap_do, /* do_it */
148  imap_done, /* done */
149  ZERO_NULL, /* do_more */
150  imap_connect, /* connect_it */
151  imap_multi_statemach, /* connecting */
152  imap_doing, /* doing */
153  imap_getsock, /* proto_getsock */
154  imap_getsock, /* doing_getsock */
155  ZERO_NULL, /* domore_getsock */
156  ZERO_NULL, /* perform_getsock */
157  imap_disconnect, /* disconnect */
158  ZERO_NULL, /* readwrite */
159  ZERO_NULL, /* connection_check */
160  PORT_IMAPS, /* defport */
161  CURLPROTO_IMAPS, /* protocol */
162  PROTOPT_CLOSEACTION | PROTOPT_SSL /* flags */
163 };
164 #endif
165 
166 #define IMAP_RESP_OK 1
167 #define IMAP_RESP_NOT_OK 2
168 #define IMAP_RESP_PREAUTH 3
169 
170 /* SASL parameters for the imap protocol */
171 static const struct SASLproto saslimap = {
172  "imap", /* The service name */
173  '+', /* Code received when continuation is expected */
174  IMAP_RESP_OK, /* Code to receive upon authentication success */
175  0, /* Maximum initial response length (no max) */
176  imap_perform_authenticate, /* Send authentication command */
177  imap_continue_authenticate, /* Send authentication continuation */
178  imap_get_message /* Get SASL response message */
179 };
180 
181 
182 #ifdef USE_SSL
183 static void imap_to_imaps(struct connectdata *conn)
184 {
185  /* Change the connection handler */
186  conn->handler = &Curl_handler_imaps;
187 
188  /* Set the connection's upgraded to TLS flag */
189  conn->tls_upgraded = TRUE;
190 }
191 #else
192 #define imap_to_imaps(x) Curl_nop_stmt
193 #endif
194 
195 /***********************************************************************
196  *
197  * imap_matchresp()
198  *
199  * Determines whether the untagged response is related to the specified
200  * command by checking if it is in format "* <command-name> ..." or
201  * "* <number> <command-name> ...".
202  *
203  * The "* " marker is assumed to have already been checked by the caller.
204  */
205 static bool imap_matchresp(const char *line, size_t len, const char *cmd)
206 {
207  const char *end = line + len;
208  size_t cmd_len = strlen(cmd);
209 
210  /* Skip the untagged response marker */
211  line += 2;
212 
213  /* Do we have a number after the marker? */
214  if(line < end && ISDIGIT(*line)) {
215  /* Skip the number */
216  do
217  line++;
218  while(line < end && ISDIGIT(*line));
219 
220  /* Do we have the space character? */
221  if(line == end || *line != ' ')
222  return FALSE;
223 
224  line++;
225  }
226 
227  /* Does the command name match and is it followed by a space character or at
228  the end of line? */
229  if(line + cmd_len <= end && strncasecompare(line, cmd, cmd_len) &&
230  (line[cmd_len] == ' ' || line + cmd_len + 2 == end))
231  return TRUE;
232 
233  return FALSE;
234 }
235 
236 /***********************************************************************
237  *
238  * imap_endofresp()
239  *
240  * Checks whether the given string is a valid tagged, untagged or continuation
241  * response which can be processed by the response handler.
242  */
243 static bool imap_endofresp(struct connectdata *conn, char *line, size_t len,
244  int *resp)
245 {
246  struct IMAP *imap = conn->data->req.protop;
247  struct imap_conn *imapc = &conn->proto.imapc;
248  const char *id = imapc->resptag;
249  size_t id_len = strlen(id);
250 
251  /* Do we have a tagged command response? */
252  if(len >= id_len + 1 && !memcmp(id, line, id_len) && line[id_len] == ' ') {
253  line += id_len + 1;
254  len -= id_len + 1;
255 
256  if(len >= 2 && !memcmp(line, "OK", 2))
257  *resp = IMAP_RESP_OK;
258  else if(len >= 7 && !memcmp(line, "PREAUTH", 7))
259  *resp = IMAP_RESP_PREAUTH;
260  else
261  *resp = IMAP_RESP_NOT_OK;
262 
263  return TRUE;
264  }
265 
266  /* Do we have an untagged command response? */
267  if(len >= 2 && !memcmp("* ", line, 2)) {
268  switch(imapc->state) {
269  /* States which are interested in untagged responses */
270  case IMAP_CAPABILITY:
271  if(!imap_matchresp(line, len, "CAPABILITY"))
272  return FALSE;
273  break;
274 
275  case IMAP_LIST:
276  if((!imap->custom && !imap_matchresp(line, len, "LIST")) ||
277  (imap->custom && !imap_matchresp(line, len, imap->custom) &&
278  (strcmp(imap->custom, "STORE") ||
279  !imap_matchresp(line, len, "FETCH")) &&
280  strcmp(imap->custom, "SELECT") &&
281  strcmp(imap->custom, "EXAMINE") &&
282  strcmp(imap->custom, "SEARCH") &&
283  strcmp(imap->custom, "EXPUNGE") &&
284  strcmp(imap->custom, "LSUB") &&
285  strcmp(imap->custom, "UID") &&
286  strcmp(imap->custom, "NOOP")))
287  return FALSE;
288  break;
289 
290  case IMAP_SELECT:
291  /* SELECT is special in that its untagged responses do not have a
292  common prefix so accept anything! */
293  break;
294 
295  case IMAP_FETCH:
296  if(!imap_matchresp(line, len, "FETCH"))
297  return FALSE;
298  break;
299 
300  case IMAP_SEARCH:
301  if(!imap_matchresp(line, len, "SEARCH"))
302  return FALSE;
303  break;
304 
305  /* Ignore other untagged responses */
306  default:
307  return FALSE;
308  }
309 
310  *resp = '*';
311  return TRUE;
312  }
313 
314  /* Do we have a continuation response? This should be a + symbol followed by
315  a space and optionally some text as per RFC-3501 for the AUTHENTICATE and
316  APPEND commands and as outlined in Section 4. Examples of RFC-4959 but
317  some e-mail servers ignore this and only send a single + instead. */
318  if(imap && !imap->custom && ((len == 3 && !memcmp("+", line, 1)) ||
319  (len >= 2 && !memcmp("+ ", line, 2)))) {
320  switch(imapc->state) {
321  /* States which are interested in continuation responses */
322  case IMAP_AUTHENTICATE:
323  case IMAP_APPEND:
324  *resp = '+';
325  break;
326 
327  default:
328  failf(conn->data, "Unexpected continuation response");
329  *resp = -1;
330  break;
331  }
332 
333  return TRUE;
334  }
335 
336  return FALSE; /* Nothing for us */
337 }
338 
339 /***********************************************************************
340  *
341  * imap_get_message()
342  *
343  * Gets the authentication message from the response buffer.
344  */
345 static void imap_get_message(char *buffer, char **outptr)
346 {
347  size_t len = 0;
348  char *message = NULL;
349 
350  /* Find the start of the message */
351  for(message = buffer + 2; *message == ' ' || *message == '\t'; message++)
352  ;
353 
354  /* Find the end of the message */
355  for(len = strlen(message); len--;)
356  if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
357  message[len] != '\t')
358  break;
359 
360  /* Terminate the message */
361  if(++len) {
362  message[len] = '\0';
363  }
364 
365  *outptr = message;
366 }
367 
368 /***********************************************************************
369  *
370  * state()
371  *
372  * This is the ONLY way to change IMAP state!
373  */
374 static void state(struct connectdata *conn, imapstate newstate)
375 {
376  struct imap_conn *imapc = &conn->proto.imapc;
377 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
378  /* for debug purposes */
379  static const char * const names[]={
380  "STOP",
381  "SERVERGREET",
382  "CAPABILITY",
383  "STARTTLS",
384  "UPGRADETLS",
385  "AUTHENTICATE",
386  "LOGIN",
387  "LIST",
388  "SELECT",
389  "FETCH",
390  "FETCH_FINAL",
391  "APPEND",
392  "APPEND_FINAL",
393  "SEARCH",
394  "LOGOUT",
395  /* LAST */
396  };
397 
398  if(imapc->state != newstate)
399  infof(conn->data, "IMAP %p state change from %s to %s\n",
400  (void *)imapc, names[imapc->state], names[newstate]);
401 #endif
402 
403  imapc->state = newstate;
404 }
405 
406 /***********************************************************************
407  *
408  * imap_perform_capability()
409  *
410  * Sends the CAPABILITY command in order to obtain a list of server side
411  * supported capabilities.
412  */
414 {
416  struct imap_conn *imapc = &conn->proto.imapc;
417 
418  imapc->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanisms yet */
419  imapc->sasl.authused = SASL_AUTH_NONE; /* Clear the auth. mechanism used */
420  imapc->tls_supported = FALSE; /* Clear the TLS capability */
421 
422  /* Send the CAPABILITY command */
423  result = imap_sendf(conn, "CAPABILITY");
424 
425  if(!result)
426  state(conn, IMAP_CAPABILITY);
427 
428  return result;
429 }
430 
431 /***********************************************************************
432  *
433  * imap_perform_starttls()
434  *
435  * Sends the STARTTLS command to start the upgrade to TLS.
436  */
438 {
440 
441  /* Send the STARTTLS command */
442  result = imap_sendf(conn, "STARTTLS");
443 
444  if(!result)
445  state(conn, IMAP_STARTTLS);
446 
447  return result;
448 }
449 
450 /***********************************************************************
451  *
452  * imap_perform_upgrade_tls()
453  *
454  * Performs the upgrade to TLS.
455  */
457 {
459  struct imap_conn *imapc = &conn->proto.imapc;
460 
461  /* Start the SSL connection */
462  result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &imapc->ssldone);
463 
464  if(!result) {
465  if(imapc->state != IMAP_UPGRADETLS)
466  state(conn, IMAP_UPGRADETLS);
467 
468  if(imapc->ssldone) {
469  imap_to_imaps(conn);
470  result = imap_perform_capability(conn);
471  }
472  }
473 
474  return result;
475 }
476 
477 /***********************************************************************
478  *
479  * imap_perform_login()
480  *
481  * Sends a clear text LOGIN command to authenticate with.
482  */
484 {
486  char *user;
487  char *passwd;
488 
489  /* Check we have a username and password to authenticate with and end the
490  connect phase if we don't */
491  if(!conn->bits.user_passwd) {
492  state(conn, IMAP_STOP);
493 
494  return result;
495  }
496 
497  /* Make sure the username and password are in the correct atom format */
498  user = imap_atom(conn->user, false);
499  passwd = imap_atom(conn->passwd, false);
500 
501  /* Send the LOGIN command */
502  result = imap_sendf(conn, "LOGIN %s %s", user ? user : "",
503  passwd ? passwd : "");
504 
505  free(user);
506  free(passwd);
507 
508  if(!result)
509  state(conn, IMAP_LOGIN);
510 
511  return result;
512 }
513 
514 /***********************************************************************
515  *
516  * imap_perform_authenticate()
517  *
518  * Sends an AUTHENTICATE command allowing the client to login with the given
519  * SASL authentication mechanism.
520  */
522  const char *mech,
523  const char *initresp)
524 {
526 
527  if(initresp) {
528  /* Send the AUTHENTICATE command with the initial response */
529  result = imap_sendf(conn, "AUTHENTICATE %s %s", mech, initresp);
530  }
531  else {
532  /* Send the AUTHENTICATE command */
533  result = imap_sendf(conn, "AUTHENTICATE %s", mech);
534  }
535 
536  return result;
537 }
538 
539 /***********************************************************************
540  *
541  * imap_continue_authenticate()
542  *
543  * Sends SASL continuation data or cancellation.
544  */
546  const char *resp)
547 {
548  struct imap_conn *imapc = &conn->proto.imapc;
549 
550  return Curl_pp_sendf(&imapc->pp, "%s", resp);
551 }
552 
553 /***********************************************************************
554  *
555  * imap_perform_authentication()
556  *
557  * Initiates the authentication sequence, with the appropriate SASL
558  * authentication mechanism, falling back to clear text should a common
559  * mechanism not be available between the client and server.
560  */
562 {
564  struct imap_conn *imapc = &conn->proto.imapc;
565  saslprogress progress;
566 
567  /* Check if already authenticated OR if there is enough data to authenticate
568  with and end the connect phase if we don't */
569  if(imapc->preauth ||
570  !Curl_sasl_can_authenticate(&imapc->sasl, conn)) {
571  state(conn, IMAP_STOP);
572  return result;
573  }
574 
575  /* Calculate the SASL login details */
576  result = Curl_sasl_start(&imapc->sasl, conn, imapc->ir_supported, &progress);
577 
578  if(!result) {
579  if(progress == SASL_INPROGRESS)
580  state(conn, IMAP_AUTHENTICATE);
581  else if(!imapc->login_disabled && (imapc->preftype & IMAP_TYPE_CLEARTEXT))
582  /* Perform clear text authentication */
583  result = imap_perform_login(conn);
584  else {
585  /* Other mechanisms not supported */
586  infof(conn->data, "No known authentication mechanisms supported!\n");
587  result = CURLE_LOGIN_DENIED;
588  }
589  }
590 
591  return result;
592 }
593 
594 /***********************************************************************
595  *
596  * imap_perform_list()
597  *
598  * Sends a LIST command or an alternative custom request.
599  */
601 {
603  struct Curl_easy *data = conn->data;
604  struct IMAP *imap = data->req.protop;
605  char *mailbox;
606 
607  if(imap->custom)
608  /* Send the custom request */
609  result = imap_sendf(conn, "%s%s", imap->custom,
610  imap->custom_params ? imap->custom_params : "");
611  else {
612  /* Make sure the mailbox is in the correct atom format if necessary */
613  mailbox = imap->mailbox ? imap_atom(imap->mailbox, true) : strdup("");
614  if(!mailbox)
615  return CURLE_OUT_OF_MEMORY;
616 
617  /* Send the LIST command */
618  result = imap_sendf(conn, "LIST \"%s\" *", mailbox);
619 
620  free(mailbox);
621  }
622 
623  if(!result)
624  state(conn, IMAP_LIST);
625 
626  return result;
627 }
628 
629 /***********************************************************************
630  *
631  * imap_perform_select()
632  *
633  * Sends a SELECT command to ask the server to change the selected mailbox.
634  */
636 {
638  struct Curl_easy *data = conn->data;
639  struct IMAP *imap = data->req.protop;
640  struct imap_conn *imapc = &conn->proto.imapc;
641  char *mailbox;
642 
643  /* Invalidate old information as we are switching mailboxes */
644  Curl_safefree(imapc->mailbox);
646 
647  /* Check we have a mailbox */
648  if(!imap->mailbox) {
649  failf(conn->data, "Cannot SELECT without a mailbox.");
650  return CURLE_URL_MALFORMAT;
651  }
652 
653  /* Make sure the mailbox is in the correct atom format */
654  mailbox = imap_atom(imap->mailbox, false);
655  if(!mailbox)
656  return CURLE_OUT_OF_MEMORY;
657 
658  /* Send the SELECT command */
659  result = imap_sendf(conn, "SELECT %s", mailbox);
660 
661  free(mailbox);
662 
663  if(!result)
664  state(conn, IMAP_SELECT);
665 
666  return result;
667 }
668 
669 /***********************************************************************
670  *
671  * imap_perform_fetch()
672  *
673  * Sends a FETCH command to initiate the download of a message.
674  */
676 {
678  struct IMAP *imap = conn->data->req.protop;
679 
680  /* Check we have a UID */
681  if(!imap->uid) {
682  failf(conn->data, "Cannot FETCH without a UID.");
683  return CURLE_URL_MALFORMAT;
684  }
685 
686  /* Send the FETCH command */
687  if(imap->partial)
688  result = imap_sendf(conn, "FETCH %s BODY[%s]<%s>",
689  imap->uid,
690  imap->section ? imap->section : "",
691  imap->partial);
692  else
693  result = imap_sendf(conn, "FETCH %s BODY[%s]",
694  imap->uid,
695  imap->section ? imap->section : "");
696 
697  if(!result)
698  state(conn, IMAP_FETCH);
699 
700  return result;
701 }
702 
703 /***********************************************************************
704  *
705  * imap_perform_append()
706  *
707  * Sends an APPEND command to initiate the upload of a message.
708  */
710 {
712  struct Curl_easy *data = conn->data;
713  struct IMAP *imap = data->req.protop;
714  char *mailbox;
715 
716  /* Check we have a mailbox */
717  if(!imap->mailbox) {
718  failf(data, "Cannot APPEND without a mailbox.");
719  return CURLE_URL_MALFORMAT;
720  }
721 
722  /* Prepare the mime data if some. */
723  if(data->set.mimepost.kind != MIMEKIND_NONE) {
724  /* Use the whole structure as data. */
725  data->set.mimepost.flags &= ~MIME_BODY_ONLY;
726 
727  /* Add external headers and mime version. */
728  curl_mime_headers(&data->set.mimepost, data->set.headers, 0);
729  result = Curl_mime_prepare_headers(&data->set.mimepost, NULL,
730  NULL, MIMESTRATEGY_MAIL);
731 
732  if(!result)
733  if(!Curl_checkheaders(conn, "Mime-Version"))
735  "Mime-Version: 1.0");
736 
737  /* Make sure we will read the entire mime structure. */
738  if(!result)
739  result = Curl_mime_rewind(&data->set.mimepost);
740 
741  if(result)
742  return result;
743 
744  data->state.infilesize = Curl_mime_size(&data->set.mimepost);
745 
746  /* Read from mime structure. */
748  data->state.in = (void *) &data->set.mimepost;
749  }
750 
751  /* Check we know the size of the upload */
752  if(data->state.infilesize < 0) {
753  failf(data, "Cannot APPEND with unknown input file size\n");
754  return CURLE_UPLOAD_FAILED;
755  }
756 
757  /* Make sure the mailbox is in the correct atom format */
758  mailbox = imap_atom(imap->mailbox, false);
759  if(!mailbox)
760  return CURLE_OUT_OF_MEMORY;
761 
762  /* Send the APPEND command */
763  result = imap_sendf(conn, "APPEND %s (\\Seen) {%" CURL_FORMAT_CURL_OFF_T "}",
764  mailbox, data->state.infilesize);
765 
766  free(mailbox);
767 
768  if(!result)
769  state(conn, IMAP_APPEND);
770 
771  return result;
772 }
773 
774 /***********************************************************************
775  *
776  * imap_perform_search()
777  *
778  * Sends a SEARCH command.
779  */
781 {
783  struct IMAP *imap = conn->data->req.protop;
784 
785  /* Check we have a query string */
786  if(!imap->query) {
787  failf(conn->data, "Cannot SEARCH without a query string.");
788  return CURLE_URL_MALFORMAT;
789  }
790 
791  /* Send the SEARCH command */
792  result = imap_sendf(conn, "SEARCH %s", imap->query);
793 
794  if(!result)
795  state(conn, IMAP_SEARCH);
796 
797  return result;
798 }
799 
800 /***********************************************************************
801  *
802  * imap_perform_logout()
803  *
804  * Performs the logout action prior to sclose() being called.
805  */
807 {
809 
810  /* Send the LOGOUT command */
811  result = imap_sendf(conn, "LOGOUT");
812 
813  if(!result)
814  state(conn, IMAP_LOGOUT);
815 
816  return result;
817 }
818 
819 /* For the initial server greeting */
821  int imapcode,
822  imapstate instate)
823 {
824  struct Curl_easy *data = conn->data;
825  (void)instate; /* no use for this yet */
826 
827  if(imapcode == IMAP_RESP_PREAUTH) {
828  /* PREAUTH */
829  struct imap_conn *imapc = &conn->proto.imapc;
830  imapc->preauth = TRUE;
831  infof(data, "PREAUTH connection, already authenticated!\n");
832  }
833  else if(imapcode != IMAP_RESP_OK) {
834  failf(data, "Got unexpected imap-server response");
836  }
837 
838  return imap_perform_capability(conn);
839 }
840 
841 /* For CAPABILITY responses */
843  int imapcode,
844  imapstate instate)
845 {
847  struct Curl_easy *data = conn->data;
848  struct imap_conn *imapc = &conn->proto.imapc;
849  const char *line = data->state.buffer;
850  size_t wordlen;
851 
852  (void)instate; /* no use for this yet */
853 
854  /* Do we have a untagged response? */
855  if(imapcode == '*') {
856  line += 2;
857 
858  /* Loop through the data line */
859  for(;;) {
860  while(*line &&
861  (*line == ' ' || *line == '\t' ||
862  *line == '\r' || *line == '\n')) {
863 
864  line++;
865  }
866 
867  if(!*line)
868  break;
869 
870  /* Extract the word */
871  for(wordlen = 0; line[wordlen] && line[wordlen] != ' ' &&
872  line[wordlen] != '\t' && line[wordlen] != '\r' &&
873  line[wordlen] != '\n';)
874  wordlen++;
875 
876  /* Does the server support the STARTTLS capability? */
877  if(wordlen == 8 && !memcmp(line, "STARTTLS", 8))
878  imapc->tls_supported = TRUE;
879 
880  /* Has the server explicitly disabled clear text authentication? */
881  else if(wordlen == 13 && !memcmp(line, "LOGINDISABLED", 13))
882  imapc->login_disabled = TRUE;
883 
884  /* Does the server support the SASL-IR capability? */
885  else if(wordlen == 7 && !memcmp(line, "SASL-IR", 7))
886  imapc->ir_supported = TRUE;
887 
888  /* Do we have a SASL based authentication mechanism? */
889  else if(wordlen > 5 && !memcmp(line, "AUTH=", 5)) {
890  size_t llen;
891  unsigned int mechbit;
892 
893  line += 5;
894  wordlen -= 5;
895 
896  /* Test the word for a matching authentication mechanism */
897  mechbit = Curl_sasl_decode_mech(line, wordlen, &llen);
898  if(mechbit && llen == wordlen)
899  imapc->sasl.authmechs |= mechbit;
900  }
901 
902  line += wordlen;
903  }
904  }
905  else if(imapcode == IMAP_RESP_OK) {
906  if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
907  /* We don't have a SSL/TLS connection yet, but SSL is requested */
908  if(imapc->tls_supported)
909  /* Switch to TLS connection now */
910  result = imap_perform_starttls(conn);
911  else if(data->set.use_ssl == CURLUSESSL_TRY)
912  /* Fallback and carry on with authentication */
913  result = imap_perform_authentication(conn);
914  else {
915  failf(data, "STARTTLS not supported.");
916  result = CURLE_USE_SSL_FAILED;
917  }
918  }
919  else
920  result = imap_perform_authentication(conn);
921  }
922  else
923  result = imap_perform_authentication(conn);
924 
925  return result;
926 }
927 
928 /* For STARTTLS responses */
930  int imapcode,
931  imapstate instate)
932 {
934  struct Curl_easy *data = conn->data;
935 
936  (void)instate; /* no use for this yet */
937 
938  if(imapcode != IMAP_RESP_OK) {
939  if(data->set.use_ssl != CURLUSESSL_TRY) {
940  failf(data, "STARTTLS denied");
941  result = CURLE_USE_SSL_FAILED;
942  }
943  else
944  result = imap_perform_authentication(conn);
945  }
946  else
947  result = imap_perform_upgrade_tls(conn);
948 
949  return result;
950 }
951 
952 /* For SASL authentication responses */
954  int imapcode,
955  imapstate instate)
956 {
958  struct Curl_easy *data = conn->data;
959  struct imap_conn *imapc = &conn->proto.imapc;
960  saslprogress progress;
961 
962  (void)instate; /* no use for this yet */
963 
964  result = Curl_sasl_continue(&imapc->sasl, conn, imapcode, &progress);
965  if(!result)
966  switch(progress) {
967  case SASL_DONE:
968  state(conn, IMAP_STOP); /* Authenticated */
969  break;
970  case SASL_IDLE: /* No mechanism left after cancellation */
971  if((!imapc->login_disabled) && (imapc->preftype & IMAP_TYPE_CLEARTEXT))
972  /* Perform clear text authentication */
973  result = imap_perform_login(conn);
974  else {
975  failf(data, "Authentication cancelled");
976  result = CURLE_LOGIN_DENIED;
977  }
978  break;
979  default:
980  break;
981  }
982 
983  return result;
984 }
985 
986 /* For LOGIN responses */
988  int imapcode,
989  imapstate instate)
990 {
992  struct Curl_easy *data = conn->data;
993 
994  (void)instate; /* no use for this yet */
995 
996  if(imapcode != IMAP_RESP_OK) {
997  failf(data, "Access denied. %c", imapcode);
998  result = CURLE_LOGIN_DENIED;
999  }
1000  else
1001  /* End of connect phase */
1002  state(conn, IMAP_STOP);
1003 
1004  return result;
1005 }
1006 
1007 /* For LIST and SEARCH responses */
1009  int imapcode,
1010  imapstate instate)
1011 {
1013  char *line = conn->data->state.buffer;
1014  size_t len = strlen(line);
1015 
1016  (void)instate; /* No use for this yet */
1017 
1018  if(imapcode == '*') {
1019  /* Temporarily add the LF character back and send as body to the client */
1020  line[len] = '\n';
1021  result = Curl_client_write(conn, CLIENTWRITE_BODY, line, len + 1);
1022  line[len] = '\0';
1023  }
1024  else if(imapcode != IMAP_RESP_OK)
1025  result = CURLE_QUOTE_ERROR; /* TODO: Fix error code */
1026  else
1027  /* End of DO phase */
1028  state(conn, IMAP_STOP);
1029 
1030  return result;
1031 }
1032 
1033 /* For SELECT responses */
1034 static CURLcode imap_state_select_resp(struct connectdata *conn, int imapcode,
1035  imapstate instate)
1036 {
1038  struct Curl_easy *data = conn->data;
1039  struct IMAP *imap = conn->data->req.protop;
1040  struct imap_conn *imapc = &conn->proto.imapc;
1041  const char *line = data->state.buffer;
1042  char tmp[20];
1043 
1044  (void)instate; /* no use for this yet */
1045 
1046  if(imapcode == '*') {
1047  /* See if this is an UIDVALIDITY response */
1048  if(sscanf(line + 2, "OK [UIDVALIDITY %19[0123456789]]", tmp) == 1) {
1050  imapc->mailbox_uidvalidity = strdup(tmp);
1051  }
1052  }
1053  else if(imapcode == IMAP_RESP_OK) {
1054  /* Check if the UIDVALIDITY has been specified and matches */
1055  if(imap->uidvalidity && imapc->mailbox_uidvalidity &&
1056  strcmp(imap->uidvalidity, imapc->mailbox_uidvalidity)) {
1057  failf(conn->data, "Mailbox UIDVALIDITY has changed");
1058  result = CURLE_REMOTE_FILE_NOT_FOUND;
1059  }
1060  else {
1061  /* Note the currently opened mailbox on this connection */
1062  imapc->mailbox = strdup(imap->mailbox);
1063 
1064  if(imap->custom)
1065  result = imap_perform_list(conn);
1066  else if(imap->query)
1067  result = imap_perform_search(conn);
1068  else
1069  result = imap_perform_fetch(conn);
1070  }
1071  }
1072  else {
1073  failf(data, "Select failed");
1074  result = CURLE_LOGIN_DENIED;
1075  }
1076 
1077  return result;
1078 }
1079 
1080 /* For the (first line of the) FETCH responses */
1081 static CURLcode imap_state_fetch_resp(struct connectdata *conn, int imapcode,
1082  imapstate instate)
1083 {
1085  struct Curl_easy *data = conn->data;
1086  struct imap_conn *imapc = &conn->proto.imapc;
1087  struct pingpong *pp = &imapc->pp;
1088  const char *ptr = data->state.buffer;
1089  bool parsed = FALSE;
1090  curl_off_t size = 0;
1091 
1092  (void)instate; /* no use for this yet */
1093 
1094  if(imapcode != '*') {
1095  Curl_pgrsSetDownloadSize(data, -1);
1096  state(conn, IMAP_STOP);
1097  return CURLE_REMOTE_FILE_NOT_FOUND; /* TODO: Fix error code */
1098  }
1099 
1100  /* Something like this is received "* 1 FETCH (BODY[TEXT] {2021}\r" so parse
1101  the continuation data contained within the curly brackets */
1102  while(*ptr && (*ptr != '{'))
1103  ptr++;
1104 
1105  if(*ptr == '{') {
1106  char *endptr;
1107  if(!curlx_strtoofft(ptr + 1, &endptr, 10, &size)) {
1108  if(endptr - ptr > 1 && endptr[0] == '}' &&
1109  endptr[1] == '\r' && endptr[2] == '\0')
1110  parsed = TRUE;
1111  }
1112  }
1113 
1114  if(parsed) {
1115  infof(data, "Found %" CURL_FORMAT_CURL_OFF_TU " bytes to download\n",
1116  size);
1117  Curl_pgrsSetDownloadSize(data, size);
1118 
1119  if(pp->cache) {
1120  /* At this point there is a bunch of data in the header "cache" that is
1121  actually body content, send it as body and then skip it. Do note
1122  that there may even be additional "headers" after the body. */
1123  size_t chunk = pp->cache_size;
1124 
1125  if(chunk > (size_t)size)
1126  /* The conversion from curl_off_t to size_t is always fine here */
1127  chunk = (size_t)size;
1128 
1129  result = Curl_client_write(conn, CLIENTWRITE_BODY, pp->cache, chunk);
1130  if(result)
1131  return result;
1132 
1133  data->req.bytecount += chunk;
1134 
1135  infof(data, "Written %" CURL_FORMAT_CURL_OFF_TU
1136  " bytes, %" CURL_FORMAT_CURL_OFF_TU
1137  " bytes are left for transfer\n", (curl_off_t)chunk,
1138  size - chunk);
1139 
1140  /* Have we used the entire cache or just part of it?*/
1141  if(pp->cache_size > chunk) {
1142  /* Only part of it so shrink the cache to fit the trailing data */
1143  memmove(pp->cache, pp->cache + chunk, pp->cache_size - chunk);
1144  pp->cache_size -= chunk;
1145  }
1146  else {
1147  /* Free the cache */
1148  Curl_safefree(pp->cache);
1149 
1150  /* Reset the cache size */
1151  pp->cache_size = 0;
1152  }
1153  }
1154 
1155  if(data->req.bytecount == size)
1156  /* The entire data is already transferred! */
1157  Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1158  else {
1159  /* IMAP download */
1160  data->req.maxdownload = size;
1161  Curl_setup_transfer(conn, FIRSTSOCKET, size, FALSE, NULL, -1, NULL);
1162  }
1163  }
1164  else {
1165  /* We don't know how to parse this line */
1166  failf(pp->conn->data, "Failed to parse FETCH response.");
1167  result = CURLE_WEIRD_SERVER_REPLY;
1168  }
1169 
1170  /* End of DO phase */
1171  state(conn, IMAP_STOP);
1172 
1173  return result;
1174 }
1175 
1176 /* For final FETCH responses performed after the download */
1178  int imapcode,
1179  imapstate instate)
1180 {
1182 
1183  (void)instate; /* No use for this yet */
1184 
1185  if(imapcode != IMAP_RESP_OK)
1186  result = CURLE_WEIRD_SERVER_REPLY;
1187  else
1188  /* End of DONE phase */
1189  state(conn, IMAP_STOP);
1190 
1191  return result;
1192 }
1193 
1194 /* For APPEND responses */
1195 static CURLcode imap_state_append_resp(struct connectdata *conn, int imapcode,
1196  imapstate instate)
1197 {
1199  struct Curl_easy *data = conn->data;
1200 
1201  (void)instate; /* No use for this yet */
1202 
1203  if(imapcode != '+') {
1204  result = CURLE_UPLOAD_FAILED;
1205  }
1206  else {
1207  /* Set the progress upload size */
1209 
1210  /* IMAP upload */
1211  Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL);
1212 
1213  /* End of DO phase */
1214  state(conn, IMAP_STOP);
1215  }
1216 
1217  return result;
1218 }
1219 
1220 /* For final APPEND responses performed after the upload */
1222  int imapcode,
1223  imapstate instate)
1224 {
1226 
1227  (void)instate; /* No use for this yet */
1228 
1229  if(imapcode != IMAP_RESP_OK)
1230  result = CURLE_UPLOAD_FAILED;
1231  else
1232  /* End of DONE phase */
1233  state(conn, IMAP_STOP);
1234 
1235  return result;
1236 }
1237 
1239 {
1241  curl_socket_t sock = conn->sock[FIRSTSOCKET];
1242  int imapcode;
1243  struct imap_conn *imapc = &conn->proto.imapc;
1244  struct pingpong *pp = &imapc->pp;
1245  size_t nread = 0;
1246 
1247  /* Busy upgrading the connection; right now all I/O is SSL/TLS, not IMAP */
1248  if(imapc->state == IMAP_UPGRADETLS)
1249  return imap_perform_upgrade_tls(conn);
1250 
1251  /* Flush any data that needs to be sent */
1252  if(pp->sendleft)
1253  return Curl_pp_flushsend(pp);
1254 
1255  do {
1256  /* Read the response from the server */
1257  result = Curl_pp_readresp(sock, pp, &imapcode, &nread);
1258  if(result)
1259  return result;
1260 
1261  /* Was there an error parsing the response line? */
1262  if(imapcode == -1)
1263  return CURLE_WEIRD_SERVER_REPLY;
1264 
1265  if(!imapcode)
1266  break;
1267 
1268  /* We have now received a full IMAP server response */
1269  switch(imapc->state) {
1270  case IMAP_SERVERGREET:
1271  result = imap_state_servergreet_resp(conn, imapcode, imapc->state);
1272  break;
1273 
1274  case IMAP_CAPABILITY:
1275  result = imap_state_capability_resp(conn, imapcode, imapc->state);
1276  break;
1277 
1278  case IMAP_STARTTLS:
1279  result = imap_state_starttls_resp(conn, imapcode, imapc->state);
1280  break;
1281 
1282  case IMAP_AUTHENTICATE:
1283  result = imap_state_auth_resp(conn, imapcode, imapc->state);
1284  break;
1285 
1286  case IMAP_LOGIN:
1287  result = imap_state_login_resp(conn, imapcode, imapc->state);
1288  break;
1289 
1290  case IMAP_LIST:
1291  result = imap_state_listsearch_resp(conn, imapcode, imapc->state);
1292  break;
1293 
1294  case IMAP_SELECT:
1295  result = imap_state_select_resp(conn, imapcode, imapc->state);
1296  break;
1297 
1298  case IMAP_FETCH:
1299  result = imap_state_fetch_resp(conn, imapcode, imapc->state);
1300  break;
1301 
1302  case IMAP_FETCH_FINAL:
1303  result = imap_state_fetch_final_resp(conn, imapcode, imapc->state);
1304  break;
1305 
1306  case IMAP_APPEND:
1307  result = imap_state_append_resp(conn, imapcode, imapc->state);
1308  break;
1309 
1310  case IMAP_APPEND_FINAL:
1311  result = imap_state_append_final_resp(conn, imapcode, imapc->state);
1312  break;
1313 
1314  case IMAP_SEARCH:
1315  result = imap_state_listsearch_resp(conn, imapcode, imapc->state);
1316  break;
1317 
1318  case IMAP_LOGOUT:
1319  /* fallthrough, just stop! */
1320  default:
1321  /* internal error */
1322  state(conn, IMAP_STOP);
1323  break;
1324  }
1325  } while(!result && imapc->state != IMAP_STOP && Curl_pp_moredata(pp));
1326 
1327  return result;
1328 }
1329 
1330 /* Called repeatedly until done from multi.c */
1331 static CURLcode imap_multi_statemach(struct connectdata *conn, bool *done)
1332 {
1334  struct imap_conn *imapc = &conn->proto.imapc;
1335 
1336  if((conn->handler->flags & PROTOPT_SSL) && !imapc->ssldone) {
1337  result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &imapc->ssldone);
1338  if(result || !imapc->ssldone)
1339  return result;
1340  }
1341 
1342  result = Curl_pp_statemach(&imapc->pp, FALSE);
1343  *done = (imapc->state == IMAP_STOP) ? TRUE : FALSE;
1344 
1345  return result;
1346 }
1347 
1349 {
1351  struct imap_conn *imapc = &conn->proto.imapc;
1352 
1353  while(imapc->state != IMAP_STOP && !result)
1354  result = Curl_pp_statemach(&imapc->pp, TRUE);
1355 
1356  return result;
1357 }
1358 
1359 /* Allocate and initialize the struct IMAP for the current Curl_easy if
1360  required */
1361 static CURLcode imap_init(struct connectdata *conn)
1362 {
1364  struct Curl_easy *data = conn->data;
1365  struct IMAP *imap;
1366 
1367  imap = data->req.protop = calloc(sizeof(struct IMAP), 1);
1368  if(!imap)
1369  result = CURLE_OUT_OF_MEMORY;
1370 
1371  return result;
1372 }
1373 
1374 /* For the IMAP "protocol connect" and "doing" phases only */
1375 static int imap_getsock(struct connectdata *conn, curl_socket_t *socks,
1376  int numsocks)
1377 {
1378  return Curl_pp_getsock(&conn->proto.imapc.pp, socks, numsocks);
1379 }
1380 
1381 /***********************************************************************
1382  *
1383  * imap_connect()
1384  *
1385  * This function should do everything that is to be considered a part of the
1386  * connection phase.
1387  *
1388  * The variable 'done' points to will be TRUE if the protocol-layer connect
1389  * phase is done when this function returns, or FALSE if not.
1390  */
1391 static CURLcode imap_connect(struct connectdata *conn, bool *done)
1392 {
1394  struct imap_conn *imapc = &conn->proto.imapc;
1395  struct pingpong *pp = &imapc->pp;
1396 
1397  *done = FALSE; /* default to not done yet */
1398 
1399  /* We always support persistent connections in IMAP */
1400  connkeep(conn, "IMAP default");
1401 
1402  /* Set the default response time-out */
1405  pp->endofresp = imap_endofresp;
1406  pp->conn = conn;
1407 
1408  /* Set the default preferred authentication type and mechanism */
1409  imapc->preftype = IMAP_TYPE_ANY;
1410  Curl_sasl_init(&imapc->sasl, &saslimap);
1411 
1412  /* Initialise the pingpong layer */
1413  Curl_pp_init(pp);
1414 
1415  /* Parse the URL options */
1416  result = imap_parse_url_options(conn);
1417  if(result)
1418  return result;
1419 
1420  /* Start off waiting for the server greeting response */
1421  state(conn, IMAP_SERVERGREET);
1422 
1423  /* Start off with an response id of '*' */
1424  strcpy(imapc->resptag, "*");
1425 
1426  result = imap_multi_statemach(conn, done);
1427 
1428  return result;
1429 }
1430 
1431 /***********************************************************************
1432  *
1433  * imap_done()
1434  *
1435  * The DONE function. This does what needs to be done after a single DO has
1436  * performed.
1437  *
1438  * Input argument is already checked for validity.
1439  */
1440 static CURLcode imap_done(struct connectdata *conn, CURLcode status,
1441  bool premature)
1442 {
1444  struct Curl_easy *data = conn->data;
1445  struct IMAP *imap = data->req.protop;
1446 
1447  (void)premature;
1448 
1449  if(!imap)
1450  return CURLE_OK;
1451 
1452  if(status) {
1453  connclose(conn, "IMAP done with bad status"); /* marked for closure */
1454  result = status; /* use the already set error code */
1455  }
1456  else if(!data->set.connect_only && !imap->custom &&
1457  (imap->uid || data->set.upload ||
1458  data->set.mimepost.kind != MIMEKIND_NONE)) {
1459  /* Handle responses after FETCH or APPEND transfer has finished */
1460  if(!data->set.upload && data->set.mimepost.kind == MIMEKIND_NONE)
1461  state(conn, IMAP_FETCH_FINAL);
1462  else {
1463  /* End the APPEND command first by sending an empty line */
1464  result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", "");
1465  if(!result)
1466  state(conn, IMAP_APPEND_FINAL);
1467  }
1468 
1469  /* Run the state-machine
1470 
1471  TODO: when the multi interface is used, this _really_ should be using
1472  the imap_multi_statemach function but we have no general support for
1473  non-blocking DONE operations!
1474  */
1475  if(!result)
1476  result = imap_block_statemach(conn);
1477  }
1478 
1479  /* Cleanup our per-request based variables */
1480  Curl_safefree(imap->mailbox);
1481  Curl_safefree(imap->uidvalidity);
1482  Curl_safefree(imap->uid);
1483  Curl_safefree(imap->section);
1484  Curl_safefree(imap->partial);
1485  Curl_safefree(imap->query);
1486  Curl_safefree(imap->custom);
1488 
1489  /* Clear the transfer mode for the next request */
1490  imap->transfer = FTPTRANSFER_BODY;
1491 
1492  return result;
1493 }
1494 
1495 /***********************************************************************
1496  *
1497  * imap_perform()
1498  *
1499  * This is the actual DO function for IMAP. Fetch or append a message, or do
1500  * other things according to the options previously setup.
1501  */
1502 static CURLcode imap_perform(struct connectdata *conn, bool *connected,
1503  bool *dophase_done)
1504 {
1505  /* This is IMAP and no proxy */
1507  struct Curl_easy *data = conn->data;
1508  struct IMAP *imap = data->req.protop;
1509  struct imap_conn *imapc = &conn->proto.imapc;
1510  bool selected = FALSE;
1511 
1512  DEBUGF(infof(conn->data, "DO phase starts\n"));
1513 
1514  if(conn->data->set.opt_no_body) {
1515  /* Requested no body means no transfer */
1516  imap->transfer = FTPTRANSFER_INFO;
1517  }
1518 
1519  *dophase_done = FALSE; /* not done yet */
1520 
1521  /* Determine if the requested mailbox (with the same UIDVALIDITY if set)
1522  has already been selected on this connection */
1523  if(imap->mailbox && imapc->mailbox &&
1524  !strcmp(imap->mailbox, imapc->mailbox) &&
1525  (!imap->uidvalidity || !imapc->mailbox_uidvalidity ||
1526  !strcmp(imap->uidvalidity, imapc->mailbox_uidvalidity)))
1527  selected = TRUE;
1528 
1529  /* Start the first command in the DO phase */
1530  if(conn->data->set.upload || data->set.mimepost.kind != MIMEKIND_NONE)
1531  /* APPEND can be executed directly */
1532  result = imap_perform_append(conn);
1533  else if(imap->custom && (selected || !imap->mailbox))
1534  /* Custom command using the same mailbox or no mailbox */
1535  result = imap_perform_list(conn);
1536  else if(!imap->custom && selected && imap->uid)
1537  /* FETCH from the same mailbox */
1538  result = imap_perform_fetch(conn);
1539  else if(!imap->custom && selected && imap->query)
1540  /* SEARCH the current mailbox */
1541  result = imap_perform_search(conn);
1542  else if(imap->mailbox && !selected &&
1543  (imap->custom || imap->uid || imap->query))
1544  /* SELECT the mailbox */
1545  result = imap_perform_select(conn);
1546  else
1547  /* LIST */
1548  result = imap_perform_list(conn);
1549 
1550  if(result)
1551  return result;
1552 
1553  /* Run the state-machine */
1554  result = imap_multi_statemach(conn, dophase_done);
1555 
1556  *connected = conn->bits.tcpconnect[FIRSTSOCKET];
1557 
1558  if(*dophase_done)
1559  DEBUGF(infof(conn->data, "DO phase is complete\n"));
1560 
1561  return result;
1562 }
1563 
1564 /***********************************************************************
1565  *
1566  * imap_do()
1567  *
1568  * This function is registered as 'curl_do' function. It decodes the path
1569  * parts etc as a wrapper to the actual DO function (imap_perform).
1570  *
1571  * The input argument is already checked for validity.
1572  */
1573 static CURLcode imap_do(struct connectdata *conn, bool *done)
1574 {
1576 
1577  *done = FALSE; /* default to false */
1578 
1579  /* Parse the URL path */
1580  result = imap_parse_url_path(conn);
1581  if(result)
1582  return result;
1583 
1584  /* Parse the custom request */
1585  result = imap_parse_custom_request(conn);
1586  if(result)
1587  return result;
1588 
1589  result = imap_regular_transfer(conn, done);
1590 
1591  return result;
1592 }
1593 
1594 /***********************************************************************
1595  *
1596  * imap_disconnect()
1597  *
1598  * Disconnect from an IMAP server. Cleanup protocol-specific per-connection
1599  * resources. BLOCKING.
1600  */
1601 static CURLcode imap_disconnect(struct connectdata *conn, bool dead_connection)
1602 {
1603  struct imap_conn *imapc = &conn->proto.imapc;
1604 
1605  /* We cannot send quit unconditionally. If this connection is stale or
1606  bad in any way, sending quit and waiting around here will make the
1607  disconnect wait in vain and cause more problems than we need to. */
1608 
1609  /* The IMAP session may or may not have been allocated/setup at this
1610  point! */
1611  if(!dead_connection && imapc->pp.conn && imapc->pp.conn->bits.protoconnstart)
1612  if(!imap_perform_logout(conn))
1613  (void)imap_block_statemach(conn); /* ignore errors on LOGOUT */
1614 
1615  /* Disconnect from the server */
1616  Curl_pp_disconnect(&imapc->pp);
1617 
1618  /* Cleanup the SASL module */
1619  Curl_sasl_cleanup(conn, imapc->sasl.authused);
1620 
1621  /* Cleanup our connection based variables */
1622  Curl_safefree(imapc->mailbox);
1624 
1625  return CURLE_OK;
1626 }
1627 
1628 /* Call this when the DO phase has completed */
1629 static CURLcode imap_dophase_done(struct connectdata *conn, bool connected)
1630 {
1631  struct IMAP *imap = conn->data->req.protop;
1632 
1633  (void)connected;
1634 
1635  if(imap->transfer != FTPTRANSFER_BODY)
1636  /* no data to transfer */
1637  Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1638 
1639  return CURLE_OK;
1640 }
1641 
1642 /* Called from multi.c while DOing */
1643 static CURLcode imap_doing(struct connectdata *conn, bool *dophase_done)
1644 {
1645  CURLcode result = imap_multi_statemach(conn, dophase_done);
1646 
1647  if(result)
1648  DEBUGF(infof(conn->data, "DO phase failed\n"));
1649  else if(*dophase_done) {
1650  result = imap_dophase_done(conn, FALSE /* not connected */);
1651 
1652  DEBUGF(infof(conn->data, "DO phase is complete\n"));
1653  }
1654 
1655  return result;
1656 }
1657 
1658 /***********************************************************************
1659  *
1660  * imap_regular_transfer()
1661  *
1662  * The input argument is already checked for validity.
1663  *
1664  * Performs all commands done before a regular transfer between a local and a
1665  * remote host.
1666  */
1668  bool *dophase_done)
1669 {
1671  bool connected = FALSE;
1672  struct Curl_easy *data = conn->data;
1673 
1674  /* Make sure size is unknown at this point */
1675  data->req.size = -1;
1676 
1677  /* Set the progress data */
1678  Curl_pgrsSetUploadCounter(data, 0);
1679  Curl_pgrsSetDownloadCounter(data, 0);
1680  Curl_pgrsSetUploadSize(data, -1);
1681  Curl_pgrsSetDownloadSize(data, -1);
1682 
1683  /* Carry out the perform */
1684  result = imap_perform(conn, &connected, dophase_done);
1685 
1686  /* Perform post DO phase operations if necessary */
1687  if(!result && *dophase_done)
1688  result = imap_dophase_done(conn, connected);
1689 
1690  return result;
1691 }
1692 
1694 {
1695  struct Curl_easy *data = conn->data;
1696 
1697  /* Initialise the IMAP layer */
1698  CURLcode result = imap_init(conn);
1699  if(result)
1700  return result;
1701 
1702  /* Clear the TLS upgraded flag */
1703  conn->tls_upgraded = FALSE;
1704  data->state.path++; /* don't include the initial slash */
1705 
1706  return CURLE_OK;
1707 }
1708 
1709 /***********************************************************************
1710  *
1711  * imap_sendf()
1712  *
1713  * Sends the formatted string as an IMAP command to the server.
1714  *
1715  * Designed to never block.
1716  */
1717 static CURLcode imap_sendf(struct connectdata *conn, const char *fmt, ...)
1718 {
1720  struct imap_conn *imapc = &conn->proto.imapc;
1721  char *taggedfmt;
1722  va_list ap;
1723 
1724  DEBUGASSERT(fmt);
1725 
1726  /* Calculate the next command ID wrapping at 3 digits */
1727  imapc->cmdid = (imapc->cmdid + 1) % 1000;
1728 
1729  /* Calculate the tag based on the connection ID and command ID */
1730  snprintf(imapc->resptag, sizeof(imapc->resptag), "%c%03d",
1731  'A' + curlx_sltosi(conn->connection_id % 26), imapc->cmdid);
1732 
1733  /* Prefix the format with the tag */
1734  taggedfmt = aprintf("%s %s", imapc->resptag, fmt);
1735  if(!taggedfmt)
1736  return CURLE_OUT_OF_MEMORY;
1737 
1738  /* Send the data with the tag */
1739  va_start(ap, fmt);
1740  result = Curl_pp_vsendf(&imapc->pp, taggedfmt, ap);
1741  va_end(ap);
1742 
1743  free(taggedfmt);
1744 
1745  return result;
1746 }
1747 
1748 /***********************************************************************
1749  *
1750  * imap_atom()
1751  *
1752  * Checks the input string for characters that need escaping and returns an
1753  * atom ready for sending to the server.
1754  *
1755  * The returned string needs to be freed.
1756  *
1757  */
1758 static char *imap_atom(const char *str, bool escape_only)
1759 {
1760  /* !checksrc! disable PARENBRACE 1 */
1761  const char atom_specials[] = "(){ %*]";
1762  const char *p1;
1763  char *p2;
1764  size_t backsp_count = 0;
1765  size_t quote_count = 0;
1766  bool others_exists = FALSE;
1767  size_t newlen = 0;
1768  char *newstr = NULL;
1769 
1770  if(!str)
1771  return NULL;
1772 
1773  /* Look for "atom-specials", counting the backslash and quote characters as
1774  these will need escapping */
1775  p1 = str;
1776  while(*p1) {
1777  if(*p1 == '\\')
1778  backsp_count++;
1779  else if(*p1 == '"')
1780  quote_count++;
1781  else if(!escape_only) {
1782  const char *p3 = atom_specials;
1783 
1784  while(*p3 && !others_exists) {
1785  if(*p1 == *p3)
1786  others_exists = TRUE;
1787 
1788  p3++;
1789  }
1790  }
1791 
1792  p1++;
1793  }
1794 
1795  /* Does the input contain any "atom-special" characters? */
1796  if(!backsp_count && !quote_count && !others_exists)
1797  return strdup(str);
1798 
1799  /* Calculate the new string length */
1800  newlen = strlen(str) + backsp_count + quote_count + (escape_only ? 0 : 2);
1801 
1802  /* Allocate the new string */
1803  newstr = (char *) malloc((newlen + 1) * sizeof(char));
1804  if(!newstr)
1805  return NULL;
1806 
1807  /* Surround the string in quotes if necessary */
1808  p2 = newstr;
1809  if(!escape_only) {
1810  newstr[0] = '"';
1811  newstr[newlen - 1] = '"';
1812  p2++;
1813  }
1814 
1815  /* Copy the string, escaping backslash and quote characters along the way */
1816  p1 = str;
1817  while(*p1) {
1818  if(*p1 == '\\' || *p1 == '"') {
1819  *p2 = '\\';
1820  p2++;
1821  }
1822 
1823  *p2 = *p1;
1824 
1825  p1++;
1826  p2++;
1827  }
1828 
1829  /* Terminate the string */
1830  newstr[newlen] = '\0';
1831 
1832  return newstr;
1833 }
1834 
1835 /***********************************************************************
1836  *
1837  * imap_is_bchar()
1838  *
1839  * Portable test of whether the specified char is a "bchar" as defined in the
1840  * grammar of RFC-5092.
1841  */
1842 static bool imap_is_bchar(char ch)
1843 {
1844  switch(ch) {
1845  /* bchar */
1846  case ':': case '@': case '/':
1847  /* bchar -> achar */
1848  case '&': case '=':
1849  /* bchar -> achar -> uchar -> unreserved */
1850  case '0': case '1': case '2': case '3': case '4': case '5': case '6':
1851  case '7': case '8': case '9':
1852  case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
1853  case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
1854  case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
1855  case 'V': case 'W': case 'X': case 'Y': case 'Z':
1856  case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
1857  case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
1858  case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
1859  case 'v': case 'w': case 'x': case 'y': case 'z':
1860  case '-': case '.': case '_': case '~':
1861  /* bchar -> achar -> uchar -> sub-delims-sh */
1862  case '!': case '$': case '\'': case '(': case ')': case '*':
1863  case '+': case ',':
1864  /* bchar -> achar -> uchar -> pct-encoded */
1865  case '%': /* HEXDIG chars are already included above */
1866  return true;
1867 
1868  default:
1869  return false;
1870  }
1871 }
1872 
1873 /***********************************************************************
1874  *
1875  * imap_parse_url_options()
1876  *
1877  * Parse the URL login options.
1878  */
1880 {
1882  struct imap_conn *imapc = &conn->proto.imapc;
1883  const char *ptr = conn->options;
1884 
1885  imapc->sasl.resetprefs = TRUE;
1886 
1887  while(!result && ptr && *ptr) {
1888  const char *key = ptr;
1889  const char *value;
1890 
1891  while(*ptr && *ptr != '=')
1892  ptr++;
1893 
1894  value = ptr + 1;
1895 
1896  while(*ptr && *ptr != ';')
1897  ptr++;
1898 
1899  if(strncasecompare(key, "AUTH=", 5))
1900  result = Curl_sasl_parse_url_auth_option(&imapc->sasl,
1901  value, ptr - value);
1902  else
1903  result = CURLE_URL_MALFORMAT;
1904 
1905  if(*ptr == ';')
1906  ptr++;
1907  }
1908 
1909  switch(imapc->sasl.prefmech) {
1910  case SASL_AUTH_NONE:
1911  imapc->preftype = IMAP_TYPE_NONE;
1912  break;
1913  case SASL_AUTH_DEFAULT:
1914  imapc->preftype = IMAP_TYPE_ANY;
1915  break;
1916  default:
1917  imapc->preftype = IMAP_TYPE_SASL;
1918  break;
1919  }
1920 
1921  return result;
1922 }
1923 
1924 /***********************************************************************
1925  *
1926  * imap_parse_url_path()
1927  *
1928  * Parse the URL path into separate path components.
1929  *
1930  */
1932 {
1933  /* The imap struct is already initialised in imap_connect() */
1935  struct Curl_easy *data = conn->data;
1936  struct IMAP *imap = data->req.protop;
1937  const char *begin = data->state.path;
1938  const char *ptr = begin;
1939 
1940  /* See how much of the URL is a valid path and decode it */
1941  while(imap_is_bchar(*ptr))
1942  ptr++;
1943 
1944  if(ptr != begin) {
1945  /* Remove the trailing slash if present */
1946  const char *end = ptr;
1947  if(end > begin && end[-1] == '/')
1948  end--;
1949 
1950  result = Curl_urldecode(data, begin, end - begin, &imap->mailbox, NULL,
1951  TRUE);
1952  if(result)
1953  return result;
1954  }
1955  else
1956  imap->mailbox = NULL;
1957 
1958  /* There can be any number of parameters in the form ";NAME=VALUE" */
1959  while(*ptr == ';') {
1960  char *name;
1961  char *value;
1962  size_t valuelen;
1963 
1964  /* Find the length of the name parameter */
1965  begin = ++ptr;
1966  while(*ptr && *ptr != '=')
1967  ptr++;
1968 
1969  if(!*ptr)
1970  return CURLE_URL_MALFORMAT;
1971 
1972  /* Decode the name parameter */
1973  result = Curl_urldecode(data, begin, ptr - begin, &name, NULL, TRUE);
1974  if(result)
1975  return result;
1976 
1977  /* Find the length of the value parameter */
1978  begin = ++ptr;
1979  while(imap_is_bchar(*ptr))
1980  ptr++;
1981 
1982  /* Decode the value parameter */
1983  result = Curl_urldecode(data, begin, ptr - begin, &value, &valuelen, TRUE);
1984  if(result) {
1985  free(name);
1986  return result;
1987  }
1988 
1989  DEBUGF(infof(conn->data, "IMAP URL parameter '%s' = '%s'\n", name, value));
1990 
1991  /* Process the known hierarchical parameters (UIDVALIDITY, UID, SECTION and
1992  PARTIAL) stripping of the trailing slash character if it is present.
1993 
1994  Note: Unknown parameters trigger a URL_MALFORMAT error. */
1995  if(strcasecompare(name, "UIDVALIDITY") && !imap->uidvalidity) {
1996  if(valuelen > 0 && value[valuelen - 1] == '/')
1997  value[valuelen - 1] = '\0';
1998 
1999  imap->uidvalidity = value;
2000  value = NULL;
2001  }
2002  else if(strcasecompare(name, "UID") && !imap->uid) {
2003  if(valuelen > 0 && value[valuelen - 1] == '/')
2004  value[valuelen - 1] = '\0';
2005 
2006  imap->uid = value;
2007  value = NULL;
2008  }
2009  else if(strcasecompare(name, "SECTION") && !imap->section) {
2010  if(valuelen > 0 && value[valuelen - 1] == '/')
2011  value[valuelen - 1] = '\0';
2012 
2013  imap->section = value;
2014  value = NULL;
2015  }
2016  else if(strcasecompare(name, "PARTIAL") && !imap->partial) {
2017  if(valuelen > 0 && value[valuelen - 1] == '/')
2018  value[valuelen - 1] = '\0';
2019 
2020  imap->partial = value;
2021  value = NULL;
2022  }
2023  else {
2024  free(name);
2025  free(value);
2026 
2027  return CURLE_URL_MALFORMAT;
2028  }
2029 
2030  free(name);
2031  free(value);
2032  }
2033 
2034  /* Does the URL contain a query parameter? Only valid when we have a mailbox
2035  and no UID as per RFC-5092 */
2036  if(imap->mailbox && !imap->uid && *ptr == '?') {
2037  /* Find the length of the query parameter */
2038  begin = ++ptr;
2039  while(imap_is_bchar(*ptr))
2040  ptr++;
2041 
2042  /* Decode the query parameter */
2043  result = Curl_urldecode(data, begin, ptr - begin, &imap->query, NULL,
2044  TRUE);
2045  if(result)
2046  return result;
2047  }
2048 
2049  /* Any extra stuff at the end of the URL is an error */
2050  if(*ptr)
2051  return CURLE_URL_MALFORMAT;
2052 
2053  return CURLE_OK;
2054 }
2055 
2056 /***********************************************************************
2057  *
2058  * imap_parse_custom_request()
2059  *
2060  * Parse the custom request.
2061  */
2063 {
2065  struct Curl_easy *data = conn->data;
2066  struct IMAP *imap = data->req.protop;
2067  const char *custom = data->set.str[STRING_CUSTOMREQUEST];
2068 
2069  if(custom) {
2070  /* URL decode the custom request */
2071  result = Curl_urldecode(data, custom, 0, &imap->custom, NULL, TRUE);
2072 
2073  /* Extract the parameters if specified */
2074  if(!result) {
2075  const char *params = imap->custom;
2076 
2077  while(*params && *params != ' ')
2078  params++;
2079 
2080  if(*params) {
2081  imap->custom_params = strdup(params);
2082  imap->custom[params - imap->custom] = '\0';
2083 
2084  if(!imap->custom_params)
2085  result = CURLE_OUT_OF_MEMORY;
2086  }
2087  }
2088  }
2089 
2090  return result;
2091 }
2092 
2093 #endif /* CURL_DISABLE_IMAP */
#define free(ptr)
Definition: curl_memory.h:130
char * query
Definition: imap.h:63
struct ssl_connect_data ssl[2]
Definition: urldata.h:887
curl_mimepart mimepost
Definition: urldata.h:1563
#define CLIENTWRITE_BODY
Definition: sendf.h:50
unsigned int authmechs
Definition: curl_sasl.h:104
static CURLcode imap_perform_append(struct connectdata *conn)
Definition: imap.c:709
struct ConnectBits bits
Definition: urldata.h:893
CURLcode Curl_urldecode(struct Curl_easy *data, const char *string, size_t length, char **ostring, size_t *olen, bool reject_ctrl)
Definition: escape.c:146
CURL_EXTERN CURLcode curl_mime_headers(curl_mimepart *part, struct curl_slist *headers, int take_ownership)
Definition: mime.c:1352
size_t sendleft
Definition: pingpong.h:59
static CURLcode imap_setup_connection(struct connectdata *conn)
Definition: imap.c:1693
bool login_disabled
Definition: imap.h:80
struct UserDefined set
Definition: urldata.h:1762
static CURLcode imap_continue_authenticate(struct connectdata *conn, const char *resp)
Definition: imap.c:545
void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size)
Definition: progress.c:304
#define connclose(x, y)
Definition: connect.h:141
curl_off_t size
Definition: urldata.h:519
#define CURLPROTO_IMAP
Definition: curl.h:856
bool opt_no_body
Definition: urldata.h:1631
int curlx_sltosi(long slnum)
Definition: warnless.c:264
long response_time
Definition: pingpong.h:63
#define IMAP_TYPE_NONE
Definition: imap.h:94
#define CURL_FORMAT_CURL_OFF_TU
Definition: system.h:374
static bool imap_matchresp(const char *line, size_t len, const char *cmd)
Definition: imap.c:205
#define FIRSTSOCKET
Definition: urldata.h:487
CURLcode Curl_pp_disconnect(struct pingpong *pp)
Definition: pingpong.c:500
char * partial
Definition: imap.h:62
void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused)
Definition: curl_sasl.c:81
bool preauth
Definition: imap.h:74
static CURLcode imap_state_auth_resp(struct connectdata *conn, int imapcode, imapstate instate)
Definition: imap.c:953
static bool imap_endofresp(struct connectdata *conn, char *line, size_t len, int *resp)
Definition: imap.c:243
#define IMAP_RESP_OK
Definition: imap.c:166
static CURLcode imap_sendf(struct connectdata *conn, const char *fmt,...)
Definition: imap.c:1717
char resptag[5]
Definition: imap.h:78
static const struct SASLproto saslimap
Definition: imap.c:171
#define failf
Definition: sendf.h:48
bool resetprefs
Definition: curl_sasl.h:107
#define strdup(ptr)
Definition: curl_memory.h:122
bool protoconnstart
Definition: urldata.h:395
int cmdid
Definition: imap.h:77
const struct Curl_handler * handler
Definition: urldata.h:904
static CURLcode imap_perform_search(struct connectdata *conn)
Definition: imap.c:780
#define DEBUGASSERT(x)
CURLcode Curl_pp_vsendf(struct pingpong *pp, const char *fmt, va_list args)
Definition: pingpong.c:161
UNITTEST_START char * ptr
Definition: unit1330.c:38
CURLcode
Definition: curl.h:454
unsigned int flags
Definition: mime.h:115
char * uidvalidity
Definition: imap.h:59
static CURLcode imap_state_starttls_resp(struct connectdata *conn, int imapcode, imapstate instate)
Definition: imap.c:929
CURLcode Curl_pp_flushsend(struct pingpong *pp)
Definition: pingpong.c:476
#define MIME_BODY_ONLY
Definition: mime.h:31
enum mimekind kind
Definition: mime.h:102
CURLcode Curl_mime_prepare_headers(curl_mimepart *part, const char *contenttype, const char *disposition, enum mimestrategy strategy)
Definition: mime.c:1577
curl_pp_transfer transfer
Definition: imap.h:57
Definition: imap.h:32
static CURLcode imap_perform_fetch(struct connectdata *conn)
Definition: imap.c:675
bool tls_upgraded
Definition: urldata.h:891
#define PORT_IMAPS
Definition: urldata.h:40
static CURLcode imap_do(struct connectdata *conn, bool *done)
Definition: imap.c:1573
#define Curl_ssl_connect_nonblocking(x, y, z)
Definition: vtls.h:267
void Curl_sasl_init(struct SASL *sasl, const struct SASLproto *params)
Definition: curl_sasl.c:178
#define PORT_IMAP
Definition: urldata.h:39
struct curl_slist * headers
Definition: urldata.h:1560
#define strcasecompare(a, b)
Definition: strcase.h:35
Definition: imap.h:56
char * uid
Definition: imap.h:60
#define malloc(size)
Definition: curl_memory.h:124
#define IMAP_TYPE_SASL
Definition: imap.h:91
bool connect_only
Definition: urldata.h:1653
#define SASL_AUTH_DEFAULT
Definition: curl_sasl.h:44
char * custom
Definition: imap.h:64
UNITTEST_START int result
Definition: unit1304.c:49
unsigned int prefmech
Definition: curl_sasl.h:105
#define IMAP_RESP_NOT_OK
Definition: imap.c:167
char buffer[]
Definition: unit1308.c:48
static CURLcode imap_state_fetch_resp(struct connectdata *conn, int imapcode, imapstate instate)
Definition: imap.c:1081
curl_usessl use_ssl
Definition: urldata.h:1643
CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, bool force_ir, saslprogress *progress)
Definition: curl_sasl.c:254
#define SASL_AUTH_NONE
Definition: curl_sasl.h:42
static CURLcode imap_statemach_act(struct connectdata *conn)
Definition: imap.c:1238
size_t len
Definition: curl_sasl.c:55
char * passwd
Definition: urldata.h:866
#define PROTOPT_SSL
Definition: urldata.h:700
static CURLcode imap_state_listsearch_resp(struct connectdata *conn, int imapcode, imapstate instate)
Definition: imap.c:1008
struct imap_conn imapc
Definition: urldata.h:1002
static CURLcode imap_state_servergreet_resp(struct connectdata *conn, int imapcode, imapstate instate)
Definition: imap.c:820
CURLcode(* statemach_act)(struct connectdata *conn)
Definition: pingpong.h:72
static CURLcode imap_disconnect(struct connectdata *conn, bool dead)
Definition: imap.c:1601
static CURLcode imap_multi_statemach(struct connectdata *conn, bool *done)
Definition: imap.c:1331
size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream)
Definition: mime.c:1428
static CURLcode imap_perform_authentication(struct connectdata *conn)
Definition: imap.c:561
#define ZERO_NULL
Definition: curlx.c:131
static CURLcode imap_perform_starttls(struct connectdata *conn)
Definition: imap.c:437
static CURLcode imap_perform_authenticate(struct connectdata *conn, const char *mech, const char *initresp)
Definition: imap.c:521
void Curl_setup_transfer(struct connectdata *conn, int sockindex, curl_off_t size, bool getheader, curl_off_t *bytecountp, int writesockindex, curl_off_t *writecountp)
Definition: transfer.c:1989
const char * str
Definition: unit1398.c:33
#define FALSE
char * buffer
Definition: urldata.h:1253
static bool imap_is_bchar(char ch)
Definition: imap.c:1842
Definition: imap.h:41
curl_easy_setopt expects a curl_off_t argument for this option curl_easy_setopt expects a curl_write_callback argument for this option curl_easy_setopt expects a curl_ioctl_callback argument for this option curl_easy_setopt expects a curl_opensocket_callback argument for this option curl_easy_setopt expects a curl_debug_callback argument for this option curl_easy_setopt expects a curl_conv_callback argument for this option curl_easy_setopt expects a private data pointer as argument for this option curl_easy_setopt expects a FILE *argument for this option curl_easy_setopt expects a struct curl_httppost *argument for this option curl_easy_setopt expects a struct curl_slist *argument for this option curl_easy_getinfo expects a pointer to char *for this info curl_easy_getinfo expects a pointer to double for this info curl_easy_getinfo expects a pointer to struct curl_tlssessioninfo *for this info curl_easy_getinfo expects a pointer to curl_socket_t for this info size_t
struct SingleRequest req
Definition: urldata.h:1761
unsigned int flags
Definition: urldata.h:696
CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt,...)
Definition: mime.c:1507
static CURLcode imap_state_login_resp(struct connectdata *conn, int imapcode, imapstate instate)
Definition: imap.c:987
bool(* endofresp)(struct connectdata *conn, char *ptr, size_t len, int *code)
Definition: pingpong.h:74
CURLcode Curl_pp_statemach(struct pingpong *pp, bool block)
Definition: pingpong.c:81
curl_off_t infilesize
Definition: urldata.h:1345
#define imap_to_imaps(x)
Definition: imap.c:192
CURLcode Curl_mime_rewind(curl_mimepart *part)
Definition: mime.c:1437
static CURLcode imap_perform_logout(struct connectdata *conn)
Definition: imap.c:806
char * mailbox_uidvalidity
Definition: imap.h:83
CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, int code, saslprogress *progress)
Definition: curl_sasl.c:408
saslprogress
Definition: curl_sasl.h:79
#define ISDIGIT(x)
bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn)
Definition: curl_sasl.c:236
unsigned int Curl_sasl_decode_mech(const char *ptr, size_t maxlen, size_t *len)
Definition: curl_sasl.c:117
CURLofft curlx_strtoofft(const char *str, char **endp, int base, curl_off_t *num)
Definition: strtoofft.c:215
bool user_passwd
Definition: urldata.h:385
#define strncasecompare(a, b, c)
Definition: strcase.h:36
static CURLcode imap_connect(struct connectdata *conn, bool *done)
Definition: imap.c:1391
#define CURLPROTO_IMAPS
Definition: curl.h:857
long connection_id
Definition: urldata.h:809
static CURLcode imap_perform_capability(struct connectdata *conn)
Definition: imap.c:413
const struct Curl_handler Curl_handler_imap
Definition: imap.c:117
struct pingpong pp
Definition: imap.h:71
void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size)
Definition: progress.c:334
bool tls_supported
Definition: imap.h:79
static void imap_get_message(char *buffer, char **outptr)
Definition: imap.c:345
void Curl_pgrsSetDownloadSize(struct Curl_easy *data, curl_off_t size)
Definition: progress.c:322
CURL_TYPEOF_CURL_OFF_T curl_off_t
Definition: system.h:420
size_t(* curl_read_callback)(char *buffer, size_t size, size_t nitems, void *instream)
Definition: curl.h:355
static CURLcode imap_init(struct connectdata *conn)
Definition: imap.c:1361
char * mailbox
Definition: imap.h:82
char * options
Definition: urldata.h:867
char * path
Definition: urldata.h:1329
static CURLcode imap_state_append_final_resp(struct connectdata *conn, int imapcode, imapstate instate)
Definition: imap.c:1221
Definition: curl.h:455
static CURLcode imap_done(struct connectdata *conn, CURLcode status, bool premature)
Definition: imap.c:1440
void * protop
Definition: urldata.h:614
static CURLcode imap_state_append_resp(struct connectdata *conn, int imapcode, imapstate instate)
Definition: imap.c:1195
CURLcode Curl_client_write(struct connectdata *conn, int type, char *ptr, size_t len)
Definition: sendf.c:624
static char * imap_atom(const char *str, bool escape_only)
Definition: imap.c:1758
char * mailbox
Definition: imap.h:58
static CURLcode imap_perform_login(struct connectdata *conn)
Definition: imap.c:483
#define Curl_safefree(ptr)
Definition: memdebug.h:170
size_t cache_size
Definition: pingpong.h:50
int Curl_pp_getsock(struct pingpong *pp, curl_socket_t *socks, int numsocks)
Definition: pingpong.c:456
bool Curl_pp_moredata(struct pingpong *pp)
Definition: pingpong.c:507
char * section
Definition: imap.h:61
struct UrlState state
Definition: urldata.h:1769
curl_off_t Curl_mime_size(curl_mimepart *part)
Definition: mime.c:1484
#define aprintf
Definition: curl_printf.h:46
static CURLcode imap_perform_upgrade_tls(struct connectdata *conn)
Definition: imap.c:456
static CURLcode imap_state_select_resp(struct connectdata *conn, int imapcode, imapstate instate)
Definition: imap.c:1034
static CURLcode imap_state_capability_resp(struct connectdata *conn, int imapcode, imapstate instate)
Definition: imap.c:842
#define RESP_TIMEOUT
Definition: urldata.h:80
static CURLcode imap_perform_list(struct connectdata *conn)
Definition: imap.c:600
char * Curl_checkheaders(const struct connectdata *conn, const char *thisheader)
Definition: transfer.c:92
Definition: imap.h:70
char * cache
Definition: pingpong.h:49
curl_socket_t sock[2]
Definition: urldata.h:876
void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size)
Definition: progress.c:286
#define connkeep(x, y)
Definition: connect.h:142
void * in
Definition: urldata.h:1356
void Curl_pp_init(struct pingpong *pp)
Definition: pingpong.c:140
static CURLcode imap_parse_url_options(struct connectdata *conn)
Definition: imap.c:1879
char * custom_params
Definition: imap.h:65
bool ssldone
Definition: imap.h:73
struct connectdata * conn
Definition: pingpong.h:66
struct SASL sasl
Definition: imap.h:75
static CURLcode imap_dophase_done(struct connectdata *conn, bool connected)
Definition: imap.c:1629
CURLcode Curl_pp_sendf(struct pingpong *pp, const char *fmt,...)
Definition: pingpong.c:248
#define infof
Definition: sendf.h:44
UNITTEST_START int * value
Definition: unit1602.c:51
static CURLcode imap_regular_transfer(struct connectdata *conn, bool *done)
Definition: imap.c:1667
curl_read_callback fread_func
Definition: urldata.h:1355
static int imap_getsock(struct connectdata *conn, curl_socket_t *socks, int numsocks)
Definition: imap.c:1375
static CURLcode imap_doing(struct connectdata *conn, bool *dophase_done)
Definition: imap.c:1643
struct curl_slist * curlheaders
Definition: mime.h:109
char * str[STRING_LAST]
Definition: urldata.h:1663
#define PROTOPT_URLOPTIONS
Definition: urldata.h:717
#define IMAP_TYPE_ANY
Definition: imap.h:95
CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl, const char *value, size_t len)
Definition: curl_sasl.c:145
imapstate
Definition: imap.h:31
static CURLcode imap_perform_select(struct connectdata *conn)
Definition: imap.c:635
static CURLcode imap_parse_custom_request(struct connectdata *conn)
Definition: imap.c:2062
union connectdata::@34 proto
CURLcode Curl_pp_readresp(curl_socket_t sockfd, struct pingpong *pp, int *code, size_t *size)
Definition: pingpong.c:267
size_t size
Definition: unit1302.c:52
static CURLcode imap_block_statemach(struct connectdata *conn)
Definition: imap.c:1348
#define snprintf
Definition: curl_printf.h:42
unsigned int preftype
Definition: imap.h:76
#define TRUE
bool ir_supported
Definition: imap.h:81
const struct Curl_handler Curl_handler_imaps
static CURLcode imap_perform(struct connectdata *conn, bool *connected, bool *dophase_done)
Definition: imap.c:1502
static CURLcode imap_state_fetch_final_resp(struct connectdata *conn, int imapcode, imapstate instate)
Definition: imap.c:1177
#define IMAP_RESP_PREAUTH
Definition: imap.c:168
#define PROTOPT_CLOSEACTION
Definition: urldata.h:702
int curl_socket_t
Definition: curl.h:130
const char * name
Definition: curl_sasl.c:54
static void state(struct connectdata *conn, imapstate newstate)
Definition: imap.c:374
bool upload
Definition: urldata.h:1632
curl_off_t bytecount
Definition: urldata.h:526
#define IMAP_TYPE_CLEARTEXT
Definition: imap.h:90
imapstate state
Definition: imap.h:72
int key
Definition: unit1602.c:56
static CURLcode imap_parse_url_path(struct connectdata *conn)
Definition: imap.c:1931
Definition: debug.c:29
bool tcpconnect[2]
Definition: urldata.h:393
char * user
Definition: urldata.h:865
#define calloc(nbelem, size)
Definition: curl_memory.h:126
curl_off_t maxdownload
Definition: urldata.h:522
#define CURL_FORMAT_CURL_OFF_T
Definition: system.h:373
#define DEBUGF(x)
struct Curl_easy * data
Definition: urldata.h:791
unsigned int authused
Definition: curl_sasl.h:106


rc_tagdetect_client
Author(s): Monika Florek-Jasinska , Raphael Schaller
autogenerated on Sat Feb 13 2021 03:42:15