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