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"
......
...@@ -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 }
......