summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org>2019-03-06 06:32:59 (GMT)
committer Sergey Poznyakoff <gray@gnu.org>2019-03-06 06:48:54 (GMT)
commitff847bb1ed851ee4285fdd3768e379855c40483c (patch) (side-by-side diff)
treea8d8139fd4978ff51d0e330ed9d1a62015d1e644
parent9db13766d47f640b5b0d57ba9c3392bdc382971e (diff)
downloadmailutils-ff847bb1ed851ee4285fdd3768e379855c40483c.tar.gz
mailutils-ff847bb1ed851ee4285fdd3768e379855c40483c.tar.bz2
Revamp UID support in dotmail
* include/mailutils/stream.h (mu_stream_header_copy): New proto. * libmailutils/stream/hdrcpy.c: New file. * libmailutils/stream/Makefile.am: Add hdrcpy.c * libmailutils/tests/hdrcpy.c: New test program. * libmailutils/tests/hdrcpy.at: New testcase. * libmailutils/tests/Makefile.am: Add new test program and testcase. * libmailutils/tests/testsuite.at: Add new testcase. * libproto/dotmail/tests/append.at: Add new tests. * libmailutils/tests/.gitignore: Update. * include/mailutils/sys/dotmail.h (mu_dotmail_message): Remove headers_scanned. New field: uid_modified. (mu_dotmail_mailbox): Change type for uidnext to unsigned long. Remove scanned_uids_count. (mu_dotmail_message_headers_prescan) (mu_dotmail_mailbox_scan_uids): Remove. (mu_dotmail_mailbox_uid_setup): New proto. * libproto/dotmail/dotmail.c: Revamp UID support. See "Notes" on line 251 for description. * libproto/dotmail/message.c (mu_dotmail_message_reconstruct): Optimize for the case where the message remains unchanged except for the UID information. * libproto/dotmail/tests/dm_mesg.c: Add mailbox inspection commands from dm_mbox. Perhaps the latter can be removed.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--include/mailutils/stream.h1
-rw-r--r--include/mailutils/sys/dotmail.h9
-rw-r--r--libmailutils/stream/Makefile.am1
-rw-r--r--libmailutils/stream/hdrcpy.c227
-rw-r--r--libmailutils/tests/.gitignore1
-rw-r--r--libmailutils/tests/Makefile.am2
-rw-r--r--libmailutils/tests/hdrcpy.at39
-rw-r--r--libmailutils/tests/hdrcpy.c27
-rw-r--r--libmailutils/tests/testsuite.at1
-rw-r--r--libproto/dotmail/dotmail.c350
-rw-r--r--libproto/dotmail/message.c400
-rw-r--r--libproto/dotmail/tests/append.at156
-rw-r--r--libproto/dotmail/tests/dm_mesg.c62
13 files changed, 850 insertions, 426 deletions
diff --git a/include/mailutils/stream.h b/include/mailutils/stream.h
index 848feae..bd4c3e7 100644
--- a/include/mailutils/stream.h
+++ b/include/mailutils/stream.h
@@ -360,6 +360,7 @@ int mu_stream_printf (mu_stream_t stream, const char *fmt, ...)
int mu_stream_copy (mu_stream_t dst, mu_stream_t src, mu_off_t size,
mu_off_t *pcsz);
+int mu_stream_header_copy (mu_stream_t dst, mu_stream_t src, char **exclude_names);
int mu_file_stream_create (mu_stream_t *pstream, const char *filename, int flags);
diff --git a/include/mailutils/sys/dotmail.h b/include/mailutils/sys/dotmail.h
index 7fa6579..800348b 100644
--- a/include/mailutils/sys/dotmail.h
+++ b/include/mailutils/sys/dotmail.h
@@ -39,9 +39,9 @@ struct mu_dotmail_message
unsigned long uid; /* IMAP-style uid. */
char *hdr[MU_DOTMAIL_HDR_MAX]; /* Pre-scanned headers */
unsigned body_dot_stuffed:1; /* True if body is dot-stuffed */
- unsigned headers_scanned:1; /* True if hdr is filled */
unsigned attr_scanned:1; /* True if attr_flags is initialized */
unsigned body_lines_scanned:1; /* True if body_lines is initialized */
+ unsigned uid_modified:1;/* UID|uidvalidity|uidnext has been modified */
int attr_flags; /* Packed "Status:" attribute flags */
mu_message_t message; /* Pointer to the message object if any */
/* Backlink to the mailbox */
@@ -65,10 +65,8 @@ struct mu_dotmail_mailbox
mu_off_t size; /* Size of the mailbox. */
unsigned long uidvalidity; /* Uidvalidity value */
- unsigned uidnext; /* Expected next UID value */
+ unsigned long uidnext; /* Expected next UID value */
unsigned uidvalidity_scanned:1; /* True if uidvalidity is initialized */
- size_t scanned_uids_count; /* Number of messages for which UIDs have been
- scanned */
struct mu_dotmail_message **mesg; /* Array of messages */
size_t mesg_count; /* Number of messages in mesgv */
@@ -78,9 +76,8 @@ struct mu_dotmail_mailbox
int mu_dotmail_mailbox_init (mu_mailbox_t mailbox);
void mu_dotmail_message_free (struct mu_dotmail_message *dmsg);
int mu_dotmail_message_get (struct mu_dotmail_message *dmsg, mu_message_t *mptr);
-int mu_dotmail_message_headers_prescan (struct mu_dotmail_message *dmsg);
int mu_dotmail_message_attr_load (struct mu_dotmail_message *dmsg);
-int mu_dotmail_mailbox_scan_uids (mu_mailbox_t mailbox, size_t msgno);
+int mu_dotmail_mailbox_uid_setup (struct mu_dotmail_mailbox *dmp);
int mu_dotmail_message_reconstruct (mu_stream_t dest,
struct mu_dotmail_message *dmsg,
struct mu_dotmail_message_ref *ref);
diff --git a/libmailutils/stream/Makefile.am b/libmailutils/stream/Makefile.am
index 9d92920..2c2c396 100644
--- a/libmailutils/stream/Makefile.am
+++ b/libmailutils/stream/Makefile.am
@@ -20,6 +20,7 @@ noinst_LTLIBRARIES = libstream.la
libstream_la_SOURCES = \
file_stream.c\
fltstream.c\
+ hdrcpy.c\
iostream.c\
logstream.c\
mapfile_stream.c\
diff --git a/libmailutils/stream/hdrcpy.c b/libmailutils/stream/hdrcpy.c
new file mode 100644
index 0000000..46d023f
--- a/dev/null
+++ b/libmailutils/stream/hdrcpy.c
@@ -0,0 +1,227 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2010-2019 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 <string.h>
+#include <errno.h>
+#include <mailutils/stream.h>
+#include <mailutils/cctype.h>
+
+static int
+excmp (const void *a, const void *b)
+{
+ return strcmp (*(const char **)a, *(const char **)b);
+}
+
+/* Given a NULL-terminated list of header names in NAMES, create a
+ corresponding expect table for use in mu_stream_header_copy. The
+ expect table is an array of strings of equal length. Each element
+ contains a header name from the input array, converted to lowercase,
+ with a ':' appended to it and stuffed with 0 bytes to the maximum
+ length. The maximum length is selected as the length of the longest
+ string from NAMES plus one.
+ The resulting array is sorted in lexicographical order.
+ On success, return the created table. Store the number of entries in
+ PCOUNT and the maximum length in PMAX.
+ On error (ENOMEM) return NULL.
+ */
+static char **
+make_exclusion_list (char **names, size_t *pcount, size_t *pmax)
+{
+ size_t i, j;
+ size_t count = 0;
+ size_t max_len = 0;
+ char **exlist;
+ char *p;
+
+ for (i = 0; names[i]; i++)
+ {
+ size_t len = strlen (names[i]) + 1;
+ if (len > max_len)
+ max_len = len;
+ }
+ count = i;
+
+ exlist = calloc (count, sizeof (exlist[0]) + max_len + 1);
+ if (!exlist)
+ return NULL;
+ p = (char*)(exlist + count);
+ for (i = 0; names[i]; i++, p += max_len + 1)
+ {
+ exlist[i] = p;
+ for (j = 0; names[i][j]; j++)
+ p[j] = mu_tolower (names[i][j]);
+ p[j++] = ':';
+ memset (p + j, 0, max_len - j + 1);
+ }
+ qsort (exlist, count, sizeof (exlist[0]), excmp);
+
+ *pcount = count;
+ *pmax = max_len;
+ return exlist;
+}
+
+/* Assuming SRC is a stream of RFC 822 headers, copy it to DST, omitting
+ headers from EXCLUDE_NAMES. Stop copying at the empty line ("\n\n")
+ or end of input, whichever occurs first. The terminating newline is
+ read from SRC, but not written to DST. This allows the caller to append
+ to DST any additional headers.
+ Returns mailutils error code.
+ FIXME: Bail out early with MU_ERR_PARSE if the input is not a well-
+ formed header stream. This can be checked in save_state_init and
+ save_state_expect by ensuring that the character read is in the
+ MU_CTYPE_HEADR class.
+*/
+int
+mu_stream_header_copy (mu_stream_t dst, mu_stream_t src, char **exclude_names)
+{
+ int rc;
+ size_t la_max;
+ char *lookahead;
+ size_t la_idx = 0;
+ enum
+ {
+ save_state_init,
+ save_state_expect,
+ save_state_skip,
+ save_state_copy,
+ save_state_stop
+ } state = save_state_init;
+ int i = 0;
+ int j = 0;
+ char **exclude;
+ size_t excount;
+
+ exclude = make_exclusion_list (exclude_names, &excount, &la_max);
+ if (!exclude)
+ return ENOMEM;
+ lookahead = malloc (la_max);
+ if (!lookahead)
+ {
+ free (exclude);
+ return ENOMEM;
+ }
+
+ while (state != save_state_stop)
+ {
+ char c;
+ size_t n;
+
+ rc = mu_stream_read (src, &c, 1, &n);
+ if (rc || n == 0)
+ break;
+
+ if (state == save_state_init || state == save_state_expect)
+ {
+ if (la_idx == la_max)
+ state = save_state_copy;
+ else
+ {
+ lookahead[la_idx++] = c;
+ c = mu_tolower (c);
+ }
+ }
+
+ switch (state)
+ {
+ case save_state_init:
+ if (c == '\n')
+ {
+ /* End of headers. */
+ state = save_state_stop;
+ break;
+ }
+
+ j = 0;
+ state = save_state_copy;
+ for (i = 0; i < excount; i++)
+ {
+ if (exclude[i][j] == c)
+ {
+ j++;
+ state = save_state_expect;
+ break;
+ }
+ }
+ break;
+
+ case save_state_expect:
+ if (exclude[i][j] != c)
+ {
+ while (++i < excount)
+ {
+ if (memcmp (exclude[i-1], exclude[i], j))
+ {
+ state = save_state_copy;
+ break;
+ }
+ if (exclude[i][j] == c)
+ break;
+ }
+ if (i == excount)
+ state = save_state_copy;
+ if (state == save_state_copy)
+ break;
+ }
+
+ if (c == ':')
+ {
+ la_idx = 0;
+ state = save_state_skip;
+ }
+ else
+ {
+ j++;
+ if (exclude[i][j] == 0)
+ state = save_state_copy;
+ }
+ break;
+
+ case save_state_copy:
+ if (la_idx > 0)
+ {
+ rc = mu_stream_write (dst, lookahead, la_idx, NULL);
+ if (rc)
+ break;
+ la_idx = 0;
+ }
+ rc = mu_stream_write (dst, &c, 1, NULL);
+ if (c == '\n')
+ state = save_state_init;
+ break;
+
+ case save_state_skip:
+ if (c == '\n')
+ state = save_state_init;
+ break;
+
+ default:
+ abort (); /* Should not happen */
+ }
+ }
+
+ if (rc == 0)
+ {
+ if (la_idx > 1)
+ rc = mu_stream_write (dst, lookahead, la_idx - 1, NULL);
+ }
+
+ free (lookahead);
+ free (exclude);
+
+ return rc;
+}
diff --git a/libmailutils/tests/.gitignore b/libmailutils/tests/.gitignore
index b93c70a..d72fd78 100644
--- a/libmailutils/tests/.gitignore
+++ b/libmailutils/tests/.gitignore
@@ -19,6 +19,7 @@ fsaf
fsaftomod
fsfolder
globtest
+hdrcpy
imapio
listop
linetrack
diff --git a/libmailutils/tests/Makefile.am b/libmailutils/tests/Makefile.am
index 26137df..b0f3b92 100644
--- a/libmailutils/tests/Makefile.am
+++ b/libmailutils/tests/Makefile.am
@@ -54,6 +54,7 @@ noinst_PROGRAMS = \
fsaftomod\
fsfolder\
globtest\
+ hdrcpy\
imapio\
listop\
linetrack\
@@ -108,6 +109,7 @@ TESTSUITE_AT = \
fsfolder00.at\
fsfolder01.at\
fsfolder02.at\
+ hdrcpy.at\
hdrflt.at\
htmlent.at\
globtest.at\
diff --git a/libmailutils/tests/hdrcpy.at b/libmailutils/tests/hdrcpy.at
new file mode 100644
index 0000000..f760ee0
--- a/dev/null
+++ b/libmailutils/tests/hdrcpy.at
@@ -0,0 +1,39 @@
+# This file is part of GNU Mailutils. -*- Autotest -*-
+# Copyright (C) 2010-2019 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 <http://www.gnu.org/licenses/>.
+
+AT_SETUP([header exclusion copy])
+AT_KEYWORDS([header-filter hdrcpy])
+AT_CHECK([
+AT_DATA([input],[From: gray@example.com
+Subject: Header exclusion test
+X-UID: 1000
+To: root@example.com
+X-IMAPbase: 1 5
+Message-Id: 0123456778
+X-IMAPtest: foo
+X-Mailer: hidden
+])
+
+hdrcpy X-uid X-imapbase x-Mailer < input
+],
+[0],
+[From: gray@example.com
+Subject: Header exclusion test
+To: root@example.com
+Message-Id: 0123456778
+X-IMAPtest: foo
+])
+AT_CLEANUP
diff --git a/libmailutils/tests/hdrcpy.c b/libmailutils/tests/hdrcpy.c
new file mode 100644
index 0000000..6fc129d
--- a/dev/null
+++ b/libmailutils/tests/hdrcpy.c
@@ -0,0 +1,27 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011-2019 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 <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+#include <mailutils/mailutils.h>
+
+int
+main (int argc, char **argv)
+{
+ mu_set_program_name (argv[0]);
+ mu_stdstream_setup (MU_STDSTREAM_RESET_NONE);
+ MU_ASSERT (mu_stream_header_copy (mu_strout, mu_strin, argv + 1));
+ return 0;
+}
diff --git a/libmailutils/tests/testsuite.at b/libmailutils/tests/testsuite.at
index d155d01..db284fd 100644
--- a/libmailutils/tests/testsuite.at
+++ b/libmailutils/tests/testsuite.at
@@ -211,6 +211,7 @@ AT_BANNER(Filters)
m4_include([fromflt.at])
m4_include([inline-comment.at])
m4_include([hdrflt.at])
+m4_include([hdrcpy.at])
m4_include([linecon.at])
m4_include([htmlent.at])
m4_include([xml.at])
diff --git a/libproto/dotmail/dotmail.c b/libproto/dotmail/dotmail.c
index 8e28985..41d7e92 100644
--- a/libproto/dotmail/dotmail.c
+++ b/libproto/dotmail/dotmail.c
@@ -38,6 +38,7 @@
#include <mailutils/header.h>
#include <mailutils/attribute.h>
#include <mailutils/util.h>
+#include <mailutils/cctype.h>
static void
dotmail_destroy (mu_mailbox_t mailbox)
@@ -67,7 +68,7 @@ dotmail_mailbox_init_stream (struct mu_dotmail_mailbox *dmp)
{
int rc;
mu_mailbox_t mailbox = dmp->mailbox;
-
+
rc = mu_mapfile_stream_create (&mailbox->stream, dmp->name, mailbox->flags);
if (rc)
{
@@ -247,6 +248,59 @@ dotmail_dispatch (mu_mailbox_t mailbox, int evt, void *data)
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
+ dotmail_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 matterwhether they
+ have X-UID headers.
+
+ 3b. When any of the following functions are called for
+ the first time: dotmail_uidvalidity, dotmail_uidnext,
+ dotmail_message_uid. This means that the caller used
+ mu_mailbox_uidvalidity, mu_mailbox_uidnext, or
+ mu_message_get_uid.
+ In this case, each message is assigned a UID equal to
+ its ordinal number (1-based) in the mailbox.
+ This is done by the mu_dotmail_mailbox_uid_setup function.
+
+ 4. When a message is appended to the mailbox, any existing
+ X-IMAPbase and X-UID headers are removed from it. If the
+ UID subsystem is initialized, the message is assigned a new
+ UID.
+ 5. Assigning new UID to a message does not change its attributes.
+ Instead, its uid_modified flag is set.
+*/
+
+/* Allocate next available UID for the mailbox.
+ The caller must ensure that the UID subsystem is initialized.
+*/
+static unsigned long
+dotmail_alloc_next_uid (struct mu_dotmail_mailbox *mbox)
+{
+ mbox->mesg[0]->uid_modified = 1;
+ return mbox->uidnext++;
+}
+
+static void
+dotmail_message_alloc_uid (struct mu_dotmail_message *dmsg)
+{
+ free (dmsg->hdr[mu_dotmail_hdr_x_uid]);
+ dmsg->hdr[mu_dotmail_hdr_x_uid] = NULL;
+ dmsg->uid = dotmail_alloc_next_uid (dmsg->mbox);
+ dmsg->uid_modified = 1;
+}
+
static int
dotmail_rescan_unlocked (mu_mailbox_t mailbox, mu_off_t offset)
{
@@ -259,6 +313,7 @@ dotmail_rescan_unlocked (mu_mailbox_t mailbox, mu_off_t offset)
dotmail_scan_init,
dotmail_scan_header,
dotmail_scan_header_newline,
+ dotmail_scan_header_expect,
dotmail_scan_body,
dotmail_scan_body_newline,
dotmail_scan_dot
@@ -266,6 +321,13 @@ dotmail_rescan_unlocked (mu_mailbox_t mailbox, mu_off_t offset)
struct mu_dotmail_message *dmsg;
size_t lines = 0;
int rc;
+ static char *expect[] = {
+ "status: ",
+ "x-imapbase:",
+ "x-uid: ",
+ };
+ int i, j;
+ int force_init_uids = 0;
rc = mu_streamref_create (&stream, mailbox->stream);
if (rc)
@@ -333,7 +395,8 @@ dotmail_rescan_unlocked (mu_mailbox_t mailbox, mu_off_t offset)
return rc;
}
--dmsg->message_start;
- state = dotmail_scan_header;
+ state = dotmail_scan_header_newline;
+ i = j = 0;
break;
case dotmail_scan_header:
@@ -358,7 +421,72 @@ dotmail_rescan_unlocked (mu_mailbox_t mailbox, mu_off_t offset)
state = dotmail_scan_body_newline;
}
else
- state = dotmail_scan_header;
+ {
+ state = dotmail_scan_header;
+ j = 0;
+ for (i = 0; i < MU_DOTMAIL_HDR_MAX; i++)
+ {
+ if (expect[i][j] == mu_tolower (cur))
+ {
+ j++;
+ state = dotmail_scan_header_expect;
+ break;
+ }
+ }
+ }
+ break;
+
+ case dotmail_scan_header_expect:
+ if (cur == '\n')
+ {
+ state = dotmail_scan_header_newline;
+ }
+ else
+ {
+ int c = mu_tolower (cur);
+ if (expect[i][j] != c)
+ {
+ if (++i == MU_DOTMAIL_HDR_MAX
+ || memcmp (expect[i-1], expect[i], j)
+ || expect[i][j] != c)
+ {
+ state = dotmail_scan_header;
+ break;
+ }
+ }
+
+ if (c == ':')
+ {
+ char *buf = NULL;
+ size_t size = 0;
+ size_t n;
+
+ rc = mu_stream_getline (stream, &buf, &size, &n);
+ if (rc)
+ {
+ mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
+ ("%s:%s (%s): %s",
+ __func__, "mu_stream_getline",
+ dmsg->mbox->name,
+ mu_strerror (rc)));
+ return rc;
+ }
+ if (n > 0)
+ {
+ buf[n-1] = 0;
+ dmsg->hdr[i] = buf;
+ }
+ else
+ free (buf);
+ state = dotmail_scan_header_newline;
+ }
+ else
+ {
+ j++;
+ if (expect[i][j] == 0)
+ state = dotmail_scan_header_newline;
+ }
+ }
break;
case dotmail_scan_body:
@@ -399,6 +527,26 @@ dotmail_rescan_unlocked (mu_mailbox_t mailbox, mu_off_t offset)
dmsg->message_end -= 2;
dmsg->body_size--;
+ if (dmsg->num == 0)
+ {
+ if (dmsg->hdr[mu_dotmail_hdr_x_imapbase]
+ && sscanf (dmsg->hdr[mu_dotmail_hdr_x_imapbase],
+ "%lu %lu",
+ &dmp->uidvalidity, &dmp->uidnext) == 2)
+ dmp->uidvalidity_scanned = 1;
+ }
+
+ if (dmp->uidvalidity_scanned)
+ {
+ if (!(!force_init_uids
+ && dmsg->hdr[mu_dotmail_hdr_x_uid]
+ && sscanf (dmsg->hdr[mu_dotmail_hdr_x_uid],
+ "%lu", &dmsg->uid) == 1))
+ force_init_uids = 1;
+ if (force_init_uids)
+ dotmail_message_alloc_uid (dmsg);
+ }
+
/* Every 100 mesgs update the lock, it should be every minute. */
if (mailbox->locker && (dmp->mesg_count % 100) == 0)
mu_locker_touchlock (mailbox->locker);
@@ -531,30 +679,13 @@ dotmail_scan (mu_mailbox_t mailbox, size_t i, size_t *pcount)
}
static int
-dotmail_prescan_headers (mu_mailbox_t mailbox)
-{
- struct mu_dotmail_mailbox *dmp = mailbox->data;
- size_t i = 0;
-
- int rc = dotmail_refresh (mailbox);
- if (rc)
- return rc;
-
- for (; i < dmp->mesg_count; i++)
- mu_dotmail_message_headers_prescan (dmp->mesg[i]);
-
- return 0;
-}
-
-static int
dotmail_messages_recent (mu_mailbox_t mailbox, size_t *pcount)
{
size_t i;
size_t count = 0;
- int rc;
struct mu_dotmail_mailbox *dmp = mailbox->data;
- rc = dotmail_prescan_headers (mailbox);
+ int rc = dotmail_refresh (mailbox);
if (rc)
return rc;
@@ -574,10 +705,9 @@ static int
dotmail_message_unseen (mu_mailbox_t mailbox, size_t *pmsgno)
{
size_t i;
- int rc;
struct mu_dotmail_mailbox *dmp = mailbox->data;
- rc = dotmail_prescan_headers (mailbox);
+ int rc = dotmail_refresh (mailbox);
if (rc)
return rc;
@@ -594,50 +724,42 @@ dotmail_message_unseen (mu_mailbox_t mailbox, size_t *pmsgno)
return MU_ERR_NOENT;
}
-static int
-dotmail_uidvalidity (mu_mailbox_t mailbox, unsigned long *puidvalidity)
+/* Initialize the mailbox UID subsystem. See the Notes above. */
+int
+mu_dotmail_mailbox_uid_setup (struct mu_dotmail_mailbox *dmp)
{
- struct mu_dotmail_mailbox *dmp = mailbox->data;
-
if (!dmp->uidvalidity_scanned)
{
- int rc = dotmail_refresh (mailbox);
- if (rc)
+ size_t i;
+ int rc = dotmail_refresh (dmp->mailbox);
+ if (rc || dmp->uidvalidity_scanned)
return rc;
- if (dmp->mesg_count)
- {
- mu_dotmail_message_attr_load (dmp->mesg[0]);
- if (dmp->mesg[0]->hdr[mu_dotmail_hdr_x_imapbase])
- {
- if (sscanf (dmp->mesg[0]->hdr[mu_dotmail_hdr_x_imapbase],
- "%lu %u",
- &dmp->uidvalidity, &dmp->uidnext) != 2)
- {
- dmp->uidvalidity = (unsigned long)time (NULL);
- dmp->uidnext = dmp->mesg_count + 1;
- }
- }
- }
- else
- {
- dmp->uidvalidity = (unsigned long)time (NULL);
- dmp->uidnext = dmp->mesg_count + 1;
- }
+ dmp->uidvalidity = (unsigned long)time (NULL);
+ dmp->uidnext = 1;
dmp->uidvalidity_scanned = 1;
+
+ for (i = 0; i < dmp->mesg_count; i++)
+ dotmail_message_alloc_uid (dmp->mesg[i]);
}
+ return 0;
+}
- if (puidvalidity)
+static int
+dotmail_uidvalidity (mu_mailbox_t mailbox, unsigned long *puidvalidity)
+{
+ struct mu_dotmail_mailbox *dmp = mailbox->data;
+ int rc = mu_dotmail_mailbox_uid_setup (dmp);
+ if (rc == 0)
*puidvalidity = dmp->uidvalidity;
-
- return 0;
+ return rc;
}
static int
dotmail_uidnext (mu_mailbox_t mailbox, size_t *puidnext)
{
struct mu_dotmail_mailbox *dmp = mailbox->data;
- int rc = dotmail_uidvalidity (mailbox, NULL);
+ int rc = mu_dotmail_mailbox_uid_setup (dmp);
if (rc == 0)
*puidnext = dmp->uidnext;
return rc;
@@ -721,6 +843,12 @@ mailbox_append_message (mu_mailbox_t mailbox, mu_message_t msg)
int rc;
mu_off_t size;
mu_stream_t istr, flt;
+ static char *exclude_headers[] = {
+ MU_HEADER_X_IMAPBASE,
+ MU_HEADER_X_UID,
+ NULL
+ };
+ struct mu_dotmail_mailbox *dmp = mailbox->data;
rc = mu_stream_seek (mailbox->stream, 0, MU_SEEK_END, &size);
if (rc)
@@ -730,14 +858,40 @@ mailbox_append_message (mu_mailbox_t mailbox, mu_message_t msg)
if (rc)
return rc;
- rc = mu_filter_create (&flt, istr, "DOT",
- MU_FILTER_ENCODE, MU_STREAM_READ);
- mu_stream_unref (istr);
+ do
+ {
+ rc = mu_stream_header_copy (mailbox->stream, istr, exclude_headers);
+ if (rc)
+ break;
+
+ /* Write UID-related data */
+ if (dmp->uidvalidity_scanned)
+ {
+ if (dmp->mesg_count == 0)
+ mu_stream_printf (mailbox->stream, "%s: %lu %lu\n",
+ MU_HEADER_X_IMAPBASE,
+ dmp->uidvalidity,
+ dmp->uidnext);
+ mu_stream_printf (mailbox->stream, "%s: %lu\n",
+ MU_HEADER_X_UID,
+ dotmail_alloc_next_uid (dmp));
+ }
+
+ rc = mu_stream_write (mailbox->stream, "\n", 1, NULL);
+ if (rc)
+ break;
+
+ rc = mu_filter_create (&flt, istr, "DOT",
+ MU_FILTER_ENCODE, MU_STREAM_READ);
+ mu_stream_destroy (&istr);
+ rc = mu_stream_copy (mailbox->stream, flt, 0, NULL);
+ mu_stream_unref (flt);
+ }
+ while (0);
- rc = mu_stream_copy (mailbox->stream, flt, 0, NULL);
- mu_stream_unref (flt);
if (rc)
{
+ mu_stream_destroy (&istr);
rc = mu_stream_truncate (mailbox->stream, size);
if (rc)
mu_error (_("cannot truncate stream after failed append: %s"),
@@ -788,42 +942,6 @@ dotmail_append_message (mu_mailbox_t mailbox, mu_message_t msg)
return rc;
}
-int
-mu_dotmail_mailbox_scan_uids (mu_mailbox_t mailbox, size_t msgno)
-{
- struct mu_dotmail_mailbox *dmp = mailbox->data;
- size_t i;
-
- if (dmp->scanned_uids_count < msgno)
- {
- int rc = dotmail_refresh (mailbox);
- if (rc)
- return rc;
-
- for (i = dmp->scanned_uids_count; i < msgno; i++)
- {
- struct mu_dotmail_message *dmsg = dmp->mesg[i];
- int rc = mu_dotmail_message_headers_prescan (dmsg);
- if (rc)
- return rc;
- if (!(dmsg->hdr[mu_dotmail_hdr_x_uid]
- && sscanf (dmsg->hdr[mu_dotmail_hdr_x_uid], "%lu", &dmsg->uid) == 1))
- break;
- }
-
- if (i < msgno)
- {
- int rc = dotmail_uidvalidity (mailbox, NULL);
- if (rc)
- return rc;
- for (; i < msgno; i++)
- dmp->mesg[i]->uid = dmp->uidnext++;
- }
- dmp->scanned_uids_count = msgno;
- }
- return 0;
-}
-
static int
dotmail_messages_count (mu_mailbox_t mailbox, size_t *pcount)
{
@@ -916,12 +1034,9 @@ dotmail_tracker_sync (struct mu_dotmail_flush_tracker *trk)
mu_dotmail_message_free (dmp->mesg[i]);
dmp->size = 0;
dmp->uidvalidity_scanned = 0;
- dmp->scanned_uids_count = 0;
}
else
{
- int reset_scanned_uids = 1;
-
for (i = 0; i < trk->mesg_count; i++)
{
if (trk->ref[i].orig_num != i)
@@ -936,17 +1051,16 @@ dotmail_tracker_sync (struct mu_dotmail_flush_tracker *trk)
dmp->mesg[i]->message_end = trk->ref[i].message_end;
if (trk->ref[i].rescan)
dmp->mesg[i]->body_lines_scanned = 0;
- if (trk->ref[i].orig_num + 1 == dmp->scanned_uids_count)
- reset_scanned_uids = 0;
}
dmp->mesg_count = trk->mesg_count;
- if (reset_scanned_uids)
- dmp->scanned_uids_count = 0;
dmp->size = trk->ref[trk->mesg_count - 1].message_end + 2;
}
/* FIXME: Check uidvalidity values */
}
+/* Write to the output stream DEST messages in the range [from,to).
+ Update TRK accordingly.
+*/
static int
dotmail_mailbox_copy_unchanged (struct mu_dotmail_flush_tracker *trk,
size_t from, size_t to,
@@ -992,6 +1106,10 @@ dotmail_mailbox_copy_unchanged (struct mu_dotmail_flush_tracker *trk,
return 0;
}
+/* Flush the mailbox described by the tracker TRK to the stream TEMPSTR.
+ First modified message is I (0-based). EXPUNGE is 1 if the
+ MU_ATTRIBUTE_DELETED attribute is to be honored.
+*/
static int
dotmail_flush_temp (struct mu_dotmail_flush_tracker *trk,
size_t i,
@@ -1036,24 +1154,22 @@ dotmail_flush_temp (struct mu_dotmail_flush_tracker *trk,
continue;
}
- if (!dmsg->message)
- {
- i++;
- continue;
- }
-
- if ((dmsg->attr_flags & MU_ATTRIBUTE_MODIFIED)
+ if (dmsg->uid_modified
+ || (dmsg->attr_flags & MU_ATTRIBUTE_MODIFIED)
|| mu_message_is_modified (dmsg->message))
{
rc = dotmail_mailbox_copy_unchanged (trk, start, i, tempstr);
if (rc)
return rc;
+
+ free (dmsg->hdr[mu_dotmail_hdr_x_imapbase]);
+ dmsg->hdr[mu_dotmail_hdr_x_imapbase] = NULL;
if (save_imapbase == i)
{
- free (dmsg->hdr[mu_dotmail_hdr_x_imapbase]);
- mu_asprintf (&dmsg->hdr[mu_dotmail_hdr_x_imapbase], "%lu %u",
+ mu_asprintf (&dmsg->hdr[mu_dotmail_hdr_x_imapbase], "%lu %lu",
dmp->uidvalidity, dmp->uidnext);
}
+
rc = mu_dotmail_message_reconstruct (tempstr, dmsg,
tracker_next_ref (trk, i));
if (rc)
@@ -1071,6 +1187,10 @@ dotmail_flush_temp (struct mu_dotmail_flush_tracker *trk,
return mu_stream_flush (tempstr);
}
+/* Flush the mailbox described by the tracker TRK to the stream TEMPSTR.
+ EXPUNGE is 1 if the MU_ATTRIBUTE_DELETED attribute is to be honored.
+ Assumes that simultaneous access to the mailbox has been blocked.
+*/
static int
dotmail_flush_unlocked (struct mu_dotmail_flush_tracker *trk, int expunge)
{
@@ -1098,6 +1218,8 @@ dotmail_flush_unlocked (struct mu_dotmail_flush_tracker *trk, int expunge)
for (dirty = 0; dirty < dmp->mesg_count; dirty++)
{
struct mu_dotmail_message *dmsg = dmp->mesg[dirty];
+ if (dmsg->uid_modified)
+ break;
mu_dotmail_message_attr_load (dmsg);
if ((dmsg->attr_flags & MU_ATTRIBUTE_MODIFIED)
|| (dmsg->attr_flags & MU_ATTRIBUTE_DELETED)
@@ -1197,6 +1319,16 @@ dotmail_flush_unlocked (struct mu_dotmail_flush_tracker *trk, int expunge)
return rc;
}
+/* Flush the changes in the mailbox DMP to disk storage.
+ EXPUNGE is 1 if the MU_ATTRIBUTE_DELETED attribute is to be honored.
+ Block simultaneous access for the duration of the process.
+
+ This is done by creating a temporary mailbox on the same device as
+ DMP and by transferring all messages (whether changed or not) to
+ it. If the process succeeds, old mailbox is removed and the temporary
+ one is renamed to it. In case of failure, the temporary is removed and
+ the original mailbox remains unchanged.
+*/
static int
dotmail_flush (struct mu_dotmail_mailbox *dmp, int expunge)
{
diff --git a/libproto/dotmail/message.c b/libproto/dotmail/message.c
index 76c1a97..1a87616 100644
--- a/libproto/dotmail/message.c
+++ b/libproto/dotmail/message.c
@@ -29,152 +29,6 @@
#include <mailutils/attribute.h>
#include <mailutils/io.h>
-/* Status, UID, uidnext and uidvalidity */
-static char *expect[] = {
- "status: ",
- "x-imapbase:",
- "x-uid: ",
-};
-
-static char *canon_name[] = {
- MU_HEADER_STATUS,
- MU_HEADER_X_IMAPBASE,
- MU_HEADER_X_UID
-};
-
-int
-mu_dotmail_message_headers_prescan (struct mu_dotmail_message *dmsg)
-{
- mu_stream_t stream;
- int rc;
- enum
- {
- prescan_state_init,
- prescan_state_expect,
- prescan_state_skip,
- prescan_state_stop
- } state = prescan_state_init;
-
- int i = 0;
- int j = 0;
-
- char cur;
- size_t n;
-
- if (dmsg->headers_scanned)
- return 0;
-
- rc = mu_streamref_create_abridged (&stream,
- dmsg->mbox->mailbox->stream,
- dmsg->message_start,
- dmsg->body_start - 1);
- if (rc)
- return rc;
-
- rc = mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
- if (rc)
- {
- mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
- ("%s:%s (%s): %s",
- __func__, "mu_stream_seek", dmsg->mbox->name,
- mu_strerror (rc)));
- return rc;
- }
-
- while (state != prescan_state_stop
- && (rc = mu_stream_read (stream, &cur, 1, &n)) == 0
- && n == 1)
- {
- switch (state)
- {
- case prescan_state_init:
- j = 0;
- state = prescan_state_stop;
- for (i = 0; i < MU_DOTMAIL_HDR_MAX; i++)
- {
- if (dmsg->hdr[i] == NULL)
- {
- state = prescan_state_skip;
- if (expect[i][j] == mu_tolower (cur))
- {
- j++;
- state = prescan_state_expect;
- break;
- }
- }
- }
- break;
-
- case prescan_state_expect:
- {
- int c = mu_tolower (cur);
- if (expect[i][j] != c)
- {
- if (++i == MU_DOTMAIL_HDR_MAX
- || memcmp (expect[i-1], expect[i], j)
- || expect[i][j] != c)
- {
- state = prescan_state_skip;
- break;
- }
- }
-
- if (c == ':')
- {
- char *buf = NULL;
- size_t size = 0;
- size_t n;
-
- rc = mu_stream_getline (stream, &buf, &size, &n);
- if (rc)
- {
- mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
- ("%s:%s (%s): %s",
- __func__, "mu_stream_getline",
- dmsg->mbox->name,
- mu_strerror (rc)));
- return rc;
- }
- if (n > 0)
- {
- buf[n-1] = 0;
- dmsg->hdr[i] = buf;
- }
- else
- free (buf);
- state = prescan_state_init;
- }
- else
- {
- j++;
- if (expect[i][j] == 0)
- state = prescan_state_skip;
- }
- }
- break;
-
- case prescan_state_skip:
- if (cur == '\n')
- state = prescan_state_init;
- break;
-
- default:
- break; /* Should not happen */
- }
- }
-
- if (rc)
- {
- mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
- ("%s:%s (%s): %s",
- __func__, "mu_stream_read", dmsg->mbox->name,
- mu_strerror (rc)));
- /* Try to get on with what we've got this far */
- }
- dmsg->headers_scanned = 1;
- return 0;
-}
-
void
mu_dotmail_message_free (struct mu_dotmail_message *dmsg)
{
@@ -301,9 +155,6 @@ mu_dotmail_message_attr_load (struct mu_dotmail_message *dmsg)
{
if (!dmsg->attr_scanned)
{
- int rc = mu_dotmail_message_headers_prescan (dmsg);
- if (rc)
- return rc;
if (dmsg->hdr[mu_dotmail_hdr_status])
mu_string_to_flags (dmsg->hdr[mu_dotmail_hdr_status], &dmsg->attr_flags);
else
@@ -369,8 +220,8 @@ static int
dotmail_message_uid (mu_message_t msg, size_t *puid)
{
struct mu_dotmail_message *dmsg = mu_message_get_owner (msg);
- int rc = mu_dotmail_mailbox_scan_uids (dmsg->mbox->mailbox, dmsg->num + 1);
- if (rc == 0 && puid)
+ int rc = mu_dotmail_mailbox_uid_setup (dmsg->mbox);
+ if (rc == 0)
*puid = dmsg->uid;
return rc;
}
@@ -438,168 +289,100 @@ mu_dotmail_message_get (struct mu_dotmail_message *dmsg, mu_message_t *mptr)
}
static int
-msg_header_to_stream (mu_stream_t dest, mu_stream_t src,
- struct mu_dotmail_message const *dmsg)
+dotmail_message_uid_save (mu_stream_t dst,
+ struct mu_dotmail_message const *dmsg)
{
- int rc;
-#define LA_MAX (sizeof (expect[0]) - 1)
- char lookahead[LA_MAX];
- int la_idx = 0;
- enum
- {
- save_state_init,
- save_state_expect,
- save_state_skip,
- save_state_copy,
- save_state_stop
- } state = save_state_init;
- int i = 0;
- int j = 0;
- int hdr_saved[MU_DOTMAIL_HDR_MAX];
-
- memset (&hdr_saved, 0, sizeof hdr_saved);
- while (1)
+ struct mu_dotmail_mailbox *dmp = dmsg->mbox;
+ if (dmp->uidvalidity_scanned)
{
- char c;
- size_t n;
+ if (dmsg->hdr[mu_dotmail_hdr_x_imapbase])
+ mu_stream_printf (dst, "%s: %s\n",
+ MU_HEADER_X_IMAPBASE,
+ dmsg->hdr[mu_dotmail_hdr_x_imapbase]);
+ mu_stream_printf (dst, "%s: %lu\n",
+ MU_HEADER_X_UID,
+ dmsg->uid);
+ return mu_stream_err (dst) ? mu_stream_last_error (dst) : 0;
+ }
+ return 0;
+}
- rc = mu_stream_read (src, &c, 1, &n);
- if (rc)
- return rc;
- if (n == 0)
- {
- if (la_idx)
- {
- rc = mu_stream_write (dest, lookahead, la_idx, NULL);
- if (rc)
- return rc;
- }
- break;
- }
+/* Copy message DMSG to DST replacing the UID-related information.
+ The message is unchanged otherwise.
+*/
+int
+dotmail_message_copy_with_uid (mu_stream_t dst,
+ struct mu_dotmail_message const *dmsg,
+ struct mu_dotmail_message_ref *ref)
+{
+ int rc;
+ mu_stream_t src;
+ static char *exclude_headers[] = {
+ MU_HEADER_X_IMAPBASE,
+ MU_HEADER_X_UID,
+ NULL
+ };
- if (state == save_state_init || state == save_state_expect)
- {
- if (la_idx == LA_MAX)
- state = save_state_copy;
- else
- {
- lookahead[la_idx++] = c;
- c = mu_tolower (c);
- }
- }
+ src = dmsg->mbox->mailbox->stream;
- switch (state)
- {
- case save_state_init:
- if (c == '\n')
- {
- /* End of headers. */
- for (i = 0; i < MU_DOTMAIL_HDR_MAX; i++)
- {
- if (!hdr_saved[i] && dmsg->hdr[i])
- {
- mu_stream_printf (dest, "%s: %s\n",
- canon_name[i], dmsg->hdr[i]);
- if (mu_stream_err (dest))
- return mu_stream_last_error (dest);
- }
- }
- state = save_state_stop;
- break;
- }
-
- j = 0;
- state = save_state_copy;
- for (i = 0; i < MU_DOTMAIL_HDR_MAX; i++)
- {
- if (!hdr_saved[i] && expect[i][j] == c)
- {
- j++;
- state = save_state_expect;
- break;
- }
- }
- break;
-
- case save_state_expect:
- if (expect[i][j] != c)
- {
- if (++i == MU_DOTMAIL_HDR_MAX
- || memcmp (expect[i-1], expect[i], j)
- || expect[i][j] != c)
- {
- state = save_state_copy;
- break;
- }
- }
-
- if (c == ':')
- {
- if (dmsg->hdr[i])
- {
- rc = mu_stream_write (dest, lookahead, la_idx, NULL);
- if (rc)
- return rc;
- rc = mu_stream_write (dest, dmsg->hdr[i],
- strlen (dmsg->hdr[i]), NULL);
- if (rc)
- return rc;
- rc = mu_stream_write (dest, "\n", 1, NULL);
- if (rc)
- return rc;
- }
- hdr_saved[i] = 1;
- la_idx = 0;
- state = save_state_skip;
- }
- else
- {
- j++;
- if (expect[i][j] == 0)
- state = save_state_copy;
- }
- break;
-
- case save_state_copy:
- if (la_idx > 0)
- {
- rc = mu_stream_write (dest, lookahead, la_idx, NULL);
- if (rc)
- return rc;
- la_idx = 0;
- }
- rc = mu_stream_write (dest, &c, 1, NULL);
- if (c == '\n')
- state = save_state_init;
- break;
+ rc = mu_stream_seek (dst, 0, MU_SEEK_CUR, &ref->message_start);
+ if (rc)
+ return rc;
- case save_state_skip:
- if (c == '\n')
- state = save_state_init;
- break;
+ rc = mu_stream_seek (src, dmsg->message_start, MU_SEEK_SET, NULL);
+ if (rc)
+ return rc;
- default:
- abort (); /* Should not happen */
- }
- }
+ rc = mu_stream_header_copy (dst, src, exclude_headers);
+ if (rc)
+ return rc;
- return 0;
+ rc = dotmail_message_uid_save (dst, dmsg);
+ if (rc)
+ return rc;
+
+ rc = mu_stream_write (dst, "\n", 1, NULL);
+ if (rc)
+ return rc;
+
+ rc = mu_stream_seek (dst, 0, MU_SEEK_CUR, &ref->body_start);
+ if (rc)
+ return rc;
+
+ rc = mu_stream_copy (dst, src,
+ dmsg->message_end - dmsg->body_start + 2,
+ NULL);
+ if (rc)
+ return rc;
+
+ return mu_stream_seek (dst, 0, MU_SEEK_CUR, &ref->message_end);
}
-int
-mu_dotmail_message_reconstruct (mu_stream_t dest,
- struct mu_dotmail_message *dmsg,
- struct mu_dotmail_message_ref *ref)
+static int
+msg_header_to_stream (mu_stream_t dst, mu_stream_t src,
+ struct mu_dotmail_message *dmsg)
{
- int rc;
- mu_header_t hdr;
- mu_body_t body;
- mu_stream_t str, flt;
+ static char *exclude_headers[] = {
+ MU_HEADER_STATUS,
+ MU_HEADER_X_IMAPBASE,
+ MU_HEADER_X_UID,
+ NULL
+ };
mu_attribute_t attr;
+ int rc;
+
+ rc = mu_stream_header_copy (dst, src, exclude_headers);
+ if (rc)
+ return rc;
+
+ rc = dotmail_message_uid_save (dst, dmsg);
+ if (rc)
+ return rc;
rc = mu_message_get_attribute (dmsg->message, &attr);
if (rc)
return rc;
+
free (dmsg->hdr[mu_dotmail_hdr_status]);
dmsg->hdr[mu_dotmail_hdr_status] = malloc (MU_STATUS_BUF_SIZE);
if (!dmsg->hdr[mu_dotmail_hdr_status])
@@ -609,6 +392,29 @@ mu_dotmail_message_reconstruct (mu_stream_t dest,
if (rc)
return rc;
+ mu_stream_printf (dst, "%s: %s\n",
+ MU_HEADER_STATUS,
+ dmsg->hdr[mu_dotmail_hdr_status]);
+
+ return mu_stream_write (dst, "\n", 1, NULL);
+}
+
+/* Write to DEST a reconstructed copy of the message DMSG. Update
+ the tracking reference REF.
+*/
+int
+mu_dotmail_message_reconstruct (mu_stream_t dest,
+ struct mu_dotmail_message *dmsg,
+ struct mu_dotmail_message_ref *ref)
+{
+ int rc;
+ mu_header_t hdr;
+ mu_body_t body;
+ mu_stream_t str, flt;
+
+ if (!dmsg->message)
+ return dotmail_message_copy_with_uid (dest, dmsg, ref);
+
rc = mu_stream_seek (dest, 0, MU_SEEK_CUR, &ref->message_start);
if (rc)
return rc;
diff --git a/libproto/dotmail/tests/append.at b/libproto/dotmail/tests/append.at
index a474edf..e8950db 100644
--- a/libproto/dotmail/tests/append.at
+++ b/libproto/dotmail/tests/append.at
@@ -12,10 +12,10 @@
# 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/>.
+# along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
DM_MESG([append],
-[Received: (from hare@wonder.land)
+[Received: (from hare@wonder.land)
by wonder.land id 3301
for alice@wonder.land; Mon, 29 Jul 2002 22:00:06 +0100
Date: Mon, 29 Jul 2002 22:00:01 +0100
@@ -27,7 +27,7 @@ Return-Path: hare@wonder.land
Have some wine
.
-Received: (from alice@wonder.land)
+Received: (from alice@wonder.land)
by wonder.land id 3302
for hare@wonder.land; Mon, 29 Jul 2002 22:00:07 +0100
Date: Mon, 29 Jul 2002 22:00:02 +0100
@@ -39,7 +39,7 @@ Return-Path: alice@wonder.land
I don't see any wine
.
-Received: (from hare@wonder.land)
+Received: (from hare@wonder.land)
by wonder.land id 3303
for alice@wonder.land; Mon, 29 Jul 2002 22:00:08 +0100
Date: Mon, 29 Jul 2002 22:00:03 +0100
@@ -53,7 +53,7 @@ There isn't any
.
],
[AT_DATA([msg],
-[Received: (from alice@wonder.land)
+[Received: (from alice@wonder.land)
by wonder.land id 3304
for hare@wonder.land; Mon, 29 Jul 2002 22:00:09 +0100
Date: Mon, 29 Jul 2002 22:00:04 +0100
@@ -62,6 +62,7 @@ Message-Id: <200207292200.3304@wonder.land>
To: March Hare <hare@wonder.land>
Subject: Re: Invitation
Return-Path: alice@wonder.land
+X-UID: 1034
Then it wasn't very civil of you to offer it
])],
@@ -73,6 +74,7 @@ append msg
# Check if it is scanned and loaded
env_date
env_sender
+headers
body_text
],
@@ -80,7 +82,151 @@ body_text
4 current message
4 env_date: Mon Jul 29 21:00:09 2002
4 env_sender: alice@wonder.land
+4 headers: Received:(from alice@wonder.land) by wonder.land id 3304 for hare@wonder.land; Mon, 29 Jul 2002 22:00:09 +0100
+Date:Mon, 29 Jul 2002 22:00:04 +0100
+From:Alice <alice@wonder.land>
+Message-Id:<200207292200.3304@wonder.land>
+To:March Hare <hare@wonder.land>
+Subject:Re: Invitation
+Return-Path:alice@wonder.land
+
4 body_text: Then it wasn't very civil of you to offer it
4
])
+
+DM_MESG([append with uid],
+[Received: (from hare@wonder.land)
+ by wonder.land id 3301
+ for alice@wonder.land; Mon, 29 Jul 2002 22:00:06 +0100
+Date: Mon, 29 Jul 2002 22:00:01 +0100
+From: March Hare <hare@wonder.land>
+Message-Id: <200207292200.3301@wonder.land>
+To: Alice <alice@wonder.land>
+Subject: Invitation
+Return-Path: hare@wonder.land
+X-IMAPbase: 1027976406 140
+X-UID: 137
+
+Have some wine
+.
+Received: (from alice@wonder.land)
+ by wonder.land id 3302
+ for hare@wonder.land; Mon, 29 Jul 2002 22:00:07 +0100
+Date: Mon, 29 Jul 2002 22:00:02 +0100
+From: Alice <alice@wonder.land>
+Message-Id: <200207292200.3302@wonder.land>
+To: March Hare <hare@wonder.land>
+Subject: Re: Invitation
+Return-Path: alice@wonder.land
+X-UID: 138
+
+I don't see any wine
+.
+Received: (from hare@wonder.land)
+ by wonder.land id 3303
+ for alice@wonder.land; Mon, 29 Jul 2002 22:00:08 +0100
+Date: Mon, 29 Jul 2002 22:00:03 +0100
+From: March Hare <hare@wonder.land>
+Message-Id: <200207292200.3303@wonder.land>
+To: Alice <alice@wonder.land>
+Subject: Re: Invitation
+Return-Path: hare@wonder.land
+X-UID: 139
+
+There isn't any
+.
+],
+[AT_DATA([msg],
+[Received: (from alice@wonder.land)
+ by wonder.land id 3304
+ for hare@wonder.land; Mon, 29 Jul 2002 22:00:09 +0100
+Date: Mon, 29 Jul 2002 22:00:04 +0100
+From: Alice <alice@wonder.land>
+Message-Id: <200207292200.3304@wonder.land>
+To: March Hare <hare@wonder.land>
+Subject: Re: Invitation
+Return-Path: alice@wonder.land
+X-UID: 1034
+
+Then it wasn't very civil of you to offer it
+])],
+[dm_mbox count uidvalidity uidnext],
+[# Append new message
+append msg
+# Select it
+4
+# Check if it is scanned and loaded
+env_date
+env_sender
+headers
+body_text
+# Check the uidvalidity and uidnext
+uidvalidity
+uidnext
+sync
+],
+
+[append: OK
+4 current message
+4 env_date: Mon Jul 29 21:00:09 2002
+4 env_sender: alice@wonder.land
+4 headers: Received:(from alice@wonder.land) by wonder.land id 3304 for hare@wonder.land; Mon, 29 Jul 2002 22:00:09 +0100
+Date:Mon, 29 Jul 2002 22:00:04 +0100
+From:Alice <alice@wonder.land>
+Message-Id:<200207292200.3304@wonder.land>
+To:March Hare <hare@wonder.land>
+Subject:Re: Invitation
+Return-Path:alice@wonder.land
+X-UID:140
+
+4 body_text: Then it wasn't very civil of you to offer it
+
+uidvalidity: 1027976406
+uidnext: 141
+sync: OK
+4
+1027976406
+141
+])
+
+DM_MESG([append to empty mailbox],
+[],
+[AT_DATA([msg],
+[Received: (from hare@wonder.land)
+ by wonder.land id 3301
+ for alice@wonder.land; Mon, 29 Jul 2002 22:00:06 +0100
+Date: Mon, 29 Jul 2002 22:00:01 +0100
+From: March Hare <hare@wonder.land>
+Message-Id: <200207292200.3301@wonder.land>
+To: Alice <alice@wonder.land>
+Subject: Invitation
+Return-Path: hare@wonder.land
+
+Have some wine
+])],[],
+[# Append new message
+append msg
+# Select it
+1
+# Check if it is scanned and loaded
+env_date
+env_sender
+headers
+body_text
+],
+[append: OK
+1 current message
+1 env_date: Mon Jul 29 21:00:06 2002
+1 env_sender: hare@wonder.land
+1 headers: Received:(from hare@wonder.land) by wonder.land id 3301 for alice@wonder.land; Mon, 29 Jul 2002 22:00:06 +0100
+Date:Mon, 29 Jul 2002 22:00:01 +0100
+From:March Hare <hare@wonder.land>
+Message-Id:<200207292200.3301@wonder.land>
+To:Alice <alice@wonder.land>
+Subject:Invitation
+Return-Path:hare@wonder.land
+
+1 body_text: Have some wine
+
+])
diff --git a/libproto/dotmail/tests/dm_mesg.c b/libproto/dotmail/tests/dm_mesg.c
index bc868a3..b3ba58e 100644
--- a/libproto/dotmail/tests/dm_mesg.c
+++ b/libproto/dotmail/tests/dm_mesg.c
@@ -114,7 +114,7 @@ dm_headers (mu_mailbox_t mbx, mu_message_t msg, char **argv)
char const *name;
char *val;
size_t i, n;
-
+
MU_ASSERT (mu_message_get_header (msg, &hdr));
MU_ASSERT (mu_header_get_field_count (hdr, &n));
for (i = 1; i <= n; i++)
@@ -229,6 +229,46 @@ dm_sync (mu_mailbox_t mbx, mu_message_t msg, char **argv)
MU_ASSERT (mu_mailbox_sync (mbx));
mu_printf ("OK");
}
+
+void
+dm_count (mu_mailbox_t mbx, mu_message_t msg, char **argv)
+{
+ size_t n;
+ MU_ASSERT (mu_mailbox_messages_count (mbx, &n));
+ mu_printf ("%lu", (unsigned long) n);
+}
+
+void
+dm_uidvalidity (mu_mailbox_t mbx, mu_message_t msg, char **argv)
+{
+ unsigned long v;
+ MU_ASSERT (mu_mailbox_uidvalidity (mbx, &v));
+ mu_printf ("%lu", v);
+}
+
+void
+dm_uidnext (mu_mailbox_t mbx, mu_message_t msg, char **argv)
+{
+ size_t n;
+ MU_ASSERT (mu_mailbox_uidnext (mbx, &n));
+ mu_printf ("%lu", (unsigned long) n);
+}
+
+void
+dm_recent (mu_mailbox_t mbx, mu_message_t msg, char **argv)
+{
+ size_t n;
+ MU_ASSERT (mu_mailbox_messages_recent (mbx, &n));
+ mu_printf ("%lu", (unsigned long) n);
+}
+
+void
+dm_unseen (mu_mailbox_t mbx, mu_message_t msg, char **argv)
+{
+ size_t n;
+ MU_ASSERT (mu_mailbox_message_unseen (mbx, &n));
+ mu_printf ("%lu", (unsigned long) n);
+}
typedef void (*dm_action_fn) (mu_mailbox_t, mu_message_t, char **);
@@ -271,7 +311,11 @@ struct dm_action actions[] = {
{ "expunge", dm_expunge, 0, 0 },
{ "sync", dm_sync, 0, 0 },
{ "append", dm_append, 0, 1 },
-
+ { "uidvalidity", dm_uidvalidity, 0, 0 },
+ { "uidnext", dm_uidnext, 0, 0 },
+ { "count", dm_count, 0, 0 },
+ { "recent", dm_recent, 0, 0 },
+ { "unseen", dm_unseen, 0, 0 },
{ NULL }
};
@@ -285,7 +329,7 @@ get_action (char const *s)
return &actions[i];
return NULL;
-}
+}
int
main (int argc, char **argv)
@@ -299,7 +343,7 @@ main (int argc, char **argv)
struct mu_wordsplit ws;
int wsflags;
int rc;
-
+
mu_set_program_name (argv[0]);
mu_stdstream_setup (MU_STDSTREAM_RESET_NONE);
mu_registrar_record (mu_dotmail_record);
@@ -319,15 +363,15 @@ main (int argc, char **argv)
MU_ASSERT (mu_mailbox_open (mbx, MU_STREAM_RDWR));
wsflags = MU_WRDSF_DEFFLAGS
- | MU_WRDSF_COMMENT
- | MU_WRDSF_ALLOC_DIE
- | MU_WRDSF_SHOWERR;
+ | MU_WRDSF_COMMENT
+ | MU_WRDSF_ALLOC_DIE
+ | MU_WRDSF_SHOWERR;
ws.ws_comment = "#";
while ((rc = mu_stream_getline (mu_strin, &buf, &size, &n)) == 0 && n > 0)
{
struct dm_action *act;
-
+
mu_ltrim_class (buf, MU_CTYPE_SPACE);
mu_rtrim_class (buf, MU_CTYPE_SPACE);
@@ -336,7 +380,7 @@ main (int argc, char **argv)
if (ws.ws_wordc == 0)
continue;
-
+
if (mu_isdigit (*ws.ws_wordv[0]))
{
msgno = get_num (ws.ws_wordv[0]);

Return to:

Send suggestions and report system problems to the System administrator.