Commit b9ef5553 b9ef5553104e1125d305c828017394c40941b19a by Sergey Poznyakoff

* examples/lsf.c: Use mu_folder_enumerate + callback function, for

speed up.
* imap4d/imap4d.h (WCARD_NOMATCH,WCARD_MATCH)
(WCARD_RECURSE_MATCH): Remove.
* imap4d/list.c: Rewrite using mu_folder_enumerate.
* imap4d/lsub.c (imap4d_lsub): Fix call to util_wcard_match.
* imap4d/util.c (util_wcard_match): Return 0 for match, 1
otherwise.
* imap4d/testsuite/imap4d/list.exp: Fix two testcases to match
the new (stricter RFC-compliant) behavior.
* include/mailutils/folder.h (mu_folder_match_fp): New typedef.
(mu_folder_enumerate_fp): New typedef.
(mu_folder_enumerate): New function.
(mu_folder_set_match, mu_folder_get_match): New functions.

* libproto/imap/folder.c, libproto/include/imap0.h,
libproto/nntp/folder.c : Use new folder list framework.
* libproto/include/folder0.h (struct _mu_folder._list): Change
signature.
(_match): New member.
* libproto/mbox/folder.c (_path_is_scheme): Improve automatic
mailbox	format detection.
(folder_mbox_list): Do not use glob, recursively scan
subdirectories instead.
* mailbox/folder.c (mu_folder_match): New function.
(mu_folder_create_from_record): Set mu_folder_match as the default
matcher.
(mu_folder_set_match, mu_folder_get_match): New functions.
(mu_folder_enumerate): New function.
(mu_folder_list): Rewrite using mu_folder_enumerate.
1 parent 6d490ce1
1 2007-12-21 Sergey Poznyakoff <gray@gnu.org.ua>
2
3 * examples/lsf.c: Use mu_folder_enumerate + callback function, for
4 speed up.
5 * imap4d/imap4d.h (WCARD_NOMATCH,WCARD_MATCH)
6 (WCARD_RECURSE_MATCH): Remove.
7 * imap4d/list.c: Rewrite using mu_folder_enumerate.
8 * imap4d/lsub.c (imap4d_lsub): Fix call to util_wcard_match.
9 * imap4d/util.c (util_wcard_match): Return 0 for match, 1
10 otherwise.
11 * imap4d/testsuite/imap4d/list.exp: Fix two testcases to match
12 the new (stricter RFC-compliant) behavior.
13 * include/mailutils/folder.h (mu_folder_match_fp): New typedef.
14 (mu_folder_enumerate_fp): New typedef.
15 (mu_folder_enumerate): New function.
16 (mu_folder_set_match, mu_folder_get_match): New functions.
17
18 * libproto/imap/folder.c, libproto/include/imap0.h,
19 libproto/nntp/folder.c : Use new folder list framework.
20 * libproto/include/folder0.h (struct _mu_folder._list): Change
21 signature.
22 (_match): New member.
23 * libproto/mbox/folder.c (_path_is_scheme): Improve automatic
24 mailbox format detection.
25 (folder_mbox_list): Do not use glob, recursively scan
26 subdirectories instead.
27 * mailbox/folder.c (mu_folder_match): New function.
28 (mu_folder_create_from_record): Set mu_folder_match as the default
29 matcher.
30 (mu_folder_set_match, mu_folder_get_match): New functions.
31 (mu_folder_enumerate): New function.
32 (mu_folder_list): Rewrite using mu_folder_enumerate.
33
1 2007-12-19 Sergey Poznyakoff <gray@gnu.org.ua> 34 2007-12-19 Sergey Poznyakoff <gray@gnu.org.ua>
2 35
3 * NEWS: Update. 36 * NEWS: Update.
......
...@@ -25,10 +25,8 @@ ...@@ -25,10 +25,8 @@
25 #include <mailutils/mailutils.h> 25 #include <mailutils/mailutils.h>
26 26
27 static int 27 static int
28 ls_printer (void *item, void *data) 28 enumfun (mu_folder_t folder, struct mu_list_response *resp, void *data)
29 { 29 {
30 struct mu_list_response *resp = item;
31
32 printf ("%c%c %c %4d %s\n", 30 printf ("%c%c %c %4d %s\n",
33 (resp->type & MU_FOLDER_ATTRIBUTE_DIRECTORY) ? 'd' : '-', 31 (resp->type & MU_FOLDER_ATTRIBUTE_DIRECTORY) ? 'd' : '-',
34 (resp->type & MU_FOLDER_ATTRIBUTE_FILE) ? 'f' : '-', 32 (resp->type & MU_FOLDER_ATTRIBUTE_FILE) ? 'f' : '-',
...@@ -60,13 +58,14 @@ ls_folders (char *fname, char *ref, char *pattern, int level) ...@@ -60,13 +58,14 @@ ls_folders (char *fname, char *ref, char *pattern, int level)
60 return 1; 58 return 1;
61 } 59 }
62 60
63 status = mu_folder_list (folder, ref, pattern, level, &flist); 61 status = mu_folder_enumerate (folder, ref, pattern, 0, level, &flist,
62 enumfun, NULL);
63
64 switch (status) 64 switch (status)
65 { 65 {
66 case 0: 66 case 0:
67 mu_list_count (flist, &count); 67 mu_list_count (flist, &count);
68 printf ("Number of folders: %lu\n", (unsigned long) count); 68 printf ("Number of folders: %lu\n", (unsigned long) count);
69 mu_list_do (flist, ls_printer, NULL);
70 mu_list_destroy (&flist); 69 mu_list_destroy (&flist);
71 break; 70 break;
72 case MU_ERR_NOENT: 71 case MU_ERR_NOENT:
...@@ -105,7 +104,5 @@ main (int argc, char *argv[]) ...@@ -105,7 +104,5 @@ main (int argc, char *argv[])
105 104
106 mu_register_all_mbox_formats (); 105 mu_register_all_mbox_formats ();
107 106
108 if (!ref)
109 ref = folder;
110 return ls_folders (folder, ref, pattern, level); 107 return ls_folders (folder, ref, pattern, level);
111 } 108 }
......
...@@ -148,11 +148,6 @@ struct imap4d_command ...@@ -148,11 +148,6 @@ struct imap4d_command
148 #define NS_SHARED 2 148 #define NS_SHARED 2
149 #define NS_MAX 3 149 #define NS_MAX 3
150 150
151 /* Wildcard return codes */
152 #define WCARD_NOMATCH 0
153 #define WCARD_MATCH 1
154 #define WCARD_RECURSE_MATCH 2
155
156 /* IMAP4D capability names */ 151 /* IMAP4D capability names */
157 #define IMAP_CAPA_STARTTLS "STARTTLS" 152 #define IMAP_CAPA_STARTTLS "STARTTLS"
158 #define IMAP_CAPA_LOGINDISABLED "LOGINDISABLED" 153 #define IMAP_CAPA_LOGINDISABLED "LOGINDISABLED"
......
...@@ -28,13 +28,90 @@ ...@@ -28,13 +28,90 @@
28 #define NOINFERIORS (1 << 3) 28 #define NOINFERIORS (1 << 3)
29 #define NOSELECT_RECURSE (1 << 4) 29 #define NOSELECT_RECURSE (1 << 4)
30 30
31 struct inode_list 31 static int
32 imap4d_match (const char *name, void *pat, int flags)
33 {
34 return util_wcard_match (name, pat, "/");
35 }
36
37 struct refinfo
32 { 38 {
33 struct inode_list *next; 39 char *refptr; /* Original reference */
34 ino_t inode; 40 size_t reflen; /* Length of the original reference */
35 dev_t dev; 41 size_t pfxlen; /* Length of the current prefix */
42 size_t homelen; /* Length of homedir */
43 char *buf;
44 size_t bufsize;
36 }; 45 };
37 46
47 static int
48 list_fun (mu_folder_t folder, struct mu_list_response *resp, void *data)
49 {
50 char *name;
51 struct refinfo *refinfo = data;
52 size_t size;
53
54 name = resp->name;
55 size = strlen (name);
56 if (size == refinfo->homelen + 6
57 && memcmp (name, homedir, refinfo->homelen) == 0
58 && memcmp (name + refinfo->homelen + 1, "INBOX", 5) == 0)
59 return 0;
60
61 util_send ("* %s", "LIST (");
62 if ((resp->type & (MU_FOLDER_ATTRIBUTE_FILE|MU_FOLDER_ATTRIBUTE_DIRECTORY))
63 == (MU_FOLDER_ATTRIBUTE_FILE|MU_FOLDER_ATTRIBUTE_DIRECTORY))
64 /* nothing */;
65 else if (resp->type & MU_FOLDER_ATTRIBUTE_FILE)
66 util_send ("\\NoInferiors");
67 else if (resp->type & MU_FOLDER_ATTRIBUTE_DIRECTORY)
68 util_send ("\\NoSelect");
69
70 util_send (") \"%c\" ", resp->separator);
71
72 name = resp->name + refinfo->pfxlen;
73 size = strlen (name) + refinfo->reflen + 1;
74 if (size > refinfo->bufsize)
75 {
76 if (refinfo->buf == NULL)
77 {
78 refinfo->bufsize = size;
79 refinfo->buf = malloc (refinfo->bufsize);
80 if (!refinfo->buf)
81 {
82 mu_error ("%s", mu_strerror (errno));
83 return 1;
84 }
85 memcpy (refinfo->buf, refinfo->refptr, refinfo->reflen);
86 }
87 else
88 {
89 char *p = realloc (refinfo->buf, size);
90 if (!p)
91 {
92 mu_error ("%s", mu_strerror (errno));
93 return 1;
94 }
95 refinfo->buf = p;
96 refinfo->bufsize = size;
97 }
98 }
99
100 if ((refinfo->reflen == 0 || refinfo->refptr[refinfo->reflen - 1] == '/')
101 && name[0] == '/')
102 name++;
103 strcpy (refinfo->buf + refinfo->reflen, name);
104 name = refinfo->buf;
105
106 if (strpbrk (name, "\"{}"))
107 util_send ("{%d}\r\n%s\r\n", strlen (name), name);
108 else if (is_atom (name))
109 util_send ("%s\r\n", name);
110 else
111 util_send ("\"%s\"\r\n", name);
112 return 0;
113 }
114
38 /* 115 /*
39 1- IMAP4 insists: the reference argument present in the 116 1- IMAP4 insists: the reference argument present in the
40 interpreted form SHOULD prefix the interpreted form. It SHOULD 117 interpreted form SHOULD prefix the interpreted form. It SHOULD
...@@ -42,6 +119,7 @@ struct inode_list ...@@ -42,6 +119,7 @@ struct inode_list
42 rule permits the client to determine if the returned mailbox name 119 rule permits the client to determine if the returned mailbox name
43 is in the context of the reference argument, or if something about 120 is in the context of the reference argument, or if something about
44 the mailbox argument overrode the reference argument. 121 the mailbox argument overrode the reference argument.
122
45 ex: 123 ex:
46 Reference Mailbox --> Interpretation 124 Reference Mailbox --> Interpretation
47 ~smith/Mail foo.* --> ~smith/Mail/foo.* 125 ~smith/Mail foo.* --> ~smith/Mail/foo.*
...@@ -51,13 +129,8 @@ struct inode_list ...@@ -51,13 +129,8 @@ struct inode_list
51 archive ~fred/Mail --> ~fred/Mail/ * 129 archive ~fred/Mail --> ~fred/Mail/ *
52 130
53 2- The character "*" is a wildcard, and matches zero or more characters 131 2- The character "*" is a wildcard, and matches zero or more characters
54 at this position. The charcater "%" is similar to "*", 132 at this position. The character "%" is similar to "*",
55 but it does not match a hierarchy delimiter. */ 133 but it does not match the hierarchy delimiter. */
56
57 static int match (const char *, const char *, const char *);
58 static void list_file (const char *, const char *, const char *, const char *, struct inode_list *);
59 static void print_file (const char *, const char *, const char *);
60 static void print_dir (const char *, const char *, const char *);
61 134
62 int 135 int
63 imap4d_list (struct imap4d_command *command, char *arg) 136 imap4d_list (struct imap4d_command *command, char *arg)
...@@ -90,8 +163,12 @@ imap4d_list (struct imap4d_command *command, char *arg) ...@@ -90,8 +163,12 @@ imap4d_list (struct imap4d_command *command, char *arg)
90 } 163 }
91 else 164 else
92 { 165 {
166 int status;
167 mu_folder_t folder;
93 char *cwd; 168 char *cwd;
94 char *dir; 169 char *p, *q;
170 struct refinfo refinfo;
171
95 switch (*wcard) 172 switch (*wcard)
96 { 173 {
97 /* Absolute Path in wcard, dump the old ref. */ 174 /* Absolute Path in wcard, dump the old ref. */
...@@ -130,20 +207,22 @@ imap4d_list (struct imap4d_command *command, char *arg) ...@@ -130,20 +207,22 @@ imap4d_list (struct imap4d_command *command, char *arg)
130 /* Move any directory not containing a wildcard into the reference 207 /* Move any directory not containing a wildcard into the reference
131 So (ref = ~guest, wcard = Mail/folder1/%.vf) --> 208 So (ref = ~guest, wcard = Mail/folder1/%.vf) -->
132 (ref = ~guest/Mail/folder1, wcard = %.vf). */ 209 (ref = ~guest/Mail/folder1, wcard = %.vf). */
133 for (; (dir = strpbrk (wcard, "/%*")); wcard = dir) 210 for (p = wcard; (q = strpbrk (p, "/%*")) && *q == '/'; p = q + 1)
211 ;
212
213 if (p > wcard)
134 { 214 {
135 if (*dir == '/') 215 size_t seglen = p - wcard;
136 { 216 size_t reflen = strlen (ref);
137 *dir = '\0'; 217 int addslash = !!(reflen == 0 || ref[reflen-1] != '/');
138 ref = realloc (ref, strlen (ref) + 1 + (dir - wcard) + 1); 218 size_t len = seglen + reflen + addslash + 1;
139 if (*ref && ref[strlen (ref) - 1] != '/') 219
140 strcat (ref, "/"); 220 ref = realloc (ref, len);
141 strcat (ref, wcard); 221 if (addslash)
142 dir++; 222 ref[reflen++] = '/';
143 } 223 memcpy (ref + reflen, wcard, seglen);
144 else 224 ref[reflen + seglen] = 0;
145 dir = wcard; 225 wcard += seglen;
146 break;
147 } 226 }
148 227
149 /* Allocates. */ 228 /* Allocates. */
...@@ -154,6 +233,22 @@ imap4d_list (struct imap4d_command *command, char *arg) ...@@ -154,6 +233,22 @@ imap4d_list (struct imap4d_command *command, char *arg)
154 return util_finish (command, RESP_NO, 233 return util_finish (command, RESP_NO,
155 "The requested item could not be found."); 234 "The requested item could not be found.");
156 } 235 }
236 status = mu_folder_create (&folder, cwd);
237 if (status)
238 {
239 free (ref);
240 free (cwd);
241 return util_finish (command, RESP_NO,
242 "The requested item could not be found.");
243 }
244 mu_folder_set_match (folder, imap4d_match);
245
246 memset (&refinfo, 0, sizeof refinfo);
247
248 refinfo.refptr = ref;
249 refinfo.reflen = strlen (ref);
250 refinfo.pfxlen = strlen (cwd);
251 refinfo.homelen = strlen (homedir);
157 252
158 /* The special name INBOX is included in the output from LIST, if 253 /* The special name INBOX is included in the output from LIST, if
159 INBOX is supported by this server for this user and if the 254 INBOX is supported by this server for this user and if the
...@@ -163,22 +258,14 @@ imap4d_list (struct imap4d_command *command, char *arg) ...@@ -163,22 +258,14 @@ imap4d_list (struct imap4d_command *command, char *arg)
163 failure; it is not relevant whether the user's real INBOX resides 258 failure; it is not relevant whether the user's real INBOX resides
164 on this or some other server. */ 259 on this or some other server. */
165 260
166 if (!*ref && (match ("INBOX", wcard, delim) 261 if (!*ref && (imap4d_match ("INBOX", wcard, 0) == 0
167 || match ("inbox", wcard, delim))) 262 || imap4d_match ("inbox", wcard, 0) == 0))
168 util_out (RESP_NONE, "LIST (\\NoInferiors) NIL INBOX"); 263 util_out (RESP_NONE, "LIST (\\NoInferiors) NIL INBOX");
169 264
170 if (chdir (cwd) == 0) 265 mu_folder_enumerate (folder, NULL, wcard, 0, 0, NULL,
171 { 266 list_fun, &refinfo);
172 struct stat st; 267 mu_folder_destroy (&folder);
173 struct inode_list inode_rec; 268 free (refinfo.buf);
174
175 stat (cwd, &st);
176 inode_rec.next = NULL;
177 inode_rec.inode = st.st_ino;
178 inode_rec.dev = st.st_dev;
179 list_file (cwd, ref, (dir) ? dir : wcard, delim, &inode_rec);
180 chdir (homedir);
181 }
182 free (cwd); 269 free (cwd);
183 free (ref); 270 free (ref);
184 } 271 }
...@@ -186,188 +273,3 @@ imap4d_list (struct imap4d_command *command, char *arg) ...@@ -186,188 +273,3 @@ imap4d_list (struct imap4d_command *command, char *arg)
186 return util_finish (command, RESP_OK, "Completed"); 273 return util_finish (command, RESP_OK, "Completed");
187 } 274 }
188 275
189 static int
190 inode_list_lookup (struct inode_list *list, struct stat *st)
191 {
192 for (; list; list = list->next)
193 if (list->inode == st->st_ino && list->dev == st->st_dev)
194 return 1;
195 return 0;
196 }
197
198 static char *
199 mkfullname (const char *dir, const char *name, const char *delim)
200 {
201 char *p;
202 int dlen = strlen (dir);
203
204 if (dlen == 0)
205 return strdup (name);
206
207 if (dir[dlen-1] == delim[0])
208 dlen--;
209
210 p = malloc (dlen + 1 + strlen (name) + 1);
211 if (p)
212 {
213 memcpy (p, dir, dlen);
214 p[dlen] = '/';
215 strcpy (p + dlen + 1, name);
216 }
217 return p;
218 }
219
220 /* Recusively calling the files. */
221 static void
222 list_file (const char *cwd, const char *ref, const char *pattern,
223 const char *delim, struct inode_list *inode_list)
224 {
225 DIR *dirp;
226 struct dirent *dp;
227 char *next;
228
229 if (!cwd || !ref)
230 return;
231
232 /* Shortcut no wildcards. */
233 if (*pattern == '\0' || !strpbrk (pattern, "%*"))
234 {
235 /* Equivalent to stat(). */
236 int status;
237 if (*pattern == '\0')
238 status = match (cwd, cwd, delim);
239 else
240 status = match (pattern, pattern, delim);
241 if (status & NOSELECT)
242 print_dir (ref, pattern, delim);
243 else if (status & NOINFERIORS)
244 print_file (ref, pattern, delim);
245 return ;
246 }
247
248 dirp = opendir (".");
249 if (dirp == NULL)
250 return;
251
252 next = strchr (pattern, delim[0]);
253 if (next)
254 *next++ = '\0';
255 while ((dp = readdir (dirp)) != NULL)
256 {
257 /* Skip "", ".", and "..". "" is returned by at least one buggy
258 implementation: Solaris 2.4 readdir on NFS filesystems. */
259 char const *entry = dp->d_name;
260 if (entry[entry[0] != '.' ? 0 : entry[1] != '.' ? 1 : 2] != '\0' &&
261 !(!strcmp (entry, "INBOX") && !strcmp(cwd, homedir)))
262 {
263 int status = match (entry, pattern, delim);
264 if (status)
265 {
266 if (status & NOSELECT)
267 {
268 struct stat st;
269
270 if (stat (entry, &st))
271 {
272 mu_error (_("Cannot stat %s: %s"),
273 entry, strerror (errno));
274 continue;
275 }
276
277 if (next || status & RECURSE_MATCH)
278 {
279 if (!next)
280 print_dir (ref, entry, delim);
281
282 if (S_ISDIR (st.st_mode)
283 && inode_list_lookup (inode_list, &st) == 0)
284 {
285 if (chdir (entry) == 0)
286 {
287 char *rf;
288 char *cd;
289 struct inode_list inode_rec;
290
291 inode_rec.inode = st.st_ino;
292 inode_rec.dev = st.st_dev;
293 inode_rec.next = inode_list;
294 rf = mkfullname (ref, entry, delim);
295 cd = mkfullname (cwd, entry, delim);
296 list_file (cd, rf, (next) ? next : pattern,
297 delim, &inode_rec);
298 free (rf);
299 free (cd);
300 chdir (cwd);
301 }
302 }
303 }
304 else
305 print_dir (ref, entry, delim);
306 }
307 else if (status & NOINFERIORS)
308 {
309 print_file (ref, entry, delim);
310 }
311 }
312 }
313 }
314 closedir (dirp);
315 }
316
317 static void
318 print_name (const char *ref, const char *file, const char *delim,
319 const char *attr)
320 {
321 char *name = mkfullname (ref, file, delim);
322 if (strpbrk (name, "\"{}"))
323 {
324 util_out (RESP_NONE, "LIST (%s) \"%s\" {%d}",
325 attr, delim, strlen (name));
326 util_send ("%s\r\n", name);
327 }
328 else if (is_atom (name))
329 util_out (RESP_NONE, "LIST (%s) \"%s\" %s", attr, delim, name);
330 else
331 util_out (RESP_NONE, "LIST (%s) \"%s\" \"%s\"", attr, delim, name);
332 free (name);
333 }
334
335 static void
336 print_file (const char *ref, const char *file, const char *delim)
337 {
338 print_name (ref, file, delim, "\\NoInferiors");
339 }
340
341 static void
342 print_dir (const char *ref, const char *file, const char *delim)
343 {
344 print_name (ref, file, delim, "\\NoSelect");
345 }
346
347 /* Calls the imap_matcher if a match found out the attribute. */
348 static int
349 match (const char *entry, const char *pattern, const char *delim)
350 {
351 struct stat stats;
352 int status = util_wcard_match (entry, pattern, delim);
353
354 switch (status)
355 {
356 case WCARD_RECURSE_MATCH:
357 status = RECURSE_MATCH;
358 break;
359 case WCARD_MATCH:
360 status = MATCH;
361 break;
362 case WCARD_NOMATCH:
363 status = NOMATCH;
364 }
365
366 if (status)
367 {
368 if (stat (entry, &stats) == 0)
369 status |= (S_ISREG (stats.st_mode)) ? NOINFERIORS : NOSELECT;
370 }
371 return status;
372 }
373
......
...@@ -60,12 +60,12 @@ imap4d_lsub (struct imap4d_command *command, char *arg) ...@@ -60,12 +60,12 @@ imap4d_lsub (struct imap4d_command *command, char *arg)
60 char *buf = NULL; 60 char *buf = NULL;
61 size_t n = 0; 61 size_t n = 0;
62 62
63 while (getline(&buf, &n, fp) > 0) 63 while (getline (&buf, &n, fp) > 0)
64 { 64 {
65 int len = strlen (buf); 65 int len = strlen (buf);
66 if (buf[len - 1] == '\n') 66 if (buf[len - 1] == '\n')
67 buf[len - 1] = '\0'; 67 buf[len - 1] = '\0';
68 if (util_wcard_match (buf, pattern, delim) != WCARD_NOMATCH) 68 if (util_wcard_match (buf, pattern, delim) == 0)
69 util_out (RESP_NONE, "LIST () \"%s\" %s", delim, buf); 69 util_out (RESP_NONE, "LIST () \"%s\" %s", delim, buf);
70 } 70 }
71 fclose (fp); 71 fclose (fp);
......
...@@ -53,8 +53,6 @@ imap4d_test "LIST \"/\" \"*\""\ ...@@ -53,8 +53,6 @@ imap4d_test "LIST \"/\" \"*\""\
53 53
54 imap4d_test -sort "LIST \"$MU_DATA_DIR\" \"*\""\ 54 imap4d_test -sort "LIST \"$MU_DATA_DIR\" \"*\""\
55 "LIST (\\NoSelect) \"/\" $MU_DATA_DIR/etc"\ 55 "LIST (\\NoSelect) \"/\" $MU_DATA_DIR/etc"\
56 "LIST (\\NoInferiors) \"/\" $MU_DATA_DIR/etc/mail.rc"\
57 "LIST (\\NoInferiors) \"/\" $MU_DATA_DIR/etc/passwd"\
58 "LIST (\\NoSelect) \"/\" $MU_DATA_DIR/spool"\ 56 "LIST (\\NoSelect) \"/\" $MU_DATA_DIR/spool"\
59 "LIST (\\NoInferiors) \"/\" $MU_DATA_DIR/spool/bigto.mbox"\ 57 "LIST (\\NoInferiors) \"/\" $MU_DATA_DIR/spool/bigto.mbox"\
60 "LIST (\\NoInferiors) \"/\" $MU_DATA_DIR/spool/relational.mbox" \ 58 "LIST (\\NoInferiors) \"/\" $MU_DATA_DIR/spool/relational.mbox" \
...@@ -77,13 +75,8 @@ imap4d_test "LIST \"$MU_DATA_DIR/folder\" \"one\""\ ...@@ -77,13 +75,8 @@ imap4d_test "LIST \"$MU_DATA_DIR/folder\" \"one\""\
77 "LIST (\\NoInferiors) \"/\" $MU_DATA_DIR/folder/one"\ 75 "LIST (\\NoInferiors) \"/\" $MU_DATA_DIR/folder/one"\
78 "OK LIST Completed" 76 "OK LIST Completed"
79 77
80 # Well, I doubt if this is quite OK with the RFC, but at least it does
81 # not contradict it. The first INBOX refers to the reserved word meaning
82 # "the primary mailbox for this user on this server", the second one is
83 # the actual filename.
84 imap4d_test -sort "LIST \"\" INBOX"\ 78 imap4d_test -sort "LIST \"\" INBOX"\
85 "LIST (\\NoInferiors) NIL INBOX"\ 79 "LIST (\\NoInferiors) NIL INBOX"\
86 "LIST (\\NoInferiors) \"/\" INBOX"\
87 "OK LIST Completed" 80 "OK LIST Completed"
88 81
89 imap4d_stop 82 imap4d_stop
......
...@@ -1028,7 +1028,7 @@ util_localname () ...@@ -1028,7 +1028,7 @@ util_localname ()
1028 return localname; 1028 return localname;
1029 } 1029 }
1030 1030
1031 /* Match STRING against the IMAP4 wildard pattern PATTERN */ 1031 /* Match STRING against the IMAP4 wildcard pattern PATTERN. */
1032 1032
1033 int 1033 int
1034 util_wcard_match (const char *string, const char *pattern, const char *delim) 1034 util_wcard_match (const char *string, const char *pattern, const char *delim)
...@@ -1041,40 +1041,39 @@ util_wcard_match (const char *string, const char *pattern, const char *delim) ...@@ -1041,40 +1041,39 @@ util_wcard_match (const char *string, const char *pattern, const char *delim)
1041 switch (c) 1041 switch (c)
1042 { 1042 {
1043 case '%': 1043 case '%':
1044 /* Matches everything except '/' */
1044 if (*p == '\0') 1045 if (*p == '\0')
1045 { 1046 {
1046 /* Matches everything except '/' */ 1047 for (; *n; ++n)
1047 for (; *n && *n != delim[0]; n++) 1048 if (*n == *delim)
1048 ; 1049 return 1;
1049 return (*n == delim[0]) ? WCARD_RECURSE_MATCH : WCARD_MATCH; 1050 return 0;
1050 } 1051 }
1051 else 1052 else
1052 for (; *n != '\0'; ++n) 1053 for (; *n != '\0'; ++n)
1053 if (util_wcard_match (n, p, delim) == WCARD_MATCH) 1054 if (util_wcard_match (n, p, delim) == 0)
1054 return WCARD_MATCH; 1055 return 0;
1055 break; 1056 break;
1056 1057
1057 case '*': 1058 case '*':
1058 if (*p == '\0') 1059 if (*p == '\0')
1059 return WCARD_RECURSE_MATCH; 1060 return 0;
1060 for (; *n != '\0'; ++n) 1061 else
1061 { 1062 for (; *n != '\0'; ++n)
1062 int status = util_wcard_match (n, p, delim); 1063 if (util_wcard_match (n, p, delim) == 0)
1063 if (status == WCARD_MATCH || status == WCARD_RECURSE_MATCH) 1064 return 0;
1064 return status;
1065 }
1066 break; 1065 break;
1067 1066
1068 default: 1067 default:
1069 if (c != *n) 1068 if (c != *n)
1070 return WCARD_NOMATCH; 1069 return 1;
1071 } 1070 }
1072 } 1071 }
1073 1072
1074 if (!c && !*n) 1073 if (!c && !*n)
1075 return WCARD_MATCH; 1074 return 0;
1076 1075
1077 return WCARD_NOMATCH; 1076 return 1;
1078 } 1077 }
1079 1078
1080 /* Return the uindvalidity of a mailbox. 1079 /* Return the uindvalidity of a mailbox.
......
...@@ -33,6 +33,10 @@ struct mu_list_response ...@@ -33,6 +33,10 @@ struct mu_list_response
33 char *name; 33 char *name;
34 }; 34 };
35 35
36 typedef int (*mu_folder_match_fp) (const char *, void *, int);
37 typedef int (*mu_folder_enumerate_fp) (mu_folder_t, struct mu_list_response *,
38 void *data);
39
36 /* Constructor/destructor and possible types. */ 40 /* Constructor/destructor and possible types. */
37 extern int mu_folder_create (mu_folder_t *, const char *); 41 extern int mu_folder_create (mu_folder_t *, const char *);
38 extern int mu_folder_create_from_record (mu_folder_t *, const char *, 42 extern int mu_folder_create_from_record (mu_folder_t *, const char *,
...@@ -47,8 +51,12 @@ extern int mu_folder_delete (mu_folder_t, const char *); ...@@ -47,8 +51,12 @@ extern int mu_folder_delete (mu_folder_t, const char *);
47 extern int mu_folder_rename (mu_folder_t, const char *, const char *); 51 extern int mu_folder_rename (mu_folder_t, const char *, const char *);
48 extern int mu_folder_subscribe (mu_folder_t, const char *); 52 extern int mu_folder_subscribe (mu_folder_t, const char *);
49 extern int mu_folder_unsubscribe (mu_folder_t, const char *); 53 extern int mu_folder_unsubscribe (mu_folder_t, const char *);
50 extern int mu_folder_list (mu_folder_t, const char *, const char *, 54 extern int mu_folder_list (mu_folder_t, const char *, void *,
51 size_t, mu_list_t *); 55 size_t, mu_list_t *);
56 extern int mu_folder_enumerate (mu_folder_t, const char *,
57 void *, int,
58 size_t, mu_list_t *,
59 mu_folder_enumerate_fp, void *);
52 extern int mu_folder_lsub (mu_folder_t, const char *, const char *, 60 extern int mu_folder_lsub (mu_folder_t, const char *, const char *,
53 mu_list_t *); 61 mu_list_t *);
54 62
...@@ -56,6 +64,11 @@ extern int mu_folder_lsub (mu_folder_t, const char *, const char *, ...@@ -56,6 +64,11 @@ extern int mu_folder_lsub (mu_folder_t, const char *, const char *,
56 extern int mu_folder_get_stream (mu_folder_t, mu_stream_t *); 64 extern int mu_folder_get_stream (mu_folder_t, mu_stream_t *);
57 extern int mu_folder_set_stream (mu_folder_t, mu_stream_t); 65 extern int mu_folder_set_stream (mu_folder_t, mu_stream_t);
58 66
67 /* Match function */
68 extern int mu_folder_set_match (mu_folder_t folder, mu_folder_match_fp pmatch);
69 extern int mu_folder_get_match (mu_folder_t folder,
70 mu_folder_match_fp *pmatch);
71
59 /* Notifications. */ 72 /* Notifications. */
60 extern int mu_folder_get_observable (mu_folder_t, mu_observable_t *); 73 extern int mu_folder_get_observable (mu_folder_t, mu_observable_t *);
61 74
......
...@@ -111,6 +111,7 @@ typedef struct _mu_tcp_server *mu_tcp_server_t; ...@@ -111,6 +111,7 @@ typedef struct _mu_tcp_server *mu_tcp_server_t;
111 111
112 #define MU_FOLDER_ATTRIBUTE_DIRECTORY 0x001 112 #define MU_FOLDER_ATTRIBUTE_DIRECTORY 0x001
113 #define MU_FOLDER_ATTRIBUTE_FILE 0x002 113 #define MU_FOLDER_ATTRIBUTE_FILE 0x002
114
114 #define MU_FOLDER_ATTRIBUTE_ALL \ 115 #define MU_FOLDER_ATTRIBUTE_ALL \
115 (MU_FOLDER_ATTRIBUTE_DIRECTORY|MU_FOLDER_ATTRIBUTE_FILE) 116 (MU_FOLDER_ATTRIBUTE_DIRECTORY|MU_FOLDER_ATTRIBUTE_FILE)
116 117
......
...@@ -111,9 +111,10 @@ static int folder_imap_open (mu_folder_t, int); ...@@ -111,9 +111,10 @@ static int folder_imap_open (mu_folder_t, int);
111 static int folder_imap_close (mu_folder_t); 111 static int folder_imap_close (mu_folder_t);
112 static void folder_imap_destroy (mu_folder_t); 112 static void folder_imap_destroy (mu_folder_t);
113 static int folder_imap_delete (mu_folder_t, const char *); 113 static int folder_imap_delete (mu_folder_t, const char *);
114 static int folder_imap_list (mu_folder_t, const char *, const char *, 114 static int folder_imap_list (mu_folder_t, const char *, void *,
115 size_t, 115 size_t,
116 mu_list_t); 116 mu_list_t,
117 mu_folder_enumerate_fp efp, void *edp);
117 static int folder_imap_lsub (mu_folder_t, const char *, const char *, 118 static int folder_imap_lsub (mu_folder_t, const char *, const char *,
118 mu_list_t); 119 mu_list_t);
119 static int folder_imap_rename (mu_folder_t, const char *, 120 static int folder_imap_rename (mu_folder_t, const char *,
...@@ -975,9 +976,10 @@ glob_to_imap (const char *pat, int recursive) ...@@ -975,9 +976,10 @@ glob_to_imap (const char *pat, int recursive)
975 } 976 }
976 977
977 static int 978 static int
978 folder_imap_list (mu_folder_t folder, const char *ref, const char *name, 979 folder_imap_list (mu_folder_t folder, const char *ref, void *name,
979 size_t max_level, 980 size_t max_level,
980 mu_list_t flist) 981 mu_list_t flist,
982 mu_folder_enumerate_fp efp, void *edp)
981 { 983 {
982 f_imap_t f_imap = folder->data; 984 f_imap_t f_imap = folder->data;
983 int status = 0; 985 int status = 0;
...@@ -992,6 +994,11 @@ folder_imap_list (mu_folder_t folder, const char *ref, const char *name, ...@@ -992,6 +994,11 @@ folder_imap_list (mu_folder_t folder, const char *ref, const char *name,
992 if (name == NULL) 994 if (name == NULL)
993 name = ""; 995 name = "";
994 996
997 f_imap->folder = folder;
998 f_imap->enum_fun = efp;
999 f_imap->enum_stop = 0;
1000 f_imap->enum_data = edp;
1001
995 switch (f_imap->state) 1002 switch (f_imap->state)
996 { 1003 {
997 case IMAP_NO_STATE: 1004 case IMAP_NO_STATE:
...@@ -1017,6 +1024,11 @@ folder_imap_list (mu_folder_t folder, const char *ref, const char *name, ...@@ -1017,6 +1024,11 @@ folder_imap_list (mu_folder_t folder, const char *ref, const char *name,
1017 break; 1024 break;
1018 } 1025 }
1019 1026
1027 f_imap->folder = NULL;
1028 f_imap->enum_fun = NULL;
1029 f_imap->enum_stop = 0;
1030 f_imap->enum_data = NULL;
1031
1020 list_copy (flist, f_imap->flist, strlen (ref), 1032 list_copy (flist, f_imap->flist, strlen (ref),
1021 imap_mailbox_name_match, name, max_level); 1033 imap_mailbox_name_match, name, max_level);
1022 1034
...@@ -1041,6 +1053,10 @@ folder_imap_lsub (mu_folder_t folder, const char *ref, const char *name, ...@@ -1041,6 +1053,10 @@ folder_imap_lsub (mu_folder_t folder, const char *ref, const char *name,
1041 if (name == NULL) 1053 if (name == NULL)
1042 name = ""; 1054 name = "";
1043 1055
1056 f_imap->enum_fun = NULL;
1057 f_imap->enum_stop = 0;
1058 f_imap->enum_data = NULL;
1059
1044 switch (f_imap->state) 1060 switch (f_imap->state)
1045 { 1061 {
1046 case IMAP_NO_STATE: 1062 case IMAP_NO_STATE:
...@@ -1384,7 +1400,10 @@ imap_list (f_imap_t f_imap) ...@@ -1384,7 +1400,10 @@ imap_list (f_imap_t f_imap)
1384 int status = 0; 1400 int status = 0;
1385 int argc; 1401 int argc;
1386 char **argv; 1402 char **argv;
1387 1403
1404 if (f_imap->enum_stop)
1405 return 0;
1406
1388 buffer = malloc (len); 1407 buffer = malloc (len);
1389 if (!buffer) 1408 if (!buffer)
1390 return ENOMEM; 1409 return ENOMEM;
...@@ -1400,7 +1419,6 @@ imap_list (f_imap_t f_imap) ...@@ -1400,7 +1419,6 @@ imap_list (f_imap_t f_imap)
1400 mu_list_create (&f_imap->flist); 1419 mu_list_create (&f_imap->flist);
1401 mu_list_set_destroy_item (f_imap->flist, mu_list_response_free); 1420 mu_list_set_destroy_item (f_imap->flist, mu_list_response_free);
1402 } 1421 }
1403 mu_list_append (f_imap->flist, lr);
1404 1422
1405 /* Glob untag. */ 1423 /* Glob untag. */
1406 tok = strtok_r (buffer, " ", &sp); 1424 tok = strtok_r (buffer, " ", &sp);
...@@ -1475,6 +1493,12 @@ imap_list (f_imap_t f_imap) ...@@ -1475,6 +1493,12 @@ imap_list (f_imap_t f_imap)
1475 } 1493 }
1476 mu_argcv_free (argc, argv); 1494 mu_argcv_free (argc, argv);
1477 free (buffer); 1495 free (buffer);
1496
1497 if (f_imap->enum_fun)
1498 f_imap->enum_stop = f_imap->enum_fun (f_imap->folder, lr,
1499 f_imap->enum_data);
1500 mu_list_append (f_imap->flist, lr);
1501
1478 return status; 1502 return status;
1479 } 1503 }
1480 1504
......
...@@ -33,6 +33,9 @@ ...@@ -33,6 +33,9 @@
33 extern "C" { 33 extern "C" {
34 #endif 34 #endif
35 35
36 #define MU_FOLDER_LIST 0
37 #define MU_FOLDER_ENUM 1
38
36 struct _mu_folder 39 struct _mu_folder
37 { 40 {
38 /* Data */ 41 /* Data */
...@@ -55,11 +58,11 @@ struct _mu_folder ...@@ -55,11 +58,11 @@ struct _mu_folder
55 58
56 int (*_open) (mu_folder_t, int flag); 59 int (*_open) (mu_folder_t, int flag);
57 int (*_close) (mu_folder_t); 60 int (*_close) (mu_folder_t);
58 int (*_list) (mu_folder_t, const char *, const char *, 61 int (*_list) (mu_folder_t, const char *, void *, int, size_t,
59 size_t, 62 mu_list_t, mu_folder_enumerate_fp, void *);
60 mu_list_t);
61 int (*_lsub) (mu_folder_t, const char *, const char *, 63 int (*_lsub) (mu_folder_t, const char *, const char *,
62 mu_list_t); 64 mu_list_t);
65 mu_folder_match_fp _match;
63 int (*_delete) (mu_folder_t, const char *); 66 int (*_delete) (mu_folder_t, const char *);
64 int (*_rename) (mu_folder_t, const char *, const char *); 67 int (*_rename) (mu_folder_t, const char *, const char *);
65 int (*_subscribe) (mu_folder_t, const char *); 68 int (*_subscribe) (mu_folder_t, const char *);
......
...@@ -161,7 +161,10 @@ struct _f_imap ...@@ -161,7 +161,10 @@ struct _f_imap
161 161
162 /* Use for LIST and LSUB. */ 162 /* Use for LIST and LSUB. */
163 mu_list_t flist; 163 mu_list_t flist;
164 164 mu_folder_enumerate_fp enum_fun;
165 void *enum_data;
166 int enum_stop;
167
165 int isopen; 168 int isopen;
166 169
167 /* Server channel buffer I/O */ 170 /* Server channel buffer I/O */
...@@ -170,8 +173,8 @@ struct _f_imap ...@@ -170,8 +173,8 @@ struct _f_imap
170 char *ptr; 173 char *ptr;
171 char *nl; 174 char *nl;
172 mu_off_t offset; /* Dummy, this is used because of the stream buffering. 175 mu_off_t offset; /* Dummy, this is used because of the stream buffering.
173 The mu_stream_t maintains and offset and the offset we use must 176 The mu_stream_t maintains and offset and the offset we
174 be in sync. */ 177 use must be in sync. */
175 178
176 /* Login */ 179 /* Login */
177 char *user; 180 char *user;
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
41 #include <mailutils/stream.h> 41 #include <mailutils/stream.h>
42 #include <mailutils/mutil.h> 42 #include <mailutils/mutil.h>
43 #include <mailutils/errno.h> 43 #include <mailutils/errno.h>
44 #include <mailutils/debug.h>
44 45
45 /* We export url parsing and the initialisation of 46 /* We export url parsing and the initialisation of
46 the mailbox, via the register entry/record. */ 47 the mailbox, via the register entry/record. */
...@@ -77,11 +78,32 @@ _path_is_scheme (mu_record_t record, const char *url, int flags) ...@@ -77,11 +78,32 @@ _path_is_scheme (mu_record_t record, const char *url, int flags)
77 struct stat st; 78 struct stat st;
78 79
79 if (stat (path, &st) < 0) 80 if (stat (path, &st) < 0)
80 return MU_FOLDER_ATTRIBUTE_ALL; /* mu_mailbox_open will complain */ 81 {
82 if (errno == ENOENT)
83 rc |= MU_FOLDER_ATTRIBUTE_FILE;
84 return rc;
85 }
81 86
82 if ((flags & MU_FOLDER_ATTRIBUTE_FILE) 87 if (S_ISREG (st.st_mode) || S_ISCHR (st.st_mode))
83 && (S_ISREG (st.st_mode) || S_ISCHR (st.st_mode))) 88 {
84 rc |= MU_FOLDER_ATTRIBUTE_FILE; 89 if (st.st_size == 0)
90 {
91 rc |= MU_FOLDER_ATTRIBUTE_FILE;
92 }
93 else if (flags & MU_FOLDER_ATTRIBUTE_FILE)
94 {
95 int fd = open (path, O_RDONLY);
96 if (fd != -1)
97 {
98 char buf[5];
99 if (read (fd, buf, 5) == 5)
100 if (memcmp (buf, "From ", 5) == 0)
101 rc |= MU_FOLDER_ATTRIBUTE_FILE;
102 close (fd);
103 }
104 }
105 }
106
85 if ((flags & MU_FOLDER_ATTRIBUTE_DIRECTORY) 107 if ((flags & MU_FOLDER_ATTRIBUTE_DIRECTORY)
86 && S_ISDIR (st.st_mode)) 108 && S_ISDIR (st.st_mode))
87 rc |= MU_FOLDER_ATTRIBUTE_DIRECTORY; 109 rc |= MU_FOLDER_ATTRIBUTE_DIRECTORY;
...@@ -113,8 +135,9 @@ static int folder_mbox_open (mu_folder_t, int); ...@@ -113,8 +135,9 @@ static int folder_mbox_open (mu_folder_t, int);
113 static int folder_mbox_close (mu_folder_t); 135 static int folder_mbox_close (mu_folder_t);
114 static int folder_mbox_delete (mu_folder_t, const char *); 136 static int folder_mbox_delete (mu_folder_t, const char *);
115 static int folder_mbox_rename (mu_folder_t , const char *, const char *); 137 static int folder_mbox_rename (mu_folder_t , const char *, const char *);
116 static int folder_mbox_list (mu_folder_t, const char *, const char *, 138 static int folder_mbox_list (mu_folder_t, const char *, void *, int,
117 size_t, mu_list_t); 139 size_t, mu_list_t, mu_folder_enumerate_fp,
140 void *);
118 static int folder_mbox_subscribe (mu_folder_t, const char *); 141 static int folder_mbox_subscribe (mu_folder_t, const char *);
119 static int folder_mbox_unsubscribe (mu_folder_t, const char *); 142 static int folder_mbox_unsubscribe (mu_folder_t, const char *);
120 static int folder_mbox_lsub (mu_folder_t, const char *, const char *, 143 static int folder_mbox_lsub (mu_folder_t, const char *, const char *,
...@@ -228,7 +251,8 @@ folder_mbox_delete (mu_folder_t folder, const char *filename) ...@@ -228,7 +251,8 @@ folder_mbox_delete (mu_folder_t folder, const char *filename)
228 } 251 }
229 252
230 static int 253 static int
231 folder_mbox_rename (mu_folder_t folder, const char *oldpath, const char *newpath) 254 folder_mbox_rename (mu_folder_t folder, const char *oldpath,
255 const char *newpath)
232 { 256 {
233 fmbox_t fmbox = folder->data; 257 fmbox_t fmbox = folder->data;
234 if (oldpath && newpath) 258 if (oldpath && newpath)
...@@ -266,8 +290,15 @@ struct inode_list /* Inode/dev number list used to cut off ...@@ -266,8 +290,15 @@ struct inode_list /* Inode/dev number list used to cut off
266 struct search_data 290 struct search_data
267 { 291 {
268 mu_list_t result; 292 mu_list_t result;
269 const char *pattern; 293 mu_folder_enumerate_fp enumfun;
294 void *enumdata;
295 char *dirname;
296 size_t dirlen;
297 void *pattern;
298 int flags;
270 size_t max_level; 299 size_t max_level;
300 size_t errcnt;
301 mu_folder_t folder;
271 }; 302 };
272 303
273 static int 304 static int
...@@ -279,126 +310,146 @@ inode_list_lookup (struct inode_list *list, struct stat *st) ...@@ -279,126 +310,146 @@ inode_list_lookup (struct inode_list *list, struct stat *st)
279 return 0; 310 return 0;
280 } 311 }
281 312
282
283 static int 313 static int
284 list_helper (struct search_data *data, 314 list_helper (struct search_data *data, const char *dirname, size_t level,
285 const char *dirname, size_t level, struct inode_list *ilist) 315 struct inode_list *ilist)
286 { 316 {
287 int status; 317 DIR *dirp;
288 glob_t gl; 318 struct dirent *dp;
289 char *pathname; 319 int stop = 0;
290 320
291 ++level;
292 if (data->max_level && level > data->max_level) 321 if (data->max_level && level > data->max_level)
293 return 0; 322 return 0;
294
295 pathname = get_pathname (dirname, data->pattern);
296 if (!pathname)
297 return ENOMEM;
298 323
299 memset(&gl, 0, sizeof(gl)); 324 dirp = opendir (dirname);
300 status = glob (pathname, 0, NULL, &gl); 325 if (dirp == NULL)
301 free (pathname);
302
303 if (status == 0)
304 { 326 {
305 size_t i; 327 MU_DEBUG2 (data->folder->debug, MU_DEBUG_ERROR,
306 struct mu_list_response *resp; 328 "list_helper cannot open directory %s: %s",
329 dirname, mu_strerror (errno));
330 data->errcnt++;
331 return 1;
332 }
333
334 while ((dp = readdir (dirp)))
335 {
336 char const *ename = dp->d_name;
337 char *fname;
307 338
308 for (i = 0; i < gl.gl_pathc; i++) 339 if (ename[ename[0] != '.' ? 0 : ename[1] != '.' ? 1 : 2] == 0)
340 continue;
341 fname = get_pathname (dirname, ename);
342 if (data->folder->_match == NULL
343 || data->folder->_match (fname + data->dirlen +
344 ((data->dirlen > 1
345 && data->dirname[data->dirlen-1] != '/') ?
346 1 : 0),
347 data->pattern,
348 data->flags) == 0)
309 { 349 {
310 struct stat st; 350 struct stat st;
311 351
312 resp = malloc (sizeof (*resp)); 352 if (stat (fname, &st) == 0)
313 if (resp == NULL)
314 {
315 status = ENOMEM;
316 break;
317 }
318 else if ((resp->name = strdup (gl.gl_pathv[i])) == NULL)
319 { 353 {
320 free (resp); 354 char *refname = fname;
321 status = ENOMEM; 355 int type = 0;
322 break; 356 struct mu_list_response *resp;
323 } 357
358 resp = malloc (sizeof (*resp));
359 if (resp == NULL)
360 {
361 MU_DEBUG1 (data->folder->debug, MU_DEBUG_ERROR,
362 "list_helper: %s", mu_strerror (ENOMEM));
363 data->errcnt++;
364 free (fname);
365 continue;
366 }
324 367
325 resp->level = level; 368 mu_registrar_lookup (refname, MU_FOLDER_ATTRIBUTE_ALL, NULL,
326 resp->separator = '/'; 369 &type);
327 resp->type = 0;
328
329 mu_list_append (data->result, resp);
330 370
331 if (stat (gl.gl_pathv[i], &st) == 0) 371 resp->name = fname;
332 { 372 resp->level = level;
333 resp->type = 0; 373 resp->separator = '/';
334 mu_registrar_lookup (gl.gl_pathv[i], MU_FOLDER_ATTRIBUTE_ALL, 374 resp->type = type;
335 NULL, &resp->type); 375
336 if ((resp->type & MU_FOLDER_ATTRIBUTE_DIRECTORY) 376 if (resp->type == 0)
377 {
378 free (resp->name);
379 free (resp);
380 continue;
381 }
382
383 if (data->enumfun)
384 {
385 if (data->enumfun (data->folder, resp, data->enumdata))
386 {
387 free (resp->name);
388 free (resp);
389 stop = 1;
390 break;
391 }
392 }
393
394 if (data->result)
395 {
396 fname = NULL;
397 mu_list_append (data->result, resp);
398 }
399 else
400 free (resp);
401
402 if ((type & MU_FOLDER_ATTRIBUTE_DIRECTORY)
337 && !inode_list_lookup (ilist, &st)) 403 && !inode_list_lookup (ilist, &st))
338 { 404 {
339 struct inode_list idata; 405 struct inode_list idata;
406
340 idata.inode = st.st_ino; 407 idata.inode = st.st_ino;
341 idata.dev = st.st_dev; 408 idata.dev = st.st_dev;
342 idata.next = ilist; 409 idata.next = ilist;
343 status = list_helper (data, gl.gl_pathv[i], level, &idata); 410 stop = list_helper (data, refname, level + 1, &idata);
344 if (status)
345 break;
346 } 411 }
347 } 412 }
348 }
349 globfree (&gl);
350 }
351 else
352 {
353 switch (status)
354 {
355 case GLOB_NOSPACE:
356 status = ENOMEM;
357 break;
358
359 case GLOB_ABORTED:
360 status = MU_ERR_READ;
361 break;
362
363 case GLOB_NOMATCH:
364 if (mu_list_is_empty (data->result))
365 status = MU_ERR_NOENT;
366 else 413 else
367 status = 0; 414 {
368 break; 415 MU_DEBUG2 (data->folder->debug, MU_DEBUG_ERROR,
369 416 "list_helper cannot stat %s: %s",
370 case GLOB_NOSYS: 417 fname, mu_strerror (errno));
371 status = ENOSYS; 418 }
372 break;
373
374 default:
375 status = MU_ERR_FAILURE;
376 break;
377 } 419 }
420 free (fname);
378 } 421 }
379 return status; 422 closedir (dirp);
423 return stop;
380 } 424 }
381 425
382 /* The listing is not recursive and we use glob() some expansion for us.
383 Unfortunately glob() does not expand the '~'. We also return
384 the full pathname so it can be use to create other folders. */
385 static int 426 static int
386 folder_mbox_list (mu_folder_t folder, const char *dirname, const char *pattern, 427 folder_mbox_list (mu_folder_t folder, const char *ref,
428 void *pattern,
429 int flags,
387 size_t max_level, 430 size_t max_level,
388 mu_list_t flist) 431 mu_list_t flist,
432 mu_folder_enumerate_fp enumfun, void *enumdata)
389 { 433 {
390 fmbox_t fmbox = folder->data; 434 fmbox_t fmbox = folder->data;
391 struct inode_list iroot; 435 struct inode_list iroot;
392 struct search_data sdata; 436 struct search_data sdata;
393 437
394 memset (&iroot, 0, sizeof iroot); 438 memset (&iroot, 0, sizeof iroot);
395 if (dirname == NULL || dirname[0] == '\0') 439 sdata.dirname = get_pathname (fmbox->dirname, ref);
396 dirname = (const char *)fmbox->dirname; 440 sdata.dirlen = strlen (sdata.dirname);
397
398 sdata.result = flist; 441 sdata.result = flist;
442 sdata.enumfun = enumfun;
443 sdata.enumdata = enumdata;
399 sdata.pattern = pattern; 444 sdata.pattern = pattern;
445 sdata.flags = flags;
400 sdata.max_level = max_level; 446 sdata.max_level = max_level;
401 return list_helper (&sdata, dirname, 0, &iroot); 447 sdata.folder = folder;
448 sdata.errcnt = 0;
449 list_helper (&sdata, sdata.dirname, 0, &iroot);
450 free (sdata.dirname);
451 /* FIXME: error code */
452 return 0;
402 } 453 }
403 454
404 static int 455 static int
......
...@@ -63,9 +63,10 @@ static int nntp_folder_open (mu_folder_t, int); ...@@ -63,9 +63,10 @@ static int nntp_folder_open (mu_folder_t, int);
63 static int nntp_folder_close (mu_folder_t); 63 static int nntp_folder_close (mu_folder_t);
64 static void nntp_folder_destroy (mu_folder_t folder); 64 static void nntp_folder_destroy (mu_folder_t folder);
65 static int nntp_folder_list (mu_folder_t folder, const char *ref, 65 static int nntp_folder_list (mu_folder_t folder, const char *ref,
66 const char *name, 66 void *name,
67 size_t max, 67 size_t max,
68 mu_list_t flist); 68 mu_list_t flist,
69 mu_folder_enumerate_fp efp, void *edp);
69 70
70 int 71 int
71 _nntp_folder_init (mu_folder_t folder) 72 _nntp_folder_init (mu_folder_t folder)
...@@ -185,8 +186,9 @@ nntp_folder_destroy (mu_folder_t folder) ...@@ -185,8 +186,9 @@ nntp_folder_destroy (mu_folder_t folder)
185 186
186 187
187 static int 188 static int
188 nntp_folder_list (mu_folder_t folder, const char *ref, const char *name, 189 nntp_folder_list (mu_folder_t folder, const char *ref, void *pat,
189 size_t max_level, mu_list_t flist) 190 size_t max_level, mu_list_t flist,
191 mu_folder_enumerate_fp efp, void *edp)
190 { 192 {
191 return ENOTSUP; 193 return ENOTSUP;
192 } 194 }
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
24 #include <errno.h> 24 #include <errno.h>
25 #include <stdlib.h> 25 #include <stdlib.h>
26 #include <string.h> 26 #include <string.h>
27 #include <fnmatch.h>
27 28
28 #include <mailutils/auth.h> 29 #include <mailutils/auth.h>
29 #include <mailutils/debug.h> 30 #include <mailutils/debug.h>
...@@ -45,13 +46,19 @@ static int is_known_folder (mu_url_t, mu_folder_t *); ...@@ -45,13 +46,19 @@ static int is_known_folder (mu_url_t, mu_folder_t *);
45 /* Static folder lock. */ 46 /* Static folder lock. */
46 static struct mu_monitor folder_lock = MU_MONITOR_INITIALIZER; 47 static struct mu_monitor folder_lock = MU_MONITOR_INITIALIZER;
47 48
49 int
50 mu_folder_match (const char *name, void *pattern, int flags)
51 {
52 return fnmatch (pattern, name[0] == '/' ? name + 1 : name, flags);
53 }
54
48 /* A folder could be remote (IMAP), or local(a spool directory) like $HOME/Mail 55 /* A folder could be remote (IMAP), or local(a spool directory) like $HOME/Mail
49 etc .. We maintain a known list of folder to not generate multiple folder 56 etc .. We maintain a list of known folders to avoid creating multiple
50 of the same URL. Meaning when mu_folder_create () is call we'll check if we 57 folders for the same URL. So, when mu_folder_create is called we check if
51 already have a folder for that URL and return the same, if not we create a 58 we already have a folder for that URL and return it, otherwise we create a
52 new one. The downside, the scheme to detect the same URL is very weak, and 59 new one. Downsides: the scheme to detect the same URL is very weak, and
53 they maybe cases where you want a different folder for the same URL, there 60 there could be cases where you'll want a different folder for the same URL,
54 is not easy way to do this. */ 61 there is not easy way to do this. */
55 int 62 int
56 mu_folder_create_from_record (mu_folder_t *pfolder, const char *name, 63 mu_folder_create_from_record (mu_folder_t *pfolder, const char *name,
57 mu_record_t record) 64 mu_record_t record)
...@@ -112,6 +119,8 @@ mu_folder_create_from_record (mu_folder_t *pfolder, const char *name, ...@@ -112,6 +119,8 @@ mu_folder_create_from_record (mu_folder_t *pfolder, const char *name,
112 status = f_init (folder); 119 status = f_init (folder);
113 if (status == 0) 120 if (status == 0)
114 { 121 {
122 if (!folder->_match)
123 folder->_match = mu_folder_match;
115 *pfolder = folder; 124 *pfolder = folder;
116 folder->ref++; 125 folder->ref++;
117 /* Put on the internal list of known folders. */ 126 /* Put on the internal list of known folders. */
...@@ -280,6 +289,26 @@ mu_folder_get_observable (mu_folder_t folder, mu_observable_t *pobservable) ...@@ -280,6 +289,26 @@ mu_folder_get_observable (mu_folder_t folder, mu_observable_t *pobservable)
280 } 289 }
281 290
282 int 291 int
292 mu_folder_set_match (mu_folder_t folder, mu_folder_match_fp pmatch)
293 {
294 if (folder == NULL)
295 return EINVAL;
296 folder->_match = pmatch;
297 return 0;
298 }
299
300 int
301 mu_folder_get_match (mu_folder_t folder, mu_folder_match_fp *pmatch)
302 {
303 if (folder == NULL)
304 return EINVAL;
305 if (pmatch == NULL)
306 return MU_ERR_OUT_PTR_NULL;
307 *pmatch = folder->_match;
308 return 0;
309 }
310
311 int
283 mu_folder_has_debug (mu_folder_t folder) 312 mu_folder_has_debug (mu_folder_t folder)
284 { 313 {
285 if (folder == NULL) 314 if (folder == NULL)
...@@ -325,20 +354,41 @@ mu_list_response_free (void *data) ...@@ -325,20 +354,41 @@ mu_list_response_free (void *data)
325 } 354 }
326 355
327 int 356 int
328 mu_folder_list (mu_folder_t folder, const char *dirname, const char *basename, 357 mu_folder_list (mu_folder_t folder, const char *dirname, void *pattern,
329 size_t max_level, 358 size_t max_level,
330 mu_list_t *pflist) 359 mu_list_t *pflist)
331 { 360 {
361 return mu_folder_enumerate (folder, dirname, pattern, 0, max_level,
362 pflist, NULL, NULL);
363 }
364
365 int
366 mu_folder_enumerate (mu_folder_t folder, const char *name,
367 void *pattern, int flags,
368 size_t max_level,
369 mu_list_t *pflist,
370 mu_folder_enumerate_fp enumfun, void *enumdata)
371 {
332 int status; 372 int status;
333 if (folder == NULL || folder->_list == NULL) 373 if (folder == NULL || folder->_list == NULL)
334 return EINVAL; 374 return EINVAL;
335 else 375 else
336 { 376 {
337 status = mu_list_create (pflist); 377 mu_list_t list = NULL;
338 if (status) 378
339 return status; 379 if (pflist)
340 mu_list_set_destroy_item (*pflist, mu_list_response_free); 380 {
341 status = folder->_list (folder, dirname, basename, max_level, *pflist); 381 status = mu_list_create (&list);
382 if (status)
383 return status;
384 *pflist = list;
385 mu_list_set_destroy_item (list, mu_list_response_free);
386 }
387 else if (!enumfun)
388 return EINVAL;
389
390 status = folder->_list (folder, name, pattern, flags, max_level,
391 list, enumfun, enumdata);
342 if (status) 392 if (status)
343 mu_list_destroy (pflist); 393 mu_list_destroy (pflist);
344 } 394 }
......