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