1 /*
2  * libEtPan! -- a mail stuff library
3  *
4  * Copyright (C) 2001, 2005 - DINH Viet Hoa
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the libEtPan! project nor the names of its
16  *    contributors may be used to endorse or promote products derived
17  *    from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 /*
33  * $Id: mailimap.c,v 1.51 2011/07/10 23:10:12 hoa Exp $
34  */
35 
36 #ifdef HAVE_CONFIG_H
37 #	include <config.h>
38 #endif
39 
40 #include "mailimap.h"
41 #include "mailimap_parser.h"
42 #include "mailimap_sender.h"
43 #include "mailimap_extension.h"
44 #include "mail.h"
45 #include "condstore.h"
46 #include "condstore_private.h"
47 
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 
52 #ifdef USE_SASL
53 #include <sasl/sasl.h>
54 #include <sasl/saslutil.h>
55 #endif
56 
57 #include "mailsasl.h"
58 
59 #ifdef DEBUG
60 #include "mailimap_print.h"
61 #endif
62 
63 /*
64   RFC 2060 : IMAP4rev1
65   draft-crispin-imapv-15
66   RFC 2222 : Simple Authentication and Security Layer
67 
68 2061 IMAP4 Compatibility with IMAP2bis. M. Crispin. December 1996.
69      (Format: TXT=5867 bytes) (Obsoletes RFC1730) (Status: INFORMATIONAL)
70 
71 2062 Internet Message Access Protocol - Obsolete Syntax. M. Crispin.
72      December 1996. (Format: TXT=14222 bytes) (Status: INFORMATIONAL)
73 
74 2086 IMAP4 ACL extension. J. Myers. January 1997. (Format: TXT=13925
75      bytes) (Status: PROPOSED STANDARD)
76 
77 2087 IMAP4 QUOTA extension. J. Myers. January 1997. (Format: TXT=8542
78      bytes) (Status: PROPOSED STANDARD)
79 
80 2088 IMAP4 non-synchronizing literals. J. Myers. January 1997.
81      (Format: TXT=4052 bytes) (Status: PROPOSED STANDARD)
82 
83 2177 IMAP4 IDLE command. B. Leiba. June 1997. (Format: TXT=6770 bytes)
84      (Status: PROPOSED STANDARD)
85 
86 2180 IMAP4 Multi-Accessed Mailbox Practice. M. Gahrns. July 1997.
87      (Format: TXT=24750 bytes) (Status: INFORMATIONAL)
88 
89 2192 IMAP URL Scheme. C. Newman. September 1997. (Format: TXT=31426
90      bytes) (Status: PROPOSED STANDARD)
91 
92 2193 IMAP4 Mailbox Referrals. M. Gahrns. September 1997. (Format:
93      TXT=16248 bytes) (Status: PROPOSED STANDARD)
94 
95 2195 IMAP/POP AUTHorize Extension for Simple Challenge/Response. J.
96      Klensin, R. Catoe, P. Krumviede. September 1997. (Format: TXT=10468
97      bytes) (Obsoletes RFC2095) (Status: PROPOSED STANDARD)
98 
99 2221 IMAP4 Login Referrals. M. Gahrns. October 1997. (Format: TXT=9251
100      bytes) (Status: PROPOSED STANDARD)
101 
102 2342 IMAP4 Namespace. M. Gahrns, C. Newman. May 1998. (Format:
103      TXT=19489 bytes) (Status: PROPOSED STANDARD)
104 
105 2359 IMAP4 UIDPLUS extension. J. Myers. June 1998. (Format: TXT=10862
106      bytes) (Status: PROPOSED STANDARD)
107 
108 2595 Using TLS with IMAP, POP3 and ACAP. C. Newman. June 1999.
109      (Format: TXT=32440 bytes) (Status: PROPOSED STANDARD)
110 
111 2683 IMAP4 Implementation Recommendations. B. Leiba. September 1999.
112      (Format: TXT=56300 bytes) (Status: INFORMATIONAL)
113 
114 2971 IMAP4 ID extension. T. Showalter. October 2000. (Format:
115      TXT=14670 bytes) (Status: PROPOSED STANDARD)
116 
117 http://www.ietf.org/ids.by.wg/imapext.html
118 */
119 
120 static inline void imap_logger(mailstream * s, int log_type,
121     const char * str, size_t size, void * context);
122 
123 static int parse_greeting(mailimap * session,
124 			   struct mailimap_greeting ** result);
125 
126 
127 /* struct mailimap_response_info * */
128 
resp_text_store(mailimap * session,struct mailimap_resp_text * resp_text)129 static void resp_text_store(mailimap * session,
130 			    struct mailimap_resp_text *
131 			    resp_text)
132 {
133   struct mailimap_resp_text_code * resp_text_code;
134 
135   resp_text_code = resp_text->rsp_code;
136 
137   if (resp_text_code != NULL) {
138     switch (resp_text_code->rc_type) {
139     case MAILIMAP_RESP_TEXT_CODE_ALERT:
140       if (session->imap_response_info) {
141 	if (session->imap_response_info->rsp_alert != NULL)
142 	  free(session->imap_response_info->rsp_alert);
143         session->imap_response_info->rsp_alert = strdup(resp_text->rsp_text);
144       }
145       break;
146 
147     case MAILIMAP_RESP_TEXT_CODE_BADCHARSET:
148       if (session->imap_response_info) {
149 	if (session->imap_response_info->rsp_badcharset != NULL) {
150 	  clist_foreach(resp_text_code->rc_data.rc_badcharset,
151               (clist_func) mailimap_astring_free, NULL);
152 	  clist_free(resp_text_code->rc_data.rc_badcharset);
153 	}
154 	session->imap_response_info->rsp_badcharset =
155           resp_text_code->rc_data.rc_badcharset;
156 	resp_text_code->rc_data.rc_badcharset = NULL;
157       }
158       break;
159 
160     case MAILIMAP_RESP_TEXT_CODE_CAPABILITY_DATA:
161       if (session->imap_connection_info) {
162 	if (session->imap_connection_info->imap_capability != NULL)
163 	  mailimap_capability_data_free(session->imap_connection_info->imap_capability);
164 	session->imap_connection_info->imap_capability =
165           resp_text_code->rc_data.rc_cap_data;
166         /* detach before free */
167 	resp_text_code->rc_data.rc_cap_data = NULL;
168       }
169       break;
170 
171     case MAILIMAP_RESP_TEXT_CODE_PARSE:
172       if (session->imap_response_info) {
173 	if (session->imap_response_info->rsp_parse != NULL)
174 	  free(session->imap_response_info->rsp_parse);
175 	session->imap_response_info->rsp_parse = strdup(resp_text->rsp_text);
176       }
177       break;
178 
179     case MAILIMAP_RESP_TEXT_CODE_PERMANENTFLAGS:
180       if (session->imap_selection_info) {
181 	if (session->imap_selection_info->sel_perm_flags != NULL) {
182 	  clist_foreach(session->imap_selection_info->sel_perm_flags,
183               (clist_func) mailimap_flag_perm_free, NULL);
184 	  clist_free(session->imap_selection_info->sel_perm_flags);
185 	}
186 	session->imap_selection_info->sel_perm_flags =
187           resp_text_code->rc_data.rc_perm_flags;
188         /* detach before free */
189 	resp_text_code->rc_data.rc_perm_flags = NULL;
190       }
191       break;
192 
193     case MAILIMAP_RESP_TEXT_CODE_READ_ONLY:
194       if (session->imap_selection_info)
195 	session->imap_selection_info->sel_perm = MAILIMAP_MAILBOX_READONLY;
196       break;
197 
198     case MAILIMAP_RESP_TEXT_CODE_READ_WRITE:
199       if (session->imap_selection_info)
200 	session->imap_selection_info->sel_perm = MAILIMAP_MAILBOX_READWRITE;
201       break;
202 
203     case MAILIMAP_RESP_TEXT_CODE_TRY_CREATE:
204       if (session->imap_response_info)
205 	session->imap_response_info->rsp_trycreate = TRUE;
206       break;
207 
208     case MAILIMAP_RESP_TEXT_CODE_UIDNEXT:
209       if (session->imap_selection_info)
210 	session->imap_selection_info->sel_uidnext =
211           resp_text_code->rc_data.rc_uidnext;
212       break;
213 
214     case MAILIMAP_RESP_TEXT_CODE_UIDVALIDITY:
215       if (session->imap_selection_info)
216 	session->imap_selection_info->sel_uidvalidity =
217           resp_text_code->rc_data.rc_uidvalidity;
218       break;
219 
220     case MAILIMAP_RESP_TEXT_CODE_UNSEEN:
221       if (session->imap_selection_info)
222 	session->imap_selection_info->sel_first_unseen =
223           resp_text_code->rc_data.rc_first_unseen;
224       break;
225 
226     case MAILIMAP_RESP_TEXT_CODE_OTHER:
227       if (session->imap_response_info) {
228         if (session->imap_response_info->rsp_atom != NULL)
229           free(session->imap_response_info->rsp_atom);
230         if (session->imap_response_info->rsp_value != NULL)
231           free(session->imap_response_info->rsp_value);
232 	session->imap_response_info->rsp_atom =
233           resp_text_code->rc_data.rc_atom.atom_name;
234         resp_text_code->rc_data.rc_atom.atom_name = NULL;
235 	session->imap_response_info->rsp_value =
236           resp_text_code->rc_data.rc_atom.atom_value;
237         resp_text_code->rc_data.rc_atom.atom_value = NULL;
238       }
239       break;
240     case MAILIMAP_RESP_TEXT_CODE_EXTENSION:
241       mailimap_extension_data_store(session, &(resp_text_code->rc_data.rc_ext_data));
242       break;
243     }
244   }
245 }
246 
resp_cond_state_store(mailimap * session,struct mailimap_resp_cond_state * resp_cond_state)247 static void resp_cond_state_store(mailimap * session,
248     struct mailimap_resp_cond_state * resp_cond_state)
249 {
250   resp_text_store(session, resp_cond_state->rsp_text);
251 }
252 
mailbox_data_store(mailimap * session,struct mailimap_mailbox_data * mb_data)253 static void mailbox_data_store(mailimap * session,
254     struct mailimap_mailbox_data * mb_data)
255 {
256   int r;
257 
258   switch (mb_data->mbd_type) {
259   case MAILIMAP_MAILBOX_DATA_FLAGS:
260     if (session->imap_selection_info) {
261       if (session->imap_selection_info->sel_flags != NULL)
262 	mailimap_flag_list_free(session->imap_selection_info->sel_flags);
263       session->imap_selection_info->sel_flags = mb_data->mbd_data.mbd_flags;
264       mb_data->mbd_data.mbd_flags = NULL;
265     }
266     break;
267 
268   case MAILIMAP_MAILBOX_DATA_LIST:
269     if (session->imap_response_info) {
270       r = clist_append(session->imap_response_info->rsp_mailbox_list,
271           mb_data->mbd_data.mbd_list);
272       if (r == 0)
273 	mb_data->mbd_data.mbd_list = NULL;
274       else {
275 	/* TODO must handle error case */
276       }
277     }
278     break;
279 
280   case MAILIMAP_MAILBOX_DATA_LSUB:
281     if (session->imap_response_info) {
282       r =  clist_append(session->imap_response_info->rsp_mailbox_lsub,
283           mb_data->mbd_data.mbd_lsub);
284       if (r == 0)
285 	mb_data->mbd_data.mbd_lsub = NULL;
286       else {
287 	/* TODO must handle error case */
288       }
289     }
290     break;
291 
292   case MAILIMAP_MAILBOX_DATA_SEARCH:
293     if (session->imap_response_info) {
294       if (session->imap_response_info->rsp_search_result != NULL) {
295         if (mb_data->mbd_data.mbd_search != NULL) {
296           clist_concat(session->imap_response_info->rsp_search_result,
297               mb_data->mbd_data.mbd_search);
298           clist_free(mb_data->mbd_data.mbd_search);
299           mb_data->mbd_data.mbd_search = NULL;
300         }
301       }
302       else {
303         if (mb_data->mbd_data.mbd_search != NULL) {
304           session->imap_response_info->rsp_search_result =
305             mb_data->mbd_data.mbd_search;
306           mb_data->mbd_data.mbd_search = NULL;
307         }
308       }
309     }
310     break;
311 
312   case MAILIMAP_MAILBOX_DATA_STATUS:
313     if (session->imap_response_info) {
314       if (session->imap_response_info->rsp_status != NULL)
315         mailimap_mailbox_data_status_free(session->imap_response_info->rsp_status);
316       session->imap_response_info->rsp_status = mb_data->mbd_data.mbd_status;
317 #if 0
318       if (session->imap_selection_info != NULL) {
319         clistiter * cur;
320 
321         for(cur = clist_begin(mb_data->status->status_info_list)
322             ; cur != NULL ; cur = clist_next(cur)) {
323           struct mailimap_status_info * info;
324 
325           info = clist_content(cur);
326           switch (info->att) {
327             case MAILIMAP_STATUS_ATT_MESSAGES:
328               session->imap_selection_info->exists = info->value;
329               break;
330             case MAILIMAP_STATUS_ATT_RECENT:
331               session->imap_selection_info->recent = info->value;
332               break;
333             case MAILIMAP_STATUS_ATT_UIDNEXT:
334               session->imap_selection_info->uidnext = info->value;
335               break;
336             case MAILIMAP_STATUS_ATT_UIDVALIDITY:
337               session->imap_selection_info->uidvalidity = info->value;
338               break;
339             case MAILIMAP_STATUS_ATT_UNSEEN:
340               session->imap_selection_info->unseen = info->value;
341               break;
342           }
343         }
344       }
345 #endif
346 #if 0
347       mailimap_mailbox_data_status_free(mb_data->status);
348 #endif
349       mb_data->mbd_data.mbd_status = NULL;
350     }
351     break;
352 
353   case MAILIMAP_MAILBOX_DATA_EXISTS:
354     if (session->imap_selection_info) {
355       session->imap_selection_info->sel_exists = mb_data->mbd_data.mbd_exists;
356       session->imap_selection_info->sel_has_exists = 1;
357     }
358     break;
359 
360   case MAILIMAP_MAILBOX_DATA_RECENT:
361     if (session->imap_selection_info) {
362       session->imap_selection_info->sel_recent = mb_data->mbd_data.mbd_recent;
363       session->imap_selection_info->sel_has_recent = 1;
364     }
365     break;
366   case MAILIMAP_MAILBOX_DATA_EXTENSION_DATA:
367     mailimap_extension_data_store(session, &mb_data->mbd_data.mbd_extension);
368     break;
369   }
370 }
371 
372 static void
message_data_store(mailimap * session,struct mailimap_message_data * msg_data)373 message_data_store(mailimap * session,
374     struct mailimap_message_data * msg_data)
375 {
376   uint32_t * expunged;
377   int r;
378 
379   switch (msg_data->mdt_type) {
380   case MAILIMAP_MESSAGE_DATA_EXPUNGE:
381     if (session->imap_response_info) {
382       expunged = mailimap_number_alloc_new(msg_data->mdt_number);
383       if (expunged != NULL) {
384 	r = clist_append(session->imap_response_info->rsp_expunged, expunged);
385 	if (r == 0) {
386 	  /* do nothing */
387 	}
388 	else {
389 	  /* TODO : must handle error case */
390 	  mailimap_number_alloc_free(expunged);
391 	}
392         if (session->imap_selection_info != NULL)
393           session->imap_selection_info->sel_exists --;
394       }
395     }
396     break;
397 
398   case MAILIMAP_MESSAGE_DATA_FETCH:
399     r = clist_append(session->imap_response_info->rsp_fetch_list,
400         msg_data->mdt_msg_att);
401     if (r == 0) {
402       msg_data->mdt_msg_att->att_number = msg_data->mdt_number;
403       msg_data->mdt_msg_att = NULL;
404     }
405     else {
406       /* TODO : must handle error case */
407     }
408     break;
409   }
410 }
411 
412 static void
cont_req_or_resp_data_store(mailimap * session,struct mailimap_cont_req_or_resp_data * cont_req_or_resp_data)413 cont_req_or_resp_data_store(mailimap * session,
414     struct mailimap_cont_req_or_resp_data * cont_req_or_resp_data)
415 {
416   if (cont_req_or_resp_data->rsp_type == MAILIMAP_RESP_RESP_DATA) {
417     struct mailimap_response_data * resp_data;
418 
419     resp_data = cont_req_or_resp_data->rsp_data.rsp_resp_data;
420 
421     switch (resp_data->rsp_type) {
422     case MAILIMAP_RESP_DATA_TYPE_COND_STATE:
423       resp_cond_state_store(session, resp_data->rsp_data.rsp_cond_state);
424       break;
425     case MAILIMAP_RESP_DATA_TYPE_MAILBOX_DATA:
426       mailbox_data_store(session, resp_data->rsp_data.rsp_mailbox_data);
427       break;
428     case MAILIMAP_RESP_DATA_TYPE_MESSAGE_DATA:
429       message_data_store(session, resp_data->rsp_data.rsp_message_data);
430       break;
431     case MAILIMAP_RESP_DATA_TYPE_CAPABILITY_DATA:
432       if (session->imap_connection_info) {
433 	if (session->imap_connection_info->imap_capability != NULL)
434 	  mailimap_capability_data_free(session->imap_connection_info->imap_capability);
435 	session->imap_connection_info->imap_capability = resp_data->rsp_data.rsp_capability_data;
436 	resp_data->rsp_data.rsp_capability_data = NULL;
437       }
438       break;
439     case MAILIMAP_RESP_DATA_TYPE_EXTENSION_DATA:
440       mailimap_extension_data_store(session, &(resp_data->rsp_data.rsp_extension_data));
441       break;
442     }
443   }
444 }
445 
response_tagged_store(mailimap * session,struct mailimap_response_tagged * tagged)446 static void response_tagged_store(mailimap * session,
447     struct mailimap_response_tagged * tagged)
448 {
449   resp_cond_state_store(session, tagged->rsp_cond_state);
450 }
451 
resp_cond_bye_store(mailimap * session,struct mailimap_resp_cond_bye * resp_cond_bye)452 static void resp_cond_bye_store(mailimap * session,
453     struct mailimap_resp_cond_bye * resp_cond_bye)
454 {
455   resp_text_store(session, resp_cond_bye->rsp_text);
456 }
457 
response_fatal_store(mailimap * session,struct mailimap_response_fatal * fatal)458 static void response_fatal_store(mailimap * session,
459     struct mailimap_response_fatal * fatal)
460 {
461   resp_cond_bye_store(session, fatal->rsp_bye);
462 }
463 
response_done_store(mailimap * session,struct mailimap_response_done * resp_done)464 static void response_done_store(mailimap * session,
465     struct mailimap_response_done * resp_done)
466 {
467   switch(resp_done->rsp_type) {
468   case MAILIMAP_RESP_DONE_TYPE_TAGGED:
469     response_tagged_store(session, resp_done->rsp_data.rsp_tagged);
470     break;
471   case MAILIMAP_RESP_DONE_TYPE_FATAL:
472     response_fatal_store(session, resp_done->rsp_data.rsp_fatal);
473     break;
474   }
475 }
476 
477 static void
response_store(mailimap * session,struct mailimap_response * response)478 response_store(mailimap * session,
479     struct mailimap_response * response)
480 {
481   clistiter * cur;
482 
483   if (session->imap_response_info) {
484     mailimap_response_info_free(session->imap_response_info);
485     session->imap_response_info = NULL;
486   }
487 
488   session->imap_response_info = mailimap_response_info_new();
489   if (session->imap_response_info == NULL) {
490     /* ignored error */
491     return;
492   }
493 
494   if (response->rsp_cont_req_or_resp_data_list != NULL) {
495     for(cur = clist_begin(response->rsp_cont_req_or_resp_data_list) ;
496 	cur != NULL ; cur = clist_next(cur)) {
497       struct mailimap_cont_req_or_resp_data * cont_req_or_resp_data;
498 
499       cont_req_or_resp_data = clist_content(cur);
500 
501       cont_req_or_resp_data_store(session, cont_req_or_resp_data);
502     }
503   }
504 
505   response_done_store(session, response->rsp_resp_done);
506 }
507 
resp_cond_auth_store(mailimap * session,struct mailimap_resp_cond_auth * cond_auth)508 static void resp_cond_auth_store(mailimap * session,
509     struct mailimap_resp_cond_auth * cond_auth)
510 {
511   resp_text_store(session, cond_auth->rsp_text);
512 }
513 
greeting_store(mailimap * session,struct mailimap_greeting * greeting)514 static void greeting_store(mailimap * session,
515     struct mailimap_greeting * greeting)
516 {
517   switch (greeting->gr_type) {
518   case MAILIMAP_GREETING_RESP_COND_AUTH:
519     resp_cond_auth_store(session, greeting->gr_data.gr_auth);
520     break;
521 
522   case MAILIMAP_GREETING_RESP_COND_BYE:
523     resp_cond_bye_store(session, greeting->gr_data.gr_bye);
524     break;
525   }
526 }
527 
528 LIBETPAN_EXPORT
mailimap_connect(mailimap * session,mailstream * s)529 int mailimap_connect(mailimap * session, mailstream * s)
530 {
531   struct mailimap_greeting * greeting;
532   int r;
533   int auth_type;
534   struct mailimap_connection_info * connection_info;
535 
536   if (session->imap_state != MAILIMAP_STATE_DISCONNECTED)
537     return MAILIMAP_ERROR_BAD_STATE;
538 
539   session->imap_stream = s;
540   mailstream_set_logger(s, imap_logger, session);
541 
542   if (session->imap_connection_info)
543     mailimap_connection_info_free(session->imap_connection_info);
544   connection_info = mailimap_connection_info_new();
545   if (connection_info != NULL)
546     session->imap_connection_info = connection_info;
547 
548   if (mailimap_read_line(session) == NULL) {
549     return MAILIMAP_ERROR_STREAM;
550   }
551 
552   r = parse_greeting(session, &greeting);
553   if (r != MAILIMAP_NO_ERROR) {
554     return r;
555   }
556 
557   auth_type = greeting->gr_data.gr_auth->rsp_type;
558 
559   mailimap_greeting_free(greeting);
560 
561   switch (auth_type) {
562   case MAILIMAP_RESP_COND_AUTH_PREAUTH:
563     session->imap_state = MAILIMAP_STATE_AUTHENTICATED;
564     return MAILIMAP_NO_ERROR_AUTHENTICATED;
565   default:
566     session->imap_state = MAILIMAP_STATE_NON_AUTHENTICATED;
567     return MAILIMAP_NO_ERROR_NON_AUTHENTICATED;
568   }
569 }
570 
571 
572 
573 
574 
575 
576 
577 
578 /* ********************************************************************** */
579 
580 
581 
582 LIBETPAN_EXPORT
mailimap_append(mailimap * session,const char * mailbox,struct mailimap_flag_list * flag_list,struct mailimap_date_time * date_time,const char * literal,size_t literal_size)583 int mailimap_append(mailimap * session, const char * mailbox,
584     struct mailimap_flag_list * flag_list,
585     struct mailimap_date_time * date_time,
586     const char * literal, size_t literal_size)
587 {
588   struct mailimap_response * response;
589   int r;
590   int error_code;
591   struct mailimap_continue_req * cont_req;
592   size_t indx;
593   size_t fixed_literal_size;
594 
595   if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) &&
596       (session->imap_state != MAILIMAP_STATE_SELECTED))
597     return MAILIMAP_ERROR_BAD_STATE;
598 
599   r = mailimap_send_current_tag(session);
600   if (r != MAILIMAP_NO_ERROR)
601 	return r;
602 
603   fixed_literal_size = mailstream_get_data_crlf_size(literal, literal_size);
604 
605   r = mailimap_append_send(session->imap_stream, mailbox, flag_list, date_time,
606       fixed_literal_size);
607   if (r != MAILIMAP_NO_ERROR)
608 	return r;
609 
610   if (mailstream_flush(session->imap_stream) == -1)
611     return MAILIMAP_ERROR_STREAM;
612 
613   if (mailimap_read_line(session) == NULL)
614     return MAILIMAP_ERROR_STREAM;
615 
616   indx = 0;
617 
618   r = mailimap_continue_req_parse(session->imap_stream,
619       session->imap_stream_buffer, NULL,
620       &indx, &cont_req,
621       session->imap_progr_rate, session->imap_progr_fun);
622   if (r == MAILIMAP_NO_ERROR)
623     mailimap_continue_req_free(cont_req);
624 
625   if (r == MAILIMAP_ERROR_PARSE) {
626     r = mailimap_parse_response(session, &response);
627     if (r != MAILIMAP_NO_ERROR)
628       return r;
629     mailimap_response_free(response);
630 
631     return MAILIMAP_ERROR_APPEND;
632   }
633 
634   if (session->imap_body_progress_fun != NULL) {
635     r = mailimap_literal_data_send_with_context(session->imap_stream, literal, literal_size,
636                                                 session->imap_body_progress_fun,
637                                                 session->imap_progress_context);
638   }
639   else {
640     r = mailimap_literal_data_send(session->imap_stream, literal, literal_size,
641                                    session->imap_progr_rate, session->imap_progr_fun);
642   }
643   if (r != MAILIMAP_NO_ERROR)
644 	return r;
645 
646   r = mailimap_crlf_send(session->imap_stream);
647   if (r != MAILIMAP_NO_ERROR)
648 	return r;
649 
650   if (mailstream_flush(session->imap_stream) == -1)
651 	return MAILIMAP_ERROR_STREAM;
652 
653   if (mailimap_read_line(session) == NULL)
654     return MAILIMAP_ERROR_STREAM;
655 
656   r = mailimap_parse_response(session, &response);
657   if (r != MAILIMAP_NO_ERROR)
658     return r;
659 
660   error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
661 
662   mailimap_response_free(response);
663 
664   switch (error_code) {
665   case MAILIMAP_RESP_COND_STATE_OK:
666     return MAILIMAP_NO_ERROR;
667 
668   default:
669     return MAILIMAP_ERROR_APPEND;
670   }
671 }
672 
673 LIBETPAN_EXPORT
mailimap_noop(mailimap * session)674 int mailimap_noop(mailimap * session)
675 {
676   struct mailimap_response * response;
677   int r;
678   int error_code;
679 
680   r = mailimap_send_current_tag(session);
681   if (r != MAILIMAP_NO_ERROR)
682 	return r;
683 
684   r = mailimap_noop_send(session->imap_stream);
685   if (r != MAILIMAP_NO_ERROR)
686 	return r;
687 
688   r = mailimap_crlf_send(session->imap_stream);
689   if (r != MAILIMAP_NO_ERROR)
690 	return r;
691 
692   if (mailstream_flush(session->imap_stream) == -1)
693     return MAILIMAP_ERROR_STREAM;
694 
695   if (mailimap_read_line(session) == NULL)
696     return MAILIMAP_ERROR_STREAM;
697 
698   r = mailimap_parse_response(session, &response);
699   if (r != MAILIMAP_NO_ERROR)
700     return r;
701 
702   error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
703 
704   mailimap_response_free(response);
705 
706   switch (error_code) {
707   case MAILIMAP_RESP_COND_STATE_OK:
708     return MAILIMAP_NO_ERROR;
709 
710   default:
711     return MAILIMAP_ERROR_NOOP;
712   }
713 }
714 
715 LIBETPAN_EXPORT
mailimap_logout(mailimap * session)716 int mailimap_logout(mailimap * session)
717 {
718   struct mailimap_response * response;
719   int r;
720   int error_code;
721   int res;
722 
723   r = mailimap_send_current_tag(session);
724   if (r != MAILIMAP_NO_ERROR) {
725     res = r;
726     goto close;
727   }
728 
729   r = mailimap_logout_send(session->imap_stream);
730   if (r != MAILIMAP_NO_ERROR) {
731     res = r;
732     goto close;
733   }
734 
735   r = mailimap_crlf_send(session->imap_stream);
736   if (r != MAILIMAP_NO_ERROR) {
737     res = r;
738     goto close;
739   }
740 
741   if (mailstream_flush(session->imap_stream) == -1) {
742     res = MAILIMAP_ERROR_STREAM;
743     goto close;
744   }
745 
746   if (mailimap_read_line(session) == NULL) {
747     res = MAILIMAP_ERROR_STREAM;
748     goto close;
749   }
750 
751   r = mailimap_parse_response(session, &response);
752   if (r == MAILIMAP_ERROR_STREAM) {
753     // the response is expected to be MAILIMAP_ERROR_STREAM
754     // because the server responds with BYE so the stream
755     // is immediately closed
756     res = MAILIMAP_NO_ERROR;
757     goto close;
758   } else if (r != MAILIMAP_NO_ERROR) {
759     res = r;
760     goto close;
761   }
762 
763   error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
764 
765   mailimap_response_free(response);
766 
767   switch (error_code) {
768   case MAILIMAP_RESP_COND_STATE_OK:
769     if (session->imap_connection_info) {
770       mailimap_connection_info_free(session->imap_connection_info);
771       session->imap_connection_info = NULL;
772     }
773     res = MAILIMAP_NO_ERROR;
774     goto close;
775 
776   default:
777     res = MAILIMAP_ERROR_LOGOUT;
778     goto close;
779   }
780 
781  close:
782   mailstream_close(session->imap_stream);
783   session->imap_stream = NULL;
784   session->imap_state = MAILIMAP_STATE_DISCONNECTED;
785   return res;
786 }
787 
788 /* send the results back to the caller */
789 /* duplicate the result */
790 
791 static struct mailimap_capability *
mailimap_capability_dup(struct mailimap_capability * orig_cap)792 mailimap_capability_dup(struct mailimap_capability * orig_cap)
793 {
794   struct mailimap_capability * cap;
795   char * auth_type;
796   char * name;
797 
798   name = NULL;
799   auth_type = NULL;
800   switch (orig_cap->cap_type) {
801   case MAILIMAP_CAPABILITY_NAME:
802     name = strdup(orig_cap->cap_data.cap_name);
803     if (name == NULL)
804       goto err;
805     break;
806   case MAILIMAP_CAPABILITY_AUTH_TYPE:
807     auth_type = strdup(orig_cap->cap_data.cap_auth_type);
808     if (auth_type == NULL)
809       goto err;
810     break;
811   }
812 
813   cap = mailimap_capability_new(orig_cap->cap_type, auth_type, name);
814   if (cap == NULL)
815     goto free;
816 
817   return cap;
818 
819  free:
820   if (name != NULL)
821     free(name);
822   if (auth_type != NULL)
823     free(auth_type);
824  err:
825   return NULL;
826 }
827 
828 static struct mailimap_capability_data *
mailimap_capability_data_dup(struct mailimap_capability_data * orig_cap_data)829 mailimap_capability_data_dup(struct mailimap_capability_data * orig_cap_data)
830 {
831   struct mailimap_capability_data * cap_data;
832   struct mailimap_capability * cap_dup;
833   clist * list;
834   clistiter * cur;
835   int r;
836 
837   list = clist_new();
838   if (list == NULL)
839 	goto err;
840 
841   for(cur = clist_begin(orig_cap_data->cap_list) ;
842       cur != NULL ; cur = clist_next(cur)) {
843     struct mailimap_capability * cap;
844 
845     cap = clist_content(cur);
846 
847     cap_dup = mailimap_capability_dup(cap);
848     if (cap_dup == NULL)
849       goto list;
850 
851     r = clist_append(list, cap_dup);
852     if (r < 0) {
853       mailimap_capability_free(cap_dup);
854       goto list;
855     }
856   }
857 
858   cap_data = mailimap_capability_data_new(list);
859   if (cap_data == NULL)
860     goto list;
861 
862   return cap_data;
863 
864 list:
865   clist_foreach(list, (clist_func) mailimap_capability_free, NULL);
866   clist_free(list);
867 err:
868   return NULL;
869 }
870 
871 LIBETPAN_EXPORT
mailimap_capability(mailimap * session,struct mailimap_capability_data ** result)872 int mailimap_capability(mailimap * session,
873 				struct mailimap_capability_data ** result)
874 {
875   struct mailimap_response * response;
876   int r;
877   int error_code;
878   struct mailimap_capability_data * cap_data;
879 
880   r = mailimap_send_current_tag(session);
881   if (r != MAILIMAP_NO_ERROR)
882 	return r;
883 
884   r = mailimap_capability_send(session->imap_stream);
885   if (r != MAILIMAP_NO_ERROR)
886 	return r;
887 
888   r = mailimap_crlf_send(session->imap_stream);
889   if (r != MAILIMAP_NO_ERROR)
890 	return r;
891 
892   if (mailstream_flush(session->imap_stream) == -1)
893     return MAILIMAP_ERROR_STREAM;
894 
895   if (mailimap_read_line(session) == NULL)
896     return MAILIMAP_ERROR_STREAM;
897 
898   r = mailimap_parse_response(session, &response);
899   if (r != MAILIMAP_NO_ERROR)
900     return r;
901 
902   error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
903 
904   mailimap_response_free(response);
905 
906   switch (error_code) {
907   case MAILIMAP_RESP_COND_STATE_OK:
908     cap_data =
909       mailimap_capability_data_dup(session->imap_connection_info->imap_capability);
910     if (cap_data == NULL)
911 	  return MAILIMAP_ERROR_MEMORY;
912 
913 	* result = cap_data;
914 
915 	return MAILIMAP_NO_ERROR;
916 
917   default:
918     return MAILIMAP_ERROR_CAPABILITY;
919   }
920 }
921 
922 LIBETPAN_EXPORT
mailimap_check(mailimap * session)923 int mailimap_check(mailimap * session)
924 {
925   struct mailimap_response * response;
926   int r;
927   int error_code;
928 
929   if (session->imap_state != MAILIMAP_STATE_SELECTED)
930     return MAILIMAP_ERROR_BAD_STATE;
931 
932   r = mailimap_send_current_tag(session);
933   if (r != MAILIMAP_NO_ERROR)
934 	return r;
935 
936   r = mailimap_check_send(session->imap_stream);
937   if (r != MAILIMAP_NO_ERROR)
938 	return r;
939 
940   r = mailimap_crlf_send(session->imap_stream);
941   if (r != MAILIMAP_NO_ERROR)
942 	return r;
943 
944   if (mailstream_flush(session->imap_stream) == -1)
945     return MAILIMAP_ERROR_STREAM;
946 
947   if (mailimap_read_line(session) == NULL)
948     return MAILIMAP_ERROR_STREAM;
949 
950   r = mailimap_parse_response(session, &response);
951   if (r != MAILIMAP_NO_ERROR)
952     return r;
953 
954   error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
955 
956   mailimap_response_free(response);
957 
958   switch (error_code) {
959   case MAILIMAP_RESP_COND_STATE_OK:
960     return MAILIMAP_NO_ERROR;
961 
962   default:
963     return MAILIMAP_ERROR_CHECK;
964   }
965 }
966 
967 LIBETPAN_EXPORT
mailimap_close(mailimap * session)968 int mailimap_close(mailimap * session)
969 {
970   struct mailimap_response * response;
971   int r;
972   int error_code;
973 
974   if (session->imap_state != MAILIMAP_STATE_SELECTED)
975     return MAILIMAP_ERROR_BAD_STATE;
976 
977   r = mailimap_send_current_tag(session);
978   if (r != MAILIMAP_NO_ERROR)
979 	return r;
980 
981   r = mailimap_close_send(session->imap_stream);
982   if (r != MAILIMAP_NO_ERROR)
983 	return r;
984 
985   r = mailimap_crlf_send(session->imap_stream);
986   if (r != MAILIMAP_NO_ERROR)
987 	return r;
988 
989   if (mailstream_flush(session->imap_stream) == -1)
990     return MAILIMAP_ERROR_STREAM;
991 
992   if (mailimap_read_line(session) == NULL)
993     return MAILIMAP_ERROR_STREAM;
994 
995   r = mailimap_parse_response(session, &response);
996   if (r != MAILIMAP_NO_ERROR)
997     return r;
998 
999   error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
1000 
1001   mailimap_response_free(response);
1002 
1003   switch (error_code) {
1004   case MAILIMAP_RESP_COND_STATE_OK:
1005     /* leave selected state */
1006     mailimap_selection_info_free(session->imap_selection_info);
1007     session->imap_selection_info = NULL;
1008 
1009     session->imap_state = MAILIMAP_STATE_AUTHENTICATED;
1010     return MAILIMAP_NO_ERROR;
1011 
1012   default:
1013     return MAILIMAP_ERROR_CLOSE;
1014   }
1015 }
1016 
1017 LIBETPAN_EXPORT
mailimap_expunge(mailimap * session)1018 int mailimap_expunge(mailimap * session)
1019 {
1020   struct mailimap_response * response;
1021   int r;
1022   int error_code;
1023 
1024   if (session->imap_state != MAILIMAP_STATE_SELECTED)
1025     return MAILIMAP_ERROR_BAD_STATE;
1026 
1027   r = mailimap_send_current_tag(session);
1028   if (r != MAILIMAP_NO_ERROR)
1029 	return r;
1030 
1031   r = mailimap_expunge_send(session->imap_stream);
1032   if (r != MAILIMAP_NO_ERROR)
1033 	return r;
1034 
1035   r = mailimap_crlf_send(session->imap_stream);
1036   if (r != MAILIMAP_NO_ERROR)
1037 	return r;
1038 
1039   if (mailstream_flush(session->imap_stream) == -1)
1040     return MAILIMAP_ERROR_STREAM;
1041 
1042   if (mailimap_read_line(session) == NULL)
1043     return MAILIMAP_ERROR_STREAM;
1044 
1045   r = mailimap_parse_response(session, &response);
1046   if (r != MAILIMAP_NO_ERROR)
1047     return r;
1048 
1049   error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
1050 
1051   mailimap_response_free(response);
1052 
1053   switch (error_code) {
1054   case MAILIMAP_RESP_COND_STATE_OK:
1055     return MAILIMAP_NO_ERROR;
1056 
1057   default:
1058     return MAILIMAP_ERROR_EXPUNGE;
1059   }
1060 }
1061 
1062 LIBETPAN_EXPORT
mailimap_copy(mailimap * session,struct mailimap_set * set,const char * mb)1063 int mailimap_copy(mailimap * session, struct mailimap_set * set,
1064     const char * mb)
1065 {
1066   struct mailimap_response * response;
1067   int r;
1068   int error_code;
1069 
1070   if (session->imap_state != MAILIMAP_STATE_SELECTED)
1071     return MAILIMAP_ERROR_BAD_STATE;
1072 
1073   r = mailimap_send_current_tag(session);
1074   if (r != MAILIMAP_NO_ERROR)
1075     return r;
1076 
1077   r = mailimap_copy_send(session->imap_stream, set, mb);
1078   if (r != MAILIMAP_NO_ERROR)
1079     return r;
1080 
1081   r = mailimap_crlf_send(session->imap_stream);
1082   if (r != MAILIMAP_NO_ERROR)
1083     return r;
1084 
1085   if (mailstream_flush(session->imap_stream) == -1)
1086     return MAILIMAP_ERROR_STREAM;
1087 
1088   if (mailimap_read_line(session) == NULL)
1089     return MAILIMAP_ERROR_STREAM;
1090 
1091   r = mailimap_parse_response(session, &response);
1092   if (r != MAILIMAP_NO_ERROR)
1093     return r;
1094 
1095   error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
1096 
1097   mailimap_response_free(response);
1098 
1099   switch (error_code) {
1100   case MAILIMAP_RESP_COND_STATE_OK:
1101     return MAILIMAP_NO_ERROR;
1102 
1103   default:
1104     return MAILIMAP_ERROR_COPY;
1105   }
1106 }
1107 
1108 LIBETPAN_EXPORT
mailimap_uid_copy(mailimap * session,struct mailimap_set * set,const char * mb)1109 int mailimap_uid_copy(mailimap * session, struct mailimap_set * set,
1110     const char * mb)
1111 {
1112   struct mailimap_response * response;
1113   int r;
1114   int error_code;
1115 
1116   if (session->imap_state != MAILIMAP_STATE_SELECTED)
1117     return MAILIMAP_ERROR_BAD_STATE;
1118 
1119   r = mailimap_send_current_tag(session);
1120   if (r != MAILIMAP_NO_ERROR)
1121     return r;
1122 
1123   r = mailimap_uid_copy_send(session->imap_stream, set, mb);
1124   if (r != MAILIMAP_NO_ERROR)
1125     return r;
1126 
1127   r = mailimap_crlf_send(session->imap_stream);
1128   if (r != MAILIMAP_NO_ERROR)
1129     return r;
1130 
1131   if (mailstream_flush(session->imap_stream) == -1)
1132     return MAILIMAP_ERROR_STREAM;
1133 
1134   if (mailimap_read_line(session) == NULL)
1135     return MAILIMAP_ERROR_STREAM;
1136 
1137   r = mailimap_parse_response(session, &response);
1138   if (r != MAILIMAP_NO_ERROR)
1139     return r;
1140 
1141   error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
1142 
1143   mailimap_response_free(response);
1144 
1145   switch (error_code) {
1146   case MAILIMAP_RESP_COND_STATE_OK:
1147     return MAILIMAP_NO_ERROR;
1148 
1149   default:
1150     return MAILIMAP_ERROR_UID_COPY;
1151   }
1152 }
1153 
1154 LIBETPAN_EXPORT
mailimap_move(mailimap * session,struct mailimap_set * set,const char * mb)1155 int mailimap_move(mailimap * session, struct mailimap_set * set,
1156                   const char * mb)
1157 {
1158   struct mailimap_response * response;
1159   int r;
1160   int error_code;
1161 
1162   if (session->imap_state != MAILIMAP_STATE_SELECTED)
1163     return MAILIMAP_ERROR_BAD_STATE;
1164 
1165   r = mailimap_send_current_tag(session);
1166   if (r != MAILIMAP_NO_ERROR)
1167     return r;
1168 
1169   r = mailimap_move_send(session->imap_stream, set, mb);
1170   if (r != MAILIMAP_NO_ERROR)
1171     return r;
1172 
1173   r = mailimap_crlf_send(session->imap_stream);
1174   if (r != MAILIMAP_NO_ERROR)
1175     return r;
1176 
1177   if (mailstream_flush(session->imap_stream) == -1)
1178     return MAILIMAP_ERROR_STREAM;
1179 
1180   if (mailimap_read_line(session) == NULL)
1181     return MAILIMAP_ERROR_STREAM;
1182 
1183   r = mailimap_parse_response(session, &response);
1184   if (r != MAILIMAP_NO_ERROR)
1185     return r;
1186 
1187   error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
1188 
1189   mailimap_response_free(response);
1190 
1191   switch (error_code) {
1192     case MAILIMAP_RESP_COND_STATE_OK:
1193       return MAILIMAP_NO_ERROR;
1194 
1195     default:
1196       return MAILIMAP_ERROR_MOVE;
1197   }
1198 }
1199 
1200 LIBETPAN_EXPORT
mailimap_uid_move(mailimap * session,struct mailimap_set * set,const char * mb)1201 int mailimap_uid_move(mailimap * session, struct mailimap_set * set,
1202                       const char * mb)
1203 {
1204   struct mailimap_response * response;
1205   int r;
1206   int error_code;
1207 
1208   if (session->imap_state != MAILIMAP_STATE_SELECTED)
1209     return MAILIMAP_ERROR_BAD_STATE;
1210 
1211   r = mailimap_send_current_tag(session);
1212   if (r != MAILIMAP_NO_ERROR)
1213     return r;
1214 
1215   r = mailimap_uid_move_send(session->imap_stream, set, mb);
1216   if (r != MAILIMAP_NO_ERROR)
1217     return r;
1218 
1219   r = mailimap_crlf_send(session->imap_stream);
1220   if (r != MAILIMAP_NO_ERROR)
1221     return r;
1222 
1223   if (mailstream_flush(session->imap_stream) == -1)
1224     return MAILIMAP_ERROR_STREAM;
1225 
1226   if (mailimap_read_line(session) == NULL)
1227     return MAILIMAP_ERROR_STREAM;
1228 
1229   r = mailimap_parse_response(session, &response);
1230   if (r != MAILIMAP_NO_ERROR)
1231     return r;
1232 
1233   error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
1234 
1235   mailimap_response_free(response);
1236 
1237   switch (error_code) {
1238     case MAILIMAP_RESP_COND_STATE_OK:
1239       return MAILIMAP_NO_ERROR;
1240 
1241     default:
1242       return MAILIMAP_ERROR_UID_MOVE;
1243   }
1244 }
1245 
1246 LIBETPAN_EXPORT
mailimap_create(mailimap * session,const char * mb)1247 int mailimap_create(mailimap * session, const char * mb)
1248 {
1249   struct mailimap_response * response;
1250   int r;
1251   int error_code;
1252 
1253   if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) &&
1254       (session->imap_state != MAILIMAP_STATE_SELECTED))
1255     return MAILIMAP_ERROR_BAD_STATE;
1256 
1257   r = mailimap_send_current_tag(session);
1258   if (r != MAILIMAP_NO_ERROR)
1259     return r;
1260 
1261   r = mailimap_create_send(session->imap_stream, mb);
1262   if (r != MAILIMAP_NO_ERROR)
1263     return r;
1264 
1265   r = mailimap_crlf_send(session->imap_stream);
1266   if (r != MAILIMAP_NO_ERROR)
1267 	return r;
1268 
1269   if (mailstream_flush(session->imap_stream) == -1)
1270     return MAILIMAP_ERROR_STREAM;
1271 
1272   if (mailimap_read_line(session) == NULL)
1273     return MAILIMAP_ERROR_STREAM;
1274 
1275   r = mailimap_parse_response(session, &response);
1276   if (r != MAILIMAP_NO_ERROR)
1277     return r;
1278 
1279   error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
1280 
1281   mailimap_response_free(response);
1282 
1283   switch (error_code) {
1284   case MAILIMAP_RESP_COND_STATE_OK:
1285     return MAILIMAP_NO_ERROR;
1286 
1287   default:
1288     return MAILIMAP_ERROR_CREATE;
1289   }
1290 }
1291 
1292 
1293 LIBETPAN_EXPORT
mailimap_delete(mailimap * session,const char * mb)1294 int mailimap_delete(mailimap * session, const char * mb)
1295 {
1296   struct mailimap_response * response;
1297   int r;
1298   int error_code;
1299 
1300   if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) &&
1301       (session->imap_state != MAILIMAP_STATE_SELECTED))
1302     return MAILIMAP_ERROR_BAD_STATE;
1303 
1304   r = mailimap_send_current_tag(session);
1305   if (r != MAILIMAP_NO_ERROR)
1306     return r;
1307 
1308   r = mailimap_delete_send(session->imap_stream, mb);
1309   if (r != MAILIMAP_NO_ERROR)
1310     return r;
1311 
1312   r = mailimap_crlf_send(session->imap_stream);
1313   if (r != MAILIMAP_NO_ERROR)
1314     return r;
1315 
1316   if (mailstream_flush(session->imap_stream) == -1)
1317     return MAILIMAP_ERROR_STREAM;
1318 
1319   if (mailimap_read_line(session) == NULL)
1320     return MAILIMAP_ERROR_STREAM;
1321 
1322   r = mailimap_parse_response(session, &response);
1323   if (r != MAILIMAP_NO_ERROR)
1324     return r;
1325 
1326   error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
1327 
1328   mailimap_response_free(response);
1329 
1330   switch (error_code) {
1331   case MAILIMAP_RESP_COND_STATE_OK:
1332     return MAILIMAP_NO_ERROR;
1333 
1334   default:
1335     return MAILIMAP_ERROR_DELETE;
1336   }
1337 }
1338 
1339 #if 0
1340 LIBETPAN_EXPORT
1341 int mailimap_examine(mailimap * session, const char * mb)
1342 {
1343   struct mailimap_response * response;
1344   int r;
1345   int error_code;
1346 
1347   if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) &&
1348       (session->imap_state != MAILIMAP_STATE_SELECTED))
1349     return MAILIMAP_ERROR_BAD_STATE;
1350 
1351   r = mailimap_send_current_tag(session);
1352   if (r != MAILIMAP_NO_ERROR)
1353     return r;
1354 
1355   r = mailimap_examine_send(session->imap_stream, mb);
1356   if (r != MAILIMAP_NO_ERROR)
1357     return r;
1358 
1359   r = mailimap_crlf_send(session->imap_stream);
1360   if (r != MAILIMAP_NO_ERROR)
1361     return r;
1362 
1363   if (mailstream_flush(session->imap_stream) == -1)
1364     return MAILIMAP_ERROR_STREAM;
1365 
1366   if (mailimap_read_line(session) == NULL)
1367     return MAILIMAP_ERROR_STREAM;
1368 
1369   if (session->imap_selection_info != NULL)
1370     mailimap_selection_info_free(session->imap_selection_info);
1371   session->imap_selection_info = mailimap_selection_info_new();
1372 
1373   r = mailimap_parse_response(session, &response);
1374   if (r != MAILIMAP_NO_ERROR)
1375     return r;
1376 
1377   error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
1378 
1379   mailimap_response_free(response);
1380 
1381   switch (error_code) {
1382   case MAILIMAP_RESP_COND_STATE_OK:
1383     session->imap_state = MAILIMAP_STATE_SELECTED;
1384     return MAILIMAP_NO_ERROR;
1385 
1386   default:
1387     mailimap_selection_info_free(session->imap_selection_info);
1388     session->imap_selection_info = NULL;
1389     session->imap_state = MAILIMAP_STATE_AUTHENTICATED;
1390     return MAILIMAP_ERROR_EXAMINE;
1391   }
1392 }
1393 #else
1394 LIBETPAN_EXPORT
mailimap_examine(mailimap * session,const char * mb)1395 int mailimap_examine(mailimap * session, const char * mb)
1396 {
1397 	uint64_t dummy;
1398 	return mailimap_examine_condstore_optional(session, mb, 0, &dummy);
1399 }
1400 #endif
1401 
1402 LIBETPAN_EXPORT
1403 int
mailimap_fetch(mailimap * session,struct mailimap_set * set,struct mailimap_fetch_type * fetch_type,clist ** result)1404 mailimap_fetch(mailimap * session, struct mailimap_set * set,
1405 	       struct mailimap_fetch_type * fetch_type, clist ** result)
1406 {
1407 #if 0
1408   struct mailimap_response * response;
1409   int r;
1410   int error_code;
1411 
1412   if (session->imap_state != MAILIMAP_STATE_SELECTED)
1413     return MAILIMAP_ERROR_BAD_STATE;
1414 
1415   r = mailimap_send_current_tag(session);
1416   if (r != MAILIMAP_NO_ERROR)
1417     return r;
1418 
1419   r = mailimap_fetch_send(session->imap_stream, set, fetch_type);
1420   if (r != MAILIMAP_NO_ERROR)
1421     return r;
1422 
1423   r = mailimap_crlf_send(session->imap_stream);
1424   if (r != MAILIMAP_NO_ERROR)
1425     return r;
1426 
1427   if (mailstream_flush(session->imap_stream) == -1)
1428     return MAILIMAP_ERROR_STREAM;
1429 
1430   if (mailimap_read_line(session) == NULL)
1431     return MAILIMAP_ERROR_STREAM;
1432 
1433   r = mailimap_parse_response(session, &response);
1434   if (r != MAILIMAP_NO_ERROR)
1435     return r;
1436 
1437   * result = session->imap_response_info->rsp_fetch_list;
1438   session->imap_response_info->rsp_fetch_list = NULL;
1439 
1440   if (clist_count(* result) == 0) {
1441     error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
1442   }
1443   else {
1444     error_code = MAILIMAP_RESP_COND_STATE_OK;
1445   }
1446 
1447   mailimap_response_free(response);
1448 
1449   switch (error_code) {
1450   case MAILIMAP_RESP_COND_STATE_OK:
1451     return MAILIMAP_NO_ERROR;
1452 
1453   default:
1454     mailimap_fetch_list_free(* result);
1455     return MAILIMAP_ERROR_FETCH;
1456   }
1457 #else
1458   return mailimap_fetch_changedsince(session, set, fetch_type, 0, result);
1459 #endif
1460 }
1461 
1462 LIBETPAN_EXPORT
mailimap_fetch_list_free(clist * fetch_list)1463 void mailimap_fetch_list_free(clist * fetch_list)
1464 {
1465   clist_foreach(fetch_list, (clist_func) mailimap_msg_att_free, NULL);
1466   clist_free(fetch_list);
1467 }
1468 
1469 LIBETPAN_EXPORT
1470 int
mailimap_uid_fetch(mailimap * session,struct mailimap_set * set,struct mailimap_fetch_type * fetch_type,clist ** result)1471 mailimap_uid_fetch(mailimap * session,
1472 		   struct mailimap_set * set,
1473 		   struct mailimap_fetch_type * fetch_type, clist ** result)
1474 {
1475 #if 0
1476   struct mailimap_response * response;
1477   int r;
1478   int error_code;
1479 
1480   if (session->imap_state != MAILIMAP_STATE_SELECTED)
1481     return MAILIMAP_ERROR_BAD_STATE;
1482 
1483   r = mailimap_send_current_tag(session);
1484   if (r != MAILIMAP_NO_ERROR)
1485     return r;
1486 
1487   r = mailimap_uid_fetch_send(session->imap_stream, set, fetch_type);
1488   if (r != MAILIMAP_NO_ERROR)
1489     return r;
1490 
1491   r = mailimap_crlf_send(session->imap_stream);
1492   if (r != MAILIMAP_NO_ERROR)
1493     return r;
1494 
1495   if (mailstream_flush(session->imap_stream) == -1)
1496     return MAILIMAP_ERROR_STREAM;
1497 
1498   if (mailimap_read_line(session) == NULL)
1499     return MAILIMAP_ERROR_STREAM;
1500 
1501   r = mailimap_parse_response(session, &response);
1502   if (r != MAILIMAP_NO_ERROR) {
1503     return r;
1504   }
1505 
1506   * result = session->imap_response_info->rsp_fetch_list;
1507   session->imap_response_info->rsp_fetch_list = NULL;
1508 
1509   if (clist_count(* result) == 0) {
1510     error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
1511   }
1512   else {
1513     error_code = MAILIMAP_RESP_COND_STATE_OK;
1514   }
1515 
1516   mailimap_response_free(response);
1517 
1518   switch (error_code) {
1519   case MAILIMAP_RESP_COND_STATE_OK:
1520     return MAILIMAP_NO_ERROR;
1521 
1522   default:
1523     mailimap_fetch_list_free(* result);
1524     * result = NULL;
1525     return MAILIMAP_ERROR_UID_FETCH;
1526   }
1527 #else
1528   return mailimap_uid_fetch_changedsince(session, set, fetch_type, 0, result);
1529 #endif
1530 }
1531 
1532 LIBETPAN_EXPORT
mailimap_list(mailimap * session,const char * mb,const char * list_mb,clist ** result)1533 int mailimap_list(mailimap * session, const char * mb,
1534 		   const char * list_mb, clist ** result)
1535 {
1536   struct mailimap_response * response;
1537   int r;
1538   int error_code;
1539 
1540   if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) &&
1541       (session->imap_state != MAILIMAP_STATE_SELECTED))
1542     return MAILIMAP_ERROR_BAD_STATE;
1543 
1544   r = mailimap_send_current_tag(session);
1545   if (r != MAILIMAP_NO_ERROR)
1546     return r;
1547 
1548   r = mailimap_list_send(session->imap_stream, mb, list_mb);
1549   if (r != MAILIMAP_NO_ERROR)
1550     return r;
1551 
1552   r = mailimap_crlf_send(session->imap_stream);
1553   if (r != MAILIMAP_NO_ERROR)
1554 	return r;
1555 
1556   if (mailstream_flush(session->imap_stream) == -1)
1557     return MAILIMAP_ERROR_STREAM;
1558 
1559   if (mailimap_read_line(session) == NULL)
1560     return MAILIMAP_ERROR_STREAM;
1561 
1562   r = mailimap_parse_response(session, &response);
1563   if (r != MAILIMAP_NO_ERROR)
1564     return r;
1565 
1566   * result = session->imap_response_info->rsp_mailbox_list;
1567   session->imap_response_info->rsp_mailbox_list = NULL;
1568 
1569   error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
1570 
1571   mailimap_response_free(response);
1572 
1573   switch (error_code) {
1574   case MAILIMAP_RESP_COND_STATE_OK:
1575     return MAILIMAP_NO_ERROR;
1576 
1577   default:
1578     return MAILIMAP_ERROR_LIST;
1579   }
1580 }
1581 
1582 LIBETPAN_EXPORT
mailimap_login(mailimap * session,const char * userid,const char * password)1583 int mailimap_login(mailimap * session,
1584     const char * userid, const char * password)
1585 {
1586   struct mailimap_response * response;
1587   int r;
1588   int error_code;
1589 
1590   if (session->imap_state != MAILIMAP_STATE_NON_AUTHENTICATED)
1591     return MAILIMAP_ERROR_BAD_STATE;
1592 
1593   mailstream_set_privacy(session->imap_stream, 0);
1594   r = mailimap_send_current_tag(session);
1595   if (r != MAILIMAP_NO_ERROR) {
1596     mailstream_set_privacy(session->imap_stream, 1);
1597     return r;
1598   }
1599 
1600   r = mailimap_login_send(session->imap_stream, userid, password);
1601   if (r != MAILIMAP_NO_ERROR) {
1602     mailstream_set_privacy(session->imap_stream, 1);
1603     return r;
1604   }
1605 
1606   r = mailimap_crlf_send(session->imap_stream);
1607   if (r != MAILIMAP_NO_ERROR) {
1608     mailstream_set_privacy(session->imap_stream, 1);
1609     return r;
1610   }
1611 
1612   if (mailstream_flush(session->imap_stream) == -1) {
1613     mailstream_set_privacy(session->imap_stream, 1);
1614     return MAILIMAP_ERROR_STREAM;
1615   }
1616   mailstream_set_privacy(session->imap_stream, 1);
1617 
1618   if (mailimap_read_line(session) == NULL)
1619     return MAILIMAP_ERROR_STREAM;
1620 
1621   r = mailimap_parse_response(session, &response);
1622   if (r != MAILIMAP_NO_ERROR)
1623     return r;
1624 
1625   error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
1626 
1627   mailimap_response_free(response);
1628 
1629   switch (error_code) {
1630   case MAILIMAP_RESP_COND_STATE_OK:
1631     session->imap_state = MAILIMAP_STATE_AUTHENTICATED;
1632     return MAILIMAP_NO_ERROR;
1633 
1634   default:
1635     return MAILIMAP_ERROR_LOGIN;
1636   }
1637 }
1638 
1639 #ifdef USE_SASL
sasl_getsimple(void * context,int id,const char ** result,unsigned * len)1640 static int sasl_getsimple(void * context, int id,
1641     const char ** result, unsigned * len)
1642 {
1643   mailimap * session;
1644 
1645   session = context;
1646 
1647   switch (id) {
1648   case SASL_CB_USER:
1649     if (result != NULL)
1650       * result = session->imap_sasl.sasl_login;
1651     if (len != NULL)
1652       * len = (unsigned) strlen(session->imap_sasl.sasl_login);
1653     return SASL_OK;
1654 
1655   case SASL_CB_AUTHNAME:
1656     if (result != NULL)
1657       * result = session->imap_sasl.sasl_auth_name;
1658     if (len != NULL)
1659       * len = (unsigned) strlen(session->imap_sasl.sasl_auth_name);
1660     return SASL_OK;
1661   }
1662 
1663   return SASL_FAIL;
1664 }
1665 
sasl_getsecret(sasl_conn_t * conn,void * context,int id,sasl_secret_t ** psecret)1666 static int sasl_getsecret(sasl_conn_t * conn, void * context, int id,
1667     sasl_secret_t ** psecret)
1668 {
1669   mailimap * session;
1670 
1671   session = context;
1672 
1673   switch (id) {
1674   case SASL_CB_PASS:
1675     if (psecret != NULL)
1676       * psecret = session->imap_sasl.sasl_secret;
1677     return SASL_OK;
1678   }
1679 
1680   return SASL_FAIL;
1681 }
1682 
sasl_getrealm(void * context,int id,const char ** availrealms,const char ** result)1683 static int sasl_getrealm(void * context, int id,
1684     const char ** availrealms,
1685     const char ** result)
1686 {
1687   mailimap * session;
1688 
1689   session = context;
1690 
1691   switch (id) {
1692   case SASL_CB_GETREALM:
1693     if (result != NULL)
1694       * result = session->imap_sasl.sasl_realm;
1695     return SASL_OK;
1696   }
1697 
1698   return SASL_FAIL;
1699 }
1700 #endif
1701 
1702 LIBETPAN_EXPORT
mailimap_authenticate(mailimap * session,const char * auth_type,const char * server_fqdn,const char * local_ip_port,const char * remote_ip_port,const char * login,const char * auth_name,const char * password,const char * realm)1703 int mailimap_authenticate(mailimap * session, const char * auth_type,
1704     const char * server_fqdn,
1705     const char * local_ip_port,
1706     const char * remote_ip_port,
1707     const char * login, const char * auth_name,
1708     const char * password, const char * realm)
1709 {
1710 #ifdef USE_SASL
1711   struct mailimap_response * response;
1712   int r;
1713   int error_code;
1714   size_t indx;
1715   sasl_callback_t sasl_callback[5];
1716   const char * sasl_out;
1717   unsigned sasl_out_len;
1718   const char * mechusing;
1719   sasl_secret_t * secret;
1720   int res;
1721   size_t len;
1722 
1723   if (session->imap_state != MAILIMAP_STATE_NON_AUTHENTICATED) {
1724     res = MAILIMAP_ERROR_BAD_STATE;
1725     goto err;
1726   }
1727 
1728   sasl_callback[0].id = SASL_CB_GETREALM;
1729   sasl_callback[0].proc =  (int(*)(void)) sasl_getrealm;
1730   sasl_callback[0].context = session;
1731   sasl_callback[1].id = SASL_CB_USER;
1732   sasl_callback[1].proc =  (int(*)(void)) sasl_getsimple;
1733   sasl_callback[1].context = session;
1734   sasl_callback[2].id = SASL_CB_AUTHNAME;
1735   sasl_callback[2].proc =  (int(*)(void)) sasl_getsimple;
1736   sasl_callback[2].context = session;
1737   sasl_callback[3].id = SASL_CB_PASS;
1738   sasl_callback[3].proc =  (int(*)(void)) sasl_getsecret;
1739   sasl_callback[3].context = session;
1740   sasl_callback[4].id = SASL_CB_LIST_END;
1741   sasl_callback[4].proc =  NULL;
1742   sasl_callback[4].context = NULL;
1743 
1744   len = strlen(password);
1745   secret = malloc(sizeof(* secret) + len);
1746   if (secret == NULL) {
1747     res = MAILIMAP_ERROR_MEMORY;
1748     goto err;
1749   }
1750   secret->len = len;
1751   memcpy(secret->data, password, len + 1);
1752 
1753   session->imap_sasl.sasl_server_fqdn = server_fqdn;
1754   session->imap_sasl.sasl_login = login;
1755   session->imap_sasl.sasl_auth_name = auth_name;
1756   session->imap_sasl.sasl_password = password;
1757   session->imap_sasl.sasl_realm = realm;
1758   session->imap_sasl.sasl_secret = secret;
1759 
1760   /* init SASL */
1761   if (session->imap_sasl.sasl_conn != NULL) {
1762     sasl_dispose((sasl_conn_t **) &session->imap_sasl.sasl_conn);
1763     session->imap_sasl.sasl_conn = NULL;
1764   }
1765   else {
1766     mailsasl_ref();
1767   }
1768 
1769   r = sasl_client_new("imap", server_fqdn,
1770       local_ip_port, remote_ip_port, sasl_callback, 0,
1771       (sasl_conn_t **) &session->imap_sasl.sasl_conn);
1772   if (r != SASL_OK) {
1773     res = MAILIMAP_ERROR_LOGIN;
1774     goto free_secret;
1775   }
1776 
1777   r = sasl_client_start(session->imap_sasl.sasl_conn,
1778       auth_type, NULL, &sasl_out, &sasl_out_len, &mechusing);
1779   if ((r != SASL_CONTINUE) && (r != SASL_OK)) {
1780     res = MAILIMAP_ERROR_LOGIN;
1781     goto free_sasl_conn;
1782   }
1783 
1784   mailstream_set_privacy(session->imap_stream, 0);
1785   r = mailimap_send_current_tag(session);
1786   if (r != MAILIMAP_NO_ERROR) {
1787     res = r;
1788     goto free_sasl_conn;
1789   }
1790 
1791   r = mailimap_authenticate_send(session->imap_stream, auth_type);
1792   if (r != MAILIMAP_NO_ERROR) {
1793     res = r;
1794     goto free_sasl_conn;
1795   }
1796 
1797   r = mailimap_crlf_send(session->imap_stream);
1798   if (r != MAILIMAP_NO_ERROR) {
1799     res = r;
1800     goto free_sasl_conn;
1801   }
1802 
1803   if (mailstream_flush(session->imap_stream) == -1) {
1804     res = MAILIMAP_ERROR_STREAM;
1805     goto free_sasl_conn;
1806   }
1807 
1808   while (1) {
1809     struct mailimap_continue_req * cont_req;
1810     char * response_base64;
1811     int got_response;
1812     char * encoded;
1813     unsigned int encoded_len;
1814     unsigned int max_encoded;
1815 
1816     if (mailimap_read_line(session) == NULL) {
1817       res = MAILIMAP_ERROR_STREAM;
1818       goto free_sasl_conn;
1819     }
1820 
1821     indx = 0;
1822 
1823     r = mailimap_continue_req_parse(session->imap_stream,
1824         session->imap_stream_buffer, NULL,
1825         &indx, &cont_req,
1826         session->imap_progr_rate, session->imap_progr_fun);
1827     if (r != MAILIMAP_NO_ERROR)
1828       break;
1829 
1830     got_response = 1;
1831     if (cont_req->cr_type == MAILIMAP_CONTINUE_REQ_BASE64) {
1832       response_base64 = cont_req->cr_data.cr_base64;
1833       if (* response_base64 == '\0')
1834         got_response = 0;
1835     }
1836     else {
1837       response_base64 = "";
1838       got_response = 0;
1839     }
1840 
1841     if (got_response) {
1842       unsigned int response_len;
1843       char * decoded;
1844       unsigned int decoded_len;
1845       unsigned int max_decoded;
1846 
1847       response_len = (unsigned int) strlen(response_base64);
1848       max_decoded = response_len * 3 / 4;
1849       decoded = malloc(max_decoded + 1);
1850       if (decoded == NULL) {
1851         mailimap_continue_req_free(cont_req);
1852         res = MAILIMAP_ERROR_MEMORY;
1853         goto free_sasl_conn;
1854       }
1855 
1856       r = sasl_decode64(response_base64, response_len,
1857           decoded, max_decoded + 1, &decoded_len);
1858 
1859       mailimap_continue_req_free(cont_req);
1860 
1861       if (r != SASL_OK) {
1862         free(decoded);
1863         res = MAILIMAP_ERROR_MEMORY;
1864         goto free_sasl_conn;
1865       }
1866 
1867       r = sasl_client_step(session->imap_sasl.sasl_conn,
1868           decoded, decoded_len, NULL, &sasl_out, &sasl_out_len);
1869 
1870       free(decoded);
1871 
1872       if ((r != SASL_CONTINUE) && (r != SASL_OK)) {
1873         res = MAILIMAP_ERROR_LOGIN;
1874         goto free_sasl_conn;
1875       }
1876     }
1877     else {
1878       mailimap_continue_req_free(cont_req);
1879     }
1880 
1881     max_encoded = ((sasl_out_len + 2) / 3) * 4;
1882     encoded = malloc(max_encoded + 1);
1883     if (encoded == NULL) {
1884       res = MAILIMAP_ERROR_MEMORY;
1885       goto free_sasl_conn;
1886     }
1887 
1888     r = sasl_encode64(sasl_out, sasl_out_len,
1889         encoded, max_encoded + 1, &encoded_len);
1890     if (r != SASL_OK) {
1891       free(encoded);
1892       res = MAILIMAP_ERROR_MEMORY;
1893       goto free_sasl_conn;
1894     }
1895 
1896     r = mailimap_token_send(session->imap_stream, encoded);
1897 
1898     free(encoded);
1899 
1900     if (r != MAILIMAP_NO_ERROR) {
1901       res = r;
1902       goto free_sasl_conn;
1903     }
1904 
1905     r = mailimap_crlf_send(session->imap_stream);
1906     if (r != MAILIMAP_NO_ERROR) {
1907       res = r;
1908       goto free_sasl_conn;
1909     }
1910 
1911     if (mailstream_flush(session->imap_stream) == -1) {
1912       res = MAILIMAP_ERROR_STREAM;
1913       goto free_sasl_conn;
1914     }
1915   }
1916 
1917   free(session->imap_sasl.sasl_secret);
1918   session->imap_sasl.sasl_secret = NULL;
1919 
1920   r = mailimap_parse_response(session, &response);
1921   if (r != MAILIMAP_NO_ERROR) {
1922     res = r;
1923     goto free_sasl_conn;
1924   }
1925 
1926   error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
1927 
1928   mailimap_response_free(response);
1929 
1930   switch (error_code) {
1931   case MAILIMAP_RESP_COND_STATE_OK:
1932     session->imap_state = MAILIMAP_STATE_AUTHENTICATED;
1933     res = MAILIMAP_NO_ERROR;
1934     goto free_sasl_conn;
1935 
1936   default:
1937     res = MAILIMAP_ERROR_LOGIN;
1938     goto free_sasl_conn;
1939   }
1940 
1941  free_sasl_conn:
1942   mailstream_set_privacy(session->imap_stream, 1);
1943   sasl_dispose((sasl_conn_t **) &session->imap_sasl.sasl_conn);
1944   session->imap_sasl.sasl_conn = NULL;
1945   mailsasl_unref();
1946  free_secret:
1947   free(session->imap_sasl.sasl_secret);
1948   session->imap_sasl.sasl_secret = NULL;
1949  err:
1950   return res;
1951 #else
1952   return MAILIMAP_ERROR_LOGIN;
1953 #endif
1954 }
1955 
1956 LIBETPAN_EXPORT
mailimap_lsub(mailimap * session,const char * mb,const char * list_mb,clist ** result)1957 int mailimap_lsub(mailimap * session, const char * mb,
1958     const char * list_mb, clist ** result)
1959 {
1960   struct mailimap_response * response;
1961   int r;
1962   int error_code;
1963 
1964   if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) &&
1965       (session->imap_state != MAILIMAP_STATE_SELECTED))
1966     return MAILIMAP_ERROR_BAD_STATE;
1967 
1968   r = mailimap_send_current_tag(session);
1969   if (r != MAILIMAP_NO_ERROR)
1970 	return r;
1971 
1972   r = mailimap_lsub_send(session->imap_stream, mb, list_mb);
1973   if (r != MAILIMAP_NO_ERROR)
1974 	return r;
1975 
1976   r = mailimap_crlf_send(session->imap_stream);
1977   if (r != MAILIMAP_NO_ERROR)
1978 	return r;
1979 
1980   if (mailstream_flush(session->imap_stream) == -1)
1981     return MAILIMAP_ERROR_STREAM;
1982 
1983   if (mailimap_read_line(session) == NULL)
1984     return MAILIMAP_ERROR_STREAM;
1985 
1986   r = mailimap_parse_response(session, &response);
1987   if (r != MAILIMAP_NO_ERROR)
1988     return r;
1989 
1990   * result = session->imap_response_info->rsp_mailbox_lsub;
1991   session->imap_response_info->rsp_mailbox_lsub = NULL;
1992 
1993   error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
1994 
1995   mailimap_response_free(response);
1996 
1997   switch (error_code) {
1998   case MAILIMAP_RESP_COND_STATE_OK:
1999     return MAILIMAP_NO_ERROR;
2000 
2001   default:
2002     return MAILIMAP_ERROR_LSUB;
2003   }
2004 }
2005 
2006 LIBETPAN_EXPORT
mailimap_list_result_free(clist * list)2007 void mailimap_list_result_free(clist * list)
2008 {
2009   clist_foreach(list, (clist_func) mailimap_mailbox_list_free, NULL);
2010   clist_free(list);
2011 }
2012 
2013 LIBETPAN_EXPORT
mailimap_rename(mailimap * session,const char * mb,const char * new_name)2014 int mailimap_rename(mailimap * session,
2015     const char * mb, const char * new_name)
2016 {
2017   struct mailimap_response * response;
2018   int r;
2019   int error_code;
2020 
2021   if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) &&
2022       (session->imap_state != MAILIMAP_STATE_SELECTED))
2023     return MAILIMAP_ERROR_BAD_STATE;
2024 
2025   r = mailimap_send_current_tag(session);
2026   if (r != MAILIMAP_NO_ERROR)
2027 	return r;
2028 
2029   r = mailimap_rename_send(session->imap_stream, mb, new_name);
2030   if (r != MAILIMAP_NO_ERROR)
2031 	return r;
2032 
2033   if (!mailimap_crlf_send(session->imap_stream))
2034   if (r != MAILIMAP_NO_ERROR)
2035 	return r;
2036 
2037   if (mailstream_flush(session->imap_stream) == -1)
2038     return MAILIMAP_ERROR_STREAM;
2039 
2040   if (mailimap_read_line(session) == NULL)
2041     return MAILIMAP_ERROR_STREAM;
2042 
2043   r = mailimap_parse_response(session, &response);
2044   if (r != MAILIMAP_NO_ERROR)
2045     return r;
2046 
2047   error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
2048 
2049   mailimap_response_free(response);
2050 
2051   switch (error_code) {
2052   case MAILIMAP_RESP_COND_STATE_OK:
2053     return MAILIMAP_NO_ERROR;
2054 
2055   default:
2056     return MAILIMAP_ERROR_RENAME;
2057   }
2058 }
2059 
2060 LIBETPAN_EXPORT
2061 int
mailimap_search(mailimap * session,const char * charset,struct mailimap_search_key * key,clist ** result)2062 mailimap_search(mailimap * session, const char * charset,
2063     struct mailimap_search_key * key, clist ** result)
2064 {
2065   return mailimap_search_modseq(session, charset, key, result, NULL);
2066 }
2067 
2068 LIBETPAN_EXPORT
2069 int
mailimap_uid_search(mailimap * session,const char * charset,struct mailimap_search_key * key,clist ** result)2070 mailimap_uid_search(mailimap * session, const char * charset,
2071     struct mailimap_search_key * key, clist ** result)
2072 {
2073   return mailimap_uid_search_modseq(session, charset, key, result, NULL);
2074 }
2075 
mailimap_search_literalplus(mailimap * session,const char * charset,struct mailimap_search_key * key,clist ** result)2076 LIBETPAN_EXPORT int mailimap_search_literalplus(mailimap * session, const char * charset,
2077                                                 struct mailimap_search_key * key, clist ** result)
2078 {
2079   return mailimap_search_literalplus_modseq(session, charset, key, result, NULL);
2080 }
2081 
mailimap_uid_search_literalplus(mailimap * session,const char * charset,struct mailimap_search_key * key,clist ** result)2082 LIBETPAN_EXPORT int mailimap_uid_search_literalplus(mailimap * session, const char * charset,
2083                                                     struct mailimap_search_key * key, clist ** result)
2084 {
2085   return mailimap_uid_search_literalplus_modseq(session, charset, key, result, NULL);
2086 }
2087 
2088 LIBETPAN_EXPORT
mailimap_search_result_free(clist * search_result)2089 void mailimap_search_result_free(clist * search_result)
2090 {
2091   clist_foreach(search_result, (clist_func) free, NULL);
2092   clist_free(search_result);
2093 }
2094 
2095 LIBETPAN_EXPORT
2096 int
mailimap_select(mailimap * session,const char * mb)2097 mailimap_select(mailimap * session, const char * mb)
2098 {
2099 	uint64_t dummy;
2100 	return mailimap_select_condstore_optional(session, mb, 0, &dummy);
2101 }
2102 
2103 LIBETPAN_EXPORT
2104 int
mailimap_custom_command(mailimap * session,const char * command)2105 mailimap_custom_command(mailimap * session, const char * command)
2106 {
2107   int r;
2108   int error_code;
2109   struct mailimap_response * response;
2110 
2111   r = mailimap_send_current_tag(session);
2112   if (r != MAILIMAP_NO_ERROR)
2113     return r;
2114 
2115   r = mailimap_send_custom_command(session->imap_stream, command);
2116   if (r != MAILIMAP_NO_ERROR)
2117     return r;
2118 
2119   r = mailimap_crlf_send(session->imap_stream);
2120   if (r != MAILIMAP_NO_ERROR)
2121     return r;
2122 
2123   if (mailstream_flush(session->imap_stream) == -1)
2124     return MAILIMAP_ERROR_STREAM;
2125 
2126   if (mailimap_read_line(session) == NULL)
2127     return MAILIMAP_ERROR_STREAM;
2128 
2129   r = mailimap_parse_response(session, &response);
2130   if (r != MAILIMAP_NO_ERROR)
2131     return r;
2132 
2133   error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
2134 
2135   mailimap_response_free(response);
2136 
2137   switch (error_code) {
2138     case MAILIMAP_RESP_COND_STATE_OK:
2139       return MAILIMAP_NO_ERROR;
2140 
2141     default:
2142       return MAILIMAP_ERROR_CUSTOM_COMMAND;
2143   }
2144 }
2145 
2146 LIBETPAN_EXPORT
2147 int
mailimap_status(mailimap * session,const char * mb,struct mailimap_status_att_list * status_att_list,struct mailimap_mailbox_data_status ** result)2148 mailimap_status(mailimap * session, const char * mb,
2149     struct mailimap_status_att_list * status_att_list,
2150     struct mailimap_mailbox_data_status ** result)
2151 {
2152   struct mailimap_response * response;
2153   int r;
2154   int error_code;
2155 
2156   if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) &&
2157       (session->imap_state != MAILIMAP_STATE_SELECTED))
2158     return MAILIMAP_ERROR_BAD_STATE;
2159 
2160   r = mailimap_send_current_tag(session);
2161   if (r != MAILIMAP_NO_ERROR)
2162 	return r;
2163 
2164   r = mailimap_status_send(session->imap_stream, mb, status_att_list);
2165   if (r != MAILIMAP_NO_ERROR)
2166 	return r;
2167 
2168   r = mailimap_crlf_send(session->imap_stream);
2169   if (r != MAILIMAP_NO_ERROR)
2170 	return r;
2171 
2172   if (mailstream_flush(session->imap_stream) == -1)
2173     return MAILIMAP_ERROR_STREAM;
2174 
2175   if (mailimap_read_line(session) == NULL)
2176     return MAILIMAP_ERROR_STREAM;
2177 
2178   r = mailimap_parse_response(session, &response);
2179   if (r != MAILIMAP_NO_ERROR)
2180     return r;
2181 
2182   * result = session->imap_response_info->rsp_status;
2183   session->imap_response_info->rsp_status = NULL;
2184 
2185   error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
2186 
2187   mailimap_response_free(response);
2188 
2189   switch (error_code) {
2190   case MAILIMAP_RESP_COND_STATE_OK:
2191     return MAILIMAP_NO_ERROR;
2192 
2193   default:
2194     return MAILIMAP_ERROR_STATUS;
2195   }
2196 }
2197 
2198 
2199 LIBETPAN_EXPORT
2200 int
mailimap_store(mailimap * session,struct mailimap_set * set,struct mailimap_store_att_flags * store_att_flags)2201 mailimap_store(mailimap * session,
2202 	       struct mailimap_set * set,
2203 	       struct mailimap_store_att_flags * store_att_flags)
2204 {
2205 #if 0
2206   struct mailimap_response * response;
2207   int r;
2208   int error_code;
2209 
2210   if (session->imap_state != MAILIMAP_STATE_SELECTED)
2211     return MAILIMAP_ERROR_BAD_STATE;
2212 
2213   r = mailimap_send_current_tag(session);
2214   if (r != MAILIMAP_NO_ERROR)
2215     return r;
2216 
2217   r = mailimap_store_send(session->imap_stream, set, store_att_flags);
2218   if (r != MAILIMAP_NO_ERROR)
2219     return r;
2220 
2221   r = mailimap_crlf_send(session->imap_stream);
2222   if (r != MAILIMAP_NO_ERROR)
2223     return r;
2224 
2225   if (mailstream_flush(session->imap_stream) == -1)
2226     return MAILIMAP_ERROR_STREAM;
2227 
2228   if (mailimap_read_line(session) == NULL)
2229     return MAILIMAP_ERROR_STREAM;
2230 
2231   r = mailimap_parse_response(session, &response);
2232   if (r != MAILIMAP_NO_ERROR)
2233     return r;
2234 
2235   error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
2236 
2237   mailimap_response_free(response);
2238 
2239   switch (error_code) {
2240   case MAILIMAP_RESP_COND_STATE_OK:
2241     return MAILIMAP_NO_ERROR;
2242 
2243   default:
2244     return MAILIMAP_ERROR_STORE;
2245   }
2246 #else
2247   return mailimap_store_unchangedsince_optional(session,
2248   	set, 0, 0, store_att_flags);
2249 #endif
2250 }
2251 
2252 LIBETPAN_EXPORT
2253 int
mailimap_uid_store(mailimap * session,struct mailimap_set * set,struct mailimap_store_att_flags * store_att_flags)2254 mailimap_uid_store(mailimap * session,
2255 		   struct mailimap_set * set,
2256 		   struct mailimap_store_att_flags * store_att_flags)
2257 {
2258 #if 0
2259   struct mailimap_response * response;
2260   int r;
2261   int error_code;
2262 
2263   if (session->imap_state != MAILIMAP_STATE_SELECTED)
2264     return MAILIMAP_ERROR_BAD_STATE;
2265 
2266   r = mailimap_send_current_tag(session);
2267   if (r != MAILIMAP_NO_ERROR)
2268 	return r;
2269 
2270   r = mailimap_uid_store_send(session->imap_stream, set, store_att_flags);
2271   if (r != MAILIMAP_NO_ERROR)
2272 	return r;
2273 
2274   r = mailimap_crlf_send(session->imap_stream);
2275   if (r != MAILIMAP_NO_ERROR)
2276 	return r;
2277 
2278   if (mailstream_flush(session->imap_stream) == -1)
2279     return MAILIMAP_ERROR_STREAM;
2280 
2281   if (mailimap_read_line(session) == NULL)
2282     return MAILIMAP_ERROR_STREAM;
2283 
2284   r = mailimap_parse_response(session, &response);
2285   if (r != MAILIMAP_NO_ERROR)
2286     return r;
2287 
2288   error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
2289 
2290   mailimap_response_free(response);
2291 
2292   switch (error_code) {
2293   case MAILIMAP_RESP_COND_STATE_OK:
2294     return MAILIMAP_NO_ERROR;
2295 
2296   default:
2297     return MAILIMAP_ERROR_UID_STORE;
2298   }
2299 #else
2300   return mailimap_uid_store_unchangedsince_optional(session,
2301   	set, 0, 0, store_att_flags);
2302 #endif
2303 }
2304 
2305 LIBETPAN_EXPORT
mailimap_subscribe(mailimap * session,const char * mb)2306 int mailimap_subscribe(mailimap * session, const char * mb)
2307 {
2308   struct mailimap_response * response;
2309   int r;
2310   int error_code;
2311 
2312   if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) &&
2313       (session->imap_state != MAILIMAP_STATE_SELECTED))
2314     return MAILIMAP_ERROR_BAD_STATE;
2315 
2316   r = mailimap_send_current_tag(session);
2317   if (r != MAILIMAP_NO_ERROR)
2318 	return r;
2319 
2320   r = mailimap_subscribe_send(session->imap_stream, mb);
2321   if (r != MAILIMAP_NO_ERROR)
2322 	return r;
2323 
2324   r = mailimap_crlf_send(session->imap_stream);
2325   if (r != MAILIMAP_NO_ERROR)
2326 	return r;
2327 
2328   if (mailstream_flush(session->imap_stream) == -1)
2329     return MAILIMAP_ERROR_STREAM;
2330 
2331   if (mailimap_read_line(session) == NULL)
2332     return MAILIMAP_ERROR_STREAM;
2333 
2334   r = mailimap_parse_response(session, &response);
2335   if (r != MAILIMAP_NO_ERROR)
2336     return r;
2337 
2338   error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
2339 
2340   mailimap_response_free(response);
2341 
2342   switch (error_code) {
2343   case MAILIMAP_RESP_COND_STATE_OK:
2344     return MAILIMAP_NO_ERROR;
2345 
2346   default:
2347     return MAILIMAP_ERROR_SUBSCRIBE;
2348   }
2349 }
2350 
2351 LIBETPAN_EXPORT
mailimap_unsubscribe(mailimap * session,const char * mb)2352 int mailimap_unsubscribe(mailimap * session, const char * mb)
2353 {
2354   struct mailimap_response * response;
2355   int r;
2356   int error_code;
2357 
2358   if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) &&
2359       (session->imap_state != MAILIMAP_STATE_SELECTED))
2360     return MAILIMAP_ERROR_BAD_STATE;
2361 
2362   r = mailimap_send_current_tag(session);
2363   if (r != MAILIMAP_NO_ERROR)
2364     return r;
2365 
2366   r = mailimap_unsubscribe_send(session->imap_stream, mb);
2367   if (r != MAILIMAP_NO_ERROR)
2368     return r;
2369 
2370   r = mailimap_crlf_send(session->imap_stream);
2371   if (r != MAILIMAP_NO_ERROR)
2372     return r;
2373 
2374   if (mailstream_flush(session->imap_stream) == -1)
2375     return MAILIMAP_ERROR_STREAM;
2376 
2377   if (mailimap_read_line(session) == NULL)
2378     return MAILIMAP_ERROR_STREAM;
2379 
2380   r = mailimap_parse_response(session, &response);
2381   if (r != MAILIMAP_NO_ERROR)
2382     return r;
2383 
2384   error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
2385 
2386   mailimap_response_free(response);
2387 
2388   switch (error_code) {
2389   case MAILIMAP_RESP_COND_STATE_OK:
2390     return MAILIMAP_NO_ERROR;
2391 
2392   default:
2393     return MAILIMAP_ERROR_UNSUBSCRIBE;
2394   }
2395 }
2396 
2397 
2398 LIBETPAN_EXPORT
mailimap_starttls(mailimap * session)2399 int mailimap_starttls(mailimap * session)
2400 {
2401   struct mailimap_response * response;
2402   int r;
2403   int error_code;
2404 
2405   r = mailimap_send_current_tag(session);
2406   if (r != MAILIMAP_NO_ERROR)
2407     return r;
2408 
2409   r = mailimap_starttls_send(session->imap_stream);
2410   if (r != MAILIMAP_NO_ERROR)
2411     return r;
2412 
2413   r = mailimap_crlf_send(session->imap_stream);
2414   if (r != MAILIMAP_NO_ERROR)
2415     return r;
2416 
2417   if (mailstream_flush(session->imap_stream) == -1)
2418     return MAILIMAP_ERROR_STREAM;
2419 
2420   if (mailimap_read_line(session) == NULL)
2421     return MAILIMAP_ERROR_STREAM;
2422 
2423   r = mailimap_parse_response(session, &response);
2424   if (r != MAILIMAP_NO_ERROR)
2425     return r;
2426 
2427   error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
2428 
2429   mailimap_response_free(response);
2430 
2431   switch (error_code) {
2432   case MAILIMAP_RESP_COND_STATE_OK:
2433     return MAILIMAP_NO_ERROR;
2434 
2435   default:
2436     return MAILIMAP_ERROR_STARTTLS;
2437   }
2438 }
2439 
2440 
2441 
mailimap_read_line(mailimap * session)2442 char * mailimap_read_line(mailimap * session)
2443 {
2444   return mailstream_read_line(session->imap_stream, session->imap_stream_buffer);
2445 }
2446 
mailimap_send_current_tag(mailimap * session)2447 int mailimap_send_current_tag(mailimap * session)
2448 {
2449   char tag_str[15];
2450   int r;
2451 
2452   session->imap_tag ++;
2453 
2454   if(mailimap_is_163_workaround_enabled(session))
2455     snprintf(tag_str, 15, "C%i", session->imap_tag);
2456   else
2457     snprintf(tag_str, 15, "%i", session->imap_tag);
2458 
2459 
2460   r = mailimap_tag_send(session->imap_stream, tag_str);
2461   if (r != MAILIMAP_NO_ERROR)
2462     return r;
2463 
2464   r = mailimap_space_send(session->imap_stream);
2465   if (r != MAILIMAP_NO_ERROR)
2466     return r;
2467 
2468   return MAILIMAP_NO_ERROR;
2469 }
2470 
mailimap_parse_response(mailimap * session,struct mailimap_response ** result)2471 int mailimap_parse_response(mailimap * session,
2472     struct mailimap_response ** result)
2473 {
2474   size_t indx;
2475   struct mailimap_response * response;
2476   struct mailimap_parser_context * parser_ctx;
2477   char tag_str[15];
2478   int r;
2479 
2480   indx = 0;
2481 
2482   session->imap_response = NULL;
2483 
2484   if (session->imap_stream_buffer->allocated_len > 128 * 1024) {
2485 		MMAPString * buffer;
2486 
2487 		buffer = mmap_string_new_len(session->imap_stream_buffer->str, session->imap_stream_buffer->len);
2488 		mmap_string_free(session->imap_stream_buffer);
2489 		session->imap_stream_buffer = buffer;
2490   }
2491 
2492   parser_ctx = mailimap_parser_context_new(session);
2493   if (parser_ctx == NULL)
2494     return MAILIMAP_ERROR_MEMORY;
2495 
2496   if ((session->imap_body_progress_fun != NULL) ||
2497       (session->imap_items_progress_fun != NULL)) {
2498     r = mailimap_response_parse_with_context(session->imap_stream,
2499                                              session->imap_stream_buffer,
2500                                              parser_ctx,
2501                                              &indx, &response,
2502                                              session->imap_body_progress_fun,
2503                                              session->imap_items_progress_fun,
2504                                              session->imap_progress_context,
2505                                              session->imap_msg_att_handler,
2506                                              session->imap_msg_att_handler_context);
2507   }
2508   else {
2509     r = mailimap_response_parse(session->imap_stream,
2510                                 session->imap_stream_buffer,
2511                                 parser_ctx,
2512                                 &indx, &response,
2513                                 session->imap_progr_rate, session->imap_progr_fun);
2514   }
2515 
2516   mailimap_parser_context_free(parser_ctx);
2517 
2518   if (r != MAILIMAP_NO_ERROR)
2519     return r;
2520 
2521 #if 0
2522   mailimap_response_print(response);
2523 #endif
2524 
2525   response_store(session, response);
2526 
2527   if (response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_text->rsp_text != NULL) {
2528     if (mmap_string_assign(session->imap_response_buffer,
2529             response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_text->rsp_text)
2530         == NULL) {
2531       mailimap_response_free(response);
2532       return MAILIMAP_ERROR_MEMORY;
2533     }
2534   }
2535 
2536   session->imap_response = session->imap_response_buffer->str;
2537 
2538   if (response->rsp_resp_done->rsp_type == MAILIMAP_RESP_DONE_TYPE_FATAL) {
2539     mailimap_response_free(response);
2540     return MAILIMAP_ERROR_FATAL;
2541   }
2542 
2543   if(mailimap_is_163_workaround_enabled(session))
2544     snprintf(tag_str, 15, "C%i", session->imap_tag);
2545   else
2546     snprintf(tag_str, 15, "%i", session->imap_tag);
2547 
2548   if (strcmp(response->rsp_resp_done->rsp_data.rsp_tagged->rsp_tag, tag_str) != 0) {
2549     mailimap_response_free(response);
2550     return MAILIMAP_ERROR_PROTOCOL;
2551   }
2552 
2553   if (response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type ==
2554       MAILIMAP_RESP_COND_STATE_BAD) {
2555     mailimap_response_free(response);
2556     return MAILIMAP_ERROR_PROTOCOL;
2557   }
2558 
2559   * result = response;
2560 
2561   return MAILIMAP_NO_ERROR;
2562 }
2563 
2564 
parse_greeting(mailimap * session,struct mailimap_greeting ** result)2565 static int parse_greeting(mailimap * session,
2566 	 			struct mailimap_greeting ** result)
2567 {
2568   size_t indx;
2569   struct mailimap_greeting * greeting;
2570   int r;
2571 
2572   indx = 0;
2573 
2574   session->imap_response = NULL;
2575 
2576   r = mailimap_greeting_parse(session->imap_stream,
2577       session->imap_stream_buffer, NULL,
2578       &indx, &greeting, session->imap_progr_rate,
2579       session->imap_progr_fun);
2580   if (r != MAILIMAP_NO_ERROR)
2581     return r;
2582 
2583 #if 0
2584   mailimap_greeting_print(greeting);
2585 #endif
2586 
2587   greeting_store(session, greeting);
2588 
2589   if (greeting->gr_type == MAILIMAP_GREETING_RESP_COND_BYE) {
2590     if (greeting->gr_data.gr_bye->rsp_text->rsp_text != NULL) {
2591       if (mmap_string_assign(session->imap_response_buffer,
2592               greeting->gr_data.gr_bye->rsp_text->rsp_text) == NULL)
2593         return MAILIMAP_ERROR_MEMORY;
2594     }
2595 
2596     session->imap_response = session->imap_response_buffer->str;
2597 
2598     return MAILIMAP_ERROR_DONT_ACCEPT_CONNECTION;
2599   }
2600 
2601   if (greeting->gr_data.gr_auth->rsp_text->rsp_text != NULL) {
2602     if (mmap_string_assign(session->imap_response_buffer,
2603             greeting->gr_data.gr_auth->rsp_text->rsp_text) == NULL)
2604       return MAILIMAP_ERROR_MEMORY;
2605   }
2606 
2607   session->imap_response = session->imap_response_buffer->str;
2608 
2609   * result = greeting;
2610 
2611   return MAILIMAP_NO_ERROR;
2612 }
2613 
2614 
2615 LIBETPAN_EXPORT
mailimap_new(size_t imap_progr_rate,progress_function * imap_progr_fun)2616 mailimap * mailimap_new(size_t imap_progr_rate,
2617     progress_function * imap_progr_fun)
2618 {
2619   mailimap * f;
2620 
2621   f = malloc(sizeof(* f));
2622   if (f == NULL)
2623     goto err;
2624 
2625   f->imap_response = NULL;
2626 
2627   f->imap_stream = NULL;
2628 
2629   f->imap_progr_rate = imap_progr_rate;
2630   f->imap_progr_fun = imap_progr_fun;
2631 
2632   f->imap_stream_buffer = mmap_string_new("");
2633   if (f->imap_stream_buffer == NULL)
2634     goto free_f;
2635 
2636   f->imap_response_buffer = mmap_string_new("");
2637   if (f->imap_response_buffer == NULL)
2638     goto free_stream_buffer;
2639 
2640   f->imap_state = MAILIMAP_STATE_DISCONNECTED;
2641   f->imap_tag = 0;
2642 
2643   f->imap_selection_info = NULL;
2644   f->imap_response_info = NULL;
2645   f->imap_connection_info = NULL;
2646 
2647 #ifdef USE_SASL
2648   f->imap_sasl.sasl_conn = NULL;
2649 #endif
2650 
2651   f->imap_idle_timestamp = 0;
2652   f->imap_idle_maxdelay = 29 * 60; /* IMAP IDLE spec */
2653 
2654   f->imap_body_progress_fun = NULL;
2655   f->imap_items_progress_fun = NULL;
2656   f->imap_progress_context = NULL;
2657 
2658   f->imap_msg_att_handler = NULL;
2659   f->imap_msg_att_handler_context = NULL;
2660 
2661   f->imap_msg_body_handler = NULL;
2662   f->imap_msg_body_handler_context = NULL;
2663 
2664 	f->imap_timeout = 0;
2665 
2666   f->imap_logger = NULL;
2667   f->imap_logger_context = NULL;
2668   f->is_163_workaround_enabled = 0;
2669   f->is_rambler_workaround_enabled = 0;
2670   f->is_qip_workaround_enabled = 0;
2671   return f;
2672 
2673  free_stream_buffer:
2674   mmap_string_free(f->imap_stream_buffer);
2675  free_f:
2676   free(f);
2677  err:
2678   return NULL;
2679 }
2680 
2681 LIBETPAN_EXPORT
mailimap_free(mailimap * session)2682 void mailimap_free(mailimap * session)
2683 {
2684 #ifdef USE_SASL
2685   if (session->imap_sasl.sasl_conn != NULL) {
2686     sasl_dispose((sasl_conn_t **) &session->imap_sasl.sasl_conn);
2687     mailsasl_unref();
2688   }
2689 #endif
2690 
2691   if (session->imap_stream)
2692     mailimap_logout(session);
2693 
2694   mmap_string_free(session->imap_response_buffer);
2695   mmap_string_free(session->imap_stream_buffer);
2696 
2697   if (session->imap_response_info)
2698     mailimap_response_info_free(session->imap_response_info);
2699   if (session->imap_selection_info)
2700     mailimap_selection_info_free(session->imap_selection_info);
2701   if (session->imap_connection_info)
2702     mailimap_connection_info_free(session->imap_connection_info);
2703 
2704   free(session);
2705 }
2706 
2707 LIBETPAN_EXPORT
mailimap_set_timeout(mailimap * session,time_t timeout)2708 void mailimap_set_timeout(mailimap * session, time_t timeout)
2709 {
2710 	session->imap_timeout = timeout;
2711 }
2712 
2713 LIBETPAN_EXPORT
mailimap_get_timeout(mailimap * session)2714 time_t mailimap_get_timeout(mailimap * session)
2715 {
2716 	return session->imap_timeout;
2717 }
2718 
2719 LIBETPAN_EXPORT
mailimap_set_progress_callback(mailimap * session,mailprogress_function * body_progr_fun,mailprogress_function * items_progr_fun,void * context)2720 void mailimap_set_progress_callback(mailimap * session,
2721                                     mailprogress_function * body_progr_fun,
2722                                     mailprogress_function * items_progr_fun,
2723                                     void * context)
2724 {
2725   session->imap_body_progress_fun = body_progr_fun;
2726   session->imap_items_progress_fun = items_progr_fun;
2727   session->imap_progress_context = context;
2728 }
2729 
2730 LIBETPAN_EXPORT
mailimap_set_msg_att_handler(mailimap * session,mailimap_msg_att_handler * handler,void * context)2731 void mailimap_set_msg_att_handler(mailimap * session,
2732                                   mailimap_msg_att_handler * handler,
2733                                   void * context)
2734 {
2735   session->imap_msg_att_handler = handler;
2736   session->imap_msg_att_handler_context = context;
2737 }
2738 
2739 LIBETPAN_EXPORT
mailimap_set_msg_body_handler(mailimap * session,mailimap_msg_body_handler * handler,void * context)2740 void mailimap_set_msg_body_handler(mailimap * session,
2741                                    mailimap_msg_body_handler * handler,
2742                                    void * context)
2743 {
2744   session->imap_msg_body_handler = handler;
2745   session->imap_msg_body_handler_context = context;
2746 }
2747 
imap_logger(mailstream * s,int log_type,const char * str,size_t size,void * context)2748 static inline void imap_logger(mailstream * s, int log_type,
2749     const char * str, size_t size, void * context)
2750 {
2751   mailimap * session;
2752 
2753   session = context;
2754   if (session->imap_logger == NULL)
2755     return;
2756 
2757   session->imap_logger(session, log_type, str, size, session->imap_logger_context);
2758 }
2759 
2760 LIBETPAN_EXPORT
mailimap_set_logger(mailimap * session,void (* logger)(mailimap * session,int log_type,const char * str,size_t size,void * context),void * logger_context)2761 void mailimap_set_logger(mailimap * session, void (* logger)(mailimap * session, int log_type,
2762     const char * str, size_t size, void * context), void * logger_context)
2763 {
2764   session->imap_logger = logger;
2765   session->imap_logger_context = logger_context;
2766 }
2767 
2768 LIBETPAN_EXPORT
mailimap_set_163_workaround_enabled(mailimap * session,int enabled)2769 void mailimap_set_163_workaround_enabled(mailimap * session, int enabled) {
2770 	session->is_163_workaround_enabled = enabled;
2771 }
2772 
2773 LIBETPAN_EXPORT
mailimap_is_163_workaround_enabled(mailimap * session)2774 int mailimap_is_163_workaround_enabled(mailimap * session) {
2775 	return session->is_163_workaround_enabled;
2776 }
2777 
2778 LIBETPAN_EXPORT
mailimap_set_rambler_workaround_enabled(mailimap * session,int enabled)2779 void mailimap_set_rambler_workaround_enabled(mailimap * session, int enabled) {
2780   if (session)
2781     session->is_rambler_workaround_enabled = enabled;
2782 }
2783 
2784 LIBETPAN_EXPORT
mailimap_is_rambler_workaround_enabled(mailimap * session)2785 int mailimap_is_rambler_workaround_enabled(mailimap * session) {
2786   return session->is_rambler_workaround_enabled;
2787 }
2788 
2789 LIBETPAN_EXPORT
mailimap_set_qip_workaround_enabled(mailimap * session,int enabled)2790 void mailimap_set_qip_workaround_enabled(mailimap * session, int enabled) {
2791   if (session) {
2792     session->is_qip_workaround_enabled = enabled;
2793   }
2794 }
2795 
2796 LIBETPAN_EXPORT
mailimap_is_qip_workaround_enabled(mailimap * session)2797 int mailimap_is_qip_workaround_enabled(mailimap * session) {
2798   return session->is_qip_workaround_enabled;
2799 }
2800