Commit 46e3b517 46e3b517d99ae4c24c000d893095168017129eb5 by Sergey Poznyakoff

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.
1 parent c97b96ae
...@@ -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
......
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. */
......
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
......