Commit 8611b6e6 8611b6e6b983579fd8955f5878f53d463acce42a by Sergey Poznyakoff

Fix message delivery to maildir boxes.

* libproto/include/amd.h (struct _amd_message): Remove `deleted',
add `orig_flags' instead.
(struct _amd_data): Remove `msg_file_name', add `cur_msg_file_name'
and `new_msg_file_name'.
Add `mailbox_size'.
* libproto/maildir/mbox.c (struct _maildir_message): Remove
`newflag', add `dir'.
(maildir_name_info_ptr): New function.
(mk_info_filename): Bugfix.
(maildir_cur_message_name, maildir_new_message_name): New
functions.
(maildir_msg_init): Set ->dir
(maildir_msg_finish_delivery): Handle error conditions.
(maildir_scan_dir): New argument `dirname'. Initialize orig_flags.
(maildir_qfetch): Initialize dir.
(_mailbox_maildir_init): Set cur_msg_file_name and
new_msg_file_name.
* libproto/mh/mbox.c (_mh_cur_message_name)
(_mh_new_message_name): New functions.
(mh_scan0): Initialize orig_flags.
(_mailbox_mh_init): Set cur_msg_file_name and
new_msg_file_name.
* mailbox/amd.c (amd_message_qid, _amd_message_save)
(amd_append_message, amd_expunge, amd_scan_message)
(amd_pool_open, amd_header_fill): Use appropriate msg_file_name
functions.
(amd_get_size): Implemented.
* mailbox/mailbox.c (mu_mailbox_flush): Bugfix.
1 parent 5d286f5d
2008-01-06 Sergey Poznyakoff <gray@gnu.org.ua>
Fix message delivery to maildir boxes.
* libproto/include/amd.h (struct _amd_message): Remove `deleted',
add `orig_flags' instead.
(struct _amd_data): Remove `msg_file_name', add `cur_msg_file_name'
and `new_msg_file_name'.
Add `mailbox_size'.
* libproto/maildir/mbox.c (struct _maildir_message): Remove
`newflag', add `dir'.
(maildir_name_info_ptr): New function.
(mk_info_filename): Bugfix.
(maildir_cur_message_name, maildir_new_message_name): New
functions.
(maildir_msg_init): Set ->dir
(maildir_msg_finish_delivery): Handle error conditions.
(maildir_scan_dir): New argument `dirname'. Initialize orig_flags.
(maildir_qfetch): Initialize dir.
(_mailbox_maildir_init): Set cur_msg_file_name and
new_msg_file_name.
* libproto/mh/mbox.c (_mh_cur_message_name)
(_mh_new_message_name): New functions.
(mh_scan0): Initialize orig_flags.
(_mailbox_mh_init): Set cur_msg_file_name and
new_msg_file_name.
* mailbox/amd.c (amd_message_qid, _amd_message_save)
(amd_append_message, amd_expunge, amd_scan_message)
(amd_pool_open, amd_header_fill): Use appropriate msg_file_name
functions.
(amd_get_size): Implemented.
* mailbox/mailbox.c (mu_mailbox_flush): Bugfix.
2008-01-05 Sergey Poznyakoff <gray@gnu.org.ua>
* NEWS: Update.
......
......@@ -48,8 +48,9 @@ struct _amd_message
mu_off_t body_start; /* Offset of body start in the message file */
mu_off_t body_end; /* Offset of body end (size of file, effectively)*/
int attr_flags; /* Attribute flags */
int deleted; /* Was the message originally deleted */
int orig_flags; /* Original attribute flags */
int attr_flags; /* Current attribute flags */
time_t mtime; /* Time of last modification */
size_t header_lines; /* Number of lines in the header part */
......@@ -65,9 +66,11 @@ struct _amd_data
int (*msg_init_delivery) (struct _amd_data *, struct _amd_message *);
int (*msg_finish_delivery) (struct _amd_data *, struct _amd_message *);
void (*msg_free) (struct _amd_message *);
char *(*msg_file_name) (struct _amd_message *, int deleted);
int (*cur_msg_file_name) (struct _amd_message *, char **);
int (*new_msg_file_name) (struct _amd_message *, int attr_flags, char **);
int (*scan0) (mu_mailbox_t mailbox, size_t msgno, size_t *pcount,
int do_notify);
int (*mailbox_size) (mu_mailbox_t mailbox, mu_off_t *psize);
int (*qfetch) (struct _amd_data *, mu_message_qid_t qid);
int (*msg_cmp) (struct _amd_message *, struct _amd_message *);
int (*message_uid) (mu_message_t msg, size_t *puid);
......
......@@ -78,7 +78,7 @@
struct _maildir_message
{
struct _amd_message amd_message;
int newflag;
char *dir;
char *file_name;
unsigned long uid;
};
......@@ -123,6 +123,15 @@ info_to_flags (char *buf)
return 0;
}
static char *
maildir_name_info_ptr (char *name)
{
char *p = strchr (name, ':');
if (p && memcmp (p + 1, "2,", 2) == 0)
return p + 3;
return NULL;
}
static int
maildir_message_cmp (struct _amd_message *a, struct _amd_message *b)
......@@ -269,7 +278,7 @@ mk_info_filename (char *directory, char *suffix, char *name, int flags)
size += 3 + strlen (fbuf);
tmp = malloc (size);
if (fbuf[0])
if (!fbuf[0])
sprintf (tmp, "%s/%s/%*.*s:2", directory, suffix, namelen, namelen, name);
else
sprintf (tmp, "%s/%s/%*.*s:2,%s", directory, suffix, namelen, namelen, name, fbuf);
......@@ -324,16 +333,31 @@ maildir_uniq (struct _amd_data *amd, int fd)
return strdup (buffer);
}
char *
maildir_message_name (struct _amd_message *amsg, int deleted)
/* FIXME: The following two functions dump core on ENOMEM */
static int
maildir_cur_message_name (struct _amd_message *amsg, char **pname)
{
struct _maildir_message *msg = (struct _maildir_message *) amsg;
if (deleted)
return NULL; /* Force amd.c to unlink the file.
FIXME: We could also add a 'T' info to it. Should
we have an option deciding which approach to take? */
return maildir_mkfilename (amsg->amd->name,
msg->newflag ? NEWSUF : CURSUF, msg->file_name);
*pname = maildir_mkfilename (amsg->amd->name, msg->dir, msg->file_name);
return 0;
}
static int
maildir_new_message_name (struct _amd_message *amsg, int flags, char **pname)
{
struct _maildir_message *msg = (struct _maildir_message *) amsg;
if (flags & MU_ATTRIBUTE_DELETED)
{
/* Force amd.c to unlink the file.
FIXME: We could also add a 'T' info to it. Should
we have an option deciding which approach to take? */
*pname = NULL;
}
else if (strcmp (msg->dir, CURSUF) == 0)
*pname = mk_info_filename (amsg->amd->name, CURSUF, msg->file_name, flags);
else
*pname = maildir_mkfilename (amsg->amd->name, msg->dir, msg->file_name);
return 0;
}
static void
......@@ -415,6 +439,8 @@ maildir_msg_init (struct _amd_data *amd, struct _amd_message *amm)
name = maildir_uniq (amd, -1);
fname = maildir_mkfilename (amd->name, NEWSUF, name);
msg->dir = TMPSUF;
for (i = 0; i < NTRIES; i++)
{
......@@ -442,11 +468,13 @@ maildir_msg_finish_delivery (struct _amd_data *amd, struct _amd_message *amm)
char *newname = maildir_mkfilename (amd->name, NEWSUF, msg->file_name);
unlink (newname);
if (link (oldname, newname))
if (link (oldname, newname) == 0)
unlink (oldname);
else
{
unlink (oldname);
msg->newflag = 1;
return errno; /* FIXME? */
}
msg->dir = NEWSUF;
free (oldname);
free (newname);
return 0;
......@@ -535,16 +563,15 @@ maildir_message_lookup (struct _amd_data *amd, char *file_name)
}
static int
maildir_scan_dir (struct _amd_data *amd, DIR *dir)
maildir_scan_dir (struct _amd_data *amd, DIR *dir, char *dirname)
{
struct _maildir_message *msg;
struct dirent *entry;
struct _maildir_message *msg;
char *p;
int insert;
while ((entry = readdir (dir)))
{
char *p;
int insert;
switch (entry->d_name[0])
{
case '.':
......@@ -555,7 +582,6 @@ maildir_scan_dir (struct _amd_data *amd, DIR *dir)
if (msg)
{
free (msg->file_name);
msg->newflag = 0;
insert = 0;
}
else
......@@ -564,14 +590,15 @@ maildir_scan_dir (struct _amd_data *amd, DIR *dir)
insert = 1;
}
msg->dir = dirname;
msg->file_name = strdup (entry->d_name);
p = strchr (msg->file_name, ':');
if (p && strcmp (p+1, "2,") == 0)
msg->amd_message.attr_flags = info_to_flags (p+3);
p = maildir_name_info_ptr (msg->file_name);
if (p)
msg->amd_message.attr_flags = info_to_flags (p);
else
msg->amd_message.attr_flags = 0;
msg->amd_message.deleted = msg->amd_message.attr_flags & MU_ATTRIBUTE_DELETED;
msg->amd_message.orig_flags = msg->amd_message.attr_flags;
if (insert)
{
msg->uid = amd->next_uid (amd);
......@@ -595,7 +622,8 @@ maildir_scan0 (mu_mailbox_t mailbox, size_t msgno MU_ARG_UNUSED,
if (amd == NULL)
return EINVAL;
if (mailbox->flags & MU_STREAM_APPEND)
return 0;
mu_monitor_wrlock (mailbox->monitor);
/* 1st phase: Flush tmp/ */
......@@ -617,7 +645,7 @@ maildir_scan0 (mu_mailbox_t mailbox, size_t msgno MU_ARG_UNUSED,
status = maildir_opendir (&dir, name, PERMS);
if (status == 0)
{
status = maildir_scan_dir (amd, dir);
status = maildir_scan_dir (amd, dir, CURSUF);
closedir (dir);
}
free (name);
......@@ -666,19 +694,32 @@ maildir_qfetch (struct _amd_data *amd, mu_message_qid_t qid)
struct _maildir_message *msg;
char *name = strrchr (qid, '/');
char *p;
char *dir;
if (!name)
return EINVAL;
name++;
if (name - qid < 4)
return EINVAL;
else if (memcmp (name - 4, CURSUF, sizeof (CURSUF) - 1) == 0)
dir = CURSUF;
else if (memcmp (name - 4, NEWSUF, sizeof (NEWSUF) - 1) == 0)
dir = NEWSUF;
else if (memcmp (name - 4, TMPSUF, sizeof (TMPSUF) - 1) == 0)
dir = TMPSUF;
else
return EINVAL;
msg = calloc (1, sizeof(*msg));
msg->file_name = strdup (name);
p = strchr (msg->file_name, ':');
if (p && strcmp (p + 1, "2,") == 0)
msg->amd_message.attr_flags = info_to_flags (p + 3);
msg->dir = dir;
p = maildir_name_info_ptr (msg->file_name);
if (p)
msg->amd_message.attr_flags = info_to_flags (p);
else
msg->amd_message.attr_flags = 0;
msg->amd_message.deleted = msg->amd_message.attr_flags & MU_ATTRIBUTE_DELETED;
msg->amd_message.orig_flags = msg->amd_message.attr_flags;
msg->uid = amd->next_uid (amd);
_amd_message_insert (amd, (struct _amd_message*) msg);
return 0;
......@@ -699,7 +740,8 @@ _mailbox_maildir_init (mu_mailbox_t mailbox)
amd->msg_free = maildir_msg_free;
amd->msg_init_delivery = maildir_msg_init;
amd->msg_finish_delivery = maildir_msg_finish_delivery;
amd->msg_file_name = maildir_message_name;
amd->cur_msg_file_name = maildir_cur_message_name;
amd->new_msg_file_name = maildir_new_message_name;
amd->scan0 = maildir_scan0;
amd->qfetch = maildir_qfetch;
amd->msg_cmp = maildir_message_cmp;
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2002, 2003,
2004, 2005, 2007 Free Software Foundation, Inc.
2004, 2005, 2007, 2008 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
......@@ -66,6 +66,7 @@
#include <mailbox0.h>
#include <registrar0.h>
#include <amd.h>
#include <mu_umaxtostr.h>
struct _mh_message
{
......@@ -93,22 +94,55 @@ _mh_next_seq (struct _amd_data *amd)
return (msg ? msg->seq_number : 0) + 1;
}
/* Return filename for the message.
/* Return current filename for the message.
NOTE: Allocates memory. */
static char *
_mh_message_name (struct _amd_message *amsg, int deleted)
static int
_mh_cur_message_name (struct _amd_message *amsg, char **pname)
{
int status = 0;
struct _mh_message *mhm = (struct _mh_message *) amsg;
char *filename;
char buf[UINTMAX_STRSIZE_BOUND];
char *pnum = umaxtostr (mhm->seq_number, buf);
size_t len = strlen (amsg->amd->name) + 1 + strlen (pnum) + 1;
filename = malloc (len);
if (filename)
{
strcpy (filename, amsg->amd->name);
strcat (filename, "/");
strcat (filename, pnum);
*pname = filename;
}
else
status = ENOMEM;
return status;
}
/* Return newfilename for the message.
NOTE: Allocates memory. */
static int
_mh_new_message_name (struct _amd_message *amsg, int flags, char **pname)
{
int status = 0;
struct _mh_message *mhm = (struct _mh_message *) amsg;
char *filename;
size_t len = strlen (amsg->amd->name) + 32;
char buf[UINTMAX_STRSIZE_BOUND];
char *pnum = umaxtostr (mhm->seq_number, buf);
size_t len = strlen (amsg->amd->name) + 1 +
((flags & MU_ATTRIBUTE_DELETED) ? 1 : 0) + strlen (pnum) + 1;
filename = malloc (len);
if (deleted)
snprintf (filename, len, "%s/,%lu", amsg->amd->name,
(unsigned long) mhm->seq_number);
if (filename)
{
strcpy (filename, amsg->amd->name);
strcat (filename, "/");
if (flags & MU_ATTRIBUTE_DELETED)
strcat (filename, ",");
strcat (filename, pnum);
*pname = filename;
}
else
snprintf (filename, len, "%s/%lu", amsg->amd->name,
(unsigned long) mhm->seq_number);
return filename;
status = ENOMEM;
return status;
}
/* Find the message with the given sequence number */
......@@ -193,13 +227,14 @@ mh_scan0 (mu_mailbox_t mailbox, size_t msgno MU_ARG_UNUSED, size_t *pcount,
msg->seq_number = num;
msg->amd_message.attr_flags = attr_flags;
msg->amd_message.deleted = attr_flags & MU_ATTRIBUTE_DELETED;
msg->amd_message.orig_flags = msg->amd_message.attr_flags;
_amd_message_insert (amd, (struct _amd_message*) msg);
}
else
{
msg->amd_message.attr_flags = attr_flags;
msg->amd_message.orig_flags = msg->amd_message.attr_flags;
}
}
......@@ -278,7 +313,7 @@ mh_qfetch (struct _amd_data *amd, mu_message_qid_t qid)
msg = calloc (1, sizeof (*msg));
msg->seq_number = num;
msg->amd_message.attr_flags = attr_flags;
msg->amd_message.deleted = attr_flags & MU_ATTRIBUTE_DELETED;
msg->amd_message.orig_flags = msg->amd_message.attr_flags;
_amd_message_insert (amd, (struct _amd_message*) msg);
return 0;
}
......@@ -321,7 +356,8 @@ _mailbox_mh_init (mu_mailbox_t mailbox)
amd->msg_free = NULL;
amd->msg_init_delivery = _mh_msg_init;
amd->msg_finish_delivery = NULL;
amd->msg_file_name = _mh_message_name;
amd->cur_msg_file_name = _mh_cur_message_name;
amd->new_msg_file_name = _mh_new_message_name;
amd->scan0 = mh_scan0;
amd->qfetch = mh_qfetch;
amd->msg_cmp = mh_message_cmp;
......
......@@ -389,9 +389,7 @@ amd_message_qid (mu_message_t msg, mu_message_qid_t *pqid)
{
struct _amd_message *mhm = mu_message_get_owner (msg);
*pqid = mhm->amd->msg_file_name (mhm,
mhm->attr_flags & MU_ATTRIBUTE_DELETED);
return 0;
return mhm->amd->cur_msg_file_name (mhm, pqid);
}
struct _amd_message *
......@@ -644,7 +642,8 @@ _amd_message_save (struct _amd_data *amd, struct _amd_message *mhm,
}
/* Add imapbase */
if (amd->next_uid
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",
......@@ -712,14 +711,29 @@ _amd_message_save (struct _amd_data *amd, struct _amd_message *mhm,
free (buf);
fclose (fp);
/* FIXME: This does not work for maildir. */
msg_name = amd->msg_file_name (mhm, mhm->deleted);
if (rename (name, msg_name))
status = errno;
status = amd->new_msg_file_name (mhm, mhm->attr_flags, &msg_name);
if (status == 0)
{
char *old_name;
status = amd->cur_msg_file_name (mhm, &old_name);
if (status == 0)
{
if (rename (name, msg_name))
status = errno;
else
{
if (strcmp (old_name, msg_name))
/* Unlink original message */
unlink (old_name);
}
free (old_name);
mhm->orig_flags = mhm->attr_flags;
}
free (msg_name);
}
free (name);
free (msg_name);
return 0;
return status;
}
static int
......@@ -772,14 +786,17 @@ amd_append_message (mu_mailbox_t mailbox, mu_message_t msg)
}
if (amd->msg_finish_delivery)
amd->msg_finish_delivery (amd, mhm);
status = amd->msg_finish_delivery (amd, mhm);
if (mailbox->observable)
if (status == 0 && mailbox->observable)
{
char *qid = amd->msg_file_name (mhm,
mhm->attr_flags & MU_ATTRIBUTE_DELETED);
mu_observable_notify (mailbox->observable, MU_EVT_MESSAGE_APPEND, qid);
free (qid);
char *qid;
if (amd->cur_msg_file_name (mhm, &qid) == 0)
{
mu_observable_notify (mailbox->observable, MU_EVT_MESSAGE_APPEND,
qid);
free (qid);
}
}
return status;
......@@ -883,10 +900,22 @@ amd_expunge (mu_mailbox_t mailbox)
if (mhm->attr_flags & MU_ATTRIBUTE_DELETED)
{
if (!mhm->deleted)
if (!(mhm->orig_flags & MU_ATTRIBUTE_DELETED))
{
char *old_name = amd->msg_file_name (mhm, 0);
char *new_name = amd->msg_file_name (mhm, 1);
int rc;
char *old_name;
char *new_name;
rc = amd->cur_msg_file_name (mhm, &old_name);
if (rc)
return rc;
rc = amd->new_msg_file_name (mhm, mhm->attr_flags, &new_name);
if (rc)
{
free (old_name);
return rc;
}
if (new_name)
{
/* Rename original message */
......@@ -907,7 +936,6 @@ amd_expunge (mu_mailbox_t mailbox)
|| (mhm->message && mu_message_is_modified (mhm->message)))
{
_amd_attach_message (mailbox, mhm, NULL);
mhm->deleted = mhm->attr_flags & MU_ATTRIBUTE_DELETED;
_amd_message_save (amd, mhm, 1);
}
i++; /* Move to the next message */
......@@ -947,7 +975,6 @@ amd_sync (mu_mailbox_t mailbox)
|| (mhm->message && mu_message_is_modified (mhm->message)))
{
_amd_attach_message (mailbox, mhm, NULL);
mhm->deleted = mhm->attr_flags & MU_ATTRIBUTE_DELETED;
_amd_message_save (amd, mhm, 0);
}
}
......@@ -1074,7 +1101,11 @@ amd_scan_message (struct _amd_message *mhm)
if (mhm->mtime)
{
struct stat st;
char *msg_name = mhm->amd->msg_file_name (mhm, mhm->deleted);
char *msg_name;
status = mhm->amd->cur_msg_file_name (mhm, &msg_name);
if (status)
return status;
if (stat (msg_name, &st) == 0 && st.st_mtime == mhm->mtime)
{
......@@ -1158,10 +1189,80 @@ amd_is_updated (mu_mailbox_t mailbox)
}
static int
amd_get_size (mu_mailbox_t mailbox MU_ARG_UNUSED, mu_off_t *psize MU_ARG_UNUSED)
compute_mailbox_size (const char *name, mu_off_t *psize)
{
/*FIXME*/
return ENOSYS;
DIR *dir;
struct dirent *entry;
char *buf;
size_t bufsize;
size_t dirlen;
size_t flen;
int status = 0;
struct stat sb;
dir = opendir (name);
if (!dir)
return errno;
dirlen = strlen (name);
bufsize = dirlen + 32;
buf = malloc (bufsize);
if (!buf)
{
closedir (dir);
return ENOMEM;
}
strcpy (buf, name);
if (buf[dirlen-1] != '/')
buf[++dirlen - 1] = '/';
while ((entry = readdir (dir)))
{
switch (entry->d_name[0])
{
case '.':
break;
default:
flen = strlen (entry->d_name);
if (dirlen + flen + 1 > bufsize)
{
bufsize = dirlen + flen + 1;
buf = realloc (buf, bufsize);
if (!buf)
{
status = ENOMEM;
break;
}
}
strcpy (buf + dirlen, entry->d_name);
if (stat (buf, &sb) == 0)
{
if (S_ISREG (sb.st_mode))
*psize += sb.st_size;
else if (S_ISDIR (sb.st_mode))
compute_mailbox_size (buf, psize);
}
/* FIXME: else? */
break;
}
}
free (buf);
closedir (dir);
return 0;
}
static int
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;
return compute_mailbox_size (amd->name, psize);
}
/* Return number of open streams residing in a message pool */
......@@ -1202,6 +1303,7 @@ amd_pool_lookup (struct _amd_message *mhm)
static int
amd_pool_open (struct _amd_message *mhm)
{
int status;
struct _amd_data *amd = mhm->amd;
if (amd_pool_lookup (mhm))
return 0;
......@@ -1210,7 +1312,9 @@ amd_pool_open (struct _amd_message *mhm)
amd_message_stream_close (amd->msg_pool[amd->pool_first++]);
amd->pool_first %= MAX_OPEN_STREAMS;
}
amd_message_stream_open (mhm);
status = amd_message_stream_open (mhm);
if (status)
return status;
amd->msg_pool[amd->pool_last++] = mhm;
amd->pool_last %= MAX_OPEN_STREAMS;
return 0;
......@@ -1237,12 +1341,13 @@ int
amd_message_stream_open (struct _amd_message *mhm)
{
struct _amd_data *amd = mhm->amd;
char *filename = amd->msg_file_name (mhm, mhm->deleted);
char *filename;
int status;
int flags = MU_STREAM_ALLOW_LINKS;
if (!filename)
return ENOMEM;
status = amd->cur_msg_file_name (mhm, &filename);
if (status)
return status;
/* The message should be at least readable */
if (amd->mailbox->flags & (MU_STREAM_RDWR|MU_STREAM_WRITE|MU_STREAM_APPEND))
......@@ -1399,8 +1504,9 @@ amd_header_fill (mu_header_t header, char *buffer, size_t len,
{
mu_message_t msg = mu_header_get_owner (header);
struct _amd_message *mhm = mu_message_get_owner (msg);
amd_pool_open (mhm);
int status = amd_pool_open (mhm);
if (status)
return status;
return amd_readstream (mhm, buffer, len, off, pnread, 0,
0, mhm->body_start);
}
......
......@@ -325,18 +325,15 @@ mu_mailbox_flush (mu_mailbox_t mbox, int expunge)
return 0;
mu_mailbox_messages_count (mbox, &total);
if (mbox->flags & MU_STREAM_APPEND)
i = total;
else
i = 1;
for ( ; i <= total; i++)
{
mu_message_t msg = NULL;
mu_attribute_t attr = NULL;
mu_mailbox_get_message (mbox, i, &msg);
mu_message_get_attribute (msg, &attr);
mu_attribute_set_seen (attr);
}
if (!(mbox->flags & MU_STREAM_APPEND))
for (i = 1; i <= total; i++)
{
mu_message_t msg = NULL;
mu_attribute_t attr = NULL;
mu_mailbox_get_message (mbox, i, &msg);
mu_message_get_attribute (msg, &attr);
mu_attribute_set_seen (attr);
}
if (expunge)
status = mu_mailbox_expunge (mbox);
......