From 661f53f37bfa6cd7562146ec4857413797bc8dd7 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Sun, 12 Sep 2010 18:44:59 +0300 Subject: 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) : 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. * guimb/scm/Makefile.am: Add sieve.scm to AM_INSTALLCHECK_STD_OPTIONS_EXEMPT. --- NEWS | 3 + configure.ac | 6 +- guimb/scm/Makefile.am | 5 ++ imap4d/Makefile.am | 1 + imap4d/append.c | 48 ++++++++--- imap4d/copy.c | 170 ++++++++++++++++++++++++++++++++++--- imap4d/imap4d.c | 5 ++ imap4d/imap4d.h | 7 +- imap4d/quota.c | 203 ++++++++++++++++++++++++++++++++++++++++++++ include/mailutils/folder.h | 1 + include/mailutils/mailbox.h | 5 +- include/mailutils/types.hin | 5 +- libproto/mbox/folder.c | 7 +- mailbox/mailbox.c | 188 ++++++++++++++++++++++------------------ sieve/testsuite/Reject | 6 +- 15 files changed, 547 insertions(+), 113 deletions(-) create mode 100644 imap4d/quota.c diff --git a/NEWS b/NEWS index 4e1f3fc4d..b3e774370 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,9 @@ See the end of file for copying conditions. Please send mailutils bug reports to . +Version 2.2.1 (Git) + + Version 2.2 - 2010-09-08 * Guile support updated to compile with Guile 1.9 diff --git a/configure.ac b/configure.ac index 275d50f1d..7d9e21810 100644 --- a/configure.ac +++ b/configure.ac @@ -18,7 +18,7 @@ dnl with GNU Mailutils; if not, write to the Free Software Foundation, dnl Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA AC_PREREQ(2.63) -AC_INIT([GNU Mailutils], [2.2], [bug-mailutils@gnu.org], [mailutils]) +AC_INIT([GNU Mailutils], [2.2.1], [bug-mailutils@gnu.org], [mailutils]) AC_CONFIG_SRCDIR([mailbox/mailbox.c]) AC_CONFIG_AUX_DIR([build-aux]) AM_INIT_AUTOMAKE([gnits 1.11 dist-bzip2 dist-lzma dist-xz std-options silent-rules]) @@ -1221,7 +1221,9 @@ CPPFLAGS="$CPPFLAGS -DSYSCONFDIR=\\\"\$(sysconfdir)\\\"" AC_SUBST(RENDITION) case `echo $VERSION|sed 's/[[^.]]//g'` in ""|".") RENDITION=DISTRIB;; -"..") if test `echo $VERSION | sed 's/.*\.//'` -lt 50; then +"..") MINOR=`echo $VERSION | sed 's/.*\.//'` + MINS=`echo $MINOR | sed 's/^[0-9][0-9]*//g'` + if test -n "$MINS" || test $MINOR -lt 50; then RENDITION=DISTRIB else RENDITION=PROOF diff --git a/guimb/scm/Makefile.am b/guimb/scm/Makefile.am index 68df43fb0..5a0648340 100644 --- a/guimb/scm/Makefile.am +++ b/guimb/scm/Makefile.am @@ -21,6 +21,11 @@ MU_GUILE_SIEVE_SCRIPTS_X=sieve.scm bin_SCRIPTS = sieve.scm EXTRA_SCRIPTS=sieve.scm +# FIXME: Sieve.scm is temporarly exempted from installchecks because +# it may fail starting during checks, if libguile-mailutils-v- library +# has not been previously installed. The proper fix would be to alter +# %load-path during tests. +AM_INSTALLCHECK_STD_OPTIONS_EXEMPT=sieve.scm sievemoddir=@MU_GUILE_SIEVE_MOD_DIR@ diff --git a/imap4d/Makefile.am b/imap4d/Makefile.am index 65a5b8cba..0d5572889 100644 --- a/imap4d/Makefile.am +++ b/imap4d/Makefile.am @@ -49,6 +49,7 @@ imap4d_SOURCES = \ noop.c\ parsebuf.c\ preauth.c\ + quota.c\ rename.c\ search.c\ select.c\ diff --git a/imap4d/append.c b/imap4d/append.c index f6662aab3..dac1a8ba3 100644 --- a/imap4d/append.c +++ b/imap4d/append.c @@ -71,7 +71,8 @@ imap4d_append0 (mu_mailbox_t mbox, int flags, char *date_time, char *text, struct tm *tm; time_t t; mu_envelope_t env; - + size_t size; + if (mu_message_create (&msg, &tm)) return 1; @@ -94,9 +95,9 @@ imap4d_append0 (mu_mailbox_t mbox, int flags, char *date_time, char *text, } } else - time(&t); + time (&t); - tm = gmtime(&t); + tm = gmtime (&t); while (*text && mu_isblank (*text)) text++; @@ -109,17 +110,42 @@ imap4d_append0 (mu_mailbox_t mbox, int flags, char *date_time, char *text, mu_envelope_set_date (env, _append_date, msg); mu_envelope_set_sender (env, _append_sender, msg); mu_message_set_envelope (msg, env, &tm); + + rc = _append_size (msg, &size); + if (rc) + { + mu_diag_output (MU_DIAG_NOTICE, + _("cannot compute size of the message being appended; " + "using estimated value: %s"), + mu_strerror (rc)); + /* raw estimate */ + size = strlen (text); + } + rc = quota_check (size); + if (rc != RESP_OK) + { + *err_text = rc == RESP_NO ? + "Mailbox quota exceeded" : "Operation failed"; + mu_message_destroy (&msg, &tm); + return 1; + } + rc = mu_mailbox_append_message (mbox, msg); - if (rc == 0 && flags) + if (rc == 0) { - size_t num = 0; - mu_attribute_t attr = NULL; - mu_mailbox_messages_count (mbox, &num); - mu_mailbox_get_message (mbox, num, &msg); - mu_message_get_attribute (msg, &attr); - mu_attribute_set_flags (attr, flags); + if (flags) + { + size_t num = 0; + mu_attribute_t attr = NULL; + mu_mailbox_messages_count (mbox, &num); + mu_mailbox_get_message (mbox, num, &msg); + mu_message_get_attribute (msg, &attr); + mu_attribute_set_flags (attr, flags); + } + /* FIXME: If not INBOX */ + quota_update (size); } - + mu_message_destroy (&msg, &tm); return rc; } diff --git a/imap4d/copy.c b/imap4d/copy.c index b25e1ee30..e0ec3d3cc 100644 --- a/imap4d/copy.c +++ b/imap4d/copy.c @@ -35,6 +35,153 @@ copy messages in argv[2] to mailbox in argv[3] */ +static int +copy_check_size (mu_mailbox_t mbox, size_t n, size_t *set, mu_off_t *size) +{ + int status; + size_t i; + mu_off_t total = 0; + + for (i = 0; i < n; i++) + { + mu_message_t msg = NULL; + size_t msgno = set[i]; + if (msgno) + { + status = mu_mailbox_get_message (mbox, msgno, &msg); + if (status) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_get_message", NULL, + status); + return RESP_BAD; + } + else + { + size_t size; + status = mu_message_size (msg, &size); + if (status) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_message_size", NULL, + status); + return RESP_BAD; + } + total += size; + } + } + } + *size = total; + return quota_check (total); +} + +static int +try_copy (mu_mailbox_t dst, mu_mailbox_t src, size_t n, size_t *set) +{ + int result; + size_t i; + mu_off_t total; + + result = copy_check_size (src, n, set, &total); + if (result) + return result; + + for (i = 0; i < n; i++) + { + mu_message_t msg = NULL; + size_t msgno = set[i]; + + if (msgno) + { + int status = mu_mailbox_get_message (src, msgno, &msg); + if (status) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_get_message", NULL, + status); + return RESP_BAD; + } + + status = mu_mailbox_append_message (dst, msg); + if (status) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_append_message", + NULL, + status); + return RESP_BAD; + } + } + } + quota_update (total); + return RESP_OK; +} + +static int +safe_copy (mu_mailbox_t dst, mu_mailbox_t src, size_t n, size_t *set, + char **err_text) +{ + size_t nmesg; + int status; + + status = mu_mailbox_messages_count (dst, &nmesg); + if (status) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_messages_count", + NULL, status); + *err_text = "Operation failed"; + return RESP_NO; + } + + status = try_copy (dst, src, n, set); + if (status) + { + size_t maxmesg; + + if (status == RESP_NO) + *err_text = "Mailbox quota exceeded"; + else + *err_text = "Operation failed"; + + /* If the COPY command is unsuccessful for any reason, server + implementations MUST restore the destination mailbox to its state + before the COPY attempt. */ + + status = mu_mailbox_messages_count (dst, &maxmesg); + if (status) + { + mu_url_t url = NULL; + + mu_mailbox_get_url (dst, &url); + mu_error (_("cannot count messages in mailbox %s: %s"), + mu_url_to_string (url), mu_strerror (status)); + imap4d_bye (ERR_MAILBOX_CORRUPTED); + } + + for (nmesg++; nmesg <= maxmesg; nmesg++) + { + mu_message_t msg; + + if (mu_mailbox_get_message (dst, nmesg, &msg) == 0) + { + mu_attribute_t attr; + mu_message_get_attribute (msg, &attr); + mu_attribute_set_userflag (attr, MU_ATTRIBUTE_DELETED); + } + } + + status = mu_mailbox_flush (dst, 1); + if (status) + { + mu_url_t url = NULL; + + mu_mailbox_get_url (dst, &url); + mu_error (_("cannot flush mailbox %s: %s"), + mu_url_to_string (url), mu_strerror (status)); + imap4d_bye (ERR_MAILBOX_CORRUPTED); + } + return RESP_NO; + } + + return RESP_OK; +} + int imap4d_copy (struct imap4d_command *command, imap4d_tokbuf_t tok) { @@ -71,6 +218,7 @@ imap4d_copy0 (imap4d_tokbuf_t tok, int isuid, char **err_text) int arg = IMAP4_ARG_1 + !!isuid; int ns; + *err_text = NULL; if (imap4d_tokbuf_argc (tok) != arg + 2) { *err_text = "Invalid arguments"; @@ -89,11 +237,19 @@ imap4d_copy0 (imap4d_tokbuf_t tok, int isuid, char **err_text) return RESP_OK; } + if (isuid) + { + int i; + /* Fixup the message set. Perhaps util_msgset should do it itself? */ + for (i = 0; i < n; i++) + set[i] = uid_to_msgno (set[i]); + } + mailbox_name = namespace_getfullpath (name, delim, &ns); if (!mailbox_name) { - *err_text = "NO Copy failed."; + *err_text = "Copy failed."; return RESP_NO; } @@ -106,14 +262,7 @@ imap4d_copy0 (imap4d_tokbuf_t tok, int isuid, char **err_text) status = mu_mailbox_open (cmbox, MU_STREAM_RDWR | mailbox_mode[ns]); if (status == 0) { - size_t i; - for (i = 0; i < n; i++) - { - mu_message_t msg = NULL; - size_t msgno = (isuid) ? uid_to_msgno (set[i]) : set[i]; - if (msgno && mu_mailbox_get_message (mbox, msgno, &msg) == 0) - mu_mailbox_append_message (cmbox, msg); - } + status = safe_copy (cmbox, mbox, n, set, err_text); mu_mailbox_close (cmbox); } mu_mailbox_destroy (&cmbox); @@ -132,6 +281,7 @@ imap4d_copy0 (imap4d_tokbuf_t tok, int isuid, char **err_text) of the text of the tagged NO response. This gives a hint to the client that it can attempt a CREATE command and retry the copy if the CREATE is successful. */ - *err_text = "[TRYCREATE] failed"; + if (!*err_text) + *err_text = "[TRYCREATE] failed"; return RESP_NO; } diff --git a/imap4d/imap4d.c b/imap4d/imap4d.c index 0b36a0068..ebbdbcb3b 100644 --- a/imap4d/imap4d.c +++ b/imap4d/imap4d.c @@ -352,9 +352,14 @@ imap4d_session_setup0 () util_chdir (imap4d_homedir); namespace_init_session (imap4d_homedir); + mu_diag_output (MU_DIAG_INFO, _("user `%s' logged in (source: %s)"), auth_data->name, auth_data->source); + + if (auth_data->quota) + quota_setup (); + return 0; } diff --git a/imap4d/imap4d.h b/imap4d/imap4d.h index 1d9378d20..31ce80fd4 100644 --- a/imap4d/imap4d.h +++ b/imap4d/imap4d.h @@ -400,7 +400,12 @@ extern void auth_gsasl_init (void); #else # define auth_gsasl_init() #endif - + +/* Quota support */ +void quota_setup (void); +int quota_check (mu_off_t size); +void quota_update (mu_off_t size); + #ifdef __cplusplus } #endif diff --git a/imap4d/quota.c b/imap4d/quota.c new file mode 100644 index 000000000..b39f0d8e9 --- /dev/null +++ b/imap4d/quota.c @@ -0,0 +1,203 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 1999, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, + 2009, 2010 Free Software Foundation, Inc. + + GNU Mailutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GNU Mailutils is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Mailutils. If not, see . */ + +#include "imap4d.h" + +struct imap4d_sizeinfo +{ + mu_off_t size; + mu_off_t nfiles; + mu_off_t ndirs; + mu_off_t nerrs; +}; + +static int +addsize (mu_folder_t folder, struct mu_list_response *resp, void *data) +{ + struct imap4d_sizeinfo *si = data; + + if (resp->type & MU_FOLDER_ATTRIBUTE_DIRECTORY) + si->ndirs++; + + if (resp->type & MU_FOLDER_ATTRIBUTE_FILE) + { + mu_off_t size; + mu_mailbox_t mbox; + int rc; + + si->nfiles++; + + rc = mu_mailbox_create_from_record (&mbox, resp->format, resp->name); + + if (rc) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_create_from_record", + resp->name, rc); + si->nerrs++; + return 0; + } + + rc = mu_mailbox_open (mbox, MU_STREAM_READ); + if (rc) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_open", + resp->name, rc); + si->nerrs++; + mu_mailbox_destroy (&mbox); + return 0; + } + + rc = mu_mailbox_get_size (mbox, &size); + mu_mailbox_destroy (&mbox); + + if (rc) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_open", + resp->name, rc); + si->nerrs++; + return 0; + } + si->size += size; + } + return 0; +} + +void +directory_size (const char *dirname, mu_off_t *size) +{ + mu_folder_t folder; + struct imap4d_sizeinfo sizeinfo; + int status; + + status = mu_folder_create (&folder, dirname); + if (status) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_create", dirname, status); + return; + } + + status = mu_folder_open (folder, MU_STREAM_READ); + if (status) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_open", dirname, status); + mu_folder_destroy (&folder); + return; + } + + memset (&sizeinfo, 0, sizeof (sizeinfo)); + status = mu_folder_enumerate (folder, NULL, "*", 0, 0, NULL, + addsize, &sizeinfo); + if (status) + mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_enumerate", dirname, status); + else + { + mu_diag_output (MU_DIAG_INFO, + _("%s statistics: size=%lu, ndirs=%lu, nfiles=%lu, nerrs=%lu"), + dirname, + (unsigned long)sizeinfo.size, + (unsigned long)sizeinfo.ndirs, + (unsigned long)sizeinfo.nfiles, + (unsigned long)sizeinfo.nerrs); + } + *size = sizeinfo.size; +} + + +mu_off_t used_size; + +void +quota_setup () +{ + directory_size (imap4d_homedir, &used_size); +} + +int +quota_check (mu_off_t size) +{ + char *mailbox_name; + mu_mailbox_t mbox; + mu_off_t total; + int rc; + + if (auth_data->quota == 0) + return RESP_OK; + + total = used_size; + + mailbox_name = namespace_getfullpath ("INBOX", "/", NULL); + rc = mu_mailbox_create (&mbox, mailbox_name); + if (rc) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_create", mailbox_name, rc); + free (mailbox_name); + } + else + { + do + { + mu_off_t mbsize; + + rc = mu_mailbox_open (mbox, MU_STREAM_READ); + if (rc) + { + if (rc != ENOENT) + mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_open", + mailbox_name, rc); + break; + } + + rc = mu_mailbox_get_size (mbox, &mbsize); + if (rc) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_get_size", + mailbox_name, rc); + mu_mailbox_close (mbox); + break; + } + total += mbsize; + mu_mailbox_close (mbox); + } + while (0); + mu_mailbox_destroy (&mbox); + } + free (mailbox_name); + + if (rc) + return RESP_BAD; + + if (total > auth_data->quota) + { + mu_diag_output (MU_DIAG_NOTICE, + _("user %s is out of mailbox quota"), + auth_data->name); + return RESP_NO; + } + else if (total + size > auth_data->quota) + { + mu_diag_output (MU_DIAG_NOTICE, + _("user %s: adding %lu bytes would exceed mailbox quota"), + auth_data->name, (unsigned long) size); + return RESP_NO; + } + return RESP_OK; +} + +void +quota_update (mu_off_t size) +{ + used_size += size; +} diff --git a/include/mailutils/folder.h b/include/mailutils/folder.h index 03390dc62..e639d8b8e 100644 --- a/include/mailutils/folder.h +++ b/include/mailutils/folder.h @@ -32,6 +32,7 @@ struct mu_list_response int level; int separator; char *name; + mu_record_t format; /* Associated mailbox format record */ }; typedef int (*mu_folder_match_fp) (const char *, void *, int); diff --git a/include/mailutils/mailbox.h b/include/mailutils/mailbox.h index d3aa895d1..b8567a9a1 100644 --- a/include/mailutils/mailbox.h +++ b/include/mailutils/mailbox.h @@ -40,9 +40,12 @@ int mu_construct_user_mailbox_url (char **pout, const char *name); /* Constructor/destructor and possible types. */ extern int mu_mailbox_create (mu_mailbox_t *, const char *); extern int mu_mailbox_create_from_url (mu_mailbox_t *, mu_url_t); +extern int mu_mailbox_create_from_record (mu_mailbox_t *pmbox, + mu_record_t record, + const char *name); +extern int mu_mailbox_create_default (mu_mailbox_t *, const char *); extern void mu_mailbox_destroy (mu_mailbox_t *); -extern int mu_mailbox_create_default (mu_mailbox_t *, const char *); extern int mu_mailbox_open (mu_mailbox_t, int flag); extern int mu_mailbox_close (mu_mailbox_t); diff --git a/include/mailutils/types.hin b/include/mailutils/types.hin index 019e66fac..5a0614671 100644 --- a/include/mailutils/types.hin +++ b/include/mailutils/types.hin @@ -115,8 +115,9 @@ typedef struct _mu_progmailer *mu_progmailer_t; typedef struct _mu_secret *mu_secret_t; typedef struct _mu_mime_io_buffer *mu_mime_io_buffer_t; -#define MU_FOLDER_ATTRIBUTE_DIRECTORY 0x001 -#define MU_FOLDER_ATTRIBUTE_FILE 0x002 +#define MU_FOLDER_ATTRIBUTE_DIRECTORY 0x001 +#define MU_FOLDER_ATTRIBUTE_FILE 0x002 +#define MU_FOLDER_ATTRIBUTE_LINK 0x004 #define MU_FOLDER_ATTRIBUTE_ALL \ (MU_FOLDER_ATTRIBUTE_DIRECTORY|MU_FOLDER_ATTRIBUTE_FILE) diff --git a/libproto/mbox/folder.c b/libproto/mbox/folder.c index 3557a88f1..389d59649 100644 --- a/libproto/mbox/folder.c +++ b/libproto/mbox/folder.c @@ -315,7 +315,7 @@ list_helper (struct search_data *data, mu_record_t record, DIR *dirp; struct dirent *dp; int stop = 0; - + if (data->max_level && level > data->max_level) return 0; @@ -345,13 +345,15 @@ list_helper (struct search_data *data, mu_record_t record, if (ename[ename[0] != '.' ? 0 : ename[1] != '.' ? 1 : 2] == 0) continue; fname = get_pathname (dirname, ename); - if (stat (fname, &st) == 0) + if (lstat (fname, &st) == 0) { int f; if (S_ISDIR (st.st_mode)) f = MU_FOLDER_ATTRIBUTE_DIRECTORY; else if (S_ISREG (st.st_mode)) f = MU_FOLDER_ATTRIBUTE_FILE; + else if (S_ISLNK (st.st_mode)) + f = MU_FOLDER_ATTRIBUTE_LINK; else f = 0; if (mu_record_list_p (record, ename, f)) @@ -386,6 +388,7 @@ list_helper (struct search_data *data, mu_record_t record, resp->level = level; resp->separator = '/'; resp->type = type; + resp->format = rec; if (resp->type == 0) { diff --git a/mailbox/mailbox.c b/mailbox/mailbox.c index b06fe3d51..917c5806b 100644 --- a/mailbox/mailbox.c +++ b/mailbox/mailbox.c @@ -69,101 +69,109 @@ mailbox_folder_create (mu_mailbox_t mbox, const char *name, return rc; } -static int -_create_mailbox0 (mu_mailbox_t *pmbox, mu_url_t url, const char *name) +int +_mailbox_create_from_record (mu_mailbox_t *pmbox, + mu_record_t record, + mu_url_t url, + const char *name) { - int status; - mu_record_t record = NULL; - - if (mu_registrar_lookup_url (url, MU_FOLDER_ATTRIBUTE_FILE, &record, NULL) - == 0) + mu_log_level_t level; + int (*m_init) (mu_mailbox_t) = NULL; + + mu_record_get_mailbox (record, &m_init); + if (m_init) { - mu_log_level_t level; - int (*m_init) (mu_mailbox_t) = NULL; + int status; + int (*u_init) (mu_url_t) = NULL; + mu_mailbox_t mbox; - mu_record_get_mailbox (record, &m_init); - if (m_init) - { - int (*u_init) (mu_url_t) = NULL; - mu_mailbox_t mbox; - - /* Allocate memory for mbox. */ - mbox = calloc (1, sizeof (*mbox)); - if (mbox == NULL) - return ENOMEM; - - /* Initialize the internal lock now, so the concrete mailbox - could use it. */ - status = mu_monitor_create (&mbox->monitor, 0, mbox); - if (status != 0) - { - mu_mailbox_destroy (&mbox); - return status; - } - - /* Make sure scheme contains actual mailbox scheme */ - /* FIXME: It is appropriate not for all record types. For now we - assume that if the record scheme ends with a plus sign, this - should not be done. Probably it requires some flag in struct - _mu_record? */ - if (strcmp (url->scheme, record->scheme)) - { - char *p = strdup (record->scheme); - if (!p) - { - mu_mailbox_destroy (&mbox); - return errno; - } - free (url->scheme); - url->scheme = p; - } - - mu_record_get_url (record, &u_init); - if (u_init && (status = u_init (url)) != 0) + /* Allocate memory for mbox. */ + mbox = calloc (1, sizeof (*mbox)); + if (mbox == NULL) + return ENOMEM; + + /* Initialize the internal lock now, so the concrete mailbox + could use it. */ + status = mu_monitor_create (&mbox->monitor, 0, mbox); + if (status != 0) + { + mu_mailbox_destroy (&mbox); + return status; + } + + /* Make sure scheme contains actual mailbox scheme */ + /* FIXME: It is appropriate not for all record types. For now we + assume that if the record scheme ends with a plus sign, this + should not be done. Probably it requires some flag in struct + _mu_record? */ + if (strcmp (url->scheme, record->scheme)) + { + char *p = strdup (record->scheme); + if (!p) { mu_mailbox_destroy (&mbox); - return status; + return errno; } - - mbox->url = url; - - /* Create the folder before initializing the concrete mailbox. - The mailbox needs it's back pointer. */ - status = mailbox_folder_create (mbox, name, record); + free (url->scheme); + url->scheme = p; + } + + mu_record_get_url (record, &u_init); + if (u_init && (status = u_init (url)) != 0) + { + mu_mailbox_destroy (&mbox); + return status; + } + + mbox->url = url; + + /* Create the folder before initializing the concrete mailbox. + The mailbox needs it's back pointer. */ + status = mailbox_folder_create (mbox, name, record); + + if (status == 0) + status = m_init (mbox); /* Create the concrete mailbox type. */ + + if (status != 0) + { + /* Take care not to destroy url. Leave it to caller. */ + mbox->url = NULL; + mu_mailbox_destroy (&mbox); + } + else + { + *pmbox = mbox; - if (status == 0) - status = m_init (mbox); /* Create the concrete mailbox type. */ - - if (status != 0) - { - /* Take care not to destroy url. Leave it to caller. */ - mbox->url = NULL; - mu_mailbox_destroy (&mbox); - } - else + level = mu_global_debug_level ("mailbox"); + if (level) { - *pmbox = mbox; - - level = mu_global_debug_level ("mailbox"); - if (level) - { - int status = mu_debug_create (&mbox->debug, mbox); - if (status) - return 0; /* FIXME: don't want to bail out just because I - failed to create a *debug* object. But I may - be wrong... */ - mu_debug_set_level (mbox->debug, level); - if (level & MU_DEBUG_INHERIT) - mu_folder_set_debug (mbox->folder, mbox->debug); - } + int status = mu_debug_create (&mbox->debug, mbox); + if (status) + return 0; /* FIXME: don't want to bail out just because I + failed to create a *debug* object. But I may + be wrong... */ + mu_debug_set_level (mbox->debug, level); + if (level & MU_DEBUG_INHERIT) + mu_folder_set_debug (mbox->folder, mbox->debug); } - - return status; } + + return status; } return MU_ERR_NO_HANDLER; } +static int +_create_mailbox0 (mu_mailbox_t *pmbox, mu_url_t url, const char *name) +{ + mu_record_t record = NULL; + + if (mu_registrar_lookup_url (url, MU_FOLDER_ATTRIBUTE_FILE, &record, NULL) + == 0) + return _mailbox_create_from_record (pmbox, record, url, name); + return MU_ERR_NO_HANDLER; +} + static int _create_mailbox (mu_mailbox_t *pmbox, const char *name) { @@ -202,6 +210,24 @@ mu_mailbox_create_from_url (mu_mailbox_t *pmbox, mu_url_t url) return _create_mailbox0 (pmbox, url, mu_url_to_string (url)); } +int +mu_mailbox_create_from_record (mu_mailbox_t *pmbox, mu_record_t record, + const char *name) +{ + mu_url_t url; + int rc; + + rc = mu_url_create (&url, name); + if (rc) + return rc; + rc = mu_url_parse (url); + if (rc == 0) + rc = _mailbox_create_from_record (pmbox, record, url, name); + if (rc) + mu_url_destroy (&url); + return rc; +} + void mu_mailbox_destroy (mu_mailbox_t *pmbox) { diff --git a/sieve/testsuite/Reject b/sieve/testsuite/Reject index d8ed5e846..d39d24219 100644 --- a/sieve/testsuite/Reject +++ b/sieve/testsuite/Reject @@ -52,7 +52,7 @@ ENVELOPE TO: 18: Content-Type: message/delivery-status 19: -re - 20: Reporting-UA: sieve; GNU Mailutils [0-9][0-9.]* + 20: Reporting-UA: sieve; GNU Mailutils [0-9][^ ]* -re 21: Arrival-Date: [A-Z][a-z][a-z], [A-Z][a-z][a-z] [ 0-3][0-9] [ 0-2][0-9]:[0-6][0-9]:[0-6][0-9] [0-9][0-9][0-9][0-9] [a-zA-Z0-9]* 22: Final-Recipient: RFC822; foobar@nonexistent.net @@ -113,7 +113,7 @@ ENVELOPE TO: 18: Content-Type: message/delivery-status 19: -re - 20: Reporting-UA: sieve; GNU Mailutils [0-9][0-9.]* + 20: Reporting-UA: sieve; GNU Mailutils [0-9][^ ]* -re 21: Arrival-Date: [A-Z][a-z][a-z], [A-Z][a-z][a-z] [ 0-3][0-9] [ 0-2][0-9]:[0-6][0-9]:[0-6][0-9] [0-9][0-9][0-9][0-9] [a-zA-Z0-9]* 22: Final-Recipient: RFC822; foobar@nonexistent.net @@ -172,7 +172,7 @@ ENVELOPE TO: 18: Content-Type: message/delivery-status 19: -re - 20: Reporting-UA: sieve; GNU Mailutils [0-9][0-9.]* + 20: Reporting-UA: sieve; GNU Mailutils [0-9][^ ]* -re 21: Arrival-Date: [A-Z][a-z][a-z], [A-Z][a-z][a-z] [ 0-3][0-9] [ 0-2][0-9]:[0-6][0-9]:[0-6][0-9] [0-9][0-9][0-9][0-9] [a-zA-Z0-9]* 22: Final-Recipient: RFC822; foobar@nonexistent.net -- cgit v1.2.1