summaryrefslogtreecommitdiffabout
path: root/libetpan/src/low-level/pop3/mailpop3.c
Unidiff
Diffstat (limited to 'libetpan/src/low-level/pop3/mailpop3.c') (more/less context) (ignore whitespace changes)
-rw-r--r--libetpan/src/low-level/pop3/mailpop3.c1230
1 files changed, 1230 insertions, 0 deletions
diff --git a/libetpan/src/low-level/pop3/mailpop3.c b/libetpan/src/low-level/pop3/mailpop3.c
new file mode 100644
index 0000000..6f77a3a
--- a/dev/null
+++ b/libetpan/src/low-level/pop3/mailpop3.c
@@ -0,0 +1,1230 @@
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$
34 */
35
36/*
37 POP3 Protocol
38
39 RFC 1734
40 RFC 1939
41 RFC 2449
42
43 */
44
45#include "mailpop3.h"
46#include <stdio.h>
47#include <string.h>
48#include "md5.h"
49#include "mail.h"
50#include <stdlib.h>
51
52
53
54
55enum {
56 POP3_STATE_DISCONNECTED,
57 POP3_STATE_AUTHORIZATION,
58 POP3_STATE_TRANSACTION
59};
60
61
62
63/*
64 mailpop3_msg_info structure
65*/
66
67static struct mailpop3_msg_info *
68mailpop3_msg_info_new(unsigned int index, uint32_t size, char * uidl)
69{
70 struct mailpop3_msg_info * msg;
71
72 msg = malloc(sizeof(* msg));
73 if (msg == NULL)
74 return NULL;
75 msg->msg_index = index;
76 msg->msg_size = size;
77 msg->msg_deleted = FALSE;
78 msg->msg_uidl = uidl;
79
80 return msg;
81}
82
83static void mailpop3_msg_info_free(struct mailpop3_msg_info * msg)
84{
85 if (msg->msg_uidl != NULL)
86 free(msg->msg_uidl);
87 free(msg);
88}
89
90static void mailpop3_msg_info_tab_free(carray * msg_tab)
91{
92 unsigned int i;
93
94 for(i = 0 ; i < carray_count(msg_tab) ; i++) {
95 struct mailpop3_msg_info * msg;
96
97 msg = carray_get(msg_tab, i);
98 mailpop3_msg_info_free(msg);
99 }
100 carray_free(msg_tab);
101}
102
103static void mailpop3_msg_info_tab_reset(carray * msg_tab)
104{
105 unsigned int i;
106
107 for(i = 0 ; i < carray_count(msg_tab) ; i++) {
108 struct mailpop3_msg_info * msg;
109 msg = carray_get(msg_tab, i);
110 msg->msg_deleted = FALSE;
111 }
112}
113
114static inline struct mailpop3_msg_info *
115mailpop3_msg_info_tab_find_msg(carray * msg_tab, unsigned int index)
116{
117 struct mailpop3_msg_info * msg;
118
119 if (index == 0)
120 return NULL;
121
122 if (index > carray_count(msg_tab))
123 return NULL;
124
125 msg = carray_get(msg_tab, index - 1);
126
127 return msg;
128}
129
130
131
132int mailpop3_get_msg_info(mailpop3 * f, unsigned int index,
133 struct mailpop3_msg_info ** result)
134{
135 carray * tab;
136 struct mailpop3_msg_info * info;
137
138 mailpop3_list(f, &tab);
139
140 if (tab == NULL)
141 return MAILPOP3_ERROR_BAD_STATE;
142
143 info = mailpop3_msg_info_tab_find_msg(tab, index);
144 if (info == NULL)
145 return MAILPOP3_ERROR_NO_SUCH_MESSAGE;
146
147 * result = info;
148
149 return MAILPOP3_NO_ERROR;
150}
151
152
153/*
154 mailpop3_capa
155*/
156
157struct mailpop3_capa * mailpop3_capa_new(char * name, clist * param)
158{
159 struct mailpop3_capa * capa;
160
161 capa = malloc(sizeof(* capa));
162 if (capa == NULL)
163 return NULL;
164 capa->cap_name = name;
165 capa->cap_param = param;
166
167 return capa;
168}
169
170
171void mailpop3_capa_free(struct mailpop3_capa * capa)
172{
173 clist_foreach(capa->cap_param, (clist_func) free, NULL);
174 clist_free(capa->cap_param);
175 free(capa->cap_name);
176 free(capa);
177}
178
179/*
180 mailpop3 structure
181*/
182
183mailpop3 * mailpop3_new(size_t progr_rate, progress_function * progr_fun)
184{
185 mailpop3 * f;
186
187 f = malloc(sizeof(* f));
188 if (f == NULL)
189 goto err;
190
191 f->pop3_timestamp = NULL;
192 f->pop3_response = NULL;
193
194 f->pop3_stream = NULL;
195
196 f->pop3_progr_rate = progr_rate;
197 f->pop3_progr_fun = progr_fun;
198
199 f->pop3_stream_buffer = mmap_string_new("");
200 if (f->pop3_stream_buffer == NULL)
201 goto free_f;
202
203 f->pop3_response_buffer = mmap_string_new("");
204 if (f->pop3_response_buffer == NULL)
205 goto free_stream_buffer;
206
207 f->pop3_msg_tab = NULL;
208 f->pop3_deleted_count = 0;
209 f->pop3_state = POP3_STATE_DISCONNECTED;
210
211 return f;
212
213 free_stream_buffer:
214 mmap_string_free(f->pop3_stream_buffer);
215 free_f:
216 free(f);
217 err:
218 return NULL;
219}
220
221
222
223void mailpop3_free(mailpop3 * f)
224{
225 if (f->pop3_stream)
226 mailpop3_quit(f);
227
228 mmap_string_free(f->pop3_response_buffer);
229 mmap_string_free(f->pop3_stream_buffer);
230
231 free(f);
232}
233
234
235
236
237
238
239
240
241
242
243
244/*
245 operations on mailpop3 structure
246*/
247
248#define RESPONSE_OK 0
249#define RESPONSE_ERR -1
250
251static int send_command(mailpop3 * f, char * command);
252
253static char * read_line(mailpop3 * f);
254
255static char * read_multiline(mailpop3 * f, size_t size,
256 MMAPString * multiline_buffer);
257
258static int parse_response(mailpop3 * f, char * response);
259
260
261/* get the timestamp in the connection response */
262
263#define TIMESTAMP_START '<'
264#define TIMESTAMP_END '>'
265
266static char * mailpop3_get_timestamp(char * response)
267{
268 char * begin_timestamp;
269 char * end_timestamp;
270 char * timestamp;
271 int len_timestamp;
272
273 if (response == NULL)
274 return NULL;
275
276 begin_timestamp = strchr(response, TIMESTAMP_START);
277
278 end_timestamp = NULL;
279 if (begin_timestamp != NULL) {
280 end_timestamp = strchr(begin_timestamp, TIMESTAMP_END);
281 if (end_timestamp == NULL)
282 begin_timestamp = NULL;
283 }
284
285 if (!begin_timestamp)
286 return NULL;
287
288 len_timestamp = end_timestamp - begin_timestamp + 1;
289
290 timestamp = malloc(len_timestamp + 1);
291 if (timestamp == NULL)
292 return NULL;
293 strncpy(timestamp, begin_timestamp, len_timestamp);
294 timestamp[len_timestamp] = '\0';
295
296 return timestamp;
297}
298
299/*
300 connect a stream to the mailpop3 structure
301*/
302
303int mailpop3_connect(mailpop3 * f, mailstream * s)
304{
305 char * response;
306 int r;
307 char * timestamp;
308
309 if (f->pop3_state != POP3_STATE_DISCONNECTED)
310 return MAILPOP3_ERROR_BAD_STATE;
311
312 f->pop3_stream = s;
313
314 response = read_line(f);
315
316 r = parse_response(f, response);
317 if (r != RESPONSE_OK)
318 return MAILPOP3_ERROR_UNAUTHORIZED;
319
320 f->pop3_state = POP3_STATE_AUTHORIZATION;
321
322 timestamp = mailpop3_get_timestamp(f->pop3_response);
323 if (timestamp != NULL)
324 f->pop3_timestamp = timestamp;
325
326 return MAILPOP3_NO_ERROR;
327}
328
329
330/*
331 disconnect from a pop3 server
332*/
333
334int mailpop3_quit(mailpop3 * f)
335{
336 char command[POP3_STRING_SIZE];
337 char * response;
338 int r;
339 int res;
340
341 if ((f->pop3_state != POP3_STATE_AUTHORIZATION)
342 && (f->pop3_state != POP3_STATE_TRANSACTION)) {
343 res = MAILPOP3_ERROR_BAD_STATE;
344 goto close;
345 }
346
347 snprintf(command, POP3_STRING_SIZE, "QUIT\r\n");
348 r = send_command(f, command);
349 if (r == -1) {
350 res = MAILPOP3_ERROR_STREAM;
351 goto close;
352 }
353
354 response = read_line(f);
355 if (response == NULL) {
356 res = MAILPOP3_ERROR_STREAM;
357 goto close;
358 }
359 parse_response(f, response);
360
361 res = MAILPOP3_NO_ERROR;
362
363 close:
364 mailstream_close(f->pop3_stream);
365
366 if (f->pop3_timestamp != NULL) {
367 free(f->pop3_timestamp);
368 f->pop3_timestamp = NULL;
369 }
370
371 f->pop3_stream = NULL;
372 if (f->pop3_msg_tab != NULL) {
373 mailpop3_msg_info_tab_free(f->pop3_msg_tab);
374 f->pop3_msg_tab = NULL;
375 }
376
377 f->pop3_state = POP3_STATE_DISCONNECTED;
378
379 return res;
380}
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413int mailpop3_apop(mailpop3 * f,
414 const char * user, const char * password)
415{
416 char command[POP3_STRING_SIZE];
417 MD5_CTX md5context;
418 unsigned char md5digest[16];
419 char md5string[33];
420 char * cmd_ptr;
421 int r;
422 int i;
423 char * response;
424
425 if (f->pop3_state != POP3_STATE_AUTHORIZATION)
426 return MAILPOP3_ERROR_BAD_STATE;
427
428 if (f->pop3_timestamp == NULL)
429 return MAILPOP3_ERROR_APOP_NOT_SUPPORTED;
430
431 /* calculate md5 sum */
432
433 MD5Init(&md5context);
434 MD5Update(&md5context, f->pop3_timestamp, strlen (f->pop3_timestamp));
435 MD5Update(&md5context, password, strlen (password));
436 MD5Final(md5digest, &md5context);
437
438 cmd_ptr = md5string;
439 for(i = 0 ; i < 16 ; i++, cmd_ptr += 2)
440 snprintf(cmd_ptr, 3, "%02x", md5digest[i]);
441 * cmd_ptr = 0;
442
443 /* send apop command */
444
445 snprintf(command, POP3_STRING_SIZE, "APOP %s %s\r\n", user, md5string);
446 r = send_command(f, command);
447 if (r == -1)
448 return MAILPOP3_ERROR_STREAM;
449
450 response = read_line(f);
451
452 if (response == NULL)
453 return MAILPOP3_ERROR_STREAM;
454 r = parse_response(f, response);
455 if (r != RESPONSE_OK)
456 return MAILPOP3_ERROR_DENIED;
457
458 f->pop3_state = POP3_STATE_TRANSACTION;
459
460 return MAILPOP3_NO_ERROR;
461}
462
463int mailpop3_user(mailpop3 * f, const char * user)
464{
465 char command[POP3_STRING_SIZE];
466 int r;
467 char * response;
468
469 if (f->pop3_state != POP3_STATE_AUTHORIZATION)
470 return MAILPOP3_ERROR_BAD_STATE;
471
472 /* send user command */
473
474 snprintf(command, POP3_STRING_SIZE, "USER %s\r\n", user);
475 r = send_command(f, command);
476 if (r == -1)
477 return MAILPOP3_ERROR_STREAM;
478
479 response = read_line(f);
480 if (response == NULL)
481 return MAILPOP3_ERROR_STREAM;
482 r = parse_response(f, response);
483
484 if (r != RESPONSE_OK)
485 return MAILPOP3_ERROR_BAD_USER;
486
487 return MAILPOP3_NO_ERROR;
488}
489
490int mailpop3_pass(mailpop3 * f, const char * password)
491{
492 char command[POP3_STRING_SIZE];
493 int r;
494 char * response;
495
496 if (f->pop3_state != POP3_STATE_AUTHORIZATION)
497 return MAILPOP3_ERROR_BAD_STATE;
498
499 /* send password command */
500
501 snprintf(command, POP3_STRING_SIZE, "PASS %s\r\n", password);
502 r = send_command(f, command);
503 if (r == -1)
504 return MAILPOP3_ERROR_STREAM;
505
506 response = read_line(f);
507 if (response == NULL)
508 return MAILPOP3_ERROR_STREAM;
509 r = parse_response(f, response);
510
511 if (r != RESPONSE_OK)
512 return MAILPOP3_ERROR_BAD_PASSWORD;
513
514 f->pop3_state = POP3_STATE_TRANSACTION;
515
516 return MAILPOP3_NO_ERROR;
517}
518
519static int read_list(mailpop3 * f, carray ** result);
520
521
522
523static int read_uidl(mailpop3 * f, carray * msg_tab);
524
525
526
527static int mailpop3_do_uidl(mailpop3 * f, carray * msg_tab)
528{
529 char command[POP3_STRING_SIZE];
530 int r;
531 char * response;
532
533 if (f->pop3_state != POP3_STATE_TRANSACTION)
534 return MAILPOP3_ERROR_BAD_STATE;
535
536 /* send list command */
537
538 snprintf(command, POP3_STRING_SIZE, "UIDL\r\n");
539 r = send_command(f, command);
540 if (r == -1)
541 return MAILPOP3_ERROR_STREAM;
542
543 response = read_line(f);
544 if (response == NULL)
545 return MAILPOP3_ERROR_STREAM;
546 r = parse_response(f, response);
547
548 if (r != RESPONSE_OK)
549 return MAILPOP3_ERROR_CANT_LIST;
550
551 r = read_uidl(f, msg_tab);
552 if (r != MAILPOP3_NO_ERROR)
553 return r;
554
555 return MAILPOP3_NO_ERROR;
556}
557
558
559
560static int mailpop3_do_list(mailpop3 * f)
561{
562 char command[POP3_STRING_SIZE];
563 int r;
564 carray * msg_tab;
565 char * response;
566
567 if (f->pop3_msg_tab != NULL) {
568 mailpop3_msg_info_tab_free(f->pop3_msg_tab);
569 f->pop3_msg_tab = NULL;
570 }
571
572 if (f->pop3_state != POP3_STATE_TRANSACTION)
573 return MAILPOP3_ERROR_BAD_STATE;
574
575 /* send list command */
576
577 snprintf(command, POP3_STRING_SIZE, "LIST\r\n");
578 r = send_command(f, command);
579 if (r == -1)
580 return MAILPOP3_ERROR_STREAM;
581
582 response = read_line(f);
583 if (response == NULL)
584 return MAILPOP3_ERROR_STREAM;
585 r = parse_response(f, response);
586
587 if (r != RESPONSE_OK)
588 return MAILPOP3_ERROR_CANT_LIST;
589
590 r = read_list(f, &msg_tab);
591 if (r != MAILPOP3_NO_ERROR)
592 return r;
593
594 f->pop3_msg_tab = msg_tab;
595 f->pop3_deleted_count = 0;
596
597 mailpop3_do_uidl(f, msg_tab);
598
599 return MAILPOP3_NO_ERROR;
600}
601
602
603
604static void mailpop3_list_if_needed(mailpop3 * f)
605{
606 if (f->pop3_msg_tab == NULL)
607 mailpop3_do_list(f);
608}
609
610/*
611 mailpop3_list
612*/
613
614void mailpop3_list(mailpop3 * f, carray ** result)
615{
616 mailpop3_list_if_needed(f);
617 * result = f->pop3_msg_tab;
618}
619
620static inline struct mailpop3_msg_info *
621find_msg(mailpop3 * f, unsigned int index)
622{
623 mailpop3_list_if_needed(f);
624
625 if (f->pop3_msg_tab == NULL)
626 return NULL;
627
628 return mailpop3_msg_info_tab_find_msg(f->pop3_msg_tab, index);
629}
630
631
632
633
634
635
636
637
638static void mailpop3_multiline_response_free(char * str)
639{
640 mmap_string_unref(str);
641}
642
643void mailpop3_top_free(char * str)
644{
645 mailpop3_multiline_response_free(str);
646}
647
648void mailpop3_retr_free(char * str)
649{
650 mailpop3_multiline_response_free(str);
651}
652
653/*
654 mailpop3_retr
655
656 message content in (* result) is still there until the
657 next retrieve or top operation on the mailpop3 structure
658*/
659
660static int
661mailpop3_get_content(mailpop3 * f, struct mailpop3_msg_info * msginfo,
662 char ** result, size_t * result_len)
663{
664 char * response;
665 char * result_multiline;
666 MMAPString * buffer;
667 int r;
668
669 response = read_line(f);
670 if (response == NULL)
671 return MAILPOP3_ERROR_STREAM;
672 r = parse_response(f, response);
673 if (r != RESPONSE_OK)
674 return MAILPOP3_ERROR_NO_SUCH_MESSAGE;
675
676 buffer = mmap_string_new("");
677 if (buffer == NULL)
678 return MAILPOP3_ERROR_MEMORY;
679
680 result_multiline = read_multiline(f, msginfo->msg_size, buffer);
681 if (result_multiline == NULL) {
682 mmap_string_free(buffer);
683 return MAILPOP3_ERROR_STREAM;
684 }
685 else {
686 r = mmap_string_ref(buffer);
687 if (r < 0) {
688 mmap_string_free(buffer);
689 return MAILPOP3_ERROR_MEMORY;
690 }
691
692 * result = result_multiline;
693 * result_len = buffer->len;
694 return MAILPOP3_NO_ERROR;
695 }
696}
697
698int mailpop3_retr(mailpop3 * f, unsigned int index, char ** result,
699 size_t * result_len)
700{
701 char command[POP3_STRING_SIZE];
702 struct mailpop3_msg_info * msginfo;
703 int r;
704
705 if (f->pop3_state != POP3_STATE_TRANSACTION)
706 return MAILPOP3_ERROR_BAD_STATE;
707
708 msginfo = find_msg(f, index);
709
710 if (msginfo == NULL) {
711 f->pop3_response = NULL;
712 return MAILPOP3_ERROR_NO_SUCH_MESSAGE;
713 }
714
715 snprintf(command, POP3_STRING_SIZE, "RETR %i\r\n", index);
716 r = send_command(f, command);
717 if (r == -1)
718 return MAILPOP3_ERROR_STREAM;
719
720 return mailpop3_get_content(f, msginfo, result, result_len);
721}
722
723int mailpop3_top(mailpop3 * f, unsigned int index,
724 unsigned int count, char ** result,
725 size_t * result_len)
726{
727 char command[POP3_STRING_SIZE];
728 struct mailpop3_msg_info * msginfo;
729 int r;
730
731 if (f->pop3_state != POP3_STATE_TRANSACTION)
732 return MAILPOP3_ERROR_BAD_STATE;
733
734 msginfo = find_msg(f, index);
735
736 if (msginfo == NULL) {
737 f->pop3_response = NULL;
738 return MAILPOP3_ERROR_NO_SUCH_MESSAGE;
739 }
740
741 snprintf(command, POP3_STRING_SIZE, "TOP %i %i\r\n", index, count);
742 r = send_command(f, command);
743 if (r == -1)
744 return MAILPOP3_ERROR_STREAM;
745
746 return mailpop3_get_content(f, msginfo, result, result_len);
747}
748
749int mailpop3_dele(mailpop3 * f, unsigned int index)
750{
751 char command[POP3_STRING_SIZE];
752 struct mailpop3_msg_info * msginfo;
753 char * response;
754 int r;
755
756 if (f->pop3_state != POP3_STATE_TRANSACTION)
757 return MAILPOP3_ERROR_BAD_STATE;
758
759 msginfo = find_msg(f, index);
760
761 if (msginfo == NULL) {
762 f->pop3_response = NULL;
763 return MAILPOP3_ERROR_NO_SUCH_MESSAGE;
764 }
765
766 snprintf(command, POP3_STRING_SIZE, "DELE %i\r\n", index);
767 r = send_command(f, command);
768 if (r == -1)
769 return MAILPOP3_ERROR_STREAM;
770
771 response = read_line(f);
772 if (response == NULL)
773 return MAILPOP3_ERROR_STREAM;
774 r = parse_response(f, response);
775 if (r != RESPONSE_OK)
776 return MAILPOP3_ERROR_NO_SUCH_MESSAGE;
777
778 msginfo->msg_deleted = TRUE;
779 f->pop3_deleted_count ++;
780
781 return MAILPOP3_NO_ERROR;
782}
783
784int mailpop3_noop(mailpop3 * f)
785{
786 char command[POP3_STRING_SIZE];
787 char * response;
788 int r;
789
790 if (f->pop3_state != POP3_STATE_TRANSACTION)
791 return MAILPOP3_ERROR_BAD_STATE;
792
793 snprintf(command, POP3_STRING_SIZE, "NOOP\r\n");
794 r = send_command(f, command);
795 if (r == -1)
796 return MAILPOP3_ERROR_STREAM;
797
798 response = read_line(f);
799 if (response == NULL)
800 return MAILPOP3_ERROR_STREAM;
801 parse_response(f, response);
802
803 return MAILPOP3_NO_ERROR;
804}
805
806int mailpop3_rset(mailpop3 * f)
807{
808 char command[POP3_STRING_SIZE];
809 char * response;
810 int r;
811
812 if (f->pop3_state != POP3_STATE_TRANSACTION)
813 return MAILPOP3_ERROR_BAD_STATE;
814
815 snprintf(command, POP3_STRING_SIZE, "RSET\r\n");
816 r = send_command(f, command);
817 if (r == -1)
818 return MAILPOP3_ERROR_STREAM;
819
820 response = read_line(f);
821 if (response == NULL)
822 return MAILPOP3_ERROR_STREAM;
823 parse_response(f, response);
824
825 if (f->pop3_msg_tab != NULL) {
826 mailpop3_msg_info_tab_reset(f->pop3_msg_tab);
827 f->pop3_deleted_count = 0;
828 }
829
830 return MAILPOP3_NO_ERROR;
831}
832
833
834
835static int read_capa_resp(mailpop3 * f, clist ** result);
836
837int mailpop3_capa(mailpop3 * f, clist ** result)
838{
839 clist * capa_list;
840 char command[POP3_STRING_SIZE];
841 int r;
842 char * response;
843
844 snprintf(command, POP3_STRING_SIZE, "CAPA\r\n");
845 r = send_command(f, command);
846 if (r == -1)
847 return MAILPOP3_ERROR_STREAM;
848
849 response = read_line(f);
850 if (response == NULL)
851 return MAILPOP3_ERROR_STREAM;
852 r = parse_response(f, response);
853
854 if (r != RESPONSE_OK)
855 return MAILPOP3_ERROR_CAPA_NOT_SUPPORTED;
856
857 r = read_capa_resp(f, &capa_list);
858 if (r != MAILPOP3_NO_ERROR)
859 return r;
860
861 * result = capa_list;
862
863 return MAILPOP3_NO_ERROR;
864}
865
866void mailpop3_capa_resp_free(clist * capa_list)
867{
868 clist_foreach(capa_list, (clist_func) mailpop3_capa_free, NULL);
869 clist_free(capa_list);
870}
871
872int mailpop3_stls(mailpop3 * f)
873{
874 char command[POP3_STRING_SIZE];
875 int r;
876 char * response;
877
878 snprintf(command, POP3_STRING_SIZE, "STLS\r\n");
879 r = send_command(f, command);
880 if (r == -1)
881 return MAILPOP3_ERROR_STREAM;
882
883 response = read_line(f);
884 if (response == NULL)
885 return MAILPOP3_ERROR_STREAM;
886 r = parse_response(f, response);
887
888 if (r != RESPONSE_OK)
889 return MAILPOP3_ERROR_STLS_NOT_SUPPORTED;
890
891 return MAILPOP3_NO_ERROR;
892}
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917#define RESP_OK_STR "+OK"
918#define RESP_ERR_STR "-ERR"
919
920
921static int parse_space(char ** line)
922{
923 char * p;
924
925 p = * line;
926
927 while ((* p == ' ') || (* p == '\t'))
928 p ++;
929
930 if (p != * line) {
931 * line = p;
932 return TRUE;
933 }
934 else
935 return FALSE;
936}
937
938static char * cut_token(char * line)
939{
940 char * p;
941 char * p_tab;
942 char * p_space;
943
944 p = line;
945
946 p_space = strchr(line, ' ');
947 p_tab = strchr(line, '\t');
948 if (p_tab == NULL)
949 p = p_space;
950 else if (p_space == NULL)
951 p = p_tab;
952 else {
953 if (p_tab < p_space)
954 p = p_tab;
955 else
956 p = p_space;
957 }
958 if (p == NULL)
959 return NULL;
960 * p = 0;
961 p ++;
962
963 return p;
964}
965
966
967static int parse_response(mailpop3 * f, char * response)
968{
969 char * msg;
970
971 if (response == NULL) {
972 f->pop3_response = NULL;
973 return RESPONSE_ERR;
974 }
975
976 if (strncmp(response, RESP_OK_STR, strlen(RESP_OK_STR)) == 0) {
977
978 if (response[strlen(RESP_OK_STR)] == ' ')
979 msg = response + strlen(RESP_OK_STR) + 1;
980 else
981 msg = response + strlen(RESP_OK_STR);
982
983 if (mmap_string_assign(f->pop3_response_buffer, msg))
984 f->pop3_response = f->pop3_response_buffer->str;
985 else
986 f->pop3_response = NULL;
987
988 return RESPONSE_OK;
989 }
990 else if (strncmp(response, RESP_ERR_STR, strlen(RESP_ERR_STR)) == 0) {
991
992 if (response[strlen(RESP_ERR_STR)] == ' ')
993 msg = response + strlen(RESP_ERR_STR) + 1;
994 else
995 msg = response + strlen(RESP_ERR_STR);
996
997 if (mmap_string_assign(f->pop3_response_buffer, msg))
998 f->pop3_response = f->pop3_response_buffer->str;
999 else
1000 f->pop3_response = NULL;
1001 }
1002
1003 f->pop3_response = NULL;
1004 return RESPONSE_ERR;
1005}
1006
1007
1008
1009
1010
1011
1012
1013static int read_list(mailpop3 * f, carray ** result)
1014{
1015 unsigned int index;
1016 uint32_t size;
1017 carray * msg_tab;
1018 struct mailpop3_msg_info * msg;
1019 char * line;
1020
1021 msg_tab = carray_new(128);
1022 if (msg_tab == NULL)
1023 goto err;
1024
1025 while (1) {
1026 line = read_line(f);
1027 if (line == NULL)
1028 goto free_list;
1029
1030 if (mailstream_is_end_multiline(line))
1031 break;
1032
1033 index = strtol(line, &line, 10);
1034
1035 if (!parse_space(&line))
1036 continue;
1037
1038 size = strtol(line, &line, 10);
1039
1040 msg = mailpop3_msg_info_new(index, size, NULL);
1041 if (msg == NULL)
1042 goto free_list;
1043
1044 if (carray_count(msg_tab) < index) {
1045 int r;
1046
1047 r = carray_set_size(msg_tab, index);
1048 if (r == -1)
1049 goto free_list;
1050 }
1051
1052 carray_set(msg_tab, index - 1, msg);
1053 }
1054
1055 * result = msg_tab;
1056
1057 return MAILPOP3_NO_ERROR;
1058
1059 free_list:
1060 mailpop3_msg_info_tab_free(msg_tab);
1061 err:
1062 return MAILPOP3_ERROR_STREAM;
1063}
1064
1065
1066
1067static int read_uidl(mailpop3 * f, carray * msg_tab)
1068{
1069 unsigned int index;
1070 struct mailpop3_msg_info * msg;
1071 char * line;
1072
1073 while (1) {
1074 char * uidl;
1075
1076 line = read_line(f);
1077 if (line == NULL)
1078 goto err;
1079
1080 if (mailstream_is_end_multiline(line))
1081 break;
1082
1083 index = strtol(line, &line, 10);
1084
1085 if (!parse_space(&line))
1086 continue;
1087
1088 uidl = strdup(line);
1089 if (uidl == NULL)
1090 continue;
1091
1092 if (index > carray_count(msg_tab)) {
1093 free(uidl);
1094 continue;
1095 }
1096
1097 msg = carray_get(msg_tab, index - 1);
1098 if (msg == NULL) {
1099 free(uidl);
1100 continue;
1101 }
1102
1103 msg->msg_uidl = uidl;
1104 }
1105
1106 return MAILPOP3_NO_ERROR;
1107
1108 err:
1109 return MAILPOP3_ERROR_STREAM;
1110}
1111
1112
1113
1114static int read_capa_resp(mailpop3 * f, clist ** result)
1115{
1116 char * line;
1117 int res;
1118 clist * list;
1119 int r;
1120 char * name;
1121 clist * param_list;
1122
1123 list = clist_new();
1124 if (list == NULL) {
1125 res = MAILPOP3_NO_ERROR;
1126 goto err;
1127 }
1128
1129 while (1) {
1130 char * next_token;
1131 char * param;
1132 struct mailpop3_capa * capa;
1133
1134 line = read_line(f);
1135 if (line == NULL) {
1136 res = MAILPOP3_ERROR_STREAM;
1137 goto free_list;
1138 }
1139
1140 if (mailstream_is_end_multiline(line))
1141 break;
1142
1143 next_token = cut_token(line);
1144 name = strdup(line);
1145 if (name == NULL) {
1146 res = MAILPOP3_ERROR_MEMORY;
1147 goto free_list;
1148 }
1149
1150 param_list = clist_new();
1151 if (param_list == NULL) {
1152 res = MAILPOP3_ERROR_MEMORY;
1153 goto free_capa_name;
1154 }
1155
1156 while (next_token != NULL) {
1157 line = next_token;
1158 next_token = cut_token(line);
1159 param = strdup(line);
1160 if (param == NULL) {
1161 res = MAILPOP3_ERROR_MEMORY;
1162 goto free_param_list;
1163 }
1164 r = clist_append(param_list, param);
1165 if (r < 0) {
1166 free(param);
1167 res = MAILPOP3_ERROR_MEMORY;
1168 goto free_param_list;
1169 }
1170 }
1171
1172 capa = mailpop3_capa_new(name, param_list);
1173 if (capa == NULL) {
1174 res = MAILPOP3_ERROR_MEMORY;
1175 goto free_param_list;
1176 }
1177
1178 r = clist_append(list, capa);
1179 if (r < 0) {
1180 mailpop3_capa_free(capa);
1181 res = MAILPOP3_ERROR_MEMORY;
1182 goto free_list;
1183 }
1184 }
1185
1186 * result = list;
1187
1188 return MAILPOP3_NO_ERROR;
1189
1190 free_param_list:
1191 clist_foreach(param_list, (clist_func) free, NULL);
1192 clist_free(param_list);
1193 free_capa_name:
1194 free(name);
1195 free_list:
1196 clist_foreach(list, (clist_func) mailpop3_capa_free, NULL);
1197 clist_free(list);
1198 err:
1199 return res;
1200}
1201
1202
1203
1204static char * read_line(mailpop3 * f)
1205{
1206 return mailstream_read_line_remove_eol(f->pop3_stream, f->pop3_stream_buffer);
1207}
1208
1209static char * read_multiline(mailpop3 * f, size_t size,
1210 MMAPString * multiline_buffer)
1211{
1212 return mailstream_read_multiline(f->pop3_stream, size,
1213 f->pop3_stream_buffer, multiline_buffer,
1214 f->pop3_progr_rate, f->pop3_progr_fun);
1215}
1216
1217static int send_command(mailpop3 * f, char * command)
1218{
1219 ssize_t r;
1220
1221 r = mailstream_write(f->pop3_stream, command, strlen(command));
1222 if (r == -1)
1223 return -1;
1224
1225 r = mailstream_flush(f->pop3_stream);
1226 if (r == -1)
1227 return -1;
1228
1229 return 0;
1230}