summaryrefslogtreecommitdiff
path: root/libmailutils/base/amd.c
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2011-10-20 16:16:02 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2011-10-20 16:30:00 +0300
commitfa3be4baf0edf9c9df06ca272a19fae88c71d88b (patch)
tree91755894f2d64b7d84489c707c0fe681653eafaa /libmailutils/base/amd.c
parentf697923aaf4a171efe5a074fc064edf415d6643f (diff)
downloadmailutils-fa3be4baf0edf9c9df06ca272a19fae88c71d88b.tar.gz
mailutils-fa3be4baf0edf9c9df06ca272a19fae88c71d88b.tar.bz2
Change attribute handling in Maildir format.
* include/mailutils/message.h (MU_MSG_ATTRIBUTE_MODIFIED) (MU_MSG_HEADER_MODIFIED,MU_MSG_BODY_MODIFIED): New flags. * libmailutils/mailbox/message.c (mu_message_is_modified): Return a bitmask from the above values. * libmailutils/property/create.c (mu_property_create_init): Return error code. * include/mailutils/sys/amd.h (_amd_data) <chattr_msg> <capabilities, prop>: New members. <uidvalidity>: Remove. * libmailutils/base/amd.c: Use MH-style proplist to keep the mailbox properties: uidvalidity, last uid and to cache its size. Store message attributes in the message header only if the mailbox implementation is unable to keep them elsewhere. Use chattr_msg method (if provided) to flush changes in message attributes. * libproto/maildir/folder.c (_maildir_list_p): Ignore .mh* and .mu* files. * libproto/mh/folder.c (_mh_list_p): Likewise. * libproto/maildir/mbox.c: Implement all Maildir flags (except P). Implement the chattr_msg method. * libproto/mh/mbox.c: Remove special handling for uidvalidity. * mh/tests/folder.at: Ignore .mu-prop in directory listings.
Diffstat (limited to 'libmailutils/base/amd.c')
-rw-r--r--libmailutils/base/amd.c433
1 files changed, 295 insertions, 138 deletions
diff --git a/libmailutils/base/amd.c b/libmailutils/base/amd.c
index a63651aab..a5685d99a 100644
--- a/libmailutils/base/amd.c
+++ b/libmailutils/base/amd.c
@@ -129,7 +129,148 @@ struct _amd_body_stream
mu_body_t body;
mu_off_t off;
};
+
+/* AMD Properties */
+int
+_amd_prop_fetch_off (struct _amd_data *amd, const char *name, mu_off_t *pval)
+{
+ const char *p;
+ mu_off_t n = 0;
+
+ if (!amd->prop || mu_property_sget_value (amd->prop, name, &p))
+ return MU_ERR_NOENT;
+ if (!pval)
+ return 0;
+ for (; *p; p++)
+ {
+ if (!mu_isdigit (*p))
+ return EINVAL;
+ n = n * 10 + *p - '0';
+ }
+ *pval = n;
+ return 0;
+}
+
+int
+_amd_prop_fetch_size (struct _amd_data *amd, const char *name, size_t *pval)
+{
+ mu_off_t n;
+ int rc = _amd_prop_fetch_off (amd, name, &n);
+ if (rc == 0)
+ {
+ size_t s = n;
+ if (s != n)
+ return ERANGE;
+ if (pval)
+ *pval = s;
+ }
+ return rc;
+}
+
+int
+_amd_prop_fetch_ulong (struct _amd_data *amd, const char *name,
+ unsigned long *pval)
+{
+ mu_off_t n;
+ int rc = _amd_prop_fetch_off (amd, name, &n);
+ if (rc == 0)
+ {
+ unsigned long s = n;
+ if (s != n)
+ return ERANGE;
+ if (pval)
+ *pval = s;
+ }
+ return rc;
+}
+int
+_amd_prop_store_off (struct _amd_data *amd, const char *name, mu_off_t val)
+{
+ char nbuf[128];
+ char *p;
+ int sign = 0;
+
+ p = nbuf + sizeof nbuf;
+ *--p = 0;
+ if (val < 0)
+ {
+ sign = 1;
+ val = - val;
+ }
+ do
+ {
+ unsigned d = val % 10;
+ if (p == nbuf)
+ return ERANGE;
+ *--p = d + '0';
+ val /= 10;
+ }
+ while (val);
+ if (sign)
+ {
+ if (p == nbuf)
+ return ERANGE;
+ *--p = '-';
+ }
+ return mu_property_set_value (amd->prop, name, p, 1);
+}
+
+/* Backward-compatible size file support */
+static int
+read_size_file (struct _amd_data *amd)
+{
+ FILE *fp;
+ int rc;
+ char *name = mu_make_file_name (amd->name, _MU_AMD_SIZE_FILE_NAME);
+ if (!name)
+ return 1;
+ fp = fopen (name, "r");
+ if (fp)
+ {
+ unsigned long size;
+ if (fscanf (fp, "%lu", &size) == 1)
+ {
+ rc = _amd_prop_store_off (amd, _MU_AMD_PROP_SIZE, size);
+ }
+ else
+ rc = 1;
+ fclose (fp);
+ unlink (name);
+ }
+ else
+ rc = 1;
+ free (name);
+ return rc;
+}
+
+static int
+_amd_prop_create (struct _amd_data *amd)
+{
+ int rc;
+ struct mu_mh_prop *mhprop;
+ mhprop = calloc (1, sizeof (mhprop[0]));
+ if (!mhprop)
+ return ENOMEM;
+ mhprop->filename = mu_make_file_name (amd->name, _MU_AMD_PROP_FILE_NAME);
+ if (!mhprop->filename)
+ {
+ free (mhprop);
+ return errno;
+ }
+ rc = mu_property_create_init (&amd->prop, mu_mh_property_init, mhprop);
+ if (rc)
+ {
+ mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
+ ("mu_property_create_init: %s",
+ mu_strerror (rc)));
+ free (mhprop->filename);
+ free (mhprop);
+ }
+ else
+ read_size_file (amd);
+ return rc;
+}
/* Operations on message array */
@@ -246,8 +387,8 @@ amd_array_expand (struct _amd_data *amd, size_t index)
return 0;
}
-/* Shrink the message array by removing element at INDEX-COUNT and
- shifting left by COUNT positions all the elements on the right of
+/* Shrink the message array by removing the element at INDEX-COUNT and
+ shifting left by COUNT positions all the elements to the right of
it. */
int
amd_array_shrink (struct _amd_data *amd, size_t index, size_t count)
@@ -273,7 +414,7 @@ amd_init_mailbox (mu_mailbox_t mailbox, size_t amd_size,
return EINVAL;
amd = mailbox->data = calloc (1, amd_size);
- if (mailbox->data == NULL)
+ if (amd == NULL)
return ENOMEM;
/* Back pointer. */
@@ -333,7 +474,9 @@ amd_destroy (mu_mailbox_t mailbox)
free (amd->msg_array[i]);
}
free (amd->msg_array);
-
+
+ mu_property_destroy (&amd->prop);
+
if (amd->name)
free (amd->name);
@@ -374,6 +517,9 @@ amd_open (mu_mailbox_t mailbox, int flags)
W_OK : R_OK | X_OK))
return errno;
+ /* Create/read properties. It is not an error if this fails. */
+ _amd_prop_create (amd);
+
if (mailbox->locker == NULL)
mu_locker_create (&mailbox->locker, "/dev/null", 0);
@@ -405,7 +551,6 @@ amd_close (mu_mailbox_t mailbox)
amd->msg_count = 0; /* number of messages in the list */
amd->msg_max = 0; /* maximum message buffer capacity */
- amd->uidvalidity = 0;
mu_monitor_unlock (mailbox->monitor);
return 0;
@@ -547,6 +692,27 @@ _amd_attach_message (mu_mailbox_t mailbox, struct _amd_message *mhm,
}
static int
+_amd_scan0 (struct _amd_data *amd, size_t msgno, size_t *pcount,
+ int do_notify)
+{
+ int status = amd->scan0 (amd->mailbox, msgno, pcount, do_notify);
+ if (status != 0)
+ return status;
+ /* Reset the uidvalidity. */
+ if (amd->msg_count > 0)
+ {
+ unsigned long uidval;
+ if (_amd_prop_fetch_ulong (amd, _MU_AMD_PROP_UIDVALIDITY, &uidval) ||
+ !uidval)
+ {
+ uidval = (unsigned long)time (NULL);
+ _amd_prop_store_off (amd, _MU_AMD_PROP_UIDVALIDITY, uidval);
+ }
+ }
+ return 0;
+}
+
+static int
amd_get_message (mu_mailbox_t mailbox, size_t msgno, mu_message_t *pmsg)
{
int status;
@@ -562,7 +728,7 @@ amd_get_message (mu_mailbox_t mailbox, size_t msgno, mu_message_t *pmsg)
/* If we did not start a scanning yet do it now. */
if (amd->msg_count == 0)
{
- status = amd->scan0 (mailbox, 1, NULL, 0);
+ status = _amd_scan0 (amd, 1, NULL, 0);
if (status != 0)
return status;
}
@@ -647,7 +813,6 @@ _amd_message_save (struct _amd_data *amd, struct _amd_message *mhm,
mu_body_t body;
const char *sbuf;
mu_envelope_t env = NULL;
- char statbuf[MU_STATUS_BUF_SIZE];
status = mu_message_size (msg, &bsize);
if (status)
@@ -724,17 +889,6 @@ _amd_message_save (struct _amd_data *amd, struct _amd_message *mhm,
}
mu_stream_destroy (&stream);
- /* Add imapbase */
- if (!(amd->mailbox->flags & MU_STREAM_APPEND)
- && amd->next_uid
- && (!amd->msg_array || (amd->msg_array[0] == mhm))) /*FIXME*/
- {
- nbytes += fprintf (fp, "X-IMAPbase: %lu %u\n",
- (unsigned long) amd->uidvalidity,
- (unsigned) amd->next_uid (amd));
- nlines++;
- }
-
mu_message_get_envelope (msg, &env);
if (mu_envelope_sget_date (env, &sbuf) == 0)
{
@@ -754,15 +908,21 @@ _amd_message_save (struct _amd_data *amd, struct _amd_message *mhm,
fprintf (fp, "%s: %s\n", MU_HEADER_ENV_SENDER, sbuf);
nlines++;
}
-
- /* Add status */
- mu_message_get_attribute (msg, &attr);
- mu_attribute_to_string (attr, statbuf, sizeof (statbuf), &n);
- if (n)
+
+ if (!(amd->capabilities & MU_AMD_STATUS))
{
- nbytes += fprintf (fp, "Status: %s\n", statbuf);
- nlines++;
+ /* Add status */
+ char statbuf[MU_STATUS_BUF_SIZE];
+
+ mu_message_get_attribute (msg, &attr);
+ mu_attribute_to_string (attr, statbuf, sizeof (statbuf), &n);
+ if (n)
+ {
+ nbytes += fprintf (fp, "Status: %s\n", statbuf);
+ nlines++;
+ }
}
+
nbytes += fprintf (fp, "\n");
nlines++;
@@ -858,7 +1018,7 @@ amd_append_message (mu_mailbox_t mailbox, mu_message_t msg)
/* If we did not start a scanning yet do it now. */
if (amd->msg_count == 0)
{
- status = amd->scan0 (mailbox, 1, NULL, 0);
+ status = _amd_scan0 (amd, 1, NULL, 0);
if (status != 0)
{
free (mhm);
@@ -923,7 +1083,7 @@ amd_messages_count (mu_mailbox_t mailbox, size_t *pcount)
return EINVAL;
if (!amd_is_updated (mailbox))
- return amd->scan0 (mailbox, amd->msg_count, pcount, 0);
+ return _amd_scan0 (amd, amd->msg_count, pcount, 0);
if (pcount)
*pcount = amd->msg_count;
@@ -943,7 +1103,7 @@ amd_messages_recent (mu_mailbox_t mailbox, size_t *pcount)
/* If we did not start a scanning yet do it now. */
if (amd->msg_count == 0)
{
- int status = amd->scan0 (mailbox, 1, NULL, 0);
+ int status = _amd_scan0 (amd, 1, NULL, 0);
if (status != 0)
return status;
}
@@ -967,7 +1127,7 @@ amd_message_unseen (mu_mailbox_t mailbox, size_t *pmsgno)
/* If we did not start a scanning yet do it now. */
if (amd->msg_count == 0)
{
- int status = amd->scan0 (mailbox, 1, NULL, 0);
+ int status = _amd_scan0 (amd, 1, NULL, 0);
if (status != 0)
return status;
}
@@ -982,71 +1142,10 @@ amd_message_unseen (mu_mailbox_t mailbox, size_t *pmsgno)
}
return 0;
}
-
-static char *
-make_size_file_name (struct _amd_data *amd)
-{
- size_t size = strlen (amd->name) + 1 + sizeof (MU_AMD_SIZE_FILE_NAME);
- char *name = malloc (size);
- if (name)
- {
- strcpy (name, amd->name);
- strcat (name, "/");
- strcat (name, MU_AMD_SIZE_FILE_NAME);
- }
- return name;
-}
-
-static int
-read_size_file (struct _amd_data *amd, mu_off_t *psize)
-{
- FILE *fp;
- int rc;
- char *name = make_size_file_name (amd);
- if (!name)
- return 1;
- fp = fopen (name, "r");
- if (fp)
- {
- unsigned long size;
- if (fscanf (fp, "%lu", &size) == 1)
- {
- *psize = size;
- rc = 0;
- }
- else
- rc = 1;
- fclose (fp);
- }
- else
- rc = 1;
- free (name);
- return rc;
-}
-
-static int
-write_size_file (struct _amd_data *amd, mu_off_t size)
-{
- FILE *fp;
- int rc;
- char *name = make_size_file_name (amd);
- if (!name)
- return 1;
- fp = fopen (name, "w");
- if (fp)
- {
- fprintf (fp, "%lu", (unsigned long) size);
- fclose (fp);
- rc = 0;
- }
- else
- rc = 1;
- free (name);
- return rc;
-}
-
+
static int
-compute_mailbox_size (struct _amd_data *amd, const char *name, mu_off_t *psize)
+_compute_mailbox_size_recursive (struct _amd_data *amd, const char *name,
+ mu_off_t *psize)
{
DIR *dir;
struct dirent *entry;
@@ -1099,7 +1198,7 @@ compute_mailbox_size (struct _amd_data *amd, const char *name, mu_off_t *psize)
if (S_ISREG (sb.st_mode))
*psize += sb.st_size;
else if (S_ISDIR (sb.st_mode))
- compute_mailbox_size (amd, buf, psize);
+ _compute_mailbox_size_recursive (amd, buf, psize);
}
/* FIXME: else? */
break;
@@ -1113,6 +1212,20 @@ compute_mailbox_size (struct _amd_data *amd, const char *name, mu_off_t *psize)
}
static int
+compute_mailbox_size (struct _amd_data *amd, mu_off_t *psize)
+{
+ mu_off_t size = 0;
+ int rc = _compute_mailbox_size_recursive (amd, amd->name, &size);
+ if (rc == 0)
+ {
+ rc = _amd_prop_store_off (amd, _MU_AMD_PROP_SIZE, size);
+ if (rc == 0 && psize)
+ *psize = size;
+ }
+ return rc;
+}
+
+static int
amd_remove_mbox (mu_mailbox_t mailbox)
{
int rc;
@@ -1123,11 +1236,22 @@ amd_remove_mbox (mu_mailbox_t mailbox)
rc = amd->remove (amd);
if (rc == 0)
{
- char *name = make_size_file_name (amd);
+ char *name;
+
+ name = mu_make_file_name (amd->name, _MU_AMD_SIZE_FILE_NAME);
if (!name)
return ENOMEM;
if (unlink (name) && errno != ENOENT)
rc = errno;
+ else
+ {
+ free (name);
+ name = mu_make_file_name (amd->name, _MU_AMD_PROP_FILE_NAME);
+ if (!name)
+ return ENOMEM;
+ if (unlink (name) && errno != ENOENT)
+ rc = errno;
+ }
free (name);
}
@@ -1147,6 +1271,55 @@ amd_remove_mbox (mu_mailbox_t mailbox)
}
static int
+_amd_update_message (struct _amd_data *amd, struct _amd_message *mhm,
+ int expunge, int *upd)
+{
+ int flg, rc;
+
+ if (mhm->message)
+ flg = mu_message_is_modified (mhm->message);
+ else if (mhm->attr_flags & MU_ATTRIBUTE_MODIFIED)
+ flg = MU_MSG_ATTRIBUTE_MODIFIED;
+
+ if (!flg)
+ return 0;
+
+ if (flg == MU_MSG_ATTRIBUTE_MODIFIED && amd->chattr_msg)
+ {
+ rc = amd->chattr_msg (mhm, expunge);
+ if (rc)
+ {
+ mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
+ ("_amd_update_message: chattr_msg failed: %s",
+ mu_strerror (rc)));
+ return rc;
+ }
+ }
+ else
+ {
+ rc = _amd_attach_message (amd->mailbox, mhm, NULL);
+ if (rc)
+ {
+ mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
+ ("_amd_update_message: _amd_attach_message failed: %s",
+ mu_strerror (rc)));
+ return rc;
+ }
+
+ rc = _amd_message_save (amd, mhm, expunge);
+ if (rc)
+ {
+ mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
+ ("_amd_update_message: _amd_message_save failed: %s",
+ mu_strerror (rc)));
+ return rc;
+ }
+ }
+ *upd = 1;
+ return rc;
+}
+
+static int
amd_expunge (mu_mailbox_t mailbox)
{
struct _amd_data *amd = mailbox->data;
@@ -1232,13 +1405,7 @@ amd_expunge (mu_mailbox_t mailbox)
}
else
{
- if ((mhm->attr_flags & MU_ATTRIBUTE_MODIFIED)
- || (mhm->message && mu_message_is_modified (mhm->message)))
- {
- _amd_attach_message (mailbox, mhm, NULL);
- _amd_message_save (amd, mhm, 1);
- updated = 1;
- }
+ _amd_update_message (amd, mhm, 1, &updated);/*FIXME: Error checking*/
}
}
@@ -1263,10 +1430,7 @@ amd_expunge (mu_mailbox_t mailbox)
if (updated && !amd->mailbox_size)
{
- mu_off_t size = 0;
- int rc = compute_mailbox_size (amd, amd->name, &size);
- if (rc == 0)
- write_size_file (amd, size);
+ compute_mailbox_size (amd, NULL);
}
return 0;
}
@@ -1297,22 +1461,12 @@ amd_sync (mu_mailbox_t mailbox)
for ( ; i < amd->msg_count; i++)
{
mhm = amd->msg_array[i];
-
- if ((mhm->attr_flags & MU_ATTRIBUTE_MODIFIED)
- || (mhm->message && mu_message_is_modified (mhm->message)))
- {
- _amd_attach_message (mailbox, mhm, NULL);
- _amd_message_save (amd, mhm, 0);
- updated = 1;
- }
+ _amd_update_message (amd, mhm, 0, &updated);
}
if (updated && !amd->mailbox_size)
{
- mu_off_t size = 0;
- int rc = compute_mailbox_size (amd, amd->name, &size);
- if (rc == 0)
- write_size_file (amd, size);
+ compute_mailbox_size (amd, NULL);
}
return 0;
@@ -1328,13 +1482,12 @@ amd_uidvalidity (mu_mailbox_t mailbox, unsigned long *puidvalidity)
/* If we did not start a scanning yet do it now. */
if (amd->msg_count == 0)
{
- status = amd->scan0 (mailbox, 1, NULL, 0);
+ status = _amd_scan0 (amd, 1, NULL, 0);
if (status != 0)
return status;
}
- if (puidvalidity)
- *puidvalidity = amd->uidvalidity;
- return 0;
+
+ return _amd_prop_fetch_ulong (amd, _MU_AMD_PROP_UIDVALIDITY, puidvalidity);
}
static int
@@ -1351,7 +1504,7 @@ amd_uidnext (mu_mailbox_t mailbox, size_t *puidnext)
/* If we did not start a scanning yet do it now. */
if (amd->msg_count == 0)
{
- status = amd->scan0 (mailbox, 1, NULL, 0);
+ status = _amd_scan0 (amd, 1, NULL, 0);
if (status != 0)
return status;
}
@@ -1458,7 +1611,9 @@ amd_scan_message (struct _amd_message *mhm)
size_t body_start = 0;
struct stat st;
char *msg_name;
-
+ struct _amd_data *amd = mhm->amd;
+ int amd_capa = amd->capabilities;
+
/* Check if the message was modified after the last scan */
status = mhm->amd->cur_msg_file_name (mhm, &msg_name);
if (status)
@@ -1498,17 +1653,25 @@ amd_scan_message (struct _amd_message *mhm)
hlines++;
/* Process particular attributes */
- if (mu_c_strncasecmp (buf, "status:", 7) == 0)
+ if (!(amd_capa & MU_AMD_STATUS) &&
+ mu_c_strncasecmp (buf, "status:", 7) == 0)
{
int deleted = mhm->attr_flags & MU_ATTRIBUTE_DELETED;
mu_string_to_flags (buf, &mhm->attr_flags);
mhm->attr_flags |= deleted;
}
- else if (mu_c_strncasecmp (buf, "x-imapbase:", 11) == 0)
+ else if (!(amd_capa & MU_AMD_IMAPBASE) &&
+ mu_c_strncasecmp (buf, "x-imapbase:", 11) == 0)
{
- char *p;
- mhm->amd->uidvalidity = strtoul (buf + 11, &p, 10);
- /* second number is next uid. Ignored */
+ if (_amd_prop_fetch_ulong (amd, _MU_AMD_PROP_UIDVALIDITY,
+ NULL))
+ {
+ char *p;
+ unsigned long uidval = strtoul (buf + 11, &p, 10);
+ /* The next number is next uid. Ignored */
+ _amd_prop_store_off (amd, _MU_AMD_PROP_UIDVALIDITY,
+ uidval);
+ }
}
}
else
@@ -1545,7 +1708,7 @@ amd_scan (mu_mailbox_t mailbox, size_t msgno, size_t *pcount)
struct _amd_data *amd = mailbox->data;
if (! amd_is_updated (mailbox))
- return amd->scan0 (mailbox, msgno, pcount, 1);
+ return _amd_scan0 (amd, msgno, pcount, 1);
if (pcount)
*pcount = amd->msg_count;
@@ -1573,14 +1736,8 @@ amd_get_size (mu_mailbox_t mailbox, mu_off_t *psize)
struct _amd_data *amd = mailbox->data;
if (amd->mailbox_size)
return amd->mailbox_size (mailbox, psize);
- *psize = 0;
- if (read_size_file (amd, psize))
- {
- int rc = compute_mailbox_size (amd, amd->name, psize);
- if (rc == 0)
- write_size_file (amd, *psize);
- return rc;
- }
+ if (_amd_prop_fetch_off (amd, _MU_AMD_PROP_SIZE, psize))
+ return compute_mailbox_size (amd, psize);
return 0;
}

Return to:

Send suggestions and report system problems to the System administrator.