Re-implement pop3 client functions.
* include/mailutils/filter.h (mu_filter_io) <eof>: New member. * mailbox/fltstream.c (init_iobuf): Initialize eof to 0. (filter_read): Break the loop if the decoder has set eof. * mailbox/xscript-stream.c (_xscript_ctl) <MU_IOCTL_SWAP_STREAM>: Handle a special case when the transport does not support stream swapping. * include/mailutils/pop3.h (mu_pop3_set_debug): Remove. (MU_POP3_TRACE_CLR, MU_POP3_TRACE_SET, MU_POP3_TRACE_QRY): New macros. (mu_pop3_trace): New proto. (mu_pop3_readline): Remove. (mu_pop3_getline): New proto. (mu_pop3_capa): Change signature. * include/mailutils/sys/pop3.h (mu_pop3_state): Remove the *_ACK states. (mu_pop3_work_buf): Remove. (MU_POP3_ACK, MU_POP3_TRACE): New defines. (_mu_pop3): Rewrite the structure. (mu_pop3_debug_cmd, mu_pop3_debug_ack): Remove functions. (MU_POP3_FISSET, MU_POP3_FSET, MU_POP3_FCLR): New macros. (_mu_pop3_trace_enable, _mu_pop3_trace_disable) (_mu_pop3_init): New protos. * include/mailutils/tls.h (mu_tls_stream_ctl_fn) (mu_tls_writeline_fn): Change typedefs. * libmu_auth/tls.c (mu_tls_begin): Update function calls accordingly. * libproto/pop/pop3_debug.c: Remove. * libproto/pop/pop3_trace.c: New function. * libproto/pop/Makefile.am (libmu_pop_la_SOURCES): Temporarly comment out folder.c, mbox.c and url.c. Remove pop3_debug.c. Add pop3_trace.c. * libproto/pop/pop3_capa.c: Rewrite. * libproto/pop/pop3_create.c: Rewrite. * libproto/pop/pop3_iterator.c: Rewrite. * libproto/pop/pop3_response.c: Rewrite. * libproto/pop/pop3_sendline.c: Rewrite. * libproto/pop/pop3_stls.c: Rewrite. * libproto/pop/pop3_stream.c: Rewrite. * libproto/pop/pop3_apop.c: Reflect changes to the pop3 framework. * libproto/pop/pop3_carrier.c: Likewise. * libproto/pop/pop3_connect.c: Likewise. * libproto/pop/pop3_dele.c: Likewise. * libproto/pop/pop3_destroy.c: Likewise. * libproto/pop/pop3_disconnect.c: Likewise. * libproto/pop/pop3_list.c: Likewise. * libproto/pop/pop3_lista.c: Likewise. * libproto/pop/pop3_noop.c: Likewise. * libproto/pop/pop3_pass.c: Likewise. * libproto/pop/pop3_quit.c: Likewise. * libproto/pop/pop3_retr.c: Likewise. * libproto/pop/pop3_readline.c: Likewise. * libproto/pop/pop3_rset.c: Likewise. * libproto/pop/pop3_stat.c: Likewise. * libproto/pop/pop3_top.c: Likewise. * libproto/pop/pop3_uidl.c: Likewise. * libproto/pop/pop3_uidla.c: Likewise. * libproto/pop/pop3_user.c: Likewise. * examples/pop3client.c: Implement the stls comand. (main) [WITH_TLS]: Call mu_init_tls_libs. (com_verbose): Redo verbose support. (com_capa): Implement "reread" option.
Showing
37 changed files
with
774 additions
and
734 deletions
... | @@ -48,6 +48,7 @@ | ... | @@ -48,6 +48,7 @@ |
48 | #include <mailutils/argcv.h> | 48 | #include <mailutils/argcv.h> |
49 | #include <mailutils/cctype.h> | 49 | #include <mailutils/cctype.h> |
50 | #include <mailutils/cstr.h> | 50 | #include <mailutils/cstr.h> |
51 | #include <mailutils/tls.h> | ||
51 | 52 | ||
52 | /* A structure which contains information on the commands this program | 53 | /* A structure which contains information on the commands this program |
53 | can understand. */ | 54 | can understand. */ |
... | @@ -80,6 +81,7 @@ int com_uidl (char *); | ... | @@ -80,6 +81,7 @@ int com_uidl (char *); |
80 | int com_user (char *); | 81 | int com_user (char *); |
81 | int com_verbose (char *); | 82 | int com_verbose (char *); |
82 | int com_prompt (char *); | 83 | int com_prompt (char *); |
84 | int com_stls (char *); | ||
83 | 85 | ||
84 | void initialize_readline (void); | 86 | void initialize_readline (void); |
85 | COMMAND *find_command (char *); | 87 | COMMAND *find_command (char *); |
... | @@ -106,6 +108,7 @@ COMMAND commands[] = { | ... | @@ -106,6 +108,7 @@ COMMAND commands[] = { |
106 | { "retr", com_retr, "Dowload message: RETR msgno" }, | 108 | { "retr", com_retr, "Dowload message: RETR msgno" }, |
107 | { "rset", com_rset, "Unmark all messages: RSET" }, | 109 | { "rset", com_rset, "Unmark all messages: RSET" }, |
108 | { "stat", com_stat, "Get the size and count of mailbox : STAT [msgno]" }, | 110 | { "stat", com_stat, "Get the size and count of mailbox : STAT [msgno]" }, |
111 | { "stls", com_stls, "Start TLS negotiation" }, | ||
109 | { "top", com_top, "Get the header of message: TOP msgno [lines]" }, | 112 | { "top", com_top, "Get the header of message: TOP msgno [lines]" }, |
110 | { "uidl", com_uidl, "Get the unique id of message: UIDL [msgno]" }, | 113 | { "uidl", com_uidl, "Get the unique id of message: UIDL [msgno]" }, |
111 | { "user", com_user, "send login: USER user" }, | 114 | { "user", com_user, "send login: USER user" }, |
... | @@ -310,7 +313,9 @@ main (int argc MU_ARG_UNUSED, char **argv) | ... | @@ -310,7 +313,9 @@ main (int argc MU_ARG_UNUSED, char **argv) |
310 | mu_set_program_name (argv[0]); | 313 | mu_set_program_name (argv[0]); |
311 | prompt = strdup (DEFAULT_PROMPT); | 314 | prompt = strdup (DEFAULT_PROMPT); |
312 | initialize_readline (); /* Bind our completer. */ | 315 | initialize_readline (); /* Bind our completer. */ |
313 | 316 | #ifdef WITH_TLS | |
317 | mu_init_tls_libs (); | ||
318 | #endif | ||
314 | /* Loop reading and executing lines until the user quits. */ | 319 | /* Loop reading and executing lines until the user quits. */ |
315 | while (!done) | 320 | while (!done) |
316 | { | 321 | { |
... | @@ -393,16 +398,9 @@ com_verbose (char *arg) | ... | @@ -393,16 +398,9 @@ com_verbose (char *arg) |
393 | if (pop3 != NULL) | 398 | if (pop3 != NULL) |
394 | { | 399 | { |
395 | if (verbose == 1) | 400 | if (verbose == 1) |
396 | { | 401 | mu_pop3_trace (pop3, MU_POP3_TRACE_SET); |
397 | mu_debug_t debug; | ||
398 | mu_debug_create (&debug, NULL); | ||
399 | mu_debug_set_level (debug, MU_DEBUG_LEVEL_UPTO (MU_DEBUG_PROT)); | ||
400 | status = mu_pop3_set_debug (pop3, debug); | ||
401 | } | ||
402 | else | 402 | else |
403 | { | 403 | mu_pop3_trace (pop3, MU_POP3_TRACE_CLR); |
404 | status = mu_pop3_set_debug (pop3, NULL); | ||
405 | } | ||
406 | } | 404 | } |
407 | return status; | 405 | return status; |
408 | } | 406 | } |
... | @@ -442,10 +440,24 @@ com_apop (char *arg) | ... | @@ -442,10 +440,24 @@ com_apop (char *arg) |
442 | } | 440 | } |
443 | 441 | ||
444 | int | 442 | int |
445 | com_capa (char *arg MU_ARG_UNUSED) | 443 | com_capa (char *arg) |
446 | { | 444 | { |
447 | mu_iterator_t iterator = NULL; | 445 | mu_iterator_t iterator = NULL; |
448 | int status = mu_pop3_capa (pop3, &iterator); | 446 | int status; |
447 | int reread = 0; | ||
448 | |||
449 | if (arg && *arg) | ||
450 | { | ||
451 | if (strcmp (arg, "reread") == 0) | ||
452 | reread = 1; | ||
453 | else | ||
454 | { | ||
455 | mu_error ("%s: unknown argument", "capa"); | ||
456 | return 0; | ||
457 | } | ||
458 | } | ||
459 | |||
460 | status = mu_pop3_capa (pop3, reread, &iterator); | ||
449 | 461 | ||
450 | if (status == 0) | 462 | if (status == 0) |
451 | { | 463 | { |
... | @@ -609,6 +621,12 @@ com_stat (char *arg MU_ARG_UNUSED) | ... | @@ -609,6 +621,12 @@ com_stat (char *arg MU_ARG_UNUSED) |
609 | } | 621 | } |
610 | 622 | ||
611 | int | 623 | int |
624 | com_stls (char *arg MU_ARG_UNUSED) | ||
625 | { | ||
626 | return mu_pop3_stls (pop3); | ||
627 | } | ||
628 | |||
629 | int | ||
612 | com_dele (char *arg) | 630 | com_dele (char *arg) |
613 | { | 631 | { |
614 | unsigned msgno; | 632 | unsigned msgno; |
... | @@ -799,8 +817,7 @@ com_connect (char *arg) | ... | @@ -799,8 +817,7 @@ com_connect (char *arg) |
799 | 817 | ||
800 | if (verbose) | 818 | if (verbose) |
801 | com_verbose ("on"); | 819 | com_verbose ("on"); |
802 | status = | 820 | status = mu_tcp_stream_create (&tcp, argv[0], n, MU_STREAM_READ); |
803 | mu_tcp_stream_create (&tcp, argv[0], n, MU_STREAM_READ); | ||
804 | if (status == 0) | 821 | if (status == 0) |
805 | { | 822 | { |
806 | mu_pop3_set_carrier (pop3, tcp); | 823 | mu_pop3_set_carrier (pop3, tcp); | ... | ... |
... | @@ -42,6 +42,7 @@ struct mu_filter_io | ... | @@ -42,6 +42,7 @@ struct mu_filter_io |
42 | char *output; | 42 | char *output; |
43 | size_t osize; | 43 | size_t osize; |
44 | int errcode; | 44 | int errcode; |
45 | int eof; | ||
45 | }; | 46 | }; |
46 | 47 | ||
47 | enum mu_filter_command | 48 | enum mu_filter_command |
... | @@ -57,7 +58,7 @@ enum mu_filter_result | ... | @@ -57,7 +58,7 @@ enum mu_filter_result |
57 | mu_filter_ok, | 58 | mu_filter_ok, |
58 | mu_filter_falure, | 59 | mu_filter_falure, |
59 | mu_filter_moreinput, | 60 | mu_filter_moreinput, |
60 | mu_filter_moreoutput, | 61 | mu_filter_moreoutput |
61 | }; | 62 | }; |
62 | 63 | ||
63 | typedef int (*mu_filter_new_data_t) (void **, int, void *); | 64 | typedef int (*mu_filter_new_data_t) (void **, int, void *); | ... | ... |
... | @@ -29,7 +29,7 @@ extern "C" { | ... | @@ -29,7 +29,7 @@ extern "C" { |
29 | #endif | 29 | #endif |
30 | 30 | ||
31 | struct _mu_pop3; | 31 | struct _mu_pop3; |
32 | typedef struct _mu_pop3* mu_pop3_t; | 32 | typedef struct _mu_pop3 *mu_pop3_t; |
33 | 33 | ||
34 | #define MU_POP3_DEFAULT_PORT 110 | 34 | #define MU_POP3_DEFAULT_PORT 110 |
35 | 35 | ||
... | @@ -45,23 +45,28 @@ extern int mu_pop3_disconnect (mu_pop3_t pop3); | ... | @@ -45,23 +45,28 @@ extern int mu_pop3_disconnect (mu_pop3_t pop3); |
45 | extern int mu_pop3_set_timeout (mu_pop3_t pop3, int timeout); | 45 | extern int mu_pop3_set_timeout (mu_pop3_t pop3, int timeout); |
46 | extern int mu_pop3_get_timeout (mu_pop3_t pop3, int *timeout); | 46 | extern int mu_pop3_get_timeout (mu_pop3_t pop3, int *timeout); |
47 | 47 | ||
48 | extern int mu_pop3_set_debug (mu_pop3_t pop3, mu_debug_t debug); | 48 | #define MU_POP3_TRACE_CLR 0 |
49 | #define MU_POP3_TRACE_SET 1 | ||
50 | #define MU_POP3_TRACE_QRY 2 | ||
51 | extern int mu_pop3_trace (mu_pop3_t pop3, int op); | ||
49 | 52 | ||
50 | extern int mu_pop3_apop (mu_pop3_t pop3, const char *name, const char *digest); | 53 | extern int mu_pop3_apop (mu_pop3_t pop3, const char *name, const char *digest); |
51 | 54 | ||
52 | extern int mu_pop3_stls (mu_pop3_t pop3); | 55 | extern int mu_pop3_stls (mu_pop3_t pop3); |
53 | 56 | ||
54 | /* It is the responsability of the caller to call mu_iterator_destroy() when done | 57 | /* It is the responsability of the caller to call mu_iterator_destroy() when |
55 | with the iterator. The items return by the iterator are of type "const char *", | 58 | done with the iterator. The items returned by the iterator are of type |
56 | no processing is done on the item except the removal of the trailing newline. */ | 59 | "const char *", no processing is done on the item except the removal of |
57 | extern int mu_pop3_capa (mu_pop3_t pop3, mu_iterator_t *iterator); | 60 | the trailing newline. */ |
61 | extern int mu_pop3_capa (mu_pop3_t pop3, int reread, | ||
62 | mu_iterator_t *piter); | ||
58 | 63 | ||
59 | extern int mu_pop3_dele (mu_pop3_t pop3, unsigned int mesgno); | 64 | extern int mu_pop3_dele (mu_pop3_t pop3, unsigned int mesgno); |
60 | 65 | ||
61 | extern int mu_pop3_list (mu_pop3_t pop3, unsigned int mesgno, size_t *mesg_octet); | 66 | extern int mu_pop3_list (mu_pop3_t pop3, unsigned int mesgno, size_t *mesg_octet); |
62 | 67 | ||
63 | /* An iterator is return with the multi-line answer. It is the responsability of | 68 | /* An iterator is return with the multi-line answer. It is the responsability |
64 | the caller to call mu_iterator_destroy() to dispose of the iterator. */ | 69 | of the caller to call mu_iterator_destroy() to dispose of the iterator. */ |
65 | extern int mu_pop3_list_all (mu_pop3_t pop3, mu_iterator_t *piterator); | 70 | extern int mu_pop3_list_all (mu_pop3_t pop3, mu_iterator_t *piterator); |
66 | 71 | ||
67 | extern int mu_pop3_noop (mu_pop3_t pop3); | 72 | extern int mu_pop3_noop (mu_pop3_t pop3); |
... | @@ -70,49 +75,44 @@ extern int mu_pop3_pass (mu_pop3_t pop3, const char *pass); | ... | @@ -70,49 +75,44 @@ extern int mu_pop3_pass (mu_pop3_t pop3, const char *pass); |
70 | 75 | ||
71 | extern int mu_pop3_quit (mu_pop3_t pop3); | 76 | extern int mu_pop3_quit (mu_pop3_t pop3); |
72 | 77 | ||
73 | /* A stream is return with the multi-line answer. It is the responsability of | 78 | /* A stream is returned with the multi-line answer. It is the responsability |
74 | the caller to call mu_stream_destroy() to dipose of the stream. */ | 79 | of the caller to call mu_stream_destroy() to dipose of the stream. */ |
75 | extern int mu_pop3_retr (mu_pop3_t pop3, unsigned int mesgno, mu_stream_t *pstream); | 80 | extern int mu_pop3_retr (mu_pop3_t pop3, unsigned int mesgno, |
81 | mu_stream_t *pstream); | ||
76 | 82 | ||
77 | extern int mu_pop3_rset (mu_pop3_t pop3); | 83 | extern int mu_pop3_rset (mu_pop3_t pop3); |
78 | 84 | ||
79 | extern int mu_pop3_stat (mu_pop3_t pop3, unsigned int *count, size_t *octets); | 85 | extern int mu_pop3_stat (mu_pop3_t pop3, unsigned int *count, |
80 | 86 | size_t *octets); | |
81 | /* A stream is return with the multi-line answer. It is the responsability of | 87 | |
82 | the caller to call mu_stream_destroy() to dipose of the stream. */ | 88 | /* A stream is returned with the multi-line answer. It is the responsability |
83 | extern int mu_pop3_top (mu_pop3_t pop3, unsigned int mesgno, unsigned int lines, mu_stream_t *pstream); | 89 | of the caller to call mu_stream_destroy() to dipose of the stream. */ |
84 | 90 | extern int mu_pop3_top (mu_pop3_t pop3, unsigned int mesgno, | |
85 | /* The uidl is malloc and return in puidl, it is the responsability of caller | 91 | unsigned int lines, mu_stream_t *pstream); |
86 | to free() the uild when done. */ | 92 | |
87 | extern int mu_pop3_uidl (mu_pop3_t pop3, unsigned int mesgno, char **puidl); | 93 | /* The uidl is malloc'ed and returned in puidl; it is the responsability of |
88 | /* An iterator is return with the multi-line answer. It is the responsability of | 94 | the caller to free() the uild when done. */ |
89 | the caller to call mu_iterator_destroy() to dispose of the iterator. */ | 95 | extern int mu_pop3_uidl (mu_pop3_t pop3, unsigned int mesgno, |
96 | char **puidl); | ||
97 | /* An iterator is returned with the multi-line answer. It is the | ||
98 | responsability of the caller to call mu_iterator_destroy() to dispose of | ||
99 | the iterator. */ | ||
90 | extern int mu_pop3_uidl_all (mu_pop3_t pop3, mu_iterator_t *piterator); | 100 | extern int mu_pop3_uidl_all (mu_pop3_t pop3, mu_iterator_t *piterator); |
91 | 101 | ||
92 | extern int mu_pop3_user (mu_pop3_t pop3, const char *user); | 102 | extern int mu_pop3_user (mu_pop3_t pop3, const char *user); |
93 | 103 | ||
94 | 104 | ||
95 | /* Reads the multi-line response of the server, nread will be 0 when the termination octets | ||
96 | are detected. Clients should not use this function unless they are sending direct command. */ | ||
97 | extern int mu_pop3_readline (mu_pop3_t pop3, char *buffer, size_t buflen, size_t *nread); | ||
98 | 105 | ||
99 | /* Returns the last command acknowledge. If the server supports RESP-CODE, the message | 106 | /* Returns the last command acknowledge. If the server supports RESP-CODE, |
100 | could be retrieve, but it is up the caller to do the parsing. */ | 107 | the message could be retrieved, but it is up to the caller to do the |
101 | extern int mu_pop3_response (mu_pop3_t pop3, char *buffer, size_t buflen, size_t *nread); | 108 | parsing. */ |
109 | extern int mu_pop3_response (mu_pop3_t pop3, size_t *nread); | ||
102 | 110 | ||
103 | /* pop3_writeline copies the line in the internal buffer, a mu_pop3_send() is | ||
104 | needed to do the actual transmission. */ | ||
105 | extern int mu_pop3_writeline (mu_pop3_t pop3, const char *format, ...) | 111 | extern int mu_pop3_writeline (mu_pop3_t pop3, const char *format, ...) |
106 | MU_PRINTFLIKE(2,3); | 112 | MU_PRINTFLIKE(2,3); |
107 | 113 | ||
108 | /* mu_pop3_sendline() is equivalent to: | ||
109 | mu_pop3_writeline (pop3, line); | ||
110 | mu_pop3_send (pop3); | ||
111 | */ | ||
112 | extern int mu_pop3_sendline (mu_pop3_t pop3, const char *line); | 114 | extern int mu_pop3_sendline (mu_pop3_t pop3, const char *line); |
113 | 115 | extern int mu_pop3_getline (mu_pop3_t pop3); | |
114 | /* Transmit via the carrier the internal buffer data. */ | ||
115 | extern int mu_pop3_send (mu_pop3_t pop3); | ||
116 | 116 | ||
117 | #ifdef __cplusplus | 117 | #ifdef __cplusplus |
118 | } | 118 | } | ... | ... |
... | @@ -37,65 +37,63 @@ enum mu_pop3_state | ... | @@ -37,65 +37,63 @@ enum mu_pop3_state |
37 | { | 37 | { |
38 | MU_POP3_NO_STATE, | 38 | MU_POP3_NO_STATE, |
39 | MU_POP3_CONNECT, MU_POP3_GREETINGS, | 39 | MU_POP3_CONNECT, MU_POP3_GREETINGS, |
40 | MU_POP3_APOP, MU_POP3_APOP_ACK, | 40 | MU_POP3_APOP, |
41 | MU_POP3_AUTH, MU_POP3_AUTH_ACK, | 41 | MU_POP3_AUTH, |
42 | MU_POP3_CAPA, MU_POP3_CAPA_ACK, MU_POP3_CAPA_RX, | 42 | MU_POP3_CAPA, MU_POP3_CAPA_RX, |
43 | MU_POP3_DELE, MU_POP3_DELE_ACK, | 43 | MU_POP3_DELE, |
44 | MU_POP3_LIST, MU_POP3_LIST_ACK, MU_POP3_LIST_RX, | 44 | MU_POP3_LIST, MU_POP3_LIST_RX, |
45 | MU_POP3_NOOP, MU_POP3_NOOP_ACK, | 45 | MU_POP3_NOOP, |
46 | MU_POP3_PASS, MU_POP3_PASS_ACK, | 46 | MU_POP3_PASS, |
47 | MU_POP3_QUIT, MU_POP3_QUIT_ACK, | 47 | MU_POP3_QUIT, |
48 | MU_POP3_RETR, MU_POP3_RETR_ACK, MU_POP3_RETR_RX, | 48 | MU_POP3_RETR, MU_POP3_RETR_RX, |
49 | MU_POP3_RSET, MU_POP3_RSET_ACK, | 49 | MU_POP3_RSET, |
50 | MU_POP3_STAT, MU_POP3_STAT_ACK, | 50 | MU_POP3_STAT, |
51 | MU_POP3_STLS, MU_POP3_STLS_ACK, MU_POP3_STLS_CONNECT, | 51 | MU_POP3_STLS, MU_POP3_STLS_CONNECT, |
52 | MU_POP3_TOP, MU_POP3_TOP_ACK, MU_POP3_TOP_RX, | 52 | MU_POP3_TOP, MU_POP3_TOP_RX, |
53 | MU_POP3_UIDL, MU_POP3_UIDL_ACK, MU_POP3_UIDL_RX, | 53 | MU_POP3_UIDL, MU_POP3_UIDL_RX, |
54 | MU_POP3_USER, MU_POP3_USER_ACK, | 54 | MU_POP3_USER, |
55 | MU_POP3_DONE, MU_POP3_UNKNOWN, MU_POP3_ERROR | 55 | MU_POP3_DONE, |
56 | MU_POP3_UNKNOWN, | ||
57 | MU_POP3_ERROR | ||
56 | }; | 58 | }; |
57 | 59 | ||
58 | /* Structure holding the data necessary to do proper buffering. */ | 60 | #define MU_POP3_ACK 0x01 |
59 | struct mu_pop3_work_buf | 61 | #define MU_POP3_TRACE 0x02 |
60 | { | ||
61 | char *buf; | ||
62 | char *ptr; | ||
63 | char *nl; | ||
64 | size_t len; | ||
65 | }; | ||
66 | 62 | ||
67 | /* Structure to hold things general to POP3 mailbox, like its state, etc ... */ | 63 | /* Structure to hold things general to POP3 mailbox, like its state, etc ... */ |
68 | struct _mu_pop3 | 64 | struct _mu_pop3 |
69 | { | 65 | { |
70 | /* Working I/O buffer. | 66 | int flags; |
71 | io.buf: Working io buffer | ||
72 | io.ptr: Points to the end of the buffer, the non consumed chars | ||
73 | io.nl: Points to the '\n' char in the string | ||
74 | io.len: Len of io_buf. */ | ||
75 | struct mu_pop3_work_buf io; | ||
76 | |||
77 | /* Holds the first line response of the last command, i.e the ACK: | ||
78 | ack.buf: Buffer for the ack | ||
79 | ack.ptr: Working pointer, indicate the start of the non consumed chars | ||
80 | ack.len: Size 512 according to RFC2449. */ | ||
81 | struct mu_pop3_work_buf ack; | ||
82 | int acknowledge; | ||
83 | 67 | ||
84 | char *timestamp; /* For apop, if supported. */ | 68 | /* Holds the first line response of the last command, i.e the ACK */ |
85 | unsigned timeout; /* Default is 10 minutes. */ | 69 | char *ackbuf; |
70 | size_t acksize; | ||
86 | 71 | ||
87 | mu_debug_t debug; /* debugging trace. */ | 72 | char *rdbuf; |
73 | size_t rdsize; | ||
88 | 74 | ||
89 | enum mu_pop3_state state; /* Indicate the state of the running command. */ | 75 | char *timestamp; /* For apop, if supported. */ |
76 | unsigned timeout; /* Default is 10 minutes. */ | ||
90 | 77 | ||
78 | enum mu_pop3_state state; /* Indicate the state of the running | ||
79 | command. */ | ||
80 | mu_list_t capa; /* Capabilities. */ | ||
91 | mu_stream_t carrier; /* TCP Connection. */ | 81 | mu_stream_t carrier; /* TCP Connection. */ |
92 | }; | 82 | }; |
93 | 83 | ||
94 | extern int mu_pop3_debug_cmd (mu_pop3_t); | 84 | #define MU_POP3_FSET(p,f) ((p)->flags |= (f)) |
95 | extern int mu_pop3_debug_ack (mu_pop3_t); | 85 | #define MU_POP3_FISSET(p,f) ((p)->flags & (f)) |
86 | #define MU_POP3_FCLR(p,f) ((p)->flags &= ~(f)) | ||
87 | |||
96 | extern int mu_pop3_iterator_create (mu_pop3_t pop3, mu_iterator_t *piterator); | 88 | extern int mu_pop3_iterator_create (mu_pop3_t pop3, mu_iterator_t *piterator); |
97 | extern int mu_pop3_stream_create (mu_pop3_t pop3, mu_stream_t *pstream); | 89 | extern int mu_pop3_stream_create (mu_pop3_t pop3, mu_stream_t *pstream); |
98 | extern int mu_pop3_carrier_is_ready (mu_stream_t carrier, int flag, int timeout); | 90 | extern int mu_pop3_carrier_is_ready (mu_stream_t carrier, int flag, |
91 | int timeout); | ||
92 | |||
93 | int _mu_pop3_trace_enable (mu_pop3_t pop3); | ||
94 | int _mu_pop3_trace_disable (mu_pop3_t pop3); | ||
95 | |||
96 | int _mu_pop3_init (mu_pop3_t pop3); | ||
99 | 97 | ||
100 | /* Check for non recoverable error. | 98 | /* Check for non recoverable error. |
101 | The error is consider not recoverable if not part of the signal set: | 99 | The error is consider not recoverable if not part of the signal set: |
... | @@ -104,48 +102,46 @@ extern int mu_pop3_carrier_is_ready (mu_stream_t carrier, int flag, int timeout | ... | @@ -104,48 +102,46 @@ extern int mu_pop3_carrier_is_ready (mu_stream_t carrier, int flag, int timeout |
104 | to the begining of the buffer and setting the state to error. | 102 | to the begining of the buffer and setting the state to error. |
105 | */ | 103 | */ |
106 | #define MU_POP3_CHECK_EAGAIN(pop3, status) \ | 104 | #define MU_POP3_CHECK_EAGAIN(pop3, status) \ |
107 | do \ | 105 | do \ |
108 | { \ | 106 | { \ |
109 | if (status != 0) \ | 107 | if (status != 0) \ |
110 | { \ | 108 | { \ |
111 | if (status != EAGAIN && status != EINPROGRESS && status != EINTR) \ | 109 | if (status != EAGAIN && status != EINPROGRESS && status != EINTR) \ |
112 | { \ | 110 | { \ |
113 | pop3->io.ptr = pop3->io.buf; \ | ||
114 | pop3->state = MU_POP3_ERROR; \ | 111 | pop3->state = MU_POP3_ERROR; \ |
115 | } \ | 112 | } \ |
116 | return status; \ | 113 | return status; \ |
117 | } \ | 114 | } \ |
118 | } \ | 115 | } \ |
119 | while (0) | 116 | while (0) |
120 | 117 | ||
121 | /* If error return. | 118 | /* If error return. |
122 | Check status an reset(see MU_POP2_CHECK_EAGAIN) the buffer. | 119 | Check status an reset(see MU_POP2_CHECK_EAGAIN) the buffer. |
123 | */ | 120 | */ |
124 | #define MU_POP3_CHECK_ERROR(pop3, status) \ | 121 | #define MU_POP3_CHECK_ERROR(pop3, status) \ |
125 | do \ | 122 | do \ |
126 | { \ | 123 | { \ |
127 | if (status != 0) \ | 124 | if (status != 0) \ |
128 | { \ | 125 | { \ |
129 | pop3->io.ptr = pop3->io.buf; \ | ||
130 | pop3->state = MU_POP3_ERROR; \ | 126 | pop3->state = MU_POP3_ERROR; \ |
131 | return status; \ | 127 | return status; \ |
132 | } \ | 128 | } \ |
133 | } \ | 129 | } \ |
134 | while (0) | 130 | while (0) |
135 | 131 | ||
136 | /* Check if we got "+OK". | 132 | /* Check if we got "+OK". |
137 | In POP3 protocol and ack of "+OK" means the command was successfull. | 133 | In POP3 protocol and ack of "+OK" means the command was successfull. |
138 | */ | 134 | */ |
139 | #define MU_POP3_CHECK_OK(pop3) \ | 135 | #define MU_POP3_CHECK_OK(pop3) \ |
140 | do \ | 136 | do \ |
141 | { \ | 137 | { \ |
142 | if (mu_c_strncasecmp (pop3->ack.buf, "+OK", 3) != 0) \ | 138 | if (mu_c_strncasecmp (pop3->ackbuf, "+OK", 3) != 0) \ |
143 | { \ | 139 | { \ |
144 | pop3->state = MU_POP3_NO_STATE; \ | 140 | pop3->state = MU_POP3_NO_STATE; \ |
145 | return EACCES; \ | 141 | return EACCES; \ |
146 | } \ | 142 | } \ |
147 | } \ | 143 | } \ |
148 | while (0) | 144 | while (0) |
149 | 145 | ||
150 | #ifdef __cplusplus | 146 | #ifdef __cplusplus |
151 | } | 147 | } | ... | ... |
... | @@ -47,10 +47,13 @@ extern int mu_check_tls_environment (void); | ... | @@ -47,10 +47,13 @@ extern int mu_check_tls_environment (void); |
47 | extern int mu_init_tls_libs (void); | 47 | extern int mu_init_tls_libs (void); |
48 | extern void mu_deinit_tls_libs (void); | 48 | extern void mu_deinit_tls_libs (void); |
49 | 49 | ||
50 | typedef int (*mu_tls_readline_fn) (void *iodata); | 50 | typedef int (*mu_tls_readline_fn) (void *iodata, int n); |
51 | typedef int (*mu_tls_writeline_fn) (void *iodata, char *buf); | 51 | typedef int (*mu_tls_writeline_fn) (void *iodata, char *buf); |
52 | typedef void (*mu_tls_stream_ctl_fn) (void *iodata, mu_stream_t *pold, | 52 | |
53 | mu_stream_t __new); | 53 | #define MU_TLS_SESS_GET_STREAMS 0 |
54 | #define MU_TLS_SESS_SET_STREAMS 1 | ||
55 | typedef int (*mu_tls_stream_ctl_fn) (void *iodata, int __op, | ||
56 | mu_stream_t *pstr); | ||
54 | 57 | ||
55 | extern int mu_tls_begin (void *iodata, mu_tls_readline_fn reader, | 58 | extern int mu_tls_begin (void *iodata, mu_tls_readline_fn reader, |
56 | mu_tls_writeline_fn writer, | 59 | mu_tls_writeline_fn writer, | ... | ... |
... | @@ -115,11 +115,23 @@ mu_check_tls_environment (void) | ... | @@ -115,11 +115,23 @@ mu_check_tls_environment (void) |
115 | 115 | ||
116 | int mu_tls_enable = 0; | 116 | int mu_tls_enable = 0; |
117 | 117 | ||
118 | #if 0 | ||
119 | void | ||
120 | _mu_gtls_logger(int level, const char *text) | ||
121 | { | ||
122 | mu_diag_output (MU_DIAG_DEBUG, "GnuTLS(%d): %s", level, text); | ||
123 | } | ||
124 | #endif | ||
125 | |||
118 | int | 126 | int |
119 | mu_init_tls_libs (void) | 127 | mu_init_tls_libs (void) |
120 | { | 128 | { |
121 | if (mu_tls_module_config.enable && !mu_tls_enable) | 129 | if (mu_tls_module_config.enable && !mu_tls_enable) |
122 | mu_tls_enable = !gnutls_global_init (); /* Returns 1 on success */ | 130 | mu_tls_enable = !gnutls_global_init (); /* Returns 1 on success */ |
131 | #if 0 | ||
132 | gnutls_global_set_log_function (_mu_gtls_logger); | ||
133 | gnutls_global_set_log_level (110); | ||
134 | #endif | ||
123 | return mu_tls_enable; | 135 | return mu_tls_enable; |
124 | } | 136 | } |
125 | 137 | ||
... | @@ -161,7 +173,7 @@ mu_tls_begin (void *iodata, | ... | @@ -161,7 +173,7 @@ mu_tls_begin (void *iodata, |
161 | { | 173 | { |
162 | int i = 0; | 174 | int i = 0; |
163 | int status; | 175 | int status; |
164 | mu_stream_t oldstr, newstr; | 176 | mu_stream_t streams[2], newstr; |
165 | 177 | ||
166 | if (keywords == NULL) | 178 | if (keywords == NULL) |
167 | return EINVAL; | 179 | return EINVAL; |
... | @@ -181,19 +193,23 @@ mu_tls_begin (void *iodata, | ... | @@ -181,19 +193,23 @@ mu_tls_begin (void *iodata, |
181 | return status; | 193 | return status; |
182 | } | 194 | } |
183 | 195 | ||
184 | status = reader (iodata); | 196 | status = reader (iodata, i); |
185 | if (status != 0) | 197 | if (status != 0) |
186 | { | 198 | { |
187 | mu_error ("mu_tls_begin: reader (0): %s", mu_strerror (status)); | 199 | mu_error ("mu_tls_begin: reader (0): %s", mu_strerror (status)); |
188 | return status; | 200 | return status; |
189 | } | 201 | } |
190 | 202 | ||
191 | stream_ctl (iodata, &oldstr, NULL); | 203 | status = stream_ctl (iodata, MU_TLS_SESS_GET_STREAMS, streams); |
192 | status = mu_tls_client_stream_create (&newstr, oldstr, oldstr, 0); | 204 | if (status) |
205 | return status; | ||
206 | status = mu_tls_client_stream_create (&newstr, | ||
207 | streams[0], streams[1], 0); | ||
193 | if (status != 0) | 208 | if (status != 0) |
194 | { | 209 | { |
195 | mu_error ("mu_tls_begin: mu_tls_client_stream_create(0): %s", | 210 | mu_error ("mu_tls_begin: mu_tls_client_stream_create(0): %s", |
196 | mu_strerror (status)); | 211 | mu_strerror (status)); |
212 | stream_ctl (iodata, MU_TLS_SESS_SET_STREAMS, streams); | ||
197 | return status; | 213 | return status; |
198 | } | 214 | } |
199 | 215 | ||
... | @@ -202,10 +218,13 @@ mu_tls_begin (void *iodata, | ... | @@ -202,10 +218,13 @@ mu_tls_begin (void *iodata, |
202 | { | 218 | { |
203 | mu_error ("mu_tls_begin: mu_stream_open (0): %s", | 219 | mu_error ("mu_tls_begin: mu_stream_open (0): %s", |
204 | mu_strerror (status)); | 220 | mu_strerror (status)); |
221 | stream_ctl (iodata, MU_TLS_SESS_SET_STREAMS, streams); | ||
205 | return status; | 222 | return status; |
206 | } | 223 | } |
207 | 224 | ||
208 | stream_ctl (iodata, NULL, newstr); | 225 | streams[0] = streams[1] = newstr; |
226 | stream_ctl (iodata, MU_TLS_SESS_SET_STREAMS, streams); | ||
227 | /* FIXME: Unref newstr */ | ||
209 | break; | 228 | break; |
210 | 229 | ||
211 | case 1: | 230 | case 1: |
... | @@ -219,7 +238,7 @@ mu_tls_begin (void *iodata, | ... | @@ -219,7 +238,7 @@ mu_tls_begin (void *iodata, |
219 | return status; | 238 | return status; |
220 | } | 239 | } |
221 | 240 | ||
222 | status = reader (iodata); | 241 | status = reader (iodata, i); |
223 | if (status != 0) | 242 | if (status != 0) |
224 | { | 243 | { |
225 | mu_error ("mu_tls_begin: reader (1): %s", mu_strerror (status)); | 244 | mu_error ("mu_tls_begin: reader (1): %s", mu_strerror (status)); |
... | @@ -420,6 +439,7 @@ _tls_stream_push (gnutls_transport_ptr fd, const void *buf, size_t size) | ... | @@ -420,6 +439,7 @@ _tls_stream_push (gnutls_transport_ptr fd, const void *buf, size_t size) |
420 | mu_error ("_tls_stream_push: %s", mu_strerror (rc)); /* FIXME */ | 439 | mu_error ("_tls_stream_push: %s", mu_strerror (rc)); /* FIXME */ |
421 | return -1; | 440 | return -1; |
422 | } | 441 | } |
442 | |||
423 | mu_stream_flush (stream); | 443 | mu_stream_flush (stream); |
424 | return size; | 444 | return size; |
425 | } | 445 | } |
... | @@ -475,9 +495,11 @@ _tls_server_open (mu_stream_t stream) | ... | @@ -475,9 +495,11 @@ _tls_server_open (mu_stream_t stream) |
475 | } | 495 | } |
476 | 496 | ||
477 | static int | 497 | static int |
478 | prepare_client_session (struct _mu_tls_stream *sp) | 498 | prepare_client_session (mu_stream_t stream) |
479 | { | 499 | { |
500 | struct _mu_tls_stream *sp = (struct _mu_tls_stream *) stream; | ||
480 | int rc; | 501 | int rc; |
502 | mu_transport_t transport[2]; | ||
481 | static int protocol_priority[] = {GNUTLS_TLS1, GNUTLS_SSL3, 0}; | 503 | static int protocol_priority[] = {GNUTLS_TLS1, GNUTLS_SSL3, 0}; |
482 | static int kx_priority[] = {GNUTLS_KX_RSA, 0}; | 504 | static int kx_priority[] = {GNUTLS_KX_RSA, 0}; |
483 | static int cipher_priority[] = {GNUTLS_CIPHER_3DES_CBC, | 505 | static int cipher_priority[] = {GNUTLS_CIPHER_3DES_CBC, |
... | @@ -508,9 +530,10 @@ prepare_client_session (struct _mu_tls_stream *sp) | ... | @@ -508,9 +530,10 @@ prepare_client_session (struct _mu_tls_stream *sp) |
508 | 530 | ||
509 | gnutls_credentials_set (sp->session, GNUTLS_CRD_CERTIFICATE, x509_cred); | 531 | gnutls_credentials_set (sp->session, GNUTLS_CRD_CERTIFICATE, x509_cred); |
510 | 532 | ||
533 | mu_stream_ioctl (stream, MU_IOCTL_GET_TRANSPORT, transport); | ||
511 | gnutls_transport_set_ptr2 (sp->session, | 534 | gnutls_transport_set_ptr2 (sp->session, |
512 | (gnutls_transport_ptr) sp->transport[0], | 535 | (gnutls_transport_ptr) transport[0], |
513 | (gnutls_transport_ptr) sp->transport[1]); | 536 | (gnutls_transport_ptr) transport[1]); |
514 | gnutls_transport_set_pull_function (sp->session, _tls_stream_pull); | 537 | gnutls_transport_set_pull_function (sp->session, _tls_stream_pull); |
515 | gnutls_transport_set_push_function (sp->session, _tls_stream_push); | 538 | gnutls_transport_set_push_function (sp->session, _tls_stream_push); |
516 | 539 | ||
... | @@ -532,7 +555,7 @@ _tls_client_open (mu_stream_t stream) | ... | @@ -532,7 +555,7 @@ _tls_client_open (mu_stream_t stream) |
532 | /* FALLTHROUGH */ | 555 | /* FALLTHROUGH */ |
533 | 556 | ||
534 | case state_init: | 557 | case state_init: |
535 | prepare_client_session (sp); | 558 | prepare_client_session (stream); |
536 | rc = gnutls_handshake (sp->session); | 559 | rc = gnutls_handshake (sp->session); |
537 | if (rc < 0) | 560 | if (rc < 0) |
538 | { | 561 | { | ... | ... |
... | @@ -24,17 +24,16 @@ lib_LTLIBRARIES = libmu_pop.la | ... | @@ -24,17 +24,16 @@ lib_LTLIBRARIES = libmu_pop.la |
24 | libmu_pop_la_LDFLAGS=-version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@ | 24 | libmu_pop_la_LDFLAGS=-version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@ |
25 | libmu_pop_la_LIBADD = ${MU_LIB_AUTH} ${MU_LIB_MAILUTILS} @INTLLIBS@ | 25 | libmu_pop_la_LIBADD = ${MU_LIB_AUTH} ${MU_LIB_MAILUTILS} @INTLLIBS@ |
26 | 26 | ||
27 | # folder.c\ | ||
28 | # mbox.c\ | ||
29 | # url.c | ||
27 | libmu_pop_la_SOURCES = \ | 30 | libmu_pop_la_SOURCES = \ |
28 | folder.c\ | ||
29 | mbox.c\ | ||
30 | url.c \ | ||
31 | \ | 31 | \ |
32 | pop3_apop.c \ | 32 | pop3_apop.c \ |
33 | pop3_capa.c \ | 33 | pop3_capa.c \ |
34 | pop3_carrier.c \ | 34 | pop3_carrier.c \ |
35 | pop3_connect.c \ | 35 | pop3_connect.c \ |
36 | pop3_create.c \ | 36 | pop3_create.c \ |
37 | pop3_debug.c \ | ||
38 | pop3_dele.c \ | 37 | pop3_dele.c \ |
39 | pop3_destroy.c \ | 38 | pop3_destroy.c \ |
40 | pop3_disconnect.c \ | 39 | pop3_disconnect.c \ |
... | @@ -54,6 +53,7 @@ libmu_pop_la_SOURCES = \ | ... | @@ -54,6 +53,7 @@ libmu_pop_la_SOURCES = \ |
54 | pop3_stream.c \ | 53 | pop3_stream.c \ |
55 | pop3_timeout.c \ | 54 | pop3_timeout.c \ |
56 | pop3_top.c \ | 55 | pop3_top.c \ |
56 | pop3_trace.c \ | ||
57 | pop3_uidla.c \ | 57 | pop3_uidla.c \ |
58 | pop3_uidl.c \ | 58 | pop3_uidl.c \ |
59 | pop3_user.c | 59 | pop3_user.c | ... | ... |
... | @@ -39,15 +39,11 @@ mu_pop3_apop (mu_pop3_t pop3, const char *user, const char *secret) | ... | @@ -39,15 +39,11 @@ mu_pop3_apop (mu_pop3_t pop3, const char *user, const char *secret) |
39 | 39 | ||
40 | /* Sanity checks. */ | 40 | /* Sanity checks. */ |
41 | if (pop3 == NULL || user == NULL || secret == NULL) | 41 | if (pop3 == NULL || user == NULL || secret == NULL) |
42 | { | ||
43 | return EINVAL; | 42 | return EINVAL; |
44 | } | ||
45 | 43 | ||
46 | /* The server did not offer a timestamp in the greeting, bailout early. */ | 44 | /* The server did not offer a timestamp in the greeting, bailout early. */ |
47 | if (pop3->timestamp == NULL) | 45 | if (pop3->timestamp == NULL) |
48 | { | ||
49 | return ENOTSUP; | 46 | return ENOTSUP; |
50 | } | ||
51 | 47 | ||
52 | switch (pop3->state) | 48 | switch (pop3->state) |
53 | { | 49 | { |
... | @@ -61,35 +57,25 @@ mu_pop3_apop (mu_pop3_t pop3, const char *user, const char *secret) | ... | @@ -61,35 +57,25 @@ mu_pop3_apop (mu_pop3_t pop3, const char *user, const char *secret) |
61 | size_t n; | 57 | size_t n; |
62 | 58 | ||
63 | mu_md5_init_ctx (&md5context); | 59 | mu_md5_init_ctx (&md5context); |
64 | mu_md5_process_bytes (pop3->timestamp, strlen (pop3->timestamp), &md5context); | 60 | mu_md5_process_bytes (pop3->timestamp, strlen (pop3->timestamp), |
61 | &md5context); | ||
65 | mu_md5_process_bytes (secret, strlen (secret), &md5context); | 62 | mu_md5_process_bytes (secret, strlen (secret), &md5context); |
66 | mu_md5_finish_ctx (&md5context, md5digest); | 63 | mu_md5_finish_ctx (&md5context, md5digest); |
67 | for (tmp = digest, n = 0; n < 16; n++, tmp += 2) | 64 | for (tmp = digest, n = 0; n < 16; n++, tmp += 2) |
68 | { | ||
69 | sprintf (tmp, "%02x", md5digest[n]); | 65 | sprintf (tmp, "%02x", md5digest[n]); |
70 | } | ||
71 | *tmp = '\0'; | 66 | *tmp = '\0'; |
72 | 67 | ||
73 | status = mu_pop3_writeline (pop3, "APOP %s %s\r\n", user, digest); | 68 | status = mu_pop3_writeline (pop3, "APOP %s %s\r\n", user, digest); |
74 | /* Obscure the digest, for security reasons. */ | 69 | /* Obscure the digest, for security reasons. */ |
75 | memset (digest, '\0', sizeof digest); | 70 | memset (digest, '\0', sizeof digest); |
76 | MU_POP3_CHECK_ERROR (pop3, status); | 71 | MU_POP3_CHECK_ERROR (pop3, status); |
77 | mu_pop3_debug_cmd (pop3); | 72 | MU_POP3_FCLR (pop3, MU_POP3_ACK); |
78 | pop3->state = MU_POP3_APOP; | 73 | pop3->state = MU_POP3_APOP; |
79 | } | 74 | } |
80 | 75 | ||
81 | case MU_POP3_APOP: | 76 | case MU_POP3_APOP: |
82 | status = mu_pop3_send (pop3); | 77 | status = mu_pop3_response (pop3, NULL); |
83 | MU_POP3_CHECK_EAGAIN (pop3, status); | ||
84 | /* Obscure the digest, for security reasons. */ | ||
85 | memset (pop3->io.buf, '\0', pop3->io.len); | ||
86 | pop3->acknowledge = 0; | ||
87 | pop3->state = MU_POP3_APOP_ACK; | ||
88 | |||
89 | case MU_POP3_APOP_ACK: | ||
90 | status = mu_pop3_response (pop3, NULL, 0, NULL); | ||
91 | MU_POP3_CHECK_EAGAIN (pop3, status); | 78 | MU_POP3_CHECK_EAGAIN (pop3, status); |
92 | mu_pop3_debug_ack (pop3); | ||
93 | MU_POP3_CHECK_OK (pop3); | 79 | MU_POP3_CHECK_OK (pop3); |
94 | pop3->state = MU_POP3_NO_STATE; | 80 | pop3->state = MU_POP3_NO_STATE; |
95 | break; | 81 | break; | ... | ... |
... | @@ -27,47 +27,95 @@ | ... | @@ -27,47 +27,95 @@ |
27 | #include <stdlib.h> | 27 | #include <stdlib.h> |
28 | #include <errno.h> | 28 | #include <errno.h> |
29 | #include <mailutils/error.h> | 29 | #include <mailutils/error.h> |
30 | #include <mailutils/list.h> | ||
31 | #include <mailutils/cctype.h> | ||
32 | #include <mailutils/cstr.h> | ||
30 | #include <mailutils/sys/pop3.h> | 33 | #include <mailutils/sys/pop3.h> |
31 | 34 | ||
35 | static int | ||
36 | string_comp (const void *item, const void *value) | ||
37 | { | ||
38 | return strcmp (item, value); | ||
39 | } | ||
40 | |||
41 | int | ||
42 | _mu_pop3_fill_list (mu_pop3_t pop3, mu_list_t list) | ||
43 | { | ||
44 | mu_stream_t stream; | ||
45 | size_t n; | ||
46 | int status = mu_pop3_stream_create (pop3, &stream); | ||
47 | if (status) | ||
48 | return status; | ||
49 | |||
50 | while (mu_stream_getline (stream, &pop3->rdbuf, &pop3->rdsize, &n) == 0 | ||
51 | && n > 0) | ||
52 | { | ||
53 | char *np = strdup (pop3->rdbuf); | ||
54 | if (!np) | ||
55 | { | ||
56 | status = ENOMEM; | ||
57 | break; | ||
58 | } | ||
59 | mu_rtrim_class (np, MU_CTYPE_SPACE); | ||
60 | status = mu_list_append (list, np); | ||
61 | if (status) | ||
62 | break; | ||
63 | } | ||
64 | mu_stream_destroy (&stream); | ||
65 | return status; | ||
66 | } | ||
67 | |||
32 | /* | 68 | /* |
33 | CAPA command, return a list that contains the result. | 69 | CAPA command, return a list that contains the result. |
34 | It is the responsability of the caller to destroy the list(mu_list_destroy). | 70 | It is the responsability of the caller to destroy the list(mu_list_destroy). |
35 | */ | 71 | */ |
36 | int | 72 | int |
37 | mu_pop3_capa (mu_pop3_t pop3, mu_iterator_t *piterator) | 73 | mu_pop3_capa (mu_pop3_t pop3, int reread, mu_iterator_t *piter) |
38 | { | 74 | { |
39 | int status = 0; | 75 | int status = 0; |
40 | 76 | ||
41 | if (pop3 == NULL) | 77 | if (pop3 == NULL) |
42 | return EINVAL; | 78 | return EINVAL; |
43 | if (piterator == NULL) | 79 | |
44 | return MU_ERR_OUT_PTR_NULL; | 80 | if (pop3->capa) |
81 | { | ||
82 | if (!reread) | ||
83 | { | ||
84 | if (!piter) | ||
85 | return 0; | ||
86 | return mu_list_get_iterator (pop3->capa, piter); | ||
87 | } | ||
88 | mu_list_destroy (&pop3->capa); | ||
89 | } | ||
90 | |||
91 | status = mu_list_create (&pop3->capa); | ||
92 | if (status) | ||
93 | return status; | ||
94 | mu_list_set_comparator (pop3->capa, string_comp); | ||
95 | mu_list_set_destroy_item (pop3->capa, mu_list_free_item); | ||
45 | 96 | ||
46 | switch (pop3->state) | 97 | switch (pop3->state) |
47 | { | 98 | { |
48 | case MU_POP3_NO_STATE: | 99 | case MU_POP3_NO_STATE: |
49 | status = mu_pop3_writeline (pop3, "CAPA\r\n"); | 100 | status = mu_pop3_writeline (pop3, "CAPA\r\n"); |
50 | MU_POP3_CHECK_ERROR (pop3, status); | 101 | MU_POP3_CHECK_ERROR (pop3, status); |
51 | mu_pop3_debug_cmd (pop3); | 102 | MU_POP3_FCLR (pop3, MU_POP3_ACK); |
52 | pop3->state = MU_POP3_CAPA; | 103 | pop3->state = MU_POP3_CAPA; |
53 | 104 | ||
54 | case MU_POP3_CAPA: | 105 | case MU_POP3_CAPA: |
55 | status = mu_pop3_send (pop3); | 106 | status = mu_pop3_response (pop3, NULL); |
56 | MU_POP3_CHECK_EAGAIN (pop3, status); | ||
57 | pop3->acknowledge = 0; | ||
58 | pop3->state = MU_POP3_CAPA_ACK; | ||
59 | |||
60 | case MU_POP3_CAPA_ACK: | ||
61 | status = mu_pop3_response (pop3, NULL, 0, NULL); | ||
62 | MU_POP3_CHECK_EAGAIN (pop3, status); | 107 | MU_POP3_CHECK_EAGAIN (pop3, status); |
63 | mu_pop3_debug_ack (pop3); | ||
64 | MU_POP3_CHECK_OK (pop3); | 108 | MU_POP3_CHECK_OK (pop3); |
65 | status = mu_pop3_iterator_create (pop3, piterator); | ||
66 | MU_POP3_CHECK_ERROR (pop3, status); | ||
67 | pop3->state = MU_POP3_CAPA_RX; | 109 | pop3->state = MU_POP3_CAPA_RX; |
68 | 110 | ||
69 | case MU_POP3_CAPA_RX: | 111 | case MU_POP3_CAPA_RX: |
70 | /* The mu_iterator_t will read the stream and set the state to MU_POP3_NO_STATE when done. */ | 112 | status = _mu_pop3_fill_list (pop3, pop3->capa); |
113 | MU_POP3_CHECK_ERROR (pop3, status); | ||
114 | if (piter) | ||
115 | status = mu_list_get_iterator (pop3->capa, piter); | ||
116 | else | ||
117 | status = 0; | ||
118 | pop3->state = MU_POP3_NO_STATE; | ||
71 | break; | 119 | break; |
72 | 120 | ||
73 | /* They must deal with the error first by reopening. */ | 121 | /* They must deal with the error first by reopening. */ | ... | ... |
... | @@ -38,10 +38,14 @@ mu_pop3_set_carrier (mu_pop3_t pop3, mu_stream_t carrier) | ... | @@ -38,10 +38,14 @@ mu_pop3_set_carrier (mu_pop3_t pop3, mu_stream_t carrier) |
38 | mu_pop3_disconnect (pop3); | 38 | mu_pop3_disconnect (pop3); |
39 | mu_stream_destroy (&pop3->carrier); | 39 | mu_stream_destroy (&pop3->carrier); |
40 | } | 40 | } |
41 | mu_stream_ref (carrier); | ||
41 | pop3->carrier = carrier; | 42 | pop3->carrier = carrier; |
43 | if (MU_POP3_FISSET (pop3, MU_POP3_TRACE)) | ||
44 | _mu_pop3_trace_enable (pop3); | ||
42 | return 0; | 45 | return 0; |
43 | } | 46 | } |
44 | 47 | ||
48 | /* FIXME: Is it needed? */ | ||
45 | int | 49 | int |
46 | mu_pop3_get_carrier (mu_pop3_t pop3, mu_stream_t *pcarrier) | 50 | mu_pop3_get_carrier (mu_pop3_t pop3, mu_stream_t *pcarrier) |
47 | { | 51 | { | ... | ... |
... | @@ -53,14 +53,15 @@ mu_pop3_connect (mu_pop3_t pop3) | ... | @@ -53,14 +53,15 @@ mu_pop3_connect (mu_pop3_t pop3) |
53 | 53 | ||
54 | case MU_POP3_NO_STATE: | 54 | case MU_POP3_NO_STATE: |
55 | /* If the stream was previoulsy open this is sudden death: | 55 | /* If the stream was previoulsy open this is sudden death: |
56 | for many pop servers, it is important to let them time to remove any locks or move | 56 | For many pop servers, it is important to allow them some time to |
57 | the .user.pop files. This happen when we do close() and immediately open(). | 57 | remove any locks or move the .user.pop files. This happen when we |
58 | For example, the user does not want to read the entire file, and wants to start | 58 | do close() and immediately open(). For example, the user does not |
59 | to read a new message, closing the connection and immediately | 59 | want to read the entire file, and wants to start to read a new |
60 | contacting the server again, and he'll end up having | 60 | message, closing the connection and immediately contacting the |
61 | "-ERR Mail Lock busy" or something similar. To prevent this race | 61 | server again, and he'll end up having "-ERR Mail Lock busy" or |
62 | condition we sleep 2 seconds. You can see this behaviour in an | 62 | something similar. To prevent this race condition we sleep 2 seconds. |
63 | environment where QPopper(Qualcomm POP3 server) is use and the user as a big mailbox. */ | 63 | You can see this behaviour in an environment where QPopper (Qualcomm |
64 | POP3 server) is used and the user has a big mailbox. */ | ||
64 | status = mu_pop3_disconnect (pop3); | 65 | status = mu_pop3_disconnect (pop3); |
65 | if (status != 0) | 66 | if (status != 0) |
66 | mu_pop3_sleep (2); | 67 | mu_pop3_sleep (2); |
... | @@ -70,7 +71,7 @@ mu_pop3_connect (mu_pop3_t pop3) | ... | @@ -70,7 +71,7 @@ mu_pop3_connect (mu_pop3_t pop3) |
70 | /* Establish the connection. */ | 71 | /* Establish the connection. */ |
71 | status = mu_stream_open (pop3->carrier); | 72 | status = mu_stream_open (pop3->carrier); |
72 | MU_POP3_CHECK_EAGAIN (pop3, status); | 73 | MU_POP3_CHECK_EAGAIN (pop3, status); |
73 | pop3->acknowledge = 0; | 74 | MU_POP3_FCLR (pop3, MU_POP3_ACK); |
74 | pop3->state = MU_POP3_GREETINGS; | 75 | pop3->state = MU_POP3_GREETINGS; |
75 | 76 | ||
76 | case MU_POP3_GREETINGS: | 77 | case MU_POP3_GREETINGS: |
... | @@ -78,10 +79,9 @@ mu_pop3_connect (mu_pop3_t pop3) | ... | @@ -78,10 +79,9 @@ mu_pop3_connect (mu_pop3_t pop3) |
78 | { | 79 | { |
79 | size_t len = 0; | 80 | size_t len = 0; |
80 | char *right, *left; | 81 | char *right, *left; |
81 | status = mu_pop3_response (pop3, NULL, 0, &len); | 82 | status = mu_pop3_response (pop3, &len); |
82 | MU_POP3_CHECK_EAGAIN (pop3, status); | 83 | MU_POP3_CHECK_EAGAIN (pop3, status); |
83 | mu_pop3_debug_ack (pop3); | 84 | if (mu_c_strncasecmp (pop3->ackbuf, "+OK", 3) != 0) |
84 | if (mu_c_strncasecmp (pop3->ack.buf, "+OK", 3) != 0) | ||
85 | { | 85 | { |
86 | mu_stream_close (pop3->carrier); | 86 | mu_stream_close (pop3->carrier); |
87 | pop3->state = MU_POP3_NO_STATE; | 87 | pop3->state = MU_POP3_NO_STATE; |
... | @@ -89,10 +89,10 @@ mu_pop3_connect (mu_pop3_t pop3) | ... | @@ -89,10 +89,10 @@ mu_pop3_connect (mu_pop3_t pop3) |
89 | } | 89 | } |
90 | 90 | ||
91 | /* Get the timestamp. */ | 91 | /* Get the timestamp. */ |
92 | right = memchr (pop3->ack.buf, '<', len); | 92 | right = memchr (pop3->ackbuf, '<', len); |
93 | if (right) | 93 | if (right) |
94 | { | 94 | { |
95 | len = len - (right - pop3->ack.buf); | 95 | len = len - (right - pop3->ackbuf); |
96 | left = memchr (right, '>', len); | 96 | left = memchr (right, '>', len); |
97 | if (left) | 97 | if (left) |
98 | { | 98 | { |
... | @@ -121,5 +121,5 @@ mu_pop3_sleep (int seconds) | ... | @@ -121,5 +121,5 @@ mu_pop3_sleep (int seconds) |
121 | struct timeval tval; | 121 | struct timeval tval; |
122 | tval.tv_sec = seconds; | 122 | tval.tv_sec = seconds; |
123 | tval.tv_usec = 0; | 123 | tval.tv_usec = 0; |
124 | return select (1, NULL, NULL, NULL, &tval); | 124 | return select (0, NULL, NULL, NULL, &tval); |
125 | } | 125 | } | ... | ... |
... | @@ -40,34 +40,24 @@ mu_pop3_create (mu_pop3_t *ppop3) | ... | @@ -40,34 +40,24 @@ mu_pop3_create (mu_pop3_t *ppop3) |
40 | if (pop3 == NULL) | 40 | if (pop3 == NULL) |
41 | return ENOMEM; | 41 | return ENOMEM; |
42 | 42 | ||
43 | /* Reserve space for the ack(nowledgement) response. | ||
44 | According to RFC 2449: The maximum length of the first line of a | ||
45 | command response (including the initial greeting) is unchanged at | ||
46 | 512 octets (including the terminating CRLF). */ | ||
47 | pop3->ack.len = 512; | ||
48 | pop3->ack.buf = calloc (pop3->ack.len, 1); | ||
49 | if (pop3->ack.buf == NULL) | ||
50 | { | ||
51 | mu_pop3_destroy (&pop3); | ||
52 | return ENOMEM; | ||
53 | } | ||
54 | pop3->ack.ptr = pop3->ack.buf; | ||
55 | |||
56 | /* Reserve space for the data response/content. | ||
57 | RFC 2449 recommands 255, but we grow it as needed. */ | ||
58 | pop3->io.len = 255; | ||
59 | pop3->io.buf = calloc (pop3->io.len, 1); | ||
60 | if (pop3->io.buf == NULL) | ||
61 | { | ||
62 | mu_pop3_destroy (&pop3); | ||
63 | return ENOMEM; | ||
64 | } | ||
65 | pop3->io.ptr = pop3->io.buf; | ||
66 | |||
67 | pop3->state = MU_POP3_NO_STATE; /* Init with no state. */ | 43 | pop3->state = MU_POP3_NO_STATE; /* Init with no state. */ |
68 | pop3->timeout = (10 * 60) * 100; /* The default Timeout is 10 minutes. */ | 44 | pop3->timeout = (10 * 60) * 100; /* The default Timeout is 10 minutes. */ |
69 | pop3->acknowledge = 0; /* No Ack received. */ | 45 | MU_POP3_FCLR (pop3, MU_POP3_ACK); /* No Ack received. */ |
70 | 46 | ||
71 | *ppop3 = pop3; | 47 | *ppop3 = pop3; |
72 | return 0; /* Okdoke. */ | 48 | return 0; /* Okdoke. */ |
73 | } | 49 | } |
50 | |||
51 | int | ||
52 | _mu_pop3_init (mu_pop3_t pop3) | ||
53 | { | ||
54 | if (pop3 == NULL) | ||
55 | return EINVAL; | ||
56 | if (pop3->carrier == 0) | ||
57 | { | ||
58 | mu_list_destroy (&pop3->capa); | ||
59 | pop3->flags = 0; | ||
60 | } | ||
61 | } | ||
62 | |||
63 | ... | ... |
libproto/pop/pop3_debug.c
deleted
100644 → 0
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2003, 2007, 2010 Free Software Foundation, Inc. | ||
3 | |||
4 | This library is free software; you can redistribute it and/or | ||
5 | modify it under the terms of the GNU Lesser General Public | ||
6 | License as published by the Free Software Foundation; either | ||
7 | version 3 of the License, or (at your option) any later version. | ||
8 | |||
9 | This library is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | Lesser General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU Lesser General | ||
15 | Public License along with this library; if not, write to the | ||
16 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
17 | Boston, MA 02110-1301 USA */ | ||
18 | |||
19 | #ifdef HAVE_CONFIG_H | ||
20 | # include <config.h> | ||
21 | #endif | ||
22 | |||
23 | #include <stdlib.h> | ||
24 | #include <errno.h> | ||
25 | #include <mailutils/sys/pop3.h> | ||
26 | |||
27 | int | ||
28 | mu_pop3_set_debug (mu_pop3_t pop3, mu_debug_t debug) | ||
29 | { | ||
30 | if (pop3 == NULL) | ||
31 | return EINVAL; | ||
32 | if (pop3->debug) | ||
33 | mu_debug_destroy (&pop3->debug, NULL); | ||
34 | pop3->debug = debug; | ||
35 | return 0; | ||
36 | } | ||
37 | |||
38 | /* FIXME: This should be a macro */ | ||
39 | int | ||
40 | mu_pop3_debug_cmd (mu_pop3_t pop3) | ||
41 | { | ||
42 | MU_DEBUG (pop3->debug, MU_DEBUG_PROT, pop3->io.buf); | ||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | int | ||
47 | mu_pop3_debug_ack (mu_pop3_t pop3) | ||
48 | { | ||
49 | MU_DEBUG1 (pop3->debug, MU_DEBUG_PROT, "%s\n", pop3->ack.buf); | ||
50 | return 0; | ||
51 | } |
... | @@ -38,19 +38,12 @@ mu_pop3_dele (mu_pop3_t pop3, unsigned msgno) | ... | @@ -38,19 +38,12 @@ mu_pop3_dele (mu_pop3_t pop3, unsigned msgno) |
38 | case MU_POP3_NO_STATE: | 38 | case MU_POP3_NO_STATE: |
39 | status = mu_pop3_writeline (pop3, "DELE %d\r\n", msgno); | 39 | status = mu_pop3_writeline (pop3, "DELE %d\r\n", msgno); |
40 | MU_POP3_CHECK_ERROR (pop3, status); | 40 | MU_POP3_CHECK_ERROR (pop3, status); |
41 | mu_pop3_debug_cmd (pop3); | 41 | MU_POP3_FCLR (pop3, MU_POP3_ACK); |
42 | pop3->state = MU_POP3_DELE; | 42 | pop3->state = MU_POP3_DELE; |
43 | 43 | ||
44 | case MU_POP3_DELE: | 44 | case MU_POP3_DELE: |
45 | status = mu_pop3_send (pop3); | 45 | status = mu_pop3_response (pop3, NULL); |
46 | MU_POP3_CHECK_EAGAIN (pop3, status); | 46 | MU_POP3_CHECK_EAGAIN (pop3, status); |
47 | pop3->acknowledge = 0; | ||
48 | pop3->state = MU_POP3_DELE_ACK; | ||
49 | |||
50 | case MU_POP3_DELE_ACK: | ||
51 | status = mu_pop3_response (pop3, NULL, 0, NULL); | ||
52 | MU_POP3_CHECK_EAGAIN (pop3, status); | ||
53 | mu_pop3_debug_ack (pop3); | ||
54 | MU_POP3_CHECK_OK (pop3); | 47 | MU_POP3_CHECK_OK (pop3); |
55 | pop3->state = MU_POP3_NO_STATE; | 48 | pop3->state = MU_POP3_NO_STATE; |
56 | break; | 49 | break; | ... | ... |
... | @@ -32,17 +32,18 @@ mu_pop3_destroy (mu_pop3_t *ppop3) | ... | @@ -32,17 +32,18 @@ mu_pop3_destroy (mu_pop3_t *ppop3) |
32 | mu_pop3_t pop3 = *ppop3; | 32 | mu_pop3_t pop3 = *ppop3; |
33 | 33 | ||
34 | /* Free the response buffer. */ | 34 | /* Free the response buffer. */ |
35 | if (pop3->ack.buf) | 35 | if (pop3->ackbuf) |
36 | free (pop3->ack.buf); | 36 | free (pop3->ackbuf); |
37 | 37 | /* Free the read buffer. */ | |
38 | /* Free the io buffer. */ | 38 | if (pop3->rdbuf) |
39 | if (pop3->io.buf) | 39 | free (pop3->rdbuf); |
40 | free (pop3->io.buf); | ||
41 | 40 | ||
42 | /* Free the timestamp use for APOP. */ | 41 | /* Free the timestamp use for APOP. */ |
43 | if (pop3->timestamp) | 42 | if (pop3->timestamp) |
44 | free (pop3->timestamp); | 43 | free (pop3->timestamp); |
45 | 44 | ||
45 | mu_list_destroy (&pop3->capa); | ||
46 | |||
46 | /* Release the carrier. */ | 47 | /* Release the carrier. */ |
47 | if (pop3->carrier) | 48 | if (pop3->carrier) |
48 | mu_stream_destroy (&pop3->carrier); | 49 | mu_stream_destroy (&pop3->carrier); | ... | ... |
... | @@ -36,13 +36,10 @@ mu_pop3_disconnect (mu_pop3_t pop3) | ... | @@ -36,13 +36,10 @@ mu_pop3_disconnect (mu_pop3_t pop3) |
36 | /* We can keep some of the fields, if they decide to pop3_connect() again but | 36 | /* We can keep some of the fields, if they decide to pop3_connect() again but |
37 | clear the states. */ | 37 | clear the states. */ |
38 | pop3->state = MU_POP3_NO_STATE; | 38 | pop3->state = MU_POP3_NO_STATE; |
39 | pop3->acknowledge = 0; | 39 | MU_POP3_FCLR (pop3, MU_POP3_ACK); |
40 | 40 | ||
41 | /* Clear the buffers. */ | 41 | if (pop3->rdbuf) |
42 | memset (pop3->io.buf, '\0', pop3->io.len); | 42 | pop3->rdbuf[0] = 0; |
43 | pop3->io.ptr = pop3->io.buf; | ||
44 | memset (pop3->ack.buf, '\0', pop3->ack.len); | ||
45 | pop3->ack.ptr = pop3->ack.buf; | ||
46 | 43 | ||
47 | /* Free the timestamp, it will be different on each connection. */ | 44 | /* Free the timestamp, it will be different on each connection. */ |
48 | if (pop3->timestamp) | 45 | if (pop3->timestamp) | ... | ... |
... | @@ -25,7 +25,10 @@ | ... | @@ -25,7 +25,10 @@ |
25 | #include <stdlib.h> | 25 | #include <stdlib.h> |
26 | #include <stdio.h> | 26 | #include <stdio.h> |
27 | #include <errno.h> | 27 | #include <errno.h> |
28 | #include <mailutils/pop3.h> | ||
28 | #include <mailutils/sys/pop3.h> | 29 | #include <mailutils/sys/pop3.h> |
30 | #include <mailutils/cctype.h> | ||
31 | #include <mailutils/cstr.h> | ||
29 | 32 | ||
30 | static int pop3_itr_dup (void **ptr, void *owner); | 33 | static int pop3_itr_dup (void **ptr, void *owner); |
31 | static int pop3_itr_destroy (mu_iterator_t itr, void *owner); | 34 | static int pop3_itr_destroy (mu_iterator_t itr, void *owner); |
... | @@ -38,8 +41,11 @@ static int pop3_itr_finished_p (void *owner); | ... | @@ -38,8 +41,11 @@ static int pop3_itr_finished_p (void *owner); |
38 | struct pop3_iterator | 41 | struct pop3_iterator |
39 | { | 42 | { |
40 | mu_pop3_t pop3; | 43 | mu_pop3_t pop3; |
44 | mu_stream_t stream; | ||
41 | int done; | 45 | int done; |
42 | char *item; | 46 | char *item; |
47 | char *rdbuf; | ||
48 | size_t rdsize; | ||
43 | }; | 49 | }; |
44 | 50 | ||
45 | int | 51 | int |
... | @@ -53,9 +59,17 @@ mu_pop3_iterator_create (mu_pop3_t pop3, mu_iterator_t *piterator) | ... | @@ -53,9 +59,17 @@ mu_pop3_iterator_create (mu_pop3_t pop3, mu_iterator_t *piterator) |
53 | if (pop3_iterator == NULL) | 59 | if (pop3_iterator == NULL) |
54 | return ENOMEM; | 60 | return ENOMEM; |
55 | 61 | ||
62 | status = mu_pop3_stream_create (pop3, &pop3_iterator->stream); | ||
63 | if (status) | ||
64 | { | ||
65 | free (pop3_iterator); | ||
66 | return status; | ||
67 | } | ||
56 | pop3_iterator->item = NULL; | 68 | pop3_iterator->item = NULL; |
69 | pop3_iterator->rdbuf = NULL; | ||
70 | pop3_iterator->rdsize = 0; | ||
57 | pop3_iterator->done = 0; | 71 | pop3_iterator->done = 0; |
58 | pop3_iterator->pop3= pop3; | 72 | pop3_iterator->pop3 = pop3; |
59 | 73 | ||
60 | status = mu_iterator_create (&iterator, pop3_iterator); | 74 | status = mu_iterator_create (&iterator, pop3_iterator); |
61 | if (status != 0) | 75 | if (status != 0) |
... | @@ -93,17 +107,21 @@ pop3_itr_destroy (mu_iterator_t iterator, void *owner) | ... | @@ -93,17 +107,21 @@ pop3_itr_destroy (mu_iterator_t iterator, void *owner) |
93 | { | 107 | { |
94 | struct pop3_iterator *pop3_iterator = (struct pop3_iterator *)owner; | 108 | struct pop3_iterator *pop3_iterator = (struct pop3_iterator *)owner; |
95 | /* Delicate situation if they did not finish to drain the result | 109 | /* Delicate situation if they did not finish to drain the result |
96 | We take te approach to do it for the user. FIXME: Not sure | 110 | We take the approach to do it for the user. FIXME: Not sure |
97 | if this is the rigth thing to do. The other way is to close the stream */ | 111 | if this is the rigth thing to do. The other way is to close the stream */ |
98 | if (!pop3_iterator->done) | 112 | if (!pop3_iterator->done) |
99 | { | 113 | { |
100 | char buf[128]; | 114 | char buf[128]; |
101 | size_t n = 0; | 115 | size_t n = 0; |
102 | while (mu_pop3_readline (pop3_iterator->pop3, buf, sizeof buf, &n) > 0 && n > 0) | 116 | mu_stream_t str = pop3_iterator->pop3->carrier; |
117 | while (mu_stream_readline (str, buf, sizeof buf, &n) > 0 | ||
118 | && n > 0) | ||
103 | n = 0; | 119 | n = 0; |
104 | } | 120 | } |
105 | if (pop3_iterator->item) | 121 | if (pop3_iterator->item) |
106 | free (pop3_iterator->item); | 122 | free (pop3_iterator->item); |
123 | if (pop3_iterator->rdbuf) | ||
124 | free (pop3_iterator->rdbuf); | ||
107 | pop3_iterator->pop3->state = MU_POP3_NO_STATE; | 125 | pop3_iterator->pop3->state = MU_POP3_NO_STATE; |
108 | free (pop3_iterator); | 126 | free (pop3_iterator); |
109 | return 0; | 127 | return 0; |
... | @@ -119,40 +137,27 @@ static int | ... | @@ -119,40 +137,27 @@ static int |
119 | pop3_itr_next (void *owner) | 137 | pop3_itr_next (void *owner) |
120 | { | 138 | { |
121 | struct pop3_iterator *pop3_iterator = (struct pop3_iterator *)owner; | 139 | struct pop3_iterator *pop3_iterator = (struct pop3_iterator *)owner; |
122 | size_t n = 0; | ||
123 | int status = 0; | 140 | int status = 0; |
141 | size_t n; | ||
124 | 142 | ||
125 | if (!pop3_iterator->done) | 143 | status = mu_stream_getline (pop3_iterator->stream, &pop3_iterator->rdbuf, |
126 | { | 144 | &pop3_iterator->rdsize, &n); |
127 | /* The first readline will not consume the buffer, we just need to | 145 | |
128 | know how much to read. */ | 146 | if (status || n == 0) |
129 | status = mu_pop3_readline (pop3_iterator->pop3, NULL, 0, &n); | ||
130 | if (status == 0) | ||
131 | { | ||
132 | if (n) | ||
133 | { | ||
134 | char *buf; | ||
135 | buf = calloc (n + 1, 1); | ||
136 | if (buf) | ||
137 | { | 147 | { |
138 | /* Consume. */ | 148 | pop3_iterator->done = 1; |
139 | mu_pop3_readline (pop3_iterator->pop3, buf, n + 1, NULL); | 149 | pop3_iterator->pop3->state = MU_POP3_NO_STATE; |
140 | if (buf[n - 1] == '\n') | 150 | return 0; |
141 | buf[n - 1] = '\0'; | ||
142 | if (pop3_iterator->item) | ||
143 | free (pop3_iterator->item); | ||
144 | pop3_iterator->item = buf; | ||
145 | } | ||
146 | else | ||
147 | status = ENOMEM; | ||
148 | } | 151 | } |
149 | else | 152 | |
153 | n = mu_rtrim_class (pop3_iterator->rdbuf, MU_CTYPE_SPACE); | ||
154 | if (n == 1 && pop3_iterator->rdbuf[0] == '.') | ||
150 | { | 155 | { |
151 | pop3_iterator->done = 1; | 156 | pop3_iterator->done = 1; |
152 | pop3_iterator->pop3->state = MU_POP3_NO_STATE; | 157 | pop3_iterator->pop3->state = MU_POP3_NO_STATE; |
153 | } | 158 | } |
154 | } | 159 | else |
155 | } | 160 | pop3_iterator->item = pop3_iterator->rdbuf; |
156 | return status; | 161 | return status; |
157 | } | 162 | } |
158 | 163 | ... | ... |
... | @@ -42,25 +42,19 @@ mu_pop3_list (mu_pop3_t pop3, unsigned int msgno, size_t *psize) | ... | @@ -42,25 +42,19 @@ mu_pop3_list (mu_pop3_t pop3, unsigned int msgno, size_t *psize) |
42 | case MU_POP3_NO_STATE: | 42 | case MU_POP3_NO_STATE: |
43 | status = mu_pop3_writeline (pop3, "LIST %d\r\n", msgno); | 43 | status = mu_pop3_writeline (pop3, "LIST %d\r\n", msgno); |
44 | MU_POP3_CHECK_ERROR (pop3, status); | 44 | MU_POP3_CHECK_ERROR (pop3, status); |
45 | mu_pop3_debug_cmd (pop3); | 45 | MU_POP3_FCLR (pop3, MU_POP3_ACK); |
46 | pop3->state = MU_POP3_LIST; | 46 | pop3->state = MU_POP3_LIST; |
47 | 47 | ||
48 | case MU_POP3_LIST: | 48 | case MU_POP3_LIST: |
49 | status = mu_pop3_send (pop3); | 49 | status = mu_pop3_response (pop3, NULL); |
50 | MU_POP3_CHECK_EAGAIN (pop3, status); | ||
51 | pop3->acknowledge = 0; | ||
52 | pop3->state = MU_POP3_LIST_ACK; | ||
53 | |||
54 | case MU_POP3_LIST_ACK: | ||
55 | status = mu_pop3_response (pop3, NULL, 0, NULL); | ||
56 | mu_pop3_debug_ack (pop3); | ||
57 | MU_POP3_CHECK_EAGAIN (pop3, status); | 50 | MU_POP3_CHECK_EAGAIN (pop3, status); |
58 | MU_POP3_CHECK_OK (pop3); | 51 | MU_POP3_CHECK_OK (pop3); |
59 | pop3->state = MU_POP3_NO_STATE; | 52 | pop3->state = MU_POP3_NO_STATE; |
60 | 53 | ||
61 | /* Parse the answer. */ | 54 | /* Parse the answer. */ |
62 | lv = 0; | 55 | lv = 0; |
63 | sscanf (pop3->ack.buf, "+OK %d %lu", &msgno, &lv); | 56 | /* FIXME: Error checking */ |
57 | sscanf (pop3->ackbuf, "+OK %d %lu", &msgno, &lv); | ||
64 | *psize = lv; | 58 | *psize = lv; |
65 | break; | 59 | break; |
66 | 60 | ... | ... |
... | @@ -42,26 +42,20 @@ mu_pop3_list_all (mu_pop3_t pop3, mu_iterator_t *piterator) | ... | @@ -42,26 +42,20 @@ mu_pop3_list_all (mu_pop3_t pop3, mu_iterator_t *piterator) |
42 | case MU_POP3_NO_STATE: | 42 | case MU_POP3_NO_STATE: |
43 | status = mu_pop3_writeline (pop3, "LIST\r\n"); | 43 | status = mu_pop3_writeline (pop3, "LIST\r\n"); |
44 | MU_POP3_CHECK_ERROR (pop3, status); | 44 | MU_POP3_CHECK_ERROR (pop3, status); |
45 | mu_pop3_debug_cmd (pop3); | 45 | MU_POP3_FCLR (pop3, MU_POP3_ACK); |
46 | pop3->state = MU_POP3_LIST; | 46 | pop3->state = MU_POP3_LIST; |
47 | 47 | ||
48 | case MU_POP3_LIST: | 48 | case MU_POP3_LIST: |
49 | status = mu_pop3_send (pop3); | 49 | status = mu_pop3_response (pop3, NULL); |
50 | MU_POP3_CHECK_EAGAIN (pop3, status); | 50 | MU_POP3_CHECK_EAGAIN (pop3, status); |
51 | pop3->acknowledge = 0; | ||
52 | pop3->state = MU_POP3_LIST_ACK; | ||
53 | |||
54 | case MU_POP3_LIST_ACK: | ||
55 | status = mu_pop3_response (pop3, NULL, 0, NULL); | ||
56 | MU_POP3_CHECK_EAGAIN (pop3, status); | ||
57 | mu_pop3_debug_ack (pop3); | ||
58 | MU_POP3_CHECK_OK (pop3); | 51 | MU_POP3_CHECK_OK (pop3); |
59 | status = mu_pop3_iterator_create (pop3, piterator); | 52 | status = mu_pop3_iterator_create (pop3, piterator); |
60 | MU_POP3_CHECK_ERROR (pop3, status); | 53 | MU_POP3_CHECK_ERROR (pop3, status); |
61 | pop3->state = MU_POP3_LIST_RX; | 54 | pop3->state = MU_POP3_LIST_RX; |
62 | 55 | ||
63 | case MU_POP3_LIST_RX: | 56 | case MU_POP3_LIST_RX: |
64 | /* The mu_iterator_t will read the stream and set the state to MU_POP3_NO_STATE when done. */ | 57 | /* The mu_iterator_t will read the stream and set the state to |
58 | MU_POP3_NO_STATE when done. */ | ||
65 | break; | 59 | break; |
66 | 60 | ||
67 | /* They must deal with the error first by reopening. */ | 61 | /* They must deal with the error first by reopening. */ | ... | ... |
... | @@ -38,19 +38,12 @@ mu_pop3_noop (mu_pop3_t pop3) | ... | @@ -38,19 +38,12 @@ mu_pop3_noop (mu_pop3_t pop3) |
38 | case MU_POP3_NO_STATE: | 38 | case MU_POP3_NO_STATE: |
39 | status = mu_pop3_writeline (pop3, "NOOP\r\n"); | 39 | status = mu_pop3_writeline (pop3, "NOOP\r\n"); |
40 | MU_POP3_CHECK_ERROR (pop3, status); | 40 | MU_POP3_CHECK_ERROR (pop3, status); |
41 | mu_pop3_debug_cmd (pop3); | 41 | MU_POP3_FCLR (pop3, MU_POP3_ACK); |
42 | pop3->state = MU_POP3_NOOP; | 42 | pop3->state = MU_POP3_NOOP; |
43 | 43 | ||
44 | case MU_POP3_NOOP: | 44 | case MU_POP3_NOOP: |
45 | status = mu_pop3_send (pop3); | 45 | status = mu_pop3_response (pop3, NULL); |
46 | MU_POP3_CHECK_EAGAIN (pop3, status); | 46 | MU_POP3_CHECK_EAGAIN (pop3, status); |
47 | pop3->acknowledge = 0; | ||
48 | pop3->state = MU_POP3_NOOP_ACK; | ||
49 | |||
50 | case MU_POP3_NOOP_ACK: | ||
51 | status = mu_pop3_response (pop3, NULL, 0, NULL); | ||
52 | MU_POP3_CHECK_EAGAIN (pop3, status); | ||
53 | mu_pop3_debug_ack (pop3); | ||
54 | MU_POP3_CHECK_OK (pop3); | 47 | MU_POP3_CHECK_OK (pop3); |
55 | pop3->state = MU_POP3_NO_STATE; | 48 | pop3->state = MU_POP3_NO_STATE; |
56 | break; | 49 | break; | ... | ... |
... | @@ -37,21 +37,13 @@ mu_pop3_pass (mu_pop3_t pop3, const char *passwd) | ... | @@ -37,21 +37,13 @@ mu_pop3_pass (mu_pop3_t pop3, const char *passwd) |
37 | case MU_POP3_NO_STATE: | 37 | case MU_POP3_NO_STATE: |
38 | status = mu_pop3_writeline (pop3, "PASS %s\r\n", passwd); | 38 | status = mu_pop3_writeline (pop3, "PASS %s\r\n", passwd); |
39 | MU_POP3_CHECK_ERROR (pop3, status); | 39 | MU_POP3_CHECK_ERROR (pop3, status); |
40 | mu_pop3_debug_cmd (pop3); | 40 | /* FIXME: how to obscure the passwd in the stream buffer? */ |
41 | MU_POP3_FCLR (pop3, MU_POP3_ACK); | ||
41 | pop3->state = MU_POP3_PASS; | 42 | pop3->state = MU_POP3_PASS; |
42 | 43 | ||
43 | case MU_POP3_PASS: | 44 | case MU_POP3_PASS: |
44 | status = mu_pop3_send (pop3); | 45 | status = mu_pop3_response (pop3, NULL); |
45 | MU_POP3_CHECK_EAGAIN (pop3, status); | 46 | MU_POP3_CHECK_EAGAIN (pop3, status); |
46 | /* Obscure the passwd. */ | ||
47 | memset (pop3->io.buf, '\0', pop3->io.len); | ||
48 | pop3->acknowledge = 0; | ||
49 | pop3->state = MU_POP3_PASS_ACK; | ||
50 | |||
51 | case MU_POP3_PASS_ACK: | ||
52 | status = mu_pop3_response (pop3, NULL, 0, NULL); | ||
53 | MU_POP3_CHECK_EAGAIN (pop3, status); | ||
54 | mu_pop3_debug_ack (pop3); | ||
55 | MU_POP3_CHECK_OK (pop3); | 47 | MU_POP3_CHECK_OK (pop3); |
56 | pop3->state = MU_POP3_NO_STATE; | 48 | pop3->state = MU_POP3_NO_STATE; |
57 | break; | 49 | break; | ... | ... |
... | @@ -38,21 +38,15 @@ mu_pop3_quit (mu_pop3_t pop3) | ... | @@ -38,21 +38,15 @@ mu_pop3_quit (mu_pop3_t pop3) |
38 | case MU_POP3_NO_STATE: | 38 | case MU_POP3_NO_STATE: |
39 | status = mu_pop3_writeline (pop3, "QUIT\r\n"); | 39 | status = mu_pop3_writeline (pop3, "QUIT\r\n"); |
40 | MU_POP3_CHECK_ERROR (pop3, status); | 40 | MU_POP3_CHECK_ERROR (pop3, status); |
41 | mu_pop3_debug_cmd (pop3); | 41 | MU_POP3_FCLR (pop3, MU_POP3_ACK); |
42 | pop3->state = MU_POP3_QUIT; | 42 | pop3->state = MU_POP3_QUIT; |
43 | 43 | ||
44 | case MU_POP3_QUIT: | 44 | case MU_POP3_QUIT: |
45 | status = mu_pop3_send (pop3); | 45 | status = mu_pop3_response (pop3, NULL); |
46 | MU_POP3_CHECK_EAGAIN (pop3, status); | 46 | MU_POP3_CHECK_EAGAIN (pop3, status); |
47 | pop3->acknowledge = 0; | ||
48 | pop3->state = MU_POP3_QUIT_ACK; | ||
49 | |||
50 | case MU_POP3_QUIT_ACK: | ||
51 | status = mu_pop3_response (pop3, NULL, 0, NULL); | ||
52 | MU_POP3_CHECK_EAGAIN (pop3, status); | ||
53 | mu_pop3_debug_ack (pop3); | ||
54 | MU_POP3_CHECK_OK (pop3); | 47 | MU_POP3_CHECK_OK (pop3); |
55 | pop3->state = MU_POP3_NO_STATE; | 48 | pop3->state = MU_POP3_NO_STATE; |
49 | _mu_pop3_init (pop3); | ||
56 | break; | 50 | break; |
57 | 51 | ||
58 | default: | 52 | default: | ... | ... |
... | @@ -29,6 +29,8 @@ | ... | @@ -29,6 +29,8 @@ |
29 | #include <errno.h> | 29 | #include <errno.h> |
30 | #include <mailutils/sys/pop3.h> | 30 | #include <mailutils/sys/pop3.h> |
31 | #include <mailutils/error.h> | 31 | #include <mailutils/error.h> |
32 | #include <mailutils/cctype.h> | ||
33 | #include <mailutils/cstr.h> | ||
32 | 34 | ||
33 | int | 35 | int |
34 | mu_pop3_carrier_is_ready (mu_stream_t carrier, int flag, int timeout) | 36 | mu_pop3_carrier_is_ready (mu_stream_t carrier, int flag, int timeout) |
... | @@ -52,143 +54,28 @@ mu_pop3_carrier_is_ready (mu_stream_t carrier, int flag, int timeout) | ... | @@ -52,143 +54,28 @@ mu_pop3_carrier_is_ready (mu_stream_t carrier, int flag, int timeout) |
52 | /* Read a complete line from the pop server. Transform CRLF to LF, remove | 54 | /* Read a complete line from the pop server. Transform CRLF to LF, remove |
53 | the stuff byte termination octet ".", put a null in the buffer | 55 | the stuff byte termination octet ".", put a null in the buffer |
54 | when done. And Do a select() (stream_is_readready()) for the timeout. */ | 56 | when done. And Do a select() (stream_is_readready()) for the timeout. */ |
55 | static int | 57 | /* FIXME: Is it needed? */ |
58 | int | ||
56 | mu_pop3_getline (mu_pop3_t pop3) | 59 | mu_pop3_getline (mu_pop3_t pop3) |
57 | { | 60 | { |
58 | size_t n = 0; | 61 | size_t n; |
59 | size_t total = pop3->io.ptr - pop3->io.buf; | 62 | int status = mu_stream_getline (pop3->carrier, &pop3->rdbuf, |
60 | int status = 0; | 63 | &pop3->rdsize, &n); |
61 | 64 | if (status == 0) | |
62 | /* Must get a full line before bailing out. */ | ||
63 | do | ||
64 | { | ||
65 | /* Timeout with select(), note that we have to reset select() | ||
66 | since on linux tv is modified when error. */ | ||
67 | if (pop3->timeout) | ||
68 | { | 65 | { |
69 | int ready = mu_pop3_carrier_is_ready (pop3->carrier, | ||
70 | MU_STREAM_READY_RD, | ||
71 | pop3->timeout); | ||
72 | if (ready == 0) | ||
73 | return ETIMEDOUT; | ||
74 | } | ||
75 | |||
76 | status = mu_stream_readline (pop3->carrier, | ||
77 | pop3->io.buf + total, | ||
78 | pop3->io.len - total, &n); | ||
79 | if (status != 0) | ||
80 | return status; | ||
81 | |||
82 | /* The server went away: It maybe a timeout and some pop server | ||
83 | does not send the -ERR. Consider this like an error. */ | ||
84 | if (n == 0) | 66 | if (n == 0) |
85 | return EIO; | 67 | return EIO; |
86 | 68 | n = mu_rtrim_class (pop3->rdbuf, MU_CTYPE_SPACE); | |
87 | total += n; | ||
88 | pop3->io.nl = memchr (pop3->io.buf, '\n', total); | ||
89 | if (pop3->io.nl == NULL) /* Do we have a full line. */ | ||
90 | { | ||
91 | /* Allocate a bigger buffer ? */ | ||
92 | if (total >= pop3->io.len - 1) | ||
93 | { | ||
94 | pop3->io.len *= 2; | ||
95 | pop3->io.buf = realloc (pop3->io.buf, pop3->io.len + 1); | ||
96 | if (pop3->io.buf == NULL) | ||
97 | return ENOMEM; | ||
98 | } | ||
99 | } | ||
100 | pop3->io.ptr = pop3->io.buf + total; | ||
101 | } | ||
102 | while (pop3->io.nl == NULL); /* Bail only if we have a complete line. */ | ||
103 | 69 | ||
104 | /* When examining a multi-line response, the client checks to see if the | 70 | /* When examining a multi-line response, the client checks to see if the |
105 | line begins with the termination octet "."(DOT). If yes and if octets | 71 | line begins with the termination octet "."(DOT). If yes and if octets |
106 | other than CRLF follow, the first octet of the line (the termination | 72 | other than CRLF follow, the first octet of the line (the termination |
107 | octet) is stripped away. */ | 73 | octet) is stripped away. */ |
108 | if (total >= 3 && pop3->io.buf[0] == '.') | 74 | if (n >= 2 && |
109 | { | 75 | pop3->rdbuf[0] == '.' && |
110 | if (pop3->io.buf[1] != '\r' && pop3->io.buf[2] != '\n') | 76 | pop3->rdbuf[1] != '\n') |
111 | { | 77 | memmove (pop3->rdbuf, pop3->rdbuf + 1, n); |
112 | memmove (pop3->io.buf, pop3->io.buf + 1, total - 1); | ||
113 | pop3->io.ptr--; | ||
114 | pop3->io.nl--; | ||
115 | } | ||
116 | /* And if CRLF immediately follows the termination character, then | ||
117 | the response from the POP server is ended and the line containing | ||
118 | ".CRLF" is not considered part of the multi-line response. */ | ||
119 | else if (pop3->io.buf[1] == '\r' && pop3->io.buf[2] == '\n') | ||
120 | { | ||
121 | pop3->io.buf[0] = '\0'; | ||
122 | pop3->io.ptr = pop3->io.buf; | ||
123 | pop3->io.nl = NULL; | ||
124 | } | ||
125 | } | ||
126 | /* \r\n --> \n\0, conversion. */ | ||
127 | if (pop3->io.nl > pop3->io.buf) | ||
128 | { | ||
129 | *(pop3->io.nl - 1) = '\n'; | ||
130 | *(pop3->io.nl) = '\0'; | ||
131 | pop3->io.ptr = pop3->io.nl; | ||
132 | } | 78 | } |
133 | return status; | 79 | return status; |
134 | } | 80 | } |
135 | 81 | ||
136 | /* Call pop3_getline() for the dirty work, and consume i.e. put | ||
137 | in the user buffer only buflen. If buflen == 0 or buffer == NULL | ||
138 | nothing is consume, the data is save for another call to pop3_readline() | ||
139 | with a buffer != NULL. | ||
140 | */ | ||
141 | int | ||
142 | mu_pop3_readline (mu_pop3_t pop3, char *buffer, size_t buflen, size_t *pnread) | ||
143 | { | ||
144 | size_t nread = 0; | ||
145 | size_t n = 0; | ||
146 | int status = 0; | ||
147 | |||
148 | /* Do we need to fill up? Yes if no NL or the buffer is empty. */ | ||
149 | if (pop3->carrier && (pop3->io.nl == NULL || pop3->io.ptr == pop3->io.buf)) | ||
150 | { | ||
151 | status = mu_pop3_getline (pop3); | ||
152 | if (status != 0) | ||
153 | return status; | ||
154 | } | ||
155 | |||
156 | /* How much we can copy ? */ | ||
157 | n = pop3->io.ptr - pop3->io.buf; | ||
158 | |||
159 | /* Consume the line? */ | ||
160 | if (buffer && buflen) | ||
161 | { | ||
162 | buflen--; /* For the null. */ | ||
163 | if (buflen) | ||
164 | { | ||
165 | int nleft = buflen - n; | ||
166 | /* We got more then requested. */ | ||
167 | if (nleft < 0) | ||
168 | { | ||
169 | size_t sentinel; | ||
170 | nread = buflen; | ||
171 | sentinel = pop3->io.ptr - (pop3->io.buf + nread); | ||
172 | memcpy (buffer, pop3->io.buf, nread); | ||
173 | memmove (pop3->io.buf, pop3->io.buf + nread, sentinel); | ||
174 | pop3->io.ptr = pop3->io.buf + sentinel; | ||
175 | } | ||
176 | else | ||
177 | { | ||
178 | /* Drain our buffer. */; | ||
179 | nread = n; | ||
180 | memcpy (buffer, pop3->io.buf, nread); | ||
181 | pop3->io.ptr = pop3->io.buf; | ||
182 | /* Clear of all residue. */ | ||
183 | memset (pop3->io.buf, '\0', pop3->io.len); | ||
184 | } | ||
185 | } | ||
186 | buffer[nread] = '\0'; | ||
187 | } | ||
188 | else | ||
189 | nread = n; | ||
190 | |||
191 | if (pnread) | ||
192 | *pnread = nread; | ||
193 | return status; | ||
194 | } | ... | ... |
... | @@ -20,14 +20,19 @@ | ... | @@ -20,14 +20,19 @@ |
20 | # include <config.h> | 20 | # include <config.h> |
21 | #endif | 21 | #endif |
22 | 22 | ||
23 | #include <stdlib.h> | ||
23 | #include <string.h> | 24 | #include <string.h> |
24 | #include <errno.h> | 25 | #include <errno.h> |
26 | #include <mailutils/cctype.h> | ||
27 | #include <mailutils/cstr.h> | ||
25 | #include <mailutils/sys/pop3.h> | 28 | #include <mailutils/sys/pop3.h> |
26 | 29 | ||
30 | #define POP3_DEFERR "-ERR POP3 IO ERROR" | ||
31 | |||
27 | /* If we did not grap the ack already, call pop3_readline() but handle | 32 | /* If we did not grap the ack already, call pop3_readline() but handle |
28 | Nonblocking also. */ | 33 | Nonblocking also. */ |
29 | int | 34 | int |
30 | mu_pop3_response (mu_pop3_t pop3, char *buffer, size_t buflen, size_t *pnread) | 35 | mu_pop3_response (mu_pop3_t pop3, size_t *pnread) |
31 | { | 36 | { |
32 | size_t n = 0; | 37 | size_t n = 0; |
33 | int status = 0; | 38 | int status = 0; |
... | @@ -35,37 +40,33 @@ mu_pop3_response (mu_pop3_t pop3, char *buffer, size_t buflen, size_t *pnread) | ... | @@ -35,37 +40,33 @@ mu_pop3_response (mu_pop3_t pop3, char *buffer, size_t buflen, size_t *pnread) |
35 | if (pop3 == NULL) | 40 | if (pop3 == NULL) |
36 | return EINVAL; | 41 | return EINVAL; |
37 | 42 | ||
38 | if (!pop3->acknowledge) | 43 | if (!MU_POP3_FISSET (pop3, MU_POP3_ACK)) |
39 | { | 44 | { |
40 | size_t len = pop3->ack.len - (pop3->ack.ptr - pop3->ack.buf); | 45 | status = mu_stream_getline (pop3->carrier, &pop3->ackbuf, |
41 | status = mu_pop3_readline (pop3, pop3->ack.ptr, len, &n); | 46 | &pop3->acksize, NULL); |
42 | pop3->ack.ptr += n; | ||
43 | if (status == 0) | 47 | if (status == 0) |
44 | { | 48 | { |
45 | len = pop3->ack.ptr - pop3->ack.buf; | 49 | n = mu_rtrim_class (pop3->ackbuf, MU_CTYPE_SPACE); |
46 | if (len && pop3->ack.buf[len - 1] == '\n') | 50 | MU_POP3_FSET (pop3, MU_POP3_ACK); /* Flag that we have the ack. */ |
47 | pop3->ack.buf[len - 1] = '\0'; | ||
48 | pop3->acknowledge = 1; /* Flag that we have the ack. */ | ||
49 | pop3->ack.ptr = pop3->ack.buf; | ||
50 | } | 51 | } |
51 | else | 52 | else |
52 | { | 53 | { |
53 | /* Provide them with an error. */ | 54 | /* Provide them with an error. */ |
54 | const char *econ = "-ERR POP3 IO ERROR"; | 55 | if (pop3->acksize < sizeof (POP3_DEFERR)) |
55 | n = strlen (econ); | 56 | { |
56 | strcpy (pop3->ack.buf, econ); | 57 | char *p = realloc (pop3->ackbuf, sizeof (POP3_DEFERR)); |
58 | if (p) | ||
59 | { | ||
60 | pop3->ackbuf = p; | ||
61 | pop3->acksize = sizeof (POP3_DEFERR); | ||
57 | } | 62 | } |
58 | } | 63 | } |
59 | else | 64 | if (pop3->ackbuf) |
60 | n = strlen (pop3->ack.buf); | 65 | strncpy (pop3->ackbuf, POP3_DEFERR, pop3->acksize); |
61 | 66 | } | |
62 | if (buffer) | ||
63 | { | ||
64 | buflen--; /* Leave space for the NULL. */ | ||
65 | n = (buflen < n) ? buflen : n; | ||
66 | memcpy (buffer, pop3->ack.buf, n); | ||
67 | buffer[n] = '\0'; | ||
68 | } | 67 | } |
68 | else if (pop3->ackbuf) | ||
69 | n = strlen (pop3->ackbuf); | ||
69 | 70 | ||
70 | if (pnread) | 71 | if (pnread) |
71 | *pnread = n; | 72 | *pnread = n; | ... | ... |
... | @@ -41,25 +41,19 @@ mu_pop3_retr (mu_pop3_t pop3, unsigned int msgno, mu_stream_t *pstream) | ... | @@ -41,25 +41,19 @@ mu_pop3_retr (mu_pop3_t pop3, unsigned int msgno, mu_stream_t *pstream) |
41 | case MU_POP3_NO_STATE: | 41 | case MU_POP3_NO_STATE: |
42 | status = mu_pop3_writeline (pop3, "RETR %d\r\n", msgno); | 42 | status = mu_pop3_writeline (pop3, "RETR %d\r\n", msgno); |
43 | MU_POP3_CHECK_ERROR (pop3, status); | 43 | MU_POP3_CHECK_ERROR (pop3, status); |
44 | mu_pop3_debug_cmd (pop3); | 44 | MU_POP3_FCLR (pop3, MU_POP3_ACK); |
45 | pop3->state = MU_POP3_RETR; | 45 | pop3->state = MU_POP3_RETR; |
46 | 46 | ||
47 | case MU_POP3_RETR: | 47 | case MU_POP3_RETR: |
48 | status = mu_pop3_send (pop3); | 48 | status = mu_pop3_response (pop3, NULL); |
49 | MU_POP3_CHECK_EAGAIN (pop3, status); | 49 | MU_POP3_CHECK_EAGAIN (pop3, status); |
50 | pop3->acknowledge = 0; | ||
51 | pop3->state = MU_POP3_RETR_ACK; | ||
52 | |||
53 | case MU_POP3_RETR_ACK: | ||
54 | status = mu_pop3_response (pop3, NULL, 0, NULL); | ||
55 | MU_POP3_CHECK_EAGAIN (pop3, status); | ||
56 | mu_pop3_debug_ack (pop3); | ||
57 | MU_POP3_CHECK_OK (pop3); | 50 | MU_POP3_CHECK_OK (pop3); |
58 | pop3->state = MU_POP3_RETR_RX; | 51 | pop3->state = MU_POP3_RETR_RX; |
59 | 52 | ||
60 | case MU_POP3_RETR_RX: | 53 | case MU_POP3_RETR_RX: |
61 | status = mu_pop3_stream_create (pop3, pstream); | 54 | status = mu_pop3_stream_create (pop3, pstream); |
62 | MU_POP3_CHECK_ERROR (pop3, status); | 55 | MU_POP3_CHECK_ERROR (pop3, status); |
56 | pop3->state = MU_POP3_NO_STATE; | ||
63 | break; | 57 | break; |
64 | 58 | ||
65 | /* They must deal with the error first by reopening. */ | 59 | /* They must deal with the error first by reopening. */ | ... | ... |
... | @@ -38,19 +38,12 @@ mu_pop3_rset (mu_pop3_t pop3) | ... | @@ -38,19 +38,12 @@ mu_pop3_rset (mu_pop3_t pop3) |
38 | case MU_POP3_NO_STATE: | 38 | case MU_POP3_NO_STATE: |
39 | status = mu_pop3_writeline (pop3, "RSET\r\n"); | 39 | status = mu_pop3_writeline (pop3, "RSET\r\n"); |
40 | MU_POP3_CHECK_ERROR (pop3, status); | 40 | MU_POP3_CHECK_ERROR (pop3, status); |
41 | mu_pop3_debug_cmd (pop3); | 41 | MU_POP3_FCLR (pop3, MU_POP3_ACK); |
42 | pop3->state = MU_POP3_RSET; | 42 | pop3->state = MU_POP3_RSET; |
43 | 43 | ||
44 | case MU_POP3_RSET: | 44 | case MU_POP3_RSET: |
45 | status = mu_pop3_send (pop3); | 45 | status = mu_pop3_response (pop3, NULL); |
46 | MU_POP3_CHECK_EAGAIN (pop3, status); | 46 | MU_POP3_CHECK_EAGAIN (pop3, status); |
47 | pop3->acknowledge = 0; | ||
48 | pop3->state = MU_POP3_RSET_ACK; | ||
49 | |||
50 | case MU_POP3_RSET_ACK: | ||
51 | status = mu_pop3_response (pop3, NULL, 0, NULL); | ||
52 | MU_POP3_CHECK_EAGAIN (pop3, status); | ||
53 | mu_pop3_debug_ack (pop3); | ||
54 | MU_POP3_CHECK_OK (pop3); | 47 | MU_POP3_CHECK_OK (pop3); |
55 | pop3->state = MU_POP3_NO_STATE; | 48 | pop3->state = MU_POP3_NO_STATE; |
56 | break; | 49 | break; | ... | ... |
... | @@ -31,91 +31,23 @@ | ... | @@ -31,91 +31,23 @@ |
31 | #include <errno.h> | 31 | #include <errno.h> |
32 | #include <mailutils/sys/pop3.h> | 32 | #include <mailutils/sys/pop3.h> |
33 | 33 | ||
34 | /* A socket may write less then expected but stream.c:mu_stream_write() will | ||
35 | always try to send the entire buffer unless an error is reported. We have | ||
36 | to cope with nonblocking, it is done by keeping track with the pop3->ptr | ||
37 | pointer if the write failed we keep track and restart where we left. */ | ||
38 | int | ||
39 | mu_pop3_send (mu_pop3_t pop3) | ||
40 | { | ||
41 | int status = 0; | ||
42 | if (pop3->carrier && (pop3->io.ptr > pop3->io.buf)) | ||
43 | { | ||
44 | size_t n = 0; | ||
45 | size_t len = pop3->io.ptr - pop3->io.buf; | ||
46 | |||
47 | /* Timeout with select(), note that we have to reset select() | ||
48 | since on linux tv is modified when error. */ | ||
49 | if (pop3->timeout) | ||
50 | { | ||
51 | int ready = mu_pop3_carrier_is_ready (pop3->carrier, | ||
52 | MU_STREAM_READY_WR, | ||
53 | pop3->timeout); | ||
54 | if (ready == 0) | ||
55 | return ETIMEDOUT; | ||
56 | } | ||
57 | |||
58 | status = mu_stream_write (pop3->carrier, pop3->io.buf, len, &n); | ||
59 | if (n) | ||
60 | { | ||
61 | /* Consume what we sent. */ | ||
62 | memmove (pop3->io.buf, pop3->io.buf + n, len - n); | ||
63 | pop3->io.ptr -= n; | ||
64 | } | ||
65 | } | ||
66 | else | ||
67 | pop3->io.ptr = pop3->io.buf; | ||
68 | return status; | ||
69 | } | ||
70 | |||
71 | /* According to RFC 2449: The maximum length of a command is increased from | ||
72 | 47 characters (4 character command, single space, 40 character argument, | ||
73 | CRLF) to 255 octets, including the terminating CRLF. But we are flexible | ||
74 | on this and realloc() as needed. NOTE: The terminated CRLF is not | ||
75 | included. */ | ||
76 | int | 34 | int |
77 | mu_pop3_writeline (mu_pop3_t pop3, const char *format, ...) | 35 | mu_pop3_writeline (mu_pop3_t pop3, const char *format, ...) |
78 | { | 36 | { |
79 | int len; | 37 | int status; |
80 | va_list ap; | 38 | va_list ap; |
81 | int done = 1; | ||
82 | 39 | ||
83 | va_start(ap, format); | 40 | va_start (ap, format); |
84 | /* C99 says that a conforming implementation of snprintf () should | 41 | status = mu_stream_vprintf (pop3->carrier, format, ap); |
85 | return the number of char that would have been call but many old | ||
86 | GNU/Linux && BSD implementations return -1 on error. Worse, | ||
87 | QnX/Neutrino actually does not put the terminal null char. So | ||
88 | let's try to cope. */ | ||
89 | do | ||
90 | { | ||
91 | len = vsnprintf (pop3->io.buf, pop3->io.len - 1, format, ap); | ||
92 | if (len < 0 || len >= (int)pop3->io.len | ||
93 | || !memchr (pop3->io.buf, '\0', len + 1)) | ||
94 | { | ||
95 | pop3->io.len *= 2; | ||
96 | pop3->io.buf = realloc (pop3->io.buf, pop3->io.len); | ||
97 | if (pop3->io.buf == NULL) | ||
98 | return ENOMEM; | ||
99 | done = 0; | ||
100 | } | ||
101 | else | ||
102 | done = 1; | ||
103 | } | ||
104 | while (!done); | ||
105 | va_end(ap); | 42 | va_end(ap); |
106 | pop3->io.ptr = pop3->io.buf + len; | 43 | return status; |
107 | return 0; | ||
108 | } | 44 | } |
109 | 45 | ||
110 | int | 46 | int |
111 | mu_pop3_sendline (mu_pop3_t pop3, const char *line) | 47 | mu_pop3_sendline (mu_pop3_t pop3, const char *line) |
112 | { | 48 | { |
113 | if (line) | 49 | if (line) |
114 | { | 50 | return mu_stream_write (pop3->carrier, line, strlen (line), NULL); |
115 | int status = mu_pop3_writeline (pop3, line); | 51 | return mu_stream_flush (pop3->carrier); |
116 | if (status) | ||
117 | return status; | ||
118 | } | ||
119 | return mu_pop3_send (pop3); | ||
120 | } | 52 | } |
121 | 53 | ... | ... |
... | @@ -42,26 +42,20 @@ mu_pop3_stat (mu_pop3_t pop3, unsigned *msg_count, size_t *size) | ... | @@ -42,26 +42,20 @@ mu_pop3_stat (mu_pop3_t pop3, unsigned *msg_count, size_t *size) |
42 | case MU_POP3_NO_STATE: | 42 | case MU_POP3_NO_STATE: |
43 | status = mu_pop3_writeline (pop3, "STAT\r\n"); | 43 | status = mu_pop3_writeline (pop3, "STAT\r\n"); |
44 | MU_POP3_CHECK_ERROR (pop3, status); | 44 | MU_POP3_CHECK_ERROR (pop3, status); |
45 | mu_pop3_debug_cmd (pop3); | 45 | MU_POP3_FCLR (pop3, MU_POP3_ACK); |
46 | pop3->state = MU_POP3_STAT; | 46 | pop3->state = MU_POP3_STAT; |
47 | 47 | ||
48 | case MU_POP3_STAT: | 48 | case MU_POP3_STAT: |
49 | status = mu_pop3_send (pop3); | 49 | status = mu_pop3_response (pop3, NULL); |
50 | MU_POP3_CHECK_EAGAIN (pop3, status); | 50 | MU_POP3_CHECK_EAGAIN (pop3, status); |
51 | pop3->acknowledge = 0; | ||
52 | pop3->state = MU_POP3_STAT_ACK; | ||
53 | |||
54 | case MU_POP3_STAT_ACK: | ||
55 | status = mu_pop3_response (pop3, NULL, 0, NULL); | ||
56 | MU_POP3_CHECK_EAGAIN (pop3, status); | ||
57 | mu_pop3_debug_ack (pop3); | ||
58 | MU_POP3_CHECK_OK (pop3); | 51 | MU_POP3_CHECK_OK (pop3); |
59 | pop3->state = MU_POP3_NO_STATE; | 52 | pop3->state = MU_POP3_NO_STATE; |
60 | 53 | ||
61 | /* Parse the answer. */ | 54 | /* Parse the answer. */ |
62 | *msg_count = 0; | 55 | *msg_count = 0; |
63 | lv = 0; | 56 | lv = 0; |
64 | sscanf (pop3->ack.buf, "+OK %d %lu", msg_count, &lv); | 57 | /* FIXME: Error checking */ |
58 | sscanf (pop3->ackbuf, "+OK %d %lu", msg_count, &lv); | ||
65 | *size = lv; | 59 | *size = lv; |
66 | break; | 60 | break; |
67 | 61 | ... | ... |
... | @@ -25,9 +25,29 @@ | ... | @@ -25,9 +25,29 @@ |
25 | #include <string.h> | 25 | #include <string.h> |
26 | #include <errno.h> | 26 | #include <errno.h> |
27 | 27 | ||
28 | #include <mailutils/pop3.h> | ||
28 | #include <mailutils/sys/pop3.h> | 29 | #include <mailutils/sys/pop3.h> |
29 | #include <mailutils/tls.h> | 30 | #include <mailutils/tls.h> |
30 | #include <mailutils/md5.h> | 31 | #include <mailutils/list.h> |
32 | |||
33 | static int | ||
34 | pop3_swap_streams (mu_pop3_t pop3, mu_stream_t *streams) | ||
35 | { | ||
36 | int rc; | ||
37 | |||
38 | if (MU_POP3_FISSET (pop3, MU_POP3_TRACE)) | ||
39 | rc = mu_stream_ioctl (pop3->carrier, MU_IOCTL_SWAP_STREAM, streams); | ||
40 | else if (streams[0] != streams[1]) | ||
41 | rc = EINVAL; | ||
42 | else | ||
43 | { | ||
44 | mu_stream_t str = streams[0]; | ||
45 | streams[0] = streams[1] = pop3->carrier; | ||
46 | pop3->carrier = str; | ||
47 | rc = 0; | ||
48 | } | ||
49 | return rc; | ||
50 | } | ||
31 | 51 | ||
32 | /* | 52 | /* |
33 | * STLS | 53 | * STLS |
... | @@ -38,48 +58,42 @@ mu_pop3_stls (mu_pop3_t pop3) | ... | @@ -38,48 +58,42 @@ mu_pop3_stls (mu_pop3_t pop3) |
38 | { | 58 | { |
39 | #ifdef WITH_TLS | 59 | #ifdef WITH_TLS |
40 | int status; | 60 | int status; |
61 | mu_stream_t tlsstream, streams[2]; | ||
41 | 62 | ||
42 | /* Sanity checks. */ | 63 | /* Sanity checks. */ |
43 | if (pop3 == NULL) | 64 | if (pop3 == NULL) |
44 | { | ||
45 | return EINVAL; | 65 | return EINVAL; |
46 | } | ||
47 | 66 | ||
48 | switch (pop3->state) | 67 | switch (pop3->state) |
49 | { | 68 | { |
50 | case MU_POP3_NO_STATE: | 69 | case MU_POP3_NO_STATE: |
51 | status = mu_pop3_writeline (pop3, "STLS\r\n"); | 70 | status = mu_pop3_writeline (pop3, "STLS\r\n"); |
52 | MU_POP3_CHECK_ERROR (pop3, status); | 71 | MU_POP3_CHECK_ERROR (pop3, status); |
53 | mu_pop3_debug_cmd (pop3); | 72 | MU_POP3_FCLR (pop3, MU_POP3_ACK); |
54 | pop3->state = MU_POP3_STLS; | 73 | pop3->state = MU_POP3_STLS; |
55 | 74 | ||
56 | case MU_POP3_STLS: | 75 | case MU_POP3_STLS: |
57 | status = mu_pop3_send (pop3); | 76 | status = mu_pop3_response (pop3, NULL); |
58 | MU_POP3_CHECK_EAGAIN (pop3, status); | ||
59 | pop3->acknowledge = 0; | ||
60 | pop3->state = MU_POP3_STLS_ACK; | ||
61 | |||
62 | case MU_POP3_STLS_ACK: | ||
63 | { | ||
64 | mu_stream_t tls_stream; | ||
65 | status = mu_pop3_response (pop3, NULL, 0, NULL); | ||
66 | MU_POP3_CHECK_EAGAIN (pop3, status); | 77 | MU_POP3_CHECK_EAGAIN (pop3, status); |
67 | mu_pop3_debug_ack (pop3); | ||
68 | MU_POP3_CHECK_OK (pop3); | 78 | MU_POP3_CHECK_OK (pop3); |
69 | status = mu_tls_client_stream_create (&tls_stream, | ||
70 | pop3->carrier, | ||
71 | pop3->carrier, 0); | ||
72 | MU_POP3_CHECK_ERROR (pop3, status); | ||
73 | pop3->carrier = tls_stream; | ||
74 | pop3->state = MU_POP3_STLS_CONNECT; | 79 | pop3->state = MU_POP3_STLS_CONNECT; |
75 | break; | ||
76 | } | ||
77 | 80 | ||
78 | case MU_POP3_STLS_CONNECT: | 81 | case MU_POP3_STLS_CONNECT: |
79 | status = mu_stream_open (pop3->carrier); | 82 | streams[0] = streams[1] = NULL; |
83 | status = pop3_swap_streams (pop3, streams); | ||
80 | MU_POP3_CHECK_EAGAIN (pop3, status); | 84 | MU_POP3_CHECK_EAGAIN (pop3, status); |
85 | status = mu_tls_client_stream_create (&tlsstream, | ||
86 | streams[0], streams[1], 0); | ||
87 | MU_POP3_CHECK_EAGAIN (pop3, status); | ||
88 | status = mu_stream_open (tlsstream); | ||
89 | MU_POP3_CHECK_EAGAIN (pop3, status); | ||
90 | streams[0] = streams[1] = tlsstream; | ||
91 | status = pop3_swap_streams (pop3, streams); | ||
92 | MU_POP3_CHECK_EAGAIN (pop3, status); | ||
93 | /* Invalidate the capability list */ | ||
94 | mu_list_destroy (&pop3->capa); | ||
81 | pop3->state = MU_POP3_NO_STATE; | 95 | pop3->state = MU_POP3_NO_STATE; |
82 | break; | 96 | return 0; |
83 | 97 | ||
84 | /* They must deal with the error first by reopening. */ | 98 | /* They must deal with the error first by reopening. */ |
85 | case MU_POP3_ERROR: | 99 | case MU_POP3_ERROR: |
... | @@ -93,7 +107,6 @@ mu_pop3_stls (mu_pop3_t pop3) | ... | @@ -93,7 +107,6 @@ mu_pop3_stls (mu_pop3_t pop3) |
93 | 107 | ||
94 | return status; | 108 | return status; |
95 | #else | 109 | #else |
96 | (void)pop3; | ||
97 | return ENOTSUP; | 110 | return ENOTSUP; |
98 | #endif | 111 | #endif |
99 | } | 112 | } | ... | ... |
... | @@ -23,124 +23,242 @@ | ... | @@ -23,124 +23,242 @@ |
23 | #include <string.h> | 23 | #include <string.h> |
24 | #include <errno.h> | 24 | #include <errno.h> |
25 | #include <stdlib.h> | 25 | #include <stdlib.h> |
26 | #include <mailutils/filter.h> | ||
27 | #include <mailutils/stream.h> | ||
28 | #include <mailutils/sys/stream.h> | ||
26 | #include <mailutils/sys/pop3.h> | 29 | #include <mailutils/sys/pop3.h> |
27 | 30 | ||
28 | /* Implementation of the stream for TOP and RETR. */ | 31 | /* Implementation of the stream for TOP and RETR. */ |
29 | struct mu_pop3_stream | 32 | struct mu_pop3_stream |
30 | { | 33 | { |
34 | struct _mu_stream stream; | ||
31 | mu_pop3_t pop3; | 35 | mu_pop3_t pop3; |
32 | int done; | 36 | int done; |
33 | }; | 37 | }; |
34 | 38 | ||
35 | static void | 39 | enum pop3_decode_state |
36 | mu_pop3_stream_destroy (mu_stream_t stream) | ||
37 | { | ||
38 | struct mu_pop3_stream *pop3_stream = mu_stream_get_owner (stream); | ||
39 | if (pop3_stream) | ||
40 | { | 40 | { |
41 | free (pop3_stream); | 41 | pds_init, /* initial state */ |
42 | } | 42 | pds_cr, /* prev. char was \r */ |
43 | } | 43 | pds_crlf, /* 2 prev. char were \r\n */ |
44 | pds_dot, /* 3 prev. chars were \r\n. */ | ||
45 | pds_dotcr, /* 4 prev. chars were \r\n.\r */ | ||
46 | pds_end /* final state, a \r\n.\r\n seen. */ | ||
47 | }; | ||
44 | 48 | ||
45 | static int | 49 | static int |
46 | mu_pop3_stream_read (mu_stream_t stream, char *buf, size_t buflen, mu_off_t offset, size_t *pn) | 50 | newstate (int state, int c) |
47 | { | 51 | { |
48 | struct mu_pop3_stream *pop3_stream = mu_stream_get_owner (stream); | 52 | switch (state) |
49 | size_t n = 0; | 53 | { |
50 | int status = 0; | 54 | case pds_init: |
51 | char *p = buf; | 55 | switch (c) |
56 | { | ||
57 | case '\r': | ||
58 | return pds_cr; | ||
59 | } | ||
60 | break; | ||
52 | 61 | ||
53 | (void)offset; | 62 | case pds_cr: |
54 | if (pop3_stream) | 63 | switch (c) |
55 | { | 64 | { |
56 | if (!pop3_stream->done) | 65 | case '\r': |
66 | return pds_cr; | ||
67 | case '\n': | ||
68 | return pds_crlf; | ||
69 | } | ||
70 | break; | ||
71 | |||
72 | case pds_crlf: | ||
73 | switch (c) | ||
57 | { | 74 | { |
58 | do | 75 | case '\r': |
76 | return pds_cr; | ||
77 | case '.': | ||
78 | return pds_dot; | ||
79 | } | ||
80 | |||
81 | case pds_dot: | ||
82 | switch (c) | ||
59 | { | 83 | { |
60 | size_t nread = 0; | 84 | case '\r': |
85 | return pds_dotcr; | ||
86 | } | ||
87 | break; | ||
61 | 88 | ||
62 | /* The pop3_readline () function will always read one less to | 89 | case pds_dotcr: |
63 | be able to null terminate the buffer, this will cause | 90 | switch (c) |
64 | serious grief for mu_stream_read() where it is legitimate to | ||
65 | have a buffer of 1 char. So we must catch it here. */ | ||
66 | if (buflen == 1) | ||
67 | { | 91 | { |
68 | char buffer[2]; | 92 | case '\n': |
69 | *buffer = '\0'; | 93 | return pds_end; |
70 | status = mu_pop3_readline (pop3_stream->pop3, buffer, 2, &nread); | ||
71 | *p = *buffer; | ||
72 | } | 94 | } |
73 | else | 95 | } |
74 | status = mu_pop3_readline (pop3_stream->pop3, p, buflen, &nread); | 96 | return pds_init; |
97 | } | ||
98 | |||
99 | /* Move min(isize,osize) bytes from iptr to optr, replacing each \r\n | ||
100 | with \n. */ | ||
101 | static enum mu_filter_result | ||
102 | _pop3_decoder (void *xd, | ||
103 | enum mu_filter_command cmd, | ||
104 | struct mu_filter_io *iobuf) | ||
105 | { | ||
106 | int *pstate = xd; | ||
107 | size_t i, j; | ||
108 | const unsigned char *iptr; | ||
109 | size_t isize; | ||
110 | char *optr; | ||
111 | size_t osize; | ||
112 | |||
113 | switch (cmd) | ||
114 | { | ||
115 | case mu_filter_init: | ||
116 | *pstate = pds_init; | ||
117 | return mu_filter_ok; | ||
118 | |||
119 | case mu_filter_done: | ||
120 | return mu_filter_ok; | ||
121 | |||
122 | default: | ||
123 | break; | ||
124 | } | ||
125 | |||
126 | iptr = (const unsigned char *) iobuf->input; | ||
127 | isize = iobuf->isize; | ||
128 | optr = iobuf->output; | ||
129 | osize = iobuf->osize; | ||
130 | |||
131 | for (i = j = 0; *pstate != pds_end && i < isize && j < osize; i++) | ||
132 | { | ||
133 | unsigned char c = *iptr++; | ||
75 | 134 | ||
76 | if (status != 0) | 135 | if (c == '\r') |
136 | { | ||
137 | if (i + 1 == isize) | ||
77 | break; | 138 | break; |
78 | if (nread == 0) | 139 | *pstate = newstate (*pstate, c); |
140 | if (*iptr == '\n') | ||
141 | continue; | ||
142 | } | ||
143 | else if (c == '.' && *pstate == pds_crlf) | ||
79 | { | 144 | { |
80 | pop3_stream->pop3->state = MU_POP3_NO_STATE; | 145 | if (i + 1 == isize) |
81 | pop3_stream->done = 1; | ||
82 | break; | 146 | break; |
147 | *pstate = newstate (*pstate, c); | ||
148 | if (*iptr != '\r') | ||
149 | continue; | ||
83 | } | 150 | } |
84 | n += nread; | 151 | else |
85 | buflen -= nread; | 152 | *pstate = newstate (*pstate, c); |
86 | p += nread; | 153 | optr[j++] = c; |
87 | } | 154 | } |
88 | while (buflen > 0); | 155 | |
156 | if (*pstate == pds_end) | ||
157 | iobuf->eof = 1; | ||
158 | iobuf->isize = i; | ||
159 | iobuf->osize = j; | ||
160 | return mu_filter_ok; | ||
161 | } | ||
162 | |||
163 | static int | ||
164 | mu_pop3_filter_create (mu_stream_t *pstream, mu_stream_t stream) | ||
165 | { | ||
166 | int *state = malloc (sizeof (*state)); | ||
167 | if (!state) | ||
168 | return ENOMEM; | ||
169 | return mu_filter_stream_create (pstream, stream, | ||
170 | MU_FILTER_DECODE, | ||
171 | _pop3_decoder, state, | ||
172 | MU_STREAM_READ); | ||
173 | } | ||
174 | |||
175 | |||
176 | static int | ||
177 | _mu_pop3_read (struct _mu_stream *str, char *buf, size_t bufsize, | ||
178 | size_t *pnread) | ||
179 | { | ||
180 | struct mu_pop3_stream *sp = (struct mu_pop3_stream *)str; | ||
181 | mu_pop3_t pop3 = sp->pop3; | ||
182 | size_t nread; | ||
183 | int status = 0; | ||
184 | |||
185 | if (sp->done) | ||
186 | nread = 0; | ||
187 | else | ||
188 | { | ||
189 | status = mu_stream_read (pop3->carrier, buf, bufsize, &nread); | ||
190 | if (status == 0 && nread == 0) | ||
191 | { | ||
192 | pop3->state = MU_POP3_NO_STATE; | ||
193 | sp->done = 1; | ||
89 | } | 194 | } |
90 | } | 195 | } |
91 | if (pn) | 196 | *pnread = nread; |
92 | *pn = n; | ||
93 | return status; | 197 | return status; |
94 | } | 198 | } |
95 | 199 | ||
96 | static int | 200 | static int |
97 | mu_pop3_stream_readline (mu_stream_t stream, char *buf, size_t buflen, mu_off_t offset, size_t *pn) | 201 | _mu_pop3_readdelim (struct _mu_stream *str, char *buf, size_t bufsize, |
202 | int delim, size_t *pnread) | ||
98 | { | 203 | { |
99 | struct mu_pop3_stream *pop3_stream = mu_stream_get_owner (stream); | 204 | struct mu_pop3_stream *sp = (struct mu_pop3_stream *)str; |
100 | size_t n = 0; | 205 | mu_pop3_t pop3 = sp->pop3; |
206 | size_t nread; | ||
101 | int status = 0; | 207 | int status = 0; |
102 | 208 | ||
103 | (void)offset; | 209 | if (sp->done) |
104 | if (pop3_stream) | 210 | nread = 0; |
105 | { | 211 | else |
106 | if (!pop3_stream->done) | ||
107 | { | 212 | { |
108 | status = mu_pop3_readline (pop3_stream->pop3, buf, buflen, &n); | 213 | status = mu_stream_readdelim (pop3->carrier, buf, bufsize, delim, |
109 | if (n == 0) | 214 | &nread); |
215 | if (status == 0 && nread == 0) | ||
110 | { | 216 | { |
111 | pop3_stream->pop3->state = MU_POP3_NO_STATE; | 217 | pop3->state = MU_POP3_NO_STATE; |
112 | pop3_stream->done = 1; | 218 | sp->done = 1; |
113 | } | 219 | } |
114 | } | 220 | } |
115 | } | 221 | *pnread = nread; |
116 | if (pn) | ||
117 | *pn = n; | ||
118 | return status; | 222 | return status; |
119 | } | 223 | } |
120 | 224 | ||
225 | static int | ||
226 | _mu_pop3_flush (struct _mu_stream *str) | ||
227 | { | ||
228 | struct mu_pop3_stream *sp = (struct mu_pop3_stream *)str; | ||
229 | mu_pop3_t pop3 = sp->pop3; | ||
230 | return mu_stream_flush (pop3->carrier); | ||
231 | } | ||
232 | |||
233 | static int | ||
234 | _mu_pop3_wait (struct _mu_stream *str, int *pflags, struct timeval *tvp) | ||
235 | { | ||
236 | struct mu_pop3_stream *sp = (struct mu_pop3_stream *)str; | ||
237 | mu_pop3_t pop3 = sp->pop3; | ||
238 | return mu_stream_wait (pop3->carrier, pflags, tvp); | ||
239 | } | ||
240 | |||
121 | int | 241 | int |
122 | mu_pop3_stream_create (mu_pop3_t pop3, mu_stream_t *pstream) | 242 | mu_pop3_stream_create (mu_pop3_t pop3, mu_stream_t *pstream) |
123 | { | 243 | { |
124 | struct mu_pop3_stream *pop3_stream; | 244 | struct mu_pop3_stream *sp; |
245 | mu_stream_t str; | ||
125 | int status; | 246 | int status; |
126 | 247 | ||
127 | pop3_stream = malloc (sizeof *pop3_stream); | 248 | sp = (struct mu_pop3_stream *) _mu_stream_create (sizeof (*sp), |
128 | if (pop3_stream == NULL) | 249 | MU_STREAM_READ); |
250 | if (!sp) | ||
129 | return ENOMEM; | 251 | return ENOMEM; |
252 | sp->stream.read = _mu_pop3_read; | ||
253 | sp->stream.readdelim = _mu_pop3_readdelim; | ||
254 | sp->stream.flush = _mu_pop3_flush; | ||
255 | sp->stream.wait = _mu_pop3_wait; | ||
256 | sp->pop3 = pop3; | ||
257 | sp->done = 0; | ||
258 | str = (mu_stream_t) sp; | ||
259 | mu_stream_set_buffer (str, mu_buffer_line, 1024); | ||
130 | 260 | ||
131 | pop3_stream->pop3 = pop3; | 261 | status = mu_pop3_filter_create (pstream, str); |
132 | pop3_stream->done = 0; | 262 | mu_stream_unref (str); |
133 | |||
134 | status = mu_stream_create (pstream, MU_STREAM_READ, pop3_stream); | ||
135 | if (status != 0) | ||
136 | { | ||
137 | free (pop3_stream); | ||
138 | return status; | 263 | return status; |
139 | } | ||
140 | |||
141 | mu_stream_set_read (*pstream, mu_pop3_stream_read, pop3_stream); | ||
142 | mu_stream_set_readline (*pstream, mu_pop3_stream_readline, pop3_stream); | ||
143 | mu_stream_set_destroy (*pstream, mu_pop3_stream_destroy, pop3_stream); | ||
144 | |||
145 | return 0; | ||
146 | } | 264 | } | ... | ... |
... | @@ -26,7 +26,8 @@ | ... | @@ -26,7 +26,8 @@ |
26 | #include <mailutils/sys/pop3.h> | 26 | #include <mailutils/sys/pop3.h> |
27 | 27 | ||
28 | int | 28 | int |
29 | mu_pop3_top (mu_pop3_t pop3, unsigned msgno, unsigned int lines, mu_stream_t *pstream) | 29 | mu_pop3_top (mu_pop3_t pop3, unsigned msgno, unsigned int lines, |
30 | mu_stream_t *pstream) | ||
30 | { | 31 | { |
31 | int status; | 32 | int status; |
32 | 33 | ||
... | @@ -40,25 +41,19 @@ mu_pop3_top (mu_pop3_t pop3, unsigned msgno, unsigned int lines, mu_stream_t *ps | ... | @@ -40,25 +41,19 @@ mu_pop3_top (mu_pop3_t pop3, unsigned msgno, unsigned int lines, mu_stream_t *ps |
40 | case MU_POP3_NO_STATE: | 41 | case MU_POP3_NO_STATE: |
41 | status = mu_pop3_writeline (pop3, "TOP %d %d\r\n", msgno, lines); | 42 | status = mu_pop3_writeline (pop3, "TOP %d %d\r\n", msgno, lines); |
42 | MU_POP3_CHECK_ERROR (pop3, status); | 43 | MU_POP3_CHECK_ERROR (pop3, status); |
43 | mu_pop3_debug_cmd (pop3); | 44 | MU_POP3_FCLR (pop3, MU_POP3_ACK); |
44 | pop3->state = MU_POP3_TOP; | 45 | pop3->state = MU_POP3_TOP; |
45 | 46 | ||
46 | case MU_POP3_TOP: | 47 | case MU_POP3_TOP: |
47 | status = mu_pop3_send (pop3); | 48 | status = mu_pop3_response (pop3, NULL); |
48 | MU_POP3_CHECK_EAGAIN (pop3, status); | 49 | MU_POP3_CHECK_EAGAIN (pop3, status); |
49 | pop3->acknowledge = 0; | ||
50 | pop3->state = MU_POP3_TOP_ACK; | ||
51 | |||
52 | case MU_POP3_TOP_ACK: | ||
53 | status = mu_pop3_response (pop3, NULL, 0, NULL); | ||
54 | MU_POP3_CHECK_EAGAIN (pop3, status); | ||
55 | mu_pop3_debug_ack (pop3); | ||
56 | MU_POP3_CHECK_OK (pop3); | 50 | MU_POP3_CHECK_OK (pop3); |
57 | pop3->state = MU_POP3_TOP_RX; | 51 | pop3->state = MU_POP3_TOP_RX; |
58 | 52 | ||
59 | case MU_POP3_TOP_RX: | 53 | case MU_POP3_TOP_RX: |
60 | status = mu_pop3_stream_create (pop3, pstream); | 54 | status = mu_pop3_stream_create (pop3, pstream); |
61 | MU_POP3_CHECK_ERROR (pop3, status); | 55 | MU_POP3_CHECK_ERROR (pop3, status); |
56 | pop3->state = MU_POP3_NO_STATE; | ||
62 | break; | 57 | break; |
63 | 58 | ||
64 | /* They must deal with the error first by reopening. */ | 59 | /* They must deal with the error first by reopening. */ | ... | ... |
libproto/pop/pop3_trace.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 1999, 2000, 2001, 2007, 2009, 2010 Free Software | ||
3 | Foundation, Inc. | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Lesser General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 3 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General | ||
16 | Public License along with this library; if not, write to the | ||
17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301 USA */ | ||
19 | |||
20 | #ifdef HAVE_CONFIG_H | ||
21 | # include <config.h> | ||
22 | #endif | ||
23 | |||
24 | #include <string.h> | ||
25 | #include <errno.h> | ||
26 | #include <stdio.h> | ||
27 | #include <mailutils/error.h> | ||
28 | #include <mailutils/nls.h> | ||
29 | #include <mailutils/stream.h> | ||
30 | #include <mailutils/sys/pop3.h> | ||
31 | |||
32 | static const char *pop3_prefix[] = { | ||
33 | "S: ", "C: " | ||
34 | }; | ||
35 | |||
36 | int | ||
37 | _mu_pop3_trace_enable (mu_pop3_t pop3) | ||
38 | { | ||
39 | int rc = 0; | ||
40 | mu_debug_t debug; | ||
41 | mu_stream_t dstr, xstr; | ||
42 | |||
43 | if (!pop3->carrier) | ||
44 | { | ||
45 | MU_POP3_FSET (pop3, MU_POP3_TRACE); | ||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | mu_diag_get_debug (&debug); | ||
50 | |||
51 | rc = mu_dbgstream_create (&dstr, debug, MU_DIAG_DEBUG, 0); | ||
52 | if (rc) | ||
53 | mu_error (_("cannot create debug stream; transcript disabled: %s"), | ||
54 | mu_strerror (rc)); | ||
55 | else | ||
56 | { | ||
57 | rc = mu_xscript_stream_create (&xstr, pop3->carrier, dstr, | ||
58 | pop3_prefix); | ||
59 | if (rc) | ||
60 | mu_error (_("cannot create transcript stream: %s"), | ||
61 | mu_strerror (rc)); | ||
62 | else | ||
63 | { | ||
64 | mu_stream_unref (pop3->carrier); | ||
65 | pop3->carrier = xstr; | ||
66 | MU_POP3_FSET (pop3, MU_POP3_TRACE); | ||
67 | } | ||
68 | } | ||
69 | |||
70 | return rc; | ||
71 | } | ||
72 | |||
73 | int | ||
74 | _mu_pop3_trace_disable (mu_pop3_t pop3) | ||
75 | { | ||
76 | mu_stream_t xstr = pop3->carrier; | ||
77 | mu_stream_t stream[2]; | ||
78 | int rc; | ||
79 | |||
80 | if (!xstr) | ||
81 | return 0; | ||
82 | |||
83 | rc = mu_stream_ioctl (xstr, MU_IOCTL_GET_TRANSPORT, stream); | ||
84 | if (rc) | ||
85 | return rc; | ||
86 | |||
87 | pop3->carrier = stream[0]; | ||
88 | mu_stream_destroy (&xstr); | ||
89 | MU_POP3_FCLR (pop3, MU_POP3_TRACE); | ||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | int | ||
94 | mu_pop3_trace (mu_pop3_t pop3, int op) | ||
95 | { | ||
96 | int trace_on = MU_POP3_FISSET (pop3, MU_POP3_TRACE); | ||
97 | |||
98 | switch (op) | ||
99 | { | ||
100 | case MU_POP3_TRACE_SET: | ||
101 | if (trace_on) | ||
102 | return MU_ERR_EXISTS; | ||
103 | return _mu_pop3_trace_enable (pop3); | ||
104 | |||
105 | case MU_POP3_TRACE_CLR: | ||
106 | if (!trace_on) | ||
107 | return MU_ERR_NOENT; | ||
108 | return _mu_pop3_trace_disable (pop3); | ||
109 | |||
110 | case MU_POP3_TRACE_QRY: | ||
111 | if (!trace_on) | ||
112 | return MU_ERR_NOENT; | ||
113 | return 0; | ||
114 | } | ||
115 | return EINVAL; | ||
116 | } | ||
117 | |||
118 |
... | @@ -30,6 +30,7 @@ int | ... | @@ -30,6 +30,7 @@ int |
30 | mu_pop3_uidl (mu_pop3_t pop3, unsigned int msgno, char **uidl) | 30 | mu_pop3_uidl (mu_pop3_t pop3, unsigned int msgno, char **uidl) |
31 | { | 31 | { |
32 | int status; | 32 | int status; |
33 | char *space; | ||
33 | 34 | ||
34 | if (pop3 == NULL) | 35 | if (pop3 == NULL) |
35 | return EINVAL; | 36 | return EINVAL; |
... | @@ -41,29 +42,21 @@ mu_pop3_uidl (mu_pop3_t pop3, unsigned int msgno, char **uidl) | ... | @@ -41,29 +42,21 @@ mu_pop3_uidl (mu_pop3_t pop3, unsigned int msgno, char **uidl) |
41 | case MU_POP3_NO_STATE: | 42 | case MU_POP3_NO_STATE: |
42 | status = mu_pop3_writeline (pop3, "UIDL %d\r\n", msgno); | 43 | status = mu_pop3_writeline (pop3, "UIDL %d\r\n", msgno); |
43 | MU_POP3_CHECK_ERROR (pop3, status); | 44 | MU_POP3_CHECK_ERROR (pop3, status); |
44 | mu_pop3_debug_cmd (pop3); | 45 | MU_POP3_FCLR (pop3, MU_POP3_ACK); |
45 | pop3->state = MU_POP3_UIDL; | 46 | pop3->state = MU_POP3_UIDL; |
46 | 47 | ||
47 | case MU_POP3_UIDL: | 48 | case MU_POP3_UIDL: |
48 | status = mu_pop3_send (pop3); | 49 | status = mu_pop3_response (pop3, NULL); |
49 | MU_POP3_CHECK_EAGAIN (pop3, status); | ||
50 | pop3->acknowledge = 0; | ||
51 | pop3->state = MU_POP3_UIDL_ACK; | ||
52 | |||
53 | case MU_POP3_UIDL_ACK: | ||
54 | status = mu_pop3_response (pop3, NULL, 0, NULL); | ||
55 | MU_POP3_CHECK_EAGAIN (pop3, status); | 50 | MU_POP3_CHECK_EAGAIN (pop3, status); |
56 | mu_pop3_debug_ack (pop3); | ||
57 | MU_POP3_CHECK_OK (pop3); | 51 | MU_POP3_CHECK_OK (pop3); |
58 | pop3->state = MU_POP3_NO_STATE; | 52 | pop3->state = MU_POP3_NO_STATE; |
59 | 53 | ||
60 | *uidl = NULL; | 54 | *uidl = NULL; |
61 | { | 55 | |
62 | char *space; | ||
63 | /* Format: +OK msgno uidlstring */ | 56 | /* Format: +OK msgno uidlstring */ |
64 | 57 | ||
65 | /* Pass the "+OK". */ | 58 | /* Pass the "+OK". */ |
66 | space = strchr (pop3->ack.buf, ' '); | 59 | space = strchr (pop3->ackbuf, ' '); |
67 | if (space) | 60 | if (space) |
68 | { | 61 | { |
69 | /* Skip spaces. */ | 62 | /* Skip spaces. */ |
... | @@ -86,7 +79,7 @@ mu_pop3_uidl (mu_pop3_t pop3, unsigned int msgno, char **uidl) | ... | @@ -86,7 +79,7 @@ mu_pop3_uidl (mu_pop3_t pop3, unsigned int msgno, char **uidl) |
86 | memcpy (*uidl, space, len); | 79 | memcpy (*uidl, space, len); |
87 | } | 80 | } |
88 | } | 81 | } |
89 | } | 82 | |
90 | if (*uidl == NULL) /* What can we do? */ | 83 | if (*uidl == NULL) /* What can we do? */ |
91 | { | 84 | { |
92 | *uidl = malloc (1); | 85 | *uidl = malloc (1); | ... | ... |
... | @@ -40,26 +40,20 @@ mu_pop3_uidl_all (mu_pop3_t pop3, mu_iterator_t *piterator) | ... | @@ -40,26 +40,20 @@ mu_pop3_uidl_all (mu_pop3_t pop3, mu_iterator_t *piterator) |
40 | case MU_POP3_NO_STATE: | 40 | case MU_POP3_NO_STATE: |
41 | status = mu_pop3_writeline (pop3, "UIDL\r\n"); | 41 | status = mu_pop3_writeline (pop3, "UIDL\r\n"); |
42 | MU_POP3_CHECK_ERROR (pop3, status); | 42 | MU_POP3_CHECK_ERROR (pop3, status); |
43 | mu_pop3_debug_cmd (pop3); | 43 | MU_POP3_FCLR (pop3, MU_POP3_ACK); |
44 | pop3->state = MU_POP3_UIDL; | 44 | pop3->state = MU_POP3_UIDL; |
45 | 45 | ||
46 | case MU_POP3_UIDL: | 46 | case MU_POP3_UIDL: |
47 | status = mu_pop3_send (pop3); | 47 | status = mu_pop3_response (pop3, NULL); |
48 | MU_POP3_CHECK_EAGAIN (pop3, status); | 48 | MU_POP3_CHECK_EAGAIN (pop3, status); |
49 | pop3->acknowledge = 0; | ||
50 | pop3->state = MU_POP3_UIDL_ACK; | ||
51 | |||
52 | case MU_POP3_UIDL_ACK: | ||
53 | status = mu_pop3_response (pop3, NULL, 0, NULL); | ||
54 | MU_POP3_CHECK_EAGAIN (pop3, status); | ||
55 | mu_pop3_debug_ack (pop3); | ||
56 | MU_POP3_CHECK_OK (pop3); | 49 | MU_POP3_CHECK_OK (pop3); |
57 | status = mu_pop3_iterator_create (pop3, piterator); | 50 | status = mu_pop3_iterator_create (pop3, piterator); |
58 | MU_POP3_CHECK_ERROR (pop3, status); | 51 | MU_POP3_CHECK_ERROR (pop3, status); |
59 | pop3->state = MU_POP3_UIDL_RX; | 52 | pop3->state = MU_POP3_UIDL_RX; |
60 | 53 | ||
61 | case MU_POP3_UIDL_RX: | 54 | case MU_POP3_UIDL_RX: |
62 | /* The mu_iterator_t will read the stream and set the state to MU_POP3_NO_STATE when done. */ | 55 | /* The mu_iterator_t will read the stream and set the state to |
56 | MU_POP3_NO_STATE when done. */ | ||
63 | break; | 57 | break; |
64 | 58 | ||
65 | /* They must deal with the error first by reopening. */ | 59 | /* They must deal with the error first by reopening. */ | ... | ... |
... | @@ -37,19 +37,12 @@ mu_pop3_user (mu_pop3_t pop3, const char *user) | ... | @@ -37,19 +37,12 @@ mu_pop3_user (mu_pop3_t pop3, const char *user) |
37 | case MU_POP3_NO_STATE: | 37 | case MU_POP3_NO_STATE: |
38 | status = mu_pop3_writeline (pop3, "USER %s\r\n", user); | 38 | status = mu_pop3_writeline (pop3, "USER %s\r\n", user); |
39 | MU_POP3_CHECK_ERROR (pop3, status); | 39 | MU_POP3_CHECK_ERROR (pop3, status); |
40 | mu_pop3_debug_cmd (pop3); | 40 | MU_POP3_FCLR (pop3, MU_POP3_ACK); |
41 | pop3->state = MU_POP3_USER; | 41 | pop3->state = MU_POP3_USER; |
42 | 42 | ||
43 | case MU_POP3_USER: | 43 | case MU_POP3_USER: |
44 | status = mu_pop3_send (pop3); | 44 | status = mu_pop3_response (pop3, NULL); |
45 | MU_POP3_CHECK_EAGAIN (pop3, status); | 45 | MU_POP3_CHECK_EAGAIN (pop3, status); |
46 | pop3->acknowledge = 0; | ||
47 | pop3->state = MU_POP3_USER_ACK; | ||
48 | |||
49 | case MU_POP3_USER_ACK: | ||
50 | status = mu_pop3_response (pop3, NULL, 0, NULL); | ||
51 | MU_POP3_CHECK_EAGAIN (pop3, status); | ||
52 | mu_pop3_debug_ack (pop3); | ||
53 | MU_POP3_CHECK_OK (pop3); | 46 | MU_POP3_CHECK_OK (pop3); |
54 | pop3->state = MU_POP3_NO_STATE; | 47 | pop3->state = MU_POP3_NO_STATE; |
55 | break; | 48 | break; | ... | ... |
... | @@ -49,6 +49,8 @@ init_iobuf (struct mu_filter_io *io, struct _mu_filter_stream *fs) | ... | @@ -49,6 +49,8 @@ init_iobuf (struct mu_filter_io *io, struct _mu_filter_stream *fs) |
49 | io->isize = MFB_LEVEL (fs->inbuf); | 49 | io->isize = MFB_LEVEL (fs->inbuf); |
50 | io->output = MFB_ENDPTR (fs->outbuf); | 50 | io->output = MFB_ENDPTR (fs->outbuf); |
51 | io->osize = MFB_FREESIZE (fs->outbuf); | 51 | io->osize = MFB_FREESIZE (fs->outbuf); |
52 | io->errcode = 0; | ||
53 | io->eof = 0; | ||
52 | } | 54 | } |
53 | 55 | ||
54 | static int | 56 | static int |
... | @@ -114,8 +116,9 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) | ... | @@ -114,8 +116,9 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) |
114 | size_t min_input_level = MU_FILTER_BUF_SIZE; | 116 | size_t min_input_level = MU_FILTER_BUF_SIZE; |
115 | size_t min_output_size = MU_FILTER_BUF_SIZE; | 117 | size_t min_output_size = MU_FILTER_BUF_SIZE; |
116 | size_t total = 0; | 118 | size_t total = 0; |
119 | int stop = 0; | ||
117 | 120 | ||
118 | while (total < size && cmd != mu_filter_lastbuf) | 121 | while (!stop && total < size && cmd != mu_filter_lastbuf) |
119 | { | 122 | { |
120 | size_t rdsize; | 123 | size_t rdsize; |
121 | 124 | ||
... | @@ -168,6 +171,11 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) | ... | @@ -168,6 +171,11 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) |
168 | if (iobuf.isize > MFB_RDBYTES (fs->inbuf) | 171 | if (iobuf.isize > MFB_RDBYTES (fs->inbuf) |
169 | || iobuf.osize > MFB_FREESIZE (fs->outbuf)) | 172 | || iobuf.osize > MFB_FREESIZE (fs->outbuf)) |
170 | return MU_ERR_FAILURE; /* FIXME: special error code? */ | 173 | return MU_ERR_FAILURE; /* FIXME: special error code? */ |
174 | if (iobuf.eof) | ||
175 | { | ||
176 | stream->flags |= _MU_STR_EOF; | ||
177 | stop = 1; | ||
178 | } | ||
171 | break; | 179 | break; |
172 | 180 | ||
173 | case mu_filter_falure: | 181 | case mu_filter_falure: | ... | ... |
... | @@ -176,6 +176,7 @@ _xscript_ctl (struct _mu_stream *str, int op, void *arg) | ... | @@ -176,6 +176,7 @@ _xscript_ctl (struct _mu_stream *str, int op, void *arg) |
176 | { | 176 | { |
177 | struct _mu_xscript_stream *sp = (struct _mu_xscript_stream *)str; | 177 | struct _mu_xscript_stream *sp = (struct _mu_xscript_stream *)str; |
178 | mu_transport_t *ptrans; | 178 | mu_transport_t *ptrans; |
179 | int status = 0; | ||
179 | 180 | ||
180 | switch (op) | 181 | switch (op) |
181 | { | 182 | { |
... | @@ -198,11 +199,37 @@ _xscript_ctl (struct _mu_stream *str, int op, void *arg) | ... | @@ -198,11 +199,37 @@ _xscript_ctl (struct _mu_stream *str, int op, void *arg) |
198 | break; | 199 | break; |
199 | 200 | ||
200 | case MU_IOCTL_SWAP_STREAM: | 201 | case MU_IOCTL_SWAP_STREAM: |
201 | /* fall through */ | 202 | if (!arg) |
203 | return EINVAL; | ||
204 | status = mu_stream_ioctl (sp->transport, op, arg); | ||
205 | if (status == EINVAL || status == ENOSYS) | ||
206 | { | ||
207 | mu_stream_t *pstr = arg; | ||
208 | mu_stream_t tmp; | ||
209 | |||
210 | if (pstr[0] != pstr[1]) | ||
211 | return EINVAL; /* FIXME */ | ||
212 | tmp = pstr[0]; | ||
213 | pstr[0] = sp->transport; | ||
214 | pstr[1] = sp->transport; | ||
215 | sp->transport = tmp; | ||
216 | if (!(str->flags & MU_STREAM_AUTOCLOSE)) | ||
217 | { | ||
218 | if (pstr[0]) | ||
219 | mu_stream_unref (pstr[0]); | ||
220 | if (tmp) | ||
221 | mu_stream_ref (tmp); | ||
222 | } | ||
223 | if (tmp) | ||
224 | mu_stream_ref (tmp); | ||
225 | status = 0; | ||
226 | } | ||
227 | break; | ||
228 | |||
202 | default: | 229 | default: |
203 | return mu_stream_ioctl (sp->transport, op, arg); | 230 | return mu_stream_ioctl (sp->transport, op, arg); |
204 | } | 231 | } |
205 | return 0; | 232 | return status; |
206 | } | 233 | } |
207 | 234 | ||
208 | static int | 235 | static int | ... | ... |
-
Please register or sign in to post a comment