Commit 7ca75462 7ca7546248a32a53049e1d59889013925c01ed85 by Sergey Poznyakoff

imapio: fix payload tracing and handling of continuation responses

* include/mailutils/imapio.h (mu_imapio_create): Change signature. All
uses updated.
(mu_imapio_trace_payload,mu_imapio_get_trace_payload): New protos.
* include/mailutils/sys/imapio.h (_mu_imapio) <_imap_server>
<_imap_trace_payload>: New bits.
* libmailutils/imapio/create.c (mu_imapio_create): Take three arguments,
the third one specifying whether the imapio object is intended for server
or client.
* libmailutils/imapio/getline.c (initial_parse): In server mode, parse
everything at once.
Handle continuation responses in client mode.
(mu_imapio_getline): Toggle MU_XSCRIPT_PAYLOAD only if requested.
* libmailutils/imapio/literal.c: Wait for continuation response (in
client mode).
* libmailutils/imapio/trace.c (mu_imapio_trace_payload)
(mu_imapio_get_trace_payload): New functions.
* libmailutils/tests/imapio.c: New option -server.
* libmailutils/tests/imapio.at: Update literal tests.
1 parent 48fb45e6
...@@ -23,7 +23,10 @@ extern "C" { ...@@ -23,7 +23,10 @@ extern "C" {
23 23
24 # include <mailutils/types.h> 24 # include <mailutils/types.h>
25 25
26 int mu_imapio_create (mu_imapio_t *iop, mu_stream_t str); 26 #define MU_IMAPIO_CLIENT 0
27 #define MU_IMAPIO_SERVER 1
28
29 int mu_imapio_create (mu_imapio_t *iop, mu_stream_t str, int server);
27 void mu_imapio_free (mu_imapio_t io); 30 void mu_imapio_free (mu_imapio_t io);
28 void mu_imapio_destroy (mu_imapio_t *pio); 31 void mu_imapio_destroy (mu_imapio_t *pio);
29 32
...@@ -41,6 +44,8 @@ int mu_imapio_send_qstring_unfold (struct _mu_imapio *io, const char *buffer, ...@@ -41,6 +44,8 @@ int mu_imapio_send_qstring_unfold (struct _mu_imapio *io, const char *buffer,
41 int mu_imapio_trace_enable (mu_imapio_t io); 44 int mu_imapio_trace_enable (mu_imapio_t io);
42 int mu_imapio_trace_disable (mu_imapio_t io); 45 int mu_imapio_trace_disable (mu_imapio_t io);
43 int mu_imapio_get_trace (mu_imapio_t io); 46 int mu_imapio_get_trace (mu_imapio_t io);
47 void mu_imapio_trace_payload (mu_imapio_t io, int val);
48 int mu_imapio_get_trace_payload (mu_imapio_t io);
44 49
45 int mu_imapio_getbuf (mu_imapio_t io, char **pptr, size_t *psize); 50 int mu_imapio_getbuf (mu_imapio_t io, char **pptr, size_t *psize);
46 51
......
...@@ -28,7 +28,9 @@ struct _mu_imapio ...@@ -28,7 +28,9 @@ struct _mu_imapio
28 size_t _imap_buf_level; 28 size_t _imap_buf_level;
29 struct mu_wordsplit _imap_ws; 29 struct mu_wordsplit _imap_ws;
30 int _imap_ws_flags; 30 int _imap_ws_flags;
31 int _imap_server:1;
31 int _imap_transcript:1; 32 int _imap_transcript:1;
33 int _imap_trace_payload:1;
32 int _imap_reply_ready:1; 34 int _imap_reply_ready:1;
33 }; 35 };
34 36
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
21 #include <mailutils/sys/imapio.h> 21 #include <mailutils/sys/imapio.h>
22 22
23 int 23 int
24 mu_imapio_create (mu_imapio_t *iop, mu_stream_t str) 24 mu_imapio_create (mu_imapio_t *iop, mu_stream_t str, int server)
25 { 25 {
26 struct _mu_imapio *io = calloc (1, sizeof (*io)); 26 struct _mu_imapio *io = calloc (1, sizeof (*io));
27 if (!io) 27 if (!io)
...@@ -38,6 +38,7 @@ mu_imapio_create (mu_imapio_t *iop, mu_stream_t str) ...@@ -38,6 +38,7 @@ mu_imapio_create (mu_imapio_t *iop, mu_stream_t str)
38 MU_WRDSF_RETURN_DELIMS | 38 MU_WRDSF_RETURN_DELIMS |
39 MU_WRDSF_WS | 39 MU_WRDSF_WS |
40 MU_WRDSF_APPEND; 40 MU_WRDSF_APPEND;
41 io->_imap_server = server;
41 *iop = io; 42 *iop = io;
42 return 0; 43 return 0;
43 } 44 }
......
...@@ -104,16 +104,20 @@ static int ...@@ -104,16 +104,20 @@ static int
104 initial_parse (struct _mu_imapio *io) 104 initial_parse (struct _mu_imapio *io)
105 { 105 {
106 int rc, type; 106 int rc, type;
107 int eat_rest = 0;
107 108
108 if ((rc = mu_wordsplit_len (io->_imap_buf_base, io->_imap_buf_level, 109 if ((rc = mu_wordsplit_len (io->_imap_buf_base, io->_imap_buf_level,
109 &io->_imap_ws, 110 &io->_imap_ws,
110 io->_imap_ws_flags | MU_WRDSF_INCREMENTAL))) 111 io->_imap_ws_flags |
112 (io->_imap_server ? 0 : MU_WRDSF_INCREMENTAL))))
111 { 113 {
112 if (rc == MU_WRDSE_NOINPUT) 114 if (rc == MU_WRDSE_NOINPUT)
113 return IMAPIO_OK; 115 return IMAPIO_OK;
114 return IMAPIO_ERR; 116 return IMAPIO_ERR;
115 } 117 }
116 io->_imap_ws_flags |= MU_WRDSF_REUSE; 118 io->_imap_ws_flags |= MU_WRDSF_REUSE;
119 if (io->_imap_server)
120 return IMAPIO_OK;
117 121
118 if ((rc = mu_wordsplit (NULL, &io->_imap_ws, MU_WRDSF_INCREMENTAL))) 122 if ((rc = mu_wordsplit (NULL, &io->_imap_ws, MU_WRDSF_INCREMENTAL)))
119 { 123 {
...@@ -122,13 +126,20 @@ initial_parse (struct _mu_imapio *io) ...@@ -122,13 +126,20 @@ initial_parse (struct _mu_imapio *io)
122 return IMAPIO_ERR; 126 return IMAPIO_ERR;
123 } 127 }
124 128
125 if ((type = is_status_response (io->_imap_ws.ws_wordv[1])) 129 if (strcmp (io->_imap_ws.ws_wordv[0], "+") == 0)
130 eat_rest = 1;
131 else if ((type = is_status_response (io->_imap_ws.ws_wordv[1]))
126 && (type == STATUS_RESPONSE || 132 && (type == STATUS_RESPONSE ||
127 strcmp (io->_imap_ws.ws_wordv[0], "*") == 0)) 133 strcmp (io->_imap_ws.ws_wordv[0], "*") == 0))
128 { 134 {
129 rc = get_response_code (io); 135 rc = get_response_code (io);
130 if (rc) 136 if (rc)
131 return IMAPIO_ERR; 137 return IMAPIO_ERR;
138 eat_rest = 1;
139 }
140
141 if (eat_rest)
142 {
132 while (io->_imap_ws.ws_endp < io->_imap_ws.ws_len && 143 while (io->_imap_ws.ws_endp < io->_imap_ws.ws_len &&
133 mu_isblank (io->_imap_ws.ws_input[io->_imap_ws.ws_endp])) 144 mu_isblank (io->_imap_ws.ws_input[io->_imap_ws.ws_endp]))
134 io->_imap_ws.ws_endp++; 145 io->_imap_ws.ws_endp++;
...@@ -150,6 +161,7 @@ mu_imapio_getline (struct _mu_imapio *io) ...@@ -150,6 +161,7 @@ mu_imapio_getline (struct _mu_imapio *io)
150 { 161 {
151 int rc; 162 int rc;
152 char *last_arg; 163 char *last_arg;
164 int xlev = MU_XSCRIPT_NORMAL;
153 165
154 if (io->_imap_reply_ready) 166 if (io->_imap_reply_ready)
155 { 167 {
...@@ -163,7 +175,7 @@ mu_imapio_getline (struct _mu_imapio *io) ...@@ -163,7 +175,7 @@ mu_imapio_getline (struct _mu_imapio *io)
163 &io->_imap_buf_base, &io->_imap_buf_size, 175 &io->_imap_buf_base, &io->_imap_buf_size,
164 &io->_imap_buf_level); 176 &io->_imap_buf_level);
165 if (rc) 177 if (rc)
166 return rc; 178 break;
167 if (io->_imap_buf_level == 0) 179 if (io->_imap_buf_level == 0)
168 break; 180 break;
169 io->_imap_buf_level = mu_rtrim_class (io->_imap_buf_base, 181 io->_imap_buf_level = mu_rtrim_class (io->_imap_buf_base,
...@@ -185,7 +197,10 @@ mu_imapio_getline (struct _mu_imapio *io) ...@@ -185,7 +197,10 @@ mu_imapio_getline (struct _mu_imapio *io)
185 io->_imap_buf_level - io->_imap_ws.ws_endp, 197 io->_imap_buf_level - io->_imap_ws.ws_endp,
186 &io->_imap_ws, io->_imap_ws_flags); 198 &io->_imap_ws, io->_imap_ws_flags);
187 if (rc) 199 if (rc)
188 return MU_ERR_PARSE; 200 {
201 rc = MU_ERR_PARSE;
202 break;
203 }
189 204
190 if (io->_imap_ws.ws_wordc == 0) 205 if (io->_imap_ws.ws_wordc == 0)
191 break; 206 break;
...@@ -196,13 +211,18 @@ mu_imapio_getline (struct _mu_imapio *io) ...@@ -196,13 +211,18 @@ mu_imapio_getline (struct _mu_imapio *io)
196 int rc; 211 int rc;
197 unsigned long number; 212 unsigned long number;
198 char *sp = NULL; 213 char *sp = NULL;
199 int xlev = mu_imapio_set_xscript_level (io, MU_XSCRIPT_PAYLOAD); 214
215 if (!io->_imap_trace_payload)
216 xlev = mu_imapio_set_xscript_level (io, MU_XSCRIPT_PAYLOAD);
200 217
201 number = strtoul (last_arg + 1, &sp, 10); 218 number = strtoul (last_arg + 1, &sp, 10);
202 /* Client can ask for non-synchronised literal, 219 /* Client can ask for non-synchronised literal,
203 if a '+' is appended to the octet count. */ 220 if a '+' is appended to the octet count. */
204 if (*sp == '}') 221 if (*sp == '}')
222 {
223 if (io->_imap_server)
205 mu_stream_printf (io->_imap_stream, "+ GO AHEAD\n"); 224 mu_stream_printf (io->_imap_stream, "+ GO AHEAD\n");
225 }
206 else if (*sp != '+') 226 else if (*sp != '+')
207 break; 227 break;
208 228
...@@ -211,7 +231,10 @@ mu_imapio_getline (struct _mu_imapio *io) ...@@ -211,7 +231,10 @@ mu_imapio_getline (struct _mu_imapio *io)
211 size_t newsize = number + 1; 231 size_t newsize = number + 1;
212 void *newp = realloc (io->_imap_buf_base, newsize); 232 void *newp = realloc (io->_imap_buf_base, newsize);
213 if (!newp) 233 if (!newp)
214 return ENOMEM; 234 {
235 rc = ENOMEM;
236 break;
237 }
215 io->_imap_buf_base = newp; 238 io->_imap_buf_base = newp;
216 io->_imap_buf_size = newsize; 239 io->_imap_buf_size = newsize;
217 } 240 }
...@@ -229,7 +252,7 @@ mu_imapio_getline (struct _mu_imapio *io) ...@@ -229,7 +252,7 @@ mu_imapio_getline (struct _mu_imapio *io)
229 } 252 }
230 mu_imapio_set_xscript_level (io, xlev); 253 mu_imapio_set_xscript_level (io, xlev);
231 if (rc) 254 if (rc)
232 return rc; 255 break;
233 io->_imap_buf_base[io->_imap_buf_level++] = 0; 256 io->_imap_buf_base[io->_imap_buf_level++] = 0;
234 257
235 free (last_arg); 258 free (last_arg);
...@@ -237,12 +260,18 @@ mu_imapio_getline (struct _mu_imapio *io) ...@@ -237,12 +260,18 @@ mu_imapio_getline (struct _mu_imapio *io)
237 if (mu_wordsplit_len (io->_imap_buf_base, io->_imap_buf_level, 260 if (mu_wordsplit_len (io->_imap_buf_base, io->_imap_buf_level,
238 &io->_imap_ws, 261 &io->_imap_ws,
239 io->_imap_ws_flags|MU_WRDSF_NOSPLIT)) 262 io->_imap_ws_flags|MU_WRDSF_NOSPLIT))
240 return MU_ERR_PARSE; 263 {
264 rc = MU_ERR_PARSE;
265 break;
266 }
241 } 267 }
242 else 268 else
243 break; 269 break;
244 } 270 }
245 271
272 if (!io->_imap_trace_payload)
273 mu_imapio_set_xscript_level (io, xlev);
274
246 io->_imap_reply_ready = 1; 275 io->_imap_reply_ready = 1;
247 return 0; 276 return rc;
248 } 277 }
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
18 #include <stdlib.h> 18 #include <stdlib.h>
19 #include <string.h> 19 #include <string.h>
20 #include <mailutils/types.h> 20 #include <mailutils/types.h>
21 #include <mailutils/errno.h>
21 #include <mailutils/imapio.h> 22 #include <mailutils/imapio.h>
22 #include <mailutils/sys/imapio.h> 23 #include <mailutils/sys/imapio.h>
23 #include <mailutils/stream.h> 24 #include <mailutils/stream.h>
...@@ -25,7 +26,18 @@ ...@@ -25,7 +26,18 @@
25 int 26 int
26 mu_imapio_send_literal (struct _mu_imapio *io, const char *buffer) 27 mu_imapio_send_literal (struct _mu_imapio *io, const char *buffer)
27 { 28 {
28 return mu_stream_printf (io->_imap_stream, 29 size_t len = strlen (buffer);
29 "{%lu}\n%s", (unsigned long) strlen (buffer), 30
30 buffer); 31 mu_stream_printf (io->_imap_stream, "{%lu}\n", (unsigned long) len);
32
33 if (!io->_imap_server)
34 {
35 int rc = mu_imapio_getline (io);
36 if (rc)
37 return rc;
38 if (!(io->_imap_reply_ready && io->_imap_ws.ws_wordv[0][0] == '+'))
39 return MU_ERR_BADREPLY;
40 }
41
42 return mu_stream_write (io->_imap_stream, buffer, len, NULL);
31 } 43 }
......
...@@ -84,3 +84,15 @@ mu_imapio_get_trace (mu_imapio_t io) ...@@ -84,3 +84,15 @@ mu_imapio_get_trace (mu_imapio_t io)
84 { 84 {
85 return io ? io->_imap_transcript : 0; 85 return io ? io->_imap_transcript : 0;
86 } 86 }
87
88 void
89 mu_imapio_trace_payload (mu_imapio_t io, int val)
90 {
91 io->_imap_trace_payload = !!val;
92 }
93
94 int
95 mu_imapio_get_trace_payload (mu_imapio_t io)
96 {
97 return io ? io->_imap_trace_payload : 0;
98 }
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
16 16
17 AT_BANNER(IMAP IO) 17 AT_BANNER(IMAP IO)
18 18
19 m4_pushdef([IMAPIO_FLAGS])
20
19 dnl ------------------------------------------------------------ 21 dnl ------------------------------------------------------------
20 dnl IMAPIO([NAME], [KW = `'], [INPUT], [STDOUT = `'], 22 dnl IMAPIO([NAME], [KW = `'], [INPUT], [STDOUT = `'],
21 dnl [STDERR = `']) 23 dnl [STDERR = `'])
...@@ -23,7 +25,7 @@ dnl ...@@ -23,7 +25,7 @@ dnl
23 m4_pushdef([IMAPIO],[ 25 m4_pushdef([IMAPIO],[
24 m4_pushdef([MU_TEST_GROUP],[imapio]) 26 m4_pushdef([MU_TEST_GROUP],[imapio])
25 m4_pushdef([MU_TEST_KEYWORDS],[imapio]) 27 m4_pushdef([MU_TEST_KEYWORDS],[imapio])
26 m4_pushdef([MU_TEST_COMMAND],[imapio]) 28 m4_pushdef([MU_TEST_COMMAND],[imapio IMAPIO_FLAGS])
27 MU_GENERIC_TEST([$1],[$2],[$3],[],[$4],[$5]) 29 MU_GENERIC_TEST([$1],[$2],[$3],[],[$4],[$5])
28 m4_popdef([MU_TEST_COMMAND]) 30 m4_popdef([MU_TEST_COMMAND])
29 m4_popdef([MU_TEST_KEYWORDS]) 31 m4_popdef([MU_TEST_KEYWORDS])
...@@ -78,7 +80,21 @@ IMAPIO([server response with code],[], ...@@ -78,7 +80,21 @@ IMAPIO([server response with code],[],
78 6: 'Predicted next uid' 80 6: 'Predicted next uid'
79 ]) 81 ])
80 82
81 IMAPIO([literals],[literal], 83 IMAPIO([literals (client)],[literal],
84 [A001 LOGIN {11}
85 FRED FOOBAR {7}
86 fat man
87 ],
88 [],
89 [4
90 0: 'A001'
91 1: 'LOGIN'
92 2: 'FRED FOOBAR'
93 3: 'fat man'
94 ])
95
96 m4_pushdef([IMAPIO_FLAGS],[-server])
97 IMAPIO([literals (server)],[literal],
82 [A001 LOGIN {11} 98 [A001 LOGIN {11}
83 FRED FOOBAR {7} 99 FRED FOOBAR {7}
84 fat man 100 fat man
...@@ -93,7 +109,7 @@ fat man ...@@ -93,7 +109,7 @@ fat man
93 3: 'fat man' 109 3: 'fat man'
94 ]) 110 ])
95 111
96 IMAPIO([non-synch literals],[literal], 112 IMAPIO([non-synchronized literals (server)],[literal],
97 [A001 LOGIN {11+} 113 [A001 LOGIN {11+}
98 FRED FOOBAR {7+} 114 FRED FOOBAR {7+}
99 fat man 115 fat man
...@@ -105,6 +121,9 @@ fat man ...@@ -105,6 +121,9 @@ fat man
105 2: 'FRED FOOBAR' 121 2: 'FRED FOOBAR'
106 3: 'fat man' 122 3: 'fat man'
107 ]) 123 ])
124 m4_popdef([IMAPIO_FLAGS])
108 125
109 dnl ------------------------------------------------------------ 126 dnl ------------------------------------------------------------
110 m4_popdef([IMAPIO]) 127 m4_popdef([IMAPIO])
128 m4_pushdef([IMAPIO_FLAGS])
129
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
29 void 29 void
30 usage () 30 usage ()
31 { 31 {
32 mu_stream_printf (mu_strout, "usage: %s [debug=SPEC] [-transcript]\n", 32 mu_stream_printf (mu_strout, "usage: %s [debug=SPEC] [-transcript] [-server]\n",
33 mu_program_name); 33 mu_program_name);
34 exit (0); 34 exit (0);
35 } 35 }
...@@ -41,6 +41,7 @@ main (int argc, char **argv) ...@@ -41,6 +41,7 @@ main (int argc, char **argv)
41 int transcript = 0; 41 int transcript = 0;
42 mu_imapio_t io; 42 mu_imapio_t io;
43 mu_stream_t str; 43 mu_stream_t str;
44 int imapio_mode = MU_IMAPIO_CLIENT;
44 45
45 mu_stdstream_setup (MU_STDSTREAM_RESET_NONE); 46 mu_stdstream_setup (MU_STDSTREAM_RESET_NONE);
46 47
...@@ -52,6 +53,8 @@ main (int argc, char **argv) ...@@ -52,6 +53,8 @@ main (int argc, char **argv)
52 mu_debug_parse_spec (opt + 6); 53 mu_debug_parse_spec (opt + 6);
53 else if (strcmp (opt, "-transcript") == 0) 54 else if (strcmp (opt, "-transcript") == 0)
54 transcript = 1; 55 transcript = 1;
56 else if (strcmp (opt, "-server") == 0)
57 imapio_mode = MU_IMAPIO_SERVER;
55 else if (strcmp (opt, "-h") == 0) 58 else if (strcmp (opt, "-h") == 0)
56 usage (); 59 usage ();
57 else 60 else
...@@ -64,7 +67,7 @@ main (int argc, char **argv) ...@@ -64,7 +67,7 @@ main (int argc, char **argv)
64 MU_ASSERT (mu_iostream_create (&str, mu_strin, mu_strout)); 67 MU_ASSERT (mu_iostream_create (&str, mu_strin, mu_strout));
65 68
66 69
67 MU_ASSERT (mu_imapio_create (&io, str)); 70 MU_ASSERT (mu_imapio_create (&io, str, imapio_mode));
68 71
69 if (transcript) 72 if (transcript)
70 mu_imapio_trace_enable (io); 73 mu_imapio_trace_enable (io);
......