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 *);
86 96 int (*chattr_msg) (struct _amd_message *, int);
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 */
......
...@@ -129,7 +129,148 @@ struct _amd_body_stream ...@@ -129,7 +129,148 @@ struct _amd_body_stream
129 mu_body_t body; 129 mu_body_t body;
130 mu_off_t off; 130 mu_off_t off;
131 }; 131 };
132
133 /* AMD Properties */
134 int
135 _amd_prop_fetch_off (struct _amd_data *amd, const char *name, mu_off_t *pval)
136 {
137 const char *p;
138 mu_off_t n = 0;
139
140 if (!amd->prop || mu_property_sget_value (amd->prop, name, &p))
141 return MU_ERR_NOENT;
142 if (!pval)
143 return 0;
144 for (; *p; p++)
145 {
146 if (!mu_isdigit (*p))
147 return EINVAL;
148 n = n * 10 + *p - '0';
149 }
150 *pval = n;
151 return 0;
152 }
153
154 int
155 _amd_prop_fetch_size (struct _amd_data *amd, const char *name, size_t *pval)
156 {
157 mu_off_t n;
158 int rc = _amd_prop_fetch_off (amd, name, &n);
159 if (rc == 0)
160 {
161 size_t s = n;
162 if (s != n)
163 return ERANGE;
164 if (pval)
165 *pval = s;
166 }
167 return rc;
168 }
169
170 int
171 _amd_prop_fetch_ulong (struct _amd_data *amd, const char *name,
172 unsigned long *pval)
173 {
174 mu_off_t n;
175 int rc = _amd_prop_fetch_off (amd, name, &n);
176 if (rc == 0)
177 {
178 unsigned long s = n;
179 if (s != n)
180 return ERANGE;
181 if (pval)
182 *pval = s;
183 }
184 return rc;
185 }
132 186
187 int
188 _amd_prop_store_off (struct _amd_data *amd, const char *name, mu_off_t val)
189 {
190 char nbuf[128];
191 char *p;
192 int sign = 0;
193
194 p = nbuf + sizeof nbuf;
195 *--p = 0;
196 if (val < 0)
197 {
198 sign = 1;
199 val = - val;
200 }
201 do
202 {
203 unsigned d = val % 10;
204 if (p == nbuf)
205 return ERANGE;
206 *--p = d + '0';
207 val /= 10;
208 }
209 while (val);
210 if (sign)
211 {
212 if (p == nbuf)
213 return ERANGE;
214 *--p = '-';
215 }
216 return mu_property_set_value (amd->prop, name, p, 1);
217 }
218
219 /* Backward-compatible size file support */
220 static int
221 read_size_file (struct _amd_data *amd)
222 {
223 FILE *fp;
224 int rc;
225 char *name = mu_make_file_name (amd->name, _MU_AMD_SIZE_FILE_NAME);
226 if (!name)
227 return 1;
228 fp = fopen (name, "r");
229 if (fp)
230 {
231 unsigned long size;
232 if (fscanf (fp, "%lu", &size) == 1)
233 {
234 rc = _amd_prop_store_off (amd, _MU_AMD_PROP_SIZE, size);
235 }
236 else
237 rc = 1;
238 fclose (fp);
239 unlink (name);
240 }
241 else
242 rc = 1;
243 free (name);
244 return rc;
245 }
246
247 static int
248 _amd_prop_create (struct _amd_data *amd)
249 {
250 int rc;
251 struct mu_mh_prop *mhprop;
252 mhprop = calloc (1, sizeof (mhprop[0]));
253 if (!mhprop)
254 return ENOMEM;
255 mhprop->filename = mu_make_file_name (amd->name, _MU_AMD_PROP_FILE_NAME);
256 if (!mhprop->filename)
257 {
258 free (mhprop);
259 return errno;
260 }
261 rc = mu_property_create_init (&amd->prop, mu_mh_property_init, mhprop);
262 if (rc)
263 {
264 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
265 ("mu_property_create_init: %s",
266 mu_strerror (rc)));
267 free (mhprop->filename);
268 free (mhprop);
269 }
270 else
271 read_size_file (amd);
272 return rc;
273 }
133 274
134 /* Operations on message array */ 275 /* Operations on message array */
135 276
...@@ -246,8 +387,8 @@ amd_array_expand (struct _amd_data *amd, size_t index) ...@@ -246,8 +387,8 @@ amd_array_expand (struct _amd_data *amd, size_t index)
246 return 0; 387 return 0;
247 } 388 }
248 389
249 /* Shrink the message array by removing element at INDEX-COUNT and 390 /* Shrink the message array by removing the element at INDEX-COUNT and
250 shifting left by COUNT positions all the elements on the right of 391 shifting left by COUNT positions all the elements to the right of
251 it. */ 392 it. */
252 int 393 int
253 amd_array_shrink (struct _amd_data *amd, size_t index, size_t count) 394 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, ...@@ -273,7 +414,7 @@ amd_init_mailbox (mu_mailbox_t mailbox, size_t amd_size,
273 return EINVAL; 414 return EINVAL;
274 415
275 amd = mailbox->data = calloc (1, amd_size); 416 amd = mailbox->data = calloc (1, amd_size);
276 if (mailbox->data == NULL) 417 if (amd == NULL)
277 return ENOMEM; 418 return ENOMEM;
278 419
279 /* Back pointer. */ 420 /* Back pointer. */
...@@ -333,7 +474,9 @@ amd_destroy (mu_mailbox_t mailbox) ...@@ -333,7 +474,9 @@ amd_destroy (mu_mailbox_t mailbox)
333 free (amd->msg_array[i]); 474 free (amd->msg_array[i]);
334 } 475 }
335 free (amd->msg_array); 476 free (amd->msg_array);
336 477
478 mu_property_destroy (&amd->prop);
479
337 if (amd->name) 480 if (amd->name)
338 free (amd->name); 481 free (amd->name);
339 482
...@@ -374,6 +517,9 @@ amd_open (mu_mailbox_t mailbox, int flags) ...@@ -374,6 +517,9 @@ amd_open (mu_mailbox_t mailbox, int flags)
374 W_OK : R_OK | X_OK)) 517 W_OK : R_OK | X_OK))
375 return errno; 518 return errno;
376 519
520 /* Create/read properties. It is not an error if this fails. */
521 _amd_prop_create (amd);
522
377 if (mailbox->locker == NULL) 523 if (mailbox->locker == NULL)
378 mu_locker_create (&mailbox->locker, "/dev/null", 0); 524 mu_locker_create (&mailbox->locker, "/dev/null", 0);
379 525
...@@ -405,7 +551,6 @@ amd_close (mu_mailbox_t mailbox) ...@@ -405,7 +551,6 @@ amd_close (mu_mailbox_t mailbox)
405 amd->msg_count = 0; /* number of messages in the list */ 551 amd->msg_count = 0; /* number of messages in the list */
406 amd->msg_max = 0; /* maximum message buffer capacity */ 552 amd->msg_max = 0; /* maximum message buffer capacity */
407 553
408 amd->uidvalidity = 0;
409 mu_monitor_unlock (mailbox->monitor); 554 mu_monitor_unlock (mailbox->monitor);
410 555
411 return 0; 556 return 0;
...@@ -547,6 +692,27 @@ _amd_attach_message (mu_mailbox_t mailbox, struct _amd_message *mhm, ...@@ -547,6 +692,27 @@ _amd_attach_message (mu_mailbox_t mailbox, struct _amd_message *mhm,
547 } 692 }
548 693
549 static int 694 static int
695 _amd_scan0 (struct _amd_data *amd, size_t msgno, size_t *pcount,
696 int do_notify)
697 {
698 int status = amd->scan0 (amd->mailbox, msgno, pcount, do_notify);
699 if (status != 0)
700 return status;
701 /* Reset the uidvalidity. */
702 if (amd->msg_count > 0)
703 {
704 unsigned long uidval;
705 if (_amd_prop_fetch_ulong (amd, _MU_AMD_PROP_UIDVALIDITY, &uidval) ||
706 !uidval)
707 {
708 uidval = (unsigned long)time (NULL);
709 _amd_prop_store_off (amd, _MU_AMD_PROP_UIDVALIDITY, uidval);
710 }
711 }
712 return 0;
713 }
714
715 static int
550 amd_get_message (mu_mailbox_t mailbox, size_t msgno, mu_message_t *pmsg) 716 amd_get_message (mu_mailbox_t mailbox, size_t msgno, mu_message_t *pmsg)
551 { 717 {
552 int status; 718 int status;
...@@ -562,7 +728,7 @@ amd_get_message (mu_mailbox_t mailbox, size_t msgno, mu_message_t *pmsg) ...@@ -562,7 +728,7 @@ amd_get_message (mu_mailbox_t mailbox, size_t msgno, mu_message_t *pmsg)
562 /* If we did not start a scanning yet do it now. */ 728 /* If we did not start a scanning yet do it now. */
563 if (amd->msg_count == 0) 729 if (amd->msg_count == 0)
564 { 730 {
565 status = amd->scan0 (mailbox, 1, NULL, 0); 731 status = _amd_scan0 (amd, 1, NULL, 0);
566 if (status != 0) 732 if (status != 0)
567 return status; 733 return status;
568 } 734 }
...@@ -647,7 +813,6 @@ _amd_message_save (struct _amd_data *amd, struct _amd_message *mhm, ...@@ -647,7 +813,6 @@ _amd_message_save (struct _amd_data *amd, struct _amd_message *mhm,
647 mu_body_t body; 813 mu_body_t body;
648 const char *sbuf; 814 const char *sbuf;
649 mu_envelope_t env = NULL; 815 mu_envelope_t env = NULL;
650 char statbuf[MU_STATUS_BUF_SIZE];
651 816
652 status = mu_message_size (msg, &bsize); 817 status = mu_message_size (msg, &bsize);
653 if (status) 818 if (status)
...@@ -724,17 +889,6 @@ _amd_message_save (struct _amd_data *amd, struct _amd_message *mhm, ...@@ -724,17 +889,6 @@ _amd_message_save (struct _amd_data *amd, struct _amd_message *mhm,
724 } 889 }
725 mu_stream_destroy (&stream); 890 mu_stream_destroy (&stream);
726 891
727 /* Add imapbase */
728 if (!(amd->mailbox->flags & MU_STREAM_APPEND)
729 && amd->next_uid
730 && (!amd->msg_array || (amd->msg_array[0] == mhm))) /*FIXME*/
731 {
732 nbytes += fprintf (fp, "X-IMAPbase: %lu %u\n",
733 (unsigned long) amd->uidvalidity,
734 (unsigned) amd->next_uid (amd));
735 nlines++;
736 }
737
738 mu_message_get_envelope (msg, &env); 892 mu_message_get_envelope (msg, &env);
739 if (mu_envelope_sget_date (env, &sbuf) == 0) 893 if (mu_envelope_sget_date (env, &sbuf) == 0)
740 { 894 {
...@@ -754,15 +908,21 @@ _amd_message_save (struct _amd_data *amd, struct _amd_message *mhm, ...@@ -754,15 +908,21 @@ _amd_message_save (struct _amd_data *amd, struct _amd_message *mhm,
754 fprintf (fp, "%s: %s\n", MU_HEADER_ENV_SENDER, sbuf); 908 fprintf (fp, "%s: %s\n", MU_HEADER_ENV_SENDER, sbuf);
755 nlines++; 909 nlines++;
756 } 910 }
757 911
758 /* Add status */ 912 if (!(amd->capabilities & MU_AMD_STATUS))
759 mu_message_get_attribute (msg, &attr);
760 mu_attribute_to_string (attr, statbuf, sizeof (statbuf), &n);
761 if (n)
762 { 913 {
763 nbytes += fprintf (fp, "Status: %s\n", statbuf); 914 /* Add status */
764 nlines++; 915 char statbuf[MU_STATUS_BUF_SIZE];
916
917 mu_message_get_attribute (msg, &attr);
918 mu_attribute_to_string (attr, statbuf, sizeof (statbuf), &n);
919 if (n)
920 {
921 nbytes += fprintf (fp, "Status: %s\n", statbuf);
922 nlines++;
923 }
765 } 924 }
925
766 nbytes += fprintf (fp, "\n"); 926 nbytes += fprintf (fp, "\n");
767 nlines++; 927 nlines++;
768 928
...@@ -858,7 +1018,7 @@ amd_append_message (mu_mailbox_t mailbox, mu_message_t msg) ...@@ -858,7 +1018,7 @@ amd_append_message (mu_mailbox_t mailbox, mu_message_t msg)
858 /* If we did not start a scanning yet do it now. */ 1018 /* If we did not start a scanning yet do it now. */
859 if (amd->msg_count == 0) 1019 if (amd->msg_count == 0)
860 { 1020 {
861 status = amd->scan0 (mailbox, 1, NULL, 0); 1021 status = _amd_scan0 (amd, 1, NULL, 0);
862 if (status != 0) 1022 if (status != 0)
863 { 1023 {
864 free (mhm); 1024 free (mhm);
...@@ -923,7 +1083,7 @@ amd_messages_count (mu_mailbox_t mailbox, size_t *pcount) ...@@ -923,7 +1083,7 @@ amd_messages_count (mu_mailbox_t mailbox, size_t *pcount)
923 return EINVAL; 1083 return EINVAL;
924 1084
925 if (!amd_is_updated (mailbox)) 1085 if (!amd_is_updated (mailbox))
926 return amd->scan0 (mailbox, amd->msg_count, pcount, 0); 1086 return _amd_scan0 (amd, amd->msg_count, pcount, 0);
927 1087
928 if (pcount) 1088 if (pcount)
929 *pcount = amd->msg_count; 1089 *pcount = amd->msg_count;
...@@ -943,7 +1103,7 @@ amd_messages_recent (mu_mailbox_t mailbox, size_t *pcount) ...@@ -943,7 +1103,7 @@ amd_messages_recent (mu_mailbox_t mailbox, size_t *pcount)
943 /* If we did not start a scanning yet do it now. */ 1103 /* If we did not start a scanning yet do it now. */
944 if (amd->msg_count == 0) 1104 if (amd->msg_count == 0)
945 { 1105 {
946 int status = amd->scan0 (mailbox, 1, NULL, 0); 1106 int status = _amd_scan0 (amd, 1, NULL, 0);
947 if (status != 0) 1107 if (status != 0)
948 return status; 1108 return status;
949 } 1109 }
...@@ -967,7 +1127,7 @@ amd_message_unseen (mu_mailbox_t mailbox, size_t *pmsgno) ...@@ -967,7 +1127,7 @@ amd_message_unseen (mu_mailbox_t mailbox, size_t *pmsgno)
967 /* If we did not start a scanning yet do it now. */ 1127 /* If we did not start a scanning yet do it now. */
968 if (amd->msg_count == 0) 1128 if (amd->msg_count == 0)
969 { 1129 {
970 int status = amd->scan0 (mailbox, 1, NULL, 0); 1130 int status = _amd_scan0 (amd, 1, NULL, 0);
971 if (status != 0) 1131 if (status != 0)
972 return status; 1132 return status;
973 } 1133 }
...@@ -982,71 +1142,10 @@ amd_message_unseen (mu_mailbox_t mailbox, size_t *pmsgno) ...@@ -982,71 +1142,10 @@ amd_message_unseen (mu_mailbox_t mailbox, size_t *pmsgno)
982 } 1142 }
983 return 0; 1143 return 0;
984 } 1144 }
985 1145
986 static char *
987 make_size_file_name (struct _amd_data *amd)
988 {
989 size_t size = strlen (amd->name) + 1 + sizeof (MU_AMD_SIZE_FILE_NAME);
990 char *name = malloc (size);
991 if (name)
992 {
993 strcpy (name, amd->name);
994 strcat (name, "/");
995 strcat (name, MU_AMD_SIZE_FILE_NAME);
996 }
997 return name;
998 }
999
1000 static int
1001 read_size_file (struct _amd_data *amd, mu_off_t *psize)
1002 {
1003 FILE *fp;
1004 int rc;
1005 char *name = make_size_file_name (amd);
1006 if (!name)
1007 return 1;
1008 fp = fopen (name, "r");
1009 if (fp)
1010 {
1011 unsigned long size;
1012 if (fscanf (fp, "%lu", &size) == 1)
1013 {
1014 *psize = size;
1015 rc = 0;
1016 }
1017 else
1018 rc = 1;
1019 fclose (fp);
1020 }
1021 else
1022 rc = 1;
1023 free (name);
1024 return rc;
1025 }
1026
1027 static int
1028 write_size_file (struct _amd_data *amd, mu_off_t size)
1029 {
1030 FILE *fp;
1031 int rc;
1032 char *name = make_size_file_name (amd);
1033 if (!name)
1034 return 1;
1035 fp = fopen (name, "w");
1036 if (fp)
1037 {
1038 fprintf (fp, "%lu", (unsigned long) size);
1039 fclose (fp);
1040 rc = 0;
1041 }
1042 else
1043 rc = 1;
1044 free (name);
1045 return rc;
1046 }
1047
1048 static int 1146 static int
1049 compute_mailbox_size (struct _amd_data *amd, const char *name, mu_off_t *psize) 1147 _compute_mailbox_size_recursive (struct _amd_data *amd, const char *name,
1148 mu_off_t *psize)
1050 { 1149 {
1051 DIR *dir; 1150 DIR *dir;
1052 struct dirent *entry; 1151 struct dirent *entry;
...@@ -1099,7 +1198,7 @@ compute_mailbox_size (struct _amd_data *amd, const char *name, mu_off_t *psize) ...@@ -1099,7 +1198,7 @@ compute_mailbox_size (struct _amd_data *amd, const char *name, mu_off_t *psize)
1099 if (S_ISREG (sb.st_mode)) 1198 if (S_ISREG (sb.st_mode))
1100 *psize += sb.st_size; 1199 *psize += sb.st_size;
1101 else if (S_ISDIR (sb.st_mode)) 1200 else if (S_ISDIR (sb.st_mode))
1102 compute_mailbox_size (amd, buf, psize); 1201 _compute_mailbox_size_recursive (amd, buf, psize);
1103 } 1202 }
1104 /* FIXME: else? */ 1203 /* FIXME: else? */
1105 break; 1204 break;
...@@ -1113,6 +1212,20 @@ compute_mailbox_size (struct _amd_data *amd, const char *name, mu_off_t *psize) ...@@ -1113,6 +1212,20 @@ compute_mailbox_size (struct _amd_data *amd, const char *name, mu_off_t *psize)
1113 } 1212 }
1114 1213
1115 static int 1214 static int
1215 compute_mailbox_size (struct _amd_data *amd, mu_off_t *psize)
1216 {
1217 mu_off_t size = 0;
1218 int rc = _compute_mailbox_size_recursive (amd, amd->name, &size);
1219 if (rc == 0)
1220 {
1221 rc = _amd_prop_store_off (amd, _MU_AMD_PROP_SIZE, size);
1222 if (rc == 0 && psize)
1223 *psize = size;
1224 }
1225 return rc;
1226 }
1227
1228 static int
1116 amd_remove_mbox (mu_mailbox_t mailbox) 1229 amd_remove_mbox (mu_mailbox_t mailbox)
1117 { 1230 {
1118 int rc; 1231 int rc;
...@@ -1123,11 +1236,22 @@ amd_remove_mbox (mu_mailbox_t mailbox) ...@@ -1123,11 +1236,22 @@ amd_remove_mbox (mu_mailbox_t mailbox)
1123 rc = amd->remove (amd); 1236 rc = amd->remove (amd);
1124 if (rc == 0) 1237 if (rc == 0)
1125 { 1238 {
1126 char *name = make_size_file_name (amd); 1239 char *name;
1240
1241 name = mu_make_file_name (amd->name, _MU_AMD_SIZE_FILE_NAME);
1127 if (!name) 1242 if (!name)
1128 return ENOMEM; 1243 return ENOMEM;
1129 if (unlink (name) && errno != ENOENT) 1244 if (unlink (name) && errno != ENOENT)
1130 rc = errno; 1245 rc = errno;
1246 else
1247 {
1248 free (name);
1249 name = mu_make_file_name (amd->name, _MU_AMD_PROP_FILE_NAME);
1250 if (!name)
1251 return ENOMEM;
1252 if (unlink (name) && errno != ENOENT)
1253 rc = errno;
1254 }
1131 free (name); 1255 free (name);
1132 } 1256 }
1133 1257
...@@ -1147,6 +1271,55 @@ amd_remove_mbox (mu_mailbox_t mailbox) ...@@ -1147,6 +1271,55 @@ amd_remove_mbox (mu_mailbox_t mailbox)
1147 } 1271 }
1148 1272
1149 static int 1273 static int
1274 _amd_update_message (struct _amd_data *amd, struct _amd_message *mhm,
1275 int expunge, int *upd)
1276 {
1277 int flg, rc;
1278
1279 if (mhm->message)
1280 flg = mu_message_is_modified (mhm->message);
1281 else if (mhm->attr_flags & MU_ATTRIBUTE_MODIFIED)
1282 flg = MU_MSG_ATTRIBUTE_MODIFIED;
1283
1284 if (!flg)
1285 return 0;
1286
1287 if (flg == MU_MSG_ATTRIBUTE_MODIFIED && amd->chattr_msg)
1288 {
1289 rc = amd->chattr_msg (mhm, expunge);
1290 if (rc)
1291 {
1292 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
1293 ("_amd_update_message: chattr_msg failed: %s",
1294 mu_strerror (rc)));
1295 return rc;
1296 }
1297 }
1298 else
1299 {
1300 rc = _amd_attach_message (amd->mailbox, mhm, NULL);
1301 if (rc)
1302 {
1303 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
1304 ("_amd_update_message: _amd_attach_message failed: %s",
1305 mu_strerror (rc)));
1306 return rc;
1307 }
1308
1309 rc = _amd_message_save (amd, mhm, expunge);
1310 if (rc)
1311 {
1312 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
1313 ("_amd_update_message: _amd_message_save failed: %s",
1314 mu_strerror (rc)));
1315 return rc;
1316 }
1317 }
1318 *upd = 1;
1319 return rc;
1320 }
1321
1322 static int
1150 amd_expunge (mu_mailbox_t mailbox) 1323 amd_expunge (mu_mailbox_t mailbox)
1151 { 1324 {
1152 struct _amd_data *amd = mailbox->data; 1325 struct _amd_data *amd = mailbox->data;
...@@ -1232,13 +1405,7 @@ amd_expunge (mu_mailbox_t mailbox) ...@@ -1232,13 +1405,7 @@ amd_expunge (mu_mailbox_t mailbox)
1232 } 1405 }
1233 else 1406 else
1234 { 1407 {
1235 if ((mhm->attr_flags & MU_ATTRIBUTE_MODIFIED) 1408 _amd_update_message (amd, mhm, 1, &updated);/*FIXME: Error checking*/
1236 || (mhm->message && mu_message_is_modified (mhm->message)))
1237 {
1238 _amd_attach_message (mailbox, mhm, NULL);
1239 _amd_message_save (amd, mhm, 1);
1240 updated = 1;
1241 }
1242 } 1409 }
1243 } 1410 }
1244 1411
...@@ -1263,10 +1430,7 @@ amd_expunge (mu_mailbox_t mailbox) ...@@ -1263,10 +1430,7 @@ amd_expunge (mu_mailbox_t mailbox)
1263 1430
1264 if (updated && !amd->mailbox_size) 1431 if (updated && !amd->mailbox_size)
1265 { 1432 {
1266 mu_off_t size = 0; 1433 compute_mailbox_size (amd, NULL);
1267 int rc = compute_mailbox_size (amd, amd->name, &size);
1268 if (rc == 0)
1269 write_size_file (amd, size);
1270 } 1434 }
1271 return 0; 1435 return 0;
1272 } 1436 }
...@@ -1297,22 +1461,12 @@ amd_sync (mu_mailbox_t mailbox) ...@@ -1297,22 +1461,12 @@ amd_sync (mu_mailbox_t mailbox)
1297 for ( ; i < amd->msg_count; i++) 1461 for ( ; i < amd->msg_count; i++)
1298 { 1462 {
1299 mhm = amd->msg_array[i]; 1463 mhm = amd->msg_array[i];
1300 1464 _amd_update_message (amd, mhm, 0, &updated);
1301 if ((mhm->attr_flags & MU_ATTRIBUTE_MODIFIED)
1302 || (mhm->message && mu_message_is_modified (mhm->message)))
1303 {
1304 _amd_attach_message (mailbox, mhm, NULL);
1305 _amd_message_save (amd, mhm, 0);
1306 updated = 1;
1307 }
1308 } 1465 }
1309 1466
1310 if (updated && !amd->mailbox_size) 1467 if (updated && !amd->mailbox_size)
1311 { 1468 {
1312 mu_off_t size = 0; 1469 compute_mailbox_size (amd, NULL);
1313 int rc = compute_mailbox_size (amd, amd->name, &size);
1314 if (rc == 0)
1315 write_size_file (amd, size);
1316 } 1470 }
1317 1471
1318 return 0; 1472 return 0;
...@@ -1328,13 +1482,12 @@ amd_uidvalidity (mu_mailbox_t mailbox, unsigned long *puidvalidity) ...@@ -1328,13 +1482,12 @@ amd_uidvalidity (mu_mailbox_t mailbox, unsigned long *puidvalidity)
1328 /* If we did not start a scanning yet do it now. */ 1482 /* If we did not start a scanning yet do it now. */
1329 if (amd->msg_count == 0) 1483 if (amd->msg_count == 0)
1330 { 1484 {
1331 status = amd->scan0 (mailbox, 1, NULL, 0); 1485 status = _amd_scan0 (amd, 1, NULL, 0);
1332 if (status != 0) 1486 if (status != 0)
1333 return status; 1487 return status;
1334 } 1488 }
1335 if (puidvalidity) 1489
1336 *puidvalidity = amd->uidvalidity; 1490 return _amd_prop_fetch_ulong (amd, _MU_AMD_PROP_UIDVALIDITY, puidvalidity);
1337 return 0;
1338 } 1491 }
1339 1492
1340 static int 1493 static int
...@@ -1351,7 +1504,7 @@ amd_uidnext (mu_mailbox_t mailbox, size_t *puidnext) ...@@ -1351,7 +1504,7 @@ amd_uidnext (mu_mailbox_t mailbox, size_t *puidnext)
1351 /* If we did not start a scanning yet do it now. */ 1504 /* If we did not start a scanning yet do it now. */
1352 if (amd->msg_count == 0) 1505 if (amd->msg_count == 0)
1353 { 1506 {
1354 status = amd->scan0 (mailbox, 1, NULL, 0); 1507 status = _amd_scan0 (amd, 1, NULL, 0);
1355 if (status != 0) 1508 if (status != 0)
1356 return status; 1509 return status;
1357 } 1510 }
...@@ -1458,7 +1611,9 @@ amd_scan_message (struct _amd_message *mhm) ...@@ -1458,7 +1611,9 @@ amd_scan_message (struct _amd_message *mhm)
1458 size_t body_start = 0; 1611 size_t body_start = 0;
1459 struct stat st; 1612 struct stat st;
1460 char *msg_name; 1613 char *msg_name;
1461 1614 struct _amd_data *amd = mhm->amd;
1615 int amd_capa = amd->capabilities;
1616
1462 /* Check if the message was modified after the last scan */ 1617 /* Check if the message was modified after the last scan */
1463 status = mhm->amd->cur_msg_file_name (mhm, &msg_name); 1618 status = mhm->amd->cur_msg_file_name (mhm, &msg_name);
1464 if (status) 1619 if (status)
...@@ -1498,17 +1653,25 @@ amd_scan_message (struct _amd_message *mhm) ...@@ -1498,17 +1653,25 @@ amd_scan_message (struct _amd_message *mhm)
1498 hlines++; 1653 hlines++;
1499 1654
1500 /* Process particular attributes */ 1655 /* Process particular attributes */
1501 if (mu_c_strncasecmp (buf, "status:", 7) == 0) 1656 if (!(amd_capa & MU_AMD_STATUS) &&
1657 mu_c_strncasecmp (buf, "status:", 7) == 0)
1502 { 1658 {
1503 int deleted = mhm->attr_flags & MU_ATTRIBUTE_DELETED; 1659 int deleted = mhm->attr_flags & MU_ATTRIBUTE_DELETED;
1504 mu_string_to_flags (buf, &mhm->attr_flags); 1660 mu_string_to_flags (buf, &mhm->attr_flags);
1505 mhm->attr_flags |= deleted; 1661 mhm->attr_flags |= deleted;
1506 } 1662 }
1507 else if (mu_c_strncasecmp (buf, "x-imapbase:", 11) == 0) 1663 else if (!(amd_capa & MU_AMD_IMAPBASE) &&
1664 mu_c_strncasecmp (buf, "x-imapbase:", 11) == 0)
1508 { 1665 {
1509 char *p; 1666 if (_amd_prop_fetch_ulong (amd, _MU_AMD_PROP_UIDVALIDITY,
1510 mhm->amd->uidvalidity = strtoul (buf + 11, &p, 10); 1667 NULL))
1511 /* second number is next uid. Ignored */ 1668 {
1669 char *p;
1670 unsigned long uidval = strtoul (buf + 11, &p, 10);
1671 /* The next number is next uid. Ignored */
1672 _amd_prop_store_off (amd, _MU_AMD_PROP_UIDVALIDITY,
1673 uidval);
1674 }
1512 } 1675 }
1513 } 1676 }
1514 else 1677 else
...@@ -1545,7 +1708,7 @@ amd_scan (mu_mailbox_t mailbox, size_t msgno, size_t *pcount) ...@@ -1545,7 +1708,7 @@ amd_scan (mu_mailbox_t mailbox, size_t msgno, size_t *pcount)
1545 struct _amd_data *amd = mailbox->data; 1708 struct _amd_data *amd = mailbox->data;
1546 1709
1547 if (! amd_is_updated (mailbox)) 1710 if (! amd_is_updated (mailbox))
1548 return amd->scan0 (mailbox, msgno, pcount, 1); 1711 return _amd_scan0 (amd, msgno, pcount, 1);
1549 1712
1550 if (pcount) 1713 if (pcount)
1551 *pcount = amd->msg_count; 1714 *pcount = amd->msg_count;
...@@ -1573,14 +1736,8 @@ amd_get_size (mu_mailbox_t mailbox, mu_off_t *psize) ...@@ -1573,14 +1736,8 @@ amd_get_size (mu_mailbox_t mailbox, mu_off_t *psize)
1573 struct _amd_data *amd = mailbox->data; 1736 struct _amd_data *amd = mailbox->data;
1574 if (amd->mailbox_size) 1737 if (amd->mailbox_size)
1575 return amd->mailbox_size (mailbox, psize); 1738 return amd->mailbox_size (mailbox, psize);
1576 *psize = 0; 1739 if (_amd_prop_fetch_off (amd, _MU_AMD_PROP_SIZE, psize))
1577 if (read_size_file (amd, psize)) 1740 return compute_mailbox_size (amd, psize);
1578 {
1579 int rc = compute_mailbox_size (amd, amd->name, psize);
1580 if (rc == 0)
1581 write_size_file (amd, *psize);
1582 return rc;
1583 }
1584 return 0; 1741 return 0;
1585 } 1742 }
1586 1743
......
...@@ -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;
...@@ -773,6 +761,42 @@ maildir_remove (struct _amd_data *amd) ...@@ -773,6 +761,42 @@ maildir_remove (struct _amd_data *amd)
773 return rc; 761 return rc;
774 } 762 }
775 763
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
776 800
777 int 801 int
778 _mailbox_maildir_init (mu_mailbox_t mailbox) 802 _mailbox_maildir_init (mu_mailbox_t mailbox)
...@@ -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
......