Commit 33a5d852 33a5d85239028bc3e34eec59909253d12d5434f4 by Sergey Poznyakoff

Share folder implementation between mbox, mh and maildir. Fix mu_folder_delete.

* include/mailutils/folder.h (_mu_fsfolder_init): New proto.
* include/mailutils/mailbox.h (mu_mailbox_create_at): New proto.
* libmailutils/mailbox/mailbox.c (mu_mailbox_create_at): New function.
* libmailutils/mailbox/Makefile.am (libmailbox_la_SOURCES): Add fsfolder.c
* libmailutils/mailbox/folder.c (mu_folder_delete): If folder does
not provide its own method for deletion, use mu_mailbox_remove.
(mu_folder_open, mu_folder_close, mu_folder_enumerate)
(mu_folder_lsub, mu_folder_subscribe, mu_folder_unsubscribe)
(mu_folder_rename): Return EINVAL if folder is NULL.
(mu_folder_match): Bugfix: don't pass folder flags to fnmatch.
* libmailutils/mailbox/fsfolder.c: New file. Implementation of
file-system based folders.
* libmailutils/mailbox/mailbox (_create_mailbox0): Propagate error
return from mu_registrar_lookup_url.
* libmailutils/tests/fsfolder00.at: New test case.
* libmailutils/tests/fsfolder01.at: New test case.
* libmailutils/tests/fsfolder02.at: New test case.
* libmailutils/tests/Makefile.am (noinst_PROGRAMS): Add fsfolder.
(TESTSUITE_AT): Add fsfolder tests.
* libmailutils/tests/testsuite.at: Include fsfolder tests.

* libproto/mbox/folder.c: Use fsfolder.
(_mh_is_scheme): Check file even if scheme matches.
* libproto/maildir/folder.c: Likewise.
(_maildir_is_scheme): Check file even if scheme matches.
* libproto/mh/folder.c: Likewise.

