diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2020-11-23 13:11:29 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2020-11-23 13:20:58 +0200 |
commit | 9763fd4a43128bcd08de8e88cce4142473d38d06 (patch) | |
tree | c4d298e58eb19dd46cc2a11652013827ef9c264d | |
parent | ae91979e9664d99204beb116b9b5e4122e43938e (diff) | |
download | mailutils-9763fd4a43128bcd08de8e88cce4142473d38d06.tar.gz mailutils-9763fd4a43128bcd08de8e88cce4142473d38d06.tar.bz2 |
Implement mboxrb format (a replacement for the mbox used currently)
* configure.ac: New format: mboxrb
* include/mailutils/filter.h (mu_fromrb_filter): New extern.
* include/mailutils/registrar.h (mu_mboxrb_record): New extern.
(mu_register_all_mbox_formats)
(mu_register_local_mbox_formats): Add mu_mboxrb_record.
* libmailutils/filter/filter.c (mu_filter_get_list): Add mu_fromrb_filter
* libproto/Makefile.am [MU_COND_SUPPORT_MBOXRB]: Add mboxrb
* bootstrap.conf: Remove special handling for testsuite/maildir (fixes
1d846d2d92).
* testsuite/mbop.c: Implement the -r (--read-only) option.
* include/mailutils/sys/Makefile.am: Add mboxrb.h
* include/mailutils/sys/mboxrb.h: New file.
* libmailutils/filter/Makefile.am (libfilter_la_SOURCES): Add fromrb.c
* libmailutils/filter/fromrb.c: New file.
* libmailutils/tests/Makefile.am: New file.
* libmailutils/tests/fromrb.at: New file.
* libmailutils/tests/testsuite.at: New file.
* libproto/mboxrb/Makefile.am: New file.
* libproto/mboxrb/mboxrb.c: New file.
* libproto/mboxrb/message.c: New file.
* libproto/mboxrb/tests/.gitignore: New file.
* libproto/mboxrb/tests/Makefile.am: New file.
* libproto/mboxrb/tests/atlocal.in: New file.
* libproto/mboxrb/tests/attr.at: New file.
* libproto/mboxrb/tests/autodetect.at: New file.
* libproto/mboxrb/tests/body.at: New file.
* libproto/mboxrb/tests/count.at: New file.
* libproto/mboxrb/tests/env.at: New file.
* libproto/mboxrb/tests/header.at: New file.
* libproto/mboxrb/tests/testsuite.at: New file.
27 files changed, 3505 insertions, 10 deletions
diff --git a/bootstrap.conf b/bootstrap.conf index 348f71e37..a4d15b08e 100644 --- a/bootstrap.conf +++ b/bootstrap.conf @@ -96,14 +96,6 @@ if [ -z "$help" ]; then eval set -- "`sed 's/#.*$//;/^$/d' .bootstrap | tr '\n' ' '` $*" fi - # Recreate missing maildir parts - for mbox in testsuite/maildir/* - do - test -d $mbox/new || mkdir $mbox/new - test -d $mbox/cur || mkdir $mbox/cur - test -d $mbox/tmp || mkdir $mbox/tmp - done - # Grab the latest radius.m4 test -f m4/radius.m4 || wget -P m4 http://git.savannah.gnu.org/cgit/radius.git/plain/scripts/radius.m4 diff --git a/configure.ac b/configure.ac index ae80fd9c2..6c80ace4f 100644 --- a/configure.ac +++ b/configure.ac @@ -989,6 +989,7 @@ MU_ENABLE_REMOTE_MAILBOX_FORMAT([pop]) MU_ENABLE_LOCAL_MAILBOX_FORMAT([mh]) MU_ENABLE_LOCAL_MAILBOX_FORMAT([maildir]) MU_ENABLE_LOCAL_MAILBOX_FORMAT([dotmail]) +MU_ENABLE_LOCAL_MAILBOX_FORMAT([mboxrb]) AC_SUBST(MU_SMTP_PROGRAMS_BUILD) AC_SUBST(MU_SMTP_DEJATOOL) diff --git a/include/mailutils/filter.h b/include/mailutils/filter.h index e5fdca8e5..2ef398335 100644 --- a/include/mailutils/filter.h +++ b/include/mailutils/filter.h @@ -127,6 +127,7 @@ extern mu_filter_record_t mu_htmlent_filter; extern mu_filter_record_t mu_xml_filter; extern mu_filter_record_t mu_percent_filter; extern mu_filter_record_t mu_dq_filter; +extern mu_filter_record_t mu_fromrb_filter; enum mu_iconv_fallback_mode { diff --git a/include/mailutils/registrar.h b/include/mailutils/registrar.h index 5feac383d..3c252fcaf 100644 --- a/include/mailutils/registrar.h +++ b/include/mailutils/registrar.h @@ -114,6 +114,8 @@ extern mu_record_t mu_pops_record; /* Local Mailbox Unix Mailbox, "mbox:" */ extern mu_record_t mu_mbox_record; +extern mu_record_t mu_mboxrb_record; + /* Local MH, "mh:" */ extern mu_record_t mu_mh_record; /* Maildir, "maildir:" */ @@ -142,6 +144,7 @@ extern mu_record_t mu_dotmail_record; #define mu_register_all_mbox_formats() do {\ mu_registrar_record (mu_mbox_record);\ + mu_registrar_record (mu_mboxrb_record);\ mu_registrar_record (mu_dotmail_record);\ mu_registrar_record (mu_pop_record);\ mu_registrar_record (mu_pops_record);\ @@ -154,6 +157,7 @@ extern mu_record_t mu_dotmail_record; #define mu_register_local_mbox_formats() do {\ mu_registrar_record (mu_mbox_record);\ + mu_registrar_record (mu_mboxrb_record);\ mu_registrar_record (mu_dotmail_record);\ mu_registrar_record (mu_mh_record);\ mu_registrar_record (mu_maildir_record);\ diff --git a/include/mailutils/sys/Makefile.am b/include/mailutils/sys/Makefile.am index 435792aa0..d29849814 100644 --- a/include/mailutils/sys/Makefile.am +++ b/include/mailutils/sys/Makefile.am @@ -40,6 +40,7 @@ sysinclude_HEADERS = \ mailcap.h\ mailer.h\ mapfile_stream.h\ + mboxrb.h\ memory_stream.h\ message_stream.h\ message.h\ diff --git a/include/mailutils/sys/mboxrb.h b/include/mailutils/sys/mboxrb.h new file mode 100644 index 000000000..05e7eb0c4 --- /dev/null +++ b/include/mailutils/sys/mboxrb.h @@ -0,0 +1,98 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2019-2020 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _MAILUTILS_SYS_MBOX2_H +#define _MAILUTILS_SYS_MBOX2_H + +# include <mailutils/types.h> + +enum mu_mboxrb_hdr + { + mu_mboxrb_hdr_status, + mu_mboxrb_hdr_x_imapbase, + mu_mboxrb_hdr_x_uid, + MU_MBOXRB_HDR_MAX + }; + +struct mu_mboxrb_message +{ + /* Offsets in the mailbox */ + mu_off_t message_start; /* Start of message */ + size_t from_length; /* Length of the From_ line */ + int env_sender_len; + int env_date_start; + mu_off_t body_start; /* Start of body */ + mu_off_t message_end; /* Offset of the last byte of the message */ + /* Additional info */ + unsigned long uid; /* IMAP-style uid. */ + + unsigned body_lines_scanned:1; /* True if body_lines is initialized */ + unsigned body_from_escaped:1; /* True if body is from-escaped (valid if + body_lines_scanned is true) */ + unsigned uid_modified:1;/* UID|uidvalidity|uidnext has been modified */ + + int attr_flags; /* Packed "Status:" attribute flags */ + + /* The following two are set only if body_lines_scanned is true */ + size_t body_size; /* Number of octets in message body + (after >From unescape) */ + size_t body_lines; /* Number of lines in message body */ + mu_message_t message; /* Pointer to the message object if any */ + /* Backlink to the mailbox */ + struct mu_mboxrb_mailbox *mbox; /* Mailbox */ + size_t num; /* Number of this message in the mailbox (0-based) */ +}; + +struct mu_mboxrb_message_ref +{ + size_t orig_num; /* Original message index */ + mu_off_t message_start; /* Start of message */ + mu_off_t body_start; /* Start of body */ + mu_off_t message_end; /* End of message */ + int rescan; +}; + +struct mu_mboxrb_mailbox +{ + char *name; /* Disk file name */ + mu_mailbox_t mailbox; /* Associated mailbox */ + int stream_flags; /* Flags used to create the mailbox stream */ + + mu_off_t size; /* Size of the mailbox. */ + unsigned long uidvalidity; /* Uidvalidity value */ + unsigned long uidnext; /* Expected next UID value */ + unsigned uidvalidity_scanned:1; /* True if uidvalidity is initialized */ + unsigned uidvalidity_changed:1; /* True if uidvalidity or uidnext has changed */ + + size_t x_imapbase_off; /* Offset of the X-IMAPbase header */ + size_t x_imapbase_len; /* Length if the header without trailing \n */ + + struct mu_mboxrb_message **mesg; /* Array of messages */ + size_t mesg_count; /* Number of messages in mesgv */ + size_t mesg_max; /* Actual capacity of mesg */ +}; + +int mu_mboxrb_mailbox_init (mu_mailbox_t mailbox); +void mu_mboxrb_message_free (struct mu_mboxrb_message *dmsg); +int mu_mboxrb_message_get (struct mu_mboxrb_message *dmsg, mu_message_t *mptr); +int mu_mboxrb_message_attr_load (struct mu_mboxrb_message *dmsg); +int mu_mboxrb_mailbox_uid_setup (struct mu_mboxrb_mailbox *dmp); +int mu_mboxrb_message_reconstruct (mu_stream_t dest, + struct mu_mboxrb_message *dmsg, + struct mu_mboxrb_message_ref *ref, + char const *x_imapbase); + +#endif diff --git a/libmailutils/filter/Makefile.am b/libmailutils/filter/Makefile.am index 5a27dec15..353237b13 100644 --- a/libmailutils/filter/Makefile.am +++ b/libmailutils/filter/Makefile.am @@ -29,6 +29,7 @@ libfilter_la_SOURCES =\ filter.c\ fltchain.c\ fromflt.c\ + fromrb.c\ header.c\ htmlent.c\ iconvflt.c\ diff --git a/libmailutils/filter/filter.c b/libmailutils/filter/filter.c index e8d0b5ce7..381236b1e 100644 --- a/libmailutils/filter/filter.c +++ b/libmailutils/filter/filter.c @@ -87,6 +87,8 @@ mu_filter_get_list (mu_list_t *plist) mu_list_append (filter_list, mu_xml_filter); mu_list_append (filter_list, mu_percent_filter); mu_list_append (filter_list, mu_dq_filter); + mu_list_append (filter_list, mu_fromrb_filter); + /* FIXME: add the default encodings? */ } *plist = filter_list; diff --git a/libmailutils/filter/fromrb.c b/libmailutils/filter/fromrb.c new file mode 100644 index 000000000..40c1cae95 --- /dev/null +++ b/libmailutils/filter/fromrb.c @@ -0,0 +1,282 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include <string.h> +#include <mailutils/errno.h> +#include <mailutils/filter.h> +#include <mailutils/stream.h> + +enum + { + S_INIT, /* Initial state */ + S_BOL, /* Beginning of line */ + S_ESC, /* Collecting > escapes */ + S_FROM, /* Collecting "From " characters */ + }; + +struct transcoder +{ + int state; /* Transcoder state */ + int count; /* Number of consecutive '>' seen. */ + int len; /* Number of "From" charactes collected */ +}; + +static char from_line[] = "From "; + +/* Move min(isize,osize) bytes from iptr to optr, removing initial '>' + from each sequence '>+From ' at the beginning of line */ +static enum mu_filter_result +_fromrb_decoder (void *xd, + enum mu_filter_command cmd, + struct mu_filter_io *iobuf) +{ + const unsigned char *iptr; + size_t isize; + char *optr; + size_t osize; + struct transcoder *xcode = xd; + size_t i, j, k; + size_t len, reqlen; + + switch (cmd) + { + case mu_filter_init: + xcode->state = S_BOL; + xcode->count = 0; + xcode->len = 0; + return mu_filter_ok; + + case mu_filter_done: + return mu_filter_ok; + + default: + break; + } + + iptr = (const unsigned char *) iobuf->input; + isize = iobuf->isize; + optr = iobuf->output; + osize = iobuf->osize; + + for (i = j = 0; i < isize && j < osize; i++) + { + unsigned char c = *iptr++; + + switch (xcode->state) + { + case S_INIT: + optr[j++] = c; + if (c == '\n') + xcode->state = S_BOL; + break; + + case S_BOL: + if (c == '>') + { + xcode->state = S_ESC; + xcode->count = 1; + } + else + { + optr[j++] = c; + xcode->state = S_INIT; + } + break; + + case S_ESC: + if (c == '>') + { + xcode->count++; + } + else if (c == from_line[0]) + { + xcode->state = S_FROM; + xcode->len = 1; + } + else + { + xcode->state = S_INIT; + goto emit; + } + break; + + case S_FROM: + if (from_line[xcode->len] == 0) + { + xcode->count--; + } + else if (c == from_line[xcode->len]) + { + xcode->len++; + continue; + } + else + { + //RESTORE + } + emit: + reqlen = xcode->len + xcode->count; + len = osize - j; + if (len < reqlen) + { + iobuf->osize = reqlen; + return mu_filter_moreoutput; + } + for (k = 0; k < xcode->count; k++, j++) + optr[j] = '>'; + memcpy (optr + j, from_line, xcode->len); + j += xcode->len; + + xcode->state = S_INIT; + xcode->count = xcode->len = 0; + i--; + iptr--; + } + } + iobuf->isize = i; + iobuf->osize = j; + return mu_filter_ok; +} + +static enum mu_filter_result +_fromrb_encoder (void *xd, + enum mu_filter_command cmd, + struct mu_filter_io *iobuf) +{ + const unsigned char *iptr; + size_t isize; + char *optr; + size_t osize; + struct transcoder *xcode = xd; + size_t i, j, k; + size_t len, reqlen; + + switch (cmd) + { + case mu_filter_init: + xcode->state = S_BOL; + xcode->count = 0; + xcode->len = 0; + return mu_filter_ok; + + case mu_filter_done: + return mu_filter_ok; + + default: + break; + } + + iptr = (const unsigned char *) iobuf->input; + isize = iobuf->isize; + optr = iobuf->output; + osize = iobuf->osize; + + for (i = j = 0; i < isize && j < osize; i++) + { + unsigned char c = *iptr++; + + switch (xcode->state) + { + case S_INIT: + optr[j++] = c; + if (c == '\n') + xcode->state = S_BOL; + break; + + case S_BOL: + if (c == '>') + { + xcode->state = S_ESC; + xcode->count = 1; + } + else if (c == from_line[0]) + { + xcode->state = S_FROM; + xcode->count = 0; + xcode->len = 1; + } + else + { + optr[j++] = c; + xcode->state = S_INIT; + } + break; + + case S_ESC: + if (c == '>') + { + xcode->count++; + } + else if (c == from_line[0]) + { + xcode->state = S_FROM; + xcode->len = 1; + } + else + { + xcode->state = S_INIT; + goto emit; + } + break; + + case S_FROM: + if (from_line[xcode->len] == 0) + { + xcode->count++; + } + else if (c == from_line[xcode->len]) + { + xcode->len++; + continue; + } + else + { + //RESTORE + } + emit: + reqlen = xcode->len + xcode->count; + len = osize - j; + if (len < reqlen) + { + iobuf->osize = reqlen; + return mu_filter_moreoutput; + } + for (k = 0; k < xcode->count; k++, j++) + optr[j] = '>'; + memcpy (optr + j, from_line, xcode->len); + j += xcode->len; + + xcode->state = S_INIT; + xcode->count = xcode->len = 0; + i--; + iptr--; + } + } + iobuf->isize = i; + iobuf->osize = j; + return mu_filter_ok; +} + + +static int +_fromrb_alloc_state (void **pret, int mode, + int argc MU_ARG_UNUSED, const char **argv MU_ARG_UNUSED) +{ + *pret = malloc (sizeof (struct transcoder)); + if (!*pret) + return ENOMEM; + return 0; +} + +static struct _mu_filter_record _fromrb_filter = { + "FROMRB", + _fromrb_alloc_state, + _fromrb_encoder, + _fromrb_decoder +}; + +mu_filter_record_t mu_fromrb_filter = &_fromrb_filter; + + diff --git a/libmailutils/tests/Makefile.am b/libmailutils/tests/Makefile.am index 19aa995e6..6b5ea8bd5 100644 --- a/libmailutils/tests/Makefile.am +++ b/libmailutils/tests/Makefile.am @@ -103,6 +103,7 @@ TESTSUITE_AT += \ encode2047.at\ exp.at\ fromflt.at\ + fromrb.at\ fsaf.at\ fsaftomod.at\ fsfolder00.at\ diff --git a/libmailutils/tests/fromrb.at b/libmailutils/tests/fromrb.at new file mode 100644 index 000000000..022927bf2 --- /dev/null +++ b/libmailutils/tests/fromrb.at @@ -0,0 +1,56 @@ +AT_SETUP([FROMRB filter]) +AT_DATA([enc], +[From me +Fromme + From me +Fram me +From +> From me +>> From me +> >From me +>From me +>>From me +]) +AT_CHECK([fltst FROMRB encode read < enc], +[0], +[>From me +Fromme + From me +Fram me +From +> From me +>> From me +> >From me +>>From me +>>>From me +]) + +AT_DATA([dec], +[From me +>From me +>>From me +>>Fromme +> From me +>> From me +> >From me +>From +>FroM X +>FrOm X +>FRom X +]) +AT_CHECK([fltst FROMRB decode read < dec], +[0], +[From me +From me +>From me +>>Fromme +> From me +>> From me +> >From me +>From +>FroM X +>FrOm X +>FRom X +]) + +AT_CLEANUP diff --git a/libmailutils/tests/testsuite.at b/libmailutils/tests/testsuite.at index 6888f39e6..b78a61767 100644 --- a/libmailutils/tests/testsuite.at +++ b/libmailutils/tests/testsuite.at @@ -220,6 +220,7 @@ m4_include([encode2047.at]) AT_BANNER(Filters) m4_include([fromflt.at]) +m4_include([fromrb.at]) m4_include([inline-comment.at]) m4_include([hdrflt.at]) m4_include([hdrcpy.at]) diff --git a/libproto/Makefile.am b/libproto/Makefile.am index 6e3376ba6..a97641f01 100644 --- a/libproto/Makefile.am +++ b/libproto/Makefile.am @@ -36,3 +36,6 @@ if MU_COND_SUPPORT_DOTMAIL SUBDIRS += dotmail endif +if MU_COND_SUPPORT_MBOXRB + SUBDIRS += mboxrb +endif diff --git a/libproto/mboxrb/Makefile.am b/libproto/mboxrb/Makefile.am new file mode 100644 index 000000000..7bf659ed6 --- /dev/null +++ b/libproto/mboxrb/Makefile.am @@ -0,0 +1,10 @@ +AM_CPPFLAGS = $(MU_LIB_COMMON_INCLUDES) + +lib_LTLIBRARIES = libmu_mboxrb.la +libmu_mboxrb_la_LDFLAGS=-version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@ +libmu_mboxrb_la_LIBADD = $(MU_LIB_MAILUTILS) +libmu_mboxrb_la_SOURCES = \ + mboxrb.c\ + message.c + +SUBDIRS = . tests diff --git a/libproto/mboxrb/mboxrb.c b/libproto/mboxrb/mboxrb.c new file mode 100644 index 000000000..e9babd517 --- /dev/null +++ b/libproto/mboxrb/mboxrb.c @@ -0,0 +1,1739 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2019-2020 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> +#include <stdlib.h> +#include <unistd.h> +#ifdef WITH_PTHREAD +# include <pthread.h> +#endif +#include <sys/stat.h> +#include <signal.h> +#include <mailutils/sys/mboxrb.h> +#include <mailutils/sys/mailbox.h> +#include <mailutils/sys/message.h> +#include <mailutils/diag.h> +#include <mailutils/errno.h> +#include <mailutils/url.h> +#include <mailutils/property.h> +#include <mailutils/io.h> +#include <mailutils/observer.h> +#include <mailutils/filter.h> +#include <mailutils/stream.h> +#include <mailutils/locker.h> +#include <mailutils/nls.h> +#include <mailutils/header.h> +#include <mailutils/attribute.h> +#include <mailutils/util.h> +#include <mailutils/cctype.h> +#include <mailutils/sys/folder.h> +#include <mailutils/sys/registrar.h> + +static void +mboxrb_destroy (mu_mailbox_t mailbox) +{ + size_t i; + struct mu_mboxrb_mailbox *dmp = mailbox->data; + + if (!dmp) + return; + + mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE1, + ("%s (%s)", __func__, dmp->name)); + mu_monitor_wrlock (mailbox->monitor); + for (i = 0; i < dmp->mesg_count; i++) + { + mu_mboxrb_message_free (dmp->mesg[i]); + } + free (dmp->mesg); + free (dmp->name); + free (dmp); + mailbox->data = NULL; + mu_monitor_unlock (mailbox->monitor); +} + +static int +mboxrb_mailbox_init_stream (struct mu_mboxrb_mailbox *dmp) +{ + int rc; + mu_mailbox_t mailbox = dmp->mailbox; + + /* + * Initialize stream flags. If append mode is requested, convert it to + * read-write, so that mboxrb_flush_unlocked be able to update the + * X-IMAPbase header in the first message, if necessary. + */ + dmp->stream_flags = mailbox->flags; + if (dmp->stream_flags & MU_STREAM_APPEND) + dmp->stream_flags = (dmp->stream_flags & ~MU_STREAM_APPEND) | MU_STREAM_RDWR; + rc = mu_mapfile_stream_create (&mailbox->stream, dmp->name, dmp->stream_flags); + if (rc) + { + mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR, + ("%s:%s (%s): %s", + __func__, "mu_mapfile_stream_create", dmp->name, + mu_strerror (rc))); + + /* Fallback to regular file stream */ + rc = mu_file_stream_create (&mailbox->stream, dmp->name, mailbox->flags); + mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR, + ("%s:%s (%s): %s", + __func__, "mu_file_stream_create", dmp->name, + mu_strerror (rc))); + + if (rc) + return rc; + } + + mu_stream_set_buffer (mailbox->stream, mu_buffer_full, 0); + return 0; +} + +static int +mboxrb_open (mu_mailbox_t mailbox, int flags) +{ + struct mu_mboxrb_mailbox *dmp = mailbox->data; + int rc; + + if (!dmp) + return EINVAL; + + mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE1, + ("%s(%s, 0x%x)", __func__, dmp->name, mailbox->flags)); + + mailbox->flags = flags; + + rc = mboxrb_mailbox_init_stream (dmp); + + if (mailbox->locker == NULL + && (flags & (MU_STREAM_WRITE | MU_STREAM_APPEND | MU_STREAM_CREAT))) + { + rc = mu_locker_create (&mailbox->locker, dmp->name, 0); + if (rc) + mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR, + ("%s:%s (%s): %s", + __func__, "mu_locker_create", dmp->name, + mu_strerror (rc))); + } + + return rc; +} + +enum + { + FLUSH_SYNC, + FLUSH_EXPUNGE, /* implies SYNC */ + FLUSH_UIDVALIDITY + }; + +static int mboxrb_flush (struct mu_mboxrb_mailbox *dmp, int flag); + +static int +mboxrb_close (mu_mailbox_t mailbox) +{ + struct mu_mboxrb_mailbox *dmp = mailbox->data; + size_t i; + + if (!dmp) + return EINVAL; + + mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE1, + ("%s (%s)", __func__, dmp->name)); + + if (dmp->uidvalidity_changed && (dmp->stream_flags & MU_STREAM_WRITE)) + mboxrb_flush (dmp, FLUSH_UIDVALIDITY); + + mu_locker_unlock (mailbox->locker); + mu_monitor_wrlock (mailbox->monitor); + for (i = 0; i < dmp->mesg_count; i++) + { + mu_mboxrb_message_free (dmp->mesg[i]); + } + free (dmp->mesg); + dmp->mesg = NULL; + dmp->mesg_count = dmp->mesg_max = 0; + dmp->size = 0; + dmp->uidvalidity = 0; + dmp->uidnext = 1; + mu_monitor_unlock (mailbox->monitor); + mu_stream_destroy (&mailbox->stream); + return 0; +} + +static int +mboxrb_remove (mu_mailbox_t mailbox) +{ + struct mu_mboxrb_mailbox *dmp = mailbox->data; + + if (!dmp) + return EINVAL; + mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE1, + ("%s (%s)", __func__, dmp->name)); + if (unlink (dmp->name)) + return errno; + return 0; +} + +static int +mboxrb_is_updated (mu_mailbox_t mailbox) +{ + struct mu_mboxrb_mailbox *dmp = mailbox->data; + mu_off_t size = 0; + + if (!dmp) + return 0; + + if (mu_stream_size (mailbox->stream, &size) != 0) + return 1; + if (size < dmp->size) + { + mu_observable_notify (mailbox->observable, MU_EVT_MAILBOX_CORRUPT, + mailbox); + mu_diag_output (MU_DIAG_EMERG, _("mailbox corrupted, shrank in size")); + return 0; + } + return (dmp->size == size); +} + +#ifdef WITH_PTHREAD +void +mboxrb_cleanup (void *arg) +{ + mu_mailbox_t mailbox = arg; + mu_monitor_unlock (mailbox->monitor); + mu_locker_unlock (mailbox->locker); +} +#endif + +static int +mboxrb_alloc_message (struct mu_mboxrb_mailbox *dmp, + struct mu_mboxrb_message **dmsg_ptr) +{ + struct mu_mboxrb_message *dmsg; + + if (dmp->mesg_count == dmp->mesg_max) + { + size_t n = dmp->mesg_max; + void *p; + + if (n == 0) + n = 64; + else + { + if ((size_t) -1 / 3 * 2 / sizeof (dmp->mesg[0]) <= n) + return ENOMEM; + n += (n + 1) / 2; + } + p = realloc (dmp->mesg, n * sizeof (dmp->mesg[0])); + if (!p) + return ENOMEM; + dmp->mesg = p; + dmp->mesg_max = n; + } + dmsg = calloc (1, sizeof (*dmsg)); + if (!dmsg) + return ENOMEM; + dmsg->mbox = dmp; + dmsg->num = dmp->mesg_count; + dmp->mesg[dmp->mesg_count++] = dmsg; + *dmsg_ptr = dmsg; + return 0; +} + +static int +mboxrb_dispatch (mu_mailbox_t mailbox, int evt, void *data) +{ + if (!mailbox->observable) + return 0; + + mu_monitor_unlock (mailbox->monitor); + if (mu_observable_notify (mailbox->observable, evt, data)) + { + if (mailbox->locker) + mu_locker_unlock (mailbox->locker); + return EINTR; + } + mu_monitor_wrlock (mailbox->monitor); + return 0; +} + +/* Notes on the UID subsystem + + 1. The values of uidvalidity and uidnext are stored in the + X-IMAPbase header in the first message. + 2. Message UID is stored in the X-UID header in that message. + 3. To minimize unwanted modifications to the mailbox, the + UID subsystem is initialized only in the following cases: + + 3a. Upon mailbox scanning, if the first message contains a + valid X-IMAPbase header. In this case, the + mboxrb_rescan_unlocked function initializes each + message's uid value from the X-UID header. The first + message that lacks X-UID or with an X-UID that cannot + be parsed, gets assigned new UID. The subsequent + messages are assigned new UIDs no matter whether they + have X-UID headers. In this case, the uidvalidity value + is reset to the current timestamp, to indicate that all + UIDs might have changed. + + |