Implemented mbox_append () first draft. Things are still very unstable.
Showing
10 changed files
with
454 additions
and
73 deletions
... | @@ -172,6 +172,7 @@ checkit | ... | @@ -172,6 +172,7 @@ checkit |
172 | format = va_arg (args, char *); | 172 | format = va_arg (args, char *); |
173 | #endif | 173 | #endif |
174 | vasprintf (&result, format, args); | 174 | vasprintf (&result, format, args); |
175 | va_end (args); | ||
175 | if (strlen (result) < global_total_width) | 176 | if (strlen (result) < global_total_width) |
176 | printf ("PASS: "); | 177 | printf ("PASS: "); |
177 | else | 178 | else | ... | ... |
... | @@ -70,16 +70,21 @@ extern int mbox_unmark_deleted __P ((mbox_t, unsigned int)); | ... | @@ -70,16 +70,21 @@ extern int mbox_unmark_deleted __P ((mbox_t, unsigned int)); |
70 | extern int mbox_expunge __P ((mbox_t, int)); | 70 | extern int mbox_expunge __P ((mbox_t, int)); |
71 | extern int mbox_changed_on_disk __P ((mbox_t)); | 71 | extern int mbox_changed_on_disk __P ((mbox_t)); |
72 | 72 | ||
73 | extern int mbox_set_progress_cb __P ((mbox_t, int (*) __P ((int, void *)), void *)); | 73 | extern int mbox_set_progress_cb |
74 | extern int mbox_set_newmsg_cb __P ((mbox_t, int (*) __P ((int, void *)), void *)); | 74 | __P ((mbox_t, int (*) __P ((int, void *)), void *)); |
75 | extern int mbox_set_newmsg_cb | ||
76 | __P ((mbox_t, int (*) __P ((int, void *)), void *)); | ||
75 | extern int mbox_newmsg_cb __P ((mbox_t, int)); | 77 | extern int mbox_newmsg_cb __P ((mbox_t, int)); |
76 | extern int mbox_progress_cb __P ((mbox_t, int)); | 78 | extern int mbox_progress_cb __P ((mbox_t, int)); |
77 | 79 | ||
78 | extern int mbox_scan __P ((mbox_t, unsigned int, unsigned int *, int)); | 80 | extern int mbox_scan __P ((mbox_t, unsigned int, unsigned int *, int)); |
79 | extern int mbox_messages_count __P ((mbox_t, unsigned int *)); | 81 | extern int mbox_messages_count __P ((mbox_t, unsigned int *)); |
80 | 82 | ||
81 | extern int mbox_append __P ((mbox_t, const char *, stream_t)); | 83 | extern int mbox_append __P ((mbox_t, const char *, attribute_t, stream_t)); |
82 | extern int mbox_append_hb __P ((mbox_t, const char *, stream_t, stream_t)); | 84 | extern int mbox_append_hb |
85 | __P ((mbox_t, const char *, attribute_t, stream_t, stream_t)); | ||
86 | extern int mbox_append_hb0 | ||
87 | __P ((mbox_t, const char *, attribute_t, int, stream_t, stream_t)); | ||
83 | 88 | ||
84 | extern int mbox_get_carrier __P ((mbox_t, stream_t *)); | 89 | extern int mbox_get_carrier __P ((mbox_t, stream_t *)); |
85 | extern int mbox_set_carrier __P ((mbox_t, stream_t)); | 90 | extern int mbox_set_carrier __P ((mbox_t, stream_t)); |
... | @@ -95,6 +100,8 @@ extern int mbox_header_get_value __P ((mbox_t, unsigned int, const char *, | ... | @@ -95,6 +100,8 @@ extern int mbox_header_get_value __P ((mbox_t, unsigned int, const char *, |
95 | 100 | ||
96 | extern int stream_mbox_create __P ((stream_t *, mbox_t, unsigned int, int)); | 101 | extern int stream_mbox_create __P ((stream_t *, mbox_t, unsigned int, int)); |
97 | extern int attribute_mbox_create __P ((attribute_t *, mbox_t, unsigned int)); | 102 | extern int attribute_mbox_create __P ((attribute_t *, mbox_t, unsigned int)); |
103 | extern int mbox_attribute_to_status | ||
104 | __P ((attribute_t, char *, size_t, size_t *)); | ||
98 | 105 | ||
99 | #ifdef __cplusplus | 106 | #ifdef __cplusplus |
100 | } | 107 | } | ... | ... |
... | @@ -49,9 +49,8 @@ struct _mbox | ... | @@ -49,9 +49,8 @@ struct _mbox |
49 | stream_t carrier; /* File stream. */ | 49 | stream_t carrier; /* File stream. */ |
50 | 50 | ||
51 | off_t size; /* Size of the mailbox. */ | 51 | off_t size; /* Size of the mailbox. */ |
52 | time_t mtime; /* Modified time. */ | ||
53 | unsigned long uidvalidity; | 52 | unsigned long uidvalidity; |
54 | size_t uidnext; | 53 | unsigned long uidnext; |
55 | char *filename; | 54 | char *filename; |
56 | 55 | ||
57 | struct _hcache hcache; | 56 | struct _hcache hcache; |
... | @@ -59,10 +58,11 @@ struct _mbox | ... | @@ -59,10 +58,11 @@ struct _mbox |
59 | /* The variables below are use to hold the state when appending messages. */ | 58 | /* The variables below are use to hold the state when appending messages. */ |
60 | enum mbox_state | 59 | enum mbox_state |
61 | { | 60 | { |
62 | MBOX_NO_STATE = 0, | 61 | MU_MBOX_NO_STATE = 0, |
63 | MBOX_STATE_APPEND_HEADER, | 62 | MU_MBOX_STATE_APPEND_SEPARATOR, |
64 | MBOX_STATE_APPEND_BODY | 63 | MU_MBOX_STATE_APPEND_HEADER, |
65 | } state ; | 64 | MU_MBOX_STATE_APPEND_BODY |
65 | } state; | ||
66 | 66 | ||
67 | lockfile_t lockfile; | 67 | lockfile_t lockfile; |
68 | struct | 68 | struct | ... | ... |
... | @@ -20,36 +20,332 @@ | ... | @@ -20,36 +20,332 @@ |
20 | #endif | 20 | #endif |
21 | 21 | ||
22 | #include <stdlib.h> | 22 | #include <stdlib.h> |
23 | #include <string.h> | ||
23 | 24 | ||
24 | #include <mailutils/error.h> | 25 | #include <mailutils/error.h> |
25 | #include <mailutils/sys/mbox.h> | 26 | #include <mailutils/sys/mbox.h> |
26 | 27 | ||
27 | /* Save the uidvalidity | 28 | #define IS_X_IMAPBASE(buf) (\ |
28 | - if it is an empty mbox in the first message append | 29 | (buf[0] == 'X' || buf[0] == 'x') \ |
29 | - if for the first message the uidvalidity is not the same | 30 | && (buf[1] == '-') \ |
31 | && (buf[2] == 'I' || buf[2] == 'i') \ | ||
32 | && (buf[3] == 'M' || buf[3] == 'm') \ | ||
33 | && (buf[4] == 'A' || buf[4] == 'a') \ | ||
34 | && (buf[5] == 'P' || buf[5] == 'p') \ | ||
35 | && (buf[6] == 'B' || buf[6] == 'b') \ | ||
36 | && (buf[7] == 'A' || buf[7] == 'a') \ | ||
37 | && (buf[8] == 'S' || buf[8] == 's') \ | ||
38 | && (buf[9] == 'E' || buf[9] == 'e') \ | ||
39 | && (buf[10] == ':' || buf[10] == ' ' || buf[10] == '\t')) | ||
40 | |||
41 | #define IS_X_UID(buf) (\ | ||
42 | (buf[0] == 'X' || buf[0] == 'x') \ | ||
43 | && (buf[1] == '-') \ | ||
44 | && (buf[2] == 'U' || buf[2] == 'u') \ | ||
45 | && (buf[3] == 'I' || buf[3] == 'i') \ | ||
46 | && (buf[4] == 'D' || buf[4] == 'd') \ | ||
47 | && (buf[5] == ':' || buf[5] == ' ' || buf[5] == '\t')) | ||
48 | |||
49 | #define IS_CONTENT_LENGTH(buf) (\ | ||
50 | (buf[0] == 'C' || buf[0] == 'c') && \ | ||
51 | (buf[1] == 'O' || buf[1] == 'o') && \ | ||
52 | (buf[2] == 'N' || buf[2] == 'n') && \ | ||
53 | (buf[3] == 'T' || buf[3] == 't') && \ | ||
54 | (buf[4] == 'E' || buf[4] == 'e') && \ | ||
55 | (buf[5] == 'N' || buf[5] == 'n') && \ | ||
56 | (buf[6] == 'T' || buf[6] == 't') && \ | ||
57 | (buf[7] == '-') && \ | ||
58 | (buf[8] == 'L' || buf[8] == 'l') && \ | ||
59 | (buf[9] == 'E' || buf[9] == 'e') && \ | ||
60 | (buf[10] == 'N' || buf[10] == 'n') && \ | ||
61 | (buf[11] == 'G' || buf[11] == 'g') && \ | ||
62 | (buf[12] == 'T' || buf[12] == 't') && \ | ||
63 | (buf[13] == 'H' || buf[13] == 'h') && \ | ||
64 | (buf[14] == ':' || buf[14] == ' ' || buf[14] == '\t')) | ||
65 | |||
66 | #define IS_STATUS(buf) (\ | ||
67 | (buf[0] == 'S' || buf[0] == 's') && \ | ||
68 | (buf[1] == 'T' || buf[1] == 't') && \ | ||
69 | (buf[2] == 'A' || buf[2] == 'a') && \ | ||
70 | (buf[3] == 'T' || buf[3] == 't') && \ | ||
71 | (buf[4] == 'U' || buf[4] == 'u') && \ | ||
72 | (buf[5] == 'S' || buf[5] == 's') && \ | ||
73 | (buf[6] == ':' || buf[6] == ' ' || buf[6] == '\t')) | ||
74 | |||
75 | #define IS_FROM_(buf) (\ | ||
76 | (buf[0] == 'F' || buf[0] == 'f') && \ | ||
77 | (buf[1] == 'R' || buf[1] == 'r') && \ | ||
78 | (buf[2] == 'O' || buf[2] == 'o') && \ | ||
79 | (buf[3] == 'M' || buf[3] == 'm') && \ | ||
80 | (buf[4] == ' ' || buf[4] == '\t')) | ||
81 | |||
82 | /* Save the uidvalidity: | ||
83 | + if it is an empty mbox in the first message append | ||
84 | + if for the first message the uidvalidity is not the same | ||
30 | from the mbox->uidvalidity. | 85 | from the mbox->uidvalidity. |
31 | 86 | ||
32 | - strip X-IMAPBASE, X-UID | 87 | - strip X-IMAPBASE, X-UID |
33 | - add X-UID base on mbox->uidnext. | 88 | - add X-UID base on mbox->uidnext. |
34 | 89 | ||
35 | - mangle any leading "From " in the body to ">From " | 90 | - mangle any leading "From " in the body to ">From " |
91 | |||
92 | - update the size of the mailbox. | ||
93 | |||
94 | - Refuse to append if the mailbox is change on disk. | ||
36 | */ | 95 | */ |
37 | 96 | ||
38 | int | 97 | /* Assuming that the file is lock. */ |
39 | mbox_append (mbox_t mbox, const char *sep, stream_t stream) | 98 | static int |
99 | mbox_append_separator (mbox_t mbox, const char *sep) | ||
40 | { | 100 | { |
41 | if (mbox == NULL || stream == NULL) | 101 | char separator[256]; |
42 | return MU_ERROR_INVALID_PARAMETER; | 102 | size_t len; |
43 | (void)sep; | 103 | |
44 | return 0; | 104 | if (sep == NULL) |
105 | { | ||
106 | time_t now; | ||
107 | struct tm *ptm; | ||
108 | |||
109 | now = time (NULL); | ||
110 | ptm = gmtime (&now); | ||
111 | len = strftime (separator, sizeof separator, | ||
112 | "From unknown %a %b %d %H:%M:%S %Y\n", ptm); | ||
113 | if (len == 0) | ||
114 | { | ||
115 | len = snprintf (separator, sizeof separator, | ||
116 | "From unknown %s", ctime (&now)); | ||
117 | } | ||
118 | sep = separator; | ||
119 | } | ||
120 | else | ||
121 | len = strlen (sep); | ||
122 | |||
123 | /* Write the separator. */ | ||
124 | return stream_write (mbox->carrier, sep, len, NULL); | ||
125 | } | ||
126 | |||
127 | /* Assuming that the file is lock. */ | ||
128 | static int | ||
129 | mbox_append_header (mbox_t mbox, attribute_t attribute, int save_uidvalidity, | ||
130 | stream_t hstream) | ||
131 | { | ||
132 | char buffer[1024]; | ||
133 | size_t nread = 0; | ||
134 | int status = 0; | ||
135 | const char nl = '\n'; | ||
136 | |||
137 | do | ||
138 | { | ||
139 | status = stream_readline (hstream, buffer, sizeof buffer, &nread); | ||
140 | if (status != 0) | ||
141 | return status; | ||
142 | |||
143 | /* A newline means the start of the body. */ | ||
144 | if (*buffer == '\n') | ||
145 | break; | ||
146 | |||
147 | if (IS_X_IMAPBASE (buffer)) | ||
148 | { | ||
149 | /* Skip the X-IMAPBase it has special meaning for us. */ | ||
150 | continue; | ||
151 | } | ||
152 | else if (IS_X_UID (buffer)) | ||
153 | { | ||
154 | /* Skip the X-UID. A new one will be provided. */ | ||
155 | continue; | ||
156 | } | ||
157 | else if (IS_STATUS (buffer)) | ||
158 | { | ||
159 | /* Skip, use the attribute. */ | ||
160 | continue; | ||
161 | } | ||
162 | else if (IS_CONTENT_LENGTH (buffer)) | ||
163 | { | ||
164 | /* Ignore this, too often bad. */ | ||
165 | continue; | ||
166 | } | ||
167 | |||
168 | status = stream_write (mbox->carrier, buffer, nread, NULL); | ||
169 | if (status != 0) | ||
170 | return status; | ||
171 | } | ||
172 | while (nread > 0); | ||
173 | |||
174 | /* Rewrite the X-IMAPbase marker If necesary. */ | ||
175 | if (mbox->uidnext < 2 && save_uidvalidity) | ||
176 | { | ||
177 | nread = snprintf (buffer, sizeof buffer, "X-IMAPbase: %lu %lu\n", | ||
178 | mbox->uidvalidity, mbox->uidnext); | ||
179 | status = stream_write (mbox->carrier, buffer, nread, NULL); | ||
180 | if (status != 0) | ||
181 | return status; | ||
182 | } | ||
183 | |||
184 | /* Rewrite the Status for the attribute. */ | ||
185 | if (attribute) | ||
186 | { | ||
187 | mbox_attribute_to_status (attribute, buffer, sizeof buffer, &nread); | ||
188 | status = stream_write (mbox->carrier, buffer, nread, NULL); | ||
189 | if (status != 0) | ||
190 | return status; | ||
191 | } | ||
192 | |||
193 | /* Rewrite the X-UID marker . */ | ||
194 | nread = snprintf (buffer, sizeof buffer, "X-UID: %lu\n", mbox->uidnext); | ||
195 | status = stream_write (mbox->carrier, buffer, nread, NULL); | ||
196 | if (status != 0) | ||
197 | return status; | ||
198 | |||
199 | /* New line separator of the Header. */ | ||
200 | return stream_write (mbox->carrier, &nl , 1, NULL); | ||
201 | } | ||
202 | |||
203 | /* Assuming that the file is lock. */ | ||
204 | static int | ||
205 | mbox_append_body (mbox_t mbox, stream_t bstream) | ||
206 | { | ||
207 | char buffer[1024]; | ||
208 | char *buf; | ||
209 | int was_complete_line; | ||
210 | size_t nread = 0; | ||
211 | const char nl = '\n'; | ||
212 | int status; | ||
213 | |||
214 | /* For "From " mangling. */ | ||
215 | *buffer = '>'; | ||
216 | was_complete_line = 1; /* Say we start as complete line. */ | ||
217 | do | ||
218 | { | ||
219 | buf = buffer + 1; | ||
220 | status = stream_readline (bstream, buf, sizeof (buffer) - 1, &nread); | ||
221 | if (status != 0) | ||
222 | return status; | ||
223 | |||
224 | /* Unix Mbox: | ||
225 | Since it's possibpe for a message to contain lines that looks | ||
226 | like message separators, special care must be taken when adding | ||
227 | a message to an mbox folder this is done by prepending a '>' | ||
228 | character to any lines starting with zero or more '>' characters | ||
229 | folowed by "From " | ||
230 | p436 "Internet Email Protocols a Debeloper's Guid" | ||
231 | Kevin Johnson. | ||
232 | */ | ||
233 | if (was_complete_line) | ||
234 | { | ||
235 | char *s = buf; | ||
236 | /* Eat all the '>'. */ | ||
237 | while (*s == '>') | ||
238 | s++; | ||
239 | |||
240 | if (IS_FROM_ (s)) | ||
241 | { | ||
242 | buf = buffer; | ||
243 | nread++; | ||
244 | } | ||
245 | } | ||
246 | status = stream_write (mbox->carrier, buf, nread, NULL); | ||
247 | if (status != 0) | ||
248 | return status ; | ||
249 | |||
250 | /* Register if we read a complete line. */ | ||
251 | was_complete_line = (nread && buf[nread - 1] == '\n') ? 1 : 0; | ||
252 | } | ||
253 | while (nread > 0); | ||
254 | |||
255 | /* New line separator for the next message. */ | ||
256 | return stream_write (mbox->carrier, &nl, 1, NULL); | ||
45 | } | 257 | } |
46 | 258 | ||
47 | int | 259 | int |
48 | mbox_append_hb (mbox_t mbox, const char *sep, stream_t hstream, | 260 | mbox_append_hb0 (mbox_t mbox, const char *sep, attribute_t attribute, |
49 | stream_t bstream) | 261 | int save_uidvalidity, stream_t hstream, stream_t bstream) |
50 | { | 262 | { |
263 | int status = 0; | ||
264 | |||
51 | if (mbox == NULL || hstream == NULL || bstream == NULL) | 265 | if (mbox == NULL || hstream == NULL || bstream == NULL) |
52 | return MU_ERROR_INVALID_PARAMETER; | 266 | return MU_ERROR_INVALID_PARAMETER; |
53 | (void)sep; | 267 | |
54 | return 0; | 268 | switch (mbox->state) |
269 | { | ||
270 | case MU_MBOX_NO_STATE: | ||
271 | { | ||
272 | off_t size = 0; | ||
273 | unsigned long uidvalidity; | ||
274 | unsigned long uidnext; | ||
275 | |||
276 | /* Get the uidvalidity for this mbox. */ | ||
277 | mbox_get_uidvalidity (mbox, &uidvalidity); | ||
278 | mbox_get_uidnext (mbox, &uidnext); | ||
279 | |||
280 | /* Grab the lock. */ | ||
281 | status = lockfile_lock (mbox->lockfile); | ||
282 | if (status != 0) | ||
283 | break; | ||
284 | |||
285 | /* Move to the end of the stream. */ | ||
286 | if ((status = stream_get_size (mbox->carrier, &size)) != 0 | ||
287 | || (status = stream_seek (mbox->carrier, size, | ||
288 | MU_STREAM_WHENCE_SET) != 0)) | ||
289 | break; | ||
290 | mbox->state = MU_MBOX_STATE_APPEND_SEPARATOR; | ||
291 | } | ||
292 | |||
293 | case MU_MBOX_STATE_APPEND_SEPARATOR: | ||
294 | { | ||
295 | status = mbox_append_separator (mbox, sep); | ||
296 | if (status != 0) | ||
297 | break; | ||
298 | mbox->state = MU_MBOX_STATE_APPEND_HEADER; | ||
299 | } | ||
300 | |||
301 | case MU_MBOX_STATE_APPEND_HEADER: | ||
302 | { | ||
303 | status = mbox_append_header (mbox, attribute, save_uidvalidity, hstream); | ||
304 | if (status != 0) | ||
305 | break; | ||
306 | mbox->state = MU_MBOX_STATE_APPEND_BODY; | ||
307 | } | ||
308 | |||
309 | case MU_MBOX_STATE_APPEND_BODY: | ||
310 | { | ||
311 | status = mbox_append_body (mbox, bstream); | ||
312 | if (status != 0) | ||
313 | break; | ||
314 | mbox->state = MU_MBOX_NO_STATE; | ||
315 | } | ||
316 | |||
317 | default: | ||
318 | break; | ||
319 | } | ||
320 | |||
321 | /* Maintain the lock if EAGAIN. */ | ||
322 | if (status != 0) | ||
323 | { | ||
324 | if (status != MU_ERROR_TRY_AGAIN) | ||
325 | { | ||
326 | mbox->state = MU_MBOX_NO_STATE; | ||
327 | lockfile_unlock (mbox->lockfile); | ||
328 | } | ||
329 | } | ||
330 | else | ||
331 | { | ||
332 | lockfile_unlock (mbox->lockfile); | ||
333 | mbox->uidnext++; | ||
334 | } | ||
335 | |||
336 | return status; | ||
337 | } | ||
338 | |||
339 | int | ||
340 | mbox_append (mbox_t mbox, const char *sep, attribute_t attribute, | ||
341 | stream_t stream) | ||
342 | { | ||
343 | return mbox_append_hb (mbox, sep, attribute, stream, stream); | ||
344 | } | ||
345 | |||
346 | int | ||
347 | mbox_append_hb (mbox_t mbox, const char *sep, attribute_t attribute, | ||
348 | stream_t hstream, stream_t bstream) | ||
349 | { | ||
350 | return mbox_append_hb0 (mbox, sep, attribute, 1, hstream, bstream); | ||
55 | } | 351 | } | ... | ... |
... | @@ -20,6 +20,7 @@ | ... | @@ -20,6 +20,7 @@ |
20 | #endif | 20 | #endif |
21 | 21 | ||
22 | #include <stdlib.h> | 22 | #include <stdlib.h> |
23 | #include <string.h> | ||
23 | 24 | ||
24 | #include <mailutils/error.h> | 25 | #include <mailutils/error.h> |
25 | #include <mailutils/refcount.h> | 26 | #include <mailutils/refcount.h> |
... | @@ -197,3 +198,49 @@ mbox_get_attribute (mbox_t mbox, unsigned int msgno, attribute_t *pattribute) | ... | @@ -197,3 +198,49 @@ mbox_get_attribute (mbox_t mbox, unsigned int msgno, attribute_t *pattribute) |
197 | } | 198 | } |
198 | return status; | 199 | return status; |
199 | } | 200 | } |
201 | |||
202 | int | ||
203 | mbox_attribute_to_status (attribute_t attribute, char *buf, size_t buflen, | ||
204 | size_t *pn) | ||
205 | { | ||
206 | char Status[32]; | ||
207 | char a[8]; | ||
208 | size_t i; | ||
209 | |||
210 | *Status = *a = '\0'; | ||
211 | |||
212 | if (attribute) | ||
213 | { | ||
214 | if (attribute_is_read (attribute)) | ||
215 | strcat (a, "R"); | ||
216 | if (attribute_is_seen (attribute)) | ||
217 | strcat (a, "O"); | ||
218 | if (attribute_is_answered (attribute)) | ||
219 | strcat (a, "A"); | ||
220 | if (attribute_is_deleted (attribute)) | ||
221 | strcat (a, "d"); | ||
222 | if (attribute_is_flagged (attribute)) | ||
223 | strcat (a, "F"); | ||
224 | } | ||
225 | |||
226 | if (*a != '\0') | ||
227 | { | ||
228 | strcpy (Status, "Status: "); | ||
229 | strcat (Status, a); | ||
230 | strcat (Status, "\n"); | ||
231 | } | ||
232 | |||
233 | if (buf && buflen) | ||
234 | { | ||
235 | *buf = '\0'; | ||
236 | strncpy (buf, Status, buflen - 1); | ||
237 | buf[buflen - 1] = '\0'; | ||
238 | i = strlen (buf); | ||
239 | } | ||
240 | else | ||
241 | i = strlen (Status); | ||
242 | |||
243 | if (pn) | ||
244 | *pn = i; | ||
245 | return 0; | ||
246 | } | ... | ... |
... | @@ -28,8 +28,10 @@ int | ... | @@ -28,8 +28,10 @@ int |
28 | mbox_changed_on_disk (mbox_t mbox) | 28 | mbox_changed_on_disk (mbox_t mbox) |
29 | { | 29 | { |
30 | int changed = 0; | 30 | int changed = 0; |
31 | /* Check if the mtime stamp changed, random modifications can give | 31 | |
32 | us back the same size. */ | 32 | /* If the modification time is greater then the access time, the file has |
33 | been modified since the last time it was accessed. This typically means | ||
34 | new mail or someone tempered with the mailbox. */ | ||
33 | if (mbox->carrier) | 35 | if (mbox->carrier) |
34 | { | 36 | { |
35 | int fd = -1; | 37 | int fd = -1; |
... | @@ -38,7 +40,7 @@ mbox_changed_on_disk (mbox_t mbox) | ... | @@ -38,7 +40,7 @@ mbox_changed_on_disk (mbox_t mbox) |
38 | struct stat statbuf; | 40 | struct stat statbuf; |
39 | if (fstat (fd, &statbuf) == 0) | 41 | if (fstat (fd, &statbuf) == 0) |
40 | { | 42 | { |
41 | if (difftime (mbox->mtime, statbuf.st_mtime) != 0) | 43 | if (difftime (statbuf.st_mtime, statbuf.st_atime) > 0) |
42 | changed = 1; | 44 | changed = 1; |
43 | } | 45 | } |
44 | } | 46 | } | ... | ... |
... | @@ -65,7 +65,6 @@ mbox_close (mbox_t mbox) | ... | @@ -65,7 +65,6 @@ mbox_close (mbox_t mbox) |
65 | mbox->umessages = NULL; | 65 | mbox->umessages = NULL; |
66 | mbox->umessages_count = 0; | 66 | mbox->umessages_count = 0; |
67 | mbox->size = 0; | 67 | mbox->size = 0; |
68 | mbox->mtime = 0; | ||
69 | mbox->uidvalidity = 0; | 68 | mbox->uidvalidity = 0; |
70 | mbox->uidnext = 0; | 69 | mbox->uidnext = 0; |
71 | if (mbox->filename) | 70 | if (mbox->filename) | ... | ... |
... | @@ -125,6 +125,7 @@ mbox_expunge (mbox_t mbox, int remove_deleted) | ... | @@ -125,6 +125,7 @@ mbox_expunge (mbox_t mbox, int remove_deleted) |
125 | int tmp_fd; | 125 | int tmp_fd; |
126 | char *tmp_name = NULL; | 126 | char *tmp_name = NULL; |
127 | mbox_t tmp_mbox = NULL; | 127 | mbox_t tmp_mbox = NULL; |
128 | size_t save_uidvalidity = 0; /* uidvalidity is save in the first message. */ | ||
128 | 129 | ||
129 | if (mbox == NULL) | 130 | if (mbox == NULL) |
130 | return MU_ERROR_INVALID_PARAMETER; | 131 | return MU_ERROR_INVALID_PARAMETER; |
... | @@ -167,7 +168,7 @@ mbox_expunge (mbox_t mbox, int remove_deleted) | ... | @@ -167,7 +168,7 @@ mbox_expunge (mbox_t mbox, int remove_deleted) |
167 | return status; | 168 | return status; |
168 | } | 169 | } |
169 | 170 | ||
170 | /* Must be flag CREATE if not the mailbox_open will try to mmap() | 171 | /* Must be flag CREATE if not the mailbox_open will/may try to mmap() |
171 | the file. */ | 172 | the file. */ |
172 | status = mbox_open (tmp_mbox, tmp_name, MU_STREAM_CREAT | MU_STREAM_RDWR); | 173 | status = mbox_open (tmp_mbox, tmp_name, MU_STREAM_CREAT | MU_STREAM_RDWR); |
173 | if (status != 0) | 174 | if (status != 0) |
... | @@ -195,7 +196,19 @@ mbox_expunge (mbox_t mbox, int remove_deleted) | ... | @@ -195,7 +196,19 @@ mbox_expunge (mbox_t mbox, int remove_deleted) |
195 | return status; | 196 | return status; |
196 | } | 197 | } |
197 | 198 | ||
198 | /* Critical section, we can not allowed signal here. */ | 199 | /* _Must_ have and updated view of the size of the mailbox. */ |
200 | status = mbox_changed_on_disk (mbox); | ||
201 | if (status != 0) | ||
202 | { | ||
203 | mbox_close (tmp_mbox); | ||
204 | mbox_destroy (&tmp_mbox); | ||
205 | remove (tmp_name); | ||
206 | free (tmp_name); | ||
207 | /* mu_error ("Failed to grab the lock\n"); */ | ||
208 | return status; | ||
209 | } | ||
210 | |||
211 | /* Critical section, can not allowed signal here. */ | ||
199 | sigemptyset (&signalset); | 212 | sigemptyset (&signalset); |
200 | sigaddset (&signalset, SIGTERM); | 213 | sigaddset (&signalset, SIGTERM); |
201 | sigaddset (&signalset, SIGHUP); | 214 | sigaddset (&signalset, SIGHUP); |
... | @@ -216,40 +229,50 @@ mbox_expunge (mbox_t mbox, int remove_deleted) | ... | @@ -216,40 +229,50 @@ mbox_expunge (mbox_t mbox, int remove_deleted) |
216 | /* Skip it, if mark for deletion. */ | 229 | /* Skip it, if mark for deletion. */ |
217 | if (remove_deleted && ATTRIBUTE_IS_DELETED (mum->attr_flags)) | 230 | if (remove_deleted && ATTRIBUTE_IS_DELETED (mum->attr_flags)) |
218 | { | 231 | { |
232 | /* We save the uidvalidity in the first message, if it is being | ||
233 | deleted we need to move the uidvalidity to the first available | ||
234 | (non-deleted) message. */ | ||
235 | if (i == save_uidvalidity) | ||
236 | { | ||
237 | save_uidvalidity = i + 1; | ||
238 | } | ||
219 | continue; | 239 | continue; |
220 | } | 240 | } |
221 | 241 | else | |
222 | { | 242 | { |
223 | stream_t hstream = NULL, bstream = NULL; | 243 | stream_t hstream = NULL, bstream = NULL; |
224 | char *sep = NULL; | 244 | attribute_t attribute = NULL; |
225 | /* The message was not instanciated, probably the dirty flag was | 245 | char *sep = NULL; |
226 | set by mbox_scan(), create one here. */ | 246 | /* The message was not instanciated, probably the dirty flag was |
227 | if (mum->separator == NULL || mum->header.stream == NULL | 247 | set by mbox_scan(), create one here. */ |
228 | || mum->body.stream == NULL) | 248 | if (mum->separator == NULL || mum->header.stream == NULL |
229 | { | 249 | || mum->body.stream == NULL || mum->attribute == NULL) |
230 | if (mbox_get_hstream (mbox, i + 1, &hstream) != 0 | 250 | { |
231 | || mbox_get_bstream (mbox, i + 1, &bstream) != 0 | 251 | if (mbox_get_hstream (mbox, i + 1, &hstream) != 0 |
232 | || mbox_get_separator (mbox, i + 1, &sep) != 0) | 252 | || mbox_get_bstream (mbox, i + 1, &bstream) != 0 |
233 | { | 253 | || mbox_get_separator (mbox, i + 1, &sep) != 0) |
234 | /* mu_error ("Error expunge:%d", __LINE__); */ | 254 | { |
235 | goto bailout0; | 255 | /* mu_error ("Error expunge:%d", __LINE__); */ |
236 | } | 256 | goto bailout0; |
237 | } | 257 | } |
238 | status = mbox_append_hb (tmp_mbox, mum->separator, mum->header.stream, | 258 | } |
239 | mum->body.stream); | 259 | status = mbox_append_hb0 (tmp_mbox, mum->separator, mum->attribute, |
240 | if (sep) | 260 | save_uidvalidity, mum->header.stream, |
241 | free (sep); | 261 | mum->body.stream); |
242 | stream_destroy (&hstream); | 262 | if (sep) |
243 | stream_destroy (&bstream); | 263 | free (sep); |
244 | if (status != 0) | 264 | stream_destroy (&hstream); |
245 | { | 265 | stream_destroy (&bstream); |
246 | /* mu_error ("Error expunge:%d: %s", __LINE__, | 266 | attribute_destroy (&attribute); |
247 | strerror (status)); */ | 267 | if (status != 0) |
248 | goto bailout0; | 268 | { |
249 | } | 269 | /* mu_error ("Error expunge:%d: %s", __LINE__, |
250 | /* Clear the dirty bits. */ | 270 | strerror (status)); */ |
251 | mum->attr_flags &= ~MU_ATTRIBUTE_MODIFIED; | 271 | goto bailout0; |
252 | } | 272 | } |
273 | /* Clear the dirty bits. */ | ||
274 | mum->attr_flags &= ~MU_ATTRIBUTE_MODIFIED; | ||
275 | } | ||
253 | } /* for (;;) */ | 276 | } /* for (;;) */ |
254 | 277 | ||
255 | /* Caution: before ftruncate()ing the file see | 278 | /* Caution: before ftruncate()ing the file see |
... | @@ -266,7 +289,7 @@ mbox_expunge (mbox_t mbox, int remove_deleted) | ... | @@ -266,7 +289,7 @@ mbox_expunge (mbox_t mbox, int remove_deleted) |
266 | if (len > 0) | 289 | if (len > 0) |
267 | { | 290 | { |
268 | stream_seek (mbox->carrier, mbox->size, MU_STREAM_WHENCE_SET); | 291 | stream_seek (mbox->carrier, mbox->size, MU_STREAM_WHENCE_SET); |
269 | stream_seek (mbox->carrier, tmp_mbox->size, MU_STREAM_WHENCE_SET); | 292 | stream_seek (tmp_mbox->carrier, tmp_mbox->size, MU_STREAM_WHENCE_SET); |
270 | while ((status = stream_read (mbox->carrier, buffer, | 293 | while ((status = stream_read (mbox->carrier, buffer, |
271 | sizeof buffer, &n)) == 0 && n > 0) | 294 | sizeof buffer, &n)) == 0 && n > 0) |
272 | { | 295 | { |
... | @@ -345,11 +368,22 @@ mbox_expunge (mbox_t mbox, int remove_deleted) | ... | @@ -345,11 +368,22 @@ mbox_expunge (mbox_t mbox, int remove_deleted) |
345 | size_t dlast; | 368 | size_t dlast; |
346 | for (j = dirty, dlast = mbox->messages_count - 1; j <= dlast; j++) | 369 | for (j = dirty, dlast = mbox->messages_count - 1; j <= dlast; j++) |
347 | { | 370 | { |
348 | /* Clear all the references, any attach messages been already | 371 | /* Clear all the references to streams. */ |
349 | destroy above. */ | ||
350 | mum = mbox->umessages[j]; | 372 | mum = mbox->umessages[j]; |
351 | if (remove_deleted && ATTRIBUTE_IS_DELETED (mum->attr_flags)) | 373 | if (remove_deleted && ATTRIBUTE_IS_DELETED (mum->attr_flags)) |
352 | { | 374 | { |
375 | if (mum->separator) | ||
376 | free (mum->separator); | ||
377 | mum->separator = NULL; | ||
378 | if (mum->attribute) | ||
379 | attribute_destroy (&mum->attribute); | ||
380 | if (mum->header.stream) | ||
381 | stream_destroy (&mum->header.stream); | ||
382 | if (mum->body.stream) | ||
383 | stream_destroy (&mum->body.stream); | ||
384 | mbox_hcache_free (mbox, i + 1); | ||
385 | /* memset (mum, 0, sizeof (*mum)); */ | ||
386 | |||
353 | if ((j + 1) <= dlast) | 387 | if ((j + 1) <= dlast) |
354 | { | 388 | { |
355 | /* Move all the pointers up. So the message pointer | 389 | /* Move all the pointers up. So the message pointer |
... | @@ -361,8 +395,6 @@ mbox_expunge (mbox_t mbox, int remove_deleted) | ... | @@ -361,8 +395,6 @@ mbox_expunge (mbox_t mbox, int remove_deleted) |
361 | mum->body.start = mum->body.end = 0; | 395 | mum->body.start = mum->body.end = 0; |
362 | mum->header.lines = mum->body.lines = 0; | 396 | mum->header.lines = mum->body.lines = 0; |
363 | #endif | 397 | #endif |
364 | mbox_hcache_free (mbox, i + 1); | ||
365 | memset (mum, 0, sizeof (*mum)); | ||
366 | /* We are not free()ing the useless mum, but instead | 398 | /* We are not free()ing the useless mum, but instead |
367 | we put it back in the pool, to be reuse. */ | 399 | we put it back in the pool, to be reuse. */ |
368 | mbox->umessages[dlast] = mum; | 400 | mbox->umessages[dlast] = mum; |
... | @@ -371,16 +403,10 @@ mbox_expunge (mbox_t mbox, int remove_deleted) | ... | @@ -371,16 +403,10 @@ mbox_expunge (mbox_t mbox, int remove_deleted) |
371 | gets cleared to. */ | 403 | gets cleared to. */ |
372 | mum = mbox->umessages[j]; | 404 | mum = mbox->umessages[j]; |
373 | } | 405 | } |
374 | else | ||
375 | { | ||
376 | mbox_hcache_free (mbox, i + 1); | ||
377 | memset (mum, 0, sizeof (*mum)); | ||
378 | } | ||
379 | } | 406 | } |
380 | mum->from_ = mum->header.start = 0; | 407 | mum->from_ = mum->header.start = 0; |
381 | mum->body.start = mum->body.end = 0; | 408 | mum->body.start = mum->body.end = 0; |
382 | mum->header.lines = mum->body.lines = 0; | 409 | mum->header.lines = mum->body.lines = 0; |
383 | mbox_hcache_free (mbox, i + 1); | ||
384 | } | 410 | } |
385 | /* This is should reset the messages_count, the last argument 0 means | 411 | /* This is should reset the messages_count, the last argument 0 means |
386 | not to send event notification. */ | 412 | not to send event notification. */ | ... | ... |
... | @@ -150,7 +150,6 @@ mbox_scan (mbox_t mbox, unsigned int msgno, unsigned int *pcount, int do_notif) | ... | @@ -150,7 +150,6 @@ mbox_scan (mbox_t mbox, unsigned int msgno, unsigned int *pcount, int do_notif) |
150 | reality if expunge. */ | 150 | reality if expunge. */ |
151 | /* mbox->size = statbuf.st_size; */ | 151 | /* mbox->size = statbuf.st_size; */ |
152 | file_size = statbuf.st_size; | 152 | file_size = statbuf.st_size; |
153 | mbox->mtime = statbuf.st_mtime; | ||
154 | } | 153 | } |
155 | else | 154 | else |
156 | status = MU_ERROR_IO; | 155 | status = MU_ERROR_IO; | ... | ... |
-
Please register or sign in to post a comment