Allow for "INBOX." namespace.
* imap4d/imap4d.h (io_send_astring): New proto. * imap4d/io.c (io_send_astring): New function. * imap4d/list.c (list_fun): Use io_send_astring. (list_ref): Special handling for empty wcard (imap4d_list): Remove special handling for empty wcard and INBOX. Leave that to list_ref. This makes it possible to declare namespaces like "INBOX." ("." being the delimiter). * imap4d/lsub.c (imap4d_lsub): Use io_send_astring. * imap4d/namespace.c (namespace_translate_name): Check for declared namespace first.
Showing
6 changed files
with
106 additions
and
82 deletions
... | @@ -229,6 +229,7 @@ extern int io_untagged_response (int, const char *, ...) MU_PRINTFLIKE(2,3); | ... | @@ -229,6 +229,7 @@ extern int io_untagged_response (int, const char *, ...) MU_PRINTFLIKE(2,3); |
229 | extern int io_sendf (const char *, ...) MU_PRINTFLIKE(1,2); | 229 | extern int io_sendf (const char *, ...) MU_PRINTFLIKE(1,2); |
230 | extern int io_send_bytes (const char *buf, size_t size); | 230 | extern int io_send_bytes (const char *buf, size_t size); |
231 | extern int io_send_qstring (const char *); | 231 | extern int io_send_qstring (const char *); |
232 | extern int io_send_astring (const char *); | ||
232 | extern int io_send_literal (const char *); | 233 | extern int io_send_literal (const char *); |
233 | extern int io_copy_out (mu_stream_t str, size_t size); | 234 | extern int io_copy_out (mu_stream_t str, size_t size); |
234 | extern int io_completion_response (struct imap4d_command *, int, | 235 | extern int io_completion_response (struct imap4d_command *, int, | ... | ... |
... | @@ -256,6 +256,27 @@ io_send_qstring (const char *buffer) | ... | @@ -256,6 +256,27 @@ io_send_qstring (const char *buffer) |
256 | } | 256 | } |
257 | 257 | ||
258 | int | 258 | int |
259 | io_send_astring (const char *buffer) | ||
260 | { | ||
261 | if (buffer == NULL) | ||
262 | return io_sendf ("NIL"); | ||
263 | else if (*buffer == 0) | ||
264 | return io_sendf ("\"\""); | ||
265 | if (strpbrk (buffer, "\"\r\n\\")) | ||
266 | { | ||
267 | char *s; | ||
268 | int ret; | ||
269 | char *b = mu_strdup (buffer); | ||
270 | while ((s = strchr (b, '\n')) || (s = strchr (b, '\r'))) | ||
271 | *s = ' '; | ||
272 | ret = io_send_literal (b); | ||
273 | free (b); | ||
274 | return ret; | ||
275 | } | ||
276 | return io_sendf ("\"%s\"", buffer); | ||
277 | } | ||
278 | |||
279 | int | ||
259 | io_send_literal (const char *buffer) | 280 | io_send_literal (const char *buffer) |
260 | { | 281 | { |
261 | return io_sendf ("{%lu}\n%s", (unsigned long) strlen (buffer), buffer); | 282 | return io_sendf ("{%lu}\n%s", (unsigned long) strlen (buffer), buffer); | ... | ... |
... | @@ -97,7 +97,7 @@ list_fun (mu_folder_t folder, struct mu_list_response *resp, void *data) | ... | @@ -97,7 +97,7 @@ list_fun (mu_folder_t folder, struct mu_list_response *resp, void *data) |
97 | io_sendf ("%s\n", name); | 97 | io_sendf ("%s\n", name); |
98 | else | 98 | else |
99 | { | 99 | { |
100 | io_send_qstring (name); | 100 | io_send_astring (name); |
101 | io_sendf ("\n"); | 101 | io_sendf ("\n"); |
102 | } | 102 | } |
103 | return 0; | 103 | return 0; |
... | @@ -127,6 +127,26 @@ list_ref (char const *ref, char const *wcard, char const *cwd, | ... | @@ -127,6 +127,26 @@ list_ref (char const *ref, char const *wcard, char const *cwd, |
127 | mu_folder_t folder; | 127 | mu_folder_t folder; |
128 | char const *dir; | 128 | char const *dir; |
129 | mu_url_t url; | 129 | mu_url_t url; |
130 | |||
131 | if (!wcard[0]) | ||
132 | { | ||
133 | /* An empty ("" string) mailbox name argument is a special request to | ||
134 | return the hierarchy delimiter and the root name of the name given | ||
135 | in the reference. | ||
136 | */ | ||
137 | io_sendf ("* LIST (\\NoSelect) "); | ||
138 | if (mu_c_strcasecmp (ref, "INBOX") == 0) | ||
139 | { | ||
140 | io_sendf ("NIL \"\""); | ||
141 | } | ||
142 | else | ||
143 | { | ||
144 | io_sendf ("\"%c\" ", pfx->delim); | ||
145 | io_send_astring (pfx->prefix); | ||
146 | } | ||
147 | io_sendf ("\n"); | ||
148 | return RESP_OK; | ||
149 | } | ||
130 | 150 | ||
131 | if (pfx->ns == NS_OTHER && match_pfx (pfx, ref) && strpbrk (wcard, "*%")) | 151 | if (pfx->ns == NS_OTHER && match_pfx (pfx, ref) && strpbrk (wcard, "*%")) |
132 | { | 152 | { |
... | @@ -226,95 +246,77 @@ imap4d_list (struct imap4d_session *session, | ... | @@ -226,95 +246,77 @@ imap4d_list (struct imap4d_session *session, |
226 | [RESP_NO] = "The requested item could not be found", | 246 | [RESP_NO] = "The requested item could not be found", |
227 | [RESP_BAD] = "System error" | 247 | [RESP_BAD] = "System error" |
228 | }; | 248 | }; |
229 | 249 | char *cwd = NULL; | |
250 | struct namespace_prefix const *pfx = NULL; | ||
251 | |||
230 | if (imap4d_tokbuf_argc (tok) != 4) | 252 | if (imap4d_tokbuf_argc (tok) != 4) |
231 | return io_completion_response (command, RESP_BAD, "Invalid arguments"); | 253 | return io_completion_response (command, RESP_BAD, "Invalid arguments"); |
232 | 254 | ||
233 | ref = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1); | 255 | ref = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1); |
234 | wcard = imap4d_tokbuf_getarg (tok, IMAP4_ARG_2); | 256 | wcard = imap4d_tokbuf_getarg (tok, IMAP4_ARG_2); |
235 | 257 | ||
236 | /* If wildcard is empty, it is a special case: we have to | 258 | if (ref[0] == 0) |
237 | return the hierarchy. */ | ||
238 | if (*wcard == '\0') | ||
239 | { | 259 | { |
240 | if (*ref) | 260 | cwd = namespace_translate_name (wcard, &pfx); |
241 | io_untagged_response (RESP_NONE, | 261 | if (cwd) |
242 | "LIST (\\NoSelect) \"%c\" \"%c\"", | ||
243 | MU_HIERARCHY_DELIMITER, | ||
244 | MU_HIERARCHY_DELIMITER); | ||
245 | else | ||
246 | io_untagged_response (RESP_NONE, | ||
247 | "LIST (\\NoSelect) \"%c\" \"\"", | ||
248 | MU_HIERARCHY_DELIMITER); | ||
249 | } | ||
250 | |||
251 | /* There is only one mailbox in the "INBOX" hierarchy ... INBOX. */ | ||
252 | else if (mu_c_strcasecmp (ref, "INBOX") == 0 | ||
253 | || (ref[0] == 0 && mu_c_strcasecmp (wcard, "INBOX") == 0)) | ||
254 | { | ||
255 | io_untagged_response (RESP_NONE, "LIST (\\NoInferiors) NIL INBOX"); | ||
256 | } | ||
257 | else | ||
258 | { | ||
259 | char *cwd = NULL; | ||
260 | struct namespace_prefix const *pfx = NULL; | ||
261 | |||
262 | if (ref[0] == 0) | ||
263 | { | 262 | { |
264 | cwd = namespace_translate_name (wcard, &pfx); | 263 | size_t p_len = strlen (pfx->prefix); |
265 | if (cwd) | 264 | size_t w_len = strlen (wcard); |
265 | |||
266 | if (p_len <= w_len) | ||
266 | { | 267 | { |
267 | char *p = wcard + strlen (pfx->prefix); | 268 | memmove (wcard, wcard + p_len, w_len - p_len + 1); |
268 | ref = mu_strdup (pfx->prefix); | 269 | ref = mu_strdup (pfx->prefix); |
269 | memmove (wcard, p, strlen (p) + 1); | ||
270 | free (cwd); | ||
271 | } | 270 | } |
272 | else | 271 | else |
273 | ref = mu_strdup (ref); | 272 | ref = mu_strdup (ref); |
273 | free (cwd); | ||
274 | } | 274 | } |
275 | else | 275 | else |
276 | ref = mu_strdup (ref); | 276 | ref = mu_strdup (ref); |
277 | 277 | } | |
278 | if (!pfx) | 278 | else |
279 | { | 279 | ref = mu_strdup (ref); |
280 | cwd = namespace_translate_name (ref, &pfx); | 280 | |
281 | if (cwd) | 281 | if (!pfx) |
282 | free (cwd); | 282 | { |
283 | } | 283 | cwd = namespace_translate_name (ref, &pfx); |
284 | 284 | if (cwd) | |
285 | if (pfx) | 285 | free (cwd); |
286 | } | ||
287 | |||
288 | if (pfx) | ||
289 | { | ||
290 | /* Find the longest directory prefix */ | ||
291 | size_t i = strcspn (wcard, "%*"); | ||
292 | if (wcard[i]) | ||
286 | { | 293 | { |
287 | /* Find the longest directory prefix */ | 294 | while (i > 0 && wcard[i - 1] != pfx->delim) |
288 | size_t i = strcspn (wcard, "%*"); | 295 | i--; |
289 | if (wcard[i]) | 296 | /* Append it to the reference */ |
297 | if (i) | ||
290 | { | 298 | { |
291 | while (i > 0 && wcard[i - 1] != pfx->delim) | 299 | size_t reflen = strlen (ref); |
292 | i--; | 300 | size_t len = i + reflen; |
293 | /* Append it to the reference */ | 301 | |
294 | if (i) | 302 | ref = mu_realloc (ref, len); |
295 | { | 303 | memcpy (ref + reflen, wcard, i - 1); /* omit the trailing / */ |
296 | size_t reflen = strlen (ref); | 304 | ref[len-1] = 0; |
297 | size_t len = i + reflen; | 305 | |
298 | 306 | wcard += i; | |
299 | ref = mu_realloc (ref, len); | ||
300 | memcpy (ref + reflen, wcard, i - 1); /* omit the trailing / */ | ||
301 | ref[len-1] = 0; | ||
302 | |||
303 | wcard += i; | ||
304 | } | ||
305 | } | 307 | } |
306 | } | 308 | } |
307 | |||
308 | cwd = namespace_translate_name (ref, &pfx); | ||
309 | if (cwd) | ||
310 | status = list_ref (ref, wcard, cwd, pfx); | ||
311 | else | ||
312 | status = RESP_NO; | ||
313 | |||
314 | free (cwd); | ||
315 | free (ref); | ||
316 | } | 309 | } |
310 | |||
311 | cwd = namespace_translate_name (ref, &pfx); | ||
312 | if (cwd) | ||
313 | status = list_ref (ref, wcard, cwd, pfx); | ||
314 | else | ||
315 | status = RESP_NO; | ||
317 | 316 | ||
317 | free (cwd); | ||
318 | free (ref); | ||
319 | |||
318 | return io_completion_response (command, status, resp_text[status]); | 320 | return io_completion_response (command, status, resp_text[status]); |
319 | } | 321 | } |
320 | 322 | ... | ... |
... | @@ -68,7 +68,7 @@ imap4d_lsub (struct imap4d_session *session, | ... | @@ -68,7 +68,7 @@ imap4d_lsub (struct imap4d_session *session, |
68 | { | 68 | { |
69 | mu_stream_printf (iostream, "* LSUB () \"%c\" ", | 69 | mu_stream_printf (iostream, "* LSUB () \"%c\" ", |
70 | MU_HIERARCHY_DELIMITER); | 70 | MU_HIERARCHY_DELIMITER); |
71 | io_send_qstring (name); | 71 | io_send_astring (name); |
72 | io_sendf ("\n"); | 72 | io_sendf ("\n"); |
73 | } | 73 | } |
74 | } | 74 | } | ... | ... |
... | @@ -279,13 +279,7 @@ namespace_translate_name (char const *name, | ... | @@ -279,13 +279,7 @@ namespace_translate_name (char const *name, |
279 | char *res = NULL; | 279 | char *res = NULL; |
280 | struct namespace_prefix const *pfx; | 280 | struct namespace_prefix const *pfx; |
281 | 281 | ||
282 | if (mu_c_strcasecmp (name, "INBOX") == 0 && auth_data->change_uid) | 282 | res = translate_name (name, &pfx); |
283 | { | ||
284 | res = mu_strdup (auth_data->mailbox); | ||
285 | pfx = mu_assoc_get (prefixes, ""); | ||
286 | } | ||
287 | else | ||
288 | res = translate_name (name, &pfx); | ||
289 | 283 | ||
290 | if (res) | 284 | if (res) |
291 | { | 285 | { |
... | @@ -347,10 +341,16 @@ namespace_translate_name (char const *name, | ... | @@ -347,10 +341,16 @@ namespace_translate_name (char const *name, |
347 | 341 | ||
348 | res = dir; | 342 | res = dir; |
349 | trim_delim (res, '/'); | 343 | trim_delim (res, '/'); |
350 | |||
351 | if (return_pfx) | ||
352 | *return_pfx = pfx; | ||
353 | } | 344 | } |
345 | else if (mu_c_strcasecmp (name, "INBOX") == 0 && auth_data->change_uid) | ||
346 | { | ||
347 | res = mu_strdup (auth_data->mailbox); | ||
348 | pfx = mu_assoc_get (prefixes, ""); | ||
349 | } | ||
350 | |||
351 | if (res && return_pfx) | ||
352 | *return_pfx = pfx; | ||
353 | |||
354 | return res; | 354 | return res; |
355 | } | 355 | } |
356 | 356 | ... | ... |
... | @@ -446,10 +446,10 @@ mu_folder_delete (mu_folder_t folder, const char *name) | ... | @@ -446,10 +446,10 @@ mu_folder_delete (mu_folder_t folder, const char *name) |
446 | undesired results. For example, a MH mailbox can hold another | 446 | undesired results. For example, a MH mailbox can hold another |
447 | mailboxes, i.e. be a folder itself. Removing it blindly would | 447 | mailboxes, i.e. be a folder itself. Removing it blindly would |
448 | result in removing these mailboxes as well, which is clearly not | 448 | result in removing these mailboxes as well, which is clearly not |
449 | indended. | 449 | intended. |
450 | 450 | ||
451 | To solve this folder and mailbox delete methods are tightly paired, | 451 | To solve this, both folder and mailbox delete methods are tightly |
452 | but without looking into each-others internal mechanisms. */ | 452 | paired, but without looking into each-others internal mechanisms. */ |
453 | mu_mailbox_t mbox; | 453 | mu_mailbox_t mbox; |
454 | rc = mu_mailbox_create_at (&mbox, folder, name); | 454 | rc = mu_mailbox_create_at (&mbox, folder, name); |
455 | if (rc == 0) | 455 | if (rc == 0) | ... | ... |
-
Please register or sign in to post a comment