Commit 66dc09fd 66dc09fdf52d28b533842f68e4d086fafae93bfe by Alain Magloire

Implemented mbox_append () first draft. Things are still very unstable.

1 parent 663ecdf5
1 2001-09-26 Alain Magloire
2
3 * mailbox2/mbox/mbox_append.c: Implemented, first draft.
4
1 2001-09-23 Alain Magloire 5 2001-09-23 Alain Magloire
2 6
3 First draft of the mailbox/mbox2. Not functional. 7 First draft of the mailbox/mbox2. Not functional.
......
...@@ -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,16 +229,24 @@ mbox_expunge (mbox_t mbox, int remove_deleted) ...@@ -216,16 +229,24 @@ 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;
244 attribute_t attribute = NULL;
224 char *sep = NULL; 245 char *sep = NULL;
225 /* The message was not instanciated, probably the dirty flag was 246 /* The message was not instanciated, probably the dirty flag was
226 set by mbox_scan(), create one here. */ 247 set by mbox_scan(), create one here. */
227 if (mum->separator == NULL || mum->header.stream == NULL 248 if (mum->separator == NULL || mum->header.stream == NULL
228 || mum->body.stream == NULL) 249 || mum->body.stream == NULL || mum->attribute == NULL)
229 { 250 {
230 if (mbox_get_hstream (mbox, i + 1, &hstream) != 0 251 if (mbox_get_hstream (mbox, i + 1, &hstream) != 0
231 || mbox_get_bstream (mbox, i + 1, &bstream) != 0 252 || mbox_get_bstream (mbox, i + 1, &bstream) != 0
...@@ -235,12 +256,14 @@ mbox_expunge (mbox_t mbox, int remove_deleted) ...@@ -235,12 +256,14 @@ mbox_expunge (mbox_t mbox, int remove_deleted)
235 goto bailout0; 256 goto bailout0;
236 } 257 }
237 } 258 }
238 status = mbox_append_hb (tmp_mbox, mum->separator, mum->header.stream, 259 status = mbox_append_hb0 (tmp_mbox, mum->separator, mum->attribute,
260 save_uidvalidity, mum->header.stream,
239 mum->body.stream); 261 mum->body.stream);
240 if (sep) 262 if (sep)
241 free (sep); 263 free (sep);
242 stream_destroy (&hstream); 264 stream_destroy (&hstream);
243 stream_destroy (&bstream); 265 stream_destroy (&bstream);
266 attribute_destroy (&attribute);
244 if (status != 0) 267 if (status != 0)
245 { 268 {
246 /* mu_error ("Error expunge:%d: %s", __LINE__, 269 /* mu_error ("Error expunge:%d: %s", __LINE__,
...@@ -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;
......