Diffstat (limited to 'kmicromail/libetpan/pop3/mailpop3.c') (more/less context) (ignore whitespace changes)
-rw-r--r-- | kmicromail/libetpan/pop3/mailpop3.c | 1230 |
1 files changed, 1230 insertions, 0 deletions
diff --git a/kmicromail/libetpan/pop3/mailpop3.c b/kmicromail/libetpan/pop3/mailpop3.c new file mode 100644 index 0000000..28fafe9 --- a/dev/null +++ b/kmicromail/libetpan/pop3/mailpop3.c | |||
@@ -0,0 +1,1230 @@ | |||
1 | /* | ||
2 | * libEtPan! -- a mail stuff library | ||
3 | * | ||
4 | * Copyright (C) 2001, 2002 - 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 REGENTS 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 REGENTS 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 | |||
55 | enum { | ||
56 | POP3_STATE_DISCONNECTED, | ||
57 | POP3_STATE_AUTHORIZATION, | ||
58 | POP3_STATE_TRANSACTION | ||
59 | }; | ||
60 | |||
61 | |||
62 | |||
63 | /* | ||
64 | mailpop3_msg_info structure | ||
65 | */ | ||
66 | |||
67 | static struct mailpop3_msg_info * | ||
68 | mailpop3_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 | |||
83 | static 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 | |||
90 | static 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 | |||
103 | static 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 | |||
114 | static inline struct mailpop3_msg_info * | ||
115 | mailpop3_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 | |||
132 | int 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 | |||
157 | struct 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 | |||
171 | void 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 | |||
183 | mailpop3 * 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 | |||
223 | void 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 | |||
251 | static int send_command(mailpop3 * f, char * command); | ||
252 | |||
253 | static char * read_line(mailpop3 * f); | ||
254 | |||
255 | static char * read_multiline(mailpop3 * f, size_t size, | ||
256 | MMAPString * multiline_buffer); | ||
257 | |||
258 | static 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 | |||
266 | static 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 | |||
303 | int 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 | |||
334 | int 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 | |||
413 | int 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 | |||
463 | int 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 | |||
490 | int 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 | |||
519 | static int read_list(mailpop3 * f, carray ** result); | ||
520 | |||
521 | |||
522 | |||
523 | static int read_uidl(mailpop3 * f, carray * msg_tab); | ||
524 | |||
525 | |||
526 | |||
527 | static 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 | |||
560 | static 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 | |||
604 | static 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 | |||
614 | void mailpop3_list(mailpop3 * f, carray ** result) | ||
615 | { | ||
616 | mailpop3_list_if_needed(f); | ||
617 | * result = f->pop3_msg_tab; | ||
618 | } | ||
619 | |||
620 | static inline struct mailpop3_msg_info * | ||
621 | find_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 | |||
638 | static void mailpop3_multiline_response_free(char * str) | ||
639 | { | ||
640 | mmap_string_unref(str); | ||
641 | } | ||
642 | |||
643 | void mailpop3_top_free(char * str) | ||
644 | { | ||
645 | mailpop3_multiline_response_free(str); | ||
646 | } | ||
647 | |||
648 | void 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 | |||
660 | static int | ||
661 | mailpop3_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 | |||
698 | int 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 | |||
723 | int mailpop3_top(mailpop3 * f, unsigned int index, | ||
724 | uint32_t 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 | |||
749 | int 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 | |||
784 | int 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 | |||
806 | int 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 | |||
835 | static int read_capa_resp(mailpop3 * f, clist ** result); | ||
836 | |||
837 | int 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 | |||
866 | void 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 | |||
872 | int 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 | |||
921 | static 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 | |||
938 | static 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 | |||
967 | static 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 | |||
1013 | static 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 | |||
1067 | static 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 | |||
1114 | static 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 | |||
1204 | static char * read_line(mailpop3 * f) | ||
1205 | { | ||
1206 | return mailstream_read_line_remove_eol(f->pop3_stream, f->pop3_stream_buffer); | ||
1207 | } | ||
1208 | |||
1209 | static 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 | |||
1217 | static 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 | } | ||