Commit fd032c6f fd032c6f6cf30af76f67baff997367cafdacb428 by Sergey Poznyakoff

Mailbox quota support in imap4d: initial implementation.

* imap4d/quota.c: New file.
* imap4d/Makefile.am (imap4d_SOURCES): Add quota.c
* imap4d/append.c (imap4d_append0): Refuse to append if
the quota is exceeded or would be exceeded after completing
the operation.
* imap4d/copy.c (imap4d_copy0): Refuse to copy messages if
the quota is exceeded or would be exceeded after completing
the operation.
Return a meaningful textual description.
Attempt to restore mailbox to its original size if the operation failed.
* imap4d/imap4d.c (imap4d_session_setup0): Call quota_setup.
* imap4d/imap4d.h (quota_setup, quota_check, quota_update): New functions.

* include/mailutils/folder.h (mu_list_response) <format>: New member.
* include/mailutils/mailbox.h (mu_mailbox_create_from_record): New
function.
* include/mailutils/types.hin (MU_FOLDER_ATTRIBUTE_LINK): New flag.
* libproto/mbox/folder.c (list_helper): Do not return symbolic links
unless MU_FOLDER_ATTRIBUTE_LINK is set.
Fill in the resp->format member.
* mailbox/mailbox.c (_mailbox_create_from_record): New static function.
(_create_mailbox0): Rewrite as a wrapper over _mailbox_create_from_record.
(mu_mailbox_create_from_record): New function.
1 parent 7ebda349
...@@ -50,6 +50,7 @@ imap4d_SOURCES = \ ...@@ -50,6 +50,7 @@ imap4d_SOURCES = \
50 noop.c\ 50 noop.c\
51 parsebuf.c\ 51 parsebuf.c\
52 preauth.c\ 52 preauth.c\
53 quota.c\
53 rename.c\ 54 rename.c\
54 search.c\ 55 search.c\
55 select.c\ 56 select.c\
......
...@@ -71,10 +71,11 @@ imap4d_append0 (mu_mailbox_t mbox, int flags, char *date_time, char *text, ...@@ -71,10 +71,11 @@ imap4d_append0 (mu_mailbox_t mbox, int flags, char *date_time, char *text,
71 struct tm *tm; 71 struct tm *tm;
72 time_t t; 72 time_t t;
73 mu_envelope_t env; 73 mu_envelope_t env;
74 74 size_t size;
75
75 if (mu_message_create (&msg, &tm)) 76 if (mu_message_create (&msg, &tm))
76 return 1; 77 return 1;
77 78
78 if (mu_memory_stream_create (&stream, MU_STREAM_RDWR) 79 if (mu_memory_stream_create (&stream, MU_STREAM_RDWR)
79 || mu_stream_open (stream)) 80 || mu_stream_open (stream))
80 { 81 {
...@@ -94,9 +95,9 @@ imap4d_append0 (mu_mailbox_t mbox, int flags, char *date_time, char *text, ...@@ -94,9 +95,9 @@ imap4d_append0 (mu_mailbox_t mbox, int flags, char *date_time, char *text,
94 } 95 }
95 } 96 }
96 else 97 else
97 time(&t); 98 time (&t);
98 99
99 tm = gmtime(&t); 100 tm = gmtime (&t);
100 101
101 while (*text && mu_isblank (*text)) 102 while (*text && mu_isblank (*text))
102 text++; 103 text++;
...@@ -109,15 +110,40 @@ imap4d_append0 (mu_mailbox_t mbox, int flags, char *date_time, char *text, ...@@ -109,15 +110,40 @@ imap4d_append0 (mu_mailbox_t mbox, int flags, char *date_time, char *text,
109 mu_envelope_set_date (env, _append_date, msg); 110 mu_envelope_set_date (env, _append_date, msg);
110 mu_envelope_set_sender (env, _append_sender, msg); 111 mu_envelope_set_sender (env, _append_sender, msg);
111 mu_message_set_envelope (msg, env, &tm); 112 mu_message_set_envelope (msg, env, &tm);
113
114 rc = _append_size (msg, &size);
115 if (rc)
116 {
117 mu_diag_output (MU_DIAG_NOTICE,
118 _("cannot compute size of the message being appended; "
119 "using estimated value: %s"),
120 mu_strerror (rc));
121 /* raw estimate */
122 size = strlen (text);
123 }
124 rc = quota_check (size);
125 if (rc != RESP_OK)
126 {
127 *err_text = rc == RESP_NO ?
128 "Mailbox quota exceeded" : "Operation failed";
129 mu_message_destroy (&msg, &tm);
130 return 1;
131 }
132
112 rc = mu_mailbox_append_message (mbox, msg); 133 rc = mu_mailbox_append_message (mbox, msg);
113 if (rc == 0 && flags) 134 if (rc == 0)
114 { 135 {
115 size_t num = 0; 136 if (flags)
116 mu_attribute_t attr = NULL; 137 {
117 mu_mailbox_messages_count (mbox, &num); 138 size_t num = 0;
118 mu_mailbox_get_message (mbox, num, &msg); 139 mu_attribute_t attr = NULL;
119 mu_message_get_attribute (msg, &attr); 140 mu_mailbox_messages_count (mbox, &num);
120 mu_attribute_set_flags (attr, flags); 141 mu_mailbox_get_message (mbox, num, &msg);
142 mu_message_get_attribute (msg, &attr);
143 mu_attribute_set_flags (attr, flags);
144 }
145 /* FIXME: If not INBOX */
146 quota_update (size);
121 } 147 }
122 148
123 mu_message_destroy (&msg, &tm); 149 mu_message_destroy (&msg, &tm);
......
...@@ -57,6 +57,153 @@ imap4d_copy (struct imap4d_command *command, imap4d_tokbuf_t tok) ...@@ -57,6 +57,153 @@ imap4d_copy (struct imap4d_command *command, imap4d_tokbuf_t tok)
57 return io_completion_response (command, rc, "%s", text); 57 return io_completion_response (command, rc, "%s", text);
58 } 58 }
59 59
60 static int
61 copy_check_size (mu_mailbox_t mbox, size_t n, size_t *set, mu_off_t *size)
62 {
63 int status;
64 size_t i;
65 mu_off_t total = 0;
66
67 for (i = 0; i < n; i++)
68 {
69 mu_message_t msg = NULL;
70 size_t msgno = set[i];
71 if (msgno)
72 {
73 status = mu_mailbox_get_message (mbox, msgno, &msg);
74 if (status)
75 {
76 mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_get_message", NULL,
77 status);
78 return RESP_BAD;
79 }
80 else
81 {
82 size_t size;
83 status = mu_message_size (msg, &size);
84 if (status)
85 {
86 mu_diag_funcall (MU_DIAG_ERROR, "mu_message_size", NULL,
87 status);
88 return RESP_BAD;
89 }
90 total += size;
91 }
92 }
93 }
94 *size = total;
95 return quota_check (total);
96 }
97
98 static int
99 try_copy (mu_mailbox_t dst, mu_mailbox_t src, size_t n, size_t *set)
100 {
101 int result;
102 size_t i;
103 mu_off_t total;
104
105 result = copy_check_size (src, n, set, &total);
106 if (result)
107 return result;
108
109 for (i = 0; i < n; i++)
110 {
111 mu_message_t msg = NULL;
112 size_t msgno = set[i];
113
114 if (msgno)
115 {
116 int status = mu_mailbox_get_message (src, msgno, &msg);
117 if (status)
118 {
119 mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_get_message", NULL,
120 status);
121 return RESP_BAD;
122 }
123
124 status = mu_mailbox_append_message (dst, msg);
125 if (status)
126 {
127 mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_append_message",
128 NULL,
129 status);
130 return RESP_BAD;
131 }
132 }
133 }
134 quota_update (total);
135 return RESP_OK;
136 }
137
138 static int
139 safe_copy (mu_mailbox_t dst, mu_mailbox_t src, size_t n, size_t *set,
140 char **err_text)
141 {
142 size_t nmesg;
143 int status;
144
145 status = mu_mailbox_messages_count (dst, &nmesg);
146 if (status)
147 {
148 mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_messages_count",
149 NULL, status);
150 *err_text = "Operation failed";
151 return RESP_NO;
152 }
153
154 status = try_copy (dst, src, n, set);
155 if (status)
156 {
157 size_t maxmesg;
158
159 if (status == RESP_NO)
160 *err_text = "Mailbox quota exceeded";
161 else
162 *err_text = "Operation failed";
163
164 /* If the COPY command is unsuccessful for any reason, server
165 implementations MUST restore the destination mailbox to its state
166 before the COPY attempt. */
167
168 status = mu_mailbox_messages_count (dst, &maxmesg);
169 if (status)
170 {
171 mu_url_t url = NULL;
172
173 mu_mailbox_get_url (dst, &url);
174 mu_error (_("cannot count messages in mailbox %s: %s"),
175 mu_url_to_string (url), mu_strerror (status));
176 imap4d_bye (ERR_MAILBOX_CORRUPTED);
177 }
178
179 for (nmesg++; nmesg <= maxmesg; nmesg++)
180 {
181 mu_message_t msg;
182
183 if (mu_mailbox_get_message (dst, nmesg, &msg) == 0)
184 {
185 mu_attribute_t attr;
186 mu_message_get_attribute (msg, &attr);
187 mu_attribute_set_userflag (attr, MU_ATTRIBUTE_DELETED);
188 }
189 }
190
191 status = mu_mailbox_flush (dst, 1);
192 if (status)
193 {
194 mu_url_t url = NULL;
195
196 mu_mailbox_get_url (dst, &url);
197 mu_error (_("cannot flush mailbox %s: %s"),
198 mu_url_to_string (url), mu_strerror (status));
199 imap4d_bye (ERR_MAILBOX_CORRUPTED);
200 }
201 return RESP_NO;
202 }
203
204 return RESP_OK;
205 }
206
60 int 207 int
61 imap4d_copy0 (imap4d_tokbuf_t tok, int isuid, char **err_text) 208 imap4d_copy0 (imap4d_tokbuf_t tok, int isuid, char **err_text)
62 { 209 {
...@@ -70,7 +217,8 @@ imap4d_copy0 (imap4d_tokbuf_t tok, int isuid, char **err_text) ...@@ -70,7 +217,8 @@ imap4d_copy0 (imap4d_tokbuf_t tok, int isuid, char **err_text)
70 mu_mailbox_t cmbox = NULL; 217 mu_mailbox_t cmbox = NULL;
71 int arg = IMAP4_ARG_1 + !!isuid; 218 int arg = IMAP4_ARG_1 + !!isuid;
72 int ns; 219 int ns;
73 220
221 *err_text = NULL;
74 if (imap4d_tokbuf_argc (tok) != arg + 2) 222 if (imap4d_tokbuf_argc (tok) != arg + 2)
75 { 223 {
76 *err_text = "Invalid arguments"; 224 *err_text = "Invalid arguments";
...@@ -89,11 +237,19 @@ imap4d_copy0 (imap4d_tokbuf_t tok, int isuid, char **err_text) ...@@ -89,11 +237,19 @@ imap4d_copy0 (imap4d_tokbuf_t tok, int isuid, char **err_text)
89 return RESP_OK; 237 return RESP_OK;
90 } 238 }
91 239
240 if (isuid)
241 {
242 int i;
243 /* Fixup the message set. Perhaps util_msgset should do it itself? */
244 for (i = 0; i < n; i++)
245 set[i] = uid_to_msgno (set[i]);
246 }
247
92 mailbox_name = namespace_getfullpath (name, delim, &ns); 248 mailbox_name = namespace_getfullpath (name, delim, &ns);
93 249
94 if (!mailbox_name) 250 if (!mailbox_name)
95 { 251 {
96 *err_text = "NO Copy failed."; 252 *err_text = "Copy failed";
97 return RESP_NO; 253 return RESP_NO;
98 } 254 }
99 255
...@@ -106,14 +262,7 @@ imap4d_copy0 (imap4d_tokbuf_t tok, int isuid, char **err_text) ...@@ -106,14 +262,7 @@ imap4d_copy0 (imap4d_tokbuf_t tok, int isuid, char **err_text)
106 status = mu_mailbox_open (cmbox, MU_STREAM_RDWR | mailbox_mode[ns]); 262 status = mu_mailbox_open (cmbox, MU_STREAM_RDWR | mailbox_mode[ns]);
107 if (status == 0) 263 if (status == 0)
108 { 264 {
109 size_t i; 265 status = safe_copy (cmbox, mbox, n, set, err_text);
110 for (i = 0; i < n; i++)
111 {
112 mu_message_t msg = NULL;
113 size_t msgno = (isuid) ? uid_to_msgno (set[i]) : set[i];
114 if (msgno && mu_mailbox_get_message (mbox, msgno, &msg) == 0)
115 mu_mailbox_append_message (cmbox, msg);
116 }
117 mu_mailbox_close (cmbox); 266 mu_mailbox_close (cmbox);
118 } 267 }
119 mu_mailbox_destroy (&cmbox); 268 mu_mailbox_destroy (&cmbox);
...@@ -132,6 +281,7 @@ imap4d_copy0 (imap4d_tokbuf_t tok, int isuid, char **err_text) ...@@ -132,6 +281,7 @@ imap4d_copy0 (imap4d_tokbuf_t tok, int isuid, char **err_text)
132 of the text of the tagged NO response. This gives a hint to the 281 of the text of the tagged NO response. This gives a hint to the
133 client that it can attempt a CREATE command and retry the copy if 282 client that it can attempt a CREATE command and retry the copy if
134 the CREATE is successful. */ 283 the CREATE is successful. */
135 *err_text = "[TRYCREATE] failed"; 284 if (!*err_text)
285 *err_text = "[TRYCREATE] failed";
136 return RESP_NO; 286 return RESP_NO;
137 } 287 }
......
...@@ -352,9 +352,14 @@ imap4d_session_setup0 () ...@@ -352,9 +352,14 @@ imap4d_session_setup0 ()
352 352
353 util_chdir (imap4d_homedir); 353 util_chdir (imap4d_homedir);
354 namespace_init_session (imap4d_homedir); 354 namespace_init_session (imap4d_homedir);
355
355 mu_diag_output (MU_DIAG_INFO, 356 mu_diag_output (MU_DIAG_INFO,
356 _("user `%s' logged in (source: %s)"), auth_data->name, 357 _("user `%s' logged in (source: %s)"), auth_data->name,
357 auth_data->source); 358 auth_data->source);
359
360 if (auth_data->quota)
361 quota_setup ();
362
358 return 0; 363 return 0;
359 } 364 }
360 365
......
...@@ -423,7 +423,12 @@ extern void auth_gsasl_init (void); ...@@ -423,7 +423,12 @@ extern void auth_gsasl_init (void);
423 #else 423 #else
424 # define auth_gsasl_init() 424 # define auth_gsasl_init()
425 #endif 425 #endif
426 426
427 /* Quota support */
428 void quota_setup (void);
429 int quota_check (mu_off_t size);
430 void quota_update (mu_off_t size);
431
427 #ifdef __cplusplus 432 #ifdef __cplusplus
428 } 433 }
429 #endif 434 #endif
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
3 2009, 2010 Free Software Foundation, Inc.
4
5 GNU Mailutils is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3, or (at your option)
8 any later version.
9
10 GNU Mailutils 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
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
17
18 #include "imap4d.h"
19
20 struct imap4d_sizeinfo
21 {
22 mu_off_t size;
23 mu_off_t nfiles;
24 mu_off_t ndirs;
25 mu_off_t nerrs;
26 };
27
28 static int
29 addsize (mu_folder_t folder, struct mu_list_response *resp, void *data)
30 {
31 struct imap4d_sizeinfo *si = data;
32
33 if (resp->type & MU_FOLDER_ATTRIBUTE_DIRECTORY)
34 si->ndirs++;
35
36 if (resp->type & MU_FOLDER_ATTRIBUTE_FILE)
37 {
38 mu_off_t size;
39 mu_mailbox_t mbox;
40 int rc;
41
42 si->nfiles++;
43
44 rc = mu_mailbox_create_from_record (&mbox, resp->format, resp->name);
45
46 if (rc)
47 {
48 mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_create_from_record",
49 resp->name, rc);
50 si->nerrs++;
51 return 0;
52 }
53
54 rc = mu_mailbox_open (mbox, MU_STREAM_READ);
55 if (rc)
56 {
57 mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_open",
58 resp->name, rc);
59 si->nerrs++;
60 mu_mailbox_destroy (&mbox);
61 return 0;
62 }
63
64 rc = mu_mailbox_get_size (mbox, &size);
65 mu_mailbox_destroy (&mbox);
66
67 if (rc)
68 {
69 mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_open",
70 resp->name, rc);
71 si->nerrs++;
72 return 0;
73 }
74 si->size += size;
75 }
76 return 0;
77 }
78
79 void
80 directory_size (const char *dirname, mu_off_t *size)
81 {
82 mu_folder_t folder;
83 struct imap4d_sizeinfo sizeinfo;
84 int status;
85
86 status = mu_folder_create (&folder, dirname);
87 if (status)
88 {
89 mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_create", dirname, status);
90 return;
91 }
92
93 status = mu_folder_open (folder, MU_STREAM_READ);
94 if (status)
95 {
96 mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_open", dirname, status);
97 mu_folder_destroy (&folder);
98 return;
99 }
100
101 memset (&sizeinfo, 0, sizeof (sizeinfo));
102 status = mu_folder_enumerate (folder, NULL, "*", 0, 0, NULL,
103 addsize, &sizeinfo);
104 if (status)
105 mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_enumerate", dirname, status);
106 else
107 {
108 mu_diag_output (MU_DIAG_INFO,
109 _("%s statistics: size=%lu, ndirs=%lu, nfiles=%lu, nerrs=%lu"),
110 dirname,
111 (unsigned long)sizeinfo.size,
112 (unsigned long)sizeinfo.ndirs,
113 (unsigned long)sizeinfo.nfiles,
114 (unsigned long)sizeinfo.nerrs);
115 }
116 *size = sizeinfo.size;
117 }
118
119
120 mu_off_t used_size;
121
122 void
123 quota_setup ()
124 {
125 directory_size (imap4d_homedir, &used_size);
126 }
127
128 int
129 quota_check (mu_off_t size)
130 {
131 char *mailbox_name;
132 mu_mailbox_t mbox;
133 mu_off_t total;
134 int rc;
135
136 if (auth_data->quota == 0)
137 return RESP_OK;
138
139 total = used_size;
140
141 mailbox_name = namespace_getfullpath ("INBOX", "/", NULL);
142 rc = mu_mailbox_create (&mbox, mailbox_name);
143 if (rc)
144 {
145 mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_create", mailbox_name, rc);
146 free (mailbox_name);
147 }
148 else
149 {
150 do
151 {
152 mu_off_t mbsize;
153
154 rc = mu_mailbox_open (mbox, MU_STREAM_READ);
155 if (rc)
156 {
157 if (rc != ENOENT)
158 mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_open",
159 mailbox_name, rc);
160 break;
161 }
162
163 rc = mu_mailbox_get_size (mbox, &mbsize);
164 if (rc)
165 {
166 mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_get_size",
167 mailbox_name, rc);
168 mu_mailbox_close (mbox);
169 break;
170 }
171 total += mbsize;
172 mu_mailbox_close (mbox);
173 }
174 while (0);
175 mu_mailbox_destroy (&mbox);
176 }
177 free (mailbox_name);
178
179 if (rc)
180 return RESP_BAD;
181
182 if (total > auth_data->quota)
183 {
184 mu_diag_output (MU_DIAG_NOTICE,
185 _("user %s is out of mailbox quota"),
186 auth_data->name);
187 return RESP_NO;
188 }
189 else if (total + size > auth_data->quota)
190 {
191 mu_diag_output (MU_DIAG_NOTICE,
192 _("user %s: adding %lu bytes would exceed mailbox quota"),
193 auth_data->name, (unsigned long) size);
194 return RESP_NO;
195 }
196 return RESP_OK;
197 }
198
199 void
200 quota_update (mu_off_t size)
201 {
202 used_size += size;
203 }
...@@ -32,6 +32,7 @@ struct mu_list_response ...@@ -32,6 +32,7 @@ struct mu_list_response
32 int level; 32 int level;
33 int separator; 33 int separator;
34 char *name; 34 char *name;
35 mu_record_t format; /* Associated mailbox format record */
35 }; 36 };
36 37
37 typedef int (*mu_folder_match_fp) (const char *, void *, int); 38 typedef int (*mu_folder_match_fp) (const char *, void *, int);
......
...@@ -40,9 +40,12 @@ int mu_construct_user_mailbox_url (char **pout, const char *name); ...@@ -40,9 +40,12 @@ int mu_construct_user_mailbox_url (char **pout, const char *name);
40 /* Constructor/destructor and possible types. */ 40 /* Constructor/destructor and possible types. */
41 extern int mu_mailbox_create (mu_mailbox_t *, const char *); 41 extern int mu_mailbox_create (mu_mailbox_t *, const char *);
42 extern int mu_mailbox_create_from_url (mu_mailbox_t *, mu_url_t); 42 extern int mu_mailbox_create_from_url (mu_mailbox_t *, mu_url_t);
43 extern int mu_mailbox_create_from_record (mu_mailbox_t *pmbox,
44 mu_record_t record,
45 const char *name);
46 extern int mu_mailbox_create_default (mu_mailbox_t *, const char *);
43 47
44 extern void mu_mailbox_destroy (mu_mailbox_t *); 48 extern void mu_mailbox_destroy (mu_mailbox_t *);
45 extern int mu_mailbox_create_default (mu_mailbox_t *, const char *);
46 49
47 extern int mu_mailbox_open (mu_mailbox_t, int flag); 50 extern int mu_mailbox_open (mu_mailbox_t, int flag);
48 extern int mu_mailbox_close (mu_mailbox_t); 51 extern int mu_mailbox_close (mu_mailbox_t);
......
...@@ -118,8 +118,9 @@ typedef struct _mu_progmailer *mu_progmailer_t; ...@@ -118,8 +118,9 @@ typedef struct _mu_progmailer *mu_progmailer_t;
118 typedef struct _mu_secret *mu_secret_t; 118 typedef struct _mu_secret *mu_secret_t;
119 typedef struct _mu_mime_io_buffer *mu_mime_io_buffer_t; 119 typedef struct _mu_mime_io_buffer *mu_mime_io_buffer_t;
120 120
121 #define MU_FOLDER_ATTRIBUTE_DIRECTORY 0x001 121 #define MU_FOLDER_ATTRIBUTE_DIRECTORY 0x001
122 #define MU_FOLDER_ATTRIBUTE_FILE 0x002 122 #define MU_FOLDER_ATTRIBUTE_FILE 0x002
123 #define MU_FOLDER_ATTRIBUTE_LINK 0x004
123 124
124 #define MU_FOLDER_ATTRIBUTE_ALL \ 125 #define MU_FOLDER_ATTRIBUTE_ALL \
125 (MU_FOLDER_ATTRIBUTE_DIRECTORY|MU_FOLDER_ATTRIBUTE_FILE) 126 (MU_FOLDER_ATTRIBUTE_DIRECTORY|MU_FOLDER_ATTRIBUTE_FILE)
......
...@@ -315,7 +315,7 @@ list_helper (struct search_data *data, mu_record_t record, ...@@ -315,7 +315,7 @@ list_helper (struct search_data *data, mu_record_t record,
315 DIR *dirp; 315 DIR *dirp;
316 struct dirent *dp; 316 struct dirent *dp;
317 int stop = 0; 317 int stop = 0;
318 318
319 if (data->max_level && level > data->max_level) 319 if (data->max_level && level > data->max_level)
320 return 0; 320 return 0;
321 321
...@@ -345,13 +345,15 @@ list_helper (struct search_data *data, mu_record_t record, ...@@ -345,13 +345,15 @@ list_helper (struct search_data *data, mu_record_t record,
345 if (ename[ename[0] != '.' ? 0 : ename[1] != '.' ? 1 : 2] == 0) 345 if (ename[ename[0] != '.' ? 0 : ename[1] != '.' ? 1 : 2] == 0)
346 continue; 346 continue;
347 fname = get_pathname (dirname, ename); 347 fname = get_pathname (dirname, ename);
348 if (stat (fname, &st) == 0) 348 if (lstat (fname, &st) == 0)
349 { 349 {
350 int f; 350 int f;
351 if (S_ISDIR (st.st_mode)) 351 if (S_ISDIR (st.st_mode))
352 f = MU_FOLDER_ATTRIBUTE_DIRECTORY; 352 f = MU_FOLDER_ATTRIBUTE_DIRECTORY;
353 else if (S_ISREG (st.st_mode)) 353 else if (S_ISREG (st.st_mode))
354 f = MU_FOLDER_ATTRIBUTE_FILE; 354 f = MU_FOLDER_ATTRIBUTE_FILE;
355 else if (S_ISLNK (st.st_mode))
356 f = MU_FOLDER_ATTRIBUTE_LINK;
355 else 357 else
356 f = 0; 358 f = 0;
357 if (mu_record_list_p (record, ename, f)) 359 if (mu_record_list_p (record, ename, f))
...@@ -386,6 +388,7 @@ list_helper (struct search_data *data, mu_record_t record, ...@@ -386,6 +388,7 @@ list_helper (struct search_data *data, mu_record_t record,
386 resp->level = level; 388 resp->level = level;
387 resp->separator = '/'; 389 resp->separator = '/';
388 resp->type = type; 390 resp->type = type;
391 resp->format = rec;
389 392
390 if (resp->type == 0) 393 if (resp->type == 0)
391 { 394 {
......
...@@ -69,102 +69,110 @@ mailbox_folder_create (mu_mailbox_t mbox, const char *name, ...@@ -69,102 +69,110 @@ mailbox_folder_create (mu_mailbox_t mbox, const char *name,
69 return rc; 69 return rc;
70 } 70 }
71 71
72 static int 72 int
73 _create_mailbox0 (mu_mailbox_t *pmbox, mu_url_t url, const char *name) 73 _mailbox_create_from_record (mu_mailbox_t *pmbox,
74 mu_record_t record,
75 mu_url_t url,
76 const char *name)
74 { 77 {
75 int status; 78 mu_log_level_t level;
76 mu_record_t record = NULL; 79 int (*m_init) (mu_mailbox_t) = NULL;
77 80
78 if (mu_registrar_lookup_url (url, MU_FOLDER_ATTRIBUTE_FILE, &record, NULL) 81 mu_record_get_mailbox (record, &m_init);
79 == 0) 82 if (m_init)
80 { 83 {
81 mu_log_level_t level; 84 int status;
82 int (*m_init) (mu_mailbox_t) = NULL; 85 int (*u_init) (mu_url_t) = NULL;
86 mu_mailbox_t mbox;
83 87
84 mu_record_get_mailbox (record, &m_init); 88 /* Allocate memory for mbox. */
85 if (m_init) 89 mbox = calloc (1, sizeof (*mbox));
86 { 90 if (mbox == NULL)
87 int (*u_init) (mu_url_t) = NULL; 91 return ENOMEM;
88 mu_mailbox_t mbox; 92
89 93 /* Initialize the internal lock now, so the concrete mailbox
90 /* Allocate memory for mbox. */ 94 could use it. */
91 mbox = calloc (1, sizeof (*mbox)); 95 status = mu_monitor_create (&mbox->monitor, 0, mbox);
92 if (mbox == NULL) 96 if (status != 0)
93 return ENOMEM; 97 {
94 98 mu_mailbox_destroy (&mbox);
95 /* Initialize the internal lock now, so the concrete mailbox 99 return status;
96 could use it. */ 100 }
97 status = mu_monitor_create (&mbox->monitor, 0, mbox); 101
98 if (status != 0) 102 /* Make sure scheme contains actual mailbox scheme */
99 { 103 /* FIXME: It is appropriate not for all record types. For now we
100 mu_mailbox_destroy (&mbox); 104 assume that if the record scheme ends with a plus sign, this
101 return status; 105 should not be done. Probably it requires some flag in struct
102 } 106 _mu_record? */
103 107 if (strcmp (url->scheme, record->scheme))
104 /* Make sure scheme contains actual mailbox scheme */ 108 {
105 /* FIXME: It is appropriate not for all record types. For now we 109 char *p = strdup (record->scheme);
106 assume that if the record scheme ends with a plus sign, this 110 if (!p)
107 should not be done. Probably it requires some flag in struct
108 _mu_record? */
109 if (strcmp (url->scheme, record->scheme))
110 {
111 char *p = strdup (record->scheme);
112 if (!p)
113 {
114 mu_mailbox_destroy (&mbox);
115 return errno;
116 }
117 free (url->scheme);
118 url->scheme = p;
119 }
120
121 mu_record_get_url (record, &u_init);
122 if (u_init && (status = u_init (url)) != 0)
123 { 111 {
124 mu_mailbox_destroy (&mbox); 112 mu_mailbox_destroy (&mbox);
125 return status; 113 return errno;
126 } 114 }
127 115 free (url->scheme);
128 mbox->url = url; 116 url->scheme = p;
129 117 }
130 /* Create the folder before initializing the concrete mailbox. 118
131 The mailbox needs it's back pointer. */ 119 mu_record_get_url (record, &u_init);
132 status = mailbox_folder_create (mbox, name, record); 120 if (u_init && (status = u_init (url)) != 0)
121 {
122 mu_mailbox_destroy (&mbox);
123 return status;
124 }
125
126 mbox->url = url;
127
128 /* Create the folder before initializing the concrete mailbox.
129 The mailbox needs it's back pointer. */
130 status = mailbox_folder_create (mbox, name, record);
131
132 if (status == 0)
133 status = m_init (mbox); /* Create the concrete mailbox type. */
134
135 if (status != 0)
136 {
137 /* Take care not to destroy url. Leave it to caller. */
138 mbox->url = NULL;
139 mu_mailbox_destroy (&mbox);
140 }
141 else
142 {
143 *pmbox = mbox;
133 144
134 if (status == 0) 145 level = mu_global_debug_level ("mailbox");
135 status = m_init (mbox); /* Create the concrete mailbox type. */ 146 if (level)
136
137 if (status != 0)
138 {
139 /* Take care not to destroy url. Leave it to caller. */
140 mbox->url = NULL;
141 mu_mailbox_destroy (&mbox);
142 }
143 else
144 { 147 {
145 *pmbox = mbox; 148 int status = mu_debug_create (&mbox->debug, mbox);
146 149 if (status)
147 level = mu_global_debug_level ("mailbox"); 150 return 0; /* FIXME: don't want to bail out just because I
148 if (level) 151 failed to create a *debug* object. But I may
149 { 152 be wrong... */
150 int status = mu_debug_create (&mbox->debug, mbox); 153 mu_debug_set_level (mbox->debug, level);
151 if (status) 154 if (level & MU_DEBUG_INHERIT)
152 return 0; /* FIXME: don't want to bail out just because I 155 mu_folder_set_debug (mbox->folder, mbox->debug);
153 failed to create a *debug* object. But I may
154 be wrong... */
155 mu_debug_set_level (mbox->debug, level);
156 if (level & MU_DEBUG_INHERIT)
157 mu_folder_set_debug (mbox->folder, mbox->debug);
158 }
159 } 156 }
160
161 return status;
162 } 157 }
158
159 return status;
163 } 160 }
164 return MU_ERR_NO_HANDLER; 161 return MU_ERR_NO_HANDLER;
165 } 162 }
166 163
167 static int 164 static int
165 _create_mailbox0 (mu_mailbox_t *pmbox, mu_url_t url, const char *name)
166 {
167 mu_record_t record = NULL;
168
169 if (mu_registrar_lookup_url (url, MU_FOLDER_ATTRIBUTE_FILE, &record, NULL)
170 == 0)
171 return _mailbox_create_from_record (pmbox, record, url, name);
172 return MU_ERR_NO_HANDLER;
173 }
174
175 static int
168 _create_mailbox (mu_mailbox_t *pmbox, const char *name) 176 _create_mailbox (mu_mailbox_t *pmbox, const char *name)
169 { 177 {
170 int status; 178 int status;
...@@ -202,6 +210,24 @@ mu_mailbox_create_from_url (mu_mailbox_t *pmbox, mu_url_t url) ...@@ -202,6 +210,24 @@ mu_mailbox_create_from_url (mu_mailbox_t *pmbox, mu_url_t url)
202 return _create_mailbox0 (pmbox, url, mu_url_to_string (url)); 210 return _create_mailbox0 (pmbox, url, mu_url_to_string (url));
203 } 211 }
204 212
213 int
214 mu_mailbox_create_from_record (mu_mailbox_t *pmbox, mu_record_t record,
215 const char *name)
216 {
217 mu_url_t url;
218 int rc;
219
220 rc = mu_url_create (&url, name);
221 if (rc)
222 return rc;
223 rc = mu_url_parse (url);
224 if (rc == 0)
225 rc = _mailbox_create_from_record (pmbox, record, url, name);
226 if (rc)
227 mu_url_destroy (&url);
228 return rc;
229 }
230
205 void 231 void
206 mu_mailbox_destroy (mu_mailbox_t *pmbox) 232 mu_mailbox_destroy (mu_mailbox_t *pmbox)
207 { 233 {
......