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: mailpop3.c,v 1.36 2011/03/11 21:49:36 hoa Exp $
34 */
35
36 /*
37 POP3 Protocol
38
39 RFC 1734
40 RFC 1939
41 RFC 2449
42
43 */
44
45 #ifdef HAVE_CONFIG_H
46 # include <config.h>
47 #endif
48
49 #include "mailpop3.h"
50 #include <stdio.h>
51 #include <string.h>
52 #include "md5.h"
53 #include "mail.h"
54 #include <stdlib.h>
55
56 #ifdef USE_SASL
57 #include <sasl/sasl.h>
58 #include <sasl/saslutil.h>
59 #endif
60
61 #include "mailsasl.h"
62 #include "mailpop3_types.h"
63
64
65
66
67 enum {
68 POP3_STATE_DISCONNECTED,
69 POP3_STATE_AUTHORIZATION,
70 POP3_STATE_TRANSACTION
71 };
72
73 static inline void pop3_logger(mailstream * s, int log_type,
74 const char * str, size_t size, void * context);
75
76
77 /*
78 mailpop3_msg_info structure
79 */
80
81 static struct mailpop3_msg_info *
mailpop3_msg_info_new(unsigned int indx,uint32_t size,char * uidl)82 mailpop3_msg_info_new(unsigned int indx, uint32_t size, char * uidl)
83 {
84 struct mailpop3_msg_info * msg;
85
86 msg = malloc(sizeof(* msg));
87 if (msg == NULL)
88 return NULL;
89 msg->msg_index = indx;
90 msg->msg_size = size;
91 msg->msg_deleted = FALSE;
92 msg->msg_uidl = uidl;
93
94 return msg;
95 }
96
mailpop3_msg_info_free(struct mailpop3_msg_info * msg)97 static void mailpop3_msg_info_free(struct mailpop3_msg_info * msg)
98 {
99 if (msg->msg_uidl != NULL)
100 free(msg->msg_uidl);
101 free(msg);
102 }
103
mailpop3_msg_info_tab_free(carray * msg_tab)104 static void mailpop3_msg_info_tab_free(carray * msg_tab)
105 {
106 unsigned int i;
107
108 for(i = 0 ; i < carray_count(msg_tab) ; i++) {
109 struct mailpop3_msg_info * msg;
110
111 msg = carray_get(msg_tab, i);
112 mailpop3_msg_info_free(msg);
113 }
114 carray_free(msg_tab);
115 }
116
mailpop3_msg_info_tab_reset(carray * msg_tab)117 static void mailpop3_msg_info_tab_reset(carray * msg_tab)
118 {
119 unsigned int i;
120
121 for(i = 0 ; i < carray_count(msg_tab) ; i++) {
122 struct mailpop3_msg_info * msg;
123 msg = carray_get(msg_tab, i);
124 msg->msg_deleted = FALSE;
125 }
126 }
127
128 static inline struct mailpop3_msg_info *
mailpop3_msg_info_tab_find_msg(carray * msg_tab,unsigned int indx)129 mailpop3_msg_info_tab_find_msg(carray * msg_tab, unsigned int indx)
130 {
131 struct mailpop3_msg_info * msg;
132
133 if (indx == 0)
134 return NULL;
135
136 if (indx > carray_count(msg_tab))
137 return NULL;
138
139 msg = carray_get(msg_tab, indx - 1);
140
141 return msg;
142 }
143
144
145
mailpop3_get_msg_info(mailpop3 * f,unsigned int indx,struct mailpop3_msg_info ** result)146 int mailpop3_get_msg_info(mailpop3 * f, unsigned int indx,
147 struct mailpop3_msg_info ** result)
148 {
149 carray * tab;
150 struct mailpop3_msg_info * info;
151 int r;
152
153 r = mailpop3_list(f, &tab);
154 if (r != MAILPOP3_NO_ERROR)
155 return r;
156
157 if (tab == NULL)
158 return MAILPOP3_ERROR_BAD_STATE;
159
160 info = mailpop3_msg_info_tab_find_msg(tab, indx);
161 if (info == NULL)
162 return MAILPOP3_ERROR_NO_SUCH_MESSAGE;
163
164 * result = info;
165
166 return MAILPOP3_NO_ERROR;
167 }
168
169
170 /*
171 mailpop3_capa
172 */
173
mailpop3_capa_new(char * name,clist * param)174 struct mailpop3_capa * mailpop3_capa_new(char * name, clist * param)
175 {
176 struct mailpop3_capa * capa;
177
178 capa = malloc(sizeof(* capa));
179 if (capa == NULL)
180 return NULL;
181 capa->cap_name = name;
182 capa->cap_param = param;
183
184 return capa;
185 }
186
187
188
mailpop3_capa_free(struct mailpop3_capa * capa)189 void mailpop3_capa_free(struct mailpop3_capa * capa)
190 {
191 clist_foreach(capa->cap_param, (clist_func) free, NULL);
192 clist_free(capa->cap_param);
193 free(capa->cap_name);
194 free(capa);
195 }
196
197
198 /*
199 mailpop3_stat_response
200 */
201
mailpop3_stat_response_new(uint32_t count,uint32_t size)202 struct mailpop3_stat_response * mailpop3_stat_response_new(uint32_t count, uint32_t size)
203 {
204 struct mailpop3_stat_response * stat_response;
205
206 stat_response = malloc(sizeof(* stat_response));
207 if(stat_response == NULL)
208 return NULL;
209 stat_response->msgs_count = count;
210 stat_response->msgs_size = size;
211
212 return stat_response;
213 }
214
mailpop3_stat_resp_free(struct mailpop3_stat_response * stat_response)215 void mailpop3_stat_resp_free(struct mailpop3_stat_response * stat_response)
216 {
217 free(stat_response);
218 }
219
220 /*
221 mailpop3 structure
222 */
223
mailpop3_new(size_t progr_rate,progress_function * progr_fun)224 mailpop3 * mailpop3_new(size_t progr_rate, progress_function * progr_fun)
225 {
226 mailpop3 * f;
227
228 f = malloc(sizeof(* f));
229 if (f == NULL)
230 goto err;
231
232 f->pop3_timestamp = NULL;
233 f->pop3_response = NULL;
234
235 f->pop3_stream = NULL;
236
237 f->pop3_progr_rate = progr_rate;
238 f->pop3_progr_fun = progr_fun;
239
240 f->pop3_stream_buffer = mmap_string_new("");
241 if (f->pop3_stream_buffer == NULL)
242 goto free_f;
243
244 f->pop3_response_buffer = mmap_string_new("");
245 if (f->pop3_response_buffer == NULL)
246 goto free_stream_buffer;
247
248 f->pop3_msg_tab = NULL;
249 f->pop3_deleted_count = 0;
250 f->pop3_state = POP3_STATE_DISCONNECTED;
251
252 f->pop3_sasl.sasl_conn = NULL;
253
254 f->pop3_timeout = 0;
255 f->pop3_progress_fun = NULL;
256 f->pop3_progress_context = NULL;
257
258 f->pop3_logger = NULL;
259 f->pop3_logger_context = NULL;
260
261 return f;
262
263 free_stream_buffer:
264 mmap_string_free(f->pop3_stream_buffer);
265 free_f:
266 free(f);
267 err:
268 return NULL;
269 }
270
271
272
mailpop3_free(mailpop3 * f)273 void mailpop3_free(mailpop3 * f)
274 {
275 #ifdef USE_SASL
276 if (f->pop3_sasl.sasl_conn != NULL) {
277 sasl_dispose((sasl_conn_t **) &f->pop3_sasl.sasl_conn);
278 mailsasl_unref();
279 }
280 #endif
281
282 if (f->pop3_stream)
283 mailpop3_quit(f);
284
285 mmap_string_free(f->pop3_response_buffer);
286 mmap_string_free(f->pop3_stream_buffer);
287
288 free(f);
289 }
290
291
292
293
294
295
296
297
298
299
300
301 /*
302 operations on mailpop3 structure
303 */
304
305 #define RESPONSE_OK 0
306 #define RESPONSE_ERR -1
307 #define RESPONSE_AUTH_CONT 1
308
309 static int send_command(mailpop3 * f, char * command);
310 static int send_command_private(mailpop3 * f, char * command, int can_be_published);
311
312 static char * read_line(mailpop3 * f);
313
314 static char * read_multiline(mailpop3 * f, size_t size,
315 MMAPString * multiline_buffer);
316
317 static int parse_response(mailpop3 * f, char * response);
318
319
320 /* get the timestamp in the connection response */
321
322 #define TIMESTAMP_START '<'
323 #define TIMESTAMP_END '>'
324
mailpop3_get_timestamp(char * response)325 static char * mailpop3_get_timestamp(char * response)
326 {
327 char * begin_timestamp;
328 char * end_timestamp;
329 char * timestamp;
330 size_t len_timestamp;
331
332 if (response == NULL)
333 return NULL;
334
335 begin_timestamp = strchr(response, TIMESTAMP_START);
336
337 end_timestamp = NULL;
338 if (begin_timestamp != NULL) {
339 end_timestamp = strchr(begin_timestamp, TIMESTAMP_END);
340 if (end_timestamp == NULL)
341 begin_timestamp = NULL;
342 }
343
344 if (!begin_timestamp)
345 return NULL;
346
347 len_timestamp = end_timestamp - begin_timestamp + 1;
348
349 timestamp = malloc(len_timestamp + 1);
350 if (timestamp == NULL)
351 return NULL;
352 strncpy(timestamp, begin_timestamp, len_timestamp);
353 timestamp[len_timestamp] = '\0';
354
355 return timestamp;
356 }
357
358 /*
359 connect a stream to the mailpop3 structure
360 */
361
mailpop3_connect(mailpop3 * f,mailstream * s)362 int mailpop3_connect(mailpop3 * f, mailstream * s)
363 {
364 char * response;
365 int r;
366 char * timestamp;
367
368 if (f->pop3_state != POP3_STATE_DISCONNECTED)
369 return MAILPOP3_ERROR_BAD_STATE;
370
371 f->pop3_stream = s;
372 mailstream_set_logger(s, pop3_logger, f);
373
374 response = read_line(f);
375
376 r = parse_response(f, response);
377 if (r != RESPONSE_OK)
378 return MAILPOP3_ERROR_UNAUTHORIZED;
379
380 f->pop3_state = POP3_STATE_AUTHORIZATION;
381
382 timestamp = mailpop3_get_timestamp(f->pop3_response);
383 if (timestamp != NULL)
384 f->pop3_timestamp = timestamp;
385
386 return MAILPOP3_NO_ERROR;
387 }
388
389
390 /*
391 disconnect from a pop3 server
392 */
393
mailpop3_quit(mailpop3 * f)394 int mailpop3_quit(mailpop3 * f)
395 {
396 char command[POP3_STRING_SIZE];
397 char * response;
398 int r;
399 int res;
400
401 if ((f->pop3_state != POP3_STATE_AUTHORIZATION)
402 && (f->pop3_state != POP3_STATE_TRANSACTION)) {
403 res = MAILPOP3_ERROR_BAD_STATE;
404 goto close;
405 }
406
407 snprintf(command, POP3_STRING_SIZE, "QUIT\r\n");
408 r = send_command(f, command);
409 if (r == -1) {
410 res = MAILPOP3_ERROR_STREAM;
411 goto close;
412 }
413
414 response = read_line(f);
415 if (response == NULL) {
416 res = MAILPOP3_ERROR_STREAM;
417 goto close;
418 }
419 if (parse_response(f, response) == RESPONSE_OK) {
420 res = MAILPOP3_NO_ERROR;
421 }
422 else {
423 res = MAILPOP3_ERROR_QUIT_FAILED;
424 }
425
426 res = MAILPOP3_NO_ERROR;
427
428 close:
429 if (f->pop3_stream != NULL) {
430 mailstream_close(f->pop3_stream);
431 f->pop3_stream = NULL;
432 }
433
434 if (f->pop3_timestamp != NULL) {
435 free(f->pop3_timestamp);
436 f->pop3_timestamp = NULL;
437 }
438
439 if (f->pop3_msg_tab != NULL) {
440 mailpop3_msg_info_tab_free(f->pop3_msg_tab);
441 f->pop3_msg_tab = NULL;
442 }
443
444 f->pop3_state = POP3_STATE_DISCONNECTED;
445
446 return res;
447 }
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
mailpop3_apop(mailpop3 * f,const char * user,const char * password)480 int mailpop3_apop(mailpop3 * f,
481 const char * user, const char * password)
482 {
483 char command[POP3_STRING_SIZE];
484 MD5_CTX md5context;
485 unsigned char md5digest[16];
486 char md5string[33];
487 char * cmd_ptr;
488 int r;
489 int i;
490 char * response;
491
492 if (f->pop3_state != POP3_STATE_AUTHORIZATION)
493 return MAILPOP3_ERROR_BAD_STATE;
494
495 if (f->pop3_timestamp == NULL)
496 return MAILPOP3_ERROR_APOP_NOT_SUPPORTED;
497
498 /* calculate md5 sum */
499
500 MD5Init(&md5context);
501 MD5Update(&md5context, (const unsigned char *) f->pop3_timestamp, (unsigned int) strlen (f->pop3_timestamp));
502 MD5Update(&md5context, (const unsigned char *) password, (unsigned int) strlen (password));
503 MD5Final(md5digest, &md5context);
504
505 cmd_ptr = md5string;
506 for(i = 0 ; i < 16 ; i++, cmd_ptr += 2)
507 snprintf(cmd_ptr, 3, "%02x", md5digest[i]);
508 * cmd_ptr = 0;
509
510 /* send apop command */
511
512 snprintf(command, POP3_STRING_SIZE, "APOP %s %s\r\n", user, md5string);
513 r = send_command_private(f, command, 0);
514 if (r == -1)
515 return MAILPOP3_ERROR_STREAM;
516
517 response = read_line(f);
518
519 if (response == NULL)
520 return MAILPOP3_ERROR_STREAM;
521 r = parse_response(f, response);
522 if (r != RESPONSE_OK)
523 return MAILPOP3_ERROR_DENIED;
524
525 f->pop3_state = POP3_STATE_TRANSACTION;
526
527 return MAILPOP3_NO_ERROR;
528 }
529
mailpop3_user(mailpop3 * f,const char * user)530 int mailpop3_user(mailpop3 * f, const char * user)
531 {
532 char command[POP3_STRING_SIZE];
533 int r;
534 char * response;
535
536 if (f->pop3_state != POP3_STATE_AUTHORIZATION)
537 return MAILPOP3_ERROR_BAD_STATE;
538
539 /* send user command */
540
541 snprintf(command, POP3_STRING_SIZE, "USER %s\r\n", user);
542 r = send_command_private(f, command, 0);
543 if (r == -1)
544 return MAILPOP3_ERROR_STREAM;
545
546 response = read_line(f);
547 if (response == NULL)
548 return MAILPOP3_ERROR_STREAM;
549 r = parse_response(f, response);
550
551 if (r != RESPONSE_OK)
552 return MAILPOP3_ERROR_BAD_USER;
553
554 return MAILPOP3_NO_ERROR;
555 }
556
mailpop3_pass(mailpop3 * f,const char * password)557 int mailpop3_pass(mailpop3 * f, const char * password)
558 {
559 char command[POP3_STRING_SIZE];
560 int r;
561 char * response;
562
563 if (f->pop3_state != POP3_STATE_AUTHORIZATION)
564 return MAILPOP3_ERROR_BAD_STATE;
565
566 /* send password command */
567
568 snprintf(command, POP3_STRING_SIZE, "PASS %s\r\n", password);
569 r = send_command_private(f, command, 0);
570 if (r == -1)
571 return MAILPOP3_ERROR_STREAM;
572
573 response = read_line(f);
574 if (response == NULL)
575 return MAILPOP3_ERROR_STREAM;
576 r = parse_response(f, response);
577
578 if (r != RESPONSE_OK)
579 return MAILPOP3_ERROR_BAD_PASSWORD;
580
581 f->pop3_state = POP3_STATE_TRANSACTION;
582
583 return MAILPOP3_NO_ERROR;
584 }
585
586 static int read_list(mailpop3 * f, carray ** result);
587
588
589
590 static int read_uidl(mailpop3 * f, carray * msg_tab);
591
592
593
mailpop3_do_uidl(mailpop3 * f,carray * msg_tab)594 static int mailpop3_do_uidl(mailpop3 * f, carray * msg_tab)
595 {
596 char command[POP3_STRING_SIZE];
597 int r;
598 char * response;
599
600 if (f->pop3_state != POP3_STATE_TRANSACTION)
601 return MAILPOP3_ERROR_BAD_STATE;
602
603 /* send list command */
604
605 snprintf(command, POP3_STRING_SIZE, "UIDL\r\n");
606 r = send_command(f, command);
607 if (r == -1)
608 return MAILPOP3_ERROR_STREAM;
609
610 response = read_line(f);
611 if (response == NULL)
612 return MAILPOP3_ERROR_STREAM;
613 r = parse_response(f, response);
614
615 if (r != RESPONSE_OK)
616 return MAILPOP3_ERROR_CANT_LIST;
617
618 r = read_uidl(f, msg_tab);
619 if (r != MAILPOP3_NO_ERROR)
620 return r;
621
622 return MAILPOP3_NO_ERROR;
623 }
624
625
626
mailpop3_do_list(mailpop3 * f)627 static int mailpop3_do_list(mailpop3 * f)
628 {
629 char command[POP3_STRING_SIZE];
630 int r;
631 carray * msg_tab;
632 char * response;
633
634 if (f->pop3_msg_tab != NULL) {
635 mailpop3_msg_info_tab_free(f->pop3_msg_tab);
636 f->pop3_msg_tab = NULL;
637 }
638
639 if (f->pop3_state != POP3_STATE_TRANSACTION)
640 return MAILPOP3_ERROR_BAD_STATE;
641
642 /* send list command */
643
644 snprintf(command, POP3_STRING_SIZE, "LIST\r\n");
645 r = send_command(f, command);
646 if (r == -1)
647 return MAILPOP3_ERROR_STREAM;
648
649 response = read_line(f);
650 if (response == NULL)
651 return MAILPOP3_ERROR_STREAM;
652 r = parse_response(f, response);
653
654 if (r != RESPONSE_OK)
655 return MAILPOP3_ERROR_CANT_LIST;
656
657 r = read_list(f, &msg_tab);
658 if (r != MAILPOP3_NO_ERROR)
659 return r;
660
661 f->pop3_msg_tab = msg_tab;
662 f->pop3_deleted_count = 0;
663
664 mailpop3_do_uidl(f, msg_tab);
665
666 return MAILPOP3_NO_ERROR;
667 }
668
669
670
mailpop3_list_if_needed(mailpop3 * f)671 static int mailpop3_list_if_needed(mailpop3 * f)
672 {
673 if (f->pop3_msg_tab == NULL)
674 return mailpop3_do_list(f);
675 return MAILPOP3_NO_ERROR;
676 }
677
678 /*
679 mailpop3_list
680 */
681
mailpop3_list(mailpop3 * f,carray ** result)682 int mailpop3_list(mailpop3 * f, carray ** result)
683 {
684 int r;
685 r = mailpop3_list_if_needed(f);
686 if (r == MAILPOP3_NO_ERROR)
687 * result = f->pop3_msg_tab;
688 return r;
689 }
690
691 static inline struct mailpop3_msg_info *
find_msg(mailpop3 * f,unsigned int indx)692 find_msg(mailpop3 * f, unsigned int indx)
693 {
694 mailpop3_list_if_needed(f);
695
696 if (f->pop3_msg_tab == NULL)
697 return NULL;
698
699 return mailpop3_msg_info_tab_find_msg(f->pop3_msg_tab, indx);
700 }
701
702
703
704
705
706
707
708
mailpop3_multiline_response_free(char * str)709 static void mailpop3_multiline_response_free(char * str)
710 {
711 mmap_string_unref(str);
712 }
713
mailpop3_top_free(char * str)714 void mailpop3_top_free(char * str)
715 {
716 mailpop3_multiline_response_free(str);
717 }
718
mailpop3_retr_free(char * str)719 void mailpop3_retr_free(char * str)
720 {
721 mailpop3_multiline_response_free(str);
722 }
723
724 /*
725 mailpop3_retr
726
727 message content in (* result) is still there until the
728 next retrieve or top operation on the mailpop3 structure
729 */
730
731 static int
mailpop3_get_content(mailpop3 * f,struct mailpop3_msg_info * msginfo,char ** result,size_t * result_len)732 mailpop3_get_content(mailpop3 * f, struct mailpop3_msg_info * msginfo,
733 char ** result, size_t * result_len)
734 {
735 char * response;
736 char * result_multiline;
737 MMAPString * buffer;
738 int r;
739
740 response = read_line(f);
741 if (response == NULL)
742 return MAILPOP3_ERROR_STREAM;
743 r = parse_response(f, response);
744 if (r != RESPONSE_OK)
745 return MAILPOP3_ERROR_NO_SUCH_MESSAGE;
746
747 buffer = mmap_string_new("");
748 if (buffer == NULL)
749 return MAILPOP3_ERROR_MEMORY;
750
751 result_multiline = read_multiline(f, msginfo->msg_size, buffer);
752 if (result_multiline == NULL) {
753 mmap_string_free(buffer);
754 return MAILPOP3_ERROR_STREAM;
755 }
756 else {
757 r = mmap_string_ref(buffer);
758 if (r < 0) {
759 mmap_string_free(buffer);
760 return MAILPOP3_ERROR_MEMORY;
761 }
762
763 * result = result_multiline;
764 * result_len = buffer->len;
765 return MAILPOP3_NO_ERROR;
766 }
767 }
768
mailpop3_retr(mailpop3 * f,unsigned int indx,char ** result,size_t * result_len)769 int mailpop3_retr(mailpop3 * f, unsigned int indx, char ** result,
770 size_t * result_len)
771 {
772 char command[POP3_STRING_SIZE];
773 struct mailpop3_msg_info * msginfo;
774 int r;
775
776 if (f->pop3_state != POP3_STATE_TRANSACTION)
777 return MAILPOP3_ERROR_BAD_STATE;
778
779 msginfo = find_msg(f, indx);
780
781 if (msginfo == NULL) {
782 f->pop3_response = NULL;
783 return MAILPOP3_ERROR_NO_SUCH_MESSAGE;
784 }
785
786 snprintf(command, POP3_STRING_SIZE, "RETR %i\r\n", indx);
787 r = send_command(f, command);
788 if (r == -1)
789 return MAILPOP3_ERROR_STREAM;
790
791 return mailpop3_get_content(f, msginfo, result, result_len);
792 }
793
mailpop3_top(mailpop3 * f,unsigned int indx,unsigned int count,char ** result,size_t * result_len)794 int mailpop3_top(mailpop3 * f, unsigned int indx,
795 unsigned int count, char ** result,
796 size_t * result_len)
797 {
798 char command[POP3_STRING_SIZE];
799 struct mailpop3_msg_info * msginfo;
800 int r;
801
802 if (f->pop3_state != POP3_STATE_TRANSACTION)
803 return MAILPOP3_ERROR_BAD_STATE;
804
805 msginfo = find_msg(f, indx);
806
807 if (msginfo == NULL) {
808 f->pop3_response = NULL;
809 return MAILPOP3_ERROR_NO_SUCH_MESSAGE;
810 }
811
812 snprintf(command, POP3_STRING_SIZE, "TOP %i %i\r\n", indx, count);
813 r = send_command(f, command);
814 if (r == -1)
815 return MAILPOP3_ERROR_STREAM;
816
817 return mailpop3_get_content(f, msginfo, result, result_len);
818 }
819
mailpop3_dele(mailpop3 * f,unsigned int indx)820 int mailpop3_dele(mailpop3 * f, unsigned int indx)
821 {
822 char command[POP3_STRING_SIZE];
823 struct mailpop3_msg_info * msginfo;
824 char * response;
825 int r;
826
827 if (f->pop3_state != POP3_STATE_TRANSACTION)
828 return MAILPOP3_ERROR_BAD_STATE;
829
830 msginfo = find_msg(f, indx);
831
832 if (msginfo == NULL) {
833 f->pop3_response = NULL;
834 return MAILPOP3_ERROR_NO_SUCH_MESSAGE;
835 }
836
837 snprintf(command, POP3_STRING_SIZE, "DELE %i\r\n", indx);
838 r = send_command(f, command);
839 if (r == -1)
840 return MAILPOP3_ERROR_STREAM;
841
842 response = read_line(f);
843 if (response == NULL)
844 return MAILPOP3_ERROR_STREAM;
845 r = parse_response(f, response);
846 if (r != RESPONSE_OK)
847 return MAILPOP3_ERROR_NO_SUCH_MESSAGE;
848
849 msginfo->msg_deleted = TRUE;
850 f->pop3_deleted_count ++;
851
852 return MAILPOP3_NO_ERROR;
853 }
854
mailpop3_noop(mailpop3 * f)855 int mailpop3_noop(mailpop3 * f)
856 {
857 char command[POP3_STRING_SIZE];
858 char * response;
859 int r;
860
861 if (f->pop3_state != POP3_STATE_TRANSACTION)
862 return MAILPOP3_ERROR_BAD_STATE;
863
864 snprintf(command, POP3_STRING_SIZE, "NOOP\r\n");
865 r = send_command(f, command);
866 if (r == -1)
867 return MAILPOP3_ERROR_STREAM;
868
869 response = read_line(f);
870 if (response == NULL)
871 return MAILPOP3_ERROR_STREAM;
872 parse_response(f, response);
873
874 return MAILPOP3_NO_ERROR;
875 }
876
mailpop3_rset(mailpop3 * f)877 int mailpop3_rset(mailpop3 * f)
878 {
879 char command[POP3_STRING_SIZE];
880 char * response;
881 int r;
882
883 if (f->pop3_state != POP3_STATE_TRANSACTION)
884 return MAILPOP3_ERROR_BAD_STATE;
885
886 snprintf(command, POP3_STRING_SIZE, "RSET\r\n");
887 r = send_command(f, command);
888 if (r == -1)
889 return MAILPOP3_ERROR_STREAM;
890
891 response = read_line(f);
892 if (response == NULL)
893 return MAILPOP3_ERROR_STREAM;
894 parse_response(f, response);
895
896 if (f->pop3_msg_tab != NULL) {
897 mailpop3_msg_info_tab_reset(f->pop3_msg_tab);
898 f->pop3_deleted_count = 0;
899 }
900
901 return MAILPOP3_NO_ERROR;
902 }
903
904
905
906 static int read_capa_resp(mailpop3 * f, clist ** result);
907
mailpop3_capa(mailpop3 * f,clist ** result)908 int mailpop3_capa(mailpop3 * f, clist ** result)
909 {
910 clist * capa_list;
911 char command[POP3_STRING_SIZE];
912 int r;
913 char * response;
914
915 snprintf(command, POP3_STRING_SIZE, "CAPA\r\n");
916 r = send_command(f, command);
917 if (r == -1)
918 return MAILPOP3_ERROR_STREAM;
919
920 response = read_line(f);
921 if (response == NULL)
922 return MAILPOP3_ERROR_STREAM;
923 r = parse_response(f, response);
924
925 if (r != RESPONSE_OK)
926 return MAILPOP3_ERROR_CAPA_NOT_SUPPORTED;
927
928 capa_list = NULL;
929 r = read_capa_resp(f, &capa_list);
930 if (r != MAILPOP3_NO_ERROR)
931 return r;
932
933 * result = capa_list;
934
935 return MAILPOP3_NO_ERROR;
936 }
937
mailpop3_capa_resp_free(clist * capa_list)938 void mailpop3_capa_resp_free(clist * capa_list)
939 {
940 clist_foreach(capa_list, (clist_func) mailpop3_capa_free, NULL);
941 clist_free(capa_list);
942 }
943
mailpop3_stls(mailpop3 * f)944 int mailpop3_stls(mailpop3 * f)
945 {
946 char command[POP3_STRING_SIZE];
947 int r;
948 char * response;
949
950 snprintf(command, POP3_STRING_SIZE, "STLS\r\n");
951 r = send_command(f, command);
952 if (r == -1)
953 return MAILPOP3_ERROR_STREAM;
954
955 response = read_line(f);
956 if (response == NULL)
957 return MAILPOP3_ERROR_STREAM;
958 r = parse_response(f, response);
959
960 if (r != RESPONSE_OK)
961 return MAILPOP3_ERROR_STLS_NOT_SUPPORTED;
962
963 return MAILPOP3_NO_ERROR;
964 }
965
966 static int parse_stat_response(mailpop3 * f, struct mailpop3_stat_response ** result);
967
mailpop3_stat(mailpop3 * f,struct mailpop3_stat_response ** result)968 int mailpop3_stat(mailpop3 * f, struct mailpop3_stat_response ** result)
969 {
970 struct mailpop3_stat_response * stat_response;
971 char command[POP3_STRING_SIZE];
972 int r;
973 char * response;
974
975 snprintf(command, POP3_STRING_SIZE, "STAT\r\n");
976 r = send_command(f, command);
977 if (r == -1)
978 return MAILPOP3_ERROR_STREAM;
979
980 response = read_line(f);
981 if (response == NULL)
982 return MAILPOP3_ERROR_STREAM;
983 r = parse_response(f, response);
984
985 if (r != RESPONSE_OK)
986 return MAILPOP3_ERROR_CAPA_NOT_SUPPORTED;
987
988 stat_response = NULL;
989 r = parse_stat_response(f, &stat_response);
990 if (r != MAILPOP3_NO_ERROR)
991 return r;
992
993 * result = stat_response;
994
995 return MAILPOP3_NO_ERROR;
996 }
997
998
999
1000 #define RESP_OK_STR "+OK"
1001 #define RESP_ERR_STR "-ERR"
1002 #define RESP_AUTH_CONT_STR "+"
1003
1004
parse_space(char ** line)1005 static int parse_space(char ** line)
1006 {
1007 char * p;
1008
1009 p = * line;
1010
1011 while ((* p == ' ') || (* p == '\t'))
1012 p ++;
1013
1014 if (p != * line) {
1015 * line = p;
1016 return TRUE;
1017 }
1018 else
1019 return FALSE;
1020 }
1021
cut_token(char * line)1022 static char * cut_token(char * line)
1023 {
1024 char * p;
1025 char * p_tab;
1026 char * p_space;
1027
1028 p = line;
1029
1030 p_space = strchr(line, ' ');
1031 p_tab = strchr(line, '\t');
1032 if (p_tab == NULL)
1033 p = p_space;
1034 else if (p_space == NULL)
1035 p = p_tab;
1036 else {
1037 if (p_tab < p_space)
1038 p = p_tab;
1039 else
1040 p = p_space;
1041 }
1042 if (p == NULL)
1043 return NULL;
1044 * p = 0;
1045 p ++;
1046
1047 return p;
1048 }
1049
1050
parse_response(mailpop3 * f,char * response)1051 static int parse_response(mailpop3 * f, char * response)
1052 {
1053 char * msg;
1054
1055 if (response == NULL) {
1056 f->pop3_response = NULL;
1057 return RESPONSE_ERR;
1058 }
1059
1060 if (strncmp(response, RESP_OK_STR, strlen(RESP_OK_STR)) == 0) {
1061
1062 if (response[strlen(RESP_OK_STR)] == ' ')
1063 msg = response + strlen(RESP_OK_STR) + 1;
1064 else
1065 msg = response + strlen(RESP_OK_STR);
1066
1067 if (mmap_string_assign(f->pop3_response_buffer, msg))
1068 f->pop3_response = f->pop3_response_buffer->str;
1069 else
1070 f->pop3_response = NULL;
1071
1072 return RESPONSE_OK;
1073 }
1074 else if (strncmp(response, RESP_ERR_STR, strlen(RESP_ERR_STR)) == 0) {
1075
1076 if (response[strlen(RESP_ERR_STR)] == ' ')
1077 msg = response + strlen(RESP_ERR_STR) + 1;
1078 else
1079 msg = response + strlen(RESP_ERR_STR);
1080
1081 if (mmap_string_assign(f->pop3_response_buffer, msg))
1082 f->pop3_response = f->pop3_response_buffer->str;
1083 else
1084 f->pop3_response = NULL;
1085
1086 return RESPONSE_ERR;
1087 }
1088
1089 f->pop3_response = NULL;
1090 return RESPONSE_ERR;
1091 }
1092
1093
1094
1095
1096
1097 #ifdef USE_SASL
parse_auth(mailpop3 * f,char * response)1098 static int parse_auth(mailpop3 * f, char * response)
1099 {
1100 char * msg;
1101
1102 if (response == NULL) {
1103 f->pop3_response = NULL;
1104 return RESPONSE_ERR;
1105 }
1106
1107 if ((strncmp(response, RESP_AUTH_CONT_STR, strlen(RESP_AUTH_CONT_STR)) == 0) &&
1108 (strncmp(response, RESP_OK_STR, strlen(RESP_OK_STR)) != 0)) {
1109
1110 if (response[strlen(RESP_AUTH_CONT_STR)] == ' ')
1111 msg = response + strlen(RESP_AUTH_CONT_STR) + 1;
1112 else
1113 msg = response + strlen(RESP_AUTH_CONT_STR);
1114
1115 if (mmap_string_assign(f->pop3_response_buffer, msg))
1116 f->pop3_response = f->pop3_response_buffer->str;
1117 else
1118 f->pop3_response = NULL;
1119
1120 return RESPONSE_AUTH_CONT;
1121 }
1122 else {
1123 return parse_response(f, response);
1124 }
1125 }
1126 #endif
1127
1128
read_list(mailpop3 * f,carray ** result)1129 static int read_list(mailpop3 * f, carray ** result)
1130 {
1131 unsigned int indx;
1132 uint32_t size;
1133 carray * msg_tab;
1134 struct mailpop3_msg_info * msg;
1135 char * line;
1136
1137 msg_tab = carray_new(128);
1138 if (msg_tab == NULL)
1139 goto err;
1140
1141 while (1) {
1142 line = read_line(f);
1143 if (line == NULL)
1144 goto free_list;
1145
1146 if (mailstream_is_end_multiline(line))
1147 break;
1148
1149 indx = (unsigned int) strtol(line, &line, 10);
1150
1151 if (!parse_space(&line))
1152 continue;
1153
1154 size = (uint32_t) strtol(line, &line, 10);
1155
1156 msg = mailpop3_msg_info_new(indx, size, NULL);
1157 if (msg == NULL)
1158 goto free_list;
1159
1160 if (carray_count(msg_tab) < indx) {
1161 int r;
1162
1163 r = carray_set_size(msg_tab, indx);
1164 if (r == -1) {
1165 mailpop3_msg_info_free(msg);
1166 goto free_list;
1167 }
1168 }
1169
1170 carray_set(msg_tab, indx - 1, msg);
1171 }
1172
1173 * result = msg_tab;
1174
1175 return MAILPOP3_NO_ERROR;
1176
1177 free_list:
1178 mailpop3_msg_info_tab_free(msg_tab);
1179 err:
1180 return MAILPOP3_ERROR_STREAM;
1181 }
1182
1183
1184
read_uidl(mailpop3 * f,carray * msg_tab)1185 static int read_uidl(mailpop3 * f, carray * msg_tab)
1186 {
1187 unsigned int indx;
1188 struct mailpop3_msg_info * msg;
1189 char * line;
1190
1191 while (1) {
1192 char * uidl;
1193
1194 line = read_line(f);
1195 if (line == NULL)
1196 goto err;
1197
1198 if (mailstream_is_end_multiline(line))
1199 break;
1200
1201 indx = (unsigned int) strtol(line, &line, 10);
1202
1203 if (!parse_space(&line))
1204 continue;
1205
1206 uidl = strdup(line);
1207 if (uidl == NULL)
1208 continue;
1209
1210 if (indx > carray_count(msg_tab)) {
1211 free(uidl);
1212 continue;
1213 }
1214
1215 msg = carray_get(msg_tab, indx - 1);
1216 if (msg == NULL) {
1217 free(uidl);
1218 continue;
1219 }
1220
1221 msg->msg_uidl = uidl;
1222 }
1223
1224 return MAILPOP3_NO_ERROR;
1225
1226 err:
1227 return MAILPOP3_ERROR_STREAM;
1228 }
1229
1230
1231
read_capa_resp(mailpop3 * f,clist ** result)1232 static int read_capa_resp(mailpop3 * f, clist ** result)
1233 {
1234 char * line;
1235 int res;
1236 clist * list;
1237 int r;
1238 char * name;
1239 clist * param_list;
1240
1241 list = clist_new();
1242 if (list == NULL) {
1243 res = MAILPOP3_NO_ERROR;
1244 goto err;
1245 }
1246
1247 while (1) {
1248 char * next_token;
1249 char * param;
1250 struct mailpop3_capa * capa;
1251
1252 line = read_line(f);
1253 if (line == NULL) {
1254 res = MAILPOP3_ERROR_STREAM;
1255 goto free_list;
1256 }
1257
1258 if (mailstream_is_end_multiline(line))
1259 break;
1260
1261 next_token = cut_token(line);
1262 name = strdup(line);
1263 if (name == NULL) {
1264 res = MAILPOP3_ERROR_MEMORY;
1265 goto free_list;
1266 }
1267
1268 param_list = clist_new();
1269 if (param_list == NULL) {
1270 res = MAILPOP3_ERROR_MEMORY;
1271 goto free_capa_name;
1272 }
1273
1274 while (next_token != NULL) {
1275 line = next_token;
1276 next_token = cut_token(line);
1277 param = strdup(line);
1278 if (param == NULL) {
1279 res = MAILPOP3_ERROR_MEMORY;
1280 goto free_param_list;
1281 }
1282 r = clist_append(param_list, param);
1283 if (r < 0) {
1284 free(param);
1285 res = MAILPOP3_ERROR_MEMORY;
1286 goto free_param_list;
1287 }
1288 }
1289
1290 capa = mailpop3_capa_new(name, param_list);
1291 if (capa == NULL) {
1292 res = MAILPOP3_ERROR_MEMORY;
1293 goto free_param_list;
1294 }
1295
1296 r = clist_append(list, capa);
1297 if (r < 0) {
1298 mailpop3_capa_free(capa);
1299 res = MAILPOP3_ERROR_MEMORY;
1300 goto free_list;
1301 }
1302 }
1303
1304 * result = list;
1305
1306 return MAILPOP3_NO_ERROR;
1307
1308 free_param_list:
1309 clist_foreach(param_list, (clist_func) free, NULL);
1310 clist_free(param_list);
1311 free_capa_name:
1312 free(name);
1313 free_list:
1314 clist_foreach(list, (clist_func) mailpop3_capa_free, NULL);
1315 clist_free(list);
1316 err:
1317 return res;
1318 }
1319
parse_stat_response(mailpop3 * f,struct mailpop3_stat_response ** result)1320 static int parse_stat_response(mailpop3 * f, struct mailpop3_stat_response ** result)
1321 {
1322 unsigned int count;
1323 uint32_t size;
1324 struct mailpop3_stat_response * resp;
1325 char * line;
1326
1327 line = f->pop3_response;
1328 if (line == NULL)
1329 goto err;
1330
1331 count = (unsigned int) strtol(line, &line, 10);
1332
1333 if (!parse_space(&line))
1334 goto err;
1335
1336 size = (uint32_t) strtol(line, &line, 10);
1337
1338 resp = mailpop3_stat_response_new(count, size);
1339 if(resp == NULL)
1340 return MAILPOP3_ERROR_MEMORY;
1341
1342 * result = resp;
1343
1344 return MAILPOP3_NO_ERROR;
1345
1346 err:
1347 return MAILPOP3_ERROR_STREAM;
1348 }
1349
1350
1351
read_line(mailpop3 * f)1352 static char * read_line(mailpop3 * f)
1353 {
1354 return mailstream_read_line_remove_eol(f->pop3_stream, f->pop3_stream_buffer);
1355 }
1356
read_multiline(mailpop3 * f,size_t size,MMAPString * multiline_buffer)1357 static char * read_multiline(mailpop3 * f, size_t size,
1358 MMAPString * multiline_buffer)
1359 {
1360 return mailstream_read_multiline(f->pop3_stream, size,
1361 f->pop3_stream_buffer, multiline_buffer,
1362 f->pop3_progr_rate, f->pop3_progr_fun, f->pop3_progress_fun, f->pop3_progress_context);
1363 }
1364
send_command(mailpop3 * f,char * command)1365 static int send_command(mailpop3 * f, char * command)
1366 {
1367 return send_command_private(f, command, 1);
1368 }
1369
send_command_private(mailpop3 * f,char * command,int can_be_published)1370 static int send_command_private(mailpop3 * f, char * command, int can_be_published)
1371 {
1372 ssize_t r;
1373
1374 mailstream_set_privacy(f->pop3_stream, can_be_published);
1375 r = mailstream_write(f->pop3_stream, command, strlen(command));
1376 if (r == -1)
1377 return -1;
1378
1379 r = mailstream_flush(f->pop3_stream);
1380 if (r == -1)
1381 return -1;
1382
1383 return 0;
1384 }
1385
1386
1387
1388 #ifdef USE_SASL
sasl_getsimple(void * context,int id,const char ** result,unsigned * len)1389 static int sasl_getsimple(void * context, int id,
1390 const char ** result, unsigned * len)
1391 {
1392 mailpop3 * session;
1393
1394 session = context;
1395
1396 switch (id) {
1397 case SASL_CB_USER:
1398 if (result != NULL)
1399 * result = session->pop3_sasl.sasl_login;
1400 if (len != NULL)
1401 * len = (unsigned) strlen(session->pop3_sasl.sasl_login);
1402 return SASL_OK;
1403
1404 case SASL_CB_AUTHNAME:
1405 if (result != NULL)
1406 * result = session->pop3_sasl.sasl_auth_name;
1407 if (len != NULL)
1408 * len = (unsigned) strlen(session->pop3_sasl.sasl_auth_name);
1409 return SASL_OK;
1410 }
1411
1412 return SASL_FAIL;
1413 }
1414
sasl_getsecret(sasl_conn_t * conn,void * context,int id,sasl_secret_t ** psecret)1415 static int sasl_getsecret(sasl_conn_t * conn, void * context, int id,
1416 sasl_secret_t ** psecret)
1417 {
1418 mailpop3 * session;
1419
1420 session = context;
1421
1422 switch (id) {
1423 case SASL_CB_PASS:
1424 if (psecret != NULL)
1425 * psecret = session->pop3_sasl.sasl_secret;
1426 return SASL_OK;
1427 }
1428
1429 return SASL_FAIL;
1430 }
1431
sasl_getrealm(void * context,int id,const char ** availrealms,const char ** result)1432 static int sasl_getrealm(void * context, int id,
1433 const char ** availrealms,
1434 const char ** result)
1435 {
1436 mailpop3 * session;
1437
1438 session = context;
1439
1440 switch (id) {
1441 case SASL_CB_GETREALM:
1442 if (result != NULL)
1443 * result = session->pop3_sasl.sasl_realm;
1444 return SASL_OK;
1445 }
1446
1447 return SASL_FAIL;
1448 }
1449 #endif
1450
mailpop3_auth(mailpop3 * f,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)1451 int mailpop3_auth(mailpop3 * f, const char * auth_type,
1452 const char * server_fqdn,
1453 const char * local_ip_port,
1454 const char * remote_ip_port,
1455 const char * login, const char * auth_name,
1456 const char * password, const char * realm)
1457 {
1458 #ifdef USE_SASL
1459 int r;
1460 char command[POP3_STRING_SIZE];
1461 sasl_callback_t sasl_callback[5];
1462 const char * sasl_out;
1463 unsigned sasl_out_len;
1464 const char * mechusing;
1465 sasl_secret_t * secret;
1466 int res;
1467 size_t len;
1468 char * encoded;
1469 unsigned int encoded_len;
1470 unsigned int max_encoded;
1471
1472 sasl_callback[0].id = SASL_CB_GETREALM;
1473 sasl_callback[0].proc = (int(*)(void)) sasl_getrealm;
1474 sasl_callback[0].context = f;
1475 sasl_callback[1].id = SASL_CB_USER;
1476 sasl_callback[1].proc = (int(*)(void)) sasl_getsimple;
1477 sasl_callback[1].context = f;
1478 sasl_callback[2].id = SASL_CB_AUTHNAME;
1479 sasl_callback[2].proc = (int(*)(void)) sasl_getsimple;
1480 sasl_callback[2].context = f;
1481 sasl_callback[3].id = SASL_CB_PASS;
1482 sasl_callback[3].proc = (int(*)(void)) sasl_getsecret;
1483 sasl_callback[3].context = f;
1484 sasl_callback[4].id = SASL_CB_LIST_END;
1485 sasl_callback[4].proc = NULL;
1486 sasl_callback[4].context = NULL;
1487
1488 len = strlen(password);
1489 secret = malloc(sizeof(* secret) + len);
1490 if (secret == NULL) {
1491 res = MAILPOP3_ERROR_MEMORY;
1492 goto err;
1493 }
1494 secret->len = len;
1495 memcpy(secret->data, password, len + 1);
1496
1497 f->pop3_sasl.sasl_server_fqdn = server_fqdn;
1498 f->pop3_sasl.sasl_login = login;
1499 f->pop3_sasl.sasl_auth_name = auth_name;
1500 f->pop3_sasl.sasl_password = password;
1501 f->pop3_sasl.sasl_realm = realm;
1502 f->pop3_sasl.sasl_secret = secret;
1503
1504 /* init SASL */
1505 if (f->pop3_sasl.sasl_conn != NULL) {
1506 sasl_dispose((sasl_conn_t **) &f->pop3_sasl.sasl_conn);
1507 f->pop3_sasl.sasl_conn = NULL;
1508 }
1509 else {
1510 mailsasl_ref();
1511 }
1512
1513 r = sasl_client_new("pop", server_fqdn,
1514 local_ip_port, remote_ip_port, sasl_callback, 0,
1515 (sasl_conn_t **) &f->pop3_sasl.sasl_conn);
1516 if (r != SASL_OK) {
1517 res = MAILPOP3_ERROR_BAD_USER;
1518 goto free_secret;
1519 }
1520
1521 r = sasl_client_start(f->pop3_sasl.sasl_conn,
1522 auth_type, NULL, &sasl_out, &sasl_out_len, &mechusing);
1523 if ((r != SASL_CONTINUE) && (r != SASL_OK)) {
1524 res = MAILPOP3_ERROR_BAD_USER;
1525 goto free_sasl_conn;
1526 }
1527
1528 snprintf(command, POP3_STRING_SIZE, "AUTH %s\r\n", auth_type);
1529
1530 r = send_command(f, command);
1531 if (r == -1) {
1532 res = MAILPOP3_ERROR_STREAM;
1533 goto free_sasl_conn;
1534 }
1535
1536 while (1) {
1537 char * response;
1538
1539 response = read_line(f);
1540
1541 r = parse_auth(f, response);
1542 switch (r) {
1543 case RESPONSE_OK:
1544 f->pop3_state = POP3_STATE_TRANSACTION;
1545 res = MAILPOP3_NO_ERROR;
1546 goto free_sasl_conn;
1547
1548 case RESPONSE_ERR:
1549 res = MAILPOP3_ERROR_BAD_USER;
1550 goto free_sasl_conn;
1551
1552 case RESPONSE_AUTH_CONT:
1553 {
1554 unsigned int response_len;
1555 char * decoded;
1556 unsigned int decoded_len;
1557 unsigned int max_decoded;
1558 int got_response;
1559
1560 got_response = 1;
1561 if (f->pop3_response == NULL) {
1562 // Make clang static analyzer happy.
1563 got_response = 0;
1564 }
1565 else if (* f->pop3_response == '\0')
1566 got_response = 0;
1567
1568 if (got_response) {
1569 char * p;
1570
1571 p = strchr(f->pop3_response, '\r');
1572 if (p != NULL) {
1573 * p = '\0';
1574 }
1575 p = strchr(f->pop3_response, '\n');
1576 if (p != NULL) {
1577 * p = '\0';
1578 }
1579 response_len = (unsigned int) strlen(f->pop3_response);
1580 max_decoded = response_len * 3 / 4;
1581 decoded = malloc(max_decoded + 1);
1582 if (decoded == NULL) {
1583 res = MAILPOP3_ERROR_MEMORY;
1584 goto free_sasl_conn;
1585 }
1586
1587 r = sasl_decode64(f->pop3_response, response_len,
1588 decoded, max_decoded + 1, &decoded_len);
1589
1590 if (r != SASL_OK) {
1591 free(decoded);
1592 res = MAILPOP3_ERROR_MEMORY;
1593 goto free_sasl_conn;
1594 }
1595
1596 r = sasl_client_step(f->pop3_sasl.sasl_conn,
1597 decoded, decoded_len, NULL, &sasl_out, &sasl_out_len);
1598
1599 free(decoded);
1600
1601 if ((r != SASL_CONTINUE) && (r != SASL_OK)) {
1602 res = MAILPOP3_ERROR_BAD_USER;
1603 goto free_sasl_conn;
1604 }
1605 }
1606
1607 max_encoded = ((sasl_out_len + 2) / 3) * 4;
1608 encoded = malloc(max_encoded + 1);
1609 if (encoded == NULL) {
1610 res = MAILPOP3_ERROR_MEMORY;
1611 goto free_sasl_conn;
1612 }
1613
1614 r = sasl_encode64(sasl_out, sasl_out_len,
1615 encoded, max_encoded + 1, &encoded_len);
1616 if (r != SASL_OK) {
1617 free(encoded);
1618 res = MAILPOP3_ERROR_MEMORY;
1619 goto free_sasl_conn;
1620 }
1621
1622 snprintf(command, POP3_STRING_SIZE, "%s\r\n", encoded);
1623 r = send_command(f, command);
1624
1625 free(encoded);
1626
1627 if (r == -1) {
1628 res = MAILPOP3_ERROR_STREAM;
1629 goto free_sasl_conn;
1630 }
1631 }
1632 break;
1633 }
1634 }
1635
1636 f->pop3_state = POP3_STATE_TRANSACTION;
1637 res = MAILPOP3_NO_ERROR;
1638
1639 free_sasl_conn:
1640 sasl_dispose((sasl_conn_t **) &f->pop3_sasl.sasl_conn);
1641 f->pop3_sasl.sasl_conn = NULL;
1642 mailsasl_unref();
1643 free_secret:
1644 free(f->pop3_sasl.sasl_secret);
1645 f->pop3_sasl.sasl_secret = NULL;
1646 err:
1647 return res;
1648 #else
1649 return MAILPOP3_ERROR_BAD_USER;
1650 #endif
1651 }
1652
mailpop3_set_timeout(mailpop3 * f,time_t timeout)1653 void mailpop3_set_timeout(mailpop3 * f, time_t timeout)
1654 {
1655 f->pop3_timeout = timeout;
1656 }
1657
mailpop3_get_timeout(mailpop3 * f)1658 time_t mailpop3_get_timeout(mailpop3 * f)
1659 {
1660 return f->pop3_timeout;
1661 }
1662
mailpop3_set_progress_callback(mailpop3 * f,mailprogress_function * progr_fun,void * context)1663 void mailpop3_set_progress_callback(mailpop3 * f, mailprogress_function * progr_fun, void * context)
1664 {
1665 f->pop3_progress_fun = progr_fun;
1666 f->pop3_progress_context = context;
1667 }
1668
pop3_logger(mailstream * s,int log_type,const char * str,size_t size,void * context)1669 static inline void pop3_logger(mailstream * s, int log_type,
1670 const char * str, size_t size, void * context)
1671 {
1672 mailpop3 * session;
1673
1674 session = context;
1675 if (session->pop3_logger == NULL)
1676 return;
1677
1678 session->pop3_logger(session, log_type, str, size, session->pop3_logger_context);
1679 }
1680
1681 LIBETPAN_EXPORT
mailpop3_set_logger(mailpop3 * session,void (* logger)(mailpop3 * session,int log_type,const char * str,size_t size,void * context),void * logger_context)1682 void mailpop3_set_logger(mailpop3 * session, void (* logger)(mailpop3 * session, int log_type,
1683 const char * str, size_t size, void * context), void * logger_context)
1684 {
1685 session->pop3_logger = logger;
1686 session->pop3_logger_context = logger_context;
1687 }
1688