Commit fa3be4ba fa3be4baf0edf9c9df06ca272a19fae88c71d88b by Sergey Poznyakoff

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.
1 parent f697923a
......@@ -53,6 +53,11 @@ extern void mu_message_destroy (mu_message_t *, void *owner);
extern int mu_message_create_copy (mu_message_t *to, mu_message_t from);
extern void *mu_message_get_owner (mu_message_t);
#define MU_MSG_ATTRIBUTE_MODIFIED 0x01
#define MU_MSG_HEADER_MODIFIED 0x02
#define MU_MSG_BODY_MODIFIED 0x04
extern int mu_message_is_modified (mu_message_t);
extern int mu_message_clear_modified (mu_message_t);
extern int mu_message_get_mailbox (mu_message_t, mu_mailbox_t *);
......
......@@ -43,7 +43,13 @@
mu_monitor_wrlock (mbox->monitor); \
} while (0);
# define MU_AMD_SIZE_FILE_NAME ".mu-size"
#define _MU_AMD_PROP_UIDVALIDITY "uid-validity"
#define _MU_AMD_PROP_NEXT_UID "next-uid"
#define _MU_AMD_PROP_SIZE "size"
#define _MU_AMD_PROP_FILE_NAME ".mu-prop"
/* Legacy (2.x) size file name */
#define _MU_AMD_SIZE_FILE_NAME ".mu-size"
struct _amd_data;
struct _amd_message
......@@ -64,6 +70,10 @@ struct _amd_message
struct _amd_data *amd; /* Back pointer. */
};
/* AMD capabilities */
#define MU_AMD_STATUS 0x01 /* format keeps status flags */
#define MU_AMD_IMAPBASE 0x02 /* format keeps IMAP base */
struct _amd_data
{
size_t msg_size; /* Size of struct _amd_message */
......@@ -83,16 +93,19 @@ struct _amd_data
size_t (*next_uid) (struct _amd_data *mhd);
int (*remove) (struct _amd_data *);
int (*delete_msg) (struct _amd_data *, struct _amd_message *);
int (*chattr_msg) (struct _amd_message *, int);
/* List of messages: */
size_t msg_count; /* number of messages in the list */
size_t msg_max; /* maximum message buffer capacity */
struct _amd_message **msg_array;
unsigned long uidvalidity;
int capabilities;
int has_new_msg; /* New messages have been appended */
char *name; /* Directory name */
mu_property_t prop; /* Properties: uidvalidity, nextuid, etc. */
/* Pool of open message streams */
struct _amd_message *msg_pool[MAX_OPEN_STREAMS];
int pool_first; /* Index to the first used entry in msg_pool */
......
......@@ -667,10 +667,14 @@ mu_message_is_modified (mu_message_t msg)
int mod = 0;
if (msg)
{
mod |= mu_header_is_modified (msg->header);
mod |= mu_attribute_is_modified (msg->attribute);
mod |= mu_body_is_modified (msg->body);
mod |= msg->flags;
if (mu_header_is_modified (msg->header))
mod |= MU_MSG_HEADER_MODIFIED;
if (mu_attribute_is_modified (msg->attribute))
mod |= MU_MSG_ATTRIBUTE_MODIFIED;
if (mu_body_is_modified (msg->body))
mod |= MU_MSG_BODY_MODIFIED;
if (msg->flags & MESSAGE_MODIFIED)
mod |= MU_MSG_BODY_MODIFIED | MU_MSG_HEADER_MODIFIED;
}
return mod;
}
......
......@@ -45,7 +45,7 @@ mu_property_create_init (mu_property_t *pprop,
mu_property_set_init (prop, initfun, initdata);
*pprop = prop;
}
return 0;
return rc;
}
int
......
......@@ -92,7 +92,8 @@ _maildir_list_p (mu_record_t record, const char *name, int flags MU_ARG_UNUSED)
return strcmp (name, TMPSUF)
&& strcmp (name, CURSUF)
&& strcmp (name, NEWSUF)
&& strcmp (name, MU_AMD_SIZE_FILE_NAME);
&& !((strlen (name) > 3) &&
(memcmp (name, ".mh", 3) == 0 || memcmp (name, ".mu", 3) == 0));
}
static struct _mu_record _maildir_record =
......
......@@ -84,19 +84,24 @@ struct _maildir_message
/* Attribute handling.
FIXME: P (Passed), D (Draft) and F (Flagged) are not handled */
FIXME: P (Passed) is not handled */
static struct info_map {
char letter;
int flag;
} info_map[] = {
{ 'D', MU_ATTRIBUTE_DRAFT },
{ 'F', MU_ATTRIBUTE_FLAGGED },
{ 'P', 0 }, /* (passed): the user has resent/forwarded/bounced this
message to someone else. */
{ 'R', MU_ATTRIBUTE_READ },
{ 'S', MU_ATTRIBUTE_SEEN },
{ 'T', MU_ATTRIBUTE_DELETED },
{ 'a', MU_ATTRIBUTE_ANSWERED },
};
#define info_map_size (sizeof (info_map) / sizeof (info_map[0]))
/* NOTE: BUF must be at least 7 bytes long */
/* NOTE: BUF must be at least info_map_size bytes long */
static int
flags_to_info (int flags, char *buf)
{
......@@ -254,7 +259,7 @@ maildir_mkfilename (const char *directory, const char *suffix, const char *name)
static char *
mk_info_filename (char *directory, char *suffix, char *name, int flags)
{
char fbuf[9];
char fbuf[info_map_size + 1];
char *tmp;
int namelen;
size_t size;
......@@ -691,23 +696,6 @@ maildir_scan0 (mu_mailbox_t mailbox, size_t msgno MU_ARG_UNUSED,
if (pcount)
*pcount = amd->msg_count;
/* Reset the uidvalidity. */
if (amd->msg_count > 0)
{
if (amd->uidvalidity == 0)
{
amd->uidvalidity = (unsigned long) time (NULL);
/* FIXME amd->uidnext = amd->msg_count + 1;*/
/* Tell that we have been modified for expunging. */
if (amd->msg_count)
{
amd_message_stream_open (amd->msg_array[0]);
amd_message_stream_close (amd->msg_array[0]);
amd->msg_array[0]->attr_flags |= MU_ATTRIBUTE_MODIFIED;
}
}
}
/* Clean up the things */
amd_cleanup (mailbox);
return status;
......@@ -773,6 +761,42 @@ maildir_remove (struct _amd_data *amd)
return rc;
}
static int
maildir_chattr_msg (struct _amd_message *amsg, int expunge)
{
struct _maildir_message *mp = (struct _maildir_message *) amsg;
struct _amd_data *amd = amsg->amd;
int rc;
char *new_name;
rc = amd->new_msg_file_name (amsg, amsg->attr_flags, expunge, &new_name);
if (rc)
return rc;
if (!new_name)
{
if (unlink (mp->file_name))
rc = errno;
}
else
{
char *cur_name;
rc = maildir_cur_message_name (amsg, &cur_name);
if (rc)
{
free (new_name);
return rc;
}
if (rename (cur_name, new_name))
rc = errno;
free (cur_name);
}
free (new_name);
return rc;
}
int
_mailbox_maildir_init (mu_mailbox_t mailbox)
......@@ -797,6 +821,8 @@ _mailbox_maildir_init (mu_mailbox_t mailbox)
amd->message_uid = maildir_message_uid;
amd->next_uid = maildir_next_uid;
amd->remove = maildir_remove;
amd->chattr_msg = maildir_chattr_msg;
amd->capabilities = MU_AMD_STATUS;
/* Set our properties. */
{
......
......@@ -121,11 +121,9 @@ _mh_is_scheme (mu_record_t record, mu_url_t url, int flags)
static int
_mh_list_p (mu_record_t record, const char *name, int flags MU_ARG_UNUSED)
{
int len;
if (strcmp (name, MU_AMD_SIZE_FILE_NAME) == 0
|| name[0] == ','
|| (((len = strlen (name)) > 3) && memcmp (name, ".mh", 3) == 0))
if (name[0] == ',' ||
((strlen (name) > 3) &&
(memcmp (name, ".mh", 3) == 0 || memcmp (name, ".mu", 3) == 0)))
return 0;
for (; *name; name++)
......
......@@ -278,22 +278,6 @@ mh_scan0 (mu_mailbox_t mailbox, size_t msgno MU_ARG_UNUSED, size_t *pcount,
if (pcount)
*pcount = amd->msg_count;
/* Reset the uidvalidity. */
if (amd->msg_count > 0)
{
if (amd->uidvalidity == 0)
{
amd->uidvalidity = (unsigned long)time (NULL);
/* Tell that we have been modified for expunging. */
if (amd->msg_count)
{
amd_message_stream_open (amd->msg_array[0]);
amd_message_stream_close (amd->msg_array[0]);
amd->msg_array[0]->attr_flags |= MU_ATTRIBUTE_MODIFIED;
}
}
}
}
/* Clean up the things */
......
......@@ -87,7 +87,7 @@ do
mv Mail/inbox/$i Mail/inbox/${i}0
done
folder -pack || exit $?
find Mail/inbox | sort
find Mail/inbox -not -name '.mu-prop' | sort
],
[0],
[Mail/inbox
......@@ -105,7 +105,7 @@ do
mv Mail/inbox/$i Mail/inbox/${i}0
done
folder --pack=1 || exit $?
find Mail/inbox | sort
find Mail/inbox -not -name '.mu-prop' | sort
],
[0],
[Mail/inbox
......