Commit d569c130 d569c130f2cee770ab0aba6ee2a65382967b324e by Sergey Poznyakoff

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.
1 parent 80d8b59a
...@@ -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)
......