Fix input operations and RFC-compliance in imap4d.
* imap4d/util.c (util_getword, util_getitem, util_token) (util_unquote): Remove. (imap4d_readline): Rewrite to reduce memory reallocation. Add support for non-synchronizing literals (RFC 2088). (imap4d_readline_ex): Remove. (util_do_command): Rewrite using new imap4d_readline. (util_parse_internal_date0): Remove. (imap4d_tokbuf_init, imap4d_tokbuf_destroy, imap4d_tokbuf_argc) (imap4d_tokbuf_getarg, util_isdelim) (imap4d_tokbuf_from_string): New functions. * imap4d/append.c, imap4d/auth_gss.c, imap4d/authenticate.c, imap4d/check.c, imap4d/close.c, imap4d/commands.c, imap4d/copy.c, imap4d/create.c, imap4d/delete.c, imap4d/examine.c, imap4d/imap4d.h, imap4d/list.c, imap4d/login.c, imap4d/logout.c, imap4d/lsub.c, imap4d/expunge.c, imap4d/idle.c, imap4d/noop.c, imap4d/rename.c, imap4d/search.c, imap4d/select.c, imap4d/starttls.c, imap4d/status.c, imap4d/store.c, imap4d/subscribe.c, imap4d/uid.c, imap4d/unsubscribe.c, imap4d/version.c: Rewrite using new imap4d_readline. * imap4d/namespace.c: Use new imap4d_readline. Ensure that each reported prefix ends with a hierarchy delimiter. * imap4d/imap4d.c (imap4d_mainloop): Use new imap4d_readline. * imap4d/fetch.c: Rewrite parser from scratch. * imap4d/capability.c (imap4d_capability_init): Report LITERAL+ capability. * imap4d/testsuite/imap4d/anystate.exp: Account for the LITERAL+ capability. * imap4d/testsuite/imap4d/append.exp: Fix APPEND arguments (imap4d requires exactly three arguments, as per RFC3501. Fix octet count in literals returned by fetch (previous versions failed to include the trailing CRLF). * imap4d/testsuite/imap4d/create.exp: Likewise. * imap4d/testsuite/imap4d/fetch.exp: Fix FETCH arguments (previous versions incorrectly accepted header-list without parentheses. Fix result of FETCH 4 BODY[2.2.1]: it returns entire part, in the contrast to previous versions, which treated it as BODY[2.2.1.TEXT]. * maidag/mailtmp.c (mail_tmp_finish): Ensure /dev/null is treated as mailbox.
Showing
40 changed files
with
2200 additions
and
1756 deletions
1 | 2008-08-11 Sergey Poznyakoff <gray@gnu.org.ua> | ||
2 | |||
3 | Fix input operations and RFC-compliance in imap4d. | ||
4 | |||
5 | * imap4d/util.c (util_getword, util_getitem, util_token) | ||
6 | (util_unquote): Remove. | ||
7 | (imap4d_readline): Rewrite to reduce memory reallocation. Add | ||
8 | support for non-synchronizing literals (RFC 2088). | ||
9 | (imap4d_readline_ex): Remove. | ||
10 | (util_do_command): Rewrite using new imap4d_readline. | ||
11 | (util_parse_internal_date0): Remove. | ||
12 | (imap4d_tokbuf_init, imap4d_tokbuf_destroy, imap4d_tokbuf_argc) | ||
13 | (imap4d_tokbuf_getarg, util_isdelim) | ||
14 | (imap4d_tokbuf_from_string): New functions. | ||
15 | * imap4d/append.c, imap4d/auth_gss.c, imap4d/authenticate.c, | ||
16 | imap4d/check.c, imap4d/close.c, imap4d/commands.c, imap4d/copy.c, | ||
17 | imap4d/create.c, imap4d/delete.c, imap4d/examine.c, | ||
18 | imap4d/imap4d.h, imap4d/list.c, imap4d/login.c, imap4d/logout.c, | ||
19 | imap4d/lsub.c, imap4d/expunge.c, imap4d/idle.c, imap4d/noop.c, | ||
20 | imap4d/rename.c, imap4d/search.c, imap4d/select.c, | ||
21 | imap4d/starttls.c, imap4d/status.c, imap4d/store.c, | ||
22 | imap4d/subscribe.c, imap4d/uid.c, imap4d/unsubscribe.c, | ||
23 | imap4d/version.c: Rewrite using new imap4d_readline. | ||
24 | * imap4d/namespace.c: Use new imap4d_readline. Ensure that | ||
25 | each reported prefix ends with a hierarchy delimiter. | ||
26 | * imap4d/imap4d.c (imap4d_mainloop): Use new imap4d_readline. | ||
27 | * imap4d/fetch.c: Rewrite parser from scratch. | ||
28 | * imap4d/capability.c (imap4d_capability_init): Report LITERAL+ | ||
29 | capability. | ||
30 | |||
31 | * imap4d/testsuite/imap4d/anystate.exp: Account for the LITERAL+ | ||
32 | capability. | ||
33 | * imap4d/testsuite/imap4d/append.exp: Fix APPEND arguments (imap4d | ||
34 | requires exactly three arguments, as per RFC3501. | ||
35 | Fix octet count in literals returned by fetch (previous versions | ||
36 | failed to include the trailing CRLF). | ||
37 | * imap4d/testsuite/imap4d/create.exp: Likewise. | ||
38 | * imap4d/testsuite/imap4d/fetch.exp: Fix FETCH arguments (previous | ||
39 | versions incorrectly accepted header-list without parentheses. | ||
40 | Fix result of FETCH 4 BODY[2.2.1]: it returns entire part, in the | ||
41 | contrast to previous versions, which treated it as | ||
42 | BODY[2.2.1.TEXT]. | ||
43 | |||
44 | * maidag/mailtmp.c (mail_tmp_finish): Ensure /dev/null is treated | ||
45 | as mailbox. | ||
46 | |||
1 | 2008-08-08 Sergey Poznyakoff <gray@gnu.org.ua> | 47 | 2008-08-08 Sergey Poznyakoff <gray@gnu.org.ua> |
2 | 48 | ||
3 | Fix imap appends for AMD mailboxes. | 49 | Fix imap appends for AMD mailboxes. | ... | ... |
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | 1 | /* GNU Mailutils -- a suite of utilities for electronic mail |
2 | Copyright (C) 1999, 2001, 2005, 2006, 2007 Free Software Foundation, Inc. | 2 | Copyright (C) 1999, 2001, 2005, 2006, 2007, |
3 | 2008 Free Software Foundation, Inc. | ||
3 | 4 | ||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | 5 | GNU Mailutils is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU General Public License as published by | 6 | it under the terms of the GNU General Public License as published by |
... | @@ -18,49 +19,6 @@ | ... | @@ -18,49 +19,6 @@ |
18 | 19 | ||
19 | #include "imap4d.h" | 20 | #include "imap4d.h" |
20 | 21 | ||
21 | /* APPEND mbox [(flags)] [date_time] message_literal */ | ||
22 | int | ||
23 | imap4d_append (struct imap4d_command *command, char *arg) | ||
24 | { | ||
25 | char *sp; | ||
26 | char *mboxname; | ||
27 | int flags = 0; | ||
28 | mu_mailbox_t dest_mbox = NULL; | ||
29 | int status; | ||
30 | |||
31 | mboxname = util_getword (arg, &sp); | ||
32 | if (!mboxname) | ||
33 | return util_finish (command, RESP_BAD, "Too few arguments"); | ||
34 | |||
35 | util_unquote (&mboxname); | ||
36 | |||
37 | if (*sp == '(' && util_parse_attributes (sp+1, &sp, &flags)) | ||
38 | return util_finish (command, RESP_BAD, "Missing closing parenthesis"); | ||
39 | |||
40 | mboxname = namespace_getfullpath (mboxname, "/"); | ||
41 | if (!mboxname) | ||
42 | return util_finish (command, RESP_NO, "Couldn't open mailbox"); | ||
43 | |||
44 | status = mu_mailbox_create_default (&dest_mbox, mboxname); | ||
45 | if (status == 0) | ||
46 | { | ||
47 | /* It SHOULD NOT automatifcllly create the mailbox. */ | ||
48 | status = mu_mailbox_open (dest_mbox, MU_STREAM_RDWR); | ||
49 | if (status == 0) | ||
50 | { | ||
51 | status = imap4d_append0 (dest_mbox, flags, sp); | ||
52 | mu_mailbox_close (dest_mbox); | ||
53 | } | ||
54 | mu_mailbox_destroy (&dest_mbox); | ||
55 | } | ||
56 | |||
57 | free (mboxname); | ||
58 | if (status == 0) | ||
59 | return util_finish (command, RESP_OK, "Completed"); | ||
60 | |||
61 | return util_finish (command, RESP_NO, "[TRYCREATE] failed"); | ||
62 | } | ||
63 | |||
64 | static int | 22 | static int |
65 | _append_date (mu_envelope_t envelope, char *buf, size_t len, size_t *pnwrite) | 23 | _append_date (mu_envelope_t envelope, char *buf, size_t len, size_t *pnwrite) |
66 | { | 24 | { |
... | @@ -93,12 +51,18 @@ _append_size (mu_message_t msg, size_t *psize) | ... | @@ -93,12 +51,18 @@ _append_size (mu_message_t msg, size_t *psize) |
93 | mu_stream_t str; | 51 | mu_stream_t str; |
94 | int status = mu_message_get_stream (msg, &str); | 52 | int status = mu_message_get_stream (msg, &str); |
95 | if (status == 0) | 53 | if (status == 0) |
96 | status = mu_stream_size (str, psize); | 54 | { |
55 | mu_off_t size; | ||
56 | status = mu_stream_size (str, &size); | ||
57 | if (status == 0 && psize) | ||
58 | *psize = size; | ||
59 | } | ||
97 | return status; | 60 | return status; |
98 | } | 61 | } |
99 | 62 | ||
100 | int | 63 | int |
101 | imap4d_append0 (mu_mailbox_t mbox, int flags, char *text) | 64 | imap4d_append0 (mu_mailbox_t mbox, int flags, char *date_time, char *text, |
65 | char **err_text) | ||
102 | { | 66 | { |
103 | mu_stream_t stream; | 67 | mu_stream_t stream; |
104 | int rc = 0; | 68 | int rc = 0; |
... | @@ -118,23 +82,25 @@ imap4d_append0 (mu_mailbox_t mbox, int flags, char *text) | ... | @@ -118,23 +82,25 @@ imap4d_append0 (mu_mailbox_t mbox, int flags, char *text) |
118 | return 1; | 82 | return 1; |
119 | } | 83 | } |
120 | 84 | ||
121 | while (*text && isspace (*text)) | ||
122 | text++; | ||
123 | |||
124 | /* If a date_time is specified, the internal date SHOULD be set in the | 85 | /* If a date_time is specified, the internal date SHOULD be set in the |
125 | resulting message; otherwise, the internal date of the resulting | 86 | resulting message; otherwise, the internal date of the resulting |
126 | message is set to the current date and time by default. */ | 87 | message is set to the current date and time by default. */ |
127 | if (util_parse_internal_date0 (text, &t, &text) == 0) | 88 | if (date_time) |
128 | { | 89 | { |
129 | while (*text && isspace(*text)) | 90 | if (util_parse_internal_date (date_time, &t)) |
130 | text++; | 91 | { |
92 | *err_text = "Invalid date/time format"; | ||
93 | return 1; | ||
94 | } | ||
131 | } | 95 | } |
132 | else | 96 | else |
133 | { | ||
134 | time(&t); | 97 | time(&t); |
135 | } | 98 | |
136 | tm = gmtime(&t); | 99 | tm = gmtime(&t); |
137 | 100 | ||
101 | while (*text && isspace (*text)) | ||
102 | text++; | ||
103 | |||
138 | mu_stream_write (stream, text, strlen (text), len, &len); | 104 | mu_stream_write (stream, text, strlen (text), len, &len); |
139 | mu_message_set_stream (msg, stream, &tm); | 105 | mu_message_set_stream (msg, stream, &tm); |
140 | mu_message_set_size (msg, _append_size, &tm); | 106 | mu_message_set_size (msg, _append_size, &tm); |
... | @@ -159,3 +125,86 @@ imap4d_append0 (mu_mailbox_t mbox, int flags, char *text) | ... | @@ -159,3 +125,86 @@ imap4d_append0 (mu_mailbox_t mbox, int flags, char *text) |
159 | } | 125 | } |
160 | 126 | ||
161 | 127 | ||
128 | /* APPEND mbox [(flags)] [date_time] message_literal */ | ||
129 | int | ||
130 | imap4d_append (struct imap4d_command *command, imap4d_tokbuf_t tok) | ||
131 | { | ||
132 | int i; | ||
133 | char *mboxname; | ||
134 | int flags = 0; | ||
135 | mu_mailbox_t dest_mbox = NULL; | ||
136 | int status; | ||
137 | int argc = imap4d_tokbuf_argc (tok); | ||
138 | char *date_time; | ||
139 | char *msg_text; | ||
140 | char *err_text = "[TRYCREATE] failed"; | ||
141 | |||
142 | if (argc < 4) | ||
143 | return util_finish (command, RESP_BAD, "Too few arguments"); | ||
144 | |||
145 | mboxname = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1); | ||
146 | if (!mboxname) | ||
147 | return util_finish (command, RESP_BAD, "Too few arguments"); | ||
148 | |||
149 | i = IMAP4_ARG_2; | ||
150 | if (imap4d_tokbuf_getarg (tok, i)[0] == '(') | ||
151 | { | ||
152 | while (++i < argc) | ||
153 | { | ||
154 | int type; | ||
155 | char *arg = imap4d_tokbuf_getarg (tok, i); | ||
156 | |||
157 | if (!util_attribute_to_type (arg, &type)) | ||
158 | flags |= type; | ||
159 | else if (arg[0] == ')') | ||
160 | break; | ||
161 | } | ||
162 | if (i == argc) | ||
163 | return util_finish (command, RESP_BAD, "Missing closing parenthesis"); | ||
164 | i++; | ||
165 | } | ||
166 | |||
167 | switch (argc - i) | ||
168 | { | ||
169 | case 2: | ||
170 | /* Date/time is present */ | ||
171 | date_time = imap4d_tokbuf_getarg (tok, i); | ||
172 | i++; | ||
173 | break; | ||
174 | |||
175 | case 1: | ||
176 | date_time = NULL; | ||
177 | break; | ||
178 | |||
179 | default: | ||
180 | return util_finish (command, RESP_BAD, "Too many arguments"); | ||
181 | } | ||
182 | |||
183 | msg_text = imap4d_tokbuf_getarg (tok, i); | ||
184 | |||
185 | mboxname = namespace_getfullpath (mboxname, "/"); | ||
186 | if (!mboxname) | ||
187 | return util_finish (command, RESP_NO, "Couldn't open mailbox"); | ||
188 | |||
189 | status = mu_mailbox_create_default (&dest_mbox, mboxname); | ||
190 | if (status == 0) | ||
191 | { | ||
192 | /* It SHOULD NOT automatically create the mailbox. */ | ||
193 | status = mu_mailbox_open (dest_mbox, MU_STREAM_RDWR); | ||
194 | if (status == 0) | ||
195 | { | ||
196 | status = imap4d_append0 (dest_mbox, flags, date_time, msg_text, | ||
197 | &err_text); | ||
198 | mu_mailbox_close (dest_mbox); | ||
199 | } | ||
200 | mu_mailbox_destroy (&dest_mbox); | ||
201 | } | ||
202 | |||
203 | free (mboxname); | ||
204 | if (status == 0) | ||
205 | return util_finish (command, RESP_OK, "Completed"); | ||
206 | |||
207 | return util_finish (command, RESP_NO, err_text); | ||
208 | } | ||
209 | |||
210 | ... | ... |
... | @@ -119,7 +119,9 @@ auth_gssapi (struct imap4d_command *command, | ... | @@ -119,7 +119,9 @@ auth_gssapi (struct imap4d_command *command, |
119 | gss_ctx_id_t context; | 119 | gss_ctx_id_t context; |
120 | gss_cred_id_t cred_handle, server_creds; | 120 | gss_cred_id_t cred_handle, server_creds; |
121 | gss_OID mech_type; | 121 | gss_OID mech_type; |
122 | char *token_str; | 122 | char *token_str = NULL; |
123 | size_t token_size = 0; | ||
124 | size_t token_len; | ||
123 | unsigned char *tmp = NULL; | 125 | unsigned char *tmp = NULL; |
124 | size_t size; | 126 | size_t size; |
125 | gss_name_t server_name; | 127 | gss_name_t server_name; |
... | @@ -168,11 +170,10 @@ auth_gssapi (struct imap4d_command *command, | ... | @@ -168,11 +170,10 @@ auth_gssapi (struct imap4d_command *command, |
168 | 170 | ||
169 | for (;;) | 171 | for (;;) |
170 | { | 172 | { |
171 | token_str = imap4d_readline_ex (); | 173 | imap4d_getline (&token_str, &token_size, &token_len); |
172 | util_base64_decode (token_str, strlen (token_str), &tmp, &size); | 174 | util_base64_decode (token_str, token_len, &tmp, &size); |
173 | tokbuf.value = tmp; | 175 | tokbuf.value = tmp; |
174 | tokbuf.length = size; | 176 | tokbuf.length = size; |
175 | free (token_str); | ||
176 | 177 | ||
177 | maj_stat = gss_accept_sec_context (&min_stat, | 178 | maj_stat = gss_accept_sec_context (&min_stat, |
178 | &context, | 179 | &context, |
... | @@ -202,6 +203,7 @@ auth_gssapi (struct imap4d_command *command, | ... | @@ -202,6 +203,7 @@ auth_gssapi (struct imap4d_command *command, |
202 | display_status ("accept context", maj_stat, min_stat); | 203 | display_status ("accept context", maj_stat, min_stat); |
203 | maj_stat = gss_delete_sec_context (&min_stat, &context, &outbuf); | 204 | maj_stat = gss_delete_sec_context (&min_stat, &context, &outbuf); |
204 | gss_release_buffer (&min_stat, &outbuf); | 205 | gss_release_buffer (&min_stat, &outbuf); |
206 | free (token_str); | ||
205 | return RESP_NO; | 207 | return RESP_NO; |
206 | } | 208 | } |
207 | 209 | ||
... | @@ -211,8 +213,7 @@ auth_gssapi (struct imap4d_command *command, | ... | @@ -211,8 +213,7 @@ auth_gssapi (struct imap4d_command *command, |
211 | util_send ("+ %*.*s\r\n", size, size, tmp); | 213 | util_send ("+ %*.*s\r\n", size, size, tmp); |
212 | free (tmp); | 214 | free (tmp); |
213 | gss_release_buffer (&min_stat, &outbuf); | 215 | gss_release_buffer (&min_stat, &outbuf); |
214 | token_str = imap4d_readline_ex (); | 216 | imap4d_getline (&token_str, &token_size, &token_len); |
215 | free (token_str); | ||
216 | } | 217 | } |
217 | 218 | ||
218 | /* Construct security-level data */ | 219 | /* Construct security-level data */ |
... | @@ -224,6 +225,7 @@ auth_gssapi (struct imap4d_command *command, | ... | @@ -224,6 +225,7 @@ auth_gssapi (struct imap4d_command *command, |
224 | if (maj_stat != GSS_S_COMPLETE) | 225 | if (maj_stat != GSS_S_COMPLETE) |
225 | { | 226 | { |
226 | display_status ("wrap", maj_stat, min_stat); | 227 | display_status ("wrap", maj_stat, min_stat); |
228 | free (token_str); | ||
227 | return RESP_NO; | 229 | return RESP_NO; |
228 | } | 230 | } |
229 | 231 | ||
... | @@ -231,8 +233,8 @@ auth_gssapi (struct imap4d_command *command, | ... | @@ -231,8 +233,8 @@ auth_gssapi (struct imap4d_command *command, |
231 | util_send ("+ %*.*s\r\n", size, size, tmp); | 233 | util_send ("+ %*.*s\r\n", size, size, tmp); |
232 | free (tmp); | 234 | free (tmp); |
233 | 235 | ||
234 | token_str = imap4d_readline_ex (); | 236 | imap4d_getline (&token_str, &token_size, &token_len); |
235 | util_base64_decode (token_str, strlen (token_str), | 237 | util_base64_decode (token_str, token_len, |
236 | (unsigned char **) &tokbuf.value, &tokbuf.length); | 238 | (unsigned char **) &tokbuf.value, &tokbuf.length); |
237 | free (token_str); | 239 | free (token_str); |
238 | 240 | ... | ... |
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | 1 | /* GNU Mailutils -- a suite of utilities for electronic mail |
2 | Copyright (C) 1999, 2001, 2005, 2006, 2007 Free Software Foundation, Inc. | 2 | Copyright (C) 1999, 2001, 2005, 2006, 2007, |
3 | 2008 Free Software Foundation, Inc. | ||
3 | 4 | ||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | 5 | GNU Mailutils is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU General Public License as published by | 6 | it under the terms of the GNU General Public License as published by |
... | @@ -93,24 +94,30 @@ imap4d_auth_capability () | ... | @@ -93,24 +94,30 @@ imap4d_auth_capability () |
93 | mu_list_do (imap_auth_list, _auth_capa, NULL); | 94 | mu_list_do (imap_auth_list, _auth_capa, NULL); |
94 | } | 95 | } |
95 | 96 | ||
97 | /* | ||
98 | 6.2.1. AUTHENTICATE Command | ||
99 | |||
100 | Arguments: authentication mechanism name | ||
101 | */ | ||
102 | |||
96 | int | 103 | int |
97 | imap4d_authenticate (struct imap4d_command *command, char *arg) | 104 | imap4d_authenticate (struct imap4d_command *command, imap4d_tokbuf_t tok) |
98 | { | 105 | { |
99 | char *sp = NULL; | ||
100 | char *auth_type; | 106 | char *auth_type; |
101 | struct auth_data adata; | 107 | struct auth_data adata; |
102 | 108 | ||
103 | auth_type = util_getword (arg, &sp); | 109 | if (imap4d_tokbuf_argc (tok) != 3) |
104 | util_unquote (&auth_type); | 110 | return util_finish (command, RESP_BAD, "Invalid arguments"); |
105 | if (!auth_type) | 111 | |
106 | return util_finish (command, RESP_BAD, "Too few arguments"); | 112 | auth_type = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1); |
107 | 113 | ||
108 | if (tls_required) | 114 | if (tls_required) |
109 | return util_finish (command, RESP_NO, "Command disabled: Use STARTTLS first"); | 115 | return util_finish (command, RESP_NO, |
116 | "Command disabled: Use STARTTLS first"); | ||
110 | 117 | ||
111 | adata.command = command; | 118 | adata.command = command; |
112 | adata.auth_type = auth_type; | 119 | adata.auth_type = auth_type; |
113 | adata.arg = sp; | 120 | adata.arg = NULL; |
114 | adata.username = NULL; | 121 | adata.username = NULL; |
115 | 122 | ||
116 | if (mu_list_do (imap_auth_list, _auth_try, &adata) == 0) | 123 | if (mu_list_do (imap_auth_list, _auth_try, &adata) == 0) | ... | ... |
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | 1 | /* GNU Mailutils -- a suite of utilities for electronic mail |
2 | Copyright (C) 1999, 2001, 2003, 2005, 2007 Free Software Foundation, Inc. | 2 | Copyright (C) 1999, 2001, 2003, 2005, 2007, |
3 | 2008 Free Software Foundation, Inc. | ||
3 | 4 | ||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | 5 | GNU Mailutils is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU General Public License as published by | 6 | it under the terms of the GNU General Public License as published by |
... | @@ -50,6 +51,7 @@ imap4d_capability_init () | ... | @@ -50,6 +51,7 @@ imap4d_capability_init () |
50 | "IMAP4rev1", | 51 | "IMAP4rev1", |
51 | "NAMESPACE", | 52 | "NAMESPACE", |
52 | "IDLE", | 53 | "IDLE", |
54 | "LITERAL+", | ||
53 | "X-VERSION", | 55 | "X-VERSION", |
54 | NULL | 56 | NULL |
55 | }; | 57 | }; |
... | @@ -67,8 +69,11 @@ print_capa (void *item, void *data) | ... | @@ -67,8 +69,11 @@ print_capa (void *item, void *data) |
67 | } | 69 | } |
68 | 70 | ||
69 | int | 71 | int |
70 | imap4d_capability (struct imap4d_command *command, char *arg MU_ARG_UNUSED) | 72 | imap4d_capability (struct imap4d_command *command, imap4d_tokbuf_t tok) |
71 | { | 73 | { |
74 | if (imap4d_tokbuf_argc (tok) != 2) | ||
75 | return util_finish (command, RESP_BAD, "Invalid arguments"); | ||
76 | |||
72 | util_send ("* CAPABILITY"); | 77 | util_send ("* CAPABILITY"); |
73 | 78 | ||
74 | mu_list_do (capa_list, print_capa, NULL); | 79 | mu_list_do (capa_list, print_capa, NULL); | ... | ... |
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | 1 | /* GNU Mailutils -- a suite of utilities for electronic mail |
2 | Copyright (C) 1999, 2001, 2007 Free Software Foundation, Inc. | 2 | Copyright (C) 1999, 2001, 2007, 2008 Free Software Foundation, Inc. |
3 | 3 | ||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | 4 | GNU Mailutils is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU General Public License as published by | 5 | it under the terms of the GNU General Public License as published by |
... | @@ -19,13 +19,20 @@ | ... | @@ -19,13 +19,20 @@ |
19 | #include "imap4d.h" | 19 | #include "imap4d.h" |
20 | 20 | ||
21 | /* | 21 | /* |
22 | * Do we need to do anything here? | 22 | 6.4.1. CHECK Command |
23 | * FIXME: This is like noop we need to notify the client of | 23 | |
24 | * new mails etc ... and do housekeeping. | 24 | Arguments: none |
25 | */ | 25 | |
26 | Responses: no specific responses for this command | ||
27 | |||
28 | Result: OK - check completed | ||
29 | BAD - command unknown or arguments invalid | ||
30 | */ | ||
26 | 31 | ||
27 | int | 32 | int |
28 | imap4d_check (struct imap4d_command *command, char *arg MU_ARG_UNUSED) | 33 | imap4d_check (struct imap4d_command *command, imap4d_tokbuf_t tok) |
29 | { | 34 | { |
35 | if (imap4d_tokbuf_argc (tok) != 2) | ||
36 | return util_finish (command, RESP_BAD, "Invalid arguments"); | ||
30 | return util_finish (command, RESP_OK, "Completed"); | 37 | return util_finish (command, RESP_OK, "Completed"); |
31 | } | 38 | } | ... | ... |
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | 1 | /* GNU Mailutils -- a suite of utilities for electronic mail |
2 | Copyright (C) 1999, 2001, 2004, 2005, 2007 Free Software Foundation, Inc. | 2 | Copyright (C) 1999, 2001, 2004, 2005, 2007, |
3 | 2008 Free Software Foundation, Inc. | ||
3 | 4 | ||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | 5 | GNU Mailutils is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU General Public License as published by | 6 | it under the terms of the GNU General Public License as published by |
... | @@ -19,17 +20,28 @@ | ... | @@ -19,17 +20,28 @@ |
19 | #include "imap4d.h" | 20 | #include "imap4d.h" |
20 | 21 | ||
21 | /* | 22 | /* |
22 | */ | 23 | 6.4.2. CLOSE Command |
23 | 24 | ||
24 | /* The CLOSE command permanently removes from the currently selected | 25 | Arguments: none |
26 | |||
27 | Responses: no specific responses for this command | ||
28 | |||
29 | Result: OK - close completed, now in authenticated state | ||
30 | NO - close failure: no mailbox selected | ||
31 | BAD - command unknown or arguments invalid | ||
32 | |||
33 | The CLOSE command permanently removes from the currently selected | ||
25 | mailbox all messages that have the \\Deleted flag set, and returns | 34 | mailbox all messages that have the \\Deleted flag set, and returns |
26 | to authenticated state from selected state. */ | 35 | to authenticated state from selected state. */ |
27 | int | 36 | int |
28 | imap4d_close (struct imap4d_command *command, char *arg MU_ARG_UNUSED) | 37 | imap4d_close (struct imap4d_command *command, imap4d_tokbuf_t tok) |
29 | { | 38 | { |
30 | const char *msg = NULL; | 39 | const char *msg = NULL; |
31 | int status, flags; | 40 | int status, flags; |
32 | 41 | ||
42 | if (imap4d_tokbuf_argc (tok) != 2) | ||
43 | return util_finish (command, RESP_BAD, "Invalid arguments"); | ||
44 | |||
33 | mu_mailbox_get_flags (mbox, &flags); | 45 | mu_mailbox_get_flags (mbox, &flags); |
34 | if ((flags & MU_STREAM_READ) == 0) | 46 | if ((flags & MU_STREAM_READ) == 0) |
35 | { | 47 | { | ... | ... |
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | 1 | /* GNU Mailutils -- a suite of utilities for electronic mail |
2 | Copyright (C) 1999, 2001, 2003, 2007 Free Software Foundation, Inc. | 2 | Copyright (C) 1999, 2001, 2003, 2007, 2008 Free Software Foundation, Inc. |
3 | 3 | ||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | 4 | GNU Mailutils is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU General Public License as published by | 5 | it under the terms of the GNU General Public License as published by | ... | ... |
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | 1 | /* GNU Mailutils -- a suite of utilities for electronic mail |
2 | Copyright (C) 1999, 2001, 2005, 2007 Free Software Foundation, Inc. | 2 | Copyright (C) 1999, 2001, 2005, 2007, 2008 Free Software Foundation, Inc. |
3 | 3 | ||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | 4 | GNU Mailutils is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU General Public License as published by | 5 | it under the terms of the GNU General Public License as published by |
... | @@ -19,55 +19,69 @@ | ... | @@ -19,55 +19,69 @@ |
19 | #include "imap4d.h" | 19 | #include "imap4d.h" |
20 | 20 | ||
21 | /* | 21 | /* |
22 | * copy messages in argv[2] to mailbox in argv[3] | 22 | 6.4.7. COPY Command |
23 | |||
24 | Arguments: message set | ||
25 | mailbox name | ||
26 | |||
27 | Responses: no specific responses for this command | ||
28 | |||
29 | Result: OK - copy completed | ||
30 | NO - copy error: can't copy those messages or to that | ||
31 | name | ||
32 | BAD - command unknown or arguments invalid | ||
33 | |||
34 | copy messages in argv[2] to mailbox in argv[3] | ||
23 | */ | 35 | */ |
24 | 36 | ||
25 | int | 37 | int |
26 | imap4d_copy (struct imap4d_command *command, char *arg) | 38 | imap4d_copy (struct imap4d_command *command, imap4d_tokbuf_t tok) |
27 | { | 39 | { |
28 | int rc; | 40 | int rc; |
29 | char buffer[64]; | 41 | char *text; |
42 | |||
43 | if (imap4d_tokbuf_argc (tok) != 4) | ||
44 | return util_finish (command, RESP_BAD, "Invalid arguments"); | ||
45 | |||
46 | rc = imap4d_copy0 (tok, 0, &text); | ||
30 | 47 | ||
31 | rc = imap4d_copy0 (arg, 0, buffer, sizeof buffer); | ||
32 | if (rc == RESP_NONE) | 48 | if (rc == RESP_NONE) |
33 | { | 49 | { |
34 | /* Reset the state ourself. */ | 50 | /* Reset the state ourself. */ |
35 | int new_state = (rc == RESP_OK) ? command->success : command->failure; | 51 | int new_state = (rc == RESP_OK) ? command->success : command->failure; |
36 | if (new_state != STATE_NONE) | 52 | if (new_state != STATE_NONE) |
37 | state = new_state; | 53 | state = new_state; |
38 | return util_send ("%s %s\r\n", command->tag, buffer); | 54 | return util_send ("%s %s\r\n", command->tag, text); |
39 | } | 55 | } |
40 | return util_finish (command, rc, "%s", buffer); | 56 | return util_finish (command, rc, "%s", text); |
41 | } | 57 | } |
42 | 58 | ||
43 | int | 59 | int |
44 | imap4d_copy0 (char *arg, int isuid, char *resp, size_t resplen) | 60 | imap4d_copy0 (imap4d_tokbuf_t tok, int isuid, char **err_text) |
45 | { | 61 | { |
46 | int status; | 62 | int status; |
47 | char *msgset; | 63 | char *msgset; |
48 | char *name; | 64 | char *name; |
49 | char *mailbox_name; | 65 | char *mailbox_name; |
50 | const char *delim = "/"; | 66 | const char *delim = "/"; |
51 | char *sp = NULL; | ||
52 | size_t *set = NULL; | 67 | size_t *set = NULL; |
53 | int n = 0; | 68 | int n = 0; |
54 | mu_mailbox_t cmbox = NULL; | 69 | mu_mailbox_t cmbox = NULL; |
70 | int arg = IMAP4_ARG_1 + !!isuid; | ||
55 | 71 | ||
56 | msgset = util_getword (arg, &sp); | 72 | if (imap4d_tokbuf_argc (tok) != arg + 2) |
57 | name = util_getword (NULL, &sp); | ||
58 | |||
59 | util_unquote (&name); | ||
60 | if (!msgset || !name || *name == '\0') | ||
61 | { | 73 | { |
62 | snprintf (resp, resplen, "Too few args"); | 74 | *err_text = "Invalid arguments"; |
63 | return RESP_BAD; | 75 | return 1; |
64 | } | 76 | } |
65 | 77 | ||
78 | msgset = imap4d_tokbuf_getarg (tok, arg); | ||
79 | name = imap4d_tokbuf_getarg (tok, arg + 1); | ||
66 | /* Get the message numbers in set[]. */ | 80 | /* Get the message numbers in set[]. */ |
67 | status = util_msgset (msgset, &set, &n, isuid); | 81 | status = util_msgset (msgset, &set, &n, isuid); |
68 | if (status != 0) | 82 | if (status != 0) |
69 | { | 83 | { |
70 | snprintf (resp, resplen, "Bogus number set"); | 84 | *err_text = "Bogus number set"; |
71 | return RESP_BAD; | 85 | return RESP_BAD; |
72 | } | 86 | } |
73 | 87 | ||
... | @@ -75,7 +89,7 @@ imap4d_copy0 (char *arg, int isuid, char *resp, size_t resplen) | ... | @@ -75,7 +89,7 @@ imap4d_copy0 (char *arg, int isuid, char *resp, size_t resplen) |
75 | 89 | ||
76 | if (!mailbox_name) | 90 | if (!mailbox_name) |
77 | { | 91 | { |
78 | snprintf (resp, resplen, "NO Create failed."); | 92 | *err_text = "NO Create failed."; |
79 | return RESP_NO; | 93 | return RESP_NO; |
80 | } | 94 | } |
81 | 95 | ||
... | @@ -105,7 +119,7 @@ imap4d_copy0 (char *arg, int isuid, char *resp, size_t resplen) | ... | @@ -105,7 +119,7 @@ imap4d_copy0 (char *arg, int isuid, char *resp, size_t resplen) |
105 | 119 | ||
106 | if (status == 0) | 120 | if (status == 0) |
107 | { | 121 | { |
108 | snprintf (resp, resplen, "Completed"); | 122 | *err_text = "Completed"; |
109 | return RESP_OK; | 123 | return RESP_OK; |
110 | } | 124 | } |
111 | 125 | ||
... | @@ -114,6 +128,6 @@ imap4d_copy0 (char *arg, int isuid, char *resp, size_t resplen) | ... | @@ -114,6 +128,6 @@ imap4d_copy0 (char *arg, int isuid, char *resp, size_t resplen) |
114 | of the text of the tagged NO response. This gives a hint to the | 128 | of the text of the tagged NO response. This gives a hint to the |
115 | client that it can attempt a CREATE command and retry the copy if | 129 | client that it can attempt a CREATE command and retry the copy if |
116 | the CREATE is successful. */ | 130 | the CREATE is successful. */ |
117 | snprintf (resp, resplen, "NO [TRYCREATE] failed"); | 131 | *err_text = "NO [TRYCREATE] failed"; |
118 | return RESP_NONE; | 132 | return RESP_NONE; |
119 | } | 133 | } | ... | ... |
... | @@ -63,25 +63,34 @@ mkdir_p (char *name, int delim) | ... | @@ -63,25 +63,34 @@ mkdir_p (char *name, int delim) |
63 | return 0; | 63 | return 0; |
64 | } | 64 | } |
65 | 65 | ||
66 | /* | ||
67 | 6.3.3. CREATE Command | ||
68 | |||
69 | Arguments: mailbox name | ||
70 | |||
71 | Responses: no specific responses for this command | ||
72 | |||
73 | Result: OK - create completed | ||
74 | NO - create failure: can't create mailbox with that name | ||
75 | BAD - command unknown or arguments invalid | ||
76 | */ | ||
66 | /* FIXME: How do we do this ??????: | 77 | /* FIXME: How do we do this ??????: |
67 | IF a new mailbox is created with the same name as a mailbox which was | 78 | IF a new mailbox is created with the same name as a mailbox which was |
68 | deleted, its unique identifiers MUST be greater than any unique identifiers | 79 | deleted, its unique identifiers MUST be greater than any unique identifiers |
69 | used in the previous incarnation of the mailbox. */ | 80 | used in the previous incarnation of the mailbox. */ |
70 | int | 81 | int |
71 | imap4d_create (struct imap4d_command *command, char *arg) | 82 | imap4d_create (struct imap4d_command *command, imap4d_tokbuf_t tok) |
72 | { | 83 | { |
73 | char *name; | 84 | char *name; |
74 | char *sp = NULL; | ||
75 | const char *delim = "/"; | 85 | const char *delim = "/"; |
76 | int isdir = 0; | 86 | int isdir = 0; |
77 | int rc = RESP_OK; | 87 | int rc = RESP_OK; |
78 | const char *msg = "Completed"; | 88 | const char *msg = "Completed"; |
79 | 89 | ||
80 | name = util_getword (arg, &sp); | 90 | if (imap4d_tokbuf_argc (tok) != 3) |
81 | if (!name) | 91 | return util_finish (command, RESP_BAD, "Invalid arguments"); |
82 | return util_finish (command, RESP_BAD, "Too few arguments"); | ||
83 | 92 | ||
84 | util_unquote (&name); | 93 | name = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1); |
85 | 94 | ||
86 | if (*name == '\0') | 95 | if (*name == '\0') |
87 | return util_finish (command, RESP_BAD, "Too few arguments"); | 96 | return util_finish (command, RESP_BAD, "Too few arguments"); |
... | @@ -152,6 +161,5 @@ imap4d_create (struct imap4d_command *command, char *arg) | ... | @@ -152,6 +161,5 @@ imap4d_create (struct imap4d_command *command, char *arg) |
152 | msg = "already exists"; | 161 | msg = "already exists"; |
153 | } | 162 | } |
154 | 163 | ||
155 | free (name); | ||
156 | return util_finish (command, rc, msg); | 164 | return util_finish (command, rc, msg); |
157 | } | 165 | } | ... | ... |
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | 1 | /* GNU Mailutils -- a suite of utilities for electronic mail |
2 | Copyright (C) 1999, 2001, 2007 Free Software Foundation, Inc. | 2 | Copyright (C) 1999, 2001, 2007, 2008 Free Software Foundation, Inc. |
3 | 3 | ||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | 4 | GNU Mailutils is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU General Public License as published by | 5 | it under the terms of the GNU General Public License as published by |
... | @@ -19,20 +19,27 @@ | ... | @@ -19,20 +19,27 @@ |
19 | #include "imap4d.h" | 19 | #include "imap4d.h" |
20 | 20 | ||
21 | /* | 21 | /* |
22 | * | 22 | 6.3.4. DELETE Command |
23 | */ | ||
24 | 23 | ||
24 | Arguments: mailbox name | ||
25 | |||
26 | Responses: no specific responses for this command | ||
27 | |||
28 | Result: OK - delete completed | ||
29 | NO - delete failure: can't delete mailbox with that name | ||
30 | BAD - command unknown or arguments invalid | ||
31 | */ | ||
25 | int | 32 | int |
26 | imap4d_delete (struct imap4d_command *command, char *arg) | 33 | imap4d_delete (struct imap4d_command *command, imap4d_tokbuf_t tok) |
27 | { | 34 | { |
28 | char *sp = NULL; | ||
29 | int rc = RESP_OK; | 35 | int rc = RESP_OK; |
30 | const char *msg = "Completed"; | 36 | const char *msg = "Completed"; |
31 | const char *delim = "/"; | 37 | const char *delim = "/"; |
32 | char *name; | 38 | char *name; |
33 | 39 | ||
34 | name = util_getword (arg, &sp); | 40 | if (imap4d_tokbuf_argc (tok) != 3) |
35 | util_unquote (&name); | 41 | return util_finish (command, RESP_BAD, "Invalid arguments"); |
42 | name = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1); | ||
36 | if (!name || *name == '\0') | 43 | if (!name || *name == '\0') |
37 | return util_finish (command, RESP_BAD, "Too few arguments"); | 44 | return util_finish (command, RESP_BAD, "Too few arguments"); |
38 | 45 | ||
... | @@ -51,6 +58,5 @@ imap4d_delete (struct imap4d_command *command, char *arg) | ... | @@ -51,6 +58,5 @@ imap4d_delete (struct imap4d_command *command, char *arg) |
51 | rc = RESP_NO; | 58 | rc = RESP_NO; |
52 | msg = "Cannot remove"; | 59 | msg = "Cannot remove"; |
53 | } | 60 | } |
54 | free (name); | ||
55 | return util_finish (command, rc, msg); | 61 | return util_finish (command, rc, msg); |
56 | } | 62 | } | ... | ... |
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | 1 | /* GNU Mailutils -- a suite of utilities for electronic mail |
2 | Copyright (C) 1999, 2001, 2007 Free Software Foundation, Inc. | 2 | Copyright (C) 1999, 2001, 2007, 2008 Free Software Foundation, Inc. |
3 | 3 | ||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | 4 | GNU Mailutils is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU General Public License as published by | 5 | it under the terms of the GNU General Public License as published by |
... | @@ -19,11 +19,23 @@ | ... | @@ -19,11 +19,23 @@ |
19 | #include "imap4d.h" | 19 | #include "imap4d.h" |
20 | 20 | ||
21 | /* | 21 | /* |
22 | * copy things from select.c | 22 | 6.3.2. EXAMINE Command |
23 | */ | ||
24 | 23 | ||
24 | Arguments: mailbox name | ||
25 | |||
26 | Responses: REQUIRED untagged responses: FLAGS, EXISTS, RECENT | ||
27 | OPTIONAL OK untagged responses: UNSEEN, PERMANENTFLAGS | ||
28 | |||
29 | Result: OK - examine completed, now in selected state | ||
30 | NO - examine failure, now in authenticated state: no | ||
31 | such mailbox, can't access mailbox | ||
32 | BAD - command unknown or arguments invalid | ||
33 | */ | ||
25 | int | 34 | int |
26 | imap4d_examine (struct imap4d_command *command, char *arg) | 35 | imap4d_examine (struct imap4d_command *command, imap4d_tokbuf_t tok) |
27 | { | 36 | { |
28 | return imap4d_select0 (command, arg, MU_STREAM_READ); | 37 | if (imap4d_tokbuf_argc (tok) != 3) |
38 | return util_finish (command, RESP_BAD, "Invalid arguments"); | ||
39 | return imap4d_select0 (command, imap4d_tokbuf_getarg (tok, IMAP4_ARG_1), | ||
40 | MU_STREAM_READ); | ||
29 | } | 41 | } | ... | ... |
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | 1 | /* GNU Mailutils -- a suite of utilities for electronic mail |
2 | Copyright (C) 1999, 2001, 2005, 2007 Free Software Foundation, Inc. | 2 | Copyright (C) 1999, 2001, 2005, 2007, 2008 Free Software Foundation, Inc. |
3 | 3 | ||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | 4 | GNU Mailutils is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU General Public License as published by | 5 | it under the terms of the GNU General Public License as published by |
... | @@ -19,16 +19,23 @@ | ... | @@ -19,16 +19,23 @@ |
19 | #include "imap4d.h" | 19 | #include "imap4d.h" |
20 | 20 | ||
21 | /* | 21 | /* |
22 | * | 22 | 6.4.3. EXPUNGE Command |
23 | */ | 23 | |
24 | Arguments: none | ||
25 | |||
26 | Responses: untagged responses: EXPUNGE | ||
27 | |||
28 | Result: OK - expunge completed | ||
29 | NO - expunge failure: can't expunge (e.g. permission | ||
30 | denied) | ||
31 | BAD - command unknown or arguments invalid | ||
32 | */ | ||
24 | 33 | ||
25 | int | 34 | int |
26 | imap4d_expunge (struct imap4d_command *command, char *arg) | 35 | imap4d_expunge (struct imap4d_command *command, imap4d_tokbuf_t tok) |
27 | { | 36 | { |
28 | char *sp = NULL; | 37 | if (imap4d_tokbuf_argc (tok) != 2) |
29 | 38 | return util_finish (command, RESP_BAD, "Invalid arguments"); | |
30 | if (util_getword (arg, &sp)) | ||
31 | return util_finish (command, RESP_NO, "Too many args"); | ||
32 | 39 | ||
33 | /* FIXME: check for errors. */ | 40 | /* FIXME: check for errors. */ |
34 | mu_mailbox_expunge (mbox); | 41 | mu_mailbox_expunge (mbox); | ... | ... |
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | 1 | /* GNU Mailutils -- a suite of utilities for electronic mail |
2 | Copyright (C) 1999, 2001, 2005, 2006, 2007 Free Software Foundation, Inc. | 2 | Copyright (C) 1999, 2001, 2005, 2006, 2007, |
3 | 2008 Free Software Foundation, Inc. | ||
3 | 4 | ||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | 5 | GNU Mailutils is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU General Public License as published by | 6 | it under the terms of the GNU General Public License as published by |
... | @@ -20,9 +21,6 @@ | ... | @@ -20,9 +21,6 @@ |
20 | #include <ctype.h> | 21 | #include <ctype.h> |
21 | #include <mailutils/argcv.h> | 22 | #include <mailutils/argcv.h> |
22 | 23 | ||
23 | /* This will suck, too. | ||
24 | Alain: Yes it does. */ | ||
25 | |||
26 | /* Taken from RFC2060 | 24 | /* Taken from RFC2060 |
27 | fetch ::= "FETCH" SPACE set SPACE ("ALL" / "FULL" / | 25 | fetch ::= "FETCH" SPACE set SPACE ("ALL" / "FULL" / |
28 | "FAST" / fetch_att / "(" 1#fetch_att ")") | 26 | "FAST" / fetch_att / "(" 1#fetch_att ")") |
... | @@ -34,495 +32,93 @@ | ... | @@ -34,495 +32,93 @@ |
34 | ["<" number "." nz_number ">"] | 32 | ["<" number "." nz_number ">"] |
35 | */ | 33 | */ |
36 | 34 | ||
37 | struct fetch_command; | 35 | struct fetch_runtime_closure |
38 | |||
39 | static int fetch_all (struct fetch_command *, char**); | ||
40 | static int fetch_full (struct fetch_command *, char**); | ||
41 | static int fetch_fast (struct fetch_command *, char**); | ||
42 | static int fetch_envelope (struct fetch_command *, char**); | ||
43 | static int fetch_flags (struct fetch_command *, char**); | ||
44 | static int fetch_internaldate (struct fetch_command *, char**); | ||
45 | static int fetch_rfc822_header (struct fetch_command *, char**); | ||
46 | static int fetch_rfc822_size (struct fetch_command *, char**); | ||
47 | static int fetch_rfc822_text (struct fetch_command *, char**); | ||
48 | static int fetch_rfc822 (struct fetch_command *, char**); | ||
49 | static int fetch_bodystructure (struct fetch_command *, char**); | ||
50 | static int fetch_body (struct fetch_command *, char**); | ||
51 | static int fetch_uid (struct fetch_command *, char**); | ||
52 | |||
53 | /* Helper functions. */ | ||
54 | static int fetch_envelope0 (mu_message_t); | ||
55 | static int fetch_bodystructure0 (mu_message_t, int); | ||
56 | static int bodystructure (mu_message_t, int); | ||
57 | static void send_parameter_list (const char *); | ||
58 | static int fetch_operation (mu_message_t, char **, int); | ||
59 | static int fetch_message (mu_message_t, unsigned long, unsigned long); | ||
60 | static int fetch_header (mu_message_t, unsigned long, unsigned long); | ||
61 | static int fetch_body_content (mu_message_t, unsigned long, unsigned long); | ||
62 | static int fetch_io (mu_stream_t, unsigned long, unsigned long, unsigned long); | ||
63 | static int fetch_header_fields (mu_message_t, char **, unsigned long, unsigned long); | ||
64 | static int fetch_header_fields_not (mu_message_t, char **, unsigned long, unsigned long); | ||
65 | static int fetch_send_address (const char *); | ||
66 | |||
67 | static struct fetch_command* fetch_getcommand (char *, struct fetch_command*); | ||
68 | |||
69 | struct fetch_command | ||
70 | { | 36 | { |
71 | const char *name; | 37 | int eltno; |
72 | int (*func) (struct fetch_command *, char **); | 38 | size_t msgno; |
73 | mu_message_t msg; | 39 | mu_message_t msg; |
74 | } fetch_command_table [] = | 40 | char *err_text; |
75 | { | ||
76 | #define F_ALL 0 | ||
77 | {"ALL", fetch_all, 0}, | ||
78 | #define F_FULL 1 | ||
79 | {"FULL", fetch_full, 0}, | ||
80 | #define F_FAST 2 | ||
81 | {"FAST", fetch_fast, 0}, | ||
82 | #define F_ENVELOPE 3 | ||
83 | {"ENVELOPE", fetch_envelope, 0}, | ||
84 | #define F_FLAGS 4 | ||
85 | {"FLAGS", fetch_flags, 0}, | ||
86 | #define F_INTERNALDATE 5 | ||
87 | {"INTERNALDATE", fetch_internaldate, 0}, | ||
88 | #define F_RFC822_HEADER 6 | ||
89 | {"RFC822.HEADER", fetch_rfc822_header, 0}, | ||
90 | #define F_RFC822_SIZE 7 | ||
91 | {"RFC822.SIZE", fetch_rfc822_size, 0}, | ||
92 | #define F_RFC822_TEXT 8 | ||
93 | {"RFC822.TEXT", fetch_rfc822_text, 0}, | ||
94 | #define F_RFC822 9 | ||
95 | {"RFC822", fetch_rfc822, 0}, | ||
96 | #define F_BODYSTRUCTURE 10 | ||
97 | {"BODYSTRUCTURE", fetch_bodystructure, 0}, | ||
98 | #define F_BODY 11 | ||
99 | {"BODY", fetch_body, 0}, | ||
100 | #define F_UID 12 | ||
101 | {"UID", fetch_uid, 0}, | ||
102 | { NULL, 0, 0} | ||
103 | }; | 41 | }; |
104 | 42 | ||
105 | /* Go through the fetch array sub command and returns the the structure. */ | 43 | struct fetch_function_closure; |
106 | |||
107 | static struct fetch_command * | ||
108 | fetch_getcommand (char *cmd, struct fetch_command *command_table) | ||
109 | { | ||
110 | size_t i, len = strlen (cmd); | ||
111 | 44 | ||
112 | for (i = 0; command_table[i].name != 0; i++) | 45 | typedef int (*fetch_function_t) (struct fetch_function_closure *, |
113 | { | 46 | struct fetch_runtime_closure *); |
114 | if (strlen (command_table[i].name) == len && | ||
115 | !strcasecmp (command_table[i].name, cmd)) | ||
116 | return &command_table[i]; | ||
117 | } | ||
118 | return NULL; | ||
119 | } | ||
120 | 47 | ||
121 | /* The FETCH command retrieves data associated with a message in the | 48 | struct fetch_function_closure |
122 | mailbox. The data items to be fetched can be either a single atom | ||
123 | or a parenthesized list. */ | ||
124 | int | ||
125 | imap4d_fetch (struct imap4d_command *command, char *arg) | ||
126 | { | 49 | { |
127 | int rc; | 50 | fetch_function_t fun; /* Handler function */ |
128 | char buffer[64]; | 51 | const char *name; /* Response tag */ |
52 | size_t *section_part; /* Section-part */ | ||
53 | size_t nset; /* Number of elements in section_part */ | ||
54 | int peek; | ||
55 | int not; /* Negate header set */ | ||
56 | mu_list_t headers; /* Headers */ | ||
57 | size_t start; /* Substring start */ | ||
58 | size_t size; /* Substring length */ | ||
59 | }; | ||
129 | 60 | ||
130 | rc = imap4d_fetch0 (arg, 0, buffer, sizeof buffer); | ||
131 | return util_finish (command, rc, "%s", buffer); | ||
132 | } | ||
133 | 61 | ||
134 | /* Where the real implementation is. It is here since UID command also | 62 | static int |
135 | calls FETCH. */ | 63 | fetch_send_address (const char *addr) |
136 | int | ||
137 | imap4d_fetch0 (char *arg, int isuid, char *resp, size_t resplen) | ||
138 | { | 64 | { |
139 | struct fetch_command *fcmd = NULL; | 65 | mu_address_t address; |
140 | int rc = RESP_OK; | 66 | size_t i, count = 0; |
141 | char *sp = NULL; | ||
142 | char *msgset; | ||
143 | size_t *set = NULL; | ||
144 | int n = 0; | ||
145 | int i; | ||
146 | int status; | ||
147 | |||
148 | msgset = util_getword (arg, &sp); | ||
149 | if (!msgset || !sp || *sp == '\0') | ||
150 | { | ||
151 | snprintf (resp, resplen, "Too few args"); | ||
152 | return RESP_BAD; | ||
153 | } | ||
154 | 67 | ||
155 | /* Get the message numbers in set[]. */ | 68 | /* Short circuit. */ |
156 | status = util_msgset (msgset, &set, &n, isuid); | 69 | if (addr == NULL || *addr == '\0') |
157 | if (status != 0) | ||
158 | { | 70 | { |
159 | snprintf (resp, resplen, "Bogus number set"); | 71 | util_send ("NIL"); |
160 | return RESP_BAD; | 72 | return RESP_OK; |
161 | } | 73 | } |
162 | 74 | ||
163 | /* Prepare status code. It will be replaced if an error occurs in the | 75 | mu_address_create (&address, addr); |
164 | loop below */ | 76 | mu_address_get_count (address, &count); |
165 | snprintf (resp, resplen, "Completed"); | ||
166 | |||
167 | for (i = 0; i < n && rc == RESP_OK; i++) | ||
168 | { | ||
169 | size_t msgno = (isuid) ? uid_to_msgno (set[i]) : set[i]; | ||
170 | mu_message_t msg = NULL; | ||
171 | |||
172 | if (msgno && mu_mailbox_get_message (mbox, msgno, &msg) == 0) | ||
173 | { | ||
174 | char item[32]; | ||
175 | char *items = strdup (sp); | ||
176 | char *p = items; | ||
177 | int space = 0; | ||
178 | 77 | ||
179 | fcmd = NULL; | 78 | /* We failed: can't parse. */ |
180 | util_send ("* %s FETCH (", mu_umaxtostr (0, msgno)); | 79 | if (count == 0) |
181 | item[0] = '\0'; | ||
182 | /* Server implementations MUST implicitly | ||
183 | include the UID message data item as part of any FETCH | ||
184 | response caused by a UID command, regardless of whether | ||
185 | a UID was specified as a message data item to the FETCH. */ | ||
186 | if (isuid) | ||
187 | { | ||
188 | fcmd = &fetch_command_table[F_UID]; | ||
189 | fcmd->msg = msg; | ||
190 | rc = fetch_uid (fcmd, &items); | ||
191 | } | ||
192 | /* Get the fetch command names. */ | ||
193 | while (*items && *items != ')') | ||
194 | { | ||
195 | util_token (item, sizeof (item), &items); | ||
196 | /* Do not send the UID again. */ | ||
197 | if (isuid && strcasecmp (item, "UID") == 0) | ||
198 | continue; | ||
199 | if (fcmd) | ||
200 | space = 1; | ||
201 | /* Search in the table. */ | ||
202 | fcmd = fetch_getcommand (item, fetch_command_table); | ||
203 | if (fcmd) | ||
204 | { | ||
205 | if (space) | ||
206 | { | ||
207 | util_send (" "); | ||
208 | space = 0; | ||
209 | } | ||
210 | fcmd->msg = msg; | ||
211 | rc = fcmd->func (fcmd, &items); | ||
212 | } | ||
213 | } | ||
214 | util_send (")\r\n"); | ||
215 | free (p); | ||
216 | } | ||
217 | else if (!isuid) | ||
218 | /* According to RFC 3501, "A non-existent unique identifier is | ||
219 | ignored without any error message generated." */ | ||
220 | { | 80 | { |
221 | snprintf (resp, resplen, | 81 | util_send ("NIL"); |
222 | "Bogus message set: message number out of range"); | 82 | return RESP_OK; |
223 | rc = RESP_BAD; | ||
224 | break; | ||
225 | } | ||
226 | } | 83 | } |
227 | free (set); | ||
228 | return rc; | ||
229 | } | ||
230 | 84 | ||
231 | /* ALL: | 85 | util_send ("("); |
232 | Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE) | 86 | for (i = 1; i <= count; i++) |
233 | Combination of FAST and ENVELOPE. */ | 87 | { |
234 | static int | 88 | const char *str; |
235 | fetch_all (struct fetch_command *command, char **arg) | 89 | int is_group = 0; |
236 | { | ||
237 | struct fetch_command c_env = fetch_command_table[F_ENVELOPE]; | ||
238 | fetch_fast (command, arg); | ||
239 | util_send (" "); | ||
240 | c_env.msg = command->msg; | ||
241 | fetch_envelope (&c_env, arg); | ||
242 | return RESP_OK; | ||
243 | } | ||
244 | 90 | ||
245 | /* FULL: | 91 | util_send ("("); |
246 | Macro equivalent to: (FLAGS INTERNALDATE | ||
247 | RFC822.SIZE ENVELOPE BODY). | ||
248 | Combination of (ALL BODY). */ | ||
249 | static int | ||
250 | fetch_full (struct fetch_command *command, char **arg) | ||
251 | { | ||
252 | struct fetch_command c_body = fetch_command_table[F_BODY]; | ||
253 | fetch_all (command, arg); | ||
254 | util_send (" "); | ||
255 | c_body.msg = command->msg; | ||
256 | return fetch_body (&c_body, arg); | ||
257 | } | ||
258 | 92 | ||
259 | /* FAST: | 93 | mu_address_sget_personal (address, i, &str); |
260 | Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE) | 94 | util_send_qstring (str); |
261 | Combination of (FLAGS INTERNALDATE RFC822.SIZE). */ | ||
262 | static int | ||
263 | fetch_fast (struct fetch_command *command, char **arg) | ||
264 | { | ||
265 | struct fetch_command c_idate = fetch_command_table[F_INTERNALDATE]; | ||
266 | struct fetch_command c_rfc = fetch_command_table[F_RFC822_SIZE]; | ||
267 | struct fetch_command c_flags = fetch_command_table[F_FLAGS]; | ||
268 | c_flags.msg = command->msg; | ||
269 | fetch_flags (&c_flags, arg); | ||
270 | util_send (" "); | ||
271 | c_idate.msg = command->msg; | ||
272 | fetch_internaldate (&c_idate, arg); | ||
273 | util_send (" "); | 95 | util_send (" "); |
274 | c_rfc.msg = command->msg; | ||
275 | fetch_rfc822_size (&c_rfc, arg); | ||
276 | return RESP_OK; | ||
277 | } | ||
278 | |||
279 | /* ENVELOPE: | ||
280 | Header: Date, Subject, From, Sender, Reply-To, To, Cc, Bcc, In-Reply-To, | ||
281 | and Message-Id. */ | ||
282 | static int | ||
283 | fetch_envelope (struct fetch_command *command, char **arg MU_ARG_UNUSED) | ||
284 | { | ||
285 | int status; | ||
286 | util_send ("%s (", command->name); | ||
287 | status = fetch_envelope0 (command->msg); | ||
288 | util_send (")"); | ||
289 | return status; | ||
290 | } | ||
291 | 96 | ||
292 | /* FLAGS: The flags that are set for this message. */ | 97 | mu_address_sget_route (address, i, &str); |
293 | /* FIXME: User flags not done. If enable change the PERMANENTFLAGS in SELECT */ | 98 | util_send_qstring (str); |
294 | void | ||
295 | fetch_flags0 (const char *prefix, mu_message_t msg, int isuid) | ||
296 | { | ||
297 | mu_attribute_t attr = NULL; | ||
298 | 99 | ||
299 | mu_message_get_attribute (msg, &attr); | ||
300 | if (isuid) | ||
301 | { | ||
302 | struct fetch_command *fcmd = &fetch_command_table[F_UID]; | ||
303 | fcmd->msg = msg; | ||
304 | fetch_uid (fcmd, NULL); | ||
305 | util_send (" "); | 100 | util_send (" "); |
306 | } | ||
307 | util_send ("%s (", prefix); | ||
308 | util_print_flags(attr); | ||
309 | util_send (")"); | ||
310 | } | ||
311 | |||
312 | static int | ||
313 | fetch_flags (struct fetch_command *command, char **arg) | ||
314 | { | ||
315 | fetch_flags0 (command->name, command->msg, 0); | ||
316 | return RESP_OK; | ||
317 | } | ||
318 | |||
319 | |||
320 | /* INTERNALDATE The internal date of the message. | ||
321 | Format: | ||
322 | |||
323 | date_time ::= <"> date_day_fixed "-" date_month "-" date_year | ||
324 | SPACE time SPACE zone <"> | ||
325 | |||
326 | date_day ::= 1*2digit | ||
327 | ;; Day of month | ||
328 | |||
329 | date_day_fixed ::= (SPACE digit) / 2digit | ||
330 | ;; Fixed-format version of date_day | ||
331 | |||
332 | date_month ::= "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" / | ||
333 | "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec" | ||
334 | |||
335 | date_text ::= date_day "-" date_month "-" date_year | ||
336 | |||
337 | date_year ::= 4digit | ||
338 | |||
339 | time ::= 2digit ":" 2digit ":" 2digit | ||
340 | ;; Hours minutes seconds | ||
341 | |||
342 | zone ::= ("+" / "-") 4digit | ||
343 | ;; Signed four-digit value of hhmm representing | ||
344 | ;; hours and minutes west of Greenwich (that is, | ||
345 | ;; (the amount that the given time differs from | ||
346 | ;; Universal Time). Subtracting the timezone | ||
347 | ;; from the given time will give the UT form. | ||
348 | ;; The Universal Time zone is "+0000". */ | ||
349 | static int | ||
350 | fetch_internaldate (struct fetch_command *command, char **arg MU_ARG_UNUSED) | ||
351 | { | ||
352 | const char *date; | ||
353 | mu_envelope_t env = NULL; | ||
354 | struct tm tm, *tmp = NULL; | ||
355 | mu_timezone tz; | ||
356 | char datebuf[sizeof ("13-Jul-2002 00:00:00")]; | ||
357 | 101 | ||
358 | mu_message_get_envelope (command->msg, &env); | 102 | mu_address_is_group (address, i, &is_group); |
359 | if (mu_envelope_sget_date (env, &date) == 0 | 103 | str = NULL; |
360 | && mu_parse_ctime_date_time (&date, &tm, &tz) == 0) | 104 | if (is_group) |
361 | tmp = &tm; | 105 | mu_address_sget_personal (address, i, &str); |
362 | else | 106 | else |
363 | { | 107 | mu_address_sget_local_part (address, i, &str); |
364 | time_t t = time (NULL); | ||
365 | tmp = localtime (&t); | ||
366 | } | ||
367 | mu_strftime (datebuf, sizeof (datebuf), "%d-%b-%Y %H:%M:%S", tmp); | ||
368 | util_send ("%s", command->name); | ||
369 | util_send (" \"%s +0000\"", datebuf); | ||
370 | return RESP_OK; | ||
371 | } | ||
372 | |||
373 | /* | ||
374 | RFC822.HEADER: | ||
375 | Functionally equivalent to BODY.PEEK[HEADER], differing in the syntax of | ||
376 | the resulting untagged FETCH data (RFC822.HEADER is returned). */ | ||
377 | static int | ||
378 | fetch_rfc822_header (struct fetch_command *command, char **arg MU_ARG_UNUSED) | ||
379 | { | ||
380 | char buffer[32]; | ||
381 | char *p = buffer; | ||
382 | |||
383 | strcpy (buffer, ".PEEK[HEADER]"); | ||
384 | return fetch_body (command, &p); | ||
385 | } | ||
386 | |||
387 | /* RFC822.TEXT: | ||
388 | Functionally equivalent to BODY[TEXT], differing in the syntax of the | ||
389 | resulting untagged FETCH data (RFC822.TEXT is returned). */ | ||
390 | static int | ||
391 | fetch_rfc822_text (struct fetch_command *command, char **arg MU_ARG_UNUSED) | ||
392 | { | ||
393 | char buffer[16]; | ||
394 | char *p = buffer; | ||
395 | |||
396 | strcpy (buffer, "[TEXT]"); | ||
397 | return fetch_body (command, &p); | ||
398 | } | ||
399 | |||
400 | /* The [RFC-822] size of the message. */ | ||
401 | static int | ||
402 | fetch_rfc822_size (struct fetch_command *command, char **arg MU_ARG_UNUSED) | ||
403 | { | ||
404 | size_t size = 0; | ||
405 | size_t lines = 0; | ||
406 | |||
407 | mu_message_size (command->msg, &size); | ||
408 | mu_message_lines (command->msg, &lines); | ||
409 | util_send ("%s %u", command->name, size + lines); | ||
410 | return RESP_OK; | ||
411 | } | ||
412 | 108 | ||
413 | /* RFC822: | 109 | util_send_qstring (str); |
414 | Functionally equivalent to BODY[], differing in the syntax of the | ||
415 | resulting untagged FETCH data (RFC822 is returned). */ | ||
416 | static int | ||
417 | fetch_rfc822 (struct fetch_command *command, char **arg) | ||
418 | { | ||
419 | if (**arg == '.') | ||
420 | { | ||
421 | /* We have to catch the other RFC822.XXX commands here. This is because | ||
422 | util_token() in imap4d_fetch0 will return the RFC822 token only. */ | ||
423 | if (strncasecmp (*arg, ".SIZE", 5) == 0) | ||
424 | { | ||
425 | struct fetch_command c_rfc= fetch_command_table[F_RFC822_SIZE]; | ||
426 | c_rfc.msg = command->msg; | ||
427 | (*arg) += 5; | ||
428 | fetch_rfc822_size (&c_rfc, arg); | ||
429 | } | ||
430 | else if (strncasecmp (*arg, ".TEXT", 5) == 0) | ||
431 | { | ||
432 | struct fetch_command c_rfc = fetch_command_table[F_RFC822_TEXT]; | ||
433 | c_rfc.msg = command->msg; | ||
434 | (*arg) += 5; | ||
435 | fetch_rfc822_text (&c_rfc, arg); | ||
436 | } | ||
437 | else if (strncasecmp (*arg, ".HEADER", 7) == 0) | ||
438 | { | ||
439 | struct fetch_command c_rfc = fetch_command_table[F_RFC822_HEADER]; | ||
440 | c_rfc.msg = command->msg; | ||
441 | (*arg) += 7; | ||
442 | fetch_rfc822_header (&c_rfc, arg); | ||
443 | } | ||
444 | } | ||
445 | else | ||
446 | { | ||
447 | char buffer[16]; | ||
448 | char *p = buffer; | ||
449 | strcpy (buffer, "[]"); | ||
450 | fetch_body (command, &p); | ||
451 | } | ||
452 | return RESP_OK; | ||
453 | } | ||
454 | 110 | ||
455 | /* UID: The unique identifier for the message. */ | 111 | util_send (" "); |
456 | static int | ||
457 | fetch_uid (struct fetch_command *command, char **arg MU_ARG_UNUSED) | ||
458 | { | ||
459 | size_t uid = 0; | ||
460 | 112 | ||
461 | mu_message_get_uid (command->msg, &uid); | 113 | mu_address_sget_domain (address, i, &str); |
462 | util_send ("%s %s", command->name, mu_umaxtostr (0, uid)); | 114 | util_send_qstring (str); |
463 | return RESP_OK; | ||
464 | } | ||
465 | 115 | ||
466 | /* BODYSTRUCTURE: | ||
467 | The [MIME-IMB] body structure of the message. This is computed by the | ||
468 | server by parsing the [MIME-IMB] header fields in the [RFC-822] header and | ||
469 | [MIME-IMB] headers. */ | ||
470 | static int | ||
471 | fetch_bodystructure (struct fetch_command *command, char **arg MU_ARG_UNUSED) | ||
472 | { | ||
473 | util_send ("%s (", command->name); | ||
474 | fetch_bodystructure0 (command->msg, 1); /* 1 means with extension data. */ | ||
475 | util_send (")"); | 116 | util_send (")"); |
476 | return RESP_OK; | ||
477 | } | ||
478 | |||
479 | /* BODY: Non-extensible form of BODYSTRUCTURE. | ||
480 | BODY[<section>]<<partial>> : | ||
481 | The text of a particular body section. The section specification is a set | ||
482 | of zero or more part specifiers delimited by periods. A part specifier | ||
483 | is either a part number or one of the following: HEADER, HEADER.FIELDS, | ||
484 | HEADER.FIELDS.NOT, MIME, and TEXT. An empty section specification refers | ||
485 | to the entire message, including the header. | ||
486 | |||
487 | Note: for body section, the \Seen flag is implicitly set; | ||
488 | if this causes the flags to change they SHOULD be | ||
489 | included as part of the FETCH responses. */ | ||
490 | static int | ||
491 | fetch_body (struct fetch_command *command, char **arg) | ||
492 | { | ||
493 | /* It's body section, set the message as seen */ | ||
494 | if (**arg == '[') | ||
495 | { | ||
496 | mu_attribute_t attr = NULL; | ||
497 | mu_message_get_attribute (command->msg, &attr); | ||
498 | if (!mu_attribute_is_read (attr)) | ||
499 | { | ||
500 | util_send ("FLAGS (\\Seen) "); | ||
501 | mu_attribute_set_read (attr); | ||
502 | } | ||
503 | } | ||
504 | else if (strncasecmp (*arg,".PEEK", 5) == 0) | ||
505 | { | ||
506 | /* Move pass the .peek */ | ||
507 | (*arg) += 5; | ||
508 | while (isspace ((unsigned)**arg)) | ||
509 | (*arg)++; | ||
510 | } | 117 | } |
511 | else if (**arg != '[' && **arg != '.') | ||
512 | { | ||
513 | /* Call body structure without the extension. */ | ||
514 | util_send ("%s (", command->name); | ||
515 | fetch_bodystructure0 (command->msg, 0); | ||
516 | util_send (")"); | 118 | util_send (")"); |
517 | return RESP_OK; | 119 | return RESP_OK; |
518 | } | ||
519 | util_send ("%s", command->name); | ||
520 | return fetch_operation (command->msg, arg, | ||
521 | strcasecmp (command->name, "BODY")); | ||
522 | } | 120 | } |
523 | 121 | ||
524 | /* Helper Functions: Where the Beef is. */ | ||
525 | |||
526 | static void | 122 | static void |
527 | fetch_send_header_value (mu_header_t header, const char *name, | 123 | fetch_send_header_value (mu_header_t header, const char *name, |
528 | const char *defval, int space) | 124 | const char *defval, int space) |
... | @@ -543,7 +139,7 @@ fetch_send_header_value (mu_header_t header, const char *name, | ... | @@ -543,7 +139,7 @@ fetch_send_header_value (mu_header_t header, const char *name, |
543 | } | 139 | } |
544 | 140 | ||
545 | static void | 141 | static void |
546 | fetch_send_header_list (mu_header_t header, const char *name, | 142 | fetch_send_header_address (mu_header_t header, const char *name, |
547 | const char *defval, int space) | 143 | const char *defval, int space) |
548 | { | 144 | { |
549 | char *buffer; | 145 | char *buffer; |
... | @@ -552,146 +148,47 @@ fetch_send_header_list (mu_header_t header, const char *name, | ... | @@ -552,146 +148,47 @@ fetch_send_header_list (mu_header_t header, const char *name, |
552 | util_send (" "); | 148 | util_send (" "); |
553 | if (mu_header_aget_value (header, name, &buffer) == 0) | 149 | if (mu_header_aget_value (header, name, &buffer) == 0) |
554 | { | 150 | { |
555 | send_parameter_list (buffer); | 151 | fetch_send_address (buffer); |
556 | free (buffer); | 152 | free (buffer); |
557 | } | 153 | } |
558 | else if (defval) | ||
559 | send_parameter_list (defval); | ||
560 | else | 154 | else |
561 | util_send ("NIL"); | 155 | fetch_send_address (defval); |
562 | } | 156 | } |
563 | 157 | ||
158 | /* Send parameter list for the bodystructure. */ | ||
564 | static void | 159 | static void |
565 | fetch_send_header_address (mu_header_t header, const char *name, | 160 | send_parameter_list (const char *buffer) |
566 | const char *defval, int space) | ||
567 | { | 161 | { |
568 | char *buffer; | 162 | int argc = 0; |
163 | char **argv; | ||
569 | 164 | ||
570 | if (space) | 165 | if (!buffer) |
571 | util_send (" "); | ||
572 | if (mu_header_aget_value (header, name, &buffer) == 0) | ||
573 | { | 166 | { |
574 | fetch_send_address (buffer); | 167 | util_send ("NIL"); |
575 | free (buffer); | 168 | return; |
576 | } | 169 | } |
577 | else | ||
578 | fetch_send_address (defval); | ||
579 | } | ||
580 | |||
581 | /* ENVELOPE: | ||
582 | The envelope structure of the message. This is computed by the server by | ||
583 | parsing the [RFC-822] header into the component parts, defaulting various | ||
584 | fields as necessary. The fields are presented in the order: | ||
585 | Date, Subject, From, Sender, Reply-To, To, Cc, Bcc, In-Reply-To, Message-ID. | ||
586 | Any field of an envelope or address structure that is not applicable is | ||
587 | presented as NIL. Note that the server MUST default the reply-to and sender | ||
588 | fields from the from field. The date, subject, in-reply-to, and message-id | ||
589 | fields are strings. The from, sender, reply-to, to, cc, and bcc fields | ||
590 | are parenthesized lists of address structures. */ | ||
591 | static int | ||
592 | fetch_envelope0 (mu_message_t msg) | ||
593 | { | ||
594 | char *from = NULL; | ||
595 | mu_header_t header = NULL; | ||
596 | |||
597 | mu_message_get_header (msg, &header); | ||
598 | |||
599 | fetch_send_header_value (header, "Date", NULL, 0); | ||
600 | fetch_send_header_value (header, "Subject", NULL, 1); | ||
601 | |||
602 | /* From: */ | ||
603 | mu_header_aget_value (header, "From", &from); | ||
604 | util_send (" "); | ||
605 | fetch_send_address (from); | ||
606 | |||
607 | fetch_send_header_address (header, "Sender", from, 1); | ||
608 | fetch_send_header_address (header, "Reply-to", from, 1); | ||
609 | fetch_send_header_address (header, "To", NULL, 1); | ||
610 | fetch_send_header_address (header, "Cc", NULL, 1); | ||
611 | fetch_send_header_address (header, "Bcc", NULL, 1); | ||
612 | fetch_send_header_value (header, "In-Reply-To", NULL, 1); | ||
613 | fetch_send_header_value (header, "Message-ID", NULL, 1); | ||
614 | |||
615 | free (from); | ||
616 | return RESP_OK; | ||
617 | } | ||
618 | |||
619 | /* The beef BODYSTRUCTURE. | ||
620 | A parenthesized list that describes the [MIME-IMB] body structure of a | ||
621 | message. Multiple parts are indicated by parenthesis nesting. Instead of | ||
622 | a body type as the first element of the parenthesized list there is a nested | ||
623 | body. The second element of the parenthesized list is the multipart | ||
624 | subtype (mixed, digest, parallel, alternative, etc.). | ||
625 | |||
626 | The extension data of a multipart body part are in the following order: | ||
627 | body parameter parenthesized list: | ||
628 | A parenthesized list of attribute/value pairs [e.g. ("foo" "bar" "baz" | ||
629 | "rag") where "bar" is the value of "foo" and "rag" is the value of | ||
630 | "baz"] as defined in [MIME-IMB]. | ||
631 | |||
632 | body disposition: | ||
633 | A parenthesized list, consisting of a disposition type string followed by a | ||
634 | parenthesized list of disposition attribute/value pairs. The disposition | ||
635 | type and attribute names will be defined in a future standards-track | ||
636 | revision to [DISPOSITION]. | ||
637 | 170 | ||
638 | body language: | 171 | mu_argcv_get (buffer, " \t\r\n;=", NULL, &argc, &argv); |
639 | A string or parenthesized list giving the body language value as defined | ||
640 | in [LANGUAGE-TAGS]. */ | ||
641 | static int | ||
642 | fetch_bodystructure0 (mu_message_t message, int extension) | ||
643 | { | ||
644 | size_t nparts = 1; | ||
645 | size_t i; | ||
646 | int is_multipart = 0; | ||
647 | 172 | ||
648 | mu_message_is_multipart (message, &is_multipart); | 173 | if (argc == 0) |
649 | if (is_multipart) | 174 | util_send ("NIL"); |
175 | else | ||
650 | { | 176 | { |
651 | char *buffer = NULL; | 177 | char *p; |
652 | mu_header_t header = NULL; | ||
653 | |||
654 | mu_message_get_num_parts (message, &nparts); | ||
655 | 178 | ||
656 | /* Get all the sub messages. */ | ||
657 | for (i = 1; i <= nparts; i++) | ||
658 | { | ||
659 | mu_message_t msg = NULL; | ||
660 | mu_message_get_part (message, i, &msg); | ||
661 | util_send ("("); | 179 | util_send ("("); |
662 | fetch_bodystructure0 (msg, extension); | ||
663 | util_send (")"); | ||
664 | } /* for () */ | ||
665 | |||
666 | mu_message_get_header (message, &header); | ||
667 | 180 | ||
181 | p = argv[0]; | ||
182 | util_send_qstring (p); | ||
668 | 183 | ||
669 | /* The subtype. */ | 184 | if (argc > 1) |
670 | if (mu_header_aget_value (header, MU_HEADER_CONTENT_TYPE, &buffer) == 0) | ||
671 | { | ||
672 | int argc = 0; | ||
673 | char **argv; | ||
674 | char *s; | ||
675 | |||
676 | mu_argcv_get (buffer, " \t\r\n;=", NULL, &argc, &argv); | ||
677 | |||
678 | s = strchr (argv[0], '/'); | ||
679 | if (s) | ||
680 | s++; | ||
681 | util_send (" "); | ||
682 | util_send_qstring (s); | ||
683 | |||
684 | /* The extension data for multipart. */ | ||
685 | if (extension) | ||
686 | { | 185 | { |
687 | int space = 0; | 186 | int i, space = 0; |
688 | char *lvalue = NULL; | 187 | char *lvalue = NULL; |
689 | 188 | ||
690 | util_send (" ("); | 189 | util_send ("("); |
691 | for (i = 1; i < argc; i++) | 190 | for (i = 1; i < argc; i++) |
692 | { | 191 | { |
693 | /* body parameter parenthesized list: | ||
694 | Content-type parameter list. */ | ||
695 | if (lvalue) | 192 | if (lvalue) |
696 | { | 193 | { |
697 | if (space) | 194 | if (space) |
... | @@ -711,7 +208,6 @@ fetch_bodystructure0 (mu_message_t message, int extension) | ... | @@ -711,7 +208,6 @@ fetch_bodystructure0 (mu_message_t message, int extension) |
711 | { | 208 | { |
712 | char *p = argv[i]; | 209 | char *p = argv[i]; |
713 | util_send (" "); | 210 | util_send (" "); |
714 | util_unquote (&p); | ||
715 | util_send_qstring (p); | 211 | util_send_qstring (p); |
716 | } | 212 | } |
717 | break; | 213 | break; |
... | @@ -730,22 +226,65 @@ fetch_bodystructure0 (mu_message_t message, int extension) | ... | @@ -730,22 +226,65 @@ fetch_bodystructure0 (mu_message_t message, int extension) |
730 | } | 226 | } |
731 | else | 227 | else |
732 | util_send (" NIL"); | 228 | util_send (" NIL"); |
229 | util_send (")"); | ||
230 | } | ||
733 | mu_argcv_free (argc, argv); | 231 | mu_argcv_free (argc, argv); |
232 | } | ||
233 | |||
234 | static void | ||
235 | fetch_send_header_list (mu_header_t header, const char *name, | ||
236 | const char *defval, int space) | ||
237 | { | ||
238 | char *buffer; | ||
239 | |||
240 | if (space) | ||
241 | util_send (" "); | ||
242 | if (mu_header_aget_value (header, name, &buffer) == 0) | ||
243 | { | ||
244 | send_parameter_list (buffer); | ||
734 | free (buffer); | 245 | free (buffer); |
735 | } | 246 | } |
247 | else if (defval) | ||
248 | send_parameter_list (defval); | ||
736 | else | 249 | else |
737 | /* No content-type header */ | 250 | util_send ("NIL"); |
738 | util_send (" NIL"); | 251 | } |
739 | 252 | ||
740 | /* body disposition: Content-Disposition. */ | 253 | /* ENVELOPE: |
741 | fetch_send_header_list (header, MU_HEADER_CONTENT_DISPOSITION, | 254 | The envelope structure of the message. This is computed by the server by |
742 | NULL, 1); | 255 | parsing the [RFC-822] header into the component parts, defaulting various |
743 | /* body language: Content-Language. */ | 256 | fields as necessary. The fields are presented in the order: |
744 | fetch_send_header_list (header, MU_HEADER_CONTENT_LANGUAGE, | 257 | Date, Subject, From, Sender, Reply-To, To, Cc, Bcc, In-Reply-To, Message-ID. |
745 | NULL, 1); | 258 | Any field of an envelope or address structure that is not applicable is |
746 | } | 259 | presented as NIL. Note that the server MUST default the reply-to and sender |
747 | else | 260 | fields from the from field. The date, subject, in-reply-to, and message-id |
748 | bodystructure (message, extension); | 261 | fields are strings. The from, sender, reply-to, to, cc, and bcc fields |
262 | are parenthesized lists of address structures. */ | ||
263 | static int | ||
264 | fetch_envelope0 (mu_message_t msg) | ||
265 | { | ||
266 | char *from = NULL; | ||
267 | mu_header_t header = NULL; | ||
268 | |||
269 | mu_message_get_header (msg, &header); | ||
270 | |||
271 | fetch_send_header_value (header, "Date", NULL, 0); | ||
272 | fetch_send_header_value (header, "Subject", NULL, 1); | ||
273 | |||
274 | /* From: */ | ||
275 | mu_header_aget_value (header, "From", &from); | ||
276 | util_send (" "); | ||
277 | fetch_send_address (from); | ||
278 | |||
279 | fetch_send_header_address (header, "Sender", from, 1); | ||
280 | fetch_send_header_address (header, "Reply-to", from, 1); | ||
281 | fetch_send_header_address (header, "To", NULL, 1); | ||
282 | fetch_send_header_address (header, "Cc", NULL, 1); | ||
283 | fetch_send_header_address (header, "Bcc", NULL, 1); | ||
284 | fetch_send_header_value (header, "In-Reply-To", NULL, 1); | ||
285 | fetch_send_header_value (header, "Message-ID", NULL, 1); | ||
286 | |||
287 | free (from); | ||
749 | return RESP_OK; | 288 | return RESP_OK; |
750 | } | 289 | } |
751 | 290 | ||
... | @@ -857,7 +396,6 @@ bodystructure (mu_message_t msg, int extension) | ... | @@ -857,7 +396,6 @@ bodystructure (mu_message_t msg, int extension) |
857 | { | 396 | { |
858 | char *p = argv[i]; | 397 | char *p = argv[i]; |
859 | util_send (" "); | 398 | util_send (" "); |
860 | util_unquote (&p); | ||
861 | util_send_qstring (p); | 399 | util_send_qstring (p); |
862 | } | 400 | } |
863 | break; | 401 | break; |
... | @@ -955,195 +493,187 @@ bodystructure (mu_message_t msg, int extension) | ... | @@ -955,195 +493,187 @@ bodystructure (mu_message_t msg, int extension) |
955 | return RESP_OK; | 493 | return RESP_OK; |
956 | } | 494 | } |
957 | 495 | ||
496 | /* The beef BODYSTRUCTURE. | ||
497 | A parenthesized list that describes the [MIME-IMB] body structure of a | ||
498 | message. Multiple parts are indicated by parenthesis nesting. Instead of | ||
499 | a body type as the first element of the parenthesized list there is a nested | ||
500 | body. The second element of the parenthesized list is the multipart | ||
501 | subtype (mixed, digest, parallel, alternative, etc.). | ||
502 | |||
503 | The extension data of a multipart body part are in the following order: | ||
504 | body parameter parenthesized list: | ||
505 | A parenthesized list of attribute/value pairs [e.g. ("foo" "bar" "baz" | ||
506 | "rag") where "bar" is the value of "foo" and "rag" is the value of | ||
507 | "baz"] as defined in [MIME-IMB]. | ||
508 | |||
509 | body disposition: | ||
510 | A parenthesized list, consisting of a disposition type string followed by a | ||
511 | parenthesized list of disposition attribute/value pairs. The disposition | ||
512 | type and attribute names will be defined in a future standards-track | ||
513 | revision to [DISPOSITION]. | ||
514 | |||
515 | body language: | ||
516 | A string or parenthesized list giving the body language value as defined | ||
517 | in [LANGUAGE-TAGS]. */ | ||
958 | static int | 518 | static int |
959 | fetch_operation (mu_message_t msg, char **arg, int silent) | 519 | fetch_bodystructure0 (mu_message_t message, int extension) |
960 | { | 520 | { |
961 | unsigned long start = ULONG_MAX; /* No starting offset. */ | 521 | size_t nparts = 1; |
962 | unsigned long end = ULONG_MAX; /* No limit. */ | 522 | size_t i; |
963 | char *section; /* Hold the section number string. */ | 523 | int is_multipart = 0; |
964 | char *partial = strchr (*arg, '<'); | ||
965 | int rc; | ||
966 | 524 | ||
967 | /* Check for section specific offset. */ | 525 | mu_message_is_multipart (message, &is_multipart); |
968 | if (partial) | 526 | if (is_multipart) |
969 | { | ||
970 | /* NOTE: should this should be move in imap4d_fetch() and have a more | ||
971 | draconian check? */ | ||
972 | *partial = '\0'; | ||
973 | partial++; | ||
974 | start = strtoul (partial, &partial, 10); | ||
975 | if (*partial == '.') | ||
976 | { | 527 | { |
977 | partial++; | 528 | char *buffer = NULL; |
978 | end = strtoul (partial, NULL, 10); | 529 | mu_header_t header = NULL; |
979 | } | ||
980 | } | ||
981 | 530 | ||
982 | /* Pass the first bracket '[' */ | 531 | mu_message_get_num_parts (message, &nparts); |
983 | (*arg)++; | ||
984 | section = *arg; | ||
985 | 532 | ||
986 | /* Retreive the section message. */ | 533 | /* Get all the sub messages. */ |
987 | while (isdigit ((unsigned)**arg)) | 534 | for (i = 1; i <= nparts; i++) |
988 | { | 535 | { |
989 | unsigned long j = strtoul (*arg, arg, 10); | 536 | mu_message_t msg = NULL; |
990 | int status; | 537 | mu_message_get_part (message, i, &msg); |
538 | util_send ("("); | ||
539 | fetch_bodystructure0 (msg, extension); | ||
540 | util_send (")"); | ||
541 | } /* for () */ | ||
991 | 542 | ||
992 | /* Wrong section message number bail out. */ | 543 | mu_message_get_header (message, &header); |
993 | if (j == 0 || j == ULONG_MAX) /* Technical: I should check errno too. */ | ||
994 | break; | ||
995 | 544 | ||
996 | /* If the section message did not exist bail out here. */ | ||
997 | status = mu_message_get_part (msg, j, &msg); | ||
998 | if (status != 0) | ||
999 | { | ||
1000 | util_send (" \"\""); | ||
1001 | return RESP_OK; | ||
1002 | } | ||
1003 | if (**arg == '.') | ||
1004 | (*arg)++; | ||
1005 | else | ||
1006 | break; | ||
1007 | } | ||
1008 | 545 | ||
1009 | /* Did we have a section message? */ | 546 | /* The subtype. */ |
1010 | if (((*arg) - section) > 0) | 547 | if (mu_header_aget_value (header, MU_HEADER_CONTENT_TYPE, &buffer) == 0) |
1011 | { | 548 | { |
1012 | char *p = section; | 549 | int argc = 0; |
1013 | section = calloc ((*arg) - p + 1, 1); | 550 | char **argv; |
1014 | if (section) | 551 | char *s; |
1015 | memcpy (section, p, (*arg) - p); | ||
1016 | } | ||
1017 | else | ||
1018 | section = calloc (1, 1); | ||
1019 | 552 | ||
1020 | rc = RESP_OK; | 553 | mu_argcv_get (buffer, " \t\r\n;=", NULL, &argc, &argv); |
1021 | 554 | ||
1022 | /* Choose the right fetch attribute. */ | 555 | s = strchr (argv[0], '/'); |
1023 | if (*section == '\0' && **arg == ']') | 556 | if (s) |
1024 | { | 557 | s++; |
1025 | if (!silent) | 558 | util_send (" "); |
1026 | util_send ("[]"); | 559 | util_send_qstring (s); |
1027 | (*arg)++; | 560 | |
1028 | rc = fetch_message (msg, start, end); | 561 | /* The extension data for multipart. */ |
1029 | } | 562 | if (extension) |
1030 | else if (strncasecmp (*arg, "HEADER]", 7) == 0) | ||
1031 | { | ||
1032 | if (!silent) | ||
1033 | { | ||
1034 | /* NOTE: We violate the RFC here: Header cannot take a prefix for | ||
1035 | section messages it only referes to the RFC822 header .. ok | ||
1036 | see it as an extension. But according to IMAP4 we should | ||
1037 | have send an empty string: util_send (" \"\""); | ||
1038 | */ | ||
1039 | util_send ("[%sHEADER]", section); | ||
1040 | } | ||
1041 | (*arg) += 7; | ||
1042 | rc = fetch_header (msg, start, end); | ||
1043 | } | ||
1044 | else if (strncasecmp (*arg, "MIME]", 5) == 0) | ||
1045 | { | ||
1046 | if (!silent) | ||
1047 | { | 563 | { |
1048 | if (*section) | 564 | int space = 0; |
1049 | util_send ("[%sMIME]", section); | 565 | char *lvalue = NULL; |
1050 | else | 566 | |
1051 | util_send ("[%s", *arg); | 567 | util_send (" ("); |
1052 | } | 568 | for (i = 1; i < argc; i++) |
1053 | (*arg) += 5; | ||
1054 | rc = fetch_header (msg, start, end); | ||
1055 | } | ||
1056 | else if (strncasecmp (*arg, "HEADER.FIELDS.NOT", 17) == 0) | ||
1057 | { | 569 | { |
1058 | /* NOTE: we should flag an error if section is not empty: accept | 570 | /* body parameter parenthesized list: |
1059 | as an extension for now. */ | 571 | Content-type parameter list. */ |
1060 | if (*section) | 572 | if (lvalue) |
1061 | util_send ("[%s", section); | ||
1062 | else | ||
1063 | util_send ("["); | ||
1064 | (*arg) += 17; | ||
1065 | rc = fetch_header_fields_not (msg, arg, start, end); | ||
1066 | } | ||
1067 | else if (strncasecmp (*arg, "HEADER.FIELDS", 13) == 0) | ||
1068 | { | 573 | { |
1069 | /* NOTE: we should flag an error if section is not empty: accept | 574 | if (space) |
1070 | as an extension for now. */ | 575 | util_send (" "); |
1071 | if (*section) | 576 | util_send_qstring (lvalue); |
1072 | util_send ("[%s", section); | 577 | lvalue = NULL; |
1073 | else | 578 | space = 1; |
1074 | util_send ("["); | ||
1075 | (*arg) += 13; | ||
1076 | rc = fetch_header_fields (msg, arg, start, end); | ||
1077 | } | 579 | } |
1078 | 580 | ||
1079 | else if (strncasecmp (*arg, "TEXT]", 5) == 0) | 581 | switch (argv[i][0]) |
1080 | { | 582 | { |
1081 | if (!silent) | 583 | case ';': |
584 | continue; | ||
585 | |||
586 | case '=': | ||
587 | if (++i < argc) | ||
1082 | { | 588 | { |
1083 | if (*section) | 589 | char *p = argv[i]; |
1084 | util_send ("[%sTEXT]", section); | 590 | util_send (" "); |
1085 | else | 591 | util_send_qstring (p); |
1086 | util_send ("[TEXT]"); | 592 | } |
593 | break; | ||
594 | |||
595 | default: | ||
596 | lvalue = argv[i]; | ||
1087 | } | 597 | } |
1088 | (*arg) += 5; | ||
1089 | rc = fetch_body_content (msg, start, end); | ||
1090 | } | 598 | } |
1091 | else if (**arg == ']') | 599 | if (lvalue) |
1092 | { | 600 | { |
1093 | if (!silent) | 601 | if (space) |
1094 | util_send ("[%s]", section); | 602 | util_send (" "); |
1095 | (*arg)++; | 603 | util_send_qstring (lvalue); |
1096 | rc = fetch_body_content (msg, start, end); | 604 | } |
605 | util_send (")"); | ||
1097 | } | 606 | } |
1098 | else | 607 | else |
1099 | { | 608 | util_send (" NIL"); |
1100 | util_send (" \"\"");/*FIXME: ERROR Message!*/ | 609 | mu_argcv_free (argc, argv); |
1101 | rc = RESP_BAD; | 610 | free (buffer); |
1102 | } | 611 | } |
1103 | free (section); | 612 | else |
1104 | return rc; | 613 | /* No content-type header */ |
614 | util_send (" NIL"); | ||
615 | |||
616 | /* body disposition: Content-Disposition. */ | ||
617 | fetch_send_header_list (header, MU_HEADER_CONTENT_DISPOSITION, | ||
618 | NULL, 1); | ||
619 | /* body language: Content-Language. */ | ||
620 | fetch_send_header_list (header, MU_HEADER_CONTENT_LANGUAGE, | ||
621 | NULL, 1); | ||
622 | } | ||
623 | else | ||
624 | bodystructure (message, extension); | ||
625 | return RESP_OK; | ||
1105 | } | 626 | } |
1106 | 627 | ||
1107 | static int | 628 | static void |
1108 | fetch_message (mu_message_t msg, unsigned long start, unsigned long end) | 629 | set_seen (struct fetch_function_closure *ffc, |
630 | struct fetch_runtime_closure *frt) | ||
1109 | { | 631 | { |
1110 | mu_stream_t stream = NULL; | 632 | if (!ffc->peek) |
1111 | size_t size = 0, lines = 0; | 633 | { |
1112 | mu_message_get_stream (msg, &stream); | 634 | mu_attribute_t attr = NULL; |
1113 | mu_message_size (msg, &size); | 635 | mu_message_get_attribute (frt->msg, &attr); |
1114 | mu_message_lines (msg, &lines); | 636 | if (!mu_attribute_is_read (attr)) |
1115 | return fetch_io (stream, start, end, size + lines); | 637 | { |
638 | util_send ("FLAGS (\\Seen) "); | ||
639 | mu_attribute_set_read (attr); | ||
640 | } | ||
641 | } | ||
1116 | } | 642 | } |
1117 | 643 | ||
1118 | static int | 644 | static mu_message_t |
1119 | fetch_header (mu_message_t msg, unsigned long start, unsigned long end) | 645 | fetch_get_part (struct fetch_function_closure *ffc, |
646 | struct fetch_runtime_closure *frt) | ||
1120 | { | 647 | { |
1121 | mu_header_t header = NULL; | 648 | mu_message_t msg = frt->msg; |
1122 | mu_stream_t stream = NULL; | 649 | size_t i; |
1123 | size_t size = 0, lines = 0; | 650 | |
1124 | mu_message_get_header (msg, &header); | 651 | for (i = 0; i < ffc->nset; i++) |
1125 | mu_header_size (header, &size); | 652 | if (mu_message_get_part (msg, ffc->section_part[i], &msg)) |
1126 | mu_header_lines (header, &lines); | 653 | return NULL; |
1127 | mu_header_get_stream (header, &stream); | 654 | return msg; |
1128 | return fetch_io (stream, start, end, size + lines); | ||
1129 | } | 655 | } |
1130 | 656 | ||
1131 | static int | 657 | static void |
1132 | fetch_body_content (mu_message_t msg, unsigned long start, unsigned long end) | 658 | fetch_send_section_part (struct fetch_function_closure *ffc, |
659 | const char *prefix, const char *suffix) | ||
1133 | { | 660 | { |
1134 | mu_body_t body = NULL; | 661 | int i; |
1135 | mu_stream_t stream = NULL; | 662 | |
1136 | size_t size = 0, lines = 0; | 663 | util_send ("%s", prefix); |
1137 | mu_message_get_body (msg, &body); | 664 | for (i = 0; i < ffc->nset; i++) |
1138 | mu_body_size (body, &size); | 665 | { |
1139 | mu_body_lines (body, &lines); | 666 | if (i) |
1140 | mu_body_get_stream (body, &stream); | 667 | util_send ("."); |
1141 | return fetch_io (stream, start, end, size + lines); | 668 | util_send ("%lu", (unsigned long) ffc->section_part[i]); |
669 | } | ||
670 | if (i && suffix[0] != ']') | ||
671 | util_send ("."); | ||
672 | util_send ("%s", suffix); | ||
1142 | } | 673 | } |
1143 | 674 | ||
1144 | static int | 675 | static int |
1145 | fetch_io (mu_stream_t stream, unsigned long start, unsigned long end, | 676 | fetch_io (mu_stream_t stream, size_t start, size_t size, size_t max) |
1146 | unsigned long max) | ||
1147 | { | 677 | { |
1148 | mu_stream_t rfc = NULL; | 678 | mu_stream_t rfc = NULL; |
1149 | size_t n = 0; | 679 | size_t n = 0; |
... | @@ -1151,13 +681,13 @@ fetch_io (mu_stream_t stream, unsigned long start, unsigned long end, | ... | @@ -1151,13 +681,13 @@ fetch_io (mu_stream_t stream, unsigned long start, unsigned long end, |
1151 | 681 | ||
1152 | mu_filter_create (&rfc, stream, "rfc822", MU_FILTER_ENCODE, MU_STREAM_READ); | 682 | mu_filter_create (&rfc, stream, "rfc822", MU_FILTER_ENCODE, MU_STREAM_READ); |
1153 | 683 | ||
1154 | if (start == ULONG_MAX || end == ULONG_MAX) | 684 | if (start == 0 && size == (size_t) -1) |
1155 | { | 685 | { |
1156 | char buffer[512]; | 686 | char buffer[512]; |
1157 | offset = 0; | 687 | offset = 0; |
1158 | if (max) | 688 | if (max) |
1159 | { | 689 | { |
1160 | util_send (" {%lu}\r\n", max); | 690 | util_send (" {%lu}\r\n", (unsigned long) max); |
1161 | while (mu_stream_read (rfc, buffer, sizeof (buffer) - 1, offset, | 691 | while (mu_stream_read (rfc, buffer, sizeof (buffer) - 1, offset, |
1162 | &n) == 0 && n > 0) | 692 | &n) == 0 && n > 0) |
1163 | { | 693 | { |
... | @@ -1165,11 +695,12 @@ fetch_io (mu_stream_t stream, unsigned long start, unsigned long end, | ... | @@ -1165,11 +695,12 @@ fetch_io (mu_stream_t stream, unsigned long start, unsigned long end, |
1165 | util_send ("%s", buffer); | 695 | util_send ("%s", buffer); |
1166 | offset += n; | 696 | offset += n; |
1167 | } | 697 | } |
698 | /* FIXME: Make sure exactly max bytes were sent */ | ||
1168 | } | 699 | } |
1169 | else | 700 | else |
1170 | util_send (" \"\""); | 701 | util_send (" \"\""); |
1171 | } | 702 | } |
1172 | else if (end + 2 < end) /* Check for integer overflow */ | 703 | else if (size + 2 < size) /* Check for integer overflow */ |
1173 | { | 704 | { |
1174 | return RESP_BAD; | 705 | return RESP_BAD; |
1175 | } | 706 | } |
... | @@ -1178,393 +709,944 @@ fetch_io (mu_stream_t stream, unsigned long start, unsigned long end, | ... | @@ -1178,393 +709,944 @@ fetch_io (mu_stream_t stream, unsigned long start, unsigned long end, |
1178 | char *buffer, *p; | 709 | char *buffer, *p; |
1179 | size_t total = 0; | 710 | size_t total = 0; |
1180 | offset = start; | 711 | offset = start; |
1181 | p = buffer = calloc (end + 2, 1); | 712 | p = buffer = malloc (size + 1); |
1182 | while (end > 0 | 713 | if (!p) |
1183 | && mu_stream_read (rfc, buffer, end + 1, offset, &n) == 0 && n > 0) | 714 | imap4d_bye (ERR_NO_MEM); |
715 | |||
716 | while (total < size | ||
717 | && mu_stream_read (rfc, p, size - total + 1, offset, &n) == 0 | ||
718 | && n > 0) | ||
1184 | { | 719 | { |
1185 | offset += n; | 720 | offset += n; |
1186 | total += n; | 721 | total += n; |
1187 | end -= n; | 722 | p += n; |
1188 | buffer += n; | ||
1189 | } | 723 | } |
1190 | /* Make sure we null terminate. */ | 724 | *p = 0; |
1191 | *buffer = '\0'; | 725 | util_send ("<%lu>", (unsigned long) start); |
1192 | util_send ("<%lu>", start); | ||
1193 | if (total) | 726 | if (total) |
1194 | { | 727 | { |
1195 | util_send (" {%s}\r\n", mu_umaxtostr (0, total)); | 728 | util_send (" {%lu}\r\n", (unsigned long) total); |
1196 | util_send ("%s", p); | 729 | util_send ("%s", buffer); |
1197 | } | 730 | } |
1198 | else | 731 | else |
1199 | util_send (" \"\""); | 732 | util_send (" \"\""); |
1200 | free (p); | 733 | free (buffer); |
1201 | } | 734 | } |
1202 | return RESP_OK; | 735 | return RESP_OK; |
1203 | } | 736 | } |
1204 | 737 | ||
738 | |||
739 | /* Runtime functions */ | ||
1205 | static int | 740 | static int |
1206 | fetch_header_fields (mu_message_t msg, char **arg, unsigned long start, | 741 | _frt_uid (struct fetch_function_closure *ffc, |
1207 | unsigned long end) | 742 | struct fetch_runtime_closure *frt) |
1208 | { | 743 | { |
1209 | char *buffer = NULL; | 744 | size_t uid = 0; |
1210 | char **array = NULL; | ||
1211 | size_t array_len = 0; | ||
1212 | size_t off = 0; | ||
1213 | size_t lines = 0; | ||
1214 | mu_stream_t stream = NULL; | ||
1215 | int status; | ||
1216 | |||
1217 | status = mu_memory_stream_create (&stream, 0, 0); | ||
1218 | if (status != 0) | ||
1219 | imap4d_bye (ERR_NO_MEM); | ||
1220 | |||
1221 | /* Save the fields in an array. */ | ||
1222 | { | ||
1223 | char *field; | ||
1224 | char *sp = NULL; | ||
1225 | char *f = *arg; | ||
1226 | /* Find the end of the header.field tag. */ | ||
1227 | field = strchr (f, ']'); | ||
1228 | if (field) | ||
1229 | { | ||
1230 | *field++ = '\0'; | ||
1231 | *arg = field; | ||
1232 | } | ||
1233 | else | ||
1234 | *arg += strlen (*arg); | ||
1235 | |||
1236 | for (;(field = util_getitem (f, " ()]\r\n", &sp)); f = NULL, array_len++) | ||
1237 | { | ||
1238 | array = realloc (array, (array_len + 1) * sizeof (*array)); | ||
1239 | if (!array) | ||
1240 | imap4d_bye (ERR_NO_MEM); | ||
1241 | array[array_len] = field; | ||
1242 | } | ||
1243 | } | ||
1244 | |||
1245 | /* Get the header values. */ | ||
1246 | { | ||
1247 | size_t j; | ||
1248 | mu_header_t header = NULL; | ||
1249 | mu_message_get_header (msg, &header); | ||
1250 | for (j = 0; j < array_len; j++) | ||
1251 | { | ||
1252 | char *value = NULL; | ||
1253 | size_t n = 0; | ||
1254 | if (mu_header_aget_value (header, array[j], &value)) | ||
1255 | continue; | ||
1256 | 745 | ||
1257 | n = asprintf (&buffer, "%s: %s\n", array[j], value); | 746 | mu_message_get_uid (frt->msg, &uid); |
1258 | status = mu_stream_write (stream, buffer, n, off, &n); | 747 | util_send ("%s %s", ffc->name, mu_umaxtostr (0, uid)); |
1259 | off += n; | 748 | return RESP_OK; |
1260 | /* count the lines. */ | 749 | } |
1261 | { | ||
1262 | char *nl = buffer; | ||
1263 | for (;(nl = strchr (nl, '\n')); nl++) | ||
1264 | lines++; | ||
1265 | } | ||
1266 | free (value); | ||
1267 | free (buffer); | ||
1268 | buffer = NULL; | ||
1269 | if (status != 0) | ||
1270 | { | ||
1271 | free (array); | ||
1272 | imap4d_bye (ERR_NO_MEM); | ||
1273 | } | ||
1274 | } | ||
1275 | } | ||
1276 | /* Headers are always sent with the NL separator. */ | ||
1277 | mu_stream_write (stream, "\n", 1, off, NULL); | ||
1278 | off++; | ||
1279 | lines++; | ||
1280 | 750 | ||
1281 | /* Send the command back. The first braket was already sent. */ | 751 | static int |
1282 | util_send ("HEADER.FIELDS"); | 752 | _frt_envelope (struct fetch_function_closure *ffc, |
1283 | { | 753 | struct fetch_runtime_closure *frt) |
1284 | size_t j; | 754 | { |
1285 | util_send (" ("); | 755 | util_send ("%s (", ffc->name); |
1286 | for (j = 0; j < array_len; j++) | 756 | fetch_envelope0 (frt->msg); |
1287 | { | ||
1288 | util_upper (array[j]); | ||
1289 | if (j) | ||
1290 | util_send (" "); | ||
1291 | util_send_qstring (array[j]); | ||
1292 | } | ||
1293 | util_send (")"); | 757 | util_send (")"); |
1294 | util_send ("]"); | ||
1295 | } | ||
1296 | |||
1297 | fetch_io (stream, start, end, off + lines); | ||
1298 | if (array) | ||
1299 | free (array); | ||
1300 | return RESP_OK; | 758 | return RESP_OK; |
1301 | } | 759 | } |
1302 | 760 | ||
1303 | static int | 761 | static int |
1304 | fetch_header_fields_not (mu_message_t msg, char **arg, unsigned long start, | 762 | _frt_flags (struct fetch_function_closure *ffc, |
1305 | unsigned long end) | 763 | struct fetch_runtime_closure *frt) |
1306 | { | 764 | { |
1307 | char **array = NULL; | 765 | mu_attribute_t attr = NULL; |
1308 | size_t array_len = 0; | ||
1309 | char *buffer = NULL; | ||
1310 | size_t off = 0; | ||
1311 | size_t lines = 0; | ||
1312 | mu_stream_t stream = NULL; | ||
1313 | int status; | ||
1314 | 766 | ||
1315 | status = mu_memory_stream_create (&stream, 0, 0); | 767 | mu_message_get_attribute (frt->msg, &attr); |
1316 | if (status) | 768 | util_send ("%s (", ffc->name); |
1317 | imap4d_bye (ERR_NO_MEM); | 769 | util_print_flags (attr); |
770 | util_send (")"); | ||
771 | return 0; | ||
772 | } | ||
1318 | 773 | ||
1319 | /* Save the field we want to ignore. */ | 774 | /* INTERNALDATE The internal date of the message. |
1320 | { | 775 | Format: |
1321 | char *field; | ||
1322 | char *sp = NULL; | ||
1323 | char *f = *arg; | ||
1324 | /* Find the end of the header.field.no tag. */ | ||
1325 | field = strchr (f, ']'); | ||
1326 | if (field) | ||
1327 | { | ||
1328 | *field++ = '\0'; | ||
1329 | *arg = field; | ||
1330 | } | ||
1331 | else | ||
1332 | *arg += strlen (*arg); | ||
1333 | 776 | ||
1334 | for (;(field = strtok_r (f, " ()\r\n", &sp)); f = NULL, array_len++) | 777 | date_time ::= <"> date_day_fixed "-" date_month "-" date_year |
1335 | { | 778 | SPACE time SPACE zone <"> |
1336 | array = realloc (array, (array_len + 1) * sizeof (*array)); | ||
1337 | if (!array) | ||
1338 | imap4d_bye (ERR_NO_MEM); | ||
1339 | array[array_len] = field; | ||
1340 | } | ||
1341 | } | ||
1342 | 779 | ||
1343 | /* Build the memory buffer. */ | 780 | date_day ::= 1*2digit |
1344 | { | 781 | ;; Day of month |
1345 | size_t i; | ||
1346 | mu_header_t header = NULL; | ||
1347 | size_t count = 0; | ||
1348 | mu_message_get_header (msg, &header); | ||
1349 | mu_header_get_field_count (header, &count); | ||
1350 | for (i = 1; i <= count; i++) | ||
1351 | { | ||
1352 | char *name = NULL; | ||
1353 | char *value ; | ||
1354 | size_t n = 0; | ||
1355 | size_t ignore = 0; | ||
1356 | 782 | ||
1357 | /* Get the field name. */ | 783 | date_day_fixed ::= (SPACE digit) / 2digit |
1358 | status = mu_header_aget_field_name (header, i, &name); | 784 | ;; Fixed-format version of date_day |
1359 | if (*name == '\0') | ||
1360 | { | ||
1361 | free (name); | ||
1362 | continue; | ||
1363 | } | ||
1364 | 785 | ||
1365 | /* Should we ignore the field? */ | 786 | date_month ::= "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" / |
1366 | { | 787 | "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec" |
1367 | size_t j; | ||
1368 | for (j = 0; j < array_len; j++) | ||
1369 | { | ||
1370 | if (strcasecmp (array[j], name) == 0) | ||
1371 | { | ||
1372 | ignore = 1; | ||
1373 | break; | ||
1374 | } | ||
1375 | } | ||
1376 | if (ignore) | ||
1377 | { | ||
1378 | free (name); | ||
1379 | continue; | ||
1380 | } | ||
1381 | } | ||
1382 | 788 | ||
1383 | if (mu_header_aget_field_value (header, i, &value) == 0) | 789 | date_text ::= date_day "-" date_month "-" date_year |
1384 | { | ||
1385 | char *nl; | ||
1386 | 790 | ||
1387 | /* Save the field. */ | 791 | date_year ::= 4digit |
1388 | n = asprintf (&buffer, "%s: %s\n", name, value); | ||
1389 | status = mu_stream_write (stream, buffer, n, off, &n); | ||
1390 | off += n; | ||
1391 | /* count the lines. */ | ||
1392 | for (nl = buffer;(nl = strchr (nl, '\n')); nl++) | ||
1393 | lines++; | ||
1394 | 792 | ||
1395 | free (value); | 793 | time ::= 2digit ":" 2digit ":" 2digit |
1396 | } | 794 | ;; Hours minutes seconds |
1397 | free (name); | ||
1398 | free (buffer); | ||
1399 | buffer = NULL; | ||
1400 | if (status != 0) | ||
1401 | { | ||
1402 | free (array); | ||
1403 | imap4d_bye (ERR_NO_MEM); | ||
1404 | } | ||
1405 | } | ||
1406 | } | ||
1407 | /* Headers are always sent with a NL separator. */ | ||
1408 | mu_stream_write (stream, "\n", 1, off, NULL); | ||
1409 | off++; | ||
1410 | lines++; | ||
1411 | 795 | ||
1412 | util_send ("HEADER.FIELDS.NOT"); | 796 | zone ::= ("+" / "-") 4digit |
1413 | { | 797 | ;; Signed four-digit value of hhmm representing |
1414 | size_t j; | 798 | ;; hours and minutes west of Greenwich (that is, |
1415 | util_send (" ("); | 799 | ;; (the amount that the given time differs from |
1416 | for (j = 0; j < array_len; j++) | 800 | ;; Universal Time). Subtracting the timezone |
801 | ;; from the given time will give the UT form. | ||
802 | ;; The Universal Time zone is "+0000". */ | ||
803 | static int | ||
804 | _frt_internaldate (struct fetch_function_closure *ffc, | ||
805 | struct fetch_runtime_closure *frt) | ||
806 | { | ||
807 | const char *date; | ||
808 | mu_envelope_t env = NULL; | ||
809 | struct tm tm, *tmp = NULL; | ||
810 | mu_timezone tz; | ||
811 | char datebuf[sizeof ("13-Jul-2002 00:00:00")]; | ||
812 | |||
813 | mu_message_get_envelope (frt->msg, &env); | ||
814 | if (mu_envelope_sget_date (env, &date) == 0 | ||
815 | && mu_parse_ctime_date_time (&date, &tm, &tz) == 0) | ||
816 | tmp = &tm; | ||
817 | else | ||
1417 | { | 818 | { |
1418 | util_upper (array[j]); | 819 | time_t t = time (NULL); |
1419 | if (j) | 820 | tmp = localtime (&t); |
1420 | util_send (" "); | ||
1421 | util_send_qstring (array[j]); | ||
1422 | } | ||
1423 | util_send (")"); | ||
1424 | util_send ("]"); | ||
1425 | } | 821 | } |
822 | mu_strftime (datebuf, sizeof (datebuf), "%d-%b-%Y %H:%M:%S", tmp); | ||
823 | util_send ("%s", ffc->name); | ||
824 | util_send (" \"%s +0000\"", datebuf); | ||
825 | return 0; | ||
826 | } | ||
1426 | 827 | ||
1427 | fetch_io (stream, start, end, off + lines); | 828 | static int |
1428 | if (array) | 829 | _frt_bodystructure (struct fetch_function_closure *ffc, |
1429 | free (array); | 830 | struct fetch_runtime_closure *frt) |
831 | { | ||
832 | util_send ("%s (", ffc->name); | ||
833 | fetch_bodystructure0 (frt->msg, 1); /* 1 means with extension data. */ | ||
834 | util_send (")"); | ||
1430 | return RESP_OK; | 835 | return RESP_OK; |
1431 | } | 836 | } |
1432 | 837 | ||
1433 | static int | 838 | static int |
1434 | fetch_send_address (const char *addr) | 839 | _frt_bodystructure0 (struct fetch_function_closure *ffc, |
840 | struct fetch_runtime_closure *frt) | ||
1435 | { | 841 | { |
1436 | mu_address_t address; | 842 | util_send ("%s (", ffc->name); |
1437 | size_t i, count = 0; | 843 | fetch_bodystructure0 (frt->msg, 0); |
844 | util_send (")"); | ||
845 | return RESP_OK; | ||
846 | } | ||
1438 | 847 | ||
1439 | /* Short circuit. */ | 848 | /* BODY[] */ |
1440 | if (addr == NULL || *addr == '\0') | 849 | static int |
850 | _frt_body (struct fetch_function_closure *ffc, | ||
851 | struct fetch_runtime_closure *frt) | ||
852 | { | ||
853 | mu_message_t msg; | ||
854 | mu_stream_t stream = NULL; | ||
855 | size_t size = 0, lines = 0; | ||
856 | |||
857 | set_seen (ffc, frt); | ||
858 | if (ffc->name) | ||
859 | util_send ("%s", ffc->name); | ||
860 | else | ||
861 | fetch_send_section_part (ffc, "BODY[", "]"); | ||
862 | msg = fetch_get_part (ffc, frt); | ||
863 | if (!msg) | ||
1441 | { | 864 | { |
1442 | util_send ("NIL"); | 865 | util_send (" \"\""); |
1443 | return RESP_OK; | 866 | return RESP_OK; |
1444 | } | 867 | } |
868 | mu_message_get_stream (msg, &stream); | ||
869 | mu_message_size (msg, &size); | ||
870 | mu_message_lines (msg, &lines); | ||
871 | return fetch_io (stream, ffc->start, ffc->size, size + lines); | ||
872 | } | ||
1445 | 873 | ||
1446 | mu_address_create (&address, addr); | 874 | static int |
1447 | mu_address_get_count (address, &count); | 875 | _frt_body_text (struct fetch_function_closure *ffc, |
876 | struct fetch_runtime_closure *frt) | ||
877 | { | ||
878 | mu_message_t msg; | ||
879 | mu_body_t body = NULL; | ||
880 | mu_stream_t stream = NULL; | ||
881 | size_t size = 0, lines = 0; | ||
1448 | 882 | ||
1449 | /* We failed: can't parse. */ | 883 | set_seen (ffc, frt); |
1450 | if (count == 0) | 884 | if (ffc->name) |
885 | util_send ("%s", ffc->name); | ||
886 | else | ||
887 | fetch_send_section_part (ffc, "BODY[", "TEXT]"); | ||
888 | msg = fetch_get_part (ffc, frt); | ||
889 | if (!msg) | ||
1451 | { | 890 | { |
1452 | util_send ("NIL"); | 891 | util_send (" \"\""); |
1453 | return RESP_OK; | 892 | return RESP_OK; |
1454 | } | 893 | } |
1455 | 894 | ||
1456 | util_send ("("); | 895 | mu_message_get_body (msg, &body); |
1457 | for (i = 1; i <= count; i++) | 896 | mu_body_size (body, &size); |
1458 | { | 897 | mu_body_lines (body, &lines); |
1459 | const char *str; | 898 | mu_body_get_stream (body, &stream); |
1460 | int is_group = 0; | 899 | return fetch_io (stream, ffc->start, ffc->size, size + lines); |
1461 | 900 | } | |
1462 | util_send ("("); | ||
1463 | 901 | ||
1464 | mu_address_sget_personal (address, i, &str); | 902 | static int |
1465 | util_send_qstring (str); | 903 | _frt_size (struct fetch_function_closure *ffc, |
1466 | util_send (" "); | 904 | struct fetch_runtime_closure *frt) |
905 | { | ||
906 | size_t size = 0; | ||
907 | size_t lines = 0; | ||
1467 | 908 | ||
1468 | mu_address_sget_route (address, i, &str); | 909 | mu_message_size (frt->msg, &size); |
1469 | util_send_qstring (str); | 910 | mu_message_lines (frt->msg, &lines); |
911 | util_send ("%s %u", ffc->name, size + lines); | ||
912 | return RESP_OK; | ||
913 | } | ||
1470 | 914 | ||
1471 | util_send (" "); | 915 | static int |
916 | _frt_header0 (struct fetch_function_closure *ffc, | ||
917 | struct fetch_runtime_closure *frt, | ||
918 | const char *suffix) | ||
919 | { | ||
920 | mu_message_t msg; | ||
921 | mu_header_t header = NULL; | ||
922 | mu_stream_t stream = NULL; | ||
923 | size_t size = 0, lines = 0; | ||
1472 | 924 | ||
1473 | mu_address_is_group (address, i, &is_group); | 925 | set_seen (ffc, frt); |
1474 | str = NULL; | 926 | if (ffc->name) |
1475 | if (is_group) | 927 | util_send ("%s", ffc->name); |
1476 | mu_address_sget_personal (address, i, &str); | ||
1477 | else | 928 | else |
1478 | mu_address_sget_local_part (address, i, &str); | 929 | fetch_send_section_part (ffc, "BODY[", suffix); |
1479 | 930 | ||
1480 | util_send_qstring (str); | 931 | msg = fetch_get_part (ffc, frt); |
932 | if (!msg) | ||
933 | { | ||
934 | util_send (" \"\""); | ||
935 | return RESP_OK; | ||
936 | } | ||
937 | mu_message_get_header (msg, &header); | ||
938 | mu_header_size (header, &size); | ||
939 | mu_header_lines (header, &lines); | ||
940 | mu_header_get_stream (header, &stream); | ||
941 | return fetch_io (stream, ffc->start, ffc->size, size + lines); | ||
942 | } | ||
1481 | 943 | ||
944 | static int | ||
945 | _frt_header (struct fetch_function_closure *ffc, | ||
946 | struct fetch_runtime_closure *frt) | ||
947 | { | ||
948 | return _frt_header0 (ffc, frt, "HEADER]"); | ||
949 | } | ||
950 | |||
951 | static int | ||
952 | _frt_mime (struct fetch_function_closure *ffc, | ||
953 | struct fetch_runtime_closure *frt) | ||
954 | { | ||
955 | return _frt_header0 (ffc, frt, "MIME]"); | ||
956 | } | ||
957 | |||
958 | static int | ||
959 | _send_header_name (void *item, void *data) | ||
960 | { | ||
961 | int *pf = data; | ||
962 | if (*pf) | ||
1482 | util_send (" "); | 963 | util_send (" "); |
964 | else | ||
965 | *pf = 1; | ||
966 | util_send ("\"%s\"", (char*) item); | ||
967 | return 0; | ||
968 | } | ||
1483 | 969 | ||
1484 | mu_address_sget_domain (address, i, &str); | 970 | static int |
1485 | util_send_qstring (str); | 971 | count_nl (const char *str) |
972 | { | ||
973 | int n = 0; | ||
974 | for (;(str = strchr (str, '\n')); str++) | ||
975 | n++; | ||
976 | return n; | ||
977 | } | ||
1486 | 978 | ||
1487 | util_send (")"); | 979 | static int |
980 | _frt_header_fields (struct fetch_function_closure *ffc, | ||
981 | struct fetch_runtime_closure *frt) | ||
982 | { | ||
983 | int status; | ||
984 | mu_message_t msg; | ||
985 | mu_off_t size = 0; | ||
986 | size_t lines = 0; | ||
987 | mu_stream_t stream; | ||
988 | mu_header_t header; | ||
989 | mu_iterator_t itr; | ||
990 | |||
991 | set_seen (ffc, frt); | ||
992 | |||
993 | fetch_send_section_part (ffc, "BODY[", "HEADER.FIELDS"); | ||
994 | if (ffc->not) | ||
995 | util_send (".NOT"); | ||
996 | util_send (" ("); | ||
997 | status = 0; | ||
998 | mu_list_do (ffc->headers, _send_header_name, &status); | ||
999 | util_send (")]"); | ||
1000 | |||
1001 | msg = fetch_get_part (ffc, frt); | ||
1002 | if (!msg) | ||
1003 | { | ||
1004 | util_send (" \"\""); | ||
1005 | return RESP_OK; | ||
1488 | } | 1006 | } |
1489 | util_send (")"); | 1007 | |
1008 | /* Collect headers: */ | ||
1009 | if (mu_message_get_header (msg, &header) | ||
1010 | || mu_header_get_iterator (header, &itr)) | ||
1011 | { | ||
1012 | util_send (" \"\""); | ||
1490 | return RESP_OK; | 1013 | return RESP_OK; |
1014 | } | ||
1015 | |||
1016 | status = mu_memory_stream_create (&stream, NULL, MU_STREAM_NO_CHECK); | ||
1017 | if (status != 0) | ||
1018 | imap4d_bye (ERR_NO_MEM); | ||
1019 | |||
1020 | for (mu_iterator_first (itr); | ||
1021 | !mu_iterator_is_done (itr); mu_iterator_next (itr)) | ||
1022 | { | ||
1023 | const char *hf; | ||
1024 | char *hv; | ||
1025 | const char *item; | ||
1026 | |||
1027 | mu_iterator_current_kv (itr, (const void **)&hf, (void **)&hv); | ||
1028 | status = mu_list_locate (ffc->headers, (void *)hf, (void**) &item) == 0; | ||
1029 | if (ffc->not) | ||
1030 | { | ||
1031 | status = !status; | ||
1032 | item = hf; | ||
1033 | } | ||
1034 | |||
1035 | if (status) | ||
1036 | { | ||
1037 | mu_stream_sequential_printf (stream, "%s: %s\n", item, hv); | ||
1038 | lines += 1 + count_nl (hv); | ||
1039 | } | ||
1040 | } | ||
1041 | mu_stream_sequential_write (stream, "\n", 1); | ||
1042 | lines++; | ||
1043 | |||
1044 | /* Output collected data */ | ||
1045 | mu_stream_size (stream, &size); | ||
1046 | status = fetch_io (stream, ffc->start, ffc->size, size + lines); | ||
1047 | mu_stream_destroy (&stream, NULL); | ||
1048 | |||
1049 | return status; | ||
1491 | } | 1050 | } |
1492 | 1051 | ||
1493 | /* Send parameter list for the bodystructure. */ | 1052 | |
1494 | static void | 1053 | static void |
1495 | send_parameter_list (const char *buffer) | 1054 | ffc_init (struct fetch_function_closure *ffc) |
1496 | { | 1055 | { |
1497 | int argc = 0; | 1056 | memset(ffc, 0, sizeof *ffc); |
1498 | char **argv; | 1057 | ffc->start = 0; |
1058 | ffc->size = (size_t) -1; | ||
1059 | } | ||
1499 | 1060 | ||
1500 | if (!buffer) | 1061 | static void |
1062 | _free_ffc (void *item) | ||
1063 | { | ||
1064 | struct fetch_function_closure *ffc = item; | ||
1065 | mu_list_destroy (&ffc->headers); | ||
1066 | free (ffc); | ||
1067 | } | ||
1068 | |||
1069 | static int | ||
1070 | _do_fetch (void *item, void *data) | ||
1071 | { | ||
1072 | struct fetch_function_closure *ffc = item; | ||
1073 | struct fetch_runtime_closure *frt = data; | ||
1074 | if (frt->eltno++) | ||
1075 | util_send (" "); | ||
1076 | return ffc->fun (ffc, frt); | ||
1077 | } | ||
1078 | |||
1079 | struct parsebuf | ||
1080 | { | ||
1081 | imap4d_tokbuf_t tok; | ||
1082 | int arg; | ||
1083 | char *token; | ||
1084 | int isuid; | ||
1085 | mu_list_t fnlist; | ||
1086 | jmp_buf errjmp; | ||
1087 | char *err_text; | ||
1088 | }; | ||
1089 | |||
1090 | static void | ||
1091 | parsebuf_exit (struct parsebuf *p, char *text) | ||
1092 | { | ||
1093 | p->err_text = text; | ||
1094 | longjmp (p->errjmp, 1); | ||
1095 | } | ||
1096 | |||
1097 | static char * | ||
1098 | parsebuf_peek (struct parsebuf *p) | ||
1099 | { | ||
1100 | return imap4d_tokbuf_getarg (p->tok, p->arg); | ||
1101 | } | ||
1102 | |||
1103 | static char * | ||
1104 | parsebuf_next (struct parsebuf *p, int req) | ||
1105 | { | ||
1106 | p->token = imap4d_tokbuf_getarg (p->tok, p->arg++); | ||
1107 | if (!p->token && req) | ||
1108 | parsebuf_exit (p, "Too few arguments"); | ||
1109 | return p->token; | ||
1110 | } | ||
1111 | |||
1112 | static void | ||
1113 | append_ffc (struct parsebuf *p, struct fetch_function_closure *ffc) | ||
1114 | { | ||
1115 | struct fetch_function_closure *new_ffc = malloc (sizeof (*new_ffc)); | ||
1116 | if (!new_ffc) | ||
1117 | imap4d_bye (ERR_NO_MEM); | ||
1118 | *new_ffc = *ffc; | ||
1119 | mu_list_append (p->fnlist, new_ffc); | ||
1120 | } | ||
1121 | |||
1122 | static void | ||
1123 | append_simple_function (struct parsebuf *p, const char *name, | ||
1124 | fetch_function_t fun) | ||
1125 | { | ||
1126 | struct fetch_function_closure ffc; | ||
1127 | ffc_init (&ffc); | ||
1128 | ffc.fun = fun; | ||
1129 | ffc.name = name; | ||
1130 | append_ffc (p, &ffc); | ||
1131 | } | ||
1132 | |||
1133 | |||
1134 | static struct fetch_macro | ||
1135 | { | ||
1136 | char *macro; | ||
1137 | char *exp; | ||
1138 | } fetch_macro_tab[] = { | ||
1139 | { "ALL", "FLAGS INTERNALDATE RFC822.SIZE ENVELOPE" }, | ||
1140 | { "FULL", "FLAGS INTERNALDATE RFC822.SIZE ENVELOPE BODY" }, | ||
1141 | { "FAST", "FLAGS INTERNALDATE RFC822.SIZE" }, | ||
1142 | { NULL } | ||
1143 | }; | ||
1144 | |||
1145 | static char * | ||
1146 | find_macro (const char *name) | ||
1147 | { | ||
1148 | int i; | ||
1149 | for (i = 0; fetch_macro_tab[i].macro; i++) | ||
1150 | if (strcasecmp (fetch_macro_tab[i].macro, name) == 0) | ||
1151 | return fetch_macro_tab[i].exp; | ||
1152 | return NULL; | ||
1153 | } | ||
1154 | |||
1155 | |||
1156 | struct fetch_att_tab | ||
1157 | { | ||
1158 | char *name; | ||
1159 | fetch_function_t fun; | ||
1160 | }; | ||
1161 | |||
1162 | static struct fetch_att_tab fetch_att_tab[] = { | ||
1163 | { "ENVELOPE", _frt_envelope }, | ||
1164 | { "FLAGS", _frt_flags }, | ||
1165 | { "INTERNALDATE", _frt_internaldate }, | ||
1166 | { "UID", _frt_uid }, | ||
1167 | { NULL } | ||
1168 | }; | ||
1169 | |||
1170 | static struct fetch_att_tab * | ||
1171 | find_fetch_att_tab (char *name) | ||
1172 | { | ||
1173 | struct fetch_att_tab *p; | ||
1174 | for (p = fetch_att_tab; p->name; p++) | ||
1175 | if (strcasecmp (p->name, name) == 0) | ||
1176 | return p; | ||
1177 | return NULL; | ||
1178 | } | ||
1179 | |||
1180 | /* | ||
1181 | fetch-att = "ENVELOPE" / "FLAGS" / "INTERNALDATE" / | ||
1182 | "RFC822" [".HEADER" / ".SIZE" / ".TEXT"] / | ||
1183 | "BODY" ["STRUCTURE"] / "UID" / | ||
1184 | "BODY" section ["<" number "." nz-number ">"] / | ||
1185 | "BODY.PEEK" section ["<" number "." nz-number ">"] | ||
1186 | |||
1187 | */ | ||
1188 | |||
1189 | /* "RFC822" [".HEADER" / ".SIZE" / ".TEXT"] */ | ||
1190 | static void | ||
1191 | parse_fetch_rfc822 (struct parsebuf *p) | ||
1192 | { | ||
1193 | struct fetch_function_closure ffc; | ||
1194 | ffc_init (&ffc); | ||
1195 | ffc.name = "RFC822"; | ||
1196 | parsebuf_next (p, 0); | ||
1197 | if (p->token == NULL || p->token[0] == ')') | ||
1501 | { | 1198 | { |
1502 | util_send ("NIL"); | 1199 | /* Equivalent to BODY[]. */ |
1503 | return; | 1200 | ffc.fun = _frt_body; |
1504 | } | 1201 | } |
1202 | else if (p->token[0] == '.') | ||
1203 | { | ||
1204 | parsebuf_next (p, 1); | ||
1205 | if (strcasecmp (p->token, "HEADER") == 0) | ||
1206 | { | ||
1207 | /* RFC822.HEADER | ||
1208 | Equivalent to BODY[HEADER]. Note that this did not result in | ||
1209 | \Seen being set, because RFC822.HEADER response data occurs as | ||
1210 | a result of a FETCH of RFC822.HEADER. BODY[HEADER] response | ||
1211 | data occurs as a result of a FETCH of BODY[HEADER] (which sets | ||
1212 | \Seen) or BODY.PEEK[HEADER] (which does not set \Seen). */ | ||
1505 | 1213 | ||
1506 | mu_argcv_get (buffer, " \t\r\n;=", NULL, &argc, &argv); | 1214 | ffc.name = "RFC822.HEADER"; |
1215 | ffc.fun = _frt_header; | ||
1216 | ffc.peek = 1; | ||
1217 | parsebuf_next (p, 0); | ||
1218 | } | ||
1219 | else if (strcasecmp (p->token, "SIZE") == 0) | ||
1220 | { | ||
1221 | /* A number expressing the [RFC-2822] size of the message. */ | ||
1222 | ffc.name = "RFC822.SIZE"; | ||
1223 | ffc.fun = _frt_size; | ||
1224 | parsebuf_next (p, 0); | ||
1225 | } | ||
1226 | else if (strcasecmp (p->token, "TEXT") == 0) | ||
1227 | { | ||
1228 | /* RFC822.TEXT | ||
1229 | Equivalent to BODY[TEXT]. */ | ||
1230 | ffc.name = "RFC822.TEXT"; | ||
1231 | ffc.fun = _frt_body_text; | ||
1232 | parsebuf_next (p, 0); | ||
1233 | } | ||
1234 | else | ||
1235 | parsebuf_exit (p, "Syntax error after RFC822."); | ||
1236 | } | ||
1237 | else | ||
1238 | parsebuf_exit (p, "Syntax error after RFC822"); | ||
1239 | append_ffc (p, &ffc); | ||
1240 | } | ||
1507 | 1241 | ||
1508 | if (argc == 0) | 1242 | static int |
1509 | util_send ("NIL"); | 1243 | _header_cmp (const void *a, const void *b) |
1244 | { | ||
1245 | return strcasecmp ((char*)a, (char*)b); | ||
1246 | } | ||
1247 | |||
1248 | /* | ||
1249 | header-fld-name = astring | ||
1250 | |||
1251 | header-list = "(" header-fld-name *(SP header-fld-name) ")" | ||
1252 | */ | ||
1253 | static void | ||
1254 | parse_header_list (struct parsebuf *p, struct fetch_function_closure *ffc) | ||
1255 | { | ||
1256 | if (p->token[0] != '(') | ||
1257 | parsebuf_exit (p, "Syntax error: expected ("); | ||
1258 | mu_list_create (&ffc->headers); | ||
1259 | mu_list_set_comparator (ffc->headers, _header_cmp); | ||
1260 | for (parsebuf_next (p, 1); p->token[0] != ')'; parsebuf_next (p, 1)) | ||
1261 | { | ||
1262 | if (util_isdelim (p->token)) | ||
1263 | parsebuf_exit (p, "Syntax error: unexpected delimiter"); | ||
1264 | mu_list_append (ffc->headers, p->token); | ||
1265 | } | ||
1266 | parsebuf_next (p, 1); | ||
1267 | } | ||
1268 | |||
1269 | /* | ||
1270 | section-msgtext = "HEADER" / "HEADER.FIELDS" [".NOT"] SP header-list / | ||
1271 | "TEXT" | ||
1272 | ; top-level or MESSAGE/RFC822 part | ||
1273 | section-text = section-msgtext / "MIME" | ||
1274 | ; text other than actual body part (headers, etc.) | ||
1275 | */ | ||
1276 | static int | ||
1277 | parse_section_text (struct parsebuf *p, struct fetch_function_closure *ffc, | ||
1278 | int allow_mime) | ||
1279 | { | ||
1280 | if (strcasecmp (p->token, "HEADER") == 0) | ||
1281 | { | ||
1282 | /* "HEADER" / "HEADER.FIELDS" [".NOT"] SP header-list */ | ||
1283 | parsebuf_next (p, 1); | ||
1284 | if (p->token[0] == '.') | ||
1285 | { | ||
1286 | parsebuf_next (p, 1); | ||
1287 | if (strcasecmp (p->token, "FIELDS")) | ||
1288 | parsebuf_exit (p, "Expected FIELDS"); | ||
1289 | ffc->fun = _frt_header_fields; | ||
1290 | parsebuf_next (p, 1); | ||
1291 | if (p->token[0] == '.') | ||
1292 | { | ||
1293 | parsebuf_next (p, 1); | ||
1294 | if (strcasecmp (p->token, "NOT") == 0) | ||
1295 | { | ||
1296 | ffc->not = 1; | ||
1297 | parsebuf_next (p, 1); | ||
1298 | } | ||
1299 | else | ||
1300 | parsebuf_exit (p, "Expected NOT"); | ||
1301 | } | ||
1302 | parse_header_list (p, ffc); | ||
1303 | } | ||
1510 | else | 1304 | else |
1305 | ffc->fun = _frt_header; | ||
1306 | } | ||
1307 | else if (strcasecmp (p->token, "TEXT") == 0) | ||
1511 | { | 1308 | { |
1512 | char *p; | 1309 | parsebuf_next (p, 1); |
1310 | ffc->fun = _frt_body_text; | ||
1311 | } | ||
1312 | else if (allow_mime && strcasecmp (p->token, "MIME") == 0) | ||
1313 | { | ||
1314 | parsebuf_next (p, 1); | ||
1315 | ffc->fun = _frt_mime; | ||
1316 | } | ||
1317 | else | ||
1318 | return 1; | ||
1319 | return 0; | ||
1320 | } | ||
1513 | 1321 | ||
1514 | util_send ("("); | 1322 | static size_t |
1323 | parsebuf_get_number (struct parsebuf *p) | ||
1324 | { | ||
1325 | char *cp; | ||
1326 | unsigned n = strtoul (p->token, &cp, 10); | ||
1515 | 1327 | ||
1516 | p = argv[0]; | 1328 | if (*cp) |
1517 | util_send_qstring (p); | 1329 | parsebuf_exit (p, "Syntax error: expected number"); |
1330 | return n; | ||
1331 | } | ||
1518 | 1332 | ||
1519 | if (argc > 1) | 1333 | /* |
1334 | section-part = nz-number *("." nz-number) | ||
1335 | ; body part nesting | ||
1336 | */ | ||
1337 | static void | ||
1338 | parse_section_part (struct parsebuf *p, struct fetch_function_closure *ffc) | ||
1339 | { | ||
1340 | size_t *parts; | ||
1341 | size_t nmax = 0; | ||
1342 | size_t ncur = 0; | ||
1343 | |||
1344 | for (;;) | ||
1520 | { | 1345 | { |
1521 | int i, space = 0; | 1346 | char *cp; |
1522 | char *lvalue = NULL; | 1347 | size_t n = parsebuf_get_number (p); |
1348 | if (ncur == nmax) | ||
1349 | { | ||
1350 | if (nmax == 0) | ||
1351 | { | ||
1352 | nmax = 16; | ||
1353 | parts = calloc (nmax, sizeof (parts[0])); | ||
1354 | } | ||
1355 | else | ||
1356 | { | ||
1357 | nmax *= 2; | ||
1358 | parts = realloc (parts, nmax * sizeof (parts[0])); | ||
1359 | } | ||
1360 | if (!parts) | ||
1361 | imap4d_bye (ERR_NO_MEM); | ||
1362 | } | ||
1363 | parts[ncur++] = n; | ||
1523 | 1364 | ||
1524 | util_send ("("); | 1365 | parsebuf_next (p, 1); |
1525 | for (i = 1; i < argc; i++) | 1366 | if (p->token[0] == '.' |
1367 | && (cp = parsebuf_peek (p)) && isascii (*cp) && isdigit (cp[0])) | ||
1368 | parsebuf_next (p, 1); | ||
1369 | else | ||
1370 | break; | ||
1371 | } | ||
1372 | ffc->section_part = parts; | ||
1373 | ffc->nset = ncur; | ||
1374 | } | ||
1375 | |||
1376 | /* | ||
1377 | section = "[" [section-spec] "]" | ||
1378 | section-spec = section-msgtext / (section-part ["." section-text]) | ||
1379 | */ | ||
1380 | static int | ||
1381 | parse_section (struct parsebuf *p, struct fetch_function_closure *ffc) | ||
1382 | { | ||
1383 | if (p->token[0] != '[') | ||
1384 | return 1; | ||
1385 | ffc_init (ffc); | ||
1386 | ffc->name = NULL; | ||
1387 | ffc->fun = _frt_body; | ||
1388 | parsebuf_next (p, 1); | ||
1389 | if (parse_section_text (p, ffc, 0)) | ||
1526 | { | 1390 | { |
1527 | if (lvalue) | 1391 | if (p->token[0] == ']') |
1392 | /* OK */; | ||
1393 | else if (isascii (p->token[0]) && isdigit (p->token[0])) | ||
1528 | { | 1394 | { |
1529 | if (space) | 1395 | parse_section_part (p, ffc); |
1530 | util_send (" "); | 1396 | if (p->token[0] == '.') |
1531 | util_send_qstring (lvalue); | 1397 | { |
1532 | lvalue = NULL; | 1398 | parsebuf_next (p, 1); |
1533 | space = 1; | 1399 | parse_section_text (p, ffc, 1); |
1400 | } | ||
1534 | } | 1401 | } |
1402 | else | ||
1403 | parsebuf_exit (p, "Syntax error"); | ||
1404 | } | ||
1405 | if (p->token[0] != ']') | ||
1406 | parsebuf_exit (p, "Syntax error: missing ]"); | ||
1407 | parsebuf_next (p, 0); | ||
1408 | return 0; | ||
1409 | } | ||
1535 | 1410 | ||
1536 | switch (argv[i][0]) | 1411 | static void |
1412 | parse_substring (struct parsebuf *p, struct fetch_function_closure *ffc) | ||
1413 | { | ||
1414 | if (p->token && p->token[0] == '<') | ||
1415 | { | ||
1416 | parsebuf_next (p, 1); | ||
1417 | ffc->start = parsebuf_get_number (p); | ||
1418 | parsebuf_next (p, 1); | ||
1419 | if (p->token[0] != '.') | ||
1420 | parsebuf_exit (p, "Syntax error: expected ."); | ||
1421 | parsebuf_next (p, 1); | ||
1422 | ffc->size = parsebuf_get_number (p); | ||
1423 | parsebuf_next (p, 1); | ||
1424 | if (p->token[0] != '>') | ||
1425 | parsebuf_exit (p, "Syntax error: expected >"); | ||
1426 | parsebuf_next (p, 0); | ||
1427 | } | ||
1428 | } | ||
1429 | |||
1430 | /* section ["<" number "." nz-number ">"] */ | ||
1431 | static int | ||
1432 | parse_body_args (struct parsebuf *p, int peek) | ||
1433 | { | ||
1434 | struct fetch_function_closure ffc; | ||
1435 | if (parse_section (p, &ffc) == 0) | ||
1537 | { | 1436 | { |
1538 | case ';': | 1437 | parse_substring (p, &ffc); |
1539 | continue; | 1438 | ffc.peek = peek; |
1439 | append_ffc (p, &ffc); | ||
1440 | return 0; | ||
1441 | } | ||
1442 | return 1; | ||
1443 | } | ||
1540 | 1444 | ||
1541 | case '=': | 1445 | static void |
1542 | if (++i < argc) | 1446 | parse_body_peek (struct parsebuf *p) |
1447 | { | ||
1448 | parsebuf_next (p, 1); | ||
1449 | if (strcasecmp (p->token, "PEEK") == 0) | ||
1543 | { | 1450 | { |
1544 | char *p = argv[i]; | 1451 | parsebuf_next (p, 1); |
1545 | util_send (" "); | 1452 | if (parse_body_args (p, 1)) |
1546 | util_unquote (&p); | 1453 | parsebuf_exit (p, "Syntax error"); |
1547 | util_send_qstring (p); | ||
1548 | } | 1454 | } |
1549 | break; | 1455 | else |
1456 | parsebuf_exit (p, "Syntax error: expected PEEK"); | ||
1457 | } | ||
1550 | 1458 | ||
1551 | default: | 1459 | /* "BODY" ["STRUCTURE"] / |
1552 | lvalue = argv[i]; | 1460 | "BODY" section ["<" number "." nz-number ">"] / |
1461 | "BODY.PEEK" section ["<" number "." nz-number ">"] */ | ||
1462 | static void | ||
1463 | parse_fetch_body (struct parsebuf *p) | ||
1464 | { | ||
1465 | if (parsebuf_next (p, 0) == NULL || p->token[0] == ')') | ||
1466 | append_simple_function (p, "BODY", _frt_bodystructure0); | ||
1467 | else if (p->token[0] == '.') | ||
1468 | parse_body_peek (p); | ||
1469 | else if (strcasecmp (p->token, "STRUCTURE") == 0) | ||
1470 | { | ||
1471 | /* For compatibility with previous versions */ | ||
1472 | append_simple_function (p, "BODYSTRUCTURE", _frt_bodystructure); | ||
1473 | parsebuf_next (p, 0); | ||
1474 | } | ||
1475 | else if (parse_body_args (p, 0)) | ||
1476 | parsebuf_exit (p, "Syntax error"); | ||
1477 | } | ||
1478 | |||
1479 | static int | ||
1480 | parse_fetch_att (struct parsebuf *p) | ||
1481 | { | ||
1482 | struct fetch_att_tab *ent; | ||
1483 | |||
1484 | ent = find_fetch_att_tab (p->token); | ||
1485 | if (ent) | ||
1486 | { | ||
1487 | if (!(ent->fun == _frt_uid && p->isuid)) | ||
1488 | append_simple_function (p, ent->name, ent->fun); | ||
1489 | parsebuf_next (p, 0); | ||
1553 | } | 1490 | } |
1491 | else if (strcasecmp (p->token, "RFC822") == 0) | ||
1492 | parse_fetch_rfc822 (p); | ||
1493 | else if (strcasecmp (p->token, "BODY") == 0) | ||
1494 | parse_fetch_body (p); | ||
1495 | else if (strcasecmp (p->token, "BODYSTRUCTURE") == 0) | ||
1496 | { | ||
1497 | append_simple_function (p, "BODYSTRUCTURE", _frt_bodystructure); | ||
1498 | parsebuf_next (p, 0); | ||
1554 | } | 1499 | } |
1555 | if (lvalue) | 1500 | else |
1501 | return 1; | ||
1502 | return 0; | ||
1503 | } | ||
1504 | |||
1505 | /* fetch-att *(SP fetch-att) */ | ||
1506 | static void | ||
1507 | parse_fetch_att_list (struct parsebuf *p) | ||
1508 | { | ||
1509 | while (p->token && parse_fetch_att (p) == 0) | ||
1510 | ; | ||
1511 | } | ||
1512 | |||
1513 | /* "ALL" / "FULL" / "FAST" / fetch-att / "(" */ | ||
1514 | static void | ||
1515 | parse_macro (struct parsebuf *p) | ||
1516 | { | ||
1517 | char *exp; | ||
1518 | |||
1519 | parsebuf_next (p, 1); | ||
1520 | if (p->token[0] == '(') | ||
1556 | { | 1521 | { |
1557 | if (space) | 1522 | parsebuf_next (p, 1); |
1558 | util_send (" "); | 1523 | parse_fetch_att_list (p); |
1559 | util_send_qstring (lvalue); | 1524 | if (p->token[0] != ')') |
1525 | parsebuf_exit (p, "Missing closing parenthesis"); | ||
1560 | } | 1526 | } |
1561 | util_send (")"); | 1527 | else if ((exp = find_macro (p->token))) |
1528 | { | ||
1529 | imap4d_tokbuf_t save_tok = p->tok; | ||
1530 | int save_arg = p->arg; | ||
1531 | p->tok = imap4d_tokbuf_from_string (exp); | ||
1532 | p->arg = 0; | ||
1533 | parsebuf_next (p, 1); | ||
1534 | parse_fetch_att_list (p); | ||
1535 | imap4d_tokbuf_destroy (&p->tok); | ||
1536 | |||
1537 | p->arg = save_arg; | ||
1538 | p->tok = save_tok; | ||
1539 | |||
1540 | if (parsebuf_peek (p)) | ||
1541 | parsebuf_exit (p, "Too many arguments"); | ||
1562 | } | 1542 | } |
1563 | else | 1543 | else |
1564 | util_send (" NIL"); | 1544 | { |
1565 | util_send (")"); | 1545 | parse_fetch_att (p); |
1546 | if (p->token) | ||
1547 | parsebuf_exit (p, "Too many arguments"); | ||
1566 | } | 1548 | } |
1567 | mu_argcv_free (argc, argv); | ||
1568 | } | 1549 | } |
1569 | 1550 | ||
1551 | /* Where the real implementation is. It is here since UID command also | ||
1552 | calls FETCH. */ | ||
1553 | int | ||
1554 | imap4d_fetch0 (imap4d_tokbuf_t tok, int isuid, char **err_text) | ||
1555 | { | ||
1556 | int rc = RESP_OK; | ||
1557 | char *msgset; | ||
1558 | size_t *set = NULL; | ||
1559 | int n = 0; | ||
1560 | int i; | ||
1561 | int status; | ||
1562 | struct fetch_runtime_closure frc; | ||
1563 | struct parsebuf pb; | ||
1564 | |||
1565 | if (imap4d_tokbuf_argc (tok) - (IMAP4_ARG_1 + isuid) < 2) | ||
1566 | { | ||
1567 | *err_text = "Invalid arguments"; | ||
1568 | return 1; | ||
1569 | } | ||
1570 | |||
1571 | pb.tok = tok; | ||
1572 | pb.arg = IMAP4_ARG_1 + isuid; | ||
1573 | pb.isuid = isuid; | ||
1574 | pb.err_text = "Syntax error"; | ||
1575 | mu_list_create (&pb.fnlist); | ||
1576 | mu_list_set_destroy_item (pb.fnlist, _free_ffc); | ||
1577 | if (setjmp (pb.errjmp)) | ||
1578 | { | ||
1579 | *err_text = pb.err_text; | ||
1580 | mu_list_destroy (&pb.fnlist); | ||
1581 | return RESP_BAD; | ||
1582 | } | ||
1583 | |||
1584 | msgset = parsebuf_next (&pb, 1); | ||
1585 | |||
1586 | /* Get the message numbers in set[]. */ | ||
1587 | status = util_msgset (msgset, &set, &n, isuid); | ||
1588 | if (status != 0) | ||
1589 | { | ||
1590 | *err_text = "Bogus number set"; | ||
1591 | return RESP_BAD; | ||
1592 | } | ||
1593 | |||
1594 | /* Compile the expression */ | ||
1595 | |||
1596 | /* Server implementations MUST implicitly | ||
1597 | include the UID message data item as part of any FETCH | ||
1598 | response caused by a UID command, regardless of whether | ||
1599 | a UID was specified as a message data item to the FETCH. */ | ||
1600 | if (isuid) | ||
1601 | append_simple_function (&pb, "UID", _frt_uid); | ||
1602 | |||
1603 | parse_macro (&pb); | ||
1604 | |||
1605 | /* Prepare status code. It will be replaced if an error occurs in the | ||
1606 | loop below */ | ||
1607 | frc.err_text = "Completed"; | ||
1608 | |||
1609 | for (i = 0; i < n && rc == RESP_OK; i++) | ||
1610 | { | ||
1611 | frc.msgno = (isuid) ? uid_to_msgno (set[i]) : set[i]; | ||
1612 | |||
1613 | if (frc.msgno && mu_mailbox_get_message (mbox, frc.msgno, &frc.msg) == 0) | ||
1614 | { | ||
1615 | util_send ("* %lu FETCH (", (unsigned long) frc.msgno); | ||
1616 | frc.eltno = 0; | ||
1617 | rc = mu_list_do (pb.fnlist, _do_fetch, &frc); | ||
1618 | util_send (")\r\n"); | ||
1619 | } | ||
1620 | } | ||
1621 | |||
1622 | mu_list_destroy (&pb.fnlist); | ||
1623 | free (set); | ||
1624 | return rc; | ||
1625 | } | ||
1626 | |||
1627 | /* | ||
1628 | 6.4.5. FETCH Command | ||
1629 | |||
1630 | Arguments: message set | ||
1631 | message data item names | ||
1632 | |||
1633 | Responses: untagged responses: FETCH | ||
1634 | |||
1635 | Result: OK - fetch completed | ||
1636 | NO - fetch error: can't fetch that data | ||
1637 | BAD - command unknown or arguments invalid | ||
1638 | */ | ||
1639 | |||
1640 | /* The FETCH command retrieves data associated with a message in the | ||
1641 | mailbox. The data items to be fetched can be either a single atom | ||
1642 | or a parenthesized list. */ | ||
1643 | int | ||
1644 | imap4d_fetch (struct imap4d_command *command, imap4d_tokbuf_t tok) | ||
1645 | { | ||
1646 | int rc; | ||
1647 | char *err_text = "Completed"; | ||
1648 | |||
1649 | rc = imap4d_fetch0 (tok, 0, &err_text); | ||
1650 | return util_finish (command, rc, "%s", err_text); | ||
1651 | } | ||
1570 | 1652 | ... | ... |
... | @@ -19,13 +19,12 @@ | ... | @@ -19,13 +19,12 @@ |
19 | #include "imap4d.h" | 19 | #include "imap4d.h" |
20 | 20 | ||
21 | int | 21 | int |
22 | imap4d_idle (struct imap4d_command *command, char *arg) | 22 | imap4d_idle (struct imap4d_command *command, imap4d_tokbuf_t tok) |
23 | { | 23 | { |
24 | char *sp; | ||
25 | time_t start; | 24 | time_t start; |
26 | 25 | ||
27 | if (util_getword (arg, &sp)) | 26 | if (imap4d_tokbuf_argc (tok) != 2) |
28 | return util_finish (command, RESP_BAD, "Too many args"); | 27 | return util_finish (command, RESP_BAD, "Invalid arguments"); |
29 | 28 | ||
30 | if (util_wait_input (0) == -1) | 29 | if (util_wait_input (0) == -1) |
31 | return util_finish (command, RESP_NO, "Cannot idle"); | 30 | return util_finish (command, RESP_NO, "Cannot idle"); |
... | @@ -38,15 +37,10 @@ imap4d_idle (struct imap4d_command *command, char *arg) | ... | @@ -38,15 +37,10 @@ imap4d_idle (struct imap4d_command *command, char *arg) |
38 | { | 37 | { |
39 | if (util_wait_input (5)) | 38 | if (util_wait_input (5)) |
40 | { | 39 | { |
41 | int rc; | 40 | imap4d_readline (tok); |
42 | char *p; | 41 | if (imap4d_tokbuf_argc (tok) == 1 |
43 | char *cmd = imap4d_readline (); | 42 | && strcasecmp (imap4d_tokbuf_getarg (tok, IMAP4_ARG_TAG), |
44 | 43 | "done") == 0) | |
45 | p = util_getword (cmd, &sp); | ||
46 | rc = strcasecmp (p, "done") == 0; | ||
47 | |||
48 | free (cmd); | ||
49 | if (rc) | ||
50 | break; | 44 | break; |
51 | } | 45 | } |
52 | else if (time (NULL) - start > idle_timeout) | 46 | else if (time (NULL) - start > idle_timeout) | ... | ... |
... | @@ -370,6 +370,7 @@ get_client_address (int fd, struct sockaddr_in *pcs) | ... | @@ -370,6 +370,7 @@ get_client_address (int fd, struct sockaddr_in *pcs) |
370 | static int | 370 | static int |
371 | imap4d_mainloop (int fd, FILE *infile, FILE *outfile) | 371 | imap4d_mainloop (int fd, FILE *infile, FILE *outfile) |
372 | { | 372 | { |
373 | imap4d_tokbuf_t tokp; | ||
373 | char *text; | 374 | char *text; |
374 | int debug_mode = isatty (fd); | 375 | int debug_mode = isatty (fd); |
375 | static int sigtab[] = { SIGILL, SIGBUS, SIGFPE, SIGSEGV, SIGSTOP, SIGPIPE, | 376 | static int sigtab[] = { SIGILL, SIGBUS, SIGFPE, SIGSEGV, SIGSTOP, SIGPIPE, |
... | @@ -400,14 +401,14 @@ imap4d_mainloop (int fd, FILE *infile, FILE *outfile) | ... | @@ -400,14 +401,14 @@ imap4d_mainloop (int fd, FILE *infile, FILE *outfile) |
400 | util_out ((state == STATE_AUTH) ? RESP_PREAUTH : RESP_OK, "%s", text); | 401 | util_out ((state == STATE_AUTH) ? RESP_PREAUTH : RESP_OK, "%s", text); |
401 | util_flush_output (); | 402 | util_flush_output (); |
402 | 403 | ||
404 | tokp = imap4d_tokbuf_init (); | ||
403 | while (1) | 405 | while (1) |
404 | { | 406 | { |
405 | char *cmd = imap4d_readline (); | 407 | imap4d_readline (tokp); |
406 | /* check for updates */ | 408 | /* check for updates */ |
407 | imap4d_sync (); | 409 | imap4d_sync (); |
408 | util_do_command (cmd); | 410 | util_do_command (tokp); |
409 | imap4d_sync (); | 411 | imap4d_sync (); |
410 | free (cmd); | ||
411 | util_flush_output (); | 412 | util_flush_output (); |
412 | } | 413 | } |
413 | 414 | ... | ... |
... | @@ -41,6 +41,7 @@ | ... | @@ -41,6 +41,7 @@ |
41 | #include <stdlib.h> | 41 | #include <stdlib.h> |
42 | #include <unistd.h> | 42 | #include <unistd.h> |
43 | #include <string.h> | 43 | #include <string.h> |
44 | #include <setjmp.h> | ||
44 | #include <sys/wait.h> | 45 | #include <sys/wait.h> |
45 | #include <sys/types.h> | 46 | #include <sys/types.h> |
46 | #include <syslog.h> | 47 | #include <syslog.h> |
... | @@ -108,10 +109,12 @@ | ... | @@ -108,10 +109,12 @@ |
108 | extern "C" { | 109 | extern "C" { |
109 | #endif | 110 | #endif |
110 | 111 | ||
112 | typedef struct imap4d_tokbuf *imap4d_tokbuf_t; | ||
113 | |||
111 | struct imap4d_command | 114 | struct imap4d_command |
112 | { | 115 | { |
113 | const char *name; | 116 | const char *name; |
114 | int (*func) (struct imap4d_command *, char *); | 117 | int (*func) (struct imap4d_command *, imap4d_tokbuf_t); |
115 | int states; | 118 | int states; |
116 | int failure; | 119 | int failure; |
117 | int success; | 120 | int success; |
... | @@ -192,47 +195,62 @@ extern int imap4d_transcript; | ... | @@ -192,47 +195,62 @@ extern int imap4d_transcript; |
192 | extern char *strtok_r (char *s, const char *delim, char **save_ptr); | 195 | extern char *strtok_r (char *s, const char *delim, char **save_ptr); |
193 | #endif | 196 | #endif |
194 | 197 | ||
195 | /* Imap4 commands */ | 198 | /* Input functions */ |
196 | extern int imap4d_append (struct imap4d_command *, char *); | 199 | imap4d_tokbuf_t imap4d_tokbuf_init (void); |
197 | extern int imap4d_append0 (mu_mailbox_t mbox, int flags, char *text); | 200 | void imap4d_tokbuf_destroy (imap4d_tokbuf_t *tok); |
198 | extern int imap4d_authenticate (struct imap4d_command *, char *); | 201 | int imap4d_tokbuf_argc (imap4d_tokbuf_t tok); |
202 | char *imap4d_tokbuf_getarg (imap4d_tokbuf_t tok, int n); | ||
203 | void imap4d_readline (imap4d_tokbuf_t tok); | ||
204 | struct imap4d_tokbuf *imap4d_tokbuf_from_string (char *str); | ||
205 | int imap4d_getline (char **pbuf, size_t *psize, size_t *pnbytes); | ||
206 | |||
207 | #define IMAP4_ARG_TAG 0 | ||
208 | #define IMAP4_ARG_COMMAND 1 | ||
209 | #define IMAP4_ARG_1 2 | ||
210 | #define IMAP4_ARG_2 3 | ||
211 | #define IMAP4_ARG_3 4 | ||
212 | #define IMAP4_ARG_4 5 | ||
213 | |||
214 | /* Imap4 commands */ | ||
215 | extern int imap4d_append (struct imap4d_command *, imap4d_tokbuf_t); | ||
216 | extern int imap4d_authenticate (struct imap4d_command *, imap4d_tokbuf_t); | ||
199 | extern void imap4d_auth_capability (void); | 217 | extern void imap4d_auth_capability (void); |
200 | extern int imap4d_capability (struct imap4d_command *, char *); | 218 | extern int imap4d_capability (struct imap4d_command *, imap4d_tokbuf_t); |
201 | extern int imap4d_check (struct imap4d_command *, char *); | 219 | extern int imap4d_check (struct imap4d_command *, imap4d_tokbuf_t); |
202 | extern int imap4d_close (struct imap4d_command *, char *); | 220 | extern int imap4d_close (struct imap4d_command *, imap4d_tokbuf_t); |
203 | extern int imap4d_copy (struct imap4d_command *, char *); | 221 | extern int imap4d_copy (struct imap4d_command *, imap4d_tokbuf_t); |
204 | extern int imap4d_copy0 (char *, int, char *, size_t); | 222 | extern int imap4d_copy0 (imap4d_tokbuf_t, int isuid, char **err_text); |
205 | extern int imap4d_create (struct imap4d_command *, char *); | 223 | extern int imap4d_create (struct imap4d_command *, imap4d_tokbuf_t); |
206 | extern int imap4d_delete (struct imap4d_command *, char *); | 224 | extern int imap4d_delete (struct imap4d_command *, imap4d_tokbuf_t); |
207 | extern int imap4d_examine (struct imap4d_command *, char *); | 225 | extern int imap4d_examine (struct imap4d_command *, imap4d_tokbuf_t); |
208 | extern int imap4d_expunge (struct imap4d_command *, char *); | 226 | extern int imap4d_expunge (struct imap4d_command *, imap4d_tokbuf_t); |
209 | extern int imap4d_fetch (struct imap4d_command *, char *); | 227 | extern int imap4d_fetch (struct imap4d_command *, imap4d_tokbuf_t); |
210 | extern int imap4d_fetch0 (char *, int, char *, size_t); | 228 | extern int imap4d_fetch0 (imap4d_tokbuf_t tok, int isuid, char **err_text); |
211 | extern int imap4d_list (struct imap4d_command *, char *); | 229 | extern int imap4d_list (struct imap4d_command *, imap4d_tokbuf_t); |
212 | extern int imap4d_lsub (struct imap4d_command *, char *); | 230 | extern int imap4d_lsub (struct imap4d_command *, imap4d_tokbuf_t); |
213 | extern int imap4d_login (struct imap4d_command *, char *); | 231 | extern int imap4d_login (struct imap4d_command *, imap4d_tokbuf_t); |
214 | extern int imap4d_logout (struct imap4d_command *, char *); | 232 | extern int imap4d_logout (struct imap4d_command *, imap4d_tokbuf_t); |
215 | extern int imap4d_noop (struct imap4d_command *, char *); | 233 | extern int imap4d_noop (struct imap4d_command *, imap4d_tokbuf_t); |
216 | extern int imap4d_rename (struct imap4d_command *, char *); | 234 | extern int imap4d_rename (struct imap4d_command *, imap4d_tokbuf_t); |
217 | extern int imap4d_preauth_setup (int fd); | 235 | extern int imap4d_preauth_setup (int fd); |
218 | extern int imap4d_search (struct imap4d_command *, char *); | 236 | extern int imap4d_search (struct imap4d_command *, imap4d_tokbuf_t); |
219 | extern int imap4d_search0 (char *arg, int isuid, char *replybuf, size_t replysize); | 237 | extern int imap4d_search0 (imap4d_tokbuf_t, int isuid, char **repyptr); |
220 | extern int imap4d_select (struct imap4d_command *, char *); | 238 | extern int imap4d_select (struct imap4d_command *, imap4d_tokbuf_t); |
221 | extern int imap4d_select0 (struct imap4d_command *, char *, int); | 239 | extern int imap4d_select0 (struct imap4d_command *, char *, int); |
222 | extern int imap4d_select_status (void); | 240 | extern int imap4d_select_status (void); |
223 | #ifdef WITH_TLS | 241 | #ifdef WITH_TLS |
224 | extern int imap4d_starttls (struct imap4d_command *, char *); | 242 | extern int imap4d_starttls (struct imap4d_command *, imap4d_tokbuf_t); |
225 | extern void starttls_init (void); | 243 | extern void starttls_init (void); |
226 | #endif /* WITH_TLS */ | 244 | #endif /* WITH_TLS */ |
227 | extern int imap4d_status (struct imap4d_command *, char *); | 245 | extern int imap4d_status (struct imap4d_command *, imap4d_tokbuf_t); |
228 | extern int imap4d_store (struct imap4d_command *, char *); | 246 | extern int imap4d_store (struct imap4d_command *, imap4d_tokbuf_t); |
229 | extern int imap4d_store0 (char *, int, char *, size_t); | 247 | extern int imap4d_store0 (imap4d_tokbuf_t, int, char **); |
230 | extern int imap4d_subscribe (struct imap4d_command *, char *); | 248 | extern int imap4d_subscribe (struct imap4d_command *, imap4d_tokbuf_t); |
231 | extern int imap4d_uid (struct imap4d_command *, char *); | 249 | extern int imap4d_uid (struct imap4d_command *, imap4d_tokbuf_t); |
232 | extern int imap4d_unsubscribe (struct imap4d_command *, char *); | 250 | extern int imap4d_unsubscribe (struct imap4d_command *, imap4d_tokbuf_t); |
233 | extern int imap4d_namespace (struct imap4d_command *, char *); | 251 | extern int imap4d_namespace (struct imap4d_command *, imap4d_tokbuf_t); |
234 | extern int imap4d_version (struct imap4d_command *, char *); | 252 | extern int imap4d_version (struct imap4d_command *, imap4d_tokbuf_t); |
235 | extern int imap4d_idle (struct imap4d_command *, char *); | 253 | extern int imap4d_idle (struct imap4d_command *, imap4d_tokbuf_t); |
236 | 254 | ||
237 | extern int imap4d_check_home_dir (const char *dir, uid_t uid, gid_t gid); | 255 | extern int imap4d_check_home_dir (const char *dir, uid_t uid, gid_t gid); |
238 | 256 | ||
... | @@ -274,25 +292,17 @@ extern int util_start (char *); | ... | @@ -274,25 +292,17 @@ extern int util_start (char *); |
274 | extern int util_finish (struct imap4d_command *, int, const char *, ...) | 292 | extern int util_finish (struct imap4d_command *, int, const char *, ...) |
275 | MU_PRINTFLIKE(3,4); | 293 | MU_PRINTFLIKE(3,4); |
276 | extern int util_getstate (void); | 294 | extern int util_getstate (void); |
277 | extern int util_do_command (char *); | 295 | extern int util_do_command (imap4d_tokbuf_t); |
278 | extern char *imap4d_readline (void); | ||
279 | extern char *imap4d_readline_ex (void); | ||
280 | extern char *util_getword (char *, char **); | ||
281 | extern char *util_getitem (char *, const char *, char **); | ||
282 | extern int util_token (char *, size_t, char **); | ||
283 | extern void util_unquote (char **); | ||
284 | extern char *util_tilde_expansion (const char *, const char *); | 296 | extern char *util_tilde_expansion (const char *, const char *); |
285 | extern char *util_getfullpath (char *, const char *); | 297 | extern char *util_getfullpath (char *, const char *); |
286 | extern int util_msgset (char *, size_t **, int *, int); | 298 | extern int util_msgset (char *, size_t **, int *, int); |
287 | extern int util_upper (char *); | 299 | extern int util_upper (char *); |
288 | extern struct imap4d_command *util_getcommand (char *, | 300 | extern struct imap4d_command *util_getcommand (char *, |
289 | struct imap4d_command []); | 301 | struct imap4d_command []); |
290 | extern int util_parse_internal_date0 (char *date, time_t *timep, char **endp); | ||
291 | extern int util_parse_internal_date (char *date, time_t *timep); | 302 | extern int util_parse_internal_date (char *date, time_t *timep); |
292 | extern int util_parse_822_date (const char *date, time_t *timep); | 303 | extern int util_parse_822_date (const char *date, time_t *timep); |
293 | extern int util_parse_ctime_date (const char *date, time_t *timep); | 304 | extern int util_parse_ctime_date (const char *date, time_t *timep); |
294 | extern char *util_strcasestr (const char *haystack, const char *needle); | 305 | extern char *util_strcasestr (const char *haystack, const char *needle); |
295 | extern int util_parse_attributes (char *items, char **save, int *flags); | ||
296 | 306 | ||
297 | extern int util_base64_encode (const unsigned char *input, | 307 | extern int util_base64_encode (const unsigned char *input, |
298 | size_t input_len, | 308 | size_t input_len, |
... | @@ -330,6 +340,7 @@ void util_bye (void); | ... | @@ -330,6 +340,7 @@ void util_bye (void); |
330 | void util_atexit (void (*fp) (void)); | 340 | void util_atexit (void (*fp) (void)); |
331 | void util_chdir (const char *homedir); | 341 | void util_chdir (const char *homedir); |
332 | int is_atom (const char *s); | 342 | int is_atom (const char *s); |
343 | int util_isdelim (const char *str); | ||
333 | 344 | ||
334 | #ifdef WITH_TLS | 345 | #ifdef WITH_TLS |
335 | int imap4d_init_tls_server (void); | 346 | int imap4d_init_tls_server (void); | ... | ... |
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | 1 | /* GNU Mailutils -- a suite of utilities for electronic mail |
2 | Copyright (C) 1999, 2001, 2002, 2005, 2006, | 2 | Copyright (C) 1999, 2001, 2002, 2005, 2006, |
3 | 2007 Free Software Foundation, Inc. | 3 | 2007, 2008 Free Software Foundation, Inc. |
4 | 4 | ||
5 | GNU Mailutils is free software; you can redistribute it and/or modify | 5 | GNU Mailutils is free software; you can redistribute it and/or modify |
6 | it under the terms of the GNU General Public License as published by | 6 | it under the terms of the GNU General Public License as published by |
... | @@ -106,6 +106,19 @@ list_fun (mu_folder_t folder, struct mu_list_response *resp, void *data) | ... | @@ -106,6 +106,19 @@ list_fun (mu_folder_t folder, struct mu_list_response *resp, void *data) |
106 | } | 106 | } |
107 | 107 | ||
108 | /* | 108 | /* |
109 | 6.3.8. LIST Command | ||
110 | |||
111 | Arguments: reference name | ||
112 | mailbox name with possible wildcards | ||
113 | |||
114 | Responses: untagged responses: LIST | ||
115 | |||
116 | Result: OK - list completed | ||
117 | NO - list failure: can't list that reference or name | ||
118 | BAD - command unknown or arguments invalid | ||
119 | */ | ||
120 | |||
121 | /* | ||
109 | 1- IMAP4 insists: the reference argument present in the | 122 | 1- IMAP4 insists: the reference argument present in the |
110 | interpreted form SHOULD prefix the interpreted form. It SHOULD | 123 | interpreted form SHOULD prefix the interpreted form. It SHOULD |
111 | also be in the same form as the reference name argument. This | 124 | also be in the same form as the reference name argument. This |
... | @@ -126,21 +139,17 @@ list_fun (mu_folder_t folder, struct mu_list_response *resp, void *data) | ... | @@ -126,21 +139,17 @@ list_fun (mu_folder_t folder, struct mu_list_response *resp, void *data) |
126 | but it does not match the hierarchy delimiter. */ | 139 | but it does not match the hierarchy delimiter. */ |
127 | 140 | ||
128 | int | 141 | int |
129 | imap4d_list (struct imap4d_command *command, char *arg) | 142 | imap4d_list (struct imap4d_command *command, imap4d_tokbuf_t tok) |
130 | { | 143 | { |
131 | char *sp = NULL; | ||
132 | char *ref; | 144 | char *ref; |
133 | char *wcard; | 145 | char *wcard; |
134 | const char *delim = "/"; | 146 | const char *delim = "/"; |
135 | 147 | ||
136 | ref = util_getword (arg, &sp); | 148 | if (imap4d_tokbuf_argc (tok) != 4) |
137 | wcard = util_getword (NULL, &sp); | 149 | return util_finish (command, RESP_BAD, "Invalid arguments"); |
138 | if (!ref || !wcard) | ||
139 | return util_finish (command, RESP_BAD, "Too few arguments"); | ||
140 | 150 | ||
141 | /* Remove the double quotes. */ | 151 | ref = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1); |
142 | util_unquote (&ref); | 152 | wcard = imap4d_tokbuf_getarg (tok, IMAP4_ARG_2); |
143 | util_unquote (&wcard); | ||
144 | 153 | ||
145 | /* If wildcard is empty, it is a special case: we have to | 154 | /* If wildcard is empty, it is a special case: we have to |
146 | return the hierarchy. */ | 155 | return the hierarchy. */ | ... | ... |
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | 1 | /* GNU Mailutils -- a suite of utilities for electronic mail |
2 | Copyright (C) 1999, 2001, 2002, 2006, | 2 | Copyright (C) 1999, 2001, 2002, 2006, |
3 | 2007 Free Software Foundation, Inc. | 3 | 2007, 2008 Free Software Foundation, Inc. |
4 | 4 | ||
5 | GNU Mailutils is free software; you can redistribute it and/or modify | 5 | GNU Mailutils is free software; you can redistribute it and/or modify |
6 | it under the terms of the GNU General Public License as published by | 6 | it under the terms of the GNU General Public License as published by |
... | @@ -19,26 +19,32 @@ | ... | @@ -19,26 +19,32 @@ |
19 | 19 | ||
20 | #include "imap4d.h" | 20 | #include "imap4d.h" |
21 | 21 | ||
22 | /* | ||
23 | 6.2.2. LOGIN Command | ||
24 | |||
25 | Arguments: user name | ||
26 | password | ||
27 | |||
28 | Responses: no specific responses for this command | ||
29 | |||
30 | Result: OK - login completed, now in authenticated state | ||
31 | NO - login failure: user name or password rejected | ||
32 | BAD - command unknown or arguments invalid | ||
33 | */ | ||
22 | int | 34 | int |
23 | imap4d_login (struct imap4d_command *command, char *arg) | 35 | imap4d_login (struct imap4d_command *command, imap4d_tokbuf_t tok) |
24 | { | 36 | { |
25 | char *sp = NULL, *username, *pass; | 37 | char *username, *pass; |
26 | int rc; | 38 | int rc; |
27 | 39 | ||
28 | if (login_disabled || tls_required) | 40 | if (login_disabled || tls_required) |
29 | return util_finish (command, RESP_NO, "Command disabled"); | 41 | return util_finish (command, RESP_NO, "Command disabled"); |
30 | 42 | ||
31 | username = util_getword (arg, &sp); | 43 | if (imap4d_tokbuf_argc (tok) != 4) |
32 | pass = util_getword (NULL, &sp); | 44 | return util_finish (command, RESP_BAD, "Invalid arguments"); |
33 | |||
34 | /* Remove the double quotes. */ | ||
35 | util_unquote (&username); | ||
36 | util_unquote (&pass); | ||
37 | 45 | ||
38 | if (username == NULL || *username == '\0' || pass == NULL) | 46 | username = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1); |
39 | return util_finish (command, RESP_NO, "Too few args"); | 47 | pass = imap4d_tokbuf_getarg (tok, IMAP4_ARG_2); |
40 | else if (util_getword (NULL, &sp)) | ||
41 | return util_finish (command, RESP_NO, "Too many args"); | ||
42 | 48 | ||
43 | auth_data = mu_get_auth_by_name (username); | 49 | auth_data = mu_get_auth_by_name (username); |
44 | 50 | ... | ... |
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | 1 | /* GNU Mailutils -- a suite of utilities for electronic mail |
2 | Copyright (C) 1999, 2001, 2007 Free Software Foundation, Inc. | 2 | Copyright (C) 1999, 2001, 2007, 2008 Free Software Foundation, Inc. |
3 | 3 | ||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | 4 | GNU Mailutils is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU General Public License as published by | 5 | it under the terms of the GNU General Public License as published by |
... | @@ -19,15 +19,21 @@ | ... | @@ -19,15 +19,21 @@ |
19 | #include "imap4d.h" | 19 | #include "imap4d.h" |
20 | 20 | ||
21 | /* | 21 | /* |
22 | * This needs to properly close the mailbox | 22 | 6.1.3. LOGOUT Command |
23 | */ | 23 | |
24 | Arguments: none | ||
25 | |||
26 | Responses: REQUIRED untagged response: BYE | ||
27 | |||
28 | Result: OK - logout completed | ||
29 | BAD - command unknown or arguments invalid | ||
30 | */ | ||
24 | 31 | ||
25 | int | 32 | int |
26 | imap4d_logout (struct imap4d_command *command, char *arg) | 33 | imap4d_logout (struct imap4d_command *command, imap4d_tokbuf_t tok) |
27 | { | 34 | { |
28 | char *sp = NULL; | 35 | if (imap4d_tokbuf_argc (tok) != 2) |
29 | if (util_getword (arg, &sp)) | 36 | return util_finish (command, RESP_BAD, "Invalid arguments"); |
30 | return util_finish (command, RESP_BAD, "Too many args"); | ||
31 | imap4d_bye0 (OK, command); | 37 | imap4d_bye0 (OK, command); |
32 | return 0; | 38 | return 0; |
33 | } | 39 | } | ... | ... |
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | 1 | /* GNU Mailutils -- a suite of utilities for electronic mail |
2 | Copyright (C) 1999, 2001, 2007 Free Software Foundation, Inc. | 2 | Copyright (C) 1999, 2001, 2007, 2008 Free Software Foundation, Inc. |
3 | 3 | ||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | 4 | GNU Mailutils is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU General Public License as published by | 5 | it under the terms of the GNU General Public License as published by |
... | @@ -19,13 +19,20 @@ | ... | @@ -19,13 +19,20 @@ |
19 | #include "imap4d.h" | 19 | #include "imap4d.h" |
20 | 20 | ||
21 | /* | 21 | /* |
22 | * | 22 | 6.3.9. LSUB Command |
23 | */ | ||
24 | 23 | ||
24 | Arguments: reference name | ||
25 | mailbox name with possible wildcards | ||
26 | |||
27 | Responses: untagged responses: LSUB | ||
28 | |||
29 | Result: OK - lsub completed | ||
30 | NO - lsub failure: can't list that reference or name | ||
31 | BAD - command unknown or arguments invalid | ||
32 | */ | ||
25 | int | 33 | int |
26 | imap4d_lsub (struct imap4d_command *command, char *arg) | 34 | imap4d_lsub (struct imap4d_command *command, imap4d_tokbuf_t tok) |
27 | { | 35 | { |
28 | char *sp; | ||
29 | char *ref; | 36 | char *ref; |
30 | char *wcard; | 37 | char *wcard; |
31 | char *file = NULL; | 38 | char *file = NULL; |
... | @@ -33,14 +40,11 @@ imap4d_lsub (struct imap4d_command *command, char *arg) | ... | @@ -33,14 +40,11 @@ imap4d_lsub (struct imap4d_command *command, char *arg) |
33 | const char *delim = "/"; | 40 | const char *delim = "/"; |
34 | FILE *fp; | 41 | FILE *fp; |
35 | 42 | ||
36 | ref = util_getword (arg, &sp); | 43 | if (imap4d_tokbuf_argc (tok) != 4) |
37 | wcard = util_getword (NULL, &sp); | 44 | return util_finish (command, RESP_BAD, "Invalid arguments"); |
38 | if (!ref || !wcard) | ||
39 | return util_finish (command, RESP_BAD, "Too few arguments"); | ||
40 | 45 | ||
41 | /* Remove the double quotes. */ | 46 | ref = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1); |
42 | util_unquote (&ref); | 47 | wcard = imap4d_tokbuf_getarg (tok, IMAP4_ARG_2); |
43 | util_unquote (&wcard); | ||
44 | 48 | ||
45 | asprintf (&pattern, "%s%s", ref, wcard); | 49 | asprintf (&pattern, "%s%s", ref, wcard); |
46 | if (!pattern) | 50 | if (!pattern) | ... | ... |
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | 1 | /* GNU Mailutils -- a suite of utilities for electronic mail |
2 | Copyright (C) 1999, 2001, 2005, 2007 Free Software Foundation, Inc. | 2 | Copyright (C) 1999, 2001, 2005, 2007, 2008 Free Software Foundation, Inc. |
3 | 3 | ||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | 4 | GNU Mailutils is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU General Public License as published by | 5 | it under the terms of the GNU General Public License as published by |
... | @@ -89,8 +89,9 @@ print_namespace (int n) | ... | @@ -89,8 +89,9 @@ print_namespace (int n) |
89 | util_send ("("); | 89 | util_send ("("); |
90 | for (i = 0; i < namespace[n].subdir_c; i++) | 90 | for (i = 0; i < namespace[n].subdir_c; i++) |
91 | { | 91 | { |
92 | util_send ("(\"%s\" \"/\")", | 92 | char *dir = printable_pathname (namespace[n].subdir_v[i]); |
93 | printable_pathname (namespace[n].subdir_v[i])); | 93 | char *suf = (dir[0] && dir[strlen (dir) - 1] != '/') ? "/" : ""; |
94 | util_send ("(\"%s%s\" \"/\")", dir, suf); | ||
94 | } | 95 | } |
95 | util_send (")"); | 96 | util_send (")"); |
96 | } | 97 | } |
... | @@ -114,11 +115,27 @@ namespace_enumerate_all (nsfp_t f, void *closure) | ... | @@ -114,11 +115,27 @@ namespace_enumerate_all (nsfp_t f, void *closure) |
114 | || namespace_enumerate (NS_SHARED, f, closure); | 115 | || namespace_enumerate (NS_SHARED, f, closure); |
115 | } | 116 | } |
116 | 117 | ||
118 | /* | ||
119 | 5. NAMESPACE Command | ||
120 | |||
121 | Arguments: none | ||
122 | |||
123 | Response: an untagged NAMESPACE response that contains the prefix | ||
124 | and hierarchy delimiter to the server's Personal | ||
125 | Namespace(s), Other Users' Namespace(s), and Shared | ||
126 | Namespace(s) that the server wishes to expose. The | ||
127 | response will contain a NIL for any namespace class | ||
128 | that is not available. Namespace_Response_Extensions | ||
129 | MAY be included in the response. | ||
130 | Namespace_Response_Extensions which are not on the IETF | ||
131 | standards track, MUST be prefixed with an "X-". | ||
132 | */ | ||
133 | |||
117 | int | 134 | int |
118 | imap4d_namespace (struct imap4d_command *command, char *arg) | 135 | imap4d_namespace (struct imap4d_command *command, imap4d_tokbuf_t tok) |
119 | { | 136 | { |
120 | if (*arg) | 137 | if (imap4d_tokbuf_argc (tok) != 2) |
121 | return util_finish (command, RESP_BAD, "Too many arguments"); | 138 | return util_finish (command, RESP_BAD, "Invalid arguments"); |
122 | 139 | ||
123 | util_send ("* NAMESPACE "); | 140 | util_send ("* NAMESPACE "); |
124 | 141 | ... | ... |
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | 1 | /* GNU Mailutils -- a suite of utilities for electronic mail |
2 | Copyright (C) 1999, 2001, 2007 Free Software Foundation, Inc. | 2 | Copyright (C) 1999, 2001, 2007, 2008 Free Software Foundation, Inc. |
3 | 3 | ||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | 4 | GNU Mailutils is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU General Public License as published by | 5 | it under the terms of the GNU General Public License as published by |
... | @@ -19,13 +19,10 @@ | ... | @@ -19,13 +19,10 @@ |
19 | #include "imap4d.h" | 19 | #include "imap4d.h" |
20 | 20 | ||
21 | int | 21 | int |
22 | imap4d_noop (struct imap4d_command *command, char *arg) | 22 | imap4d_noop (struct imap4d_command *command, imap4d_tokbuf_t tok) |
23 | { | 23 | { |
24 | char *sp = NULL; | 24 | if (imap4d_tokbuf_argc (tok) != 2) |
25 | 25 | return util_finish (command, RESP_BAD, "Invalid arguments"); | |
26 | if (util_getword (arg, &sp)) | ||
27 | return util_finish (command, RESP_BAD, "Too many args"); | ||
28 | |||
29 | imap4d_sync (); | 26 | imap4d_sync (); |
30 | return util_finish (command, RESP_OK, "Completed"); | 27 | return util_finish (command, RESP_OK, "Completed"); |
31 | } | 28 | } | ... | ... |
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | 1 | /* GNU Mailutils -- a suite of utilities for electronic mail |
2 | Copyright (C) 1999, 2001, 2005, 2007 Free Software Foundation, Inc. | 2 | Copyright (C) 1999, 2001, 2005, 2007, 2008 Free Software Foundation, Inc. |
3 | 3 | ||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | 4 | GNU Mailutils is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU General Public License as published by | 5 | it under the terms of the GNU General Public License as published by |
... | @@ -19,30 +19,37 @@ | ... | @@ -19,30 +19,37 @@ |
19 | #include "imap4d.h" | 19 | #include "imap4d.h" |
20 | 20 | ||
21 | /* | 21 | /* |
22 | 6.3.5. RENAME Command | ||
23 | |||
24 | Arguments: existing mailbox name | ||
25 | new mailbox name | ||
26 | |||
27 | Responses: no specific responses for this command | ||
28 | |||
29 | Result: OK - rename completed | ||
30 | NO - rename failure: can't rename mailbox with that name, | ||
31 | can't rename to mailbox with that name | ||
32 | BAD - command unknown or arguments invalid | ||
33 | */ | ||
34 | /* | ||
22 | FIXME: Renaming a mailbox we must change the UIDVALIDITY | 35 | FIXME: Renaming a mailbox we must change the UIDVALIDITY |
23 | of the mailbox. */ | 36 | of the mailbox. */ |
24 | 37 | ||
25 | int | 38 | int |
26 | imap4d_rename (struct imap4d_command *command, char *arg) | 39 | imap4d_rename (struct imap4d_command *command, imap4d_tokbuf_t tok) |
27 | { | 40 | { |
28 | char *oldname; | 41 | char *oldname; |
29 | char *newname; | 42 | char *newname; |
30 | char *sp = NULL; | ||
31 | int rc = RESP_OK; | 43 | int rc = RESP_OK; |
32 | const char *msg = "Completed"; | 44 | const char *msg = "Completed"; |
33 | struct stat newst; | 45 | struct stat newst; |
34 | const char *delim = "/"; | 46 | const char *delim = "/"; |
35 | 47 | ||
36 | oldname = util_getword (arg, &sp); | 48 | if (imap4d_tokbuf_argc (tok) != 4) |
37 | newname = util_getword (NULL, &sp); | 49 | return util_finish (command, RESP_BAD, "Invalid arguments"); |
38 | if (!newname || !oldname) | ||
39 | return util_finish (command, RESP_BAD, "Too few arguments"); | ||
40 | |||
41 | util_unquote (&newname); | ||
42 | util_unquote (&oldname); | ||
43 | 50 | ||
44 | if (*newname == '\0' || *oldname == '\0') | 51 | oldname = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1); |
45 | return util_finish (command, RESP_BAD, "Too few arguments"); | 52 | newname = imap4d_tokbuf_getarg (tok, IMAP4_ARG_2); |
46 | 53 | ||
47 | if (strcasecmp (newname, "INBOX") == 0) | 54 | if (strcasecmp (newname, "INBOX") == 0) |
48 | return util_finish (command, RESP_NO, "Name Inbox is reservered"); | 55 | return util_finish (command, RESP_NO, "Name Inbox is reservered"); | ... | ... |
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | 1 | /* GNU Mailutils -- a suite of utilities for electronic mail |
2 | Copyright (C) 1999, 2001, 2002, 2005, 2007 Free Software Foundation, Inc. | 2 | Copyright (C) 1999, 2001, 2002, 2005, 2007, |
3 | 2008 Free Software Foundation, Inc. | ||
3 | 4 | ||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | 5 | GNU Mailutils is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU General Public License as published by | 6 | it under the terms of the GNU General Public License as published by |
... | @@ -223,11 +224,9 @@ struct mem_chain | ... | @@ -223,11 +224,9 @@ struct mem_chain |
223 | /* Parse buffer structure */ | 224 | /* Parse buffer structure */ |
224 | struct parsebuf | 225 | struct parsebuf |
225 | { | 226 | { |
226 | char *token; /* Current token. Either points to tokbuf | 227 | imap4d_tokbuf_t tok; /* Token buffer */ |
227 | or is allocated within `alloc' chain */ | 228 | int arg; /* Argument number */ |
228 | char tokbuf[MAXTOKEN+1]; /* Token buffer for short tokens */ | 229 | char *token; /* Current token */ |
229 | |||
230 | char *arg; /* Rest of command line to be parsed */ | ||
231 | int isuid; /* UIDs instead of msgnos are required */ | 230 | int isuid; /* UIDs instead of msgnos are required */ |
232 | char *err_mesg; /* Error message if a parse error occured */ | 231 | char *err_mesg; /* Error message if a parse error occured */ |
233 | struct mem_chain *alloc; /* Chain of objects allocated during parsing */ | 232 | struct mem_chain *alloc; /* Chain of objects allocated during parsing */ |
... | @@ -249,30 +248,45 @@ static int parse_gettoken (struct parsebuf *pb, int req); | ... | @@ -249,30 +248,45 @@ static int parse_gettoken (struct parsebuf *pb, int req); |
249 | static int search_run (struct parsebuf *pb); | 248 | static int search_run (struct parsebuf *pb); |
250 | static void do_search (struct parsebuf *pb); | 249 | static void do_search (struct parsebuf *pb); |
251 | 250 | ||
251 | /* | ||
252 | 6.4.4. SEARCH Command | ||
253 | |||
254 | Arguments: OPTIONAL [CHARSET] specification | ||
255 | searching criteria (one or more) | ||
256 | |||
257 | Responses: REQUIRED untagged response: SEARCH | ||
258 | |||
259 | Result: OK - search completed | ||
260 | NO - search error: can't search that [CHARSET] or | ||
261 | criteria | ||
262 | BAD - command unknown or arguments invalid | ||
263 | */ | ||
264 | |||
252 | int | 265 | int |
253 | imap4d_search (struct imap4d_command *command, char *arg) | 266 | imap4d_search (struct imap4d_command *command, imap4d_tokbuf_t tok) |
254 | { | 267 | { |
255 | int rc; | 268 | int rc; |
256 | char buffer[64]; | 269 | char *err_text= ""; |
257 | 270 | ||
258 | rc = imap4d_search0 (arg, 0, buffer, sizeof buffer); | 271 | rc = imap4d_search0 (tok, 0, &err_text); |
259 | return util_finish (command, rc, "%s", buffer); | 272 | return util_finish (command, rc, "%s", err_text); |
260 | } | 273 | } |
261 | 274 | ||
262 | int | 275 | int |
263 | imap4d_search0 (char *arg, int isuid, char *replybuf, size_t replysize) | 276 | imap4d_search0 (imap4d_tokbuf_t tok, int isuid, char **err_text) |
264 | { | 277 | { |
265 | struct parsebuf parsebuf; | 278 | struct parsebuf parsebuf; |
266 | 279 | ||
267 | memset (&parsebuf, 0, sizeof(parsebuf)); | 280 | memset (&parsebuf, 0, sizeof(parsebuf)); |
268 | parsebuf.arg = arg; | 281 | parsebuf.tok = tok; |
282 | parsebuf.arg = IMAP4_ARG_1 + !!isuid; | ||
269 | parsebuf.err_mesg = NULL; | 283 | parsebuf.err_mesg = NULL; |
270 | parsebuf.alloc = NULL; | 284 | parsebuf.alloc = NULL; |
271 | parsebuf.isuid = isuid; | 285 | parsebuf.isuid = isuid; |
272 | 286 | ||
273 | if (!parse_gettoken (&parsebuf, 0)) | 287 | if (!parse_gettoken (&parsebuf, 0)) |
274 | { | 288 | { |
275 | snprintf (replybuf, replysize, "Too few args"); | 289 | *err_text = "Too few args"; |
276 | return RESP_BAD; | 290 | return RESP_BAD; |
277 | } | 291 | } |
278 | 292 | ||
... | @@ -280,20 +294,20 @@ imap4d_search0 (char *arg, int isuid, char *replybuf, size_t replysize) | ... | @@ -280,20 +294,20 @@ imap4d_search0 (char *arg, int isuid, char *replybuf, size_t replysize) |
280 | { | 294 | { |
281 | if (!parse_gettoken (&parsebuf, 0)) | 295 | if (!parse_gettoken (&parsebuf, 0)) |
282 | { | 296 | { |
283 | snprintf (replybuf, replysize, "Too few args"); | 297 | *err_text = "Too few args"; |
284 | return RESP_BAD; | 298 | return RESP_BAD; |
285 | } | 299 | } |
286 | 300 | ||
287 | /* Currently only ASCII is supported */ | 301 | /* Currently only ASCII is supported */ |
288 | if (strcasecmp (parsebuf.token, "US-ASCII")) | 302 | if (strcasecmp (parsebuf.token, "US-ASCII")) |
289 | { | 303 | { |
290 | snprintf (replybuf, replysize, "Charset not supported"); | 304 | *err_text = "Charset not supported"; |
291 | return RESP_NO; | 305 | return RESP_NO; |
292 | } | 306 | } |
293 | 307 | ||
294 | if (!parse_gettoken (&parsebuf, 0)) | 308 | if (!parse_gettoken (&parsebuf, 0)) |
295 | { | 309 | { |
296 | snprintf (replybuf, replysize, "Too few args"); | 310 | *err_text = "Too few args"; |
297 | return RESP_BAD; | 311 | return RESP_BAD; |
298 | } | 312 | } |
299 | 313 | ||
... | @@ -304,16 +318,14 @@ imap4d_search0 (char *arg, int isuid, char *replybuf, size_t replysize) | ... | @@ -304,16 +318,14 @@ imap4d_search0 (char *arg, int isuid, char *replybuf, size_t replysize) |
304 | if (!parsebuf.tree) | 318 | if (!parsebuf.tree) |
305 | { | 319 | { |
306 | parse_free_mem (&parsebuf); | 320 | parse_free_mem (&parsebuf); |
307 | snprintf (replybuf, replysize, "%s (near %s)", | 321 | *err_text = "Parse error"; |
308 | parsebuf.err_mesg, | ||
309 | *parsebuf.arg ? parsebuf.arg : "end"); | ||
310 | return RESP_BAD; | 322 | return RESP_BAD; |
311 | } | 323 | } |
312 | 324 | ||
313 | if (parsebuf.token[0] != 0) | 325 | if (parsebuf.token) |
314 | { | 326 | { |
315 | parse_free_mem (&parsebuf); | 327 | parse_free_mem (&parsebuf); |
316 | snprintf (replybuf, replysize, "Junk at the end of statement"); | 328 | *err_text = "Junk at the end of statement"; |
317 | return RESP_BAD; | 329 | return RESP_BAD; |
318 | } | 330 | } |
319 | 331 | ||
... | @@ -322,7 +334,7 @@ imap4d_search0 (char *arg, int isuid, char *replybuf, size_t replysize) | ... | @@ -322,7 +334,7 @@ imap4d_search0 (char *arg, int isuid, char *replybuf, size_t replysize) |
322 | 334 | ||
323 | parse_free_mem (&parsebuf); | 335 | parse_free_mem (&parsebuf); |
324 | 336 | ||
325 | snprintf (replybuf, replysize, "Completed"); | 337 | *err_text = "Completed"; |
326 | return RESP_OK; | 338 | return RESP_OK; |
327 | } | 339 | } |
328 | 340 | ||
... | @@ -359,41 +371,13 @@ do_search (struct parsebuf *pb) | ... | @@ -359,41 +371,13 @@ do_search (struct parsebuf *pb) |
359 | int | 371 | int |
360 | parse_gettoken (struct parsebuf *pb, int req) | 372 | parse_gettoken (struct parsebuf *pb, int req) |
361 | { | 373 | { |
362 | int rc; | 374 | if (req && pb->arg >= imap4d_tokbuf_argc (pb->tok)) |
363 | char *s; | ||
364 | |||
365 | pb->token = pb->tokbuf; | ||
366 | while (*pb->arg && *pb->arg == ' ') | ||
367 | pb->arg++; | ||
368 | switch (*pb->arg) | ||
369 | { | 375 | { |
370 | case '(': | ||
371 | case ')': | ||
372 | pb->token[0] = *pb->arg++; | ||
373 | pb->token[1] = 0; | ||
374 | rc = 1; | ||
375 | break; | ||
376 | case '"': | ||
377 | s = ++pb->arg; | ||
378 | while (*pb->arg && *pb->arg != '"') | ||
379 | pb->arg++; | ||
380 | rc = pb->arg - s; | ||
381 | if (*pb->arg) | ||
382 | pb->arg++; | ||
383 | |||
384 | if (rc >= sizeof(pb->tokbuf)) | ||
385 | pb->token = parse_alloc (pb, rc+1); | ||
386 | memcpy (pb->token, s, rc); | ||
387 | pb->token[rc] = 0; | ||
388 | break; | ||
389 | |||
390 | default: | ||
391 | rc = util_token (pb->token, sizeof(pb->tokbuf), &pb->arg); | ||
392 | break; | ||
393 | } | ||
394 | if (req && rc == 0) | ||
395 | pb->err_mesg = "Unexpected end of statement"; | 376 | pb->err_mesg = "Unexpected end of statement"; |
396 | return rc; | 377 | return 0; |
378 | } | ||
379 | pb->token = imap4d_tokbuf_getarg (pb->tok, pb->arg++); | ||
380 | return 1; | ||
397 | } | 381 | } |
398 | 382 | ||
399 | /* Memory handling */ | 383 | /* Memory handling */ |
... | @@ -468,7 +452,7 @@ parse_search_key_list (struct parsebuf *pb) | ... | @@ -468,7 +452,7 @@ parse_search_key_list (struct parsebuf *pb) |
468 | { | 452 | { |
469 | struct search_node *leftarg = NULL; | 453 | struct search_node *leftarg = NULL; |
470 | 454 | ||
471 | while (pb->token[0] && pb->token[0] != ')') | 455 | while (pb->token && pb->token[0] != ')') |
472 | { | 456 | { |
473 | struct search_node *rightarg = parse_search_key (pb); | 457 | struct search_node *rightarg = parse_search_key (pb); |
474 | if (!rightarg) | 458 | if (!rightarg) |
... | @@ -563,8 +547,8 @@ parse_equiv_key (struct parsebuf *pb) | ... | @@ -563,8 +547,8 @@ parse_equiv_key (struct parsebuf *pb) |
563 | { | 547 | { |
564 | struct search_node *node; | 548 | struct search_node *node; |
565 | struct cond_equiv *condp; | 549 | struct cond_equiv *condp; |
566 | char *arg; | 550 | int save_arg; |
567 | char *save_arg; | 551 | imap4d_tokbuf_t save_tok; |
568 | 552 | ||
569 | for (condp = equiv_list; condp->name && strcasecmp (condp->name, pb->token); | 553 | for (condp = equiv_list; condp->name && strcasecmp (condp->name, pb->token); |
570 | condp++) | 554 | condp++) |
... | @@ -574,8 +558,9 @@ parse_equiv_key (struct parsebuf *pb) | ... | @@ -574,8 +558,9 @@ parse_equiv_key (struct parsebuf *pb) |
574 | return parse_simple_key (pb); | 558 | return parse_simple_key (pb); |
575 | 559 | ||
576 | save_arg = pb->arg; | 560 | save_arg = pb->arg; |
577 | arg = parse_strdup (pb, condp->equiv); | 561 | save_tok = pb->tok; |
578 | pb->arg = arg; | 562 | pb->tok = imap4d_tokbuf_from_string (condp->equiv); |
563 | pb->arg = 0; | ||
579 | 564 | ||
580 | parse_gettoken (pb, 0); | 565 | parse_gettoken (pb, 0); |
581 | 566 | ||
... | @@ -587,8 +572,10 @@ parse_equiv_key (struct parsebuf *pb) | ... | @@ -587,8 +572,10 @@ parse_equiv_key (struct parsebuf *pb) |
587 | __FILE__, __LINE__); | 572 | __FILE__, __LINE__); |
588 | abort (); | 573 | abort (); |
589 | } | 574 | } |
575 | imap4d_tokbuf_destroy (&pb->tok); | ||
590 | 576 | ||
591 | pb->arg = save_arg; | 577 | pb->arg = save_arg; |
578 | pb->tok = save_tok; | ||
592 | parse_gettoken (pb, 0); | 579 | parse_gettoken (pb, 0); |
593 | return node; | 580 | return node; |
594 | } | 581 | } |
... | @@ -658,7 +645,7 @@ parse_simple_key (struct parsebuf *pb) | ... | @@ -658,7 +645,7 @@ parse_simple_key (struct parsebuf *pb) |
658 | return NULL; | 645 | return NULL; |
659 | } | 646 | } |
660 | 647 | ||
661 | if (!pb->token[0]) | 648 | if (!pb->token) |
662 | { | 649 | { |
663 | pb->err_mesg = "Not enough arguments for criterion"; | 650 | pb->err_mesg = "Not enough arguments for criterion"; |
664 | return NULL; | 651 | return NULL; | ... | ... |
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | 1 | /* GNU Mailutils -- a suite of utilities for electronic mail |
2 | Copyright (C) 1999, 2001, 2003, 2005, 2006, | 2 | Copyright (C) 1999, 2001, 2003, 2005, 2006, |
3 | 2007 Free Software Foundation, Inc. | 3 | 2007, 2008 Free Software Foundation, Inc. |
4 | 4 | ||
5 | GNU Mailutils is free software; you can redistribute it and/or modify | 5 | GNU Mailutils is free software; you can redistribute it and/or modify |
6 | it under the terms of the GNU General Public License as published by | 6 | it under the terms of the GNU General Public License as published by |
... | @@ -24,25 +24,22 @@ static int select_flags; | ... | @@ -24,25 +24,22 @@ static int select_flags; |
24 | /* select ::= "SELECT" SPACE mailbox */ | 24 | /* select ::= "SELECT" SPACE mailbox */ |
25 | 25 | ||
26 | int | 26 | int |
27 | imap4d_select (struct imap4d_command *command, char *arg) | 27 | imap4d_select (struct imap4d_command *command, imap4d_tokbuf_t tok) |
28 | { | 28 | { |
29 | return imap4d_select0 (command, arg, MU_STREAM_RDWR); | 29 | if (imap4d_tokbuf_argc (tok) != 3) |
30 | return util_finish (command, RESP_BAD, "Invalid arguments"); | ||
31 | return imap4d_select0 (command, imap4d_tokbuf_getarg (tok, IMAP4_ARG_1), | ||
32 | MU_STREAM_RDWR); | ||
30 | } | 33 | } |
31 | 34 | ||
32 | /* This code is share with EXAMINE. */ | 35 | /* This code is share with EXAMINE. */ |
33 | int | 36 | int |
34 | imap4d_select0 (struct imap4d_command *command, char *arg, int flags) | 37 | imap4d_select0 (struct imap4d_command *command, char *mailbox_name, int flags) |
35 | { | 38 | { |
36 | char *mailbox_name, *sp = NULL; | ||
37 | int status; | 39 | int status; |
38 | 40 | ||
39 | /* FIXME: Check state. */ | 41 | /* FIXME: Check state. */ |
40 | 42 | ||
41 | mailbox_name = util_getword (arg, &sp); | ||
42 | util_unquote (&mailbox_name); | ||
43 | if (mailbox_name == NULL || *mailbox_name == '\0') | ||
44 | return util_finish (command, RESP_BAD, "Too few arguments"); | ||
45 | |||
46 | /* Even if a mailbox is selected, a SELECT EXAMINE or LOGOUT | 43 | /* Even if a mailbox is selected, a SELECT EXAMINE or LOGOUT |
47 | command MAY be issued without previously issuing a CLOSE command. | 44 | command MAY be issued without previously issuing a CLOSE command. |
48 | The SELECT, EXAMINE, and LOGUT commands implictly close the | 45 | The SELECT, EXAMINE, and LOGUT commands implictly close the | ... | ... |
... | @@ -23,17 +23,26 @@ | ... | @@ -23,17 +23,26 @@ |
23 | static int tls_available; | 23 | static int tls_available; |
24 | static int tls_done; | 24 | static int tls_done; |
25 | 25 | ||
26 | /* | ||
27 | 6.2.1. STARTTLS Command | ||
28 | |||
29 | Arguments: none | ||
30 | |||
31 | Responses: no specific response for this command | ||
32 | |||
33 | Result: OK - starttls completed, begin TLS negotiation | ||
34 | BAD - command unknown or arguments invalid | ||
35 | */ | ||
26 | int | 36 | int |
27 | imap4d_starttls (struct imap4d_command *command, char *arg) | 37 | imap4d_starttls (struct imap4d_command *command, imap4d_tokbuf_t tok) |
28 | { | 38 | { |
29 | int status; | 39 | int status; |
30 | char *sp = NULL; | ||
31 | 40 | ||
32 | if (!tls_available || tls_done) | 41 | if (!tls_available || tls_done) |
33 | return util_finish (command, RESP_BAD, "Invalid command"); | 42 | return util_finish (command, RESP_BAD, "Invalid command"); |
34 | 43 | ||
35 | if (util_getword (arg, &sp)) | 44 | if (imap4d_tokbuf_argc (tok) != 2) |
36 | return util_finish (command, RESP_BAD, "Too many args"); | 45 | return util_finish (command, RESP_BAD, "Invalid arguments"); |
37 | 46 | ||
38 | util_atexit (mu_deinit_tls_libs); | 47 | util_atexit (mu_deinit_tls_libs); |
39 | 48 | ... | ... |
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | 1 | /* GNU Mailutils -- a suite of utilities for electronic mail |
2 | Copyright (C) 1999, 2001, 2005, 2007 Free Software Foundation, Inc. | 2 | Copyright (C) 1999, 2001, 2005, 2007, 2008 Free Software Foundation, Inc. |
3 | 3 | ||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | 4 | GNU Mailutils is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU General Public License as published by | 5 | it under the terms of the GNU General Public License as published by |
... | @@ -53,10 +53,21 @@ status_get_handler (const char *name) | ... | @@ -53,10 +53,21 @@ status_get_handler (const char *name) |
53 | return NULL; | 53 | return NULL; |
54 | } | 54 | } |
55 | 55 | ||
56 | /* | ||
57 | 6.3.10. STATUS Command | ||
58 | |||
59 | Arguments: mailbox name | ||
60 | status data item names | ||
61 | |||
62 | Responses: untagged responses: STATUS | ||
63 | |||
64 | Result: OK - status completed | ||
65 | NO - status failure: no status for that name | ||
66 | BAD - command unknown or arguments invalid | ||
67 | */ | ||
56 | int | 68 | int |
57 | imap4d_status (struct imap4d_command *command, char *arg) | 69 | imap4d_status (struct imap4d_command *command, imap4d_tokbuf_t tok) |
58 | { | 70 | { |
59 | char *sp = NULL; | ||
60 | char *name; | 71 | char *name; |
61 | char *mailbox_name; | 72 | char *mailbox_name; |
62 | const char *delim = "/"; | 73 | const char *delim = "/"; |
... | @@ -64,11 +75,12 @@ imap4d_status (struct imap4d_command *command, char *arg) | ... | @@ -64,11 +75,12 @@ imap4d_status (struct imap4d_command *command, char *arg) |
64 | int status; | 75 | int status; |
65 | int count = 0; | 76 | int count = 0; |
66 | char *err_msg = NULL; | 77 | char *err_msg = NULL; |
78 | int argc = imap4d_tokbuf_argc (tok); | ||
79 | |||
80 | if (argc < 4) | ||
81 | return util_finish (command, RESP_BAD, "Invalid arguments"); | ||
67 | 82 | ||
68 | name = util_getword (arg, &sp); | 83 | name = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1); |
69 | util_unquote (&name); | ||
70 | if (!name || *name == '\0' || !sp || *sp == '\0') | ||
71 | return util_finish (command, RESP_BAD, "Too few args"); | ||
72 | 84 | ||
73 | mailbox_name = namespace_getfullpath (name, delim); | 85 | mailbox_name = namespace_getfullpath (name, delim); |
74 | 86 | ||
... | @@ -85,20 +97,22 @@ imap4d_status (struct imap4d_command *command, char *arg) | ... | @@ -85,20 +97,22 @@ imap4d_status (struct imap4d_command *command, char *arg) |
85 | status = mu_mailbox_open (smbox, MU_STREAM_READ); | 97 | status = mu_mailbox_open (smbox, MU_STREAM_READ); |
86 | if (status == 0) | 98 | if (status == 0) |
87 | { | 99 | { |
88 | char item[32]; | 100 | int i = IMAP4_ARG_2; |
89 | item[0] = '\0'; | 101 | char *item = imap4d_tokbuf_getarg (tok, i); |
90 | 102 | ||
91 | if (*sp == '(') | 103 | if (item[0] == '(') |
92 | sp++; | 104 | { |
93 | else | 105 | if (imap4d_tokbuf_getarg (tok, argc - 1)[0] != ')') |
94 | *sp = 0; | 106 | return util_finish (command, RESP_BAD, "Invalid arguments"); |
107 | argc--; | ||
108 | i++; | ||
109 | } | ||
95 | 110 | ||
96 | /* Get the status item names. */ | 111 | for (; i < argc; i++) |
97 | while (*sp && *sp != ')') | ||
98 | { | 112 | { |
99 | status_funcp fun; | 113 | status_funcp fun; |
100 | 114 | ||
101 | util_token (item, sizeof (item), &sp); | 115 | item = imap4d_tokbuf_getarg (tok, i); |
102 | fun = status_get_handler (item); | 116 | fun = status_get_handler (item); |
103 | if (!fun) | 117 | if (!fun) |
104 | { | 118 | { |
... | @@ -112,6 +126,8 @@ imap4d_status (struct imap4d_command *command, char *arg) | ... | @@ -112,6 +126,8 @@ imap4d_status (struct imap4d_command *command, char *arg) |
112 | if (!fun (smbox)) | 126 | if (!fun (smbox)) |
113 | util_send (" "); | 127 | util_send (" "); |
114 | } | 128 | } |
129 | |||
130 | |||
115 | if (count > 0) | 131 | if (count > 0) |
116 | util_send (")\r\n"); | 132 | util_send (")\r\n"); |
117 | mu_mailbox_close (smbox); | 133 | mu_mailbox_close (smbox); |
... | @@ -193,5 +209,4 @@ status_unseen (mu_mailbox_t smbox) | ... | @@ -193,5 +209,4 @@ status_unseen (mu_mailbox_t smbox) |
193 | } | 209 | } |
194 | util_send ("UNSEEN %d", unseen); | 210 | util_send ("UNSEEN %d", unseen); |
195 | return 0; | 211 | return 0; |
196 | |||
197 | } | 212 | } | ... | ... |
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | 1 | /* GNU Mailutils -- a suite of utilities for electronic mail |
2 | Copyright (C) 1999, 2001, 2005, 2007 Free Software Foundation, Inc. | 2 | Copyright (C) 1999, 2001, 2005, 2007, 2008 Free Software Foundation, Inc. |
3 | 3 | ||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | 4 | GNU Mailutils is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU General Public License as published by | 5 | it under the terms of the GNU General Public License as published by |
... | @@ -23,134 +23,155 @@ | ... | @@ -23,134 +23,155 @@ |
23 | */ | 23 | */ |
24 | 24 | ||
25 | int | 25 | int |
26 | imap4d_store (struct imap4d_command *command, char *arg) | 26 | imap4d_store (struct imap4d_command *command, imap4d_tokbuf_t tok) |
27 | { | 27 | { |
28 | int rc; | 28 | int rc; |
29 | char buffer[64]; | 29 | char *err_text; |
30 | 30 | ||
31 | rc = imap4d_store0 (arg, 0, buffer, sizeof buffer); | 31 | rc = imap4d_store0 (tok, 0, &err_text); |
32 | return util_finish (command, rc, "%s", buffer); | 32 | return util_finish (command, rc, "%s", err_text); |
33 | } | ||
34 | |||
35 | struct parsebuf | ||
36 | { | ||
37 | char *token; | ||
38 | imap4d_tokbuf_t tok; | ||
39 | int arg; | ||
40 | jmp_buf errjmp; | ||
41 | char *err_text; | ||
42 | }; | ||
43 | |||
44 | static void | ||
45 | parsebuf_exit (struct parsebuf *p, char *text) | ||
46 | { | ||
47 | p->err_text = text; | ||
48 | longjmp (p->errjmp, 1); | ||
49 | } | ||
50 | |||
51 | static char * | ||
52 | parsebuf_next (struct parsebuf *p, int req) | ||
53 | { | ||
54 | p->token = imap4d_tokbuf_getarg (p->tok, p->arg++); | ||
55 | if (!p->token && req) | ||
56 | parsebuf_exit (p, "Too few arguments"); | ||
57 | return p->token; | ||
33 | } | 58 | } |
34 | 59 | ||
35 | int | 60 | int |
36 | imap4d_store0 (char *arg, int isuid, char *resp, size_t resplen) | 61 | imap4d_store0 (imap4d_tokbuf_t tok, int isuid, char **ptext) |
37 | { | 62 | { |
38 | char *msgset; | 63 | char *msgset; |
39 | char *data; | ||
40 | char *sp = NULL; | ||
41 | int status; | 64 | int status; |
42 | int ack = 0; | 65 | int ack = 1; |
43 | size_t i; | 66 | size_t i; |
44 | int n = 0; | 67 | int n = 0; |
45 | size_t *set = NULL; | 68 | size_t *set = NULL; |
46 | enum value_type { STORE_SET, STORE_ADD, STORE_UNSET } how; | 69 | enum value_type { STORE_SET, STORE_ADD, STORE_UNSET } how; |
70 | struct parsebuf pb; | ||
71 | char *data; | ||
72 | int type = 0; | ||
47 | 73 | ||
48 | msgset = util_getword (arg, &sp); | 74 | pb.tok = tok; |
49 | data = util_getword (NULL, &sp); | 75 | pb.arg = IMAP4_ARG_1; |
50 | 76 | pb.err_text = NULL; | |
51 | if (!msgset || !data || !sp || *sp == '\0') | 77 | if (setjmp (pb.errjmp)) |
52 | { | 78 | { |
53 | snprintf (resp, resplen, "Too few args"); | 79 | *ptext = pb.err_text; |
80 | free (set); | ||
54 | return RESP_BAD; | 81 | return RESP_BAD; |
55 | } | 82 | } |
56 | 83 | ||
57 | /* The parsing of the data-item is a little slugish. */ | 84 | msgset = parsebuf_next (&pb, 1); |
58 | if (strcasecmp (data, "FLAGS") == 0) | 85 | data = parsebuf_next (&pb, 1); |
59 | { | 86 | |
60 | ack = 1; | 87 | if (*data == '+') |
61 | how = STORE_SET; | ||
62 | } | ||
63 | else if (strcasecmp (data, "+FLAGS") == 0) | ||
64 | { | 88 | { |
65 | ack = 1; | ||
66 | how = STORE_ADD; | 89 | how = STORE_ADD; |
90 | data++; | ||
67 | } | 91 | } |
68 | else if (strcasecmp (data, "-FLAGS") == 0) | 92 | else if (*data == '-') |
69 | { | 93 | { |
70 | ack = 1; | ||
71 | how = STORE_UNSET; | 94 | how = STORE_UNSET; |
95 | data++; | ||
72 | } | 96 | } |
73 | else if (strcasecmp (data, "FLAGS.SILENT") == 0) | 97 | else |
74 | { | ||
75 | ack = 0; | ||
76 | how = STORE_SET; | 98 | how = STORE_SET; |
77 | } | 99 | |
78 | else if (strcasecmp (data, "+FLAGS.SILENT") == 0) | 100 | if (strcasecmp (data, "FLAGS")) |
101 | parsebuf_exit (&pb, "Bogus data item"); | ||
102 | data = parsebuf_next (&pb, 1); | ||
103 | |||
104 | if (*data == '.') | ||
79 | { | 105 | { |
80 | ack = 0; | 106 | data = parsebuf_next (&pb, 1); |
81 | how = STORE_ADD; | 107 | if (strcasecmp (data, "SILENT") == 0) |
82 | } | ||
83 | else if (strcasecmp (data, "-FLAGS.SILENT") == 0) | ||
84 | { | 108 | { |
85 | ack = 0; | 109 | ack = 0; |
86 | how = STORE_UNSET; | 110 | parsebuf_next (&pb, 1); |
87 | } | 111 | } |
88 | else | 112 | else |
89 | { | 113 | parsebuf_exit (&pb, "Bogus data suffix"); |
90 | snprintf (resp, resplen, "Bogus data item"); | ||
91 | return RESP_BAD; | ||
92 | } | 114 | } |
93 | 115 | ||
94 | /* Get the message numbers in set[]. */ | 116 | /* Get the message numbers in set[]. */ |
95 | status = util_msgset (msgset, &set, &n, isuid); | 117 | status = util_msgset (msgset, &set, &n, isuid); |
96 | if (status != 0) | 118 | if (status != 0) |
119 | parsebuf_exit (&pb, "Bogus number set"); | ||
120 | |||
121 | if (pb.token[0] != '(') | ||
122 | parsebuf_exit (&pb, "Syntax error"); | ||
123 | parsebuf_next (&pb, 1); | ||
124 | |||
125 | do | ||
97 | { | 126 | { |
98 | snprintf (resp, resplen, "Bogus number set"); | 127 | int t; |
99 | return RESP_BAD; | 128 | if (!util_attribute_to_type (pb.token, &t)) |
129 | type |= t; | ||
100 | } | 130 | } |
131 | while (parsebuf_next (&pb, 1) && pb.token[0] != ')'); | ||
101 | 132 | ||
102 | for (i = 0; i < n; i++) | 133 | for (i = 0; i < n; i++) |
103 | { | 134 | { |
104 | mu_message_t msg = NULL; | 135 | mu_message_t msg = NULL; |
105 | mu_attribute_t attr = NULL; | 136 | mu_attribute_t attr = NULL; |
106 | char *items = strdup (sp); /* Don't use the orignal list. */ | 137 | size_t msgno = isuid ? uid_to_msgno (set[i]) : set[i]; |
107 | int first = 1; | ||
108 | size_t msgno; | ||
109 | char *p = items; | ||
110 | 138 | ||
111 | msgno = (isuid) ? uid_to_msgno (set[i]) : set[i]; | ||
112 | if (msgno) | 139 | if (msgno) |
113 | { | 140 | { |
114 | mu_mailbox_get_message (mbox, msgno, &msg); | 141 | mu_mailbox_get_message (mbox, msgno, &msg); |
115 | mu_message_get_attribute (msg, &attr); | 142 | mu_message_get_attribute (msg, &attr); |
116 | 143 | ||
117 | /* Get the fetch command names. */ | 144 | switch (how) |
118 | while (*items && *items != ')') | ||
119 | { | 145 | { |
120 | int type = 0; | 146 | case STORE_ADD: |
121 | char item[64] = ""; | ||
122 | util_token (item, sizeof (item), &items); | ||
123 | if (!util_attribute_to_type (item, &type)) | ||
124 | { | ||
125 | if (how == STORE_ADD ) | ||
126 | mu_attribute_set_flags (attr, type); | 147 | mu_attribute_set_flags (attr, type); |
127 | else if (how == STORE_UNSET ) | 148 | break; |
149 | |||
150 | case STORE_UNSET: | ||
128 | mu_attribute_unset_flags (attr, type); | 151 | mu_attribute_unset_flags (attr, type); |
129 | else if (how == STORE_SET ) | 152 | break; |
130 | { | 153 | |
131 | if (first) | 154 | case STORE_SET: |
132 | { | 155 | mu_attribute_unset_flags (attr, 0xffffffff); /* FIXME */ |
133 | mu_attribute_set_flags (attr, 0); | ||
134 | first = 0; | ||
135 | } | ||
136 | mu_attribute_set_flags (attr, type); | 156 | mu_attribute_set_flags (attr, type); |
137 | } | 157 | } |
138 | mu_attribute_set_flags (attr, MU_ATTRIBUTE_MODIFIED); | ||
139 | } | ||
140 | } | ||
141 | } | 158 | } |
159 | |||
142 | if (ack) | 160 | if (ack) |
143 | { | 161 | { |
144 | util_send ("* %d FETCH (", msgno); | 162 | util_send ("* %d FETCH (", msgno); |
145 | fetch_flags0 ("FLAGS", msg, isuid); | 163 | |
146 | util_send (")\r\n"); | 164 | if (isuid) |
165 | util_send ("UID %lu ", (unsigned long) msgno); | ||
166 | util_send ("FLAGS ("); | ||
167 | util_print_flags (attr); | ||
168 | util_send ("))\r\n"); | ||
147 | } | 169 | } |
148 | free (p); | ||
149 | /* Update the flags of uid table. */ | 170 | /* Update the flags of uid table. */ |
150 | imap4d_sync_flags (set[i]); | 171 | imap4d_sync_flags (set[i]); |
151 | } | 172 | } |
152 | free (set); | 173 | free (set); |
153 | snprintf (resp, resplen, "Completed"); | 174 | *ptext = "Completed"; |
154 | return RESP_OK; | 175 | return RESP_OK; |
155 | } | 176 | } |
156 | 177 | ... | ... |
... | @@ -19,21 +19,27 @@ | ... | @@ -19,21 +19,27 @@ |
19 | #include "imap4d.h" | 19 | #include "imap4d.h" |
20 | 20 | ||
21 | /* | 21 | /* |
22 | FIXME: We need to lock the file to prevent simultaneous access. | 22 | 6.3.6. SUBSCRIBE Command |
23 | */ | ||
24 | 23 | ||
24 | Arguments: mailbox | ||
25 | |||
26 | Responses: no specific responses for this command | ||
27 | |||
28 | Result: OK - subscribe completed | ||
29 | NO - subscribe failure: can't subscribe to that name | ||
30 | BAD - command unknown or arguments invalid | ||
31 | */ | ||
25 | int | 32 | int |
26 | imap4d_subscribe (struct imap4d_command *command, char *arg) | 33 | imap4d_subscribe (struct imap4d_command *command, imap4d_tokbuf_t tok) |
27 | { | 34 | { |
28 | char *sp = NULL; | ||
29 | char *name; | 35 | char *name; |
30 | char *file; | 36 | char *file; |
31 | FILE *fp; | 37 | FILE *fp; |
32 | 38 | ||
33 | name = util_getword (arg, &sp); | 39 | if (imap4d_tokbuf_argc (tok) != 3) |
34 | util_unquote (&name); | 40 | return util_finish (command, RESP_BAD, "Invalid arguments"); |
35 | if (!name || *name == '\0') | 41 | |
36 | return util_finish (command, RESP_BAD, "Too few arguments"); | 42 | name = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1); |
37 | 43 | ||
38 | asprintf (&file, "%s/.mailboxlist", homedir); | 44 | asprintf (&file, "%s/.mailboxlist", homedir); |
39 | fp = fopen (file, "a"); | 45 | fp = fopen (file, "a"); | ... | ... |
1 | # -*- tcl -*- | 1 | # -*- tcl -*- |
2 | # This file is part of Mailutils testsuite. | 2 | # This file is part of Mailutils testsuite. |
3 | # Copyright (C) 2002, 2007 Free Software Foundation | 3 | # Copyright (C) 2002, 2007, 2008 Free Software Foundation |
4 | # | 4 | # |
5 | # This program is free software; you can redistribute it and/or modify | 5 | # This program is free software; you can redistribute it and/or modify |
6 | # it under the terms of the GNU General Public License as published by | 6 | # it under the terms of the GNU General Public License as published by |
... | @@ -20,7 +20,7 @@ | ... | @@ -20,7 +20,7 @@ |
20 | imap4d_start | 20 | imap4d_start |
21 | 21 | ||
22 | imap4d_test "CAPABILITY" \ | 22 | imap4d_test "CAPABILITY" \ |
23 | "CAPABILITY IMAP4rev1 NAMESPACE IDLE X-VERSION" \ | 23 | "CAPABILITY IMAP4rev1 NAMESPACE IDLE LITERAL+ X-VERSION" \ |
24 | "OK" | 24 | "OK" |
25 | imap4d_test "NOOP" | 25 | imap4d_test "NOOP" |
26 | 26 | ... | ... |
... | @@ -48,7 +48,7 @@ Hello Joe, do you think we can meet at 3:30 tomorrow? | ... | @@ -48,7 +48,7 @@ Hello Joe, do you think we can meet at 3:30 tomorrow? |
48 | 48 | ||
49 | " | 49 | " |
50 | 50 | ||
51 | imap4d_test -long "APPEND mbox 25-Aug-2002 18:00:00 +0200"\ | 51 | imap4d_test -long "APPEND mbox \"25-Aug-2002 18:00:00 +0200\""\ |
52 | "Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST) | 52 | "Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST) |
53 | From: Fred Foobar <foobar@Blurdybloop.COM> | 53 | From: Fred Foobar <foobar@Blurdybloop.COM> |
54 | Subject: afternoon meeting again | 54 | Subject: afternoon meeting again |
... | @@ -72,7 +72,7 @@ imap4d_test "SELECT mbox"\ | ... | @@ -72,7 +72,7 @@ imap4d_test "SELECT mbox"\ |
72 | "OK" | 72 | "OK" |
73 | 73 | ||
74 | imap4d_test "FETCH 2:3 BODY\[\]"\ | 74 | imap4d_test "FETCH 2:3 BODY\[\]"\ |
75 | "2 FETCH (FLAGS (\\Seen) BODY\[\] {310}"\ | 75 | "2 FETCH (FLAGS (\\Seen) BODY\[\] {312}"\ |
76 | -literal\ | 76 | -literal\ |
77 | "Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)"\ | 77 | "Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)"\ |
78 | "From: Fred Foobar <foobar@Blurdybloop.COM>"\ | 78 | "From: Fred Foobar <foobar@Blurdybloop.COM>"\ |
... | @@ -83,9 +83,10 @@ imap4d_test "FETCH 2:3 BODY\[\]"\ | ... | @@ -83,9 +83,10 @@ imap4d_test "FETCH 2:3 BODY\[\]"\ |
83 | "Content-Type: TEXT/PLAIN; CHARSET=US-ASCII"\ | 83 | "Content-Type: TEXT/PLAIN; CHARSET=US-ASCII"\ |
84 | ""\ | 84 | ""\ |
85 | "Hello Joe, do you think we can meet at 3:30 tomorrow?"\ | 85 | "Hello Joe, do you think we can meet at 3:30 tomorrow?"\ |
86 | ""\ | ||
86 | ")"\ | 87 | ")"\ |
87 | -noliteral\ | 88 | -noliteral\ |
88 | "3 FETCH (FLAGS (\\Seen) BODY\[\] {283}"\ | 89 | "3 FETCH (FLAGS (\\Seen) BODY\[\] {285}"\ |
89 | -literal\ | 90 | -literal\ |
90 | "Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)"\ | 91 | "Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)"\ |
91 | "From: Fred Foobar <foobar@Blurdybloop.COM>"\ | 92 | "From: Fred Foobar <foobar@Blurdybloop.COM>"\ | ... | ... |
... | @@ -37,7 +37,7 @@ imap4d_test "CREATE flat" | ... | @@ -37,7 +37,7 @@ imap4d_test "CREATE flat" |
37 | 37 | ||
38 | imap4d_test "CREATE en/to/tre" | 38 | imap4d_test "CREATE en/to/tre" |
39 | 39 | ||
40 | imap4d_test -long "APPEND en/to/tre 25-Aug-2002 18:00:00 +0200"\ | 40 | imap4d_test -long "APPEND en/to/tre \"25-Aug-2002 18:00:00 +0200\""\ |
41 | "Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST) | 41 | "Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST) |
42 | From: Fred Foobar <foobar@Blurdybloop.COM> | 42 | From: Fred Foobar <foobar@Blurdybloop.COM> |
43 | Subject: afternoon meeting again | 43 | Subject: afternoon meeting again |
... | @@ -65,7 +65,7 @@ imap4d_test "SELECT en/to/tre"\ | ... | @@ -65,7 +65,7 @@ imap4d_test "SELECT en/to/tre"\ |
65 | "OK \[READ-WRITE\] SELECT Completed" | 65 | "OK \[READ-WRITE\] SELECT Completed" |
66 | 66 | ||
67 | imap4d_test "FETCH 1 ALL"\ | 67 | imap4d_test "FETCH 1 ALL"\ |
68 | "1 FETCH (FLAGS (\\Recent) INTERNALDATE \"25-Aug-2002 16:00:00 +0000\" RFC822.SIZE 283 ENVELOPE (\"Mon, 7 Feb 1994 21:52:25 -0800 (PST)\" \"afternoon meeting again\" ((\"Fred Foobar\" NIL \"foobar\" \"Blurdybloop.COM\")) ((\"Fred Foobar\" NIL \"foobar\" \"Blurdybloop.COM\")) ((\"Fred Foobar\" NIL \"foobar\" \"Blurdybloop.COM\")) ((NIL NIL \"mooch\" \"owatagu.siam.edu\")) NIL NIL NIL \"<B27397-0200000@Blurdybloop.COM>\"))"\ | 68 | "1 FETCH (FLAGS (\\Recent) INTERNALDATE \"25-Aug-2002 16:00:00 +0000\" RFC822.SIZE 285 ENVELOPE (\"Mon, 7 Feb 1994 21:52:25 -0800 (PST)\" \"afternoon meeting again\" ((\"Fred Foobar\" NIL \"foobar\" \"Blurdybloop.COM\")) ((\"Fred Foobar\" NIL \"foobar\" \"Blurdybloop.COM\")) ((\"Fred Foobar\" NIL \"foobar\" \"Blurdybloop.COM\")) ((NIL NIL \"mooch\" \"owatagu.siam.edu\")) NIL NIL NIL \"<B27397-0200000@Blurdybloop.COM>\"))"\ |
69 | "OK" | 69 | "OK" |
70 | 70 | ||
71 | 71 | ... | ... |
... | @@ -165,7 +165,7 @@ imap4d_test "FETCH 1 BODY\[HEADER\]"\ | ... | @@ -165,7 +165,7 @@ imap4d_test "FETCH 1 BODY\[HEADER\]"\ |
165 | # The subset returned by HEADER.FIELDS contains only those header fields | 165 | # The subset returned by HEADER.FIELDS contains only those header fields |
166 | # with a field-name that matches one of the names in the list; | 166 | # with a field-name that matches one of the names in the list; |
167 | 167 | ||
168 | imap4d_test "FETCH 1 BODY\[HEADER.FIELDS FROM TO SUBJECT\]"\ | 168 | imap4d_test "FETCH 1 BODY\[HEADER.FIELDS (FROM TO SUBJECT)\]"\ |
169 | "1 FETCH (BODY\[HEADER.FIELDS (\"FROM\" \"TO\" \"SUBJECT\")\] {94}"\ | 169 | "1 FETCH (BODY\[HEADER.FIELDS (\"FROM\" \"TO\" \"SUBJECT\")\] {94}"\ |
170 | -literal\ | 170 | -literal\ |
171 | "FROM: Foo Bar <foobar@nonexistent.net>"\ | 171 | "FROM: Foo Bar <foobar@nonexistent.net>"\ |
... | @@ -178,7 +178,7 @@ imap4d_test "FETCH 1 BODY\[HEADER.FIELDS FROM TO SUBJECT\]"\ | ... | @@ -178,7 +178,7 @@ imap4d_test "FETCH 1 BODY\[HEADER.FIELDS FROM TO SUBJECT\]"\ |
178 | # similarly, the subset returned by HEADER.FIELDS.NOT contains only | 178 | # similarly, the subset returned by HEADER.FIELDS.NOT contains only |
179 | # the header fields with a non-matching field-name. | 179 | # the header fields with a non-matching field-name. |
180 | 180 | ||
181 | imap4d_test "FETCH 1 BODY\[HEADER.FIELDS.NOT FROM TO SUBJECT\]"\ | 181 | imap4d_test "FETCH 1 BODY\[HEADER.FIELDS.NOT (FROM TO SUBJECT)\]"\ |
182 | "1 FETCH (BODY\[HEADER.FIELDS.NOT (\"FROM\" \"TO\" \"SUBJECT\")\] {235}"\ | 182 | "1 FETCH (BODY\[HEADER.FIELDS.NOT (\"FROM\" \"TO\" \"SUBJECT\")\] {235}"\ |
183 | -literal\ | 183 | -literal\ |
184 | "Received: (from foobar@nonexistent.net) "\ | 184 | "Received: (from foobar@nonexistent.net) "\ |
... | @@ -330,8 +330,13 @@ imap4d_test "FETCH 3 BODY\[1.MIME\]"\ | ... | @@ -330,8 +330,13 @@ imap4d_test "FETCH 3 BODY\[1.MIME\]"\ |
330 | "OK" | 330 | "OK" |
331 | 331 | ||
332 | imap4d_test "FETCH 4 BODY\[2.2.1\]"\ | 332 | imap4d_test "FETCH 4 BODY\[2.2.1\]"\ |
333 | "4 FETCH (FLAGS (\\Seen) BODY\[2.2.1\] {490}"\ | 333 | "4 FETCH (FLAGS (\\Seen) BODY\[2.2.1\] {680}"\ |
334 | -literal\ | 334 | -literal\ |
335 | "Content-Type: application/octet-stream; name=\"msg.23\""\ | ||
336 | "Content-ID: <5122.1026510654.6@Mirddin.farlep.net>"\ | ||
337 | "Content-Description: Father William Part III"\ | ||
338 | "Content-Transfer-Encoding: base64"\ | ||
339 | ""\ | ||
335 | "YFlvdSBhcmUgb2xkLCcgc2FpZCB0aGUgeW91dGgsIGBhbmQgeW91ciBqYXdzIGFyZSB0b28gd2Vh"\ | 340 | "YFlvdSBhcmUgb2xkLCcgc2FpZCB0aGUgeW91dGgsIGBhbmQgeW91ciBqYXdzIGFyZSB0b28gd2Vh"\ |
336 | "awpGb3IgYW55dGhpbmcgdG91Z2hlciB0aGFuIHN1ZXQ7CllldCB5b3UgZmluaXNoZWQgdGhlIGdv"\ | 341 | "awpGb3IgYW55dGhpbmcgdG91Z2hlciB0aGFuIHN1ZXQ7CllldCB5b3UgZmluaXNoZWQgdGhlIGdv"\ |
337 | "b3NlLCB3aXRoIHRoZSBib25lcyBhbmQgdGhlIGJlYWstLQpQcmF5IGhvdyBkaWQgeW91IG1hbmFn"\ | 342 | "b3NlLCB3aXRoIHRoZSBib25lcyBhbmQgdGhlIGJlYWstLQpQcmF5IGhvdyBkaWQgeW91IG1hbmFn"\ | ... | ... |
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | 1 | /* GNU Mailutils -- a suite of utilities for electronic mail |
2 | Copyright (C) 1999, 2001, 2007 Free Software Foundation, Inc. | 2 | Copyright (C) 1999, 2001, 2007, 2008 Free Software Foundation, Inc. |
3 | 3 | ||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | 4 | GNU Mailutils is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU General Public License as published by | 5 | it under the terms of the GNU General Public License as published by |
... | @@ -24,36 +24,29 @@ | ... | @@ -24,36 +24,29 @@ |
24 | */ | 24 | */ |
25 | 25 | ||
26 | int | 26 | int |
27 | imap4d_uid (struct imap4d_command *command, char *arg) | 27 | imap4d_uid (struct imap4d_command *command, imap4d_tokbuf_t tok) |
28 | { | 28 | { |
29 | char *cmd; | 29 | char *cmd; |
30 | char *sp = NULL; | ||
31 | int rc = RESP_NO; | 30 | int rc = RESP_NO; |
32 | char buffer[64]; | 31 | char *err_text = "Completed"; |
32 | |||
33 | if (imap4d_tokbuf_argc (tok) < 3) | ||
34 | return util_finish (command, RESP_BAD, "Invalid arguments"); | ||
35 | |||
36 | cmd = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1); | ||
33 | 37 | ||
34 | cmd = util_getword (arg, &sp); | ||
35 | if (!cmd) | ||
36 | util_finish (command, RESP_BAD, "Too few args"); | ||
37 | if (strcasecmp (cmd, "FETCH") == 0) | 38 | if (strcasecmp (cmd, "FETCH") == 0) |
38 | { | 39 | rc = imap4d_fetch0 (tok, 1, &err_text); |
39 | rc = imap4d_fetch0 (sp, 1, buffer, sizeof buffer); | ||
40 | } | ||
41 | else if (strcasecmp (cmd, "COPY") == 0) | 40 | else if (strcasecmp (cmd, "COPY") == 0) |
42 | { | 41 | rc = imap4d_copy0 (tok, 1, &err_text); |
43 | rc = imap4d_copy0 (sp, 1, buffer, sizeof buffer); | ||
44 | } | ||
45 | else if (strcasecmp (cmd, "STORE") == 0) | 42 | else if (strcasecmp (cmd, "STORE") == 0) |
46 | { | 43 | rc = imap4d_store0 (tok, 1, &err_text); |
47 | rc = imap4d_store0 (sp, 1, buffer, sizeof buffer); | ||
48 | } | ||
49 | else if (strcasecmp (cmd, "SEARCH") == 0) | 44 | else if (strcasecmp (cmd, "SEARCH") == 0) |
50 | { | 45 | rc = imap4d_search0 (tok, 1, &err_text); |
51 | rc = imap4d_search0 (sp, 1, buffer, sizeof buffer); | ||
52 | } | ||
53 | else | 46 | else |
54 | { | 47 | { |
55 | snprintf (buffer, sizeof buffer, "Error uknown uid command"); | 48 | err_text = "Uknown uid command"; |
56 | rc = RESP_BAD; | 49 | rc = RESP_BAD; |
57 | } | 50 | } |
58 | return util_finish (command, rc, "%s %s", cmd, buffer); | 51 | return util_finish (command, rc, "%s %s", cmd, err_text); |
59 | } | 52 | } | ... | ... |
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | 1 | /* GNU Mailutils -- a suite of utilities for electronic mail |
2 | Copyright (C) 1999, 2001, 2007 Free Software Foundation, Inc. | 2 | Copyright (C) 1999, 2001, 2007, 2008 Free Software Foundation, Inc. |
3 | 3 | ||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | 4 | GNU Mailutils is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU General Public License as published by | 5 | it under the terms of the GNU General Public License as published by |
... | @@ -71,19 +71,34 @@ unsubscribe (struct scan_data *data, char *name) | ... | @@ -71,19 +71,34 @@ unsubscribe (struct scan_data *data, char *name) |
71 | return 0; | 71 | return 0; |
72 | } | 72 | } |
73 | 73 | ||
74 | /* | ||
75 | 6.3.7. UNSUBSCRIBE Command | ||
76 | |||
77 | Arguments: mailbox name | ||
78 | |||
79 | Responses: no specific responses for this command | ||
80 | |||
81 | Result: OK - unsubscribe completed | ||
82 | NO - unsubscribe failure: can't unsubscribe that name | ||
83 | BAD - command unknown or arguments invalid | ||
84 | |||
85 | The UNSUBSCRIBE command removes the specified mailbox name from | ||
86 | the server's set of "active" or "subscribed" mailboxes as returned | ||
87 | by the LSUB command. This command returns a tagged OK response | ||
88 | only if the unsubscription is successful. | ||
89 | */ | ||
74 | int | 90 | int |
75 | imap4d_unsubscribe (struct imap4d_command *command, char *arg) | 91 | imap4d_unsubscribe (struct imap4d_command *command, imap4d_tokbuf_t tok) |
76 | { | 92 | { |
77 | char *sp = NULL; | ||
78 | char *name; | 93 | char *name; |
79 | char *file; | 94 | char *file; |
80 | struct scan_data sd; | 95 | struct scan_data sd; |
81 | int rc; | 96 | int rc; |
82 | 97 | ||
83 | name = util_getword (arg, &sp); | 98 | if (imap4d_tokbuf_argc (tok) != 3) |
84 | util_unquote (&name); | 99 | return util_finish (command, RESP_BAD, "Invalid arguments"); |
85 | if (!name || *name == '\0') | 100 | |
86 | return util_finish (command, RESP_BAD, "Too few arguments"); | 101 | name = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1); |
87 | 102 | ||
88 | asprintf (&file, "%s/.mailboxlist", homedir); | 103 | asprintf (&file, "%s/.mailboxlist", homedir); |
89 | sd.result = 0; | 104 | sd.result = 0; | ... | ... |
... | @@ -25,92 +25,6 @@ static mu_stream_t ostream; | ... | @@ -25,92 +25,6 @@ static mu_stream_t ostream; |
25 | static int add2set (size_t **, int *, unsigned long); | 25 | static int add2set (size_t **, int *, unsigned long); |
26 | static const char *sc2string (int); | 26 | static const char *sc2string (int); |
27 | 27 | ||
28 | /* Get the next space/CR/NL separated word, some words are between double | ||
29 | quotes, strtok() cannot handle it. */ | ||
30 | char * | ||
31 | util_getword (char *s, char **save) | ||
32 | { | ||
33 | return util_getitem (s, " \r\n", save); | ||
34 | } | ||
35 | |||
36 | /* Take care of words between double quotes. */ | ||
37 | char * | ||
38 | util_getitem (char *s, const char *delim, char **save) | ||
39 | { | ||
40 | { | ||
41 | char *p; | ||
42 | if ((p = s) || (p = *save)) | ||
43 | { | ||
44 | while (isspace ((unsigned) *p)) | ||
45 | p++; | ||
46 | if (*p == '"') | ||
47 | { | ||
48 | s = p; | ||
49 | p++; | ||
50 | while (*p && *p != '"') | ||
51 | p++; | ||
52 | if (*p == '"') | ||
53 | p++; | ||
54 | *save = (*p) ? p + 1 : p; | ||
55 | *p = '\0'; | ||
56 | return s; | ||
57 | } | ||
58 | } | ||
59 | } | ||
60 | return strtok_r (s, delim, save); | ||
61 | } | ||
62 | |||
63 | /* Stop at the first char that represents an IMAP4 special character. */ | ||
64 | int | ||
65 | util_token (char *buf, size_t len, char **ptr) | ||
66 | { | ||
67 | char *start = *ptr; | ||
68 | size_t i; | ||
69 | /* Skip leading space. */ | ||
70 | while (**ptr && **ptr == ' ') | ||
71 | (*ptr)++; | ||
72 | |||
73 | /* Break the string by token, i.e when we reconize IMAP special | ||
74 | atoms we stop and send it. */ | ||
75 | for (i = 1; **ptr && i < len; (*ptr)++, buf++, i++) | ||
76 | { | ||
77 | if (**ptr == ' ' || **ptr == '.' | ||
78 | || **ptr == '(' || **ptr == ')' | ||
79 | || **ptr == '[' || **ptr == ']' | ||
80 | || **ptr == '<' || **ptr == '>' || **ptr == '\r' || **ptr == '\n') | ||
81 | { | ||
82 | /* Advance. */ | ||
83 | if (start == (*ptr)) | ||
84 | (*ptr)++; | ||
85 | break; | ||
86 | } | ||
87 | *buf = **ptr; | ||
88 | } | ||
89 | *buf = '\0'; | ||
90 | /* Skip trailing space. */ | ||
91 | while (**ptr && **ptr == ' ') | ||
92 | (*ptr)++; | ||
93 | return *ptr - start; | ||
94 | } | ||
95 | |||
96 | /* Remove the surrounding double quotes. */ | ||
97 | /* FIXME: Check if the quote was escaped and ignore it. */ | ||
98 | void | ||
99 | util_unquote (char **ptr) | ||
100 | { | ||
101 | char *s = *ptr; | ||
102 | size_t len; | ||
103 | if (s && *s == '"' && (len = strlen (s)) > 1 && s[len - 1] == '"') | ||
104 | { | ||
105 | char *p = ++s; | ||
106 | while (*p && *p != '"') | ||
107 | p++; | ||
108 | if (*p == '"') | ||
109 | *p = '\0'; | ||
110 | } | ||
111 | *ptr = s; | ||
112 | } | ||
113 | |||
114 | /* NOTE: Allocates Memory. */ | 28 | /* NOTE: Allocates Memory. */ |
115 | /* Expand: ~ --> /home/user and to ~guest --> /home/guest. */ | 29 | /* Expand: ~ --> /home/user and to ~guest --> /home/guest. */ |
116 | char * | 30 | char * |
... | @@ -266,8 +180,8 @@ util_msgset (char *s, size_t ** set, int *n, int isuid) | ... | @@ -266,8 +180,8 @@ util_msgset (char *s, size_t ** set, int *n, int isuid) |
266 | s++; | 180 | s++; |
267 | break; | 181 | break; |
268 | 182 | ||
269 | /* As a convenience. '*' is provided to refer to the highest message | 183 | /* As a convenience. '*' is provided to refer to the highest |
270 | number int the mailbox: | 184 | message number int the mailbox: |
271 | 5:* --> 5 6 7 8 | 185 | 5:* --> 5 6 7 8 |
272 | */ | 186 | */ |
273 | case '*': | 187 | case '*': |
... | @@ -479,143 +393,30 @@ util_finish (struct imap4d_command *command, int rc, const char *format, ...) | ... | @@ -479,143 +393,30 @@ util_finish (struct imap4d_command *command, int rc, const char *format, ...) |
479 | return status; | 393 | return status; |
480 | } | 394 | } |
481 | 395 | ||
482 | /* Clients are allowed to send literal string to the servers. this | ||
483 | means that it can occur everywhere where a string is allowed. | ||
484 | A literal is a sequence of zero or more octets (including CR and LF) | ||
485 | prefix-quoted with an octet count in the form of an open brace ("{"), | ||
486 | the number of octets, close brace ("}"), and CRLF. | ||
487 | */ | ||
488 | char * | ||
489 | imap4d_readline (void) | ||
490 | { | ||
491 | char buffer[512]; | ||
492 | size_t len; | ||
493 | long number = 0; | ||
494 | size_t total = 0; | ||
495 | char *line = malloc (1); | ||
496 | |||
497 | if (!line) | ||
498 | imap4d_bye (ERR_NO_MEM); | ||
499 | |||
500 | line[0] = '\0'; /* start with a empty string. */ | ||
501 | do | ||
502 | { | ||
503 | size_t sz; | ||
504 | int rc; | ||
505 | |||
506 | alarm (idle_timeout); | ||
507 | rc = mu_stream_sequential_readline (istream, buffer, sizeof (buffer), &sz); | ||
508 | if (sz == 0) | ||
509 | { | ||
510 | mu_diag_output (MU_DIAG_INFO, _("Unexpected eof on input")); | ||
511 | imap4d_bye (ERR_NO_OFILE); | ||
512 | } | ||
513 | else if (rc) | ||
514 | { | ||
515 | const char *p; | ||
516 | if (mu_stream_strerror (istream, &p)) | ||
517 | p = strerror (errno); | ||
518 | |||
519 | mu_diag_output (MU_DIAG_INFO, _("Error reading from input file: %s"), p); | ||
520 | imap4d_bye (ERR_NO_OFILE); | ||
521 | } | ||
522 | alarm (0); | ||
523 | |||
524 | len = strlen (buffer); | ||
525 | /* If we were in a litteral substract. We have to do it here since the CR | ||
526 | is part of the count in a literal. */ | ||
527 | if (number) | ||
528 | number -= len; | ||
529 | |||
530 | /* Remove CR. */ | ||
531 | if (len > 1 && buffer[len - 1] == '\n') | ||
532 | { | ||
533 | if (buffer[len - 2] == '\r') | ||
534 | { | ||
535 | buffer[len - 2] = '\n'; | ||
536 | buffer[len - 1] = '\0'; | ||
537 | } | ||
538 | } | ||
539 | line = realloc (line, total + len + 1); | ||
540 | if (!line) | ||
541 | imap4d_bye (ERR_NO_MEM); | ||
542 | strcat (line, buffer); | ||
543 | |||
544 | total = strlen (line); | ||
545 | |||
546 | /* I observe some client requesting long FETCH operations since, I did | ||
547 | not see any limit in the command length in the RFC, catch things | ||
548 | here. */ | ||
549 | /* Check that we do have a terminated NL line and we are not retrieving | ||
550 | a literal. If we don't continue the read. */ | ||
551 | if (number <= 0 && total && line[total - 1] != '\n') | ||
552 | continue; | ||
553 | |||
554 | /* Check if the client try to send a literal and make sure we are not | ||
555 | already retrieving a literal. */ | ||
556 | if (number <= 0 && len > 2) | ||
557 | { | ||
558 | size_t n = total - 1; /* C arrays are 0-based. */ | ||
559 | /* A literal is this "{number}\n". The CR is already strip. */ | ||
560 | if (line[n] == '\n' && line[n - 1] == '}') | ||
561 | { | ||
562 | /* Search for the matching bracket. */ | ||
563 | while (n && line[n] != '{') | ||
564 | n--; | ||
565 | if (line[n] == '{') | ||
566 | { | ||
567 | char *sp = NULL; | ||
568 | /* Truncate where the literal number was. */ | ||
569 | line[n] = '\0'; | ||
570 | number = strtoul (line + n + 1, &sp, 10); | ||
571 | /* Client can ask for non synchronise literal, | ||
572 | if a '+' is append to the octet count. */ | ||
573 | if (*sp != '+') | ||
574 | util_send ("+ GO AHEAD\r\n"); | ||
575 | } | ||
576 | } | ||
577 | } | ||
578 | } | ||
579 | while (number > 0 || (total && line[total - 1] != '\n')); | ||
580 | if (imap4d_transcript) | ||
581 | mu_diag_output (MU_DIAG_DEBUG, "recv: %s", line); | ||
582 | return line; | ||
583 | } | ||
584 | |||
585 | char * | ||
586 | imap4d_readline_ex (void) | ||
587 | { | ||
588 | int len; | ||
589 | char *s = imap4d_readline (); | ||
590 | |||
591 | if (s && (len = strlen (s)) > 0 && s[len - 1] == '\n') | ||
592 | s[len - 1] = 0; | ||
593 | return s; | ||
594 | } | ||
595 | |||
596 | int | 396 | int |
597 | util_do_command (char *prompt) | 397 | util_do_command (imap4d_tokbuf_t tok) |
598 | { | 398 | { |
599 | char *sp = NULL, *tag, *cmd; | 399 | char *tag, *cmd; |
600 | struct imap4d_command *command; | 400 | struct imap4d_command *command; |
601 | static struct imap4d_command nullcommand; | 401 | static struct imap4d_command nullcommand; |
602 | size_t len; | 402 | int argc = imap4d_tokbuf_argc (tok); |
603 | 403 | ||
604 | tag = util_getword (prompt, &sp); | 404 | if (argc == 0) |
605 | cmd = util_getword (NULL, &sp); | ||
606 | if (!tag) | ||
607 | { | 405 | { |
608 | nullcommand.name = ""; | 406 | nullcommand.name = ""; |
609 | nullcommand.tag = (char *) "*"; | 407 | nullcommand.tag = (char *) "*"; |
610 | return util_finish (&nullcommand, RESP_BAD, "Null command"); | 408 | return util_finish (&nullcommand, RESP_BAD, "Null command"); |
611 | } | 409 | } |
612 | else if (!cmd) | 410 | else if (argc == 1) |
613 | { | 411 | { |
614 | nullcommand.name = ""; | 412 | nullcommand.name = ""; |
615 | nullcommand.tag = tag; | 413 | nullcommand.tag = tag; |
616 | return util_finish (&nullcommand, RESP_BAD, "Missing arguments"); | 414 | return util_finish (&nullcommand, RESP_BAD, "Missing command"); |
617 | } | 415 | } |
618 | 416 | ||
417 | tag = imap4d_tokbuf_getarg (tok, 0); | ||
418 | cmd = imap4d_tokbuf_getarg (tok, 1); | ||
419 | |||
619 | command = util_getcommand (cmd, imap4d_command_table); | 420 | command = util_getcommand (cmd, imap4d_command_table); |
620 | if (command == NULL) | 421 | if (command == NULL) |
621 | { | 422 | { |
... | @@ -629,10 +430,7 @@ util_do_command (char *prompt) | ... | @@ -629,10 +430,7 @@ util_do_command (char *prompt) |
629 | if (command->states && (command->states & state) == 0) | 430 | if (command->states && (command->states & state) == 0) |
630 | return util_finish (command, RESP_BAD, "Wrong state"); | 431 | return util_finish (command, RESP_BAD, "Wrong state"); |
631 | 432 | ||
632 | len = strlen (sp); | 433 | return command->func (command, tok); |
633 | if (len && sp[len - 1] == '\n') | ||
634 | sp[len - 1] = '\0'; | ||
635 | return command->func (command, sp); | ||
636 | } | 434 | } |
637 | 435 | ||
638 | int | 436 | int |
... | @@ -702,7 +500,7 @@ add2set (size_t ** set, int *n, unsigned long val) | ... | @@ -702,7 +500,7 @@ add2set (size_t ** set, int *n, unsigned long val) |
702 | } | 500 | } |
703 | 501 | ||
704 | int | 502 | int |
705 | util_parse_internal_date0 (char *date, time_t * timep, char **endp) | 503 | util_parse_internal_date (char *date, time_t * timep) |
706 | { | 504 | { |
707 | struct tm tm; | 505 | struct tm tm; |
708 | mu_timezone tz; | 506 | mu_timezone tz; |
... | @@ -717,19 +515,10 @@ util_parse_internal_date0 (char *date, time_t * timep, char **endp) | ... | @@ -717,19 +515,10 @@ util_parse_internal_date0 (char *date, time_t * timep, char **endp) |
717 | return 2; | 515 | return 2; |
718 | 516 | ||
719 | *timep = time; | 517 | *timep = time; |
720 | if (endp) | ||
721 | *endp = *datep; | ||
722 | return 0; | 518 | return 0; |
723 | } | 519 | } |
724 | 520 | ||
725 | int | 521 | int |
726 | util_parse_internal_date (char *date, time_t * timep) | ||
727 | { | ||
728 | return util_parse_internal_date0 (date, timep, NULL); | ||
729 | } | ||
730 | |||
731 | |||
732 | int | ||
733 | util_parse_822_date (const char *date, time_t * timep) | 522 | util_parse_822_date (const char *date, time_t * timep) |
734 | { | 523 | { |
735 | struct tm tm; | 524 | struct tm tm; |
... | @@ -875,35 +664,6 @@ util_attribute_matches_flag (mu_attribute_t attr, const char *item) | ... | @@ -875,35 +664,6 @@ util_attribute_matches_flag (mu_attribute_t attr, const char *item) |
875 | return flags & mask; | 664 | return flags & mask; |
876 | } | 665 | } |
877 | 666 | ||
878 | |||
879 | int | ||
880 | util_parse_attributes (char *items, char **save, int *flags) | ||
881 | { | ||
882 | int rc = 0; | ||
883 | |||
884 | *flags = 0; | ||
885 | while (*items) | ||
886 | { | ||
887 | int type = 0; | ||
888 | char item[64] = ""; | ||
889 | |||
890 | util_token (item, sizeof (item), &items); | ||
891 | if (!util_attribute_to_type (item, &type)) | ||
892 | *flags |= type; | ||
893 | /*FIXME: else? */ | ||
894 | |||
895 | if (*items == ')') | ||
896 | { | ||
897 | items++; | ||
898 | rc = 0; | ||
899 | break; | ||
900 | } | ||
901 | } | ||
902 | |||
903 | *save = items; | ||
904 | return rc; | ||
905 | } | ||
906 | |||
907 | int | 667 | int |
908 | util_base64_encode (const unsigned char *input, size_t input_len, | 668 | util_base64_encode (const unsigned char *input, size_t input_len, |
909 | unsigned char **output, size_t * output_len) | 669 | unsigned char **output, size_t * output_len) |
... | @@ -1324,3 +1084,327 @@ is_atom (const char *s) | ... | @@ -1324,3 +1084,327 @@ is_atom (const char *s) |
1324 | return 1; | 1084 | return 1; |
1325 | } | 1085 | } |
1326 | 1086 | ||
1087 | |||
1088 | static size_t | ||
1089 | remove_cr (char *line, size_t len) | ||
1090 | { | ||
1091 | char *prev = NULL; | ||
1092 | size_t rlen = len; | ||
1093 | char *p; | ||
1094 | while ((p = memchr (line, '\r', len))) | ||
1095 | { | ||
1096 | if (prev) | ||
1097 | { | ||
1098 | memmove (prev, line, p - line); | ||
1099 | prev += p - line; | ||
1100 | } | ||
1101 | else | ||
1102 | prev = p; | ||
1103 | rlen--; | ||
1104 | len -= p - line + 1; | ||
1105 | line = p + 1; | ||
1106 | } | ||
1107 | if (prev) | ||
1108 | memmove (prev, line, len); | ||
1109 | return rlen; | ||
1110 | } | ||
1111 | |||
1112 | static size_t | ||
1113 | unquote (char *line, size_t len) | ||
1114 | { | ||
1115 | char *prev = NULL; | ||
1116 | size_t rlen = len; | ||
1117 | char *p; | ||
1118 | int off = 0; | ||
1119 | while ((p = memchr (line + off, '\\', len - off))) | ||
1120 | { | ||
1121 | if (p[1] == '\\' || p[1] == '"') | ||
1122 | { | ||
1123 | if (prev) | ||
1124 | { | ||
1125 | memmove (prev, line, p - line); | ||
1126 | prev += p - line; | ||
1127 | } | ||
1128 | else | ||
1129 | prev = p; | ||
1130 | off = p[1] == '\\'; | ||
1131 | rlen--; | ||
1132 | len -= p - line + 1; | ||
1133 | line = p + 1; | ||
1134 | } | ||
1135 | } | ||
1136 | if (prev) | ||
1137 | memmove (prev, line, len); | ||
1138 | return rlen; | ||
1139 | } | ||
1140 | |||
1141 | struct imap4d_tokbuf { | ||
1142 | char *buffer; | ||
1143 | size_t size; | ||
1144 | size_t level; | ||
1145 | int argc; | ||
1146 | int argmax; | ||
1147 | size_t *argp; | ||
1148 | }; | ||
1149 | |||
1150 | struct imap4d_tokbuf * | ||
1151 | imap4d_tokbuf_init () | ||
1152 | { | ||
1153 | struct imap4d_tokbuf *tok = malloc (sizeof (tok[0])); | ||
1154 | if (!tok) | ||
1155 | imap4d_bye (ERR_NO_MEM); | ||
1156 | memset (tok, 0, sizeof (*tok)); | ||
1157 | return tok; | ||
1158 | } | ||
1159 | |||
1160 | void | ||
1161 | imap4d_tokbuf_destroy (struct imap4d_tokbuf **ptok) | ||
1162 | { | ||
1163 | struct imap4d_tokbuf *tok = *ptok; | ||
1164 | free (tok->buffer); | ||
1165 | free (tok->argp); | ||
1166 | free (tok); | ||
1167 | *ptok = NULL; | ||
1168 | } | ||
1169 | |||
1170 | int | ||
1171 | imap4d_tokbuf_argc (struct imap4d_tokbuf *tok) | ||
1172 | { | ||
1173 | return tok->argc; | ||
1174 | } | ||
1175 | |||
1176 | char * | ||
1177 | imap4d_tokbuf_getarg (struct imap4d_tokbuf *tok, int n) | ||
1178 | { | ||
1179 | if (n < tok->argc) | ||
1180 | return tok->buffer + tok->argp[n]; | ||
1181 | return NULL; | ||
1182 | } | ||
1183 | |||
1184 | static void | ||
1185 | imap4d_tokbuf_unquote (struct imap4d_tokbuf *tok, size_t *poff, size_t *plen) | ||
1186 | { | ||
1187 | char *buf = tok->buffer + *poff; | ||
1188 | if (buf[0] == '"' && buf[*plen - 1] == '"') | ||
1189 | { | ||
1190 | ++*poff; | ||
1191 | *plen = unquote (buf + 1, *plen - 1); | ||
1192 | } | ||
1193 | } | ||
1194 | |||
1195 | static void | ||
1196 | imap4d_tokbuf_expand (struct imap4d_tokbuf *tok, size_t size) | ||
1197 | { | ||
1198 | if (tok->size - tok->level < size) | ||
1199 | { | ||
1200 | tok->size = tok->level + size; | ||
1201 | tok->buffer = realloc (tok->buffer, tok->size); | ||
1202 | if (!tok->buffer) | ||
1203 | imap4d_bye (ERR_NO_MEM); | ||
1204 | } | ||
1205 | } | ||
1206 | |||
1207 | #define ISDELIM(c) (strchr (".()[]<>", (c)) != NULL) | ||
1208 | #define ISWS(c) (c == ' ' || c == '\t') | ||
1209 | |||
1210 | int | ||
1211 | util_isdelim (const char *str) | ||
1212 | { | ||
1213 | return str[1] == 0 && ISDELIM (str[0]); | ||
1214 | } | ||
1215 | |||
1216 | static size_t | ||
1217 | insert_nul (struct imap4d_tokbuf *tok, size_t off) | ||
1218 | { | ||
1219 | imap4d_tokbuf_expand (tok, 1); | ||
1220 | if (off < tok->level) | ||
1221 | { | ||
1222 | memmove (tok->buffer + off + 1, tok->buffer + off, tok->level - off); | ||
1223 | tok->level++; | ||
1224 | } | ||
1225 | tok->buffer[off] = 0; | ||
1226 | return off + 1; | ||
1227 | } | ||
1228 | |||
1229 | static size_t | ||
1230 | gettok (struct imap4d_tokbuf *tok, size_t off) | ||
1231 | { | ||
1232 | char *buf = tok->buffer; | ||
1233 | |||
1234 | while (off < tok->level && ISWS (buf[off])) | ||
1235 | off++; | ||
1236 | |||
1237 | if (tok->argc == tok->argmax) | ||
1238 | { | ||
1239 | if (tok->argmax == 0) | ||
1240 | tok->argmax = 16; | ||
1241 | else | ||
1242 | tok->argmax *= 2; | ||
1243 | tok->argp = realloc(tok->argp, tok->argmax * sizeof (tok->argp[0])); | ||
1244 | if (!tok->argp) | ||
1245 | imap4d_bye (ERR_NO_MEM); | ||
1246 | } | ||
1247 | |||
1248 | if (buf[off] == '"') | ||
1249 | { | ||
1250 | char *start = buf + off + 1; | ||
1251 | char *p = NULL; | ||
1252 | |||
1253 | while (*start && (p = strchr (start, '"'))) | ||
1254 | { | ||
1255 | if (p == start || p[-1] != '\\') | ||
1256 | break; | ||
1257 | start = p + 1; | ||
1258 | } | ||
1259 | |||
1260 | if (p) | ||
1261 | { | ||
1262 | size_t len; | ||
1263 | off++; | ||
1264 | len = unquote(buf + off, p - (buf + off)); | ||
1265 | buf[off + len] = 0; | ||
1266 | tok->argp[tok->argc++] = off; | ||
1267 | return p - buf + 1; | ||
1268 | } | ||
1269 | } | ||
1270 | |||
1271 | tok->argp[tok->argc++] = off; | ||
1272 | if (ISDELIM (buf[off])) | ||
1273 | return insert_nul (tok, off + 1); | ||
1274 | |||
1275 | while (off < tok->level && !ISWS (buf[off])) | ||
1276 | { | ||
1277 | if (ISDELIM (buf[off])) | ||
1278 | return insert_nul (tok, off); | ||
1279 | off++; | ||
1280 | } | ||
1281 | buf[off++] = 0; | ||
1282 | |||
1283 | return off; | ||
1284 | } | ||
1285 | |||
1286 | static void | ||
1287 | imap4d_tokbuf_tokenize (struct imap4d_tokbuf *tok, size_t off) | ||
1288 | { | ||
1289 | while (off < tok->level) | ||
1290 | off = gettok (tok, off); | ||
1291 | } | ||
1292 | |||
1293 | static void | ||
1294 | check_input_err (int rc, size_t sz) | ||
1295 | { | ||
1296 | if (rc) | ||
1297 | { | ||
1298 | const char *p; | ||
1299 | if (mu_stream_strerror (istream, &p)) | ||
1300 | p = mu_strerror (rc); | ||
1301 | |||
1302 | mu_diag_output (MU_DIAG_INFO, | ||
1303 | _("Error reading from input file: %s"), p); | ||
1304 | imap4d_bye (ERR_NO_OFILE); | ||
1305 | } | ||
1306 | else if (sz == 0) | ||
1307 | { | ||
1308 | mu_diag_output (MU_DIAG_INFO, _("Unexpected eof on input")); | ||
1309 | imap4d_bye (ERR_NO_OFILE); | ||
1310 | } | ||
1311 | } | ||
1312 | |||
1313 | static size_t | ||
1314 | imap4d_tokbuf_getline (struct imap4d_tokbuf *tok) | ||
1315 | { | ||
1316 | char buffer[512]; | ||
1317 | size_t level = tok->level; | ||
1318 | |||
1319 | do | ||
1320 | { | ||
1321 | size_t len; | ||
1322 | int rc; | ||
1323 | |||
1324 | rc = mu_stream_sequential_readline (istream, | ||
1325 | buffer, sizeof (buffer), &len); | ||
1326 | check_input_err (rc, len); | ||
1327 | imap4d_tokbuf_expand (tok, len); | ||
1328 | |||
1329 | memcpy (tok->buffer + tok->level, buffer, len); | ||
1330 | tok->level += len; | ||
1331 | } | ||
1332 | while (tok->level && tok->buffer[tok->level - 1] != '\n'); | ||
1333 | tok->buffer[--tok->level] = 0; | ||
1334 | if (tok->buffer[tok->level - 1] == '\r') | ||
1335 | tok->buffer[--tok->level] = 0; | ||
1336 | return level; | ||
1337 | } | ||
1338 | |||
1339 | void | ||
1340 | imap4d_readline (struct imap4d_tokbuf *tok) | ||
1341 | { | ||
1342 | tok->argc = 0; | ||
1343 | for (;;) | ||
1344 | { | ||
1345 | char *last_arg; | ||
1346 | size_t off = imap4d_tokbuf_getline (tok); | ||
1347 | imap4d_tokbuf_tokenize (tok, off); | ||
1348 | last_arg = tok->buffer + tok->argp[tok->argc - 1]; | ||
1349 | if (last_arg[0] == '{' && last_arg[strlen(last_arg)-1] == '}') | ||
1350 | { | ||
1351 | int rc; | ||
1352 | unsigned long number; | ||
1353 | char *sp = NULL; | ||
1354 | char *buf; | ||
1355 | size_t len; | ||
1356 | |||
1357 | number = strtoul (last_arg + 1, &sp, 10); | ||
1358 | /* Client can ask for non-synchronised literal, | ||
1359 | if a '+' is appended to the octet count. */ | ||
1360 | if (*sp == '}') | ||
1361 | util_send ("+ GO AHEAD\r\n"); | ||
1362 | else if (*sp != '+') | ||
1363 | break; | ||
1364 | imap4d_tokbuf_expand (tok, number + 1); | ||
1365 | off = tok->level; | ||
1366 | buf = tok->buffer + off; | ||
1367 | rc = mu_stream_sequential_read (istream, buf, number, &len); | ||
1368 | check_input_err (rc, len); | ||
1369 | len = remove_cr (buf, len); | ||
1370 | imap4d_tokbuf_unquote (tok, &off, &len); | ||
1371 | tok->level += len; | ||
1372 | tok->buffer[tok->level++] = 0; | ||
1373 | tok->argp[tok->argc - 1] = off; | ||
1374 | if (buf[len-1] != '\n') | ||
1375 | continue; | ||
1376 | } | ||
1377 | break; | ||
1378 | } | ||
1379 | } | ||
1380 | |||
1381 | struct imap4d_tokbuf * | ||
1382 | imap4d_tokbuf_from_string (char *str) | ||
1383 | { | ||
1384 | struct imap4d_tokbuf *tok = imap4d_tokbuf_init (); | ||
1385 | tok->buffer = strdup (str); | ||
1386 | if (!tok->buffer) | ||
1387 | imap4d_bye (ERR_NO_MEM); | ||
1388 | tok->level = strlen (str); | ||
1389 | tok->size = tok->level + 1; | ||
1390 | imap4d_tokbuf_tokenize (tok, 0); | ||
1391 | return tok; | ||
1392 | } | ||
1393 | |||
1394 | int | ||
1395 | imap4d_getline (char **pbuf, size_t *psize, size_t *pnbytes) | ||
1396 | { | ||
1397 | size_t len; | ||
1398 | int rc = mu_stream_sequential_getline (istream, pbuf, psize, &len); | ||
1399 | if (rc == 0) | ||
1400 | { | ||
1401 | char *s = *pbuf; | ||
1402 | if (s && len > 0 && s[len - 1] == '\n') | ||
1403 | s[--len] = 0; | ||
1404 | if (s && len > 0 && s[len - 1] == '\r') | ||
1405 | s[--len] = 0; | ||
1406 | if (pnbytes) | ||
1407 | *pnbytes = len; | ||
1408 | } | ||
1409 | return rc; | ||
1410 | } | ... | ... |
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | 1 | /* GNU Mailutils -- a suite of utilities for electronic mail |
2 | Copyright (C) 1999, 2001, 2007 Free Software Foundation, Inc. | 2 | Copyright (C) 1999, 2001, 2007, 2008 Free Software Foundation, Inc. |
3 | 3 | ||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | 4 | GNU Mailutils is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU General Public License as published by | 5 | it under the terms of the GNU General Public License as published by |
... | @@ -19,8 +19,10 @@ | ... | @@ -19,8 +19,10 @@ |
19 | #include "imap4d.h" | 19 | #include "imap4d.h" |
20 | 20 | ||
21 | int | 21 | int |
22 | imap4d_version (struct imap4d_command *command, char *arg) | 22 | imap4d_version (struct imap4d_command *command, imap4d_tokbuf_t tok) |
23 | { | 23 | { |
24 | if (imap4d_tokbuf_argc (tok) != 2) | ||
25 | return util_finish (command, RESP_BAD, "Invalid arguments"); | ||
24 | util_send ("* %s GNU %s\r\n", command->name, program_version); | 26 | util_send ("* %s GNU %s\r\n", command->name, program_version); |
25 | return util_finish (command, RESP_OK, "Completed"); | 27 | return util_finish (command, RESP_OK, "Completed"); |
26 | } | 28 | } | ... | ... |
... | @@ -145,7 +145,7 @@ mail_tmp_finish (struct mail_tmp *mtmp, mu_mailbox_t *mbox) | ... | @@ -145,7 +145,7 @@ mail_tmp_finish (struct mail_tmp *mtmp, mu_mailbox_t *mbox) |
145 | } | 145 | } |
146 | 146 | ||
147 | mu_stream_flush (mtmp->stream); | 147 | mu_stream_flush (mtmp->stream); |
148 | if ((status = mu_mailbox_create (mbox, "/dev/null")) | 148 | if ((status = mu_mailbox_create (mbox, "mbox:/dev/null")) |
149 | || (status = mu_mailbox_open (*mbox, MU_STREAM_READ)) | 149 | || (status = mu_mailbox_open (*mbox, MU_STREAM_READ)) |
150 | || (status = mu_mailbox_set_stream (*mbox, mtmp->stream))) | 150 | || (status = mu_mailbox_set_stream (*mbox, mtmp->stream))) |
151 | { | 151 | { | ... | ... |
... | @@ -51,7 +51,7 @@ _memory_destroy (mu_stream_t stream) | ... | @@ -51,7 +51,7 @@ _memory_destroy (mu_stream_t stream) |
51 | struct _memory_stream *mfs = mu_stream_get_owner (stream); | 51 | struct _memory_stream *mfs = mu_stream_get_owner (stream); |
52 | if (mfs && mfs->ptr != NULL) | 52 | if (mfs && mfs->ptr != NULL) |
53 | free (mfs->ptr); | 53 | free (mfs->ptr); |
54 | if(mfs->filename) | 54 | if (mfs->filename) |
55 | free (mfs->filename); | 55 | free (mfs->filename); |
56 | free (mfs); | 56 | free (mfs); |
57 | } | 57 | } | ... | ... |
-
Please register or sign in to post a comment