* testsuite/fldel.c: New file.
* testsuite/Makefile.am (noinst_PROGRAMS): Buld fldel.
1 parent a8374536
...@@ -92,6 +92,8 @@ extern int mu_folder_get_property (mu_folder_t, mu_property_t *); ...@@ -92,6 +92,8 @@ extern int mu_folder_get_property (mu_folder_t, mu_property_t *);
92 extern int mu_folder_decrement (mu_folder_t); 92 extern int mu_folder_decrement (mu_folder_t);
93 93
94 extern void mu_list_response_free (void *data); 94 extern void mu_list_response_free (void *data);
95
96 int _mu_fsfolder_init (mu_folder_t folder);
95 97
96 #ifdef __cplusplus 98 #ifdef __cplusplus
97 } 99 }
......
...@@ -43,6 +43,8 @@ extern int mu_mailbox_create_from_record (mu_mailbox_t *pmbox, ...@@ -43,6 +43,8 @@ extern int mu_mailbox_create_from_record (mu_mailbox_t *pmbox,
43 mu_record_t record, 43 mu_record_t record,
44 const char *name); 44 const char *name);
45 extern int mu_mailbox_create_default (mu_mailbox_t *, const char *); 45 extern int mu_mailbox_create_default (mu_mailbox_t *, const char *);
46 extern int mu_mailbox_create_at (mu_mailbox_t *pmbox, mu_folder_t folder,
47 const char *name);
46 48
47 extern void mu_mailbox_destroy (mu_mailbox_t *); 49 extern void mu_mailbox_destroy (mu_mailbox_t *);
48 50
......
...@@ -25,6 +25,7 @@ libmailbox_la_SOURCES = \ ...@@ -25,6 +25,7 @@ libmailbox_la_SOURCES = \
25 body.c\ 25 body.c\
26 envelope.c\ 26 envelope.c\
27 folder.c\ 27 folder.c\
28 fsfolder.c\
28 hdrfirst.c\ 29 hdrfirst.c\
29 hdritr.c\ 30 hdritr.c\
30 header.c\ 31 header.c\
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
36 #include <mailutils/url.h> 36 #include <mailutils/url.h>
37 #include <mailutils/errno.h> 37 #include <mailutils/errno.h>
38 #include <mailutils/property.h> 38 #include <mailutils/property.h>
39 #include <mailutils/mailbox.h>
39 40
40 #include <mailutils/sys/folder.h> 41 #include <mailutils/sys/folder.h>
41 42
...@@ -49,7 +50,7 @@ static struct mu_monitor folder_lock = MU_MONITOR_INITIALIZER; ...@@ -49,7 +50,7 @@ static struct mu_monitor folder_lock = MU_MONITOR_INITIALIZER;
49 int 50 int
50 mu_folder_match (const char *name, void *pattern, int flags) 51 mu_folder_match (const char *name, void *pattern, int flags)
51 { 52 {
52 return fnmatch (pattern, name[0] == '/' ? name + 1 : name, flags); 53 return fnmatch (pattern, name[0] == '/' ? name + 1 : name, 0);
53 } 54 }
54 55
55 /* A folder could be remote (IMAP), or local(a spool directory) like $HOME/Mail 56 /* A folder could be remote (IMAP), or local(a spool directory) like $HOME/Mail
...@@ -249,7 +250,9 @@ mu_folder_get_property (mu_folder_t folder, mu_property_t *prop) ...@@ -249,7 +250,9 @@ mu_folder_get_property (mu_folder_t folder, mu_property_t *prop)
249 int 250 int
250 mu_folder_open (mu_folder_t folder, int flags) 251 mu_folder_open (mu_folder_t folder, int flags)
251 { 252 {
252 if (folder == NULL || folder->_open == NULL) 253 if (folder == NULL)
254 return EINVAL;
255 if (folder->_open == NULL)
253 return ENOSYS; 256 return ENOSYS;
254 return folder->_open (folder, flags); 257 return folder->_open (folder, flags);
255 } 258 }
...@@ -257,7 +260,9 @@ mu_folder_open (mu_folder_t folder, int flags) ...@@ -257,7 +260,9 @@ mu_folder_open (mu_folder_t folder, int flags)
257 int 260 int
258 mu_folder_close (mu_folder_t folder) 261 mu_folder_close (mu_folder_t folder)
259 { 262 {
260 if (folder == NULL || folder->_close == NULL) 263 if (folder == NULL)
264 return EINVAL;
265 if (folder->_close == NULL)
261 return ENOSYS; 266 return ENOSYS;
262 return folder->_close (folder); 267 return folder->_close (folder);
263 } 268 }
...@@ -381,8 +386,10 @@ mu_folder_enumerate (mu_folder_t folder, const char *name, ...@@ -381,8 +386,10 @@ mu_folder_enumerate (mu_folder_t folder, const char *name,
381 mu_folder_enumerate_fp enumfun, void *enumdata) 386 mu_folder_enumerate_fp enumfun, void *enumdata)
382 { 387 {
383 int status; 388 int status;
384 if (folder == NULL || folder->_list == NULL) 389 if (folder == NULL)
385 return EINVAL; 390 return EINVAL;
391 else if (folder->_list == NULL)
392 return ENOSYS;
386 else 393 else
387 { 394 {
388 mu_list_t list = NULL; 395 mu_list_t list = NULL;
...@@ -412,7 +419,9 @@ mu_folder_lsub (mu_folder_t folder, const char *dirname, const char *basename, ...@@ -412,7 +419,9 @@ mu_folder_lsub (mu_folder_t folder, const char *dirname, const char *basename,
412 { 419 {
413 int status; 420 int status;
414 421
415 if (folder == NULL || folder->_lsub == NULL) 422 if (folder == NULL)
423 return EINVAL;
424 else if (folder->_lsub == NULL)
416 return ENOSYS; 425 return ENOSYS;
417 else 426 else
418 { 427 {
...@@ -428,31 +437,64 @@ mu_folder_lsub (mu_folder_t folder, const char *dirname, const char *basename, ...@@ -428,31 +437,64 @@ mu_folder_lsub (mu_folder_t folder, const char *dirname, const char *basename,
428 int 437 int
429 mu_folder_subscribe (mu_folder_t folder, const char *name) 438 mu_folder_subscribe (mu_folder_t folder, const char *name)
430 { 439 {
431 if (folder == NULL || folder->_subscribe == NULL) 440 if (folder == NULL)
432 return EINVAL; 441 return EINVAL;
442 if (folder->_subscribe == NULL)
443 return ENOSYS;
433 return folder->_subscribe (folder, name); 444 return folder->_subscribe (folder, name);
434 } 445 }
435 446
436 int 447 int
437 mu_folder_unsubscribe (mu_folder_t folder, const char *name) 448 mu_folder_unsubscribe (mu_folder_t folder, const char *name)
438 { 449 {
439 if (folder == NULL || folder->_unsubscribe == NULL) 450 if (folder == NULL)
440 return EINVAL; 451 return EINVAL;
452 if (folder->_unsubscribe == NULL)
453 return ENOSYS;
441 return folder->_unsubscribe (folder, name); 454 return folder->_unsubscribe (folder, name);
442 } 455 }
443 456
444 int 457 int
445 mu_folder_delete (mu_folder_t folder, const char *name) 458 mu_folder_delete (mu_folder_t folder, const char *name)
446 { 459 {
447 if (folder == NULL || folder->_delete == NULL) 460 int rc;
448 return ENOSYS; 461
449 return folder->_delete (folder, name); 462 if (folder == NULL)
463 return EINVAL;
464 if (folder->_delete)
465 rc = folder->_delete (folder, name);
466 else
467 {
468 /* If there is no folder-specific _delete method, then try to create the
469 mailbox and call mailbox delete (remove) method. This is necessary
470 because certain types of mailboxes share a common folder (e.g. mbox,
471 maildir and mh all use filesystem folder), but have a different
472 internal structure. Supplying mu_folder_t with a knowledge of mailbox
473 internals will harm separation of concerns. On the other hand,
474 removing something without looking into it may well yield undesired
475 results. For example, a MH mailbox can hold another mailboxes, i.e.
476 be a folder itself. Removing it blindly would result in removing
477 these mailboxes as well, which is clearly not indended.
478
479 To solve this folder and mailbox delete methods are tightly paired,
480 but without looking into each-others internal mechanisms. */
481 mu_mailbox_t mbox;
482 rc = mu_mailbox_create_at (&mbox, folder, name);
483 if (rc == 0)
484 {
485 rc = mu_mailbox_remove (mbox);
486 mu_mailbox_destroy (&mbox);
487 }
488 }
489 return rc;
450 } 490 }
451 491
452 int 492 int
453 mu_folder_rename (mu_folder_t folder, const char *oldname, const char *newname) 493 mu_folder_rename (mu_folder_t folder, const char *oldname, const char *newname)
454 { 494 {
455 if (folder == NULL || folder->_rename == NULL) 495 if (folder == NULL)
496 return EINVAL;
497 if (folder->_rename == NULL)
456 return ENOSYS; 498 return ENOSYS;
457 return folder->_rename (folder, oldname, newname); 499 return folder->_rename (folder, oldname, newname);
458 } 500 }
......
1 /* Implementation of file-system folder for GNU Mailutils
2 Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007, 2008,
3 2010, 2011 Free Software Foundation, Inc.
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 3 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General
16 Public License along with this library. If not, see
17 <http://www.gnu.org/licenses/>. */
18
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 #include <errno.h>
24 #include <sys/types.h>
25 #include <dirent.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <glob.h>
31 #include <fnmatch.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34
35 #include <mailutils/sys/folder.h>
36 #include <mailutils/sys/registrar.h>
37
38 #include <mailutils/auth.h>
39 #include <mailutils/url.h>
40 #include <mailutils/stream.h>
41 #include <mailutils/util.h>
42 #include <mailutils/errno.h>
43 #include <mailutils/debug.h>
44 #include <mailutils/property.h>
45 #include <mailutils/iterator.h>
46
47 /* File-system folder is shared between UNIX mbox, maildir and MH
48 mailboxes. It implements all usual folder methods, excepting
49 for _delete, which is implemented on the mailbox level. See
50 comment to mu_folder_delete in folder.c */
51
52 struct _mu_fsfolder
53 {
54 char *dirname;
55 mu_property_t subscription;
56 };
57
58 static int
59 open_subscription (struct _mu_fsfolder *folder)
60 {
61 int rc;
62 mu_property_t prop;
63 mu_stream_t str;
64 char *filename = mu_make_file_name (folder->dirname, ".mu-subscr");
65
66 rc = mu_file_stream_create (&str, filename, MU_STREAM_RDWR|MU_STREAM_CREAT);
67 if (rc)
68 return rc;
69 rc = mu_property_create_init (&prop, mu_assoc_property_init, str);
70 free (filename);
71 if (rc == 0)
72 folder->subscription = prop;
73 return rc;
74 }
75
76
77 static char *
78 get_pathname (const char *dirname, const char *basename)
79 {
80 char *pathname = NULL, *p;
81
82 /* Skip eventual protocol designator. */
83 p = strchr (dirname, ':');
84 if (p && p[1] == '/' && p[2] == '/')
85 dirname = p + 3;
86
87 /* null basename gives dirname. */
88 if (basename == NULL)
89 pathname = (dirname) ? strdup (dirname) : strdup (".");
90 /* Absolute. */
91 else if (basename[0] == '/')
92 pathname = strdup (basename);
93 /* Relative. */
94 else
95 {
96 size_t baselen = strlen (basename);
97 size_t dirlen = strlen (dirname);
98 while (dirlen > 0 && dirname[dirlen-1] == '/')
99 dirlen--;
100 pathname = calloc (dirlen + baselen + 2, sizeof (char));
101 if (pathname)
102 {
103 memcpy (pathname, dirname, dirlen);
104 pathname[dirlen] = '/';
105 strcpy (pathname + dirlen + 1, basename);
106 }
107 }
108 return pathname;
109 }
110
111 static void
112 _fsfolder_destroy (mu_folder_t folder)
113 {
114 if (folder->data)
115 {
116 struct _mu_fsfolder *fsfolder = folder->data;
117 free (fsfolder->dirname);
118 mu_property_destroy (&fsfolder->subscription);
119 free (folder->data);
120 folder->data = NULL;
121 }
122 }
123
124 /* Noop. */
125 static int
126 _fsfolder_open (mu_folder_t folder, int flags MU_ARG_UNUSED)
127 {
128 struct _mu_fsfolder *fsfolder = folder->data;
129 if (flags & MU_STREAM_CREAT)
130 {
131 return (mkdir (fsfolder->dirname, S_IRWXU) == 0) ? 0 : errno;
132 }
133 return 0;
134 }
135
136 /* Noop. */
137 static int
138 _fsfolder_close (mu_folder_t folder MU_ARG_UNUSED)
139 {
140 int rc = 0;
141 struct _mu_fsfolder *fsfolder = folder->data;
142
143 if (fsfolder->subscription)
144 rc = mu_property_save (fsfolder->subscription);
145 return rc;
146 }
147
148 static int
149 _fsfolder_rename (mu_folder_t folder, const char *oldpath,
150 const char *newpath)
151 {
152 struct _mu_fsfolder *fsfolder = folder->data;
153 if (oldpath && newpath)
154 {
155 int status = 0;
156 char *pathold = get_pathname (fsfolder->dirname, oldpath);
157 if (pathold)
158 {
159 char *pathnew = get_pathname (fsfolder->dirname, newpath);
160 if (pathnew)
161 {
162 if (access (pathnew, F_OK) == 0)
163 status = EEXIST;
164 else if (rename (pathold, pathnew) != 0)
165 status = errno;
166 free (pathnew);
167 }
168 else
169 status = ENOMEM;
170 free (pathold);
171 }
172 else
173 status = ENOMEM;
174 return status;
175 }
176 return EINVAL;
177 }
178
179 struct inode_list /* Inode/dev number list used to cut off
180 recursion */
181 {
182 struct inode_list *next;
183 ino_t inode;
184 dev_t dev;
185 };
186
187 struct search_data
188 {
189 mu_list_t result;
190 mu_folder_enumerate_fp enumfun;
191 void *enumdata;
192 char *dirname;
193 size_t dirlen;
194 void *pattern;
195 int flags;
196 size_t max_level;
197 size_t errcnt;
198 mu_folder_t folder;
199 };
200
201 static int
202 inode_list_lookup (struct inode_list *list, struct stat *st)
203 {
204 for (; list; list = list->next)
205 if (list->inode == st->st_ino && list->dev == st->st_dev)
206 return 1;
207 return 0;
208 }
209
210 static int
211 list_helper (struct search_data *data, mu_record_t record,
212 const char *dirname, size_t level,
213 struct inode_list *ilist)
214 {
215 DIR *dirp;
216 struct dirent *dp;
217 int stop = 0;
218
219 if (data->max_level && level > data->max_level)
220 return 0;
221
222 dirp = opendir (dirname);
223 if (dirp == NULL)
224 {
225 mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_ERROR,
226 ("list_helper cannot open directory %s: %s",
227 dirname, mu_strerror (errno)));
228 data->errcnt++;
229 return 1;
230 }
231
232 if (!record)
233 {
234 int type;
235 mu_registrar_lookup (dirname, MU_FOLDER_ATTRIBUTE_ALL,
236 &record, &type);
237 }
238
239 while ((dp = readdir (dirp)))
240 {
241 char const *ename = dp->d_name;
242 char *fname;
243 struct stat st;
244
245 if (ename[ename[0] != '.' ? 0 : ename[1] != '.' ? 1 : 2] == 0)
246 continue;
247 if (strncmp (ename, ".mu-", 4) == 0)
248 continue;
249 fname = get_pathname (dirname, ename);
250 if (lstat (fname, &st) == 0)
251 {
252 int f;
253 if (S_ISDIR (st.st_mode))
254 f = MU_FOLDER_ATTRIBUTE_DIRECTORY;
255 else if (S_ISREG (st.st_mode))
256 f = MU_FOLDER_ATTRIBUTE_FILE;
257 else if (S_ISLNK (st.st_mode))
258 f = MU_FOLDER_ATTRIBUTE_LINK;
259 else
260 f = 0;
261 if (mu_record_list_p (record, ename, f))
262 {
263 if (data->folder->_match == NULL
264 || data->folder->_match (fname + data->dirlen +
265 ((data->dirlen > 1
266 && data->dirname[data->dirlen-1] != '/') ?
267 1 : 0),
268 data->pattern,
269 data->flags) == 0)
270 {
271 char *refname = fname;
272 int type = 0;
273 struct mu_list_response *resp;
274 mu_record_t rec = NULL;
275
276 resp = malloc (sizeof (*resp));
277 if (resp == NULL)
278 {
279 mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_ERROR,
280 ("list_helper: %s", mu_strerror (ENOMEM)));
281 data->errcnt++;
282 free (fname);
283 continue;
284 }
285
286 mu_registrar_lookup (refname, MU_FOLDER_ATTRIBUTE_ALL,
287 &rec, &type);
288
289 resp->name = fname;
290 resp->level = level;
291 resp->separator = '/';
292 resp->type = type;
293 resp->format = rec;
294
295 if (resp->type == 0)
296 {
297 free (resp->name);
298 free (resp);
299 continue;
300 }
301
302 if (data->enumfun)
303 {
304 if (data->enumfun (data->folder, resp, data->enumdata))
305 {
306 free (resp->name);
307 free (resp);
308 stop = 1;
309 break;
310 }
311 }
312
313 if (data->result)
314 {
315 fname = NULL;
316 mu_list_append (data->result, resp);
317 }
318 else
319 free (resp);
320
321 if ((type & MU_FOLDER_ATTRIBUTE_DIRECTORY)
322 && !inode_list_lookup (ilist, &st))
323 {
324 struct inode_list idata;
325
326 idata.inode = st.st_ino;
327 idata.dev = st.st_dev;
328 idata.next = ilist;
329 stop = list_helper (data, rec, refname, level + 1,
330 &idata);
331 }
332 }
333 else if (S_ISDIR (st.st_mode))
334 {
335 struct inode_list idata;
336
337 idata.inode = st.st_ino;
338 idata.dev = st.st_dev;
339 idata.next = ilist;
340 stop = list_helper (data, NULL, fname, level + 1, &idata);
341 }
342 }
343 }
344 else
345 {
346 mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_ERROR,
347 ("list_helper cannot stat %s: %s",
348 fname, mu_strerror (errno)));
349 }
350 free (fname);
351 }
352 closedir (dirp);
353 return stop;
354 }
355
356 static int
357 _fsfolder_list (mu_folder_t folder, const char *ref,
358 void *pattern,
359 int flags,
360 size_t max_level,
361 mu_list_t flist,
362 mu_folder_enumerate_fp enumfun, void *enumdata)
363 {
364 struct _mu_fsfolder *fsfolder = folder->data;
365 struct inode_list iroot;
366 struct search_data sdata;
367
368 memset (&iroot, 0, sizeof iroot);
369 sdata.dirname = get_pathname (fsfolder->dirname, ref);
370 sdata.dirlen = strlen (sdata.dirname);
371 sdata.result = flist;
372 sdata.enumfun = enumfun;
373 sdata.enumdata = enumdata;
374 sdata.pattern = pattern;
375 sdata.flags = flags;
376 sdata.max_level = max_level;
377 sdata.folder = folder;
378 sdata.errcnt = 0;
379 list_helper (&sdata, NULL, sdata.dirname, 0, &iroot);
380 free (sdata.dirname);
381 /* FIXME: error code */
382 return 0;
383 }
384
385 static int
386 _fsfolder_lsub (mu_folder_t folder, const char *ref, const char *name,
387 mu_list_t flist)
388 {
389 struct _mu_fsfolder *fsfolder = folder->data;
390 int rc;
391 char *pattern;
392 mu_iterator_t itr;
393
394 if (name == NULL || *name == '\0')
395 name = "*";
396
397 if (!fsfolder->subscription && (rc = open_subscription (fsfolder)))
398 return rc;
399
400 pattern = mu_make_file_name (ref, name);
401
402 rc = mu_property_get_iterator (fsfolder->subscription, &itr);
403 if (rc == 0)
404 {
405 for (mu_iterator_first (itr); !mu_iterator_is_done (itr);
406 mu_iterator_next (itr))
407 {
408 const char *key, *val;
409
410 mu_iterator_current_kv (itr, (const void **)&key, (void**)&val);
411
412 if (fnmatch (pattern, key, 0) == 0)
413 {
414 struct mu_list_response *resp;
415 resp = malloc (sizeof (*resp));
416 if (resp == NULL)
417 {
418 rc = ENOMEM;
419 break;
420 }
421 else if ((resp->name = strdup (key)) == NULL)
422 {
423 free (resp);
424 rc = ENOMEM;
425 break;
426 }
427 resp->type = MU_FOLDER_ATTRIBUTE_FILE;
428 resp->level = 0;
429 resp->separator = '/';
430 rc = mu_list_append (flist, resp);
431 if (rc)
432 {
433 free (resp);
434 break;
435 }
436 }
437 }
438 mu_iterator_destroy (&itr);
439 }
440 free (pattern);
441 return rc;
442 }
443
444 static int
445 _fsfolder_subscribe (mu_folder_t folder, const char *name)
446 {
447 struct _mu_fsfolder *fsfolder = folder->data;
448 int rc;
449
450 if (!fsfolder->subscription && (rc = open_subscription (fsfolder)))
451 return rc;
452
453 return mu_property_set_value (fsfolder->subscription, name, "", 1);
454 }
455
456 static int
457 _fsfolder_unsubscribe (mu_folder_t folder, const char *name)
458 {
459 struct _mu_fsfolder *fsfolder = folder->data;
460 int rc;
461
462 if (!fsfolder->subscription && (rc = open_subscription (fsfolder)))
463 return rc;
464
465 return mu_property_unset (fsfolder->subscription, name);
466 }
467
468 static int
469 _fsfolder_get_authority (mu_folder_t folder, mu_authority_t *pauth)
470 {
471 int status = 0;
472 if (folder->authority == NULL)
473 status = mu_authority_create_null (&folder->authority, folder);
474 if (!status && pauth)
475 *pauth = folder->authority;
476 return status;
477 }
478
479 int
480 _mu_fsfolder_init (mu_folder_t folder)
481 {
482 struct _mu_fsfolder *dfolder;
483 int status = 0;
484
485 /* We create an authority so the API is uniform across the mailbox
486 types. */
487 status = _fsfolder_get_authority (folder, NULL);
488 if (status != 0)
489 return status;
490
491 dfolder = folder->data = calloc (1, sizeof (*dfolder));
492 if (dfolder == NULL)
493 return ENOMEM;
494
495 status = mu_url_aget_path (folder->url, &dfolder->dirname);
496 if (status == MU_ERR_NOENT)
497 {
498 dfolder->dirname = malloc (2);
499 if (dfolder->dirname == NULL)
500 status = ENOMEM;
501 else
502 {
503 strcpy (dfolder->dirname, ".");
504 status = 0;
505 }
506 }
507
508 if (status)
509 {
510 free (dfolder);
511 folder->data = NULL;
512 return status;
513 }
514
515 folder->_destroy = _fsfolder_destroy;
516
517 folder->_open = _fsfolder_open;
518 folder->_close = _fsfolder_close;
519
520 folder->_list = _fsfolder_list;
521 folder->_lsub = _fsfolder_lsub;
522 folder->_subscribe = _fsfolder_subscribe;
523 folder->_unsubscribe = _fsfolder_unsubscribe;
524 folder->_delete = NULL;
525 folder->_rename = _fsfolder_rename;
526 return 0;
527 }
528
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
41 #include <mailutils/util.h> 41 #include <mailutils/util.h>
42 42
43 #include <mailutils/sys/mailbox.h> 43 #include <mailutils/sys/mailbox.h>
44 #include <mailutils/sys/folder.h>
44 #include <mailutils/sys/url.h> 45 #include <mailutils/sys/url.h>
45 46
46 /* Mailbox-specific flags */ 47 /* Mailbox-specific flags */
...@@ -76,7 +77,8 @@ mailbox_folder_create (mu_mailbox_t mbox, const char *name, ...@@ -76,7 +77,8 @@ mailbox_folder_create (mu_mailbox_t mbox, const char *name,
76 int 77 int
77 _mailbox_create_from_record (mu_mailbox_t *pmbox, 78 _mailbox_create_from_record (mu_mailbox_t *pmbox,
78 mu_record_t record, 79 mu_record_t record,
79 mu_url_t url, 80 mu_url_t url,
81 mu_folder_t folder,
80 const char *name) 82 const char *name)
81 { 83 {
82 int (*m_init) (mu_mailbox_t) = NULL; 84 int (*m_init) (mu_mailbox_t) = NULL;
...@@ -127,10 +129,16 @@ _mailbox_create_from_record (mu_mailbox_t *pmbox, ...@@ -127,10 +129,16 @@ _mailbox_create_from_record (mu_mailbox_t *pmbox,
127 } 129 }
128 130
129 mbox->url = url; 131 mbox->url = url;
130 132
131 /* Create the folder before initializing the concrete mailbox. 133 if (folder)
132 The mailbox needs it's back pointer. */ 134 {
133 status = mailbox_folder_create (mbox, name, record); 135 folder->ref++; /* FIXME: No ref/unref function for folders */
136 mbox->folder = folder;
137 }
138 else
139 /* Create the folder before initializing the concrete mailbox.
140 The mailbox needs it's back pointer. */
141 status = mailbox_folder_create (mbox, name, record);
134 142
135 if (status == 0) 143 if (status == 0)
136 status = m_init (mbox); /* Create the concrete mailbox type. */ 144 status = m_init (mbox); /* Create the concrete mailbox type. */
...@@ -152,11 +160,12 @@ static int ...@@ -152,11 +160,12 @@ static int
152 _create_mailbox0 (mu_mailbox_t *pmbox, mu_url_t url, const char *name) 160 _create_mailbox0 (mu_mailbox_t *pmbox, mu_url_t url, const char *name)
153 { 161 {
154 mu_record_t record = NULL; 162 mu_record_t record = NULL;
155 163 int rc;
156 if (mu_registrar_lookup_url (url, MU_FOLDER_ATTRIBUTE_FILE, &record, NULL) 164
157 == 0) 165 rc = mu_registrar_lookup_url (url, MU_FOLDER_ATTRIBUTE_FILE, &record, NULL);
158 return _mailbox_create_from_record (pmbox, record, url, name); 166 if (rc == 0)
159 return ENOSYS; 167 rc = _mailbox_create_from_record (pmbox, record, url, NULL, name);
168 return rc;
160 } 169 }
161 170
162 static int 171 static int
...@@ -203,7 +212,71 @@ mu_mailbox_create_from_record (mu_mailbox_t *pmbox, mu_record_t record, ...@@ -203,7 +212,71 @@ mu_mailbox_create_from_record (mu_mailbox_t *pmbox, mu_record_t record,
203 rc = mu_url_create (&url, name); 212 rc = mu_url_create (&url, name);
204 if (rc) 213 if (rc)
205 return rc; 214 return rc;
206 rc = _mailbox_create_from_record (pmbox, record, url, name); 215 rc = _mailbox_create_from_record (pmbox, record, url, NULL, name);
216 if (rc)
217 mu_url_destroy (&url);
218 return rc;
219 }
220
221 int
222 mu_mailbox_create_at (mu_mailbox_t *pmbox, mu_folder_t folder,
223 const char *name)
224 {
225 int rc;
226 mu_url_t url;
227 const char *oldpath;
228
229 rc = mu_url_dup (folder->url, &url);
230 if (rc)
231 return rc;
232 do
233 {
234 char *path;
235 size_t oldlen, len;
236 mu_record_t record;
237
238 rc = mu_url_sget_path (url, &oldpath);
239 if (rc)
240 break;
241
242 oldlen = strlen (oldpath);
243 if (oldlen == 0)
244 {
245 path = strdup (name);
246 if (!path)
247 {
248 rc = ENOMEM;
249 break;
250 }
251 }
252 else
253 {
254 if (oldpath[oldlen-1] == '/')
255 oldlen--;
256 len = oldlen + 1 + strlen (name) + 1;
257 path = malloc (len);
258 if (!path)
259 {
260 rc = ENOMEM;
261 break;
262 }
263 memcpy (path, oldpath, oldlen);
264 path[oldlen++] = '/';
265 strcpy (path + oldlen, name);
266 }
267 rc = mu_url_set_path (url, path);
268 free (path);
269 if (rc)
270 break;
271
272 rc = mu_registrar_lookup_url (url, MU_FOLDER_ATTRIBUTE_FILE,
273 &record, NULL);
274 if (rc)
275 break;
276 rc = _mailbox_create_from_record (pmbox, record, url, folder, name);
277 }
278 while (0);
279
207 if (rc) 280 if (rc)
208 mu_url_destroy (&url); 281 mu_url_destroy (&url);
209 return rc; 282 return rc;
...@@ -314,7 +387,24 @@ mu_mailbox_remove (mu_mailbox_t mbox) ...@@ -314,7 +387,24 @@ mu_mailbox_remove (mu_mailbox_t mbox)
314 if (mbox->flags & _MU_MAILBOX_REMOVED) 387 if (mbox->flags & _MU_MAILBOX_REMOVED)
315 return MU_ERR_MBX_REMOVED; 388 return MU_ERR_MBX_REMOVED;
316 if (!mbox->_remove) 389 if (!mbox->_remove)
317 return MU_ERR_EMPTY_VFN; 390 {
391 /* Try the owning folder delete method. See comment to mu_folder_delete
392 in folder.c. This may result in a recursive call to mu_mailbox_remove
393 which is blocked by setting the _MU_MAILBOX_REMOVED flag. */
394
395 int rc;
396 const char *path;
397
398 rc = mu_url_sget_path (mbox->url, &path);
399 if (rc == 0)
400 {
401 mbox->flags |= _MU_MAILBOX_REMOVED;
402 rc = mu_folder_delete (mbox->folder, path);
403 if (rc)
404 mbox->flags &= ~_MU_MAILBOX_REMOVED;
405 }
406 return rc;
407 }
318 return mbox->_remove (mbox); 408 return mbox->_remove (mbox);
319 } 409 }
320 410
...@@ -689,7 +779,7 @@ mu_mailbox_set_folder (mu_mailbox_t mbox, mu_folder_t folder) ...@@ -689,7 +779,7 @@ mu_mailbox_set_folder (mu_mailbox_t mbox, mu_folder_t folder)
689 { 779 {
690 if (mbox == NULL) 780 if (mbox == NULL)
691 return EINVAL; 781 return EINVAL;
692 mbox->folder = folder; 782 mbox->folder = folder;
693 return 0; 783 return 0;
694 } 784 }
695 785
......
...@@ -12,6 +12,7 @@ decode2047 ...@@ -12,6 +12,7 @@ decode2047
12 encode2047 12 encode2047
13 fltst 13 fltst
14 fsaf 14 fsaf
15 fsfolder
15 imapio 16 imapio
16 listop 17 listop
17 mailcap 18 mailcap
......
...@@ -47,6 +47,7 @@ noinst_PROGRAMS = \ ...@@ -47,6 +47,7 @@ noinst_PROGRAMS = \
47 encode2047\ 47 encode2047\
48 fltst\ 48 fltst\
49 fsaf\ 49 fsaf\
50 fsfolder\
50 imapio\ 51 imapio\
51 listop\ 52 listop\
52 mailcap\ 53 mailcap\
...@@ -78,6 +79,9 @@ TESTSUITE_AT = \ ...@@ -78,6 +79,9 @@ TESTSUITE_AT = \
78 encode2047.at\ 79 encode2047.at\
79 fromflt.at\ 80 fromflt.at\
80 fsaf.at\ 81 fsaf.at\
82 fsfolder00.at\
83 fsfolder01.at\
84 fsfolder02.at\
81 hdrflt.at\ 85 hdrflt.at\
82 imapio.at\ 86 imapio.at\
83 inline-comment.at\ 87 inline-comment.at\
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2011 Free Software Foundation, Inc.
3
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
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 GNU Mailutils is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
16
17 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
20 #include <stdlib.h>
21 #include <string.h>
22 #include <mailutils/error.h>
23 #include <mailutils/errno.h>
24 #include <mailutils/folder.h>
25 #include <mailutils/stream.h>
26 #include <mailutils/stdstream.h>
27 #include <mailutils/list.h>
28 #include <mailutils/url.h>
29 #include <mailutils/util.h>
30 #include <mailutils/registrar.h>
31 #include <mailutils/sys/folder.h>
32 #include <mailutils/sys/registrar.h>
33
34 int sort_option;
35 int prefix_len;
36
37 struct command
38 {
39 char *verb;
40 int nargs;
41 char *args;
42 void (*handler) (mu_folder_t folder, char **argv);
43 };
44
45 static int
46 compare_response (void const *a, void const *b)
47 {
48 struct mu_list_response const *ra = a;
49 struct mu_list_response const *rb = b;
50
51 if (ra->level < rb->level)
52 return -1;
53 if (ra->level > rb->level)
54 return 1;
55 return strcmp (ra->name, rb->name);
56 }
57
58 static int
59 _print_list_entry (void *item, void *data)
60 {
61 struct mu_list_response *resp = item;
62 int len = data ? *(int*) data : 0;
63 mu_printf ("%c%c %c %4d %s\n",
64 (resp->type & MU_FOLDER_ATTRIBUTE_DIRECTORY) ? 'd' : '-',
65 (resp->type & MU_FOLDER_ATTRIBUTE_FILE) ? 'f' : '-',
66 resp->separator ? resp->separator : ' ',
67 resp->level,
68 resp->name + len);
69 return 0;
70 }
71
72 static void
73 com_list (mu_folder_t folder, char **argv)
74 {
75 int rc;
76 mu_list_t list;
77
78 mu_printf ("listing '%s' '%s'\n", argv[0], argv[1]);
79 rc = mu_folder_list (folder, argv[0], argv[1], 0, &list);
80 if (rc)
81 mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_list", argv[0], rc);
82 else
83 {
84 if (sort_option)
85 mu_list_sort (list, compare_response);
86 mu_list_foreach (list, _print_list_entry, &prefix_len);
87 mu_list_destroy (&list);
88 }
89 }
90
91 static void
92 com_lsub (mu_folder_t folder, char **argv)
93 {
94 int rc;
95 mu_list_t list;
96
97 mu_printf ("listing subscriptions for '%s' '%s'\n", argv[0], argv[1]);
98 rc = mu_folder_lsub (folder, argv[0], argv[1], &list);
99 if (rc)
100 mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_lsub", argv[0], rc);
101 else
102 {
103 if (sort_option)
104 mu_list_sort (list, compare_response);
105 mu_list_foreach (list, _print_list_entry, NULL);
106 mu_list_destroy (&list);
107 }
108 }
109
110 static void
111 com_rename (mu_folder_t folder, char **argv)
112 {
113 int rc;
114
115 mu_printf ("renaming %s to %s\n", argv[0], argv[1]);
116 rc = mu_folder_rename (folder, argv[0], argv[1]);
117 if (rc)
118 mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_rename", argv[0], rc);
119 else
120 mu_printf ("rename successful\n");
121 }
122
123 static void
124 com_subscribe (mu_folder_t folder, char **argv)
125 {
126 int rc;
127
128 mu_printf ("subscribing %s\n", argv[0]);
129 rc = mu_folder_subscribe (folder, argv[0]);
130 if (rc)
131 mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_subscribe", argv[0], rc);
132 else
133 mu_printf ("subscribe successful\n");
134 }
135
136 static void
137 com_unsubscribe (mu_folder_t folder, char **argv)
138 {
139 int rc;
140
141 mu_printf ("unsubscribing %s\n", argv[0]);
142 rc = mu_folder_unsubscribe (folder, argv[0]);
143 if (rc)
144 mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_unsubscribe", argv[0], rc);
145 else
146 mu_printf ("unsubscribe successful\n");
147 }
148
149 static struct command comtab[] = {
150 { "list", 2, "REF MBX", com_list },
151 { "lsub", 2, "REF MBX", com_lsub },
152 { "rename", 2, "OLD NEW", com_rename },
153 { "subscribe", 1, "MBX", com_subscribe },
154 { "unsubscribe", 1, "MBX", com_unsubscribe },
155 { NULL }
156 };
157
158 static struct command *
159 find_command (const char *name)
160 {
161 struct command *cp;
162
163 for (cp = comtab; cp->verb; cp++)
164 if (strcmp (cp->verb, name) == 0)
165 return cp;
166 return NULL;
167 }
168
169 static void
170 usage ()
171 {
172 struct command *cp;
173
174 mu_printf (
175 "usage: %s [debug=SPEC] name=URL OP ARG [ARG...] [OP ARG [ARG...]...]\n",
176 mu_program_name);
177 mu_printf ("OPerations and corresponding ARGuments are:\n");
178 for (cp = comtab; cp->verb; cp++)
179 mu_printf (" %s %s\n", cp->verb, cp->args);
180 }
181
182 static int
183 _always_is_scheme (mu_record_t record, mu_url_t url, int flags)
184 {
185 return 1;
186 }
187
188 static struct _mu_record test_record =
189 {
190 0,
191 "file",
192 MU_RECORD_LOCAL,
193 MU_URL_SCHEME | MU_URL_PATH,
194 MU_URL_PATH,
195 mu_url_expand_path, /* URL init. */
196 NULL, /* Mailbox init. */
197 NULL, /* Mailer init. */
198 _mu_fsfolder_init, /* Folder init. */
199 NULL, /* No need for an back pointer. */
200 _always_is_scheme, /* _is_scheme method. */
201 NULL, /* _get_url method. */
202 NULL, /* _get_mailbox method. */
203 NULL, /* _get_mailer method. */
204 NULL /* _get_folder method. */
205 };
206
207 int
208 main (int argc, char **argv)
209 {
210 int i;
211 int rc;
212 mu_folder_t folder;
213 char *fname = NULL;
214
215 mu_set_program_name (argv[0]);
216 mu_registrar_record (&test_record);
217
218 if (argc == 1)
219 {
220 usage ();
221 exit (0);
222 }
223
224 for (i = 1; i < argc; i++)
225 {
226 if (strncmp (argv[i], "debug=", 6) == 0)
227 mu_debug_parse_spec (argv[i] + 6);
228 else if (strncmp (argv[i], "name=", 5) == 0)
229 fname = argv[i] + 5;
230 else if (strcmp (argv[i], "sort") == 0)
231 sort_option = 1;
232 else
233 break;
234 }
235
236 if (!fname)
237 {
238 mu_error ("name not specified");
239 exit (1);
240 }
241
242 if (fname[0] != '/')
243 {
244 char *cwd = mu_getcwd ();
245 prefix_len = strlen (cwd);
246 if (cwd[prefix_len-1] != '/')
247 prefix_len++;
248 fname = mu_make_file_name (cwd, fname);
249 free (cwd);
250 }
251
252 rc = mu_folder_create (&folder, fname);
253 if (rc)
254 {
255 mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_create", fname, rc);
256 return 1;
257 }
258 rc = mu_folder_open (folder, MU_STREAM_READ);
259 if (rc)
260 {
261 mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_open", fname, rc);
262 return 1;
263 }
264
265 while (i < argc)
266 {
267 char *comargs[2];
268 struct command *cmd;
269
270 cmd = find_command (argv[i]);
271 if (!cmd)
272 {
273 mu_error ("unknown command %s\n", argv[i]);
274 break;
275 }
276
277 i++;
278 if (i + cmd->nargs > argc)
279 {
280 mu_error ("not enough arguments for %s", cmd->verb);
281 break;
282 }
283 memcpy (comargs, argv + i, cmd->nargs * sizeof (comargs[0]));
284 i += cmd->nargs;
285
286 cmd->handler (folder, comargs);
287 }
288
289 mu_folder_close (folder);
290 mu_folder_destroy (&folder);
291
292 return 0;
293 }
1 # This file is part of GNU Mailutils. -*- Autotest -*-
2 # Copyright (C) 2011 Free Software Foundation, Inc.
3 #
4 # GNU Mailutils is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License as
6 # published by the Free Software Foundation; either version 3, or (at
7 # your option) any later version.
8 #
9 # GNU Mailutils is distributed in the hope that it will be useful, but
10 # WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
16
17 AT_SETUP([List])
18 AT_KEYWORDS([fsfolder folder-list])
19
20 AT_CHECK([
21 mkdir dir
22 > dir/foo
23 > dir/bar
24 > dir/foo.mbox
25 mkdir dir/subdir
26 > dir/subdir/file
27 > dir/subdir/baz.mbox
28
29 fsfolder name=dir sort dnl
30 list "" "*" dnl
31 list subdir "*" dnl
32 list "" "*.mbox" dnl
33 list "subdir" "*.mbox"
34 ],
35 [0],
36 [listing '' '*'
37 d- / 0 dir/bar
38 d- / 0 dir/foo
39 d- / 0 dir/foo.mbox
40 d- / 0 dir/subdir
41 d- / 1 dir/subdir/baz.mbox
42 d- / 1 dir/subdir/file
43 listing 'subdir' '*'
44 d- / 0 dir/subdir/baz.mbox
45 d- / 0 dir/subdir/file
46 listing '' '*.mbox'
47 d- / 0 dir/foo.mbox
48 d- / 1 dir/subdir/baz.mbox
49 listing 'subdir' '*.mbox'
50 d- / 0 dir/subdir/baz.mbox
51 ])
52
53 AT_CLEANUP
1 # This file is part of GNU Mailutils. -*- Autotest -*-
2 # Copyright (C) 2011 Free Software Foundation, Inc.
3 #
4 # GNU Mailutils is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License as
6 # published by the Free Software Foundation; either version 3, or (at
7 # your option) any later version.
8 #
9 # GNU Mailutils is distributed in the hope that it will be useful, but
10 # WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
16
17 AT_SETUP([Subscriptions])
18 AT_KEYWORDS([fsfolder folder-subscribe])
19
20 AT_CHECK([
21 mkdir dir
22 fsfolder name=dir sort lsub "" "*"
23 fsfolder name=dir subscribe foo
24 fsfolder name=dir sort lsub "" "*"
25 fsfolder name=dir subscribe baz subscribe foo/baz subscribe foo/bar
26 fsfolder name=dir sort lsub "" "*"
27 fsfolder name=dir sort lsub foo "*"
28 fsfolder name=dir sort lsub "" 'foo*'
29 fsfolder name=dir unsubscribe baz
30 fsfolder name=dir sort lsub "" "*"
31 fsfolder name=dir unsubscribe foo
32 fsfolder name=dir sort lsub "" "*"
33 ],
34 [0],
35 [listing subscriptions for '' '*'
36 subscribing foo
37 subscribe successful
38 listing subscriptions for '' '*'
39 -f / 0 foo
40 subscribing baz
41 subscribe successful
42 subscribing foo/baz
43 subscribe successful
44 subscribing foo/bar
45 subscribe successful
46 listing subscriptions for '' '*'
47 -f / 0 baz
48 -f / 0 foo
49 -f / 0 foo/bar
50 -f / 0 foo/baz
51 listing subscriptions for 'foo' '*'
52 -f / 0 foo/bar
53 -f / 0 foo/baz
54 listing subscriptions for '' 'foo*'
55 -f / 0 foo
56 -f / 0 foo/bar
57 -f / 0 foo/baz
58 unsubscribing baz
59 unsubscribe successful
60 listing subscriptions for '' '*'
61 -f / 0 foo
62 -f / 0 foo/bar
63 -f / 0 foo/baz
64 unsubscribing foo
65 unsubscribe successful
66 listing subscriptions for '' '*'
67 -f / 0 foo/bar
68 -f / 0 foo/baz
69 ])
70
71 AT_CLEANUP
72
73
74
1 # This file is part of GNU Mailutils. -*- Autotest -*-
2 # Copyright (C) 2011 Free Software Foundation, Inc.
3 #
4 # GNU Mailutils is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License as
6 # published by the Free Software Foundation; either version 3, or (at
7 # your option) any later version.
8 #
9 # GNU Mailutils is distributed in the hope that it will be useful, but
10 # WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
16
17 AT_SETUP([Rename])
18 AT_KEYWORDS([fsfolder folder-rename])
19
20 AT_CHECK([
21 mkdir dir
22 > dir/foo
23 fsfolder name=dir rename foo bar
24 fsfolder name=dir list "" "*"
25 > dir/baz
26 fsfolder name=dir rename bar baz
27 ],
28 [0],
29 [renaming foo to bar
30 rename successful
31 listing '' '*'
32 d- / 0 dir/bar
33 renaming bar to baz
34 ],
35 [fsfolder: mu_folder_rename(bar) failed: File exists
36 ])
37
38 AT_CLEANUP
39
...@@ -68,6 +68,11 @@ m4_include([mailcap.at]) ...@@ -68,6 +68,11 @@ m4_include([mailcap.at])
68 m4_include([wicket.at]) 68 m4_include([wicket.at])
69 m4_include([prop.at]) 69 m4_include([prop.at])
70 70
71 AT_BANNER(File-system folder)
72 m4_include([fsfolder00.at])
73 m4_include([fsfolder01.at])
74 m4_include([fsfolder02.at])
75
71 AT_BANNER(Base64) 76 AT_BANNER(Base64)
72 m4_include([base64e.at]) 77 m4_include([base64e.at])
73 m4_include([base64d.at]) 78 m4_include([base64d.at])
......
...@@ -133,7 +133,6 @@ static struct command comtab[] = { ...@@ -133,7 +133,6 @@ static struct command comtab[] = {
133 { "lsub", 2, "REF MBX", com_lsub }, 133 { "lsub", 2, "REF MBX", com_lsub },
134 { "delete", 1, "MBX", com_delete }, 134 { "delete", 1, "MBX", com_delete },
135 { "rename", 2, "OLD NEW", com_rename }, 135 { "rename", 2, "OLD NEW", com_rename },
136 { "delete", 1, "MBOX", com_delete },
137 { "subscribe", 1, "MBX", com_subscribe }, 136 { "subscribe", 1, "MBX", com_subscribe },
138 { "unsubscribe", 1, "MBX", com_unsubscribe }, 137 { "unsubscribe", 1, "MBX", com_unsubscribe },
139 { NULL } 138 { NULL }
......
...@@ -37,12 +37,6 @@ ...@@ -37,12 +37,6 @@
37 #include <mailutils/sys/amd.h> 37 #include <mailutils/sys/amd.h>
38 38
39 static int 39 static int
40 _maildir_folder_init (mu_folder_t folder MU_ARG_UNUSED)
41 {
42 return 0;
43 }
44
45 static int
46 dir_exists (const char *name, const char *suf) 40 dir_exists (const char *name, const char *suf)
47 { 41 {
48 struct stat st; 42 struct stat st;
...@@ -59,31 +53,42 @@ dir_exists (const char *name, const char *suf) ...@@ -59,31 +53,42 @@ dir_exists (const char *name, const char *suf)
59 static int 53 static int
60 _maildir_is_scheme (mu_record_t record, mu_url_t url, int flags) 54 _maildir_is_scheme (mu_record_t record, mu_url_t url, int flags)
61 { 55 {
62 if (mu_url_is_scheme (url, record->scheme)) 56 int scheme_matched = mu_url_is_scheme (url, record->scheme);
63 return MU_FOLDER_ATTRIBUTE_FILE & flags; 57 int rc = 0;
64 58
65 if (mu_scheme_autodetect_p (url)) 59 if (scheme_matched || mu_scheme_autodetect_p (url))
66 { 60 {
67 /* Attemp auto-detection */ 61 /* Attemp auto-detection */
68 const char *path; 62 const char *path;
69 struct stat st; 63 struct stat st;
70 64
71 if (mu_url_sget_path (url, &path)) 65 if (mu_url_sget_path (url, &path))
72 return 0; 66 return 0;
73 67
74 if (stat (path, &st) < 0) 68 if (stat (path, &st) < 0)
75 return 0; 69 {
76 70 if (errno == ENOENT && scheme_matched)
71 return MU_FOLDER_ATTRIBUTE_ALL & flags;
72 return 0;
73 }
74
77 if (!S_ISDIR (st.st_mode)) 75 if (!S_ISDIR (st.st_mode))
78 return 0; 76 return 0;
79 77
80 if ((flags & MU_FOLDER_ATTRIBUTE_FILE) 78 if (scheme_matched)
81 && dir_exists (path, TMPSUF) 79 rc = MU_FOLDER_ATTRIBUTE_ALL;
82 && dir_exists (path, CURSUF) 80 else
83 && dir_exists (path, NEWSUF)) 81 {
84 return MU_FOLDER_ATTRIBUTE_FILE|MU_FOLDER_ATTRIBUTE_DIRECTORY; 82 rc |= MU_FOLDER_ATTRIBUTE_DIRECTORY;
83
84 if ((flags & MU_FOLDER_ATTRIBUTE_FILE)
85 && dir_exists (path, TMPSUF)
86 && dir_exists (path, CURSUF)
87 && dir_exists (path, NEWSUF))
88 rc |= MU_FOLDER_ATTRIBUTE_FILE;
89 }
85 } 90 }
86 return 0; 91 return rc & flags;
87 } 92 }
88 93
89 static int 94 static int
...@@ -106,7 +111,7 @@ static struct _mu_record _maildir_record = ...@@ -106,7 +111,7 @@ static struct _mu_record _maildir_record =
106 mu_url_expand_path, /* Url init. */ 111 mu_url_expand_path, /* Url init. */
107 _mailbox_maildir_init, /* Mailbox init. */ 112 _mailbox_maildir_init, /* Mailbox init. */
108 NULL, /* Mailer init. */ 113 NULL, /* Mailer init. */
109 _maildir_folder_init, /* Folder init. */ 114 _mu_fsfolder_init, /* Folder init. */
110 NULL, /* back pointer. */ 115 NULL, /* back pointer. */
111 _maildir_is_scheme, /* _is_scheme method. */ 116 _maildir_is_scheme, /* _is_scheme method. */
112 NULL, /* _get_url method. */ 117 NULL, /* _get_url method. */
......
...@@ -49,19 +49,23 @@ static int ...@@ -49,19 +49,23 @@ static int
49 _mbox_is_scheme (mu_record_t record, mu_url_t url, int flags) 49 _mbox_is_scheme (mu_record_t record, mu_url_t url, int flags)
50 { 50 {
51 int rc = 0; 51 int rc = 0;
52 52 int scheme_matched = mu_url_is_scheme (url, record->scheme);
53 if (mu_url_is_scheme (url, record->scheme)) 53 if (scheme_matched || mu_scheme_autodetect_p (url))
54 return MU_FOLDER_ATTRIBUTE_FILE & flags;
55
56 if (mu_scheme_autodetect_p (url))
57 { 54 {
58 struct stat st; 55 struct stat st;
59 const char *path; 56 const char *path;
60 57
61 mu_url_sget_path (url, &path); 58 mu_url_sget_path (url, &path);
62 if (stat (path, &st) < 0) 59 if (stat (path, &st) < 0)
63 return 0; 60 {
64 61 if (errno == ENOENT)
62 {
63 if (scheme_matched)
64 return MU_FOLDER_ATTRIBUTE_FILE & flags;
65 }
66 return 0;
67 }
68
65 if (S_ISREG (st.st_mode) || S_ISCHR (st.st_mode)) 69 if (S_ISREG (st.st_mode) || S_ISCHR (st.st_mode))
66 { 70 {
67 if (st.st_size == 0) 71 if (st.st_size == 0)
...@@ -71,7 +75,7 @@ _mbox_is_scheme (mu_record_t record, mu_url_t url, int flags) ...@@ -71,7 +75,7 @@ _mbox_is_scheme (mu_record_t record, mu_url_t url, int flags)
71 else if (flags & MU_FOLDER_ATTRIBUTE_FILE) 75 else if (flags & MU_FOLDER_ATTRIBUTE_FILE)
72 { 76 {
73 #if 0 77 #if 0
74 /* This effectively sieves out all non-mailbox files, 78 /* FIXME: This effectively sieves out all non-mailbox files,
75 but it makes mu_folder_enumerate crawl, which is 79 but it makes mu_folder_enumerate crawl, which is
76 intolerable for imap4d LIST command. */ 80 intolerable for imap4d LIST command. */
77 int fd = open (path, O_RDONLY); 81 int fd = open (path, O_RDONLY);
...@@ -106,7 +110,7 @@ static struct _mu_record _mbox_record = ...@@ -106,7 +110,7 @@ static struct _mu_record _mbox_record =
106 mu_url_expand_path, /* URL init. */ 110 mu_url_expand_path, /* URL init. */
107 _mailbox_mbox_init, /* Mailbox init. */ 111 _mailbox_mbox_init, /* Mailbox init. */
108 NULL, /* Mailer init. */ 112 NULL, /* Mailer init. */
109 _folder_mbox_init, /* Folder init. */ 113 _mu_fsfolder_init, /* Folder init. */
110 NULL, /* No need for an back pointer. */ 114 NULL, /* No need for an back pointer. */
111 _mbox_is_scheme, /* _is_scheme method. */ 115 _mbox_is_scheme, /* _is_scheme method. */
112 NULL, /* _get_url method. */ 116 NULL, /* _get_url method. */
...@@ -116,499 +120,4 @@ static struct _mu_record _mbox_record = ...@@ -116,499 +120,4 @@ static struct _mu_record _mbox_record =
116 }; 120 };
117 mu_record_t mu_mbox_record = &_mbox_record; 121 mu_record_t mu_mbox_record = &_mbox_record;
118 122
119 /* lsub/subscribe/unsubscribe are not needed. */
120 static void folder_mbox_destroy (mu_folder_t);
121 static int folder_mbox_open (mu_folder_t, int);
122 static int folder_mbox_close (mu_folder_t);
123 static int folder_mbox_delete (mu_folder_t, const char *);
124 static int folder_mbox_rename (mu_folder_t , const char *, const char *);
125 static int folder_mbox_list (mu_folder_t, const char *, void *, int,
126 size_t, mu_list_t, mu_folder_enumerate_fp,
127 void *);
128 static int folder_mbox_subscribe (mu_folder_t, const char *);
129 static int folder_mbox_unsubscribe (mu_folder_t, const char *);
130 static int folder_mbox_lsub (mu_folder_t, const char *, const char *,
131 mu_list_t);
132
133
134 static char *get_pathname (const char *, const char *);
135
136 static int folder_mbox_get_authority (mu_folder_t folder, mu_authority_t * pauth);
137
138 struct _fmbox
139 {
140 char *dirname;
141 char **subscribe;
142 size_t sublen;
143 };
144 typedef struct _fmbox *fmbox_t;
145
146
147 int
148 _folder_mbox_init (mu_folder_t folder)
149 {
150 fmbox_t dfolder;
151 int status = 0;
152
153 /* We create an authority so the API is uniform across the mailbox
154 types. */
155 status = folder_mbox_get_authority (folder, NULL);
156 if (status != 0)
157 return status;
158
159 dfolder = folder->data = calloc (1, sizeof (*dfolder));
160 if (dfolder == NULL)
161 return ENOMEM;
162
163 status = mu_url_aget_path (folder->url, &dfolder->dirname);
164 if (status == MU_ERR_NOENT)
165 {
166 dfolder->dirname = malloc (2);
167 if (dfolder->dirname == NULL)
168 status = ENOMEM;
169 else
170 {
171 strcpy (dfolder->dirname, ".");
172 status = 0;
173 }
174 }
175
176 if (status)
177 {
178 free (dfolder);
179 folder->data = NULL;
180 return status;
181 }
182
183 folder->_destroy = folder_mbox_destroy;
184
185 folder->_open = folder_mbox_open;
186 folder->_close = folder_mbox_close;
187
188 folder->_list = folder_mbox_list;
189 folder->_lsub = folder_mbox_lsub;
190 folder->_subscribe = folder_mbox_subscribe;
191 folder->_unsubscribe = folder_mbox_unsubscribe;
192 folder->_delete = folder_mbox_delete;
193 folder->_rename = folder_mbox_rename;
194 return 0;
195 }
196
197 void
198 folder_mbox_destroy (mu_folder_t folder)
199 {
200 if (folder->data)
201 {
202 fmbox_t fmbox = folder->data;
203 if (fmbox->dirname)
204 free (fmbox->dirname);
205 if (fmbox->subscribe)
206 free (fmbox->subscribe);
207 free (folder->data);
208 folder->data = NULL;
209 }
210 }
211
212 /* Noop. */
213 static int
214 folder_mbox_open (mu_folder_t folder, int flags MU_ARG_UNUSED)
215 {
216 fmbox_t fmbox = folder->data;
217 if (flags & MU_STREAM_CREAT)
218 {
219 return (mkdir (fmbox->dirname, S_IRWXU) == 0) ? 0 : errno;
220 }
221 return 0;
222 }
223
224 /* Noop. */
225 static int
226 folder_mbox_close (mu_folder_t folder MU_ARG_UNUSED)
227 {
228 return 0;
229 }
230
231 static int
232 folder_mbox_delete (mu_folder_t folder, const char *filename)
233 {
234 fmbox_t fmbox = folder->data;
235 if (filename)
236 {
237 int status = 0;
238 char *pathname = get_pathname (fmbox->dirname, filename);
239 if (pathname)
240 {
241 if (remove (pathname) != 0)
242 status = errno;
243 free (pathname);
244 }
245 else
246 status = ENOMEM;
247 return status;
248 }
249 return EINVAL;
250 }
251
252 static int
253 folder_mbox_rename (mu_folder_t folder, const char *oldpath,
254 const char *newpath)
255 {
256 fmbox_t fmbox = folder->data;
257 if (oldpath && newpath)
258 {
259 int status = 0;
260 char *pathold = get_pathname (fmbox->dirname, oldpath);
261 if (pathold)
262 {
263 char *pathnew = get_pathname (fmbox->dirname, newpath);
264 if (pathnew)
265 {
266 if (rename (pathold, pathnew) != 0)
267 status = errno;
268 free (pathnew);
269 }
270 else
271 status = ENOMEM;
272 free (pathold);
273 }
274 else
275 status = ENOMEM;
276 return status;
277 }
278 return EINVAL;
279 }
280
281 struct inode_list /* Inode/dev number list used to cut off
282 recursion */
283 {
284 struct inode_list *next;
285 ino_t inode;
286 dev_t dev;
287 };
288
289 struct search_data
290 {
291 mu_list_t result;
292 mu_folder_enumerate_fp enumfun;
293 void *enumdata;
294 char *dirname;
295 size_t dirlen;
296 void *pattern;
297 int flags;
298 size_t max_level;
299 size_t errcnt;
300 mu_folder_t folder;
301 };
302
303 static int
304 inode_list_lookup (struct inode_list *list, struct stat *st)
305 {
306 for (; list; list = list->next)
307 if (list->inode == st->st_ino && list->dev == st->st_dev)
308 return 1;
309 return 0;
310 }
311
312 static int
313 list_helper (struct search_data *data, mu_record_t record,
314 const char *dirname, size_t level,
315 struct inode_list *ilist)
316 {
317 DIR *dirp;
318 struct dirent *dp;
319 int stop = 0;
320
321 if (data->max_level && level > data->max_level)
322 return 0;
323
324 dirp = opendir (dirname);
325 if (dirp == NULL)
326 {
327 mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_ERROR,
328 ("list_helper cannot open directory %s: %s",
329 dirname, mu_strerror (errno)));
330 data->errcnt++;
331 return 1;
332 }
333
334 if (!record)
335 {
336 int type;
337 mu_registrar_lookup (dirname, MU_FOLDER_ATTRIBUTE_ALL,
338 &record, &type);
339 }
340
341 while ((dp = readdir (dirp)))
342 {
343 char const *ename = dp->d_name;
344 char *fname;
345 struct stat st;
346
347 if (ename[ename[0] != '.' ? 0 : ename[1] != '.' ? 1 : 2] == 0)
348 continue;
349 fname = get_pathname (dirname, ename);
350 if (lstat (fname, &st) == 0)
351 {
352 int f;
353 if (S_ISDIR (st.st_mode))
354 f = MU_FOLDER_ATTRIBUTE_DIRECTORY;
355 else if (S_ISREG (st.st_mode))
356 f = MU_FOLDER_ATTRIBUTE_FILE;
357 else if (S_ISLNK (st.st_mode))
358 f = MU_FOLDER_ATTRIBUTE_LINK;
359 else
360 f = 0;
361 if (mu_record_list_p (record, ename, f))
362 {
363 if (data->folder->_match == NULL
364 || data->folder->_match (fname + data->dirlen +
365 ((data->dirlen > 1
366 && data->dirname[data->dirlen-1] != '/') ?
367 1 : 0),
368 data->pattern,
369 data->flags) == 0)
370 {
371 char *refname = fname;
372 int type = 0;
373 struct mu_list_response *resp;
374 mu_record_t rec = NULL;
375
376 resp = malloc (sizeof (*resp));
377 if (resp == NULL)
378 {
379 mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_ERROR,
380 ("list_helper: %s", mu_strerror (ENOMEM)));
381 data->errcnt++;
382 free (fname);
383 continue;
384 }
385
386 mu_registrar_lookup (refname, MU_FOLDER_ATTRIBUTE_ALL,
387 &rec, &type);
388
389 resp->name = fname;
390 resp->level = level;
391 resp->separator = '/';
392 resp->type = type;
393 resp->format = rec;
394
395 if (resp->type == 0)
396 {
397 free (resp->name);
398 free (resp);
399 continue;
400 }
401
402 if (data->enumfun)
403 {
404 if (data->enumfun (data->folder, resp, data->enumdata))
405 {
406 free (resp->name);
407 free (resp);
408 stop = 1;
409 break;
410 }
411 }
412
413 if (data->result)
414 {
415 fname = NULL;
416 mu_list_append (data->result, resp);
417 }
418 else
419 free (resp);
420
421 if ((type & MU_FOLDER_ATTRIBUTE_DIRECTORY)
422 && !inode_list_lookup (ilist, &st))
423 {
424 struct inode_list idata;
425
426 idata.inode = st.st_ino;
427 idata.dev = st.st_dev;
428 idata.next = ilist;
429 stop = list_helper (data, rec, refname, level + 1,
430 &idata);
431 }
432 }
433 else if (S_ISDIR (st.st_mode))
434 {
435 struct inode_list idata;
436
437 idata.inode = st.st_ino;
438 idata.dev = st.st_dev;
439 idata.next = ilist;
440 stop = list_helper (data, NULL, fname, level + 1, &idata);
441 }
442 }
443 }
444 else
445 {
446 mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_ERROR,
447 ("list_helper cannot stat %s: %s",
448 fname, mu_strerror (errno)));
449 }
450 free (fname);
451 }
452 closedir (dirp);
453 return stop;
454 }
455
456 static int
457 folder_mbox_list (mu_folder_t folder, const char *ref,
458 void *pattern,
459 int flags,
460 size_t max_level,
461 mu_list_t flist,
462 mu_folder_enumerate_fp enumfun, void *enumdata)
463 {
464 fmbox_t fmbox = folder->data;
465 struct inode_list iroot;
466 struct search_data sdata;
467
468 memset (&iroot, 0, sizeof iroot);
469 sdata.dirname = get_pathname (fmbox->dirname, ref);
470 sdata.dirlen = strlen (sdata.dirname);
471 sdata.result = flist;
472 sdata.enumfun = enumfun;
473 sdata.enumdata = enumdata;
474 sdata.pattern = pattern;
475 sdata.flags = flags;
476 sdata.max_level = max_level;
477 sdata.folder = folder;
478 sdata.errcnt = 0;
479 list_helper (&sdata, NULL, sdata.dirname, 0, &iroot);
480 free (sdata.dirname);
481 /* FIXME: error code */
482 return 0;
483 }
484
485 static int
486 folder_mbox_lsub (mu_folder_t folder, const char *ref MU_ARG_UNUSED,
487 const char *name,
488 mu_list_t flist)
489 {
490 fmbox_t fmbox = folder->data;
491 int status;
492
493 if (name == NULL || *name == '\0')
494 name = "*";
495
496 if (fmbox->sublen > 0)
497 {
498 size_t i;
499
500 for (i = 0; i < fmbox->sublen; i++)
501 {
502 if (fmbox->subscribe[i]
503 && fnmatch (name, fmbox->subscribe[i], 0) == 0)
504 {
505 struct mu_list_response *resp;
506 resp = malloc (sizeof (*resp));
507 if (resp == NULL)
508 {
509 status = ENOMEM;
510 break;
511 }
512 else if ((resp->name = strdup (fmbox->subscribe[i])) == NULL)
513 {
514 free (resp);
515 status = ENOMEM;
516 break;
517 }
518 resp->type = MU_FOLDER_ATTRIBUTE_FILE;
519 resp->level = 0;
520 resp->separator = '/';
521 }
522 }
523 }
524 return status;
525 }
526
527 static int
528 folder_mbox_subscribe (mu_folder_t folder, const char *name)
529 {
530 fmbox_t fmbox = folder->data;
531 char **tmp;
532 size_t i;
533 for (i = 0; i < fmbox->sublen; i++)
534 {
535 if (fmbox->subscribe[i] && strcmp (fmbox->subscribe[i], name) == 0)
536 return 0;
537 }
538 tmp = realloc (fmbox->subscribe, (fmbox->sublen + 1) * sizeof (*tmp));
539 if (tmp == NULL)
540 return ENOMEM;
541 fmbox->subscribe = tmp;
542 fmbox->subscribe[fmbox->sublen] = strdup (name);
543 if (fmbox->subscribe[fmbox->sublen] == NULL)
544 return ENOMEM;
545 fmbox->sublen++;
546 return 0;
547 }
548
549 static int
550 folder_mbox_unsubscribe (mu_folder_t folder, const char *name)
551 {
552 fmbox_t fmbox = folder->data;
553 size_t i;
554 for (i = 0; i < fmbox->sublen; i++)
555 {
556 if (fmbox->subscribe[i] && strcmp (fmbox->subscribe[i], name) == 0)
557 {
558 free (fmbox->subscribe[i]);
559 fmbox->subscribe[i] = NULL;
560 return 0;
561 }
562 }
563 return MU_ERR_NOENT;
564 }
565
566 static char *
567 get_pathname (const char *dirname, const char *basename)
568 {
569 char *pathname = NULL;
570
571 /* Skip eventual protocol designator.
572 FIXME: Actually, any valid URL spec should be allowed as dirname ... */
573 if (strncmp (dirname, MU_MBOX_SCHEME, MU_MBOX_SCHEME_LEN) == 0)
574 dirname += MU_MBOX_SCHEME_LEN;
575 else if (strncmp (dirname, MU_FILE_SCHEME, MU_FILE_SCHEME_LEN) == 0)
576 dirname += MU_FILE_SCHEME_LEN;
577
578 /* null basename gives dirname. */
579 if (basename == NULL)
580 pathname = (dirname) ? strdup (dirname) : strdup (".");
581 /* Absolute. */
582 else if (basename[0] == '/')
583 pathname = strdup (basename);
584 /* Relative. */
585 else
586 {
587 size_t baselen = strlen (basename);
588 size_t dirlen = strlen (dirname);
589 while (dirlen > 0 && dirname[dirlen-1] == '/')
590 dirlen--;
591 pathname = calloc (dirlen + baselen + 2, sizeof (char));
592 if (pathname)
593 {
594 memcpy (pathname, dirname, dirlen);
595 pathname[dirlen] = '/';
596 strcpy (pathname + dirlen + 1, basename);
597 }
598 }
599 return pathname;
600 }
601
602 static int
603 folder_mbox_get_authority (mu_folder_t folder, mu_authority_t *pauth)
604 {
605 int status = 0;
606 if (folder->authority == NULL)
607 {
608 status = mu_authority_create_null (&folder->authority, folder);
609 }
610 if (!status && pauth)
611 *pauth = folder->authority;
612 return status;
613 }
614 123
......
...@@ -37,12 +37,6 @@ ...@@ -37,12 +37,6 @@
37 #include <mailutils/util.h> 37 #include <mailutils/util.h>
38 #include <mailutils/cctype.h> 38 #include <mailutils/cctype.h>
39 39
40 static int
41 _mh_folder_init (mu_folder_t folder MU_ARG_UNUSED)
42 {
43 return 0;
44 }
45
46 /* Check if NAME is a valid MH message name */ 40 /* Check if NAME is a valid MH message name */
47 static int 41 static int
48 mh_message_name_p (const char *name) 42 mh_message_name_p (const char *name)
...@@ -90,13 +84,11 @@ static int ...@@ -90,13 +84,11 @@ static int
90 _mh_is_scheme (mu_record_t record, mu_url_t url, int flags) 84 _mh_is_scheme (mu_record_t record, mu_url_t url, int flags)
91 { 85 {
92 int rc = 0; 86 int rc = 0;
87 int scheme_matched = mu_url_is_scheme (url, record->scheme);
93 88
94 if (mu_url_is_scheme (url, record->scheme)) 89 if (scheme_matched || mu_scheme_autodetect_p (url))
95 return MU_FOLDER_ATTRIBUTE_ALL & flags;
96
97 if (mu_scheme_autodetect_p (url))
98 { 90 {
99 /* Attemp auto-detection */ 91 /* Attempt auto-detection */
100 const char *path; 92 const char *path;
101 struct stat st; 93 struct stat st;
102 94
...@@ -104,18 +96,27 @@ _mh_is_scheme (mu_record_t record, mu_url_t url, int flags) ...@@ -104,18 +96,27 @@ _mh_is_scheme (mu_record_t record, mu_url_t url, int flags)
104 return 0; 96 return 0;
105 97
106 if (stat (path, &st) < 0) 98 if (stat (path, &st) < 0)
107 return 0; /* mu_mailbox_open will complain*/ 99 {
108 100 if (errno == ENOENT && scheme_matched)
101 return MU_FOLDER_ATTRIBUTE_ALL & flags;
102 return 0; /* mu_mailbox_open will complain*/
103 }
104
109 if (!S_ISDIR (st.st_mode)) 105 if (!S_ISDIR (st.st_mode))
110 return 0; 106 return 0;
111 107
112 rc |= (MU_FOLDER_ATTRIBUTE_DIRECTORY & flags); 108 if (scheme_matched)
109 rc = MU_FOLDER_ATTRIBUTE_ALL;
110 else
111 {
112 rc |= MU_FOLDER_ATTRIBUTE_DIRECTORY;
113 113
114 if ((flags & MU_FOLDER_ATTRIBUTE_FILE) && mh_dir_p (path)) 114 if ((flags & MU_FOLDER_ATTRIBUTE_FILE) && mh_dir_p (path))
115 return rc | MU_FOLDER_ATTRIBUTE_FILE; 115 rc |= MU_FOLDER_ATTRIBUTE_FILE;
116 }
116 } 117 }
117 118
118 return 0; 119 return rc & flags;
119 } 120 }
120 121
121 static int 122 static int
...@@ -142,7 +143,7 @@ static struct _mu_record _mh_record = ...@@ -142,7 +143,7 @@ static struct _mu_record _mh_record =
142 mu_url_expand_path, /* Url init. */ 143 mu_url_expand_path, /* Url init. */
143 _mailbox_mh_init, /* Mailbox init. */ 144 _mailbox_mh_init, /* Mailbox init. */
144 NULL, /* Mailer init. */ 145 NULL, /* Mailer init. */
145 _mh_folder_init, /* Folder init. */ 146 _mu_fsfolder_init, /* Folder init. */
146 NULL, /* back pointer. */ 147 NULL, /* back pointer. */
147 _mh_is_scheme, /* _is_scheme method. */ 148 _mh_is_scheme, /* _is_scheme method. */
148 NULL, /* _get_url method. */ 149 NULL, /* _get_url method. */
......
1 atconfig 1 atconfig
2 atlocal 2 atlocal
3 fldel
3 package.m4 4 package.m4
4 testsuite 5 testsuite
5 testsuite.dir 6 testsuite.dir
......
...@@ -50,6 +50,7 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac ...@@ -50,6 +50,7 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac
50 50
51 INCLUDES = @MU_LIB_COMMON_INCLUDES@ 51 INCLUDES = @MU_LIB_COMMON_INCLUDES@
52 noinst_PROGRAMS = \ 52 noinst_PROGRAMS = \
53 fldel\
53 lstuid\ 54 lstuid\
54 mbdel\ 55 mbdel\
55 mimetest\ 56 mimetest\
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2010, 2011 Free Software Foundation, Inc.
3
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
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 GNU Mailutils is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
16
17 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
20 #include <unistd.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <mailutils/mailutils.h>
24
25 int
26 main (int argc, char **argv)
27 {
28 int rc;
29 mu_folder_t f;
30
31 if (argc != 3)
32 {
33 fprintf (stderr, "usage: %s URL NAME\n", argv[0]);
34 return 1;
35 }
36
37 mu_register_all_mbox_formats ();
38
39 MU_ASSERT (mu_folder_create (&f, argv[1]));
40 rc = mu_folder_delete (f, argv[2]);
41 if (rc)
42 {
43 if (rc == ENOTEMPTY)
44 {
45 printf ("mailbox removed, but has subfolders\n");
46 rc = 0;
47 }
48 else
49 fprintf (stderr, "%s\n", mu_strerror (rc));
50 }
51 mu_folder_destroy (&f);
52
53 return rc != 0;
54 }