imap client: initial implementation of fetch.
* include/mailutils/imap.h (mu_imap_fetch): New proto. (MU_IMAP_CB_FETCH): New callback code. (MU_IMAP_FETCH_BODY,MU_IMAP_FETCH_BODYSTRUCTURE) (MU_IMAP_FETCH_ENVELOPE,MU_IMAP_FETCH_FLAGS) (MU_IMAP_FETCH_INTERNALDATE,MU_IMAP_FETCH_RFC822_SIZE) (MU_IMAP_FETCH_UID): New constants. (mu_imap_fetch_body,mu_imap_fetch_bodystructure) (mu_imap_fetch_envelope,mu_imap_fetch_flags) (mu_imap_fetch_internaldate,mu_imap_fetch_rfc822_size) (mu_imap_fetch_uid,mu_imap_fetch_response): New structures. * include/mailutils/sys/imap.h (MU_IMAP_SET_XSCRIPT_MASK) (MU_IMAP_CLR_XSCRIPT_MASK): New macros. (mu_imap_client_state)<MU_IMAP_FETCH_RX>: New state. (_mu_imap_list_nth_element_is_string): New proto. * libproto/imap/fetch.c: New file. * libproto/imap/Makefile.am (libmu_imap_la_SOURCES): Add fetch.c * libproto/imap/carrier.c (mu_imap_set_carrier): Update call to mu_imapio_create. * libproto/imap/resplist.c (_mu_imap_list_nth_element_is_string): New function. * libproto/imap/resproc.c (_process_unsolicited_response): Handle FETCH response. * libproto/imap/trace.c (mu_imap_trace_mask): Call mu_imapio_trace_payload if needed. * mu/imap.c (imap_bad_callback): New function. (com_disconnect): Register imap_bad_callback. (com_fetch): New function. (imap_comtab): Add the "fetch" command. * mu/mu.h (mutool_command) <flags>: New member. * mu/pop.c (pop_comtab): Update initializers. * mu/shell.c (default_comtab): Update initializers. (execute_line): Rewrite using incremental wordsplit. This allows for optionally coalescing arguments with indices >= argmax into one argument. This is useful for such commands as "prompt" and "fetch".
Showing
13 changed files
with
307 additions
and
79 deletions
... | @@ -560,7 +560,6 @@ fetch_bodystructure0 (mu_message_t message, int extension) | ... | @@ -560,7 +560,6 @@ fetch_bodystructure0 (mu_message_t message, int extension) |
560 | 560 | ||
561 | mu_message_get_header (message, &header); | 561 | mu_message_get_header (message, &header); |
562 | 562 | ||
563 | |||
564 | /* The subtype. */ | 563 | /* The subtype. */ |
565 | if (mu_header_aget_value (header, MU_HEADER_CONTENT_TYPE, &buffer) == 0) | 564 | if (mu_header_aget_value (header, MU_HEADER_CONTENT_TYPE, &buffer) == 0) |
566 | { | 565 | { | ... | ... |
... | @@ -21,6 +21,7 @@ | ... | @@ -21,6 +21,7 @@ |
21 | #include <mailutils/iterator.h> | 21 | #include <mailutils/iterator.h> |
22 | #include <mailutils/debug.h> | 22 | #include <mailutils/debug.h> |
23 | #include <mailutils/stream.h> | 23 | #include <mailutils/stream.h> |
24 | #include <mailutils/util.h> | ||
24 | #include <mailutils/kwd.h> | 25 | #include <mailutils/kwd.h> |
25 | 26 | ||
26 | #ifdef __cplusplus | 27 | #ifdef __cplusplus |
... | @@ -58,6 +59,8 @@ int mu_imap_id (mu_imap_t imap, char **idenv, mu_assoc_t *passoc); | ... | @@ -58,6 +59,8 @@ int mu_imap_id (mu_imap_t imap, char **idenv, mu_assoc_t *passoc); |
58 | 59 | ||
59 | int mu_imap_noop (mu_imap_t imap); | 60 | int mu_imap_noop (mu_imap_t imap); |
60 | 61 | ||
62 | int mu_imap_fetch (mu_imap_t imap, const char *msgset, const char *items); | ||
63 | |||
61 | int mu_imap_set_carrier (mu_imap_t imap, mu_stream_t carrier); | 64 | int mu_imap_set_carrier (mu_imap_t imap, mu_stream_t carrier); |
62 | int mu_imap_get_carrier (mu_imap_t imap, mu_stream_t *pcarrier); | 65 | int mu_imap_get_carrier (mu_imap_t imap, mu_stream_t *pcarrier); |
63 | 66 | ||
... | @@ -104,7 +107,7 @@ extern struct mu_kwd _mu_imap_status_name_table[]; | ... | @@ -104,7 +107,7 @@ extern struct mu_kwd _mu_imap_status_name_table[]; |
104 | 107 | ||
105 | /* The following five callbacks correspond to members of struct | 108 | /* The following five callbacks correspond to members of struct |
106 | mu_imap_stat and take a pointer to struct mu_imap_stat as their | 109 | mu_imap_stat and take a pointer to struct mu_imap_stat as their |
107 | only argument. */ | 110 | PDAT argument. SDAT is always 0. */ |
108 | #define MU_IMAP_CB_PERMANENT_FLAGS 0 | 111 | #define MU_IMAP_CB_PERMANENT_FLAGS 0 |
109 | #define MU_IMAP_CB_MESSAGE_COUNT 1 | 112 | #define MU_IMAP_CB_MESSAGE_COUNT 1 |
110 | #define MU_IMAP_CB_RECENT_COUNT 2 | 113 | #define MU_IMAP_CB_RECENT_COUNT 2 |
... | @@ -113,15 +116,20 @@ extern struct mu_kwd _mu_imap_status_name_table[]; | ... | @@ -113,15 +116,20 @@ extern struct mu_kwd _mu_imap_status_name_table[]; |
113 | #define MU_IMAP_CB_UIDVALIDITY 5 | 116 | #define MU_IMAP_CB_UIDVALIDITY 5 |
114 | 117 | ||
115 | /* The following callbacks correspond to server responses and take two | 118 | /* The following callbacks correspond to server responses and take two |
116 | argument: a response code (see MU_IMAP_RESPONSE, below), and | 119 | arguments: a response code (see MU_IMAP_RESPONSE, below) in SDAT, and |
117 | human-readable text string as returned by the server. The latter can | 120 | human-readable text string as returned by the server in PDAT. The |
118 | be NULL. */ | 121 | latter can be NULL. */ |
119 | #define MU_IMAP_CB_OK 6 | 122 | #define MU_IMAP_CB_OK 6 |
120 | #define MU_IMAP_CB_NO 7 | 123 | #define MU_IMAP_CB_NO 7 |
121 | #define MU_IMAP_CB_BAD 8 | 124 | #define MU_IMAP_CB_BAD 8 |
122 | #define MU_IMAP_CB_BYE 9 | 125 | #define MU_IMAP_CB_BYE 9 |
123 | #define MU_IMAP_CB_PREAUTH 10 | 126 | #define MU_IMAP_CB_PREAUTH 10 |
124 | #define _MU_IMAP_CB_MAX 11 | 127 | |
128 | /* FETCH callback. Arguments: SDAT - message sequence number, PDAT - a | ||
129 | list (mu_list_t) of union mu_imap_fetch_response (see below). */ | ||
130 | #define MU_IMAP_CB_FETCH 11 | ||
131 | |||
132 | #define _MU_IMAP_CB_MAX 12 | ||
125 | 133 | ||
126 | typedef void (*mu_imap_callback_t) (void *, int code, size_t sdat, void *pdat); | 134 | typedef void (*mu_imap_callback_t) (void *, int code, size_t sdat, void *pdat); |
127 | 135 | ||
... | @@ -145,6 +153,91 @@ void mu_imap_register_callback_function (mu_imap_t imap, int code, | ... | @@ -145,6 +153,91 @@ void mu_imap_register_callback_function (mu_imap_t imap, int code, |
145 | 153 | ||
146 | extern struct mu_kwd mu_imap_response_codes[]; | 154 | extern struct mu_kwd mu_imap_response_codes[]; |
147 | 155 | ||
156 | /* FETCH Response Codes */ | ||
157 | |||
158 | /* BODY[<section>]<<origin octet>> */ | ||
159 | #define MU_IMAP_FETCH_BODY 0 | ||
160 | /* BODY & BODYSTRUCTURE */ | ||
161 | #define MU_IMAP_FETCH_BODYSTRUCTURE 1 | ||
162 | /* ENVELOPE */ | ||
163 | #define MU_IMAP_FETCH_ENVELOPE 2 | ||
164 | /* FLAGS */ | ||
165 | #define MU_IMAP_FETCH_FLAGS 3 | ||
166 | /* INTERNALDATE */ | ||
167 | #define MU_IMAP_FETCH_INTERNALDATE 4 | ||
168 | /* RFC822.SIZE */ | ||
169 | #define MU_IMAP_FETCH_RFC822_SIZE 5 | ||
170 | /* UID */ | ||
171 | #define MU_IMAP_FETCH_UID 6 | ||
172 | |||
173 | struct mu_imap_fetch_body | ||
174 | { | ||
175 | int type; | ||
176 | size_t *partv; | ||
177 | size_t partc; | ||
178 | char *key; | ||
179 | char *text; | ||
180 | }; | ||
181 | |||
182 | struct mu_imap_fetch_bodystructure | ||
183 | { | ||
184 | int type; | ||
185 | //FIXME? | ||
186 | }; | ||
187 | |||
188 | struct mu_imap_fetch_envelope | ||
189 | { | ||
190 | int type; | ||
191 | struct tm date; | ||
192 | struct mu_timezone tz; | ||
193 | char *subject; | ||
194 | mu_address_t from; | ||
195 | mu_address_t sender; | ||
196 | mu_address_t reply_to; | ||
197 | mu_address_t to; | ||
198 | mu_address_t cc; | ||
199 | mu_address_t bcc; | ||
200 | char *in_reply_to; | ||
201 | char *message_id; | ||
202 | }; | ||
203 | |||
204 | struct mu_imap_fetch_flags | ||
205 | { | ||
206 | int type; | ||
207 | int flags; | ||
208 | }; | ||
209 | |||
210 | struct mu_imap_fetch_internaldate | ||
211 | { | ||
212 | int type; | ||
213 | struct tm tm; | ||
214 | struct mu_timezone tz; | ||
215 | }; | ||
216 | |||
217 | struct mu_imap_fetch_rfc822_size | ||
218 | { | ||
219 | int type; | ||
220 | size_t size; | ||
221 | }; | ||
222 | |||
223 | struct mu_imap_fetch_uid | ||
224 | { | ||
225 | int type; | ||
226 | size_t uid; | ||
227 | }; | ||
228 | |||
229 | union mu_imap_fetch_response | ||
230 | { | ||
231 | int type; | ||
232 | struct mu_imap_fetch_body body; | ||
233 | struct mu_imap_fetch_bodystructure bodystructure; | ||
234 | struct mu_imap_fetch_envelope envelope; | ||
235 | struct mu_imap_fetch_flags flags; | ||
236 | struct mu_imap_fetch_internaldate internaldate; | ||
237 | struct mu_imap_fetch_rfc822_size rfc822_size; | ||
238 | struct mu_imap_fetch_uid uid; | ||
239 | }; | ||
240 | |||
148 | #ifdef __cplusplus | 241 | #ifdef __cplusplus |
149 | } | 242 | } |
150 | #endif | 243 | #endif | ... | ... |
... | @@ -32,6 +32,16 @@ extern "C" { | ... | @@ -32,6 +32,16 @@ extern "C" { |
32 | #define MU_IMAP_RESP 0x01 | 32 | #define MU_IMAP_RESP 0x01 |
33 | #define MU_IMAP_TRACE 0x02 | 33 | #define MU_IMAP_TRACE 0x02 |
34 | #define MU_IMAP_XSCRIPT_MASK(n) (1<<((n)+1)) | 34 | #define MU_IMAP_XSCRIPT_MASK(n) (1<<((n)+1)) |
35 | #define MU_IMAP_SET_XSCRIPT_MASK(imap,n) \ | ||
36 | do \ | ||
37 | (imap)->flags |= MU_IMAP_XSCRIPT_MASK (n); \ | ||
38 | while (0) | ||
39 | #define MU_IMAP_CLR_XSCRIPT_MASK(imap,n) \ | ||
40 | do \ | ||
41 | (imap)->flags &= ~MU_IMAP_XSCRIPT_MASK (n); \ | ||
42 | while (0) | ||
43 | #define MU_IMAP_IS_XSCRIPT_MASK(imap,n) \ | ||
44 | ((imap)->flags & MU_IMAP_XSCRIPT_MASK (n)) | ||
35 | 45 | ||
36 | enum mu_imap_client_state | 46 | enum mu_imap_client_state |
37 | { | 47 | { |
... | @@ -47,6 +57,7 @@ enum mu_imap_client_state | ... | @@ -47,6 +57,7 @@ enum mu_imap_client_state |
47 | MU_IMAP_SELECT_RX, | 57 | MU_IMAP_SELECT_RX, |
48 | MU_IMAP_STATUS_RX, | 58 | MU_IMAP_STATUS_RX, |
49 | MU_IMAP_NOOP_RX, | 59 | MU_IMAP_NOOP_RX, |
60 | MU_IMAP_FETCH_RX, | ||
50 | MU_IMAP_CLOSING | 61 | MU_IMAP_CLOSING |
51 | }; | 62 | }; |
52 | 63 | ||
... | @@ -174,10 +185,14 @@ int _mu_imap_response (mu_imap_t imap, mu_imap_response_action_t fun, | ... | @@ -174,10 +185,14 @@ int _mu_imap_response (mu_imap_t imap, mu_imap_response_action_t fun, |
174 | 185 | ||
175 | int _mu_imap_list_element_is_string (struct imap_list_element *elt, | 186 | int _mu_imap_list_element_is_string (struct imap_list_element *elt, |
176 | const char *str); | 187 | const char *str); |
188 | int _mu_imap_list_nth_element_is_string (mu_list_t list, size_t n, | ||
189 | const char *str); | ||
190 | |||
177 | int _mu_imap_collect_flags (struct imap_list_element *arg, int *res); | 191 | int _mu_imap_collect_flags (struct imap_list_element *arg, int *res); |
178 | 192 | ||
179 | struct imap_list_element *_mu_imap_list_at (mu_list_t list, int idx); | 193 | struct imap_list_element *_mu_imap_list_at (mu_list_t list, int idx); |
180 | 194 | ||
195 | int _mu_imap_parse_fetch_response (mu_list_t resp, mu_list_t *result_list); | ||
181 | 196 | ||
182 | # ifdef __cplusplus | 197 | # ifdef __cplusplus |
183 | } | 198 | } | ... | ... |
... | @@ -28,6 +28,7 @@ libmu_imap_la_LIBADD = ${MU_LIB_AUTH} ${MU_LIB_MAILUTILS} @INTLLIBS@ | ... | @@ -28,6 +28,7 @@ libmu_imap_la_LIBADD = ${MU_LIB_AUTH} ${MU_LIB_MAILUTILS} @INTLLIBS@ |
28 | # url.c | 28 | # url.c |
29 | libmu_imap_la_SOURCES = \ | 29 | libmu_imap_la_SOURCES = \ |
30 | fake-folder.c\ | 30 | fake-folder.c\ |
31 | fetch.c\ | ||
31 | callback.c\ | 32 | callback.c\ |
32 | capability.c\ | 33 | capability.c\ |
33 | capatst.c\ | 34 | capatst.c\ | ... | ... |
... | @@ -37,7 +37,7 @@ mu_imap_set_carrier (mu_imap_t imap, mu_stream_t carrier) | ... | @@ -37,7 +37,7 @@ mu_imap_set_carrier (mu_imap_t imap, mu_stream_t carrier) |
37 | if (imap == NULL) | 37 | if (imap == NULL) |
38 | return EINVAL; | 38 | return EINVAL; |
39 | 39 | ||
40 | rc = mu_imapio_create (&io, carrier); | 40 | rc = mu_imapio_create (&io, carrier, MU_IMAPIO_CLIENT); |
41 | if (rc) | 41 | if (rc) |
42 | return rc; | 42 | return rc; |
43 | if (imap->io) | 43 | if (imap->io) | ... | ... |
libproto/imap/fetch.c
0 → 100644
This diff is collapsed.
Click to expand it.
... | @@ -270,4 +270,13 @@ _mu_imap_list_at (mu_list_t list, int idx) | ... | @@ -270,4 +270,13 @@ _mu_imap_list_at (mu_list_t list, int idx) |
270 | return arg; | 270 | return arg; |
271 | } | 271 | } |
272 | 272 | ||
273 | int | ||
274 | _mu_imap_list_nth_element_is_string (mu_list_t list, size_t n, | ||
275 | const char *str) | ||
276 | { | ||
277 | struct imap_list_element *elt = _mu_imap_list_at (list, n); | ||
278 | return elt && elt->type == imap_eltype_string && | ||
279 | strcmp (elt->v.string, str) == 0; | ||
280 | } | ||
281 | |||
273 | 282 | ... | ... |
... | @@ -304,6 +304,34 @@ _process_unsolicited_response (mu_imap_t imap, mu_list_t resp) | ... | @@ -304,6 +304,34 @@ _process_unsolicited_response (mu_imap_t imap, mu_list_t resp) |
304 | return 0; | 304 | return 0; |
305 | } | 305 | } |
306 | } | 306 | } |
307 | else if (count == 3 && | ||
308 | _mu_imap_list_nth_element_is_string (resp, 1, "FETCH")) | ||
309 | { | ||
310 | size_t msgno; | ||
311 | |||
312 | arg = _mu_imap_list_at (resp, 0); | ||
313 | if (arg && arg->type == imap_eltype_string) | ||
314 | { | ||
315 | char *p; | ||
316 | msgno = strtoul (arg->v.string, &p, 10); | ||
317 | if (*p) | ||
318 | return 1; | ||
319 | |||
320 | arg = _mu_imap_list_at (resp, 2); | ||
321 | if (arg->type == imap_eltype_list) | ||
322 | { | ||
323 | mu_list_t list; | ||
324 | |||
325 | if (_mu_imap_parse_fetch_response (arg->v.list, &list) == 0) | ||
326 | { | ||
327 | mu_imap_callback (imap, MU_IMAP_CB_FETCH, msgno, list); | ||
328 | mu_list_destroy (&list); | ||
329 | } | ||
330 | return 0; | ||
331 | } | ||
332 | } | ||
333 | } | ||
334 | |||
307 | return 1; | 335 | return 1; |
308 | } | 336 | } |
309 | 337 | ||
... | @@ -317,8 +345,8 @@ _mu_imap_process_untagged_response (mu_imap_t imap, mu_list_t list, | ... | @@ -317,8 +345,8 @@ _mu_imap_process_untagged_response (mu_imap_t imap, mu_list_t list, |
317 | if (fun) | 345 | if (fun) |
318 | fun (imap, list, data); | 346 | fun (imap, list, data); |
319 | else | 347 | else |
320 | mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR, | 348 | mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE9, |
321 | ("ignoring unexpected response")); | 349 | ("ignoring unrecognized response")); |
322 | } | 350 | } |
323 | return 0; | 351 | return 0; |
324 | } | 352 | } | ... | ... |
... | @@ -89,21 +89,26 @@ mu_imap_trace_mask (mu_imap_t imap, int op, int lev) | ... | @@ -89,21 +89,26 @@ mu_imap_trace_mask (mu_imap_t imap, int op, int lev) |
89 | switch (op) | 89 | switch (op) |
90 | { | 90 | { |
91 | case MU_IMAP_TRACE_SET: | 91 | case MU_IMAP_TRACE_SET: |
92 | imap->flags |= MU_IMAP_XSCRIPT_MASK (lev); | 92 | MU_IMAP_SET_XSCRIPT_MASK (imap, lev); |
93 | if (lev & MU_XSCRIPT_PAYLOAD) | ||
94 | mu_imapio_trace_payload (imap->io, 1); | ||
93 | break; | 95 | break; |
94 | 96 | ||
95 | case MU_IMAP_TRACE_CLR: | 97 | case MU_IMAP_TRACE_CLR: |
96 | imap->flags &= ~MU_IMAP_XSCRIPT_MASK (lev); | 98 | MU_IMAP_CLR_XSCRIPT_MASK (imap, lev); |
99 | if (lev & MU_XSCRIPT_PAYLOAD) | ||
100 | mu_imapio_trace_payload (imap->io, 0); | ||
97 | break; | 101 | break; |
98 | 102 | ||
99 | case MU_IMAP_TRACE_QRY: | 103 | case MU_IMAP_TRACE_QRY: |
100 | if (imap->flags & MU_IMAP_XSCRIPT_MASK (lev)) | 104 | if (MU_IMAP_IS_XSCRIPT_MASK (imap, lev)) |
101 | break; | 105 | break; |
102 | return MU_ERR_NOENT; | 106 | return MU_ERR_NOENT; |
103 | 107 | ||
104 | default: | 108 | default: |
105 | return EINVAL; | 109 | return EINVAL; |
106 | } | 110 | } |
111 | |||
107 | return 0; | 112 | return 0; |
108 | } | 113 | } |
109 | 114 | ... | ... |
... | @@ -182,6 +182,13 @@ imap_bye_callback (void *data, int code, size_t sdat, void *pdat) | ... | @@ -182,6 +182,13 @@ imap_bye_callback (void *data, int code, size_t sdat, void *pdat) |
182 | mu_diag_output (MU_DIAG_INFO, _("server is closing connection")); | 182 | mu_diag_output (MU_DIAG_INFO, _("server is closing connection")); |
183 | } | 183 | } |
184 | 184 | ||
185 | static void | ||
186 | imap_bad_callback (void *data, int code, size_t sdat, void *pdat) | ||
187 | { | ||
188 | const char *text = pdat; | ||
189 | mu_diag_output (MU_DIAG_CRIT, "SERVER ALERT: %s", text); | ||
190 | } | ||
191 | |||
185 | 192 | ||
186 | static int | 193 | static int |
187 | com_disconnect (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED) | 194 | com_disconnect (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED) |
... | @@ -282,6 +289,9 @@ com_connect (int argc, char **argv) | ... | @@ -282,6 +289,9 @@ com_connect (int argc, char **argv) |
282 | mu_imap_register_callback_function (imap, MU_IMAP_CB_BYE, | 289 | mu_imap_register_callback_function (imap, MU_IMAP_CB_BYE, |
283 | imap_bye_callback, | 290 | imap_bye_callback, |
284 | NULL); | 291 | NULL); |
292 | mu_imap_register_callback_function (imap, MU_IMAP_CB_BAD, | ||
293 | imap_bad_callback, | ||
294 | NULL); | ||
285 | 295 | ||
286 | 296 | ||
287 | status = mu_imap_connect (imap); | 297 | status = mu_imap_connect (imap); |
... | @@ -587,44 +597,68 @@ com_noop (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED) | ... | @@ -587,44 +597,68 @@ com_noop (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED) |
587 | return 0; | 597 | return 0; |
588 | } | 598 | } |
589 | 599 | ||
600 | static int | ||
601 | com_fetch (int argc, char **argv) | ||
602 | { | ||
603 | int status = mu_imap_fetch (imap, argv[1], argv[2]); | ||
604 | if (status) | ||
605 | report_failure ("fetch", status); | ||
606 | return 0; | ||
607 | } | ||
608 | |||
590 | struct mutool_command imap_comtab[] = { | 609 | struct mutool_command imap_comtab[] = { |
591 | { "capability", 1, -1, com_capability, | 610 | { "capability", 1, -1, 0, |
611 | com_capability, | ||
592 | /* TRANSLATORS: -reread is a keyword; do not translate. */ | 612 | /* TRANSLATORS: -reread is a keyword; do not translate. */ |
593 | N_("[-reread] [NAME...]"), | 613 | N_("[-reread] [NAME...]"), |
594 | N_("list server capabilities") }, | 614 | N_("list server capabilities") }, |
595 | { "verbose", 1, 4, com_verbose, | 615 | { "verbose", 1, 4, 0, |
616 | com_verbose, | ||
596 | "[on|off|mask|unmask] [secure [payload]]", | 617 | "[on|off|mask|unmask] [secure [payload]]", |
597 | N_("control the protocol tracing") }, | 618 | N_("control the protocol tracing") }, |
598 | { "connect", 1, 4, com_connect, | 619 | { "connect", 1, 4, 0, |
620 | com_connect, | ||
599 | /* TRANSLATORS: --tls is a keyword. */ | 621 | /* TRANSLATORS: --tls is a keyword. */ |
600 | N_("[-tls] HOSTNAME [PORT]"), | 622 | N_("[-tls] HOSTNAME [PORT]"), |
601 | N_("open connection") }, | 623 | N_("open connection") }, |
602 | { "disconnect", 1, 1, | 624 | { "disconnect", 1, 1, 0, |
603 | com_disconnect, | 625 | com_disconnect, |
604 | NULL, | 626 | NULL, |
605 | N_("close connection") }, | 627 | N_("close connection") }, |
606 | { "login", 2, 3, com_login, | 628 | { "login", 2, 3, 0, |
629 | com_login, | ||
607 | N_("USER [PASS]"), | 630 | N_("USER [PASS]"), |
608 | N_("login to the server") }, | 631 | N_("login to the server") }, |
609 | { "logout", 1, 1, com_logout, | 632 | { "logout", 1, 1, 0, |
633 | com_logout, | ||
610 | NULL, | 634 | NULL, |
611 | N_("quit imap session") }, | 635 | N_("quit imap session") }, |
612 | { "id", 1, -1, com_id, | 636 | { "id", 1, -1, 0, |
637 | com_id, | ||
613 | N_("[-test KW] [ARG [ARG...]]"), | 638 | N_("[-test KW] [ARG [ARG...]]"), |
614 | N_("send ID command") }, | 639 | N_("send ID command") }, |
615 | { "noop", 1, 1, com_noop, | 640 | { "noop", 1, 1, 0, |
641 | com_noop, | ||
616 | NULL, | 642 | NULL, |
617 | N_("no operation (keepalive)") }, | 643 | N_("no operation (keepalive)") }, |
618 | { "select", 1, 2, com_select, | 644 | { "select", 1, 2, 0, |
645 | com_select, | ||
619 | N_("[MBOX]"), | 646 | N_("[MBOX]"), |
620 | N_("select a mailbox") }, | 647 | N_("select a mailbox") }, |
621 | { "examine", 1, 2, com_examine, | 648 | { "examine", 1, 2, 0, |
649 | com_examine, | ||
622 | N_("[MBOX]"), | 650 | N_("[MBOX]"), |
623 | N_("examine a mailbox") }, | 651 | N_("examine a mailbox") }, |
624 | { "status", 3, -1, com_status, | 652 | { "status", 3, -1, 0, |
653 | com_status, | ||
625 | N_("MBOX KW [KW...]"), | 654 | N_("MBOX KW [KW...]"), |
626 | N_("get mailbox status") }, | 655 | N_("get mailbox status") }, |
627 | { "quit", 1, 1, com_logout, | 656 | { "fetch", 3, 3, CMD_COALESCE_EXTRA_ARGS, |
657 | com_fetch, | ||
658 | N_("MSGSET ITEMS"), | ||
659 | N_("fetch message data") }, | ||
660 | { "quit", 1, 1, 0, | ||
661 | com_logout, | ||
628 | NULL, | 662 | NULL, |
629 | N_("same as `logout'") }, | 663 | N_("same as `logout'") }, |
630 | { NULL } | 664 | { NULL } | ... | ... |
... | @@ -18,13 +18,15 @@ | ... | @@ -18,13 +18,15 @@ |
18 | 18 | ||
19 | typedef int (*mutool_action_t) (int argc, char **argv); | 19 | typedef int (*mutool_action_t) (int argc, char **argv); |
20 | 20 | ||
21 | #define CMD_COALESCE_EXTRA_ARGS 0x01 | ||
22 | |||
21 | struct mutool_command | 23 | struct mutool_command |
22 | { | 24 | { |
23 | const char *name; /* User printable name of the function. */ | 25 | const char *name; /* User printable name of the function. */ |
24 | int argmin; /* Min. acceptable number of arguments (-1 means | 26 | int argmin; /* Min. acceptable number of arguments (> 1) */ |
25 | pass all arguments as a single string */ | ||
26 | int argmax; /* Max. allowed number of arguments (-1 means not | 27 | int argmax; /* Max. allowed number of arguments (-1 means not |
27 | limited */ | 28 | limited */ |
29 | int flags; | ||
28 | mutool_action_t func; /* Function to call to do the job. */ | 30 | mutool_action_t func; /* Function to call to do the job. */ |
29 | const char *argdoc; /* Documentation for the arguments */ | 31 | const char *argdoc; /* Documentation for the arguments */ |
30 | const char *docstring;/* Documentation for this function. */ | 32 | const char *docstring;/* Documentation for this function. */ | ... | ... |
... | @@ -611,59 +611,59 @@ com_quit (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED) | ... | @@ -611,59 +611,59 @@ com_quit (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED) |
611 | } | 611 | } |
612 | 612 | ||
613 | struct mutool_command pop_comtab[] = { | 613 | struct mutool_command pop_comtab[] = { |
614 | { "apop", 2, 3, com_apop, | 614 | { "apop", 2, 3, 0, com_apop, |
615 | N_("USER [PASS]"), | 615 | N_("USER [PASS]"), |
616 | N_("authenticate with APOP") }, | 616 | N_("authenticate with APOP") }, |
617 | { "capa", 1, -1, com_capa, | 617 | { "capa", 1, -1, 0, com_capa, |
618 | /* TRANSLATORS: -reread is a keyword; do not translate. */ | 618 | /* TRANSLATORS: -reread is a keyword; do not translate. */ |
619 | N_("[-reread] [NAME...]"), | 619 | N_("[-reread] [NAME...]"), |
620 | N_("list server capabilities") }, | 620 | N_("list server capabilities") }, |
621 | { "disconnect", 1, 1, | 621 | { "disconnect", 1, 1, 0, |
622 | com_disconnect, | 622 | com_disconnect, |
623 | NULL, | 623 | NULL, |
624 | N_("close connection") }, | 624 | N_("close connection") }, |
625 | { "dele", 2, 2, com_dele, | 625 | { "dele", 2, 2, 0, com_dele, |
626 | N_("NUMBER"), | 626 | N_("NUMBER"), |
627 | N_("mark message for deletion") }, | 627 | N_("mark message for deletion") }, |
628 | { "list", 1, 2, com_list, | 628 | { "list", 1, 2, 0, com_list, |
629 | N_("[NUMBER]"), | 629 | N_("[NUMBER]"), |
630 | N_("list messages") }, | 630 | N_("list messages") }, |
631 | { "noop", 1, 1, com_noop, | 631 | { "noop", 1, 1, 0, com_noop, |
632 | NULL, | 632 | NULL, |
633 | N_("send a \"no operation\"") }, | 633 | N_("send a \"no operation\"") }, |
634 | { "pass", 1, 2, com_pass, | 634 | { "pass", 1, 2, 0, com_pass, |
635 | N_("[PASSWORD]"), | 635 | N_("[PASSWORD]"), |
636 | N_("send password") }, | 636 | N_("send password") }, |
637 | { "connect", 1, 4, com_connect, | 637 | { "connect", 1, 4, 0, com_connect, |
638 | /* TRANSLATORS: --tls is a keyword. */ | 638 | /* TRANSLATORS: --tls is a keyword. */ |
639 | N_("[-tls] HOSTNAME [PORT]"), | 639 | N_("[-tls] HOSTNAME [PORT]"), |
640 | N_("open connection") }, | 640 | N_("open connection") }, |
641 | { "quit", 1, 1, com_quit, | 641 | { "quit", 1, 1, 0, com_quit, |
642 | NULL, | 642 | NULL, |
643 | N_("quit pop3 session") }, | 643 | N_("quit pop3 session") }, |
644 | { "retr", 2, 2, com_retr, | 644 | { "retr", 2, 2, 0, com_retr, |
645 | "NUMBER", | 645 | "NUMBER", |
646 | N_("retrieve a message") }, | 646 | N_("retrieve a message") }, |
647 | { "rset", 1, 1, com_rset, | 647 | { "rset", 1, 1, 0, com_rset, |
648 | NULL, | 648 | NULL, |
649 | N_("remove deletion marks") }, | 649 | N_("remove deletion marks") }, |
650 | { "stat", 1, 1, com_stat, | 650 | { "stat", 1, 1, 0, com_stat, |
651 | NULL, | 651 | NULL, |
652 | N_("get the mailbox size and number of messages in it") }, | 652 | N_("get the mailbox size and number of messages in it") }, |
653 | { "stls", 1, 1, com_stls, | 653 | { "stls", 1, 1, 0, com_stls, |
654 | NULL, | 654 | NULL, |
655 | N_("start TLS negotiation") }, | 655 | N_("start TLS negotiation") }, |
656 | { "top", 2, 3, com_top, | 656 | { "top", 2, 3, 0, com_top, |
657 | "MSGNO [NUMBER]", | 657 | "MSGNO [NUMBER]", |
658 | N_("display message headers and first NUMBER (default 5) lines of" | 658 | N_("display message headers and first NUMBER (default 5) lines of" |
659 | " its body") }, | 659 | " its body") }, |
660 | { "uidl", 1, 2, com_uidl, | 660 | { "uidl", 1, 2, 0, com_uidl, |
661 | N_("[NUMBER]"), | 661 | N_("[NUMBER]"), |
662 | N_("show unique message identifiers") }, | 662 | N_("show unique message identifiers") }, |
663 | { "user", 2, 2, com_user, | 663 | { "user", 2, 2, 0, com_user, |
664 | N_("NAME"), | 664 | N_("NAME"), |
665 | N_("send login") }, | 665 | N_("send login") }, |
666 | { "verbose", 1, 4, com_verbose, | 666 | { "verbose", 1, 4, 0, com_verbose, |
667 | "[on|off|mask|unmask] [secure [payload]]", | 667 | "[on|off|mask|unmask] [secure [payload]]", |
668 | N_("control the protocol tracing") }, | 668 | N_("control the protocol tracing") }, |
669 | { NULL } | 669 | { NULL } | ... | ... |
... | @@ -71,18 +71,18 @@ static int shell_history (int, char **); | ... | @@ -71,18 +71,18 @@ static int shell_history (int, char **); |
71 | #endif | 71 | #endif |
72 | 72 | ||
73 | struct mutool_command default_comtab[] = { | 73 | struct mutool_command default_comtab[] = { |
74 | { "prompt", -1, -1, shell_prompt, | 74 | { "prompt", 1, 2, CMD_COALESCE_EXTRA_ARGS, shell_prompt, |
75 | N_("STRING"), | 75 | N_("STRING"), |
76 | N_("set command prompt") }, | 76 | N_("set command prompt") }, |
77 | { "exit", 1, 1, shell_exit, NULL, N_("exit program") }, | 77 | { "exit", 1, 1, 0, shell_exit, NULL, N_("exit program") }, |
78 | { "help", 1, 2, shell_help, | 78 | { "help", 1, 2, 0, shell_help, |
79 | N_("[COMMAND]"), | 79 | N_("[COMMAND]"), |
80 | N_("display this text") }, | 80 | N_("display this text") }, |
81 | { "?", 1, 1, shell_help, | 81 | { "?", 1, 1, 0, shell_help, |
82 | N_("[COMMAND]"), | 82 | N_("[COMMAND]"), |
83 | N_("synonym for `help'") }, | 83 | N_("synonym for `help'") }, |
84 | #ifdef WITH_READLINE | 84 | #ifdef WITH_READLINE |
85 | { "history", 1, 1, shell_history, | 85 | { "history", 1, 1, 0, shell_history, |
86 | NULL, | 86 | NULL, |
87 | N_("show command history") }, | 87 | N_("show command history") }, |
88 | #endif | 88 | #endif |
... | @@ -492,59 +492,101 @@ add_history (const char *s MU_ARG_UNUSED) | ... | @@ -492,59 +492,101 @@ add_history (const char *s MU_ARG_UNUSED) |
492 | } | 492 | } |
493 | #endif | 493 | #endif |
494 | 494 | ||
495 | static int | ||
496 | next_arg (struct mu_wordsplit *ws) | ||
497 | { | ||
498 | int rc = mu_wordsplit (NULL, ws, MU_WRDSF_INCREMENTAL); | ||
499 | if (rc == MU_WRDSE_NOINPUT) | ||
500 | { | ||
501 | mu_error ("%s: too few arguments", ws->ws_wordv[0]); | ||
502 | mu_wordsplit_free (ws); | ||
503 | return -1; | ||
504 | } | ||
505 | else if (rc) | ||
506 | { | ||
507 | mu_error ("cannot parse input line: %s", | ||
508 | mu_wordsplit_strerror (ws)); | ||
509 | return 1; | ||
510 | } | ||
511 | return 0; | ||
512 | } | ||
513 | |||
495 | /* Parse and execute a command line. */ | 514 | /* Parse and execute a command line. */ |
496 | int | 515 | int |
497 | execute_line (char *line) | 516 | execute_line (char *line) |
498 | { | 517 | { |
518 | int rc; | ||
499 | struct mu_wordsplit ws; | 519 | struct mu_wordsplit ws; |
500 | int argc; | 520 | struct mutool_command *cmd; |
501 | char **argv; | ||
502 | int status = 0; | 521 | int status = 0; |
503 | 522 | ||
504 | ws.ws_comment = "#"; | 523 | ws.ws_comment = "#"; |
505 | ws.ws_offs = 1; /* Keep extra slot for expansion in case when argmin == -1 */ | 524 | rc = mu_wordsplit (line, &ws, |
506 | if (mu_wordsplit (line, &ws, | 525 | MU_WRDSF_DEFFLAGS|MU_WRDSF_COMMENT| |
507 | MU_WRDSF_DEFFLAGS|MU_WRDSF_COMMENT|MU_WRDSF_DOOFFS)) | 526 | MU_WRDSF_INCREMENTAL|MU_WRDSF_APPEND); |
527 | if (rc == MU_WRDSE_NOINPUT) | ||
528 | { | ||
529 | mu_wordsplit_free (&ws); | ||
530 | return 0; | ||
531 | } | ||
532 | else if (rc) | ||
508 | { | 533 | { |
509 | mu_error("cannot parse input line: %s", mu_wordsplit_strerror (&ws)); | 534 | mu_error ("cannot parse input line: %s", mu_wordsplit_strerror (&ws)); |
510 | return 0; | 535 | return 0; |
511 | } | 536 | } |
512 | argc = ws.ws_wordc; | ||
513 | argv = ws.ws_wordv + 1; | ||
514 | 537 | ||
515 | if (argc >= 0) | 538 | if (ws.ws_wordc) |
516 | { | 539 | { |
517 | struct mutool_command *cmd = find_command (argv[0]); | 540 | int argmin; |
541 | cmd = find_command (ws.ws_wordv[0]); | ||
518 | 542 | ||
519 | if (!cmd) | 543 | if (!cmd) |
520 | mu_error ("%s: no such command.", argv[0]); | 544 | { |
521 | else if (cmd->argmin > 0 && argc < cmd->argmin) | 545 | mu_error ("%s: no such command.", ws.ws_wordv[0]); |
522 | mu_error ("%s: too few arguments", argv[0]); | 546 | mu_wordsplit_free (&ws); |
523 | else if (cmd->argmax > 0 && argc > cmd->argmax) | 547 | return 0; |
524 | mu_error ("%s: too many arguments", argv[0]); | 548 | } |
549 | |||
550 | argmin = cmd->argmin; | ||
551 | if (cmd->flags & CMD_COALESCE_EXTRA_ARGS) | ||
552 | --argmin; | ||
553 | while (ws.ws_wordc < argmin) | ||
554 | { | ||
555 | if (next_arg (&ws)) | ||
556 | return 0; | ||
557 | } | ||
558 | |||
559 | if (cmd->flags & CMD_COALESCE_EXTRA_ARGS) | ||
560 | { | ||
561 | ws.ws_flags |= MU_WRDSF_NOSPLIT; | ||
562 | if (next_arg (&ws)) | ||
563 | return 0; | ||
564 | } | ||
525 | else | 565 | else |
526 | { | 566 | { |
527 | if (cmd->argmin <= 0 && argc != 2) | 567 | for (;;) |
568 | { | ||
569 | if (cmd->argmax > 0 && ws.ws_wordc > cmd->argmax) | ||
528 | { | 570 | { |
529 | size_t i; | 571 | mu_error ("%s: too many arguments", ws.ws_wordv[0]); |
530 | char *word = mu_str_skip_class (line, MU_CTYPE_SPACE); | 572 | mu_wordsplit_free (&ws); |
531 | char *arg = mu_str_skip_class_comp (word, MU_CTYPE_SPACE); | 573 | return 0; |
532 | if (*arg) | 574 | } |
575 | rc = mu_wordsplit (NULL, &ws, MU_WRDSF_INCREMENTAL); | ||
576 | if (rc == 0) | ||
577 | continue; | ||
578 | else if (rc == MU_WRDSE_NOINPUT) | ||
579 | break; | ||
580 | else | ||
533 | { | 581 | { |
534 | *arg++ = 0; | 582 | mu_error ("cannot parse input line: %s", |
535 | arg = mu_str_skip_class (arg, MU_CTYPE_SPACE); | 583 | mu_wordsplit_strerror (&ws)); |
584 | return 0; | ||
536 | } | 585 | } |
537 | for (i = 0; i < ws.ws_wordc; i++) | ||
538 | free (ws.ws_wordv[i + 1]); | ||
539 | ws.ws_wordv[0] = xstrdup (word); | ||
540 | ws.ws_wordv[1] = xstrdup (arg); | ||
541 | ws.ws_wordv[2] = NULL; | ||
542 | ws.ws_wordc = 2; | ||
543 | argc = ws.ws_wordc; | ||
544 | argv = ws.ws_wordv; | ||
545 | } | 586 | } |
546 | status = cmd->func (argc, argv); | ||
547 | } | 587 | } |
588 | |||
589 | status = cmd->func (ws.ws_wordc, ws.ws_wordv); | ||
548 | } | 590 | } |
549 | mu_wordsplit_free (&ws); | 591 | mu_wordsplit_free (&ws); |
550 | return status; | 592 | return status; | ... | ... |
-
Please register or sign in to post a comment