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); ...@@ -53,6 +53,11 @@ extern void mu_message_destroy (mu_message_t *, void *owner);
53 extern int mu_message_create_copy (mu_message_t *to, mu_message_t from); 53 extern int mu_message_create_copy (mu_message_t *to, mu_message_t from);
54 54
55 extern void *mu_message_get_owner (mu_message_t); 55 extern void *mu_message_get_owner (mu_message_t);
56
57 #define MU_MSG_ATTRIBUTE_MODIFIED 0x01
58 #define MU_MSG_HEADER_MODIFIED 0x02
59 #define MU_MSG_BODY_MODIFIED 0x04
60
56 extern int mu_message_is_modified (mu_message_t); 61 extern int mu_message_is_modified (mu_message_t);
57 extern int mu_message_clear_modified (mu_message_t); 62 extern int mu_message_clear_modified (mu_message_t);
58 extern int mu_message_get_mailbox (mu_message_t, mu_mailbox_t *); 63 extern int mu_message_get_mailbox (mu_message_t, mu_mailbox_t *);
......
...@@ -43,7 +43,13 @@ ...@@ -43,7 +43,13 @@
43 mu_monitor_wrlock (mbox->monitor); \ 43 mu_monitor_wrlock (mbox->monitor); \
44 } while (0); 44 } while (0);
45 45
46 # define MU_AMD_SIZE_FILE_NAME ".mu-size" 46 #define _MU_AMD_PROP_UIDVALIDITY "uid-validity"
47 #define _MU_AMD_PROP_NEXT_UID "next-uid"
48 #define _MU_AMD_PROP_SIZE "size"
49
50 #define _MU_AMD_PROP_FILE_NAME ".mu-prop"
51 /* Legacy (2.x) size file name */
52 #define _MU_AMD_SIZE_FILE_NAME ".mu-size"
47 53
48 struct _amd_data; 54 struct _amd_data;
49 struct _amd_message 55 struct _amd_message
...@@ -64,6 +70,10 @@ struct _amd_message ...@@ -64,6 +70,10 @@ struct _amd_message
64 struct _amd_data *amd; /* Back pointer. */ 70 struct _amd_data *amd; /* Back pointer. */
65 }; 71 };
66 72
73 /* AMD capabilities */
74 #define MU_AMD_STATUS 0x01 /* format keeps status flags */
75 #define MU_AMD_IMAPBASE 0x02 /* format keeps IMAP base */
76
67 struct _amd_data 77 struct _amd_data
68 { 78 {
69 size_t msg_size; /* Size of struct _amd_message */ 79 size_t msg_size; /* Size of struct _amd_message */
...@@ -83,16 +93,19 @@ struct _amd_data ...@@ -83,16 +93,19 @@ struct _amd_data
83 size_t (*next_uid) (struct _amd_data *mhd); 93 size_t (*next_uid) (struct _amd_data *mhd);
84 int (*remove) (struct _amd_data *); 94 int (*remove) (struct _amd_data *);
85 int (*delete_msg) (struct _amd_data *, struct _amd_message *); 95 int (*delete_msg) (struct _amd_data *, struct _amd_message *);
96 int (*chattr_msg) (struct _amd_message *, int);
86 97
87 /* List of messages: */ 98 /* List of messages: */
88 size_t msg_count; /* number of messages in the list */ 99 size_t msg_count; /* number of messages in the list */
89 size_t msg_max; /* maximum message buffer capacity */ 100 size_t msg_max; /* maximum message buffer capacity */
90 struct _amd_message **msg_array; 101 struct _amd_message **msg_array;
91 102
92 unsigned long uidvalidity; 103 int capabilities;
93 int has_new_msg; /* New messages have been appended */ 104 int has_new_msg; /* New messages have been appended */
94 char *name; /* Directory name */ 105 char *name; /* Directory name */
95 106
107 mu_property_t prop; /* Properties: uidvalidity, nextuid, etc. */
108
96 /* Pool of open message streams */ 109 /* Pool of open message streams */
97 struct _amd_message *msg_pool[MAX_OPEN_STREAMS]; 110 struct _amd_message *msg_pool[MAX_OPEN_STREAMS];
98 int pool_first; /* Index to the first used entry in msg_pool */ 111 int pool_first; /* Index to the first used entry in msg_pool */
......
...@@ -667,10 +667,14 @@ mu_message_is_modified (mu_message_t msg) ...@@ -667,10 +667,14 @@ mu_message_is_modified (mu_message_t msg)
667 int mod = 0; 667 int mod = 0;
668 if (msg) 668 if (msg)
669 { 669 {
670 mod |= mu_header_is_modified (msg->header); 670 if (mu_header_is_modified (msg->header))
671 mod |= mu_attribute_is_modified (msg->attribute); 671 mod |= MU_MSG_HEADER_MODIFIED;
672 mod |= mu_body_is_modified (msg->body); 672 if (mu_attribute_is_modified (msg->attribute))
673 mod |= msg->flags; 673 mod |= MU_MSG_ATTRIBUTE_MODIFIED;
674 if (mu_body_is_modified (msg->body))
675 mod |= MU_MSG_BODY_MODIFIED;
676 if (msg->flags & MESSAGE_MODIFIED)
677 mod |= MU_MSG_BODY_MODIFIED | MU_MSG_HEADER_MODIFIED;
674 } 678 }
675 return mod; 679 return mod;
676 } 680 }
......
...@@ -45,7 +45,7 @@ mu_property_create_init (mu_property_t *pprop, ...@@ -45,7 +45,7 @@ mu_property_create_init (mu_property_t *pprop,
45 mu_property_set_init (prop, initfun, initdata); 45 mu_property_set_init (prop, initfun, initdata);
46 *pprop = prop; 46 *pprop = prop;
47 } 47 }
48 return 0; 48 return rc;
49 } 49 }
50 50
51 int 51 int
......
...@@ -92,7 +92,8 @@ _maildir_list_p (mu_record_t record, const char *name, int flags MU_ARG_UNUSED) ...@@ -92,7 +92,8 @@ _maildir_list_p (mu_record_t record, const char *name, int flags MU_ARG_UNUSED)
92 return strcmp (name, TMPSUF) 92 return strcmp (name, TMPSUF)
93 && strcmp (name, CURSUF) 93 && strcmp (name, CURSUF)
94 && strcmp (name, NEWSUF) 94 && strcmp (name, NEWSUF)
95 && strcmp (name, MU_AMD_SIZE_FILE_NAME); 95 && !((strlen (name) > 3) &&
96 (memcmp (name, ".mh", 3) == 0 || memcmp (name, ".mu", 3) == 0));
96 } 97 }
97 98
98 static struct _mu_record _maildir_record = 99 static struct _mu_record _maildir_record =
......
...@@ -84,19 +84,24 @@ struct _maildir_message ...@@ -84,19 +84,24 @@ struct _maildir_message
84 84
85 85
86 /* Attribute handling. 86 /* Attribute handling.
87 FIXME: P (Passed), D (Draft) and F (Flagged) are not handled */ 87 FIXME: P (Passed) is not handled */
88 88
89 static struct info_map { 89 static struct info_map {
90 char letter; 90 char letter;
91 int flag; 91 int flag;
92 } info_map[] = { 92 } info_map[] = {
93 { 'D', MU_ATTRIBUTE_DRAFT },
94 { 'F', MU_ATTRIBUTE_FLAGGED },
95 { 'P', 0 }, /* (passed): the user has resent/forwarded/bounced this
96 message to someone else. */
93 { 'R', MU_ATTRIBUTE_READ }, 97 { 'R', MU_ATTRIBUTE_READ },
94 { 'S', MU_ATTRIBUTE_SEEN }, 98 { 'S', MU_ATTRIBUTE_SEEN },
95 { 'T', MU_ATTRIBUTE_DELETED }, 99 { 'T', MU_ATTRIBUTE_DELETED },
100 { 'a', MU_ATTRIBUTE_ANSWERED },
96 }; 101 };
97 #define info_map_size (sizeof (info_map) / sizeof (info_map[0])) 102 #define info_map_size (sizeof (info_map) / sizeof (info_map[0]))
98 103
99 /* NOTE: BUF must be at least 7 bytes long */ 104 /* NOTE: BUF must be at least info_map_size bytes long */
100 static int 105 static int
101 flags_to_info (int flags, char *buf) 106 flags_to_info (int flags, char *buf)
102 { 107 {
...@@ -254,7 +259,7 @@ maildir_mkfilename (const char *directory, const char *suffix, const char *name) ...@@ -254,7 +259,7 @@ maildir_mkfilename (const char *directory, const char *suffix, const char *name)
254 static char * 259 static char *
255 mk_info_filename (char *directory, char *suffix, char *name, int flags) 260 mk_info_filename (char *directory, char *suffix, char *name, int flags)
256 { 261 {
257 char fbuf[9]; 262 char fbuf[info_map_size + 1];
258 char *tmp; 263 char *tmp;
259 int namelen; 264 int namelen;
260 size_t size; 265 size_t size;
...@@ -691,23 +696,6 @@ maildir_scan0 (mu_mailbox_t mailbox, size_t msgno MU_ARG_UNUSED, ...@@ -691,23 +696,6 @@ maildir_scan0 (mu_mailbox_t mailbox, size_t msgno MU_ARG_UNUSED,
691 if (pcount) 696 if (pcount)
692 *pcount = amd->msg_count; 697 *pcount = amd->msg_count;
693 698
694 /* Reset the uidvalidity. */
695 if (amd->msg_count > 0)
696 {
697 if (amd->uidvalidity == 0)
698 {
699 amd->uidvalidity = (unsigned long) time (NULL);
700 /* FIXME amd->uidnext = amd->msg_count + 1;*/
701 /* Tell that we have been modified for expunging. */
702 if (amd->msg_count)
703 {
704 amd_message_stream_open (amd->msg_array[0]);
705 amd_message_stream_close (amd->msg_array[0]);
706 amd->msg_array[0]->attr_flags |= MU_ATTRIBUTE_MODIFIED;
707 }
708 }
709 }
710
711 /* Clean up the things */ 699 /* Clean up the things */
712 amd_cleanup (mailbox); 700 amd_cleanup (mailbox);
713 return status; 701 return status;
...@@ -774,6 +762,42 @@ maildir_remove (struct _amd_data *amd) ...@@ -774,6 +762,42 @@ maildir_remove (struct _amd_data *amd)
774 } 762 }
775 763
776 764
765 static int
766 maildir_chattr_msg (struct _amd_message *amsg, int expunge)
767 {
768 struct _maildir_message *mp = (struct _maildir_message *) amsg;
769 struct _amd_data *amd = amsg->amd;
770 int rc;
771 char *new_name;
772
773 rc = amd->new_msg_file_name (amsg, amsg->attr_flags, expunge, &new_name);
774 if (rc)
775 return rc;
776 if (!new_name)
777 {
778 if (unlink (mp->file_name))
779 rc = errno;
780 }
781 else
782 {
783 char *cur_name;
784
785 rc = maildir_cur_message_name (amsg, &cur_name);
786 if (rc)
787 {
788 free (new_name);
789 return rc;
790 }
791 if (rename (cur_name, new_name))
792 rc = errno;
793 free (cur_name);
794 }
795
796 free (new_name);
797 return rc;
798 }
799
800
777 int 801 int
778 _mailbox_maildir_init (mu_mailbox_t mailbox) 802 _mailbox_maildir_init (mu_mailbox_t mailbox)
779 { 803 {
...@@ -797,6 +821,8 @@ _mailbox_maildir_init (mu_mailbox_t mailbox) ...@@ -797,6 +821,8 @@ _mailbox_maildir_init (mu_mailbox_t mailbox)
797 amd->message_uid = maildir_message_uid; 821 amd->message_uid = maildir_message_uid;
798 amd->next_uid = maildir_next_uid; 822 amd->next_uid = maildir_next_uid;
799 amd->remove = maildir_remove; 823 amd->remove = maildir_remove;
824 amd->chattr_msg = maildir_chattr_msg;
825 amd->capabilities = MU_AMD_STATUS;
800 826
801 /* Set our properties. */ 827 /* Set our properties. */
802 { 828 {
......
...@@ -121,11 +121,9 @@ _mh_is_scheme (mu_record_t record, mu_url_t url, int flags) ...@@ -121,11 +121,9 @@ _mh_is_scheme (mu_record_t record, mu_url_t url, int flags)
121 static int 121 static int
122 _mh_list_p (mu_record_t record, const char *name, int flags MU_ARG_UNUSED) 122 _mh_list_p (mu_record_t record, const char *name, int flags MU_ARG_UNUSED)
123 { 123 {
124 int len; 124 if (name[0] == ',' ||
125 125 ((strlen (name) > 3) &&
126 if (strcmp (name, MU_AMD_SIZE_FILE_NAME) == 0 126 (memcmp (name, ".mh", 3) == 0 || memcmp (name, ".mu", 3) == 0)))
127 || name[0] == ','
128 || (((len = strlen (name)) > 3) && memcmp (name, ".mh", 3) == 0))
129 return 0; 127 return 0;
130 128
131 for (; *name; name++) 129 for (; *name; name++)
......
...@@ -278,22 +278,6 @@ mh_scan0 (mu_mailbox_t mailbox, size_t msgno MU_ARG_UNUSED, size_t *pcount, ...@@ -278,22 +278,6 @@ mh_scan0 (mu_mailbox_t mailbox, size_t msgno MU_ARG_UNUSED, size_t *pcount,
278 278
279 if (pcount) 279 if (pcount)
280 *pcount = amd->msg_count; 280 *pcount = amd->msg_count;
281
282 /* Reset the uidvalidity. */
283 if (amd->msg_count > 0)
284 {
285 if (amd->uidvalidity == 0)
286 {
287 amd->uidvalidity = (unsigned long)time (NULL);
288 /* Tell that we have been modified for expunging. */
289 if (amd->msg_count)
290 {
291 amd_message_stream_open (amd->msg_array[0]);
292 amd_message_stream_close (amd->msg_array[0]);
293 amd->msg_array[0]->attr_flags |= MU_ATTRIBUTE_MODIFIED;
294 }
295 }
296 }
297 } 281 }
298 /* Clean up the things */ 282 /* Clean up the things */
299 283
......
...@@ -87,7 +87,7 @@ do ...@@ -87,7 +87,7 @@ do
87 mv Mail/inbox/$i Mail/inbox/${i}0 87 mv Mail/inbox/$i Mail/inbox/${i}0
88 done 88 done
89 folder -pack || exit $? 89 folder -pack || exit $?
90 find Mail/inbox | sort 90 find Mail/inbox -not -name '.mu-prop' | sort
91 ], 91 ],
92 [0], 92 [0],
93 [Mail/inbox 93 [Mail/inbox
...@@ -105,7 +105,7 @@ do ...@@ -105,7 +105,7 @@ do
105 mv Mail/inbox/$i Mail/inbox/${i}0 105 mv Mail/inbox/$i Mail/inbox/${i}0
106 done 106 done
107 folder --pack=1 || exit $? 107 folder --pack=1 || exit $?
108 find Mail/inbox | sort 108 find Mail/inbox -not -name '.mu-prop' | sort
109 ], 109 ],
110 [0], 110 [0],
111 [Mail/inbox 111 [Mail/inbox
......