Commit 24d3722e 24d3722ecab73da942988dc586ebfc28748fb873 by Alain Magloire

Cleanup again and all of this done with one hand !!!

We're moving closer to cleaning the repository and using
autoconf and all.  But my keyboard quota is almost expired.
1 parent 75a14dc5
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
23 #include <errno.h> 23 #include <errno.h>
24 24
25 int 25 int
26 attribute_create (attribute_t *pattr) 26 attribute_create (attribute_t *pattr, void *owner)
27 { 27 {
28 attribute_t attr; 28 attribute_t attr;
29 if (pattr == NULL) 29 if (pattr == NULL)
...@@ -31,16 +31,19 @@ attribute_create (attribute_t *pattr) ...@@ -31,16 +31,19 @@ attribute_create (attribute_t *pattr)
31 attr = calloc (1, sizeof(*attr)); 31 attr = calloc (1, sizeof(*attr));
32 if (attr == NULL) 32 if (attr == NULL)
33 return ENOMEM; 33 return ENOMEM;
34 attr->owner = owner;
34 *pattr = attr; 35 *pattr = attr;
35 return 0; 36 return 0;
36 } 37 }
37 38
38 void 39 void
39 attribute_destroy (attribute_t *pattr) 40 attribute_destroy (attribute_t *pattr, void *owner)
40 { 41 {
41 if (pattr && *pattr) 42 if (pattr && *pattr)
42 { 43 {
43 free (*pattr); 44 attribute_t attr = *pattr;
45 if (attr->owner != owner)
46 free (*pattr);
44 /* loose the link */ 47 /* loose the link */
45 *pattr = NULL; 48 *pattr = NULL;
46 } 49 }
...@@ -48,68 +51,144 @@ attribute_destroy (attribute_t *pattr) ...@@ -48,68 +51,144 @@ attribute_destroy (attribute_t *pattr)
48 } 51 }
49 52
50 int 53 int
54 attribute_get_flags (attribute_t attr, int *pflags)
55 {
56 if (attr->_get_flags)
57 return attr->_get_flags (attr, pflags);
58 if (pflags)
59 *pflags = attr->flags;
60 return 0;
61 }
62
63 int
64 attribute_set_flags (attribute_t attr, int flags)
65 {
66 if (attr->_set_flags)
67 return attr->_set_flags (attr, flags);
68 attr->flags |= flags;
69 return 0;
70 }
71
72 int
73 attribute_set_get_flags (attribute_t attr, int (*_get_flags)
74 (attribute_t, int *), void *owner)
75 {
76 if (attr == NULL)
77 return EINVAL;
78 if (attr->owner != owner)
79 return EACCES;
80 attr->_get_flags = _get_flags;
81 return 0;
82 }
83
84 int
85 attribute_set_set_flags (attribute_t attr, int (*_set_flags)
86 (attribute_t, int), void *owner)
87 {
88 if (attr == NULL)
89 return EINVAL;
90 if (attr->owner != owner)
91 return EACCES;
92 attr->_set_flags = _set_flags;
93 return 0;
94 }
95
96 int
97 attribute_set_unset_flags (attribute_t attr, int (*_unset_flags)
98 (attribute_t, int), void *owner)
99 {
100 if (attr == NULL)
101 return EINVAL;
102 if (attr->owner != owner)
103 return EACCES;
104 attr->_unset_flags = _unset_flags;
105 return 0;
106 }
107
108 int
51 attribute_set_seen (attribute_t attr) 109 attribute_set_seen (attribute_t attr)
52 { 110 {
111 int status = 0;
53 if (attr == NULL) 112 if (attr == NULL)
54 return EINVAL; 113 return EINVAL;
55 attr->flag |= MU_ATTRIBUTE_SEEN; 114 if (attr->_get_flags)
115 status = attr->_get_flags (attr, &(attr->flags));
116 attr->flags |= MU_ATTRIBUTE_SEEN;
56 return 0; 117 return 0;
57 } 118 }
58 119
59 int 120 int
60 attribute_set_answered (attribute_t attr) 121 attribute_set_answered (attribute_t attr)
61 { 122 {
123 int status = 0;
62 if (attr == NULL) 124 if (attr == NULL)
63 return EINVAL; 125 return EINVAL;
64 attr->flag |= MU_ATTRIBUTE_ANSWERED; 126 if (attr->_get_flags)
127 status = attr->_get_flags (attr, &(attr->flags));
128 attr->flags |= MU_ATTRIBUTE_ANSWERED;
65 return 0; 129 return 0;
66 } 130 }
67 131
68 int 132 int
69 attribute_set_flagged (attribute_t attr) 133 attribute_set_flagged (attribute_t attr)
70 { 134 {
135 int status = 0;
71 if (attr == NULL) 136 if (attr == NULL)
72 return EINVAL; 137 return EINVAL;
73 attr->flag |= MU_ATTRIBUTE_FLAGGED; 138 if (attr->_get_flags)
139 status = attr->_get_flags (attr, &(attr->flags));
140 attr->flags |= MU_ATTRIBUTE_FLAGGED;
74 return 0; 141 return 0;
75 } 142 }
76 143
77 int 144 int
78 attribute_set_read (attribute_t attr) 145 attribute_set_read (attribute_t attr)
79 { 146 {
147 int status = 0;
80 if (attr == NULL) 148 if (attr == NULL)
81 return EINVAL; 149 return EINVAL;
82 attr->flag |= MU_ATTRIBUTE_READ; 150 if (attr->_get_flags)
151 status = attr->_get_flags (attr, &(attr->flags));
152 attr->flags |= MU_ATTRIBUTE_READ;
83 return 0; 153 return 0;
84 } 154 }
85 155
86 int 156 int
87 attribute_set_deleted (attribute_t attr) 157 attribute_set_deleted (attribute_t attr)
88 { 158 {
159 int status = 0;
89 if (attr == NULL) 160 if (attr == NULL)
90 return EINVAL; 161 return EINVAL;
91 attr->flag |= MU_ATTRIBUTE_DELETED; 162 if (attr->_get_flags)
163 status = attr->_get_flags (attr, &(attr->flags));
164 attr->flags |= MU_ATTRIBUTE_DELETED;
92 return 0; 165 return 0;
93 } 166 }
94 167
95 int 168 int
96 attribute_set_draft (attribute_t attr) 169 attribute_set_draft (attribute_t attr)
97 { 170 {
171 int status = 0;
98 if (attr == NULL) 172 if (attr == NULL)
99 return EINVAL; 173 return EINVAL;
100 attr->flag |= MU_ATTRIBUTE_DRAFT; 174 if (attr->_get_flags)
175 status = attr->_get_flags (attr, &(attr->flags));
176 attr->flags |= MU_ATTRIBUTE_DRAFT;
101 return 0; 177 return 0;
102 } 178 }
103 179
104 int 180 int
105 attribute_set_recent (attribute_t attr) 181 attribute_set_recent (attribute_t attr)
106 { 182 {
183 int status = 0;
107 if (attr == NULL) 184 if (attr == NULL)
108 return EINVAL; 185 return EINVAL;
186 if (attr->_get_flags)
187 status = attr->_get_flags (attr, &(attr->flags));
109 if (attr == NULL) 188 if (attr == NULL)
110 { 189 {
111 attr->flag &= ~MU_ATTRIBUTE_READ; 190 attr->flags &= ~MU_ATTRIBUTE_READ;
112 attr->flag &= ~MU_ATTRIBUTE_SEEN; 191 attr->flags &= ~MU_ATTRIBUTE_SEEN;
113 return 0; 192 return 0;
114 } 193 }
115 return EACCES; 194 return EACCES;
...@@ -118,131 +197,176 @@ attribute_set_recent (attribute_t attr) ...@@ -118,131 +197,176 @@ attribute_set_recent (attribute_t attr)
118 int 197 int
119 attribute_is_seen (attribute_t attr) 198 attribute_is_seen (attribute_t attr)
120 { 199 {
200 int status = 0;
121 if (attr == NULL) 201 if (attr == NULL)
122 return 0; 202 return 0;
123 return attr->flag & MU_ATTRIBUTE_SEEN; 203 if (attr->_get_flags)
204 status = attr->_get_flags (attr, &(attr->flags));
205 return attr->flags & MU_ATTRIBUTE_SEEN;
124 } 206 }
125 207
126 int 208 int
127 attribute_is_answered (attribute_t attr) 209 attribute_is_answered (attribute_t attr)
128 { 210 {
211 int status = 0;
129 if (attr == NULL) 212 if (attr == NULL)
130 return 0; 213 return 0;
131 return attr->flag & MU_ATTRIBUTE_ANSWERED; 214 if (attr->_get_flags)
215 status = attr->_get_flags (attr, &(attr->flags));
216 return attr->flags & MU_ATTRIBUTE_ANSWERED;
132 } 217 }
133 218
134 int 219 int
135 attribute_is_flagged (attribute_t attr) 220 attribute_is_flagged (attribute_t attr)
136 { 221 {
222 int status = 0;
137 if (attr == NULL) 223 if (attr == NULL)
138 return 0; 224 return 0;
139 return attr->flag & MU_ATTRIBUTE_FLAGGED; 225 if (attr->_get_flags)
226 status = attr->_get_flags (attr, &(attr->flags));
227 return attr->flags & MU_ATTRIBUTE_FLAGGED;
140 } 228 }
141 229
142 int 230 int
143 attribute_is_read (attribute_t attr) 231 attribute_is_read (attribute_t attr)
144 { 232 {
233 int status = 0;
145 if (attr == NULL) 234 if (attr == NULL)
146 return 0; 235 return 0;
147 return attr->flag & MU_ATTRIBUTE_READ; 236 if (attr->_get_flags)
237 status = attr->_get_flags (attr, &(attr->flags));
238 return attr->flags & MU_ATTRIBUTE_READ;
148 } 239 }
149 240
150 int 241 int
151 attribute_is_deleted (attribute_t attr) 242 attribute_is_deleted (attribute_t attr)
152 { 243 {
244 int status = 0;
153 if (attr == NULL) 245 if (attr == NULL)
154 return 0; 246 return 0;
155 return attr->flag & MU_ATTRIBUTE_DELETED; 247 if (attr->_get_flags)
248 status = attr->_get_flags (attr, &(attr->flags));
249 return attr->flags & MU_ATTRIBUTE_DELETED;
156 } 250 }
157 251
158 int 252 int
159 attribute_is_draft (attribute_t attr) 253 attribute_is_draft (attribute_t attr)
160 { 254 {
255 int status = 0;
161 if (attr == NULL) 256 if (attr == NULL)
162 return 0; 257 return 0;
163 return attr->flag & MU_ATTRIBUTE_DRAFT; 258 if (attr->_get_flags)
259 status = attr->_get_flags (attr, &(attr->flags));
260 return attr->flags & MU_ATTRIBUTE_DRAFT;
164 } 261 }
165 262
166 int 263 int
167 attribute_is_recent (attribute_t attr) 264 attribute_is_recent (attribute_t attr)
168 { 265 {
266 int status = 0;
169 if (attr == NULL) 267 if (attr == NULL)
170 return 0; 268 return 0;
269 if (attr->_get_flags)
270 status = attr->_get_flags (attr, &(attr->flags));
171 /* something is recent when it is not read and not seen. */ 271 /* something is recent when it is not read and not seen. */
172 return (attr->flag == 0 272 return (attr->flags == 0
173 || ! ((attr->flag & MU_ATTRIBUTE_SEEN) 273 || ! ((attr->flags & MU_ATTRIBUTE_SEEN)
174 && (attr->flag & MU_ATTRIBUTE_READ))); 274 && (attr->flags & MU_ATTRIBUTE_READ)));
175 } 275 }
176 276
177 int 277 int
178 attribute_unset_seen (attribute_t attr) 278 attribute_unset_seen (attribute_t attr)
179 { 279 {
280 int status = 0;
180 if (attr == NULL) 281 if (attr == NULL)
181 return 0; 282 return 0;
182 attr->flag &= ~MU_ATTRIBUTE_SEEN; 283 if (attr->_unset_flags)
183 return 0; 284 status = attr->_unset_flags (attr, MU_ATTRIBUTE_SEEN);
285 attr->flags &= ~MU_ATTRIBUTE_SEEN;
286 return status;
184 } 287 }
185 288
186 int 289 int
187 attribute_unset_answered (attribute_t attr) 290 attribute_unset_answered (attribute_t attr)
188 { 291 {
292 int status = 0;
189 if (attr == NULL) 293 if (attr == NULL)
190 return 0; 294 return 0;
191 attr->flag &= ~MU_ATTRIBUTE_ANSWERED; 295 if (attr->_unset_flags)
192 return 0; 296 status = attr->_unset_flags (attr, MU_ATTRIBUTE_ANSWERED);
297 attr->flags &= ~MU_ATTRIBUTE_ANSWERED;
298 return status;
193 } 299 }
194 300
195 int 301 int
196 attribute_unset_flagged (attribute_t attr) 302 attribute_unset_flagged (attribute_t attr)
197 { 303 {
304 int status = 0;
198 if (attr == NULL) 305 if (attr == NULL)
199 return 0; 306 return 0;
200 attr->flag &= ~MU_ATTRIBUTE_FLAGGED; 307 if (attr->_unset_flags)
201 return 0; 308 status = attr->_unset_flags (attr, MU_ATTRIBUTE_FLAGGED);
309 attr->flags &= ~MU_ATTRIBUTE_FLAGGED;
310 return status;
202 } 311 }
203 312
204 int 313 int
205 attribute_unset_read (attribute_t attr) 314 attribute_unset_read (attribute_t attr)
206 { 315 {
316 int status = 0;
207 if (attr == NULL) 317 if (attr == NULL)
208 return 0; 318 return 0;
209 attr->flag &= ~MU_ATTRIBUTE_READ; 319 if (attr->_unset_flags)
210 return 0; 320 status = attr->_unset_flags (attr, MU_ATTRIBUTE_READ);
321 attr->flags &= ~MU_ATTRIBUTE_READ;
322 return status;
211 } 323 }
212 324
213 int 325 int
214 attribute_unset_deleted (attribute_t attr) 326 attribute_unset_deleted (attribute_t attr)
215 { 327 {
328 int status = 0;
216 if (attr == NULL) 329 if (attr == NULL)
217 return 0; 330 return 0;
218 attr->flag &= ~MU_ATTRIBUTE_DELETED; 331 if (attr->_unset_flags)
219 return 0; 332 status = attr->_unset_flags (attr, MU_ATTRIBUTE_DELETED);
333 attr->flags &= ~MU_ATTRIBUTE_DELETED;
334 return status;
220 } 335 }
221 336
222 int 337 int
223 attribute_unset_draft (attribute_t attr) 338 attribute_unset_draft (attribute_t attr)
224 { 339 {
340 int status = 0;
225 if (attr == NULL) 341 if (attr == NULL)
226 return 0; 342 return 0;
227 attr->flag &= ~MU_ATTRIBUTE_DRAFT; 343 if (attr->_unset_flags)
228 return 0; 344 status = attr->_unset_flags (attr, MU_ATTRIBUTE_DRAFT);
345 attr->flags &= ~MU_ATTRIBUTE_DRAFT;
346 return status;
229 } 347 }
230 348
231 int 349 int
232 attribute_unset_recent (attribute_t attr) 350 attribute_unset_recent (attribute_t attr)
233 { 351 {
352 int status = 0;
234 if (attr == NULL) 353 if (attr == NULL)
235 return 0; 354 return 0;
236 attr->flag |= MU_ATTRIBUTE_SEEN; 355 if (attr->_unset_flags)
237 return 0; 356 status = attr->_unset_flags (attr, MU_ATTRIBUTE_SEEN);
357 attr->flags |= MU_ATTRIBUTE_SEEN;
358 return status;
238 } 359 }
239 360
240 int 361 int
241 attribute_is_equal (attribute_t attr, attribute_t attr2) 362 attribute_is_equal (attribute_t attr, attribute_t attr2)
242 { 363 {
364 int status = 0;
243 if (attr == NULL || attr2 == NULL) 365 if (attr == NULL || attr2 == NULL)
244 return 0; 366 return 0;
245 return attr->flag == attr2->flag; 367 if (attr->_get_flags)
368 status = attr->_get_flags (attr, &(attr->flags));
369 return attr->flags == attr2->flags;
246 } 370 }
247 371
248 int 372 int
...@@ -255,14 +379,12 @@ attribute_copy (attribute_t dest, attribute_t src) ...@@ -255,14 +379,12 @@ attribute_copy (attribute_t dest, attribute_t src)
255 } 379 }
256 380
257 int 381 int
258 string_to_attribute (const char *buffer, attribute_t *pattr) 382 string_to_flags (const char *buffer, int *pflags)
259 { 383 {
260 const char *sep; 384 const char *sep;
261 int status;
262 385
263 status = attribute_create (pattr); 386 if (pflags == NULL)
264 if (status != 0) 387 return EINVAL;
265 return status;
266 388
267 /* Set the attribute */ 389 /* Set the attribute */
268 if (strncasecmp (buffer, "Status:", 7) == 0) 390 if (strncasecmp (buffer, "Status:", 7) == 0)
...@@ -271,22 +393,22 @@ string_to_attribute (const char *buffer, attribute_t *pattr) ...@@ -271,22 +393,22 @@ string_to_attribute (const char *buffer, attribute_t *pattr)
271 sep++; 393 sep++;
272 } 394 }
273 else 395 else
274 sep = buffer; 396 return EINVAL;
275 397
276 while (*sep == ' ') sep++; /* glob spaces */ 398 while (*sep == ' ') sep++; /* glob spaces */
277 if (strchr (sep, 'R') != NULL || strchr (sep, 'r') != NULL) 399 if (strchr (sep, 'R') != NULL || strchr (sep, 'r') != NULL)
278 attribute_set_read (*pattr); 400 *pflags |= MU_ATTRIBUTE_READ;
279 if (strchr (sep, 'O') != NULL || strchr (sep, 'o') != NULL) 401 if (strchr (sep, 'O') != NULL || strchr (sep, 'o') != NULL)
280 attribute_set_seen (*pattr); 402 *pflags |= MU_ATTRIBUTE_SEEN;
281 if (strchr (sep, 'A') != NULL || strchr (sep, 'a') != NULL) 403 if (strchr (sep, 'A') != NULL || strchr (sep, 'a') != NULL)
282 attribute_set_answered (*pattr); 404 *pflags |= MU_ATTRIBUTE_ANSWERED;
283 if (strchr (sep, 'F') != NULL || strchr (sep, 'f') != NULL) 405 if (strchr (sep, 'F') != NULL || strchr (sep, 'f') != NULL)
284 attribute_set_flagged (*pattr); 406 *pflags |= MU_ATTRIBUTE_FLAGGED;
285 return 0; 407 return 0;
286 } 408 }
287 409
288 int 410 int
289 attribute_to_string (attribute_t attr, char *buffer, size_t len, size_t *pn) 411 flags_to_string (int flags, char *buffer, size_t len, size_t *pn)
290 { 412 {
291 char status[32]; 413 char status[32];
292 char a[8]; 414 char a[8];
...@@ -294,14 +416,16 @@ attribute_to_string (attribute_t attr, char *buffer, size_t len, size_t *pn) ...@@ -294,14 +416,16 @@ attribute_to_string (attribute_t attr, char *buffer, size_t len, size_t *pn)
294 416
295 *status = *a = '\0'; 417 *status = *a = '\0';
296 418
297 if (attribute_is_seen (attr)) 419 if (flags & MU_ATTRIBUTE_SEEN)
298 strcat (a, "R"); 420 strcat (a, "R");
299 if (attribute_is_answered (attr)) 421 if (flags & MU_ATTRIBUTE_ANSWERED)
300 strcat (a, "A"); 422 strcat (a, "A");
301 if (attribute_is_flagged (attr)) 423 if (flags & MU_ATTRIBUTE_FLAGGED)
302 strcat (a, "F"); 424 strcat (a, "F");
303 if (attribute_is_read (attr)) 425 if (flags & MU_ATTRIBUTE_READ)
304 strcat (a, "O"); 426 strcat (a, "O");
427 if (flags & MU_ATTRIBUTE_DELETED)
428 strcat (a, "d");
305 429
306 if (*a != '\0') 430 if (*a != '\0')
307 { 431 {
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
20 # include "config.h" 20 # include "config.h"
21 #endif 21 #endif
22 22
23 #include <header.h> 23 #include <header0.h>
24 #include <io0.h> 24 #include <io0.h>
25 #include <string.h> 25 #include <string.h>
26 #include <stdlib.h> 26 #include <stdlib.h>
...@@ -33,30 +33,6 @@ static int header_read (stream_t is, char *buf, size_t buflen, ...@@ -33,30 +33,6 @@ static int header_read (stream_t is, char *buf, size_t buflen,
33 static int header_write (stream_t os, const char *buf, size_t buflen, 33 static int header_write (stream_t os, const char *buf, size_t buflen,
34 off_t off, size_t *pnwrite); 34 off_t off, size_t *pnwrite);
35 35
36 struct _hdr
37 {
38 char *fn;
39 char *fn_end;
40 char *fv;
41 char *fv_end;
42 };
43
44 struct _header
45 {
46 /* Owner. */
47 void *owner;
48 /* Data. */
49 char *blurb;
50 size_t blurb_len;
51 size_t hdr_count;
52 struct _hdr *hdr;
53
54 /* Streams. */
55 stream_t stream;
56 int (*_get_value) __P ((header_t, const char *, char *, size_t , size_t *));
57
58 };
59
60 int 36 int
61 header_create (header_t *ph, const char *blurb, size_t len, void *owner) 37 header_create (header_t *ph, const char *blurb, size_t len, void *owner)
62 { 38 {
...@@ -66,6 +42,7 @@ header_create (header_t *ph, const char *blurb, size_t len, void *owner) ...@@ -66,6 +42,7 @@ header_create (header_t *ph, const char *blurb, size_t len, void *owner)
66 return ENOMEM; 42 return ENOMEM;
67 h->owner = owner; 43 h->owner = owner;
68 44
45 /* Ignore the return value. */
69 header_parse (h, blurb, len); 46 header_parse (h, blurb, len);
70 47
71 *ph = h; 48 *ph = h;
...@@ -83,8 +60,10 @@ header_destroy (header_t *ph, void *owner) ...@@ -83,8 +60,10 @@ header_destroy (header_t *ph, void *owner)
83 if (h->owner == owner) 60 if (h->owner == owner)
84 { 61 {
85 stream_destroy (&(h->stream), h); 62 stream_destroy (&(h->stream), h);
86 free (h->hdr); 63 if (h->hdr)
87 free (h->blurb); 64 free (h->hdr);
65 if (h->blurb)
66 free (h->blurb);
88 free (h); 67 free (h);
89 } 68 }
90 *ph = NULL; 69 *ph = NULL;
...@@ -207,8 +186,7 @@ header_parse (header_t header, const char *blurb, int len) ...@@ -207,8 +186,7 @@ header_parse (header_t header, const char *blurb, int len)
207 } 186 }
208 187
209 /* FIXME: grossly inneficient, to many copies and reallocating. 188 /* FIXME: grossly inneficient, to many copies and reallocating.
210 * This all header business need a good rewrite. 189 This all header business need a good rewrite. */
211 */
212 int 190 int
213 header_set_value (header_t header, const char *fn, const char *fv, int replace) 191 header_set_value (header_t header, const char *fn, const char *fv, int replace)
214 { 192 {
...@@ -218,11 +196,14 @@ header_set_value (header_t header, const char *fn, const char *fv, int replace) ...@@ -218,11 +196,14 @@ header_set_value (header_t header, const char *fn, const char *fv, int replace)
218 if (header == NULL || fn == NULL || fv == NULL) 196 if (header == NULL || fn == NULL || fv == NULL)
219 return EINVAL; 197 return EINVAL;
220 198
221 /* Easy approach: if replace, overwrite the field-{namve,value} 199 /* Try to fill out the buffer, if we know how. */
222 and readjust the pointers by calling header_parse () 200 if (header->_set_value != NULL)
223 this is wastefull, we're just fragmenting the memory 201 return header->_set_value (header, fn, fv, replace);
224 it can be done better. But that may imply a rewite of the headers 202
225 So for another day. */ 203 /* Easy approach: if replace, overwrite the field-{name,value} and readjust
204 the pointers by calling header_parse () this is wastefull, we're just
205 fragmenting the memory it can be done better. But that may imply a
206 rewite of the headers So for another day. */
226 if (replace) 207 if (replace)
227 { 208 {
228 size_t name_len; 209 size_t name_len;
...@@ -251,8 +232,8 @@ header_set_value (header_t header, const char *fn, const char *fv, int replace) ...@@ -251,8 +232,8 @@ header_set_value (header_t header, const char *fn, const char *fv, int replace)
251 } 232 }
252 } 233 }
253 234
254 /* Replacing was taking care of above now just add to 235 /* Replacing was taking care of above now just add to the end the new
255 the end the new header. Really not cute. */ 236 header. Really not cute. */
256 len = strlen (fn) + strlen (fv) + 1 + 1 + 1 + 1; 237 len = strlen (fn) + strlen (fv) + 1 + 1 + 1 + 1;
257 blurb = calloc (header->blurb_len + len, 1); 238 blurb = calloc (header->blurb_len + len, 1);
258 if (blurb == NULL) 239 if (blurb == NULL)
...@@ -266,20 +247,6 @@ header_set_value (header_t header, const char *fn, const char *fv, int replace) ...@@ -266,20 +247,6 @@ header_set_value (header_t header, const char *fn, const char *fv, int replace)
266 } 247 }
267 248
268 int 249 int
269 header_set_get_value (header_t header, int (*_get_value)
270 (header_t, const char *, char *, size_t, size_t *),
271 void *owner)
272 {
273 if (header == NULL)
274 return EINVAL;
275 if (header->owner != owner)
276 return EACCES;
277
278 header->_get_value = _get_value;
279 return 0;
280 }
281
282 int
283 header_get_value (header_t header, const char *name, char *buffer, 250 header_get_value (header_t header, const char *name, char *buffer,
284 size_t buflen, size_t *pn) 251 size_t buflen, size_t *pn)
285 { 252 {
...@@ -287,20 +254,61 @@ header_get_value (header_t header, const char *name, char *buffer, ...@@ -287,20 +254,61 @@ header_get_value (header_t header, const char *name, char *buffer,
287 size_t name_len; 254 size_t name_len;
288 size_t total = 0, fn_len = 0, fv_len = 0; 255 size_t total = 0, fn_len = 0, fv_len = 0;
289 int threshold; 256 int threshold;
257 int err = 0;
290 258
291 if (header == NULL || name == NULL) 259 if (header == NULL || name == NULL)
292 return EINVAL; 260 return EINVAL;
293 261
262 if (header->_get_value != NULL)
263 return header->_get_value (header, name, buffer, buflen, pn);
264
265 /* Try to fill out the buffer, if we know how. */
266 if (header->blurb == NULL)
267 {
268 stream_t is;
269 err = header_get_stream (header, &is);
270 if (err != 0)
271 return err;
272 else
273 {
274 char buf[1024];
275 char *tbuf;
276 size_t nread = 0;
277 do
278 {
279 err = stream_read (is, buf, sizeof (buf), header->temp_blurb_len,
280 &nread);
281 if (err != 0
282 || (tbuf = realloc (header->temp_blurb,
283 header->temp_blurb_len + nread)) == NULL)
284 {
285 free (header->temp_blurb);
286 header->temp_blurb = NULL;
287 header->temp_blurb_len = 0;
288 return err;
289 }
290 else
291 header->temp_blurb = tbuf;
292 memcpy (header->temp_blurb + header->temp_blurb_len, buf, nread);
293 header->temp_blurb_len += nread;
294 } while (nread != 0);
295 /* parse it. */
296 header_parse (header, header->temp_blurb, header->temp_blurb_len);
297 free (header->temp_blurb);
298 header->temp_blurb = NULL;
299 header->temp_blurb_len = 0;
300 }
301 }
302
294 /* We set the threshold to be 1 less for the null. */ 303 /* We set the threshold to be 1 less for the null. */
295 threshold = --buflen; 304 threshold = --buflen;
296 305
297 /* Caution: We may have more then one value for a field 306 /* Caution: We may have more then one value for a field name, for example
298 name, for example a "Received" field-name is added by 307 a "Received" field-name is added by each passing MTA. The way that the
299 each passing MTA. The way that the parsing (_parse()) 308 parsing (_parse()) is done it's not take to account. So we just stuff
300 is done it's not take to account. So we just stuff in 309 in the buffer all the field-values to a corresponding field-name.
301 the buffer all the field-values to a corresponding field-name. 310 FIXME: Should we kosher the output ? meaning replace occurences of
302 FIXME: Should we kosher the output ? meaning replace 311 " \t\r\n" for spaces ? for now we don't. */
303 occurences of " \t\r\n" for spaces ? for now we don't. */
304 for (name_len = strlen (name), i = 0; i < header->hdr_count; i++) 312 for (name_len = strlen (name), i = 0; i < header->hdr_count; i++)
305 { 313 {
306 fn_len = header->hdr[i].fn_end - header->hdr[i].fn; 314 fn_len = header->hdr[i].fn_end - header->hdr[i].fn;
...@@ -332,48 +340,35 @@ header_get_value (header_t header, const char *name, char *buffer, ...@@ -332,48 +340,35 @@ header_get_value (header_t header, const char *name, char *buffer,
332 *buffer = '\0'; /* Null terminated. */ 340 *buffer = '\0'; /* Null terminated. */
333 if (pn) 341 if (pn)
334 *pn = total; 342 *pn = total;
343
344 /* Check if they provided a hook. */
335 if (total == 0) 345 if (total == 0)
336 { 346 {
337 int err = ENOENT; 347 err = ENOENT;
338 /* Check if they provided a hook. */
339 if (header->_get_value != NULL) 348 if (header->_get_value != NULL)
340 err = header->_get_value (header, name, buffer, buflen, pn); 349 err = header->_get_value (header, name, buffer, buflen, pn);
341 /* Cache it locally. */ 350 /* Success. Cache it locally. */
342 if (err == 0) 351 if (err == 0)
343 header_set_value (header, name, buffer, 0); 352 header_set_value (header, name, buffer, 0);
344 return err;
345 } 353 }
346 return 0; 354 return err;
347 }
348
349 int
350 header_entry_count (header_t header, size_t *pnum)
351 {
352 if (header == NULL)
353 {
354 if (pnum)
355 *pnum = 0;
356 return EINVAL;
357 }
358 if (pnum)
359 *pnum = header->hdr_count;
360 return 0;
361 } 355 }
362 356
363 int 357 int
364 header_lines (header_t header, size_t *plines) 358 header_lines (header_t header, size_t *plines)
365 { 359 {
366 int n; 360 int n;
367 size_t t = 0; 361 size_t lines = 0;
368 if (header == NULL) 362 if (header == NULL)
369 return EINVAL; 363 return EINVAL;
364
370 for (n = header->blurb_len - 1; n >= 0; n--) 365 for (n = header->blurb_len - 1; n >= 0; n--)
371 { 366 {
372 if (header->blurb[n] == '\n') 367 if (header->blurb[n] == '\n')
373 t++; 368 lines++;
374 } 369 }
375 if (plines) 370 if (plines)
376 *plines = t; 371 *plines = lines;
377 return 0; 372 return 0;
378 } 373 }
379 374
...@@ -382,57 +377,50 @@ header_size (header_t header, size_t *pnum) ...@@ -382,57 +377,50 @@ header_size (header_t header, size_t *pnum)
382 { 377 {
383 if (header == NULL) 378 if (header == NULL)
384 return EINVAL; 379 return EINVAL;
380
385 if (pnum) 381 if (pnum)
386 *pnum = header->blurb_len; 382 *pnum = header->blurb_len;
387 return 0; 383 return 0;
388 } 384 }
389 385
390 int 386 int
391 header_entry_name (header_t header, size_t num, char *buf, 387 header_set_get_value (header_t header, int (*_get_value)
392 size_t buflen, size_t *nwritten) 388 (header_t, const char *, char *, size_t, size_t *),
389 void *owner)
393 { 390 {
394 size_t len;
395 if (header == NULL) 391 if (header == NULL)
396 return EINVAL; 392 return EINVAL;
397 if (header->hdr_count == 0 || num > header->hdr_count) 393 if (header->owner != owner)
398 return ENOENT; 394 return EACCES;
399 len = header->hdr[num].fn_end - header->hdr[num].fn; 395 header->_get_value = _get_value;
400 /* save one for the null */
401 --buflen;
402 if (buf && buflen > 0)
403 {
404 buflen = (len > buflen) ? buflen : len;
405 memcpy (buf, header->hdr[num].fn, buflen);
406 buf[buflen] = '\0';
407 }
408 if (nwritten)
409 *nwritten = len;
410 return 0; 396 return 0;
411 } 397 }
412 398
413 int 399 int
414 header_entry_value (header_t header, size_t num, char *buf, 400 header_set_set_value (header_t header, int (*_set_value)
415 size_t buflen, size_t *nwritten) 401 (header_t , const char *, const char *, int),
402 void *owner)
416 { 403 {
417 size_t len;
418 if (header == NULL) 404 if (header == NULL)
419 return EINVAL; 405 return EINVAL;
420 if (header->hdr_count == 0 || num > header->hdr_count) 406 if (header->owner != owner)
421 return ENOENT; 407 return EACCES;
422 len = header->hdr[num].fv_end - header->hdr[num].fv; 408 header->_set_value = _set_value;
423 /* Save one for the null. */
424 --buflen;
425 if (buf && buflen > 0)
426 {
427 buflen = (len > buflen) ? buflen : len;
428 memcpy (buf, header->hdr[num].fv, buflen);
429 buf[buflen] = '\0';
430 }
431 if (nwritten)
432 *nwritten = len;
433 return 0; 409 return 0;
434 } 410 }
435 411
412 int
413 header_set_stream (header_t header, stream_t stream, void *owner)
414 {
415 if (header == NULL)
416 return EINVAL;
417 if (header->owner != owner)
418 return EACCES;
419 header->stream = stream;
420 return 0;
421 }
422
423
436 static int 424 static int
437 header_write (stream_t os, const char *buf, size_t buflen, 425 header_write (stream_t os, const char *buf, size_t buflen,
438 off_t off, size_t *pnwrite) 426 off_t off, size_t *pnwrite)
......
...@@ -34,17 +34,13 @@ extern "C" { ...@@ -34,17 +34,13 @@ extern "C" {
34 34
35 struct _attribute 35 struct _attribute
36 { 36 {
37 size_t flag; 37 void *owner;
38 size_t flags;
39 int (*_get_flags) __P ((attribute_t, int *));
40 int (*_set_flags) __P ((attribute_t, int));
41 int (*_unset_flags) __P ((attribute_t, int));
38 }; 42 };
39 43
40 #define MU_ATTRIBUTE_ANSWERED 0x01
41 #define MU_ATTRIBUTE_FLAGGED 0x02
42 #define MU_ATTRIBUTE_DELETED 0x04
43 #define MU_ATTRIBUTE_DRAFT 0x08
44 #define MU_ATTRIBUTE_SEEN 0x10
45 #define MU_ATTRIBUTE_READ 0x20
46 #define MU_ATTRIBUTE_RECENT 0x00
47
48 #ifdef __cplusplus 44 #ifdef __cplusplus
49 } 45 }
50 #endif 46 #endif
......
...@@ -35,8 +35,16 @@ extern "C" { ...@@ -35,8 +35,16 @@ extern "C" {
35 struct _attribute; 35 struct _attribute;
36 typedef struct _attribute * attribute_t; 36 typedef struct _attribute * attribute_t;
37 37
38 extern int attribute_create __P ((attribute_t *)); 38 #define MU_ATTRIBUTE_ANSWERED 0x01
39 extern void attribute_destroy __P ((attribute_t *)); 39 #define MU_ATTRIBUTE_FLAGGED 0x02
40 #define MU_ATTRIBUTE_DELETED 0x04
41 #define MU_ATTRIBUTE_DRAFT 0x08
42 #define MU_ATTRIBUTE_SEEN 0x10
43 #define MU_ATTRIBUTE_READ 0x20
44 #define MU_ATTRIBUTE_RECENT 0x00
45
46 extern int attribute_create __P ((attribute_t *, void *));
47 extern void attribute_destroy __P ((attribute_t *, void *));
40 48
41 extern int attribute_is_seen __P ((attribute_t)); 49 extern int attribute_is_seen __P ((attribute_t));
42 extern int attribute_is_answered __P ((attribute_t)); 50 extern int attribute_is_answered __P ((attribute_t));
...@@ -62,14 +70,22 @@ extern int attribute_unset_draft __P ((attribute_t)); ...@@ -62,14 +70,22 @@ extern int attribute_unset_draft __P ((attribute_t));
62 extern int attribute_unset_recent __P ((attribute_t)); 70 extern int attribute_unset_recent __P ((attribute_t));
63 extern int attribute_unset_read __P ((attribute_t)); 71 extern int attribute_unset_read __P ((attribute_t));
64 72
73 extern int attribute_get_flags __P ((attribute_t, int *));
74 extern int attribute_set_flags __P ((attribute_t, int));
75
76 extern int attribute_set_set_flags __P ((attribute_t, int (*_set_flags)
77 __P ((attribute_t, int)), void *));
78 extern int attribute_set_unset_flags __P ((attribute_t, int (*_unset_flags)
79 __P ((attribute_t, int)), void *));
80 extern int attribute_set_get_flags __P ((attribute_t, int (*_get_flags)
81 __P ((attribute_t, int *)), void *));
65 extern int attribute_is_equal __P ((attribute_t att1, attribute_t att2)); 82 extern int attribute_is_equal __P ((attribute_t att1, attribute_t att2));
66 83
67 extern int attribute_copy __P ((attribute_t dst, 84 extern int attribute_copy __P ((attribute_t dst,
68 attribute_t src)); 85 attribute_t src));
69 86
70 extern int string_to_attribute __P ((const char *buf, 87 extern int string_to_flags __P ((const char *buf, int *pattr));
71 attribute_t *pattr)); 88 extern int flags_to_string __P ((int flags, char *buf,
72 extern int attribute_to_string __P ((attribute_t attr, char *buf,
73 size_t len, size_t *)); 89 size_t len, size_t *));
74 90
75 #ifdef __cplusplus 91 #ifdef __cplusplus
......
...@@ -67,27 +67,27 @@ extern "C" { ...@@ -67,27 +67,27 @@ extern "C" {
67 struct _header; 67 struct _header;
68 typedef struct _header * header_t; 68 typedef struct _header * header_t;
69 69
70 extern int header_create __P ((header_t *, const char *blurb, 70 extern int header_create __P ((header_t *, const char *,
71 size_t ln, void *owner)); 71 size_t, void *));
72 extern void header_destroy __P ((header_t *, void *owner)); 72 extern void header_destroy __P ((header_t *, void *));
73 extern int header_set_value __P ((header_t, const char *,
74 const char *, int));
75 extern int header_get_value __P ((header_t, const char *, char *,
76 size_t, size_t *));
77 extern int header_get_stream __P ((header_t, stream_t *));
78 extern int header_size __P ((header_t, size_t *));
79 extern int header_lines __P ((header_t, size_t *));
73 80
74 extern int header_set_value __P ((header_t, const char *fn, 81 extern int header_set_stream __P ((header_t, stream_t, void *));
75 const char *fv, int replace));
76 82
83 extern int header_set_set_value __P ((header_t, int (*_set_value)
84 __P ((header_t, const char *,
85 const char *, int)),
86 void *));
77 extern int header_set_get_value __P ((header_t, int (*_get_value) 87 extern int header_set_get_value __P ((header_t, int (*_get_value)
78 __P ((header_t, const char *fn, char *buf, 88 __P ((header_t, const char *,
79 size_t buflen, size_t *nwritten)), 89 char *, size_t, size_t *)),
80 void *owner)); 90 void *));
81 extern int header_get_value __P ((header_t, const char *fn, char *buf,
82 size_t buflen, size_t *nwritten));
83 extern int header_entry_count __P ((header_t, size_t *num));
84 extern int header_entry_name __P ((header_t, size_t num, char *buf,
85 size_t buflen, size_t *total));
86 extern int header_entry_value __P ((header_t, size_t num, char *buf,
87 size_t buflen, size_t *total));
88 extern int header_get_stream __P ((header_t, stream_t *stream));
89 extern int header_size __P ((header_t, size_t *size));
90 extern int header_lines __P ((header_t, size_t *lines));
91 91
92 #ifdef _cplusplus 92 #ifdef _cplusplus
93 } 93 }
......
...@@ -21,8 +21,8 @@ ...@@ -21,8 +21,8 @@
21 #include <message0.h> 21 #include <message0.h>
22 #include <registrar0.h> 22 #include <registrar0.h>
23 #include <auth0.h> 23 #include <auth0.h>
24 #include <attribute.h> 24 #include <header0.h>
25 #include <mailutils_errno.h> 25 #include <attribute0.h>
26 26
27 #include <termios.h> 27 #include <termios.h>
28 #include <errno.h> 28 #include <errno.h>
...@@ -33,34 +33,62 @@ ...@@ -33,34 +33,62 @@
33 #include <fcntl.h> 33 #include <fcntl.h>
34 34
35 35
36 static int mailbox_pop_create (mailbox_t *mbox, const char *name); 36 /* The different possible states of a Pop client, it maps to the POP3 commands.
37 static void mailbox_pop_destroy (mailbox_t *mbox); 37 Note that POP3 is not reentrant. It is only one channel. */
38 38 enum pop_state
39 struct mailbox_registrar _mailbox_pop_registrar =
40 { 39 {
41 "POP3", 40 /* The initialisation of POP_NO_STATE is redundant but it is here for
42 mailbox_pop_create, mailbox_pop_destroy 41 info purposes meaning 0 is the starting state. */
42 POP_NO_STATE = 0,
43 POP_OPEN_CONNECTION,
44 POP_GREETINGS,
45 POP_APOP_TX, POP_APOP_ACK,
46 POP_DELE_TX, POP_DELE_ACK,
47 POP_LIST_TX, POP_LIST_ACK, POP_LIST_RX,
48 POP_PASS_TX, POP_PASS_ACK,
49 POP_QUIT_TX, POP_QUIT_ACK,
50 POP_NOOP_TX, POP_NOOP_ACK,
51 POP_RETR_TX, POP_RETR_ACK, POP_RETR_RX_HDR, POP_RETR_RX_BODY,
52 POP_RSET_TX, POP_RSET_ACK,
53 POP_STAT_TX, POP_STAT_ACK,
54 POP_TOP_TX, POP_TOP_ACK, POP_TOP_RX,
55 POP_UIDL_TX, POP_UIDL_ACK,
56 POP_USER_TX, POP_USER_ACK,
57 POP_CLOSE_CONNECTION, /* I do not think a shutdown of a connection will
58 block. More for the symmetry. */
43 }; 59 };
44 60
45 static int mailbox_pop_open (mailbox_t, int flags); 61 /* Those two are exportable funtions i.e. they are visible/call when you
46 static int mailbox_pop_close (mailbox_t); 62 call a URL "pop://..." to mailbox_create. */
47 static int mailbox_pop_get_message (mailbox_t, size_t msgno, message_t *msg);
48 static int mailbox_pop_messages_count (mailbox_t, size_t *num);
49 static int mailbox_pop_expunge (mailbox_t);
50 static int mailbox_pop_num_deleted (mailbox_t, size_t *);
51 63
52 /* update and scanning*/ 64 static int pop_create (mailbox_t *, const char *);
53 static int mailbox_pop_is_updated (mailbox_t); 65 static void pop_destroy (mailbox_t *);
54 static int mailbox_pop_scan (mailbox_t mbox, size_t msgno, size_t *pcount);
55 66
56 /* mailbox size ? */ 67 struct mailbox_registrar _mailbox_pop_registrar =
57 static int mailbox_pop_size (mailbox_t, off_t *size); 68 {
58 69 "POP3",
59 static int mailbox_pop_readstream (stream_t is, char *buffer, size_t buflen, 70 pop_create, pop_destroy
60 off_t offset, size_t *pnread); 71 };
61 static int mailbox_pop_getfd (stream_t, int *pfd);
62 static int mailbox_pop_body_size (body_t, size_t *psize);
63 72
73 /* Functions/Methods that implements the mailbox_t API. */
74 static int pop_open (mailbox_t, int);
75 static int pop_close (mailbox_t);
76 static int pop_get_message (mailbox_t, size_t, message_t *);
77 static int pop_messages_count (mailbox_t, size_t *);
78 static int pop_expunge (mailbox_t);
79 static int pop_num_deleted (mailbox_t, size_t *);
80 static int pop_scan (mailbox_t, size_t, size_t *);
81 static int pop_is_updated (mailbox_t);
82
83 /* The implementation of message_t */
84 static int pop_size (mailbox_t, off_t *);
85 static int pop_readstream (stream_t, char *, size_t, off_t, size_t *);
86 static int pop_get_fd (stream_t, int *);
87 static int pop_get_flags (attribute_t, int *);
88 static int pop_body_size (body_t, size_t *);
89 static int pop_body_lines (body_t body, size_t *plines);
90 static int pop_header_read (stream_t, char *, size_t, off_t, size_t *);
91 static int pop_uidl (message_t, char *, size_t, size_t *);
64 92
65 /* According to the rfc: 93 /* According to the rfc:
66 RFC 2449 POP3 Extension Mechanism November 1998 94 RFC 2449 POP3 Extension Mechanism November 1998
...@@ -82,7 +110,15 @@ static int mailbox_pop_body_size (body_t, size_t *psize); ...@@ -82,7 +110,15 @@ static int mailbox_pop_body_size (body_t, size_t *psize);
82 the initial greeting) is unchanged at 512 octets (including the 110 the initial greeting) is unchanged at 512 octets (including the
83 terminating CRLF). */ 111 terminating CRLF). */
84 112
85 /* buffered IO */ 113 /* Buffered I/O, since the connection maybe non-blocking, we use a little
114 working buffer to hold the I/O between us and the POP3 Server. For
115 example if write () return EAGAIN, we keep on calling bio_write () until
116 the buffer is empty. bio_read () does a little more, it takes care of
117 filtering out the starting "." and return O(zero) when seeing the terminal
118 octets ".\r\n". bio_readline () insists on having a _complete_ line .i.e
119 a string terminated by \n, it will allocate/grow the working buffer as
120 needed. The '\r\n" termination is converted to '\n'. bio_destroy ()
121 does not close the stream but only free () the working buffer. */
86 struct _bio 122 struct _bio
87 { 123 {
88 #define POP_BUFSIZ 512 124 #define POP_BUFSIZ 512
...@@ -94,64 +130,93 @@ struct _bio ...@@ -94,64 +130,93 @@ struct _bio
94 char *ptr; 130 char *ptr;
95 char *nl; 131 char *nl;
96 }; 132 };
97
98 typedef struct _bio *bio_t; 133 typedef struct _bio *bio_t;
99 134
100 static int bio_create (bio_t *, stream_t); 135 static int bio_create (bio_t *, stream_t);
101 static void bio_destroy (bio_t *); 136 static void bio_destroy (bio_t *);
102 static int bio_readline (bio_t); 137 static int bio_readline (bio_t);
103 static int bio_read (bio_t); 138 static int bio_read (bio_t);
104 static int bio_write (bio_t); 139 static int bio_write (bio_t);
105 140
106 struct _mailbox_pop_data; 141 /* Advance declarations. */
107 struct _mailbox_pop_message; 142 struct _pop_data;
108 143 struct _pop_message;
109 typedef struct _mailbox_pop_data * mailbox_pop_data_t; 144
110 typedef struct _mailbox_pop_message * mailbox_pop_message_t; 145 typedef struct _pop_data * pop_data_t;
111 146 typedef struct _pop_message * pop_message_t;
112 struct _mailbox_pop_message 147
148 /* This structure holds the info when for a pop_get_message() the
149 pop_message_t type will serve as the owner of the message_t and contains
150 the command to send to RETReive the specify message. The problem comes
151 from the header. If the POP server supports TOP, we can cleanly fetch
152 the header. But otherwise we use the clumsy approach. .i.e for the header
153 we read 'til ^\n then discard the rest for the body we read after ^\n and
154 discard the beginning. This a waste, Pop was not conceive for this
155 obviously. */
156 struct _pop_message
113 { 157 {
114 bio_t bio;
115 int inbody; 158 int inbody;
159 size_t body_size;
160 size_t body_lines;
116 size_t num; 161 size_t num;
117 off_t body_size;
118 message_t message; 162 message_t message;
119 mailbox_pop_data_t mpd; 163 pop_data_t mpd; /* Back pointer. */
120 }; 164 };
121 165
122 struct _mailbox_pop_data 166 /* Structure to hold things general to the POP client, like its state, how
167 many messages we have so far etc ... */
168 struct _pop_data
123 { 169 {
124 void *func; 170 void *func; /* Indicate a command is in operation, busy. */
125 void *id; 171 size_t id; /* Use in pop_expunge to indiate the message, if bailing out. */
126 int state; 172 enum pop_state state;
127 mailbox_pop_message_t *pmessages; 173 pop_message_t *pmessages;
128 size_t pmessages_count; 174 size_t pmessages_count;
129 size_t messages_count; 175 size_t messages_count;
130 size_t size; 176 size_t size;
131 #ifdef HAVE_PTHREAD_H 177 #ifdef HAVE_PTHREAD_H
132 pthread_mutex_t mutex; 178 pthread_mutex_t mutex;
133 #endif 179 #endif
134 int flags; 180 int flags; /* Flags of for the stream_t object. */
135 bio_t bio; 181 bio_t bio; /* Working I/O buffer. */
136 int is_updated; 182 int is_updated;
137 char *user; 183 char *user; /* Temporary holders for user and passwd. */
138 char *passwd; 184 char *passwd;
139 mailbox_pop_message_t mpm; 185 mailbox_t mbox; /* Back pointer. */
140 } ; 186 } ;
141 187
188 /* Little Macro, since this is very repetitive. */
189 #define CLEAR_STATE(mpd) \
190 mpd->func = NULL, \
191 mpd->state = POP_NO_STATE
192
193 /* Clear the state for non recoverable error. */
194 #define CHECK_NON_RECOVERABLE(mpd, status) \
195 do \
196 { \
197 if (status != 0) \
198 { \
199 if (status != EAGAIN && status != EINPROGRESS && status != EINTR) \
200 { \
201 CLEAR_STATE (mpd); \
202 } \
203 return status; \
204 } \
205 } \
206 while (0)
207
142 208
143 /* Parse the url, allocate mailbox_t etc .. */ 209 /* Parse the url, allocate mailbox_t etc .. */
144 static int 210 static int
145 mailbox_pop_create (mailbox_t *pmbox, const char *name) 211 pop_create (mailbox_t *pmbox, const char *name)
146 { 212 {
147 mailbox_t mbox; 213 mailbox_t mbox;
148 mailbox_pop_data_t mpd; 214 pop_data_t mpd;
149 size_t name_len; 215 size_t name_len;
150 int status;
151 216
152 /* Sanity check. */ 217 /* Sanity check. */
153 if (pmbox == NULL || name == NULL || *name == '\0') 218 if (pmbox == NULL || name == NULL || *name == '\0')
154 return MU_ERROR_INVALID_ARG; 219 return EINVAL;
155 220
156 name_len = strlen (name); 221 name_len = strlen (name);
157 222
...@@ -173,95 +238,104 @@ mailbox_pop_create (mailbox_t *pmbox, const char *name) ...@@ -173,95 +238,104 @@ mailbox_pop_create (mailbox_t *pmbox, const char *name)
173 /* Allocate memory for mbox. */ 238 /* Allocate memory for mbox. */
174 mbox = calloc (1, sizeof (*mbox)); 239 mbox = calloc (1, sizeof (*mbox));
175 if (mbox == NULL) 240 if (mbox == NULL)
176 return MU_ERROR_OUT_OF_MEMORY; 241 return ENOMEM;
177 242
178 /* Allocate specific pop box data. */ 243 /* Allocate specifics for pop data. */
179 mpd = mbox->data = calloc (1, sizeof (*mpd)); 244 mpd = mbox->data = calloc (1, sizeof (*mpd));
180 if (mbox->data == NULL) 245 if (mbox->data == NULL)
181 { 246 {
182 mailbox_pop_destroy (&mbox); 247 pop_destroy (&mbox);
183 return MU_ERROR_OUT_OF_MEMORY; 248 return ENOMEM;
184 }
185
186 /* Allocate the struct for buffered I/O. */
187 status = bio_create (&(mpd->bio), NULL);
188 if (status != 0)
189 {
190 mailbox_pop_destroy (&mbox);
191 return status;
192 } 249 }
250 mpd->state = POP_NO_STATE;
251 mpd->mbox = mbox;
193 252
194 /* Copy the name. */ 253 /* Copy the name. */
195 mbox->name = calloc (name_len + 1, sizeof (char)); 254 mbox->name = calloc (name_len + 1, sizeof (char));
196 if (mbox->name == NULL) 255 if (mbox->name == NULL)
197 { 256 {
198 mailbox_pop_destroy (&mbox); 257 pop_destroy (&mbox);
199 return MU_ERROR_OUT_OF_MEMORY; 258 return ENOMEM;
200 } 259 }
201 memcpy (mbox->name, name, name_len); 260 memcpy (mbox->name, name, name_len);
202 261
203 #ifdef HAVE_PHTREAD_H 262 #ifdef HAVE_PHTREAD_H
204 /* Mutex when accessing the structure fields. */ 263 /* Mutex when accessing the structure fields. */
205 /* FIXME: should we use rdwr locks instead ?? */ 264 /* FIXME: should we use rdwr locks instead ?? */
206 pthread_mutex_init (&(mud->mutex), NULL); 265 /* XXXX: This is not use yet and the library is still not thread safe. This
266 is more a gentle remider that I got more work to do. */
267 pthread_mutex_init (&(mpd->mutex), NULL);
207 #endif 268 #endif
208 269
209 /* Initialize the structure. */ 270 /* Initialize the structure. */
210 mbox->_create = mailbox_pop_create; 271 mbox->_create = pop_create;
211 mbox->_destroy = mailbox_pop_destroy; 272 mbox->_destroy = pop_destroy;
212 273
213 mbox->_open = mailbox_pop_open; 274 mbox->_open = pop_open;
214 mbox->_close = mailbox_pop_close; 275 mbox->_close = pop_close;
215 276
216 /* Messages. */ 277 /* Messages. */
217 mbox->_get_message = mailbox_pop_get_message; 278 mbox->_get_message = pop_get_message;
218 mbox->_messages_count = mailbox_pop_messages_count; 279 mbox->_messages_count = pop_messages_count;
219 mbox->_expunge = mailbox_pop_expunge; 280 mbox->_expunge = pop_expunge;
220 mbox->_num_deleted = mailbox_pop_num_deleted; 281 mbox->_num_deleted = pop_num_deleted;
221 282
222 mbox->_scan = mailbox_pop_scan; 283 mbox->_scan = pop_scan;
223 mbox->_is_updated = mailbox_pop_is_updated; 284 mbox->_is_updated = pop_is_updated;
224 285
225 mbox->_size = mailbox_pop_size; 286 mbox->_size = pop_size;
226 287
227 (*pmbox) = mbox; 288 (*pmbox) = mbox;
228 289
229 return 0; /* Okdoke. */ 290 return 0; /* Okdoke. */
230 } 291 }
231 292
293 /* Cleaning up all the ressources. */
232 static void 294 static void
233 mailbox_pop_destroy (mailbox_t *pmbox) 295 pop_destroy (mailbox_t *pmbox)
234 { 296 {
235 if (pmbox && *pmbox) 297 if (pmbox && *pmbox)
236 { 298 {
237 mailbox_t mbox = *pmbox; 299 mailbox_t mbox = *pmbox;
238 if (mbox->data) 300 if (mbox->data)
239 { 301 {
240 mailbox_pop_data_t mpd = mbox->data; 302 pop_data_t mpd = mbox->data;
241 size_t i; 303 size_t i;
304 /* Destroy the pop messages and ressources associated to them. */
242 for (i = 0; i < mpd->pmessages_count; i++) 305 for (i = 0; i < mpd->pmessages_count; i++)
243 { 306 {
244 if (mpd->pmessages[i]) 307 if (mpd->pmessages[i])
245 { 308 {
246 bio_destroy (&(mpd->pmessages[i]->bio));
247 message_destroy (&(mpd->pmessages[i]->message), 309 message_destroy (&(mpd->pmessages[i]->message),
248 mpd->pmessages[i]); 310 mpd->pmessages[i]);
311 free (mpd->pmessages[i]);
249 } 312 }
250 free (mpd->pmessages[i]);
251 } 313 }
314 bio_destroy (&(mpd->bio));
252 free (mpd->pmessages); 315 free (mpd->pmessages);
253 free (mpd); 316 free (mpd);
317 #ifdef HAVE_PHTREAD_H
318 pthread_mutex_destroy (&(mpd->mutex));
319 #endif
254 } 320 }
255 free (mbox->name); 321 /* Since the mailbox is destroy, close the stream but not via
256 free (mbox->event); 322 pop_close () which can return EAGAIN, or other unpleasant side
323 effects, but rather the hard way. */
324 stream_close (mbox->stream);
257 stream_destroy (&(mbox->stream), mbox); 325 stream_destroy (&(mbox->stream), mbox);
258 auth_destroy (&(mbox->auth), mbox); 326 auth_destroy (&(mbox->auth), mbox);
327 if (mbox->name)
328 free (mbox->name);
329 if (mbox->event)
330 free (mbox->event);
259 if (mbox->url) 331 if (mbox->url)
260 url_destroy (&(mbox->url)); 332 url_destroy (&(mbox->url));
333 free (mbox);
261 *pmbox = NULL; 334 *pmbox = NULL;
262 } 335 }
263 } 336 }
264 337
338 /* We should probably use getpass () or something similar. */
265 static struct termios stored_settings; 339 static struct termios stored_settings;
266 340
267 static void 341 static void
...@@ -283,9 +357,8 @@ echo_on(void) ...@@ -283,9 +357,8 @@ echo_on(void)
283 static int 357 static int
284 pop_authenticate (auth_t auth, char **user, char **passwd) 358 pop_authenticate (auth_t auth, char **user, char **passwd)
285 { 359 {
286 /* FIXME: this incorrect and goes against GNU style: having a limitation 360 /* FIXME: This incorrect and goes against GNU style: having a limitation on
287 * on the user/passwd length, it should be fix 361 the user/passwd length, it should be fix. */
288 */
289 char u[128]; 362 char u[128];
290 char p[128]; 363 char p[128];
291 mailbox_t mbox = auth->owner; 364 mailbox_t mbox = auth->owner;
...@@ -294,7 +367,7 @@ pop_authenticate (auth_t auth, char **user, char **passwd) ...@@ -294,7 +367,7 @@ pop_authenticate (auth_t auth, char **user, char **passwd)
294 *u = '\0'; 367 *u = '\0';
295 *p = '\0'; 368 *p = '\0';
296 369
297 /* prompt for the user/login name */ 370 /* Prompt for the user/login name. */
298 status = url_get_user (mbox->url, u, sizeof (u), NULL); 371 status = url_get_user (mbox->url, u, sizeof (u), NULL);
299 if (status != 0 || *u == '\0') 372 if (status != 0 || *u == '\0')
300 { 373 {
...@@ -302,8 +375,7 @@ pop_authenticate (auth_t auth, char **user, char **passwd) ...@@ -302,8 +375,7 @@ pop_authenticate (auth_t auth, char **user, char **passwd)
302 fgets (u, sizeof (u), stdin); 375 fgets (u, sizeof (u), stdin);
303 u [strlen (u) - 1] = '\0'; /* nuke the trailing NL */ 376 u [strlen (u) - 1] = '\0'; /* nuke the trailing NL */
304 } 377 }
305 /* prompt for the passwd */ 378 /* Prompt for the passwd. */
306 /* FIXME: should turn off echo .... */
307 status = url_get_passwd (mbox->url, p, sizeof (p), NULL); 379 status = url_get_passwd (mbox->url, p, sizeof (p), NULL);
308 if (status != 0 || *p == '\0' || *p == '*') 380 if (status != 0 || *p == '\0' || *p == '*')
309 { 381 {
...@@ -320,12 +392,12 @@ pop_authenticate (auth_t auth, char **user, char **passwd) ...@@ -320,12 +392,12 @@ pop_authenticate (auth_t auth, char **user, char **passwd)
320 } 392 }
321 393
322 static int 394 static int
323 mailbox_pop_open (mailbox_t mbox, int flags) 395 pop_open (mailbox_t mbox, int flags)
324 { 396 {
325 mailbox_pop_data_t mpd; 397 pop_data_t mpd;
326 int status; 398 int status;
327 bio_t bio; 399 bio_t bio;
328 void *func = (void *)mailbox_pop_open; 400 void *func = (void *)pop_open;
329 char host[256] ; 401 char host[256] ;
330 long port; 402 long port;
331 403
...@@ -333,20 +405,12 @@ mailbox_pop_open (mailbox_t mbox, int flags) ...@@ -333,20 +405,12 @@ mailbox_pop_open (mailbox_t mbox, int flags)
333 if (mbox == NULL || mbox->url == NULL || (mpd = mbox->data) == NULL) 405 if (mbox == NULL || mbox->url == NULL || (mpd = mbox->data) == NULL)
334 return EINVAL; 406 return EINVAL;
335 407
336 /* Create the networking stack. */ 408 /* Fetch the pop server name and the port in the url_t. */
337 if (mbox->stream == NULL) 409 if ((status = url_get_host (mbox->url, host, sizeof(host), NULL)) != 0
338 { 410 || (status = url_get_port (mbox->url, &port)) != 0)
339 status = tcp_stream_create (&(mbox->stream));
340 if (status != 0)
341 return status;
342 }
343
344 if ((status = url_get_host (mbox->url, host, sizeof(host), NULL)) != 0 ||
345 (status = url_get_port (mbox->url, &port)) != 0)
346 return status; 411 return status;
347 412
348 /* Dealing whith Authentication. */ 413 /* Dealing whith Authentication. So far only normal user/pass supported. */
349 /* So far only normal user/pass supported. */
350 if (mbox->auth == NULL) 414 if (mbox->auth == NULL)
351 { 415 {
352 status = auth_create (&(mbox->auth), mbox); 416 status = auth_create (&(mbox->auth), mbox);
...@@ -361,141 +425,134 @@ mailbox_pop_open (mailbox_t mbox, int flags) ...@@ -361,141 +425,134 @@ mailbox_pop_open (mailbox_t mbox, int flags)
361 mpd->func = func; 425 mpd->func = func;
362 bio = mpd->bio; 426 bio = mpd->bio;
363 427
364 /* Enter the state machine. */ 428 /* Enter the pop state machine, and boogy: AUTHORISATION State. */
365 switch (mpd->state) 429 switch (mpd->state)
366 { 430 {
367 /* Establish the connection. */ 431 case POP_NO_STATE:
368 case 0:
369 /* Spawn auth prologue. */ 432 /* Spawn auth prologue. */
370 auth_prologue (mbox->auth); 433 auth_prologue (mbox->auth);
434 /* Create the networking stack. */
435 if (mbox->stream == NULL)
436 {
437 status = tcp_stream_create (&(mbox->stream));
438 if (status != 0)
439 return status;
440 }
441 mpd->state = POP_OPEN_CONNECTION;
371 442
443 case POP_OPEN_CONNECTION:
444 /* Establish the connection. */
372 status = stream_open (mbox->stream, host, port, flags); 445 status = stream_open (mbox->stream, host, port, flags);
373 if (status != 0) 446 if (status != 0)
374 { 447 {
448 /* Clear the state for non recoverable error. */
375 if (status != EAGAIN && status != EINPROGRESS && status != EINTR) 449 if (status != EAGAIN && status != EINPROGRESS && status != EINTR)
376 { 450 {
377 mpd->func = NULL; 451 mpd->func = NULL;
378 mpd->state = 0; 452 mpd->state = POP_NO_STATE;
379 } 453 }
380 return status; 454 return status;
381 } 455 }
382 /* Set the Buffer I/O. */ 456 /* Allocate the struct for buffered I/O. */
383 bio->stream = mbox->stream; 457 bio_destroy (&(mpd->bio));
384 bio->ptr = bio->buffer; 458 status = bio_create (&(mpd->bio), mbox->stream);
385 bio->nl = NULL; 459 /* Can't recover bailout. */
386 mpd->state = 1;
387 /* Glob the greetings. */
388 case 1:
389 status = bio_readline (bio);
390 if (status != 0) 460 if (status != 0)
391 { 461 {
392 if (status != EAGAIN && status != EINTR) 462 stream_close (bio->stream);
393 { 463 CLEAR_STATE (mpd);
394 mpd->func = NULL;
395 mpd->state = 0;
396 }
397 return status; 464 return status;
398 } 465 }
466 bio = mpd->bio;
467 mpd->state = POP_GREETINGS;
468
469 case POP_GREETINGS:
470 /* Swallow the greetings. */
471 status = bio_readline (bio);
472 CHECK_NON_RECOVERABLE (mpd, status);
473 mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
399 if (strncasecmp (bio->buffer, "+OK", 3) != 0) 474 if (strncasecmp (bio->buffer, "+OK", 3) != 0)
400 { 475 {
401 mpd->func = NULL;
402 mpd->state = 0;
403 stream_close (bio->stream); 476 stream_close (bio->stream);
404 bio->stream = NULL; 477 CLEAR_STATE (mpd);
405 return EACCES; 478 return EACCES;
406 } 479 }
407 480
481 /* Fetch the the user/passwd from them. */
408 auth_authenticate (mbox->auth, &mpd->user, &mpd->passwd); 482 auth_authenticate (mbox->auth, &mpd->user, &mpd->passwd);
409 /* FIXME: Use snprintf. */ 483
410 //mpd->len = sprintf (pop->buffer, POP_BUFSIZ, "USER %s\r\n", user); 484 bio->len = snprintf (bio->buffer, bio->maxlen, "USER %s\r\n", mpd->user);
411 bio->len = sprintf (bio->buffer, "USER %s\r\n", mpd->user);
412 bio->ptr = bio->buffer; 485 bio->ptr = bio->buffer;
413 mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer); 486 mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
414 free (mpd->user); mpd->user = NULL; 487 free (mpd->user); mpd->user = NULL;
415 mpd->state = 2; 488 mpd->state = POP_USER_TX;
489
490 case POP_USER_TX:
416 /* Send username. */ 491 /* Send username. */
417 case 2:
418 status = bio_write (bio); 492 status = bio_write (bio);
419 if (status != 0) 493 CHECK_NON_RECOVERABLE (mpd, status);
420 { 494 mpd->state = POP_USER_ACK;
421 if (status != EAGAIN && status != EINTR) 495
422 { 496 case POP_USER_ACK:
423 mpd->func = NULL; 497 /* Get the user ack. */
424 mpd->state = 0;
425 }
426 return status;
427 }
428 mpd->state = 3;
429 /* Get the ack. */
430 case 3:
431 status = bio_readline (bio); 498 status = bio_readline (bio);
432 if (status != 0) 499 CHECK_NON_RECOVERABLE (mpd, status);
433 {
434 if (status != EAGAIN && status != EINTR)
435 {
436 mpd->func = NULL;
437 mpd->state = 0;
438 }
439 return status;
440 }
441 mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer); 500 mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
442 if (strncasecmp (bio->buffer, "+OK", 3) != 0) 501 if (strncasecmp (bio->buffer, "+OK", 3) != 0)
443 return EACCES; 502 {
444 503 stream_close (bio->stream);
445 /* FIXME Use snprintf. */ 504 CLEAR_STATE (mpd);
446 //mpd->len = snprintf (mpd->buffer, POP_BUFSIZ, "PASS %s\r\n", passwd); 505 return EACCES;
447 bio->len = sprintf (bio->buffer, "PASS %s\r\n", mpd->passwd); 506 }
507 bio->len = snprintf (bio->buffer, POP_BUFSIZ, "PASS %s\r\n",
508 mpd->passwd);
448 bio->ptr = bio->buffer; 509 bio->ptr = bio->buffer;
449 mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer); 510 mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
511 /* We have to nuke the passwd. */
512 memset (mpd->passwd, 0, strlen (mpd->passwd));
450 free (mpd->passwd); mpd->passwd = NULL; 513 free (mpd->passwd); mpd->passwd = NULL;
451 mpd->state = 4; 514 mpd->state = POP_PASS_TX;
515
516 case POP_PASS_TX:
452 /* Send passwd. */ 517 /* Send passwd. */
453 case 4:
454 status = bio_write (bio); 518 status = bio_write (bio);
455 if (status != 0) 519 CHECK_NON_RECOVERABLE (mpd, status);
456 { 520 mpd->state = POP_PASS_ACK;
457 if (status != EAGAIN && status != EINTR) 521
458 { 522 case POP_PASS_ACK:
459 mpd->func = NULL;
460 mpd->state = 0;
461 }
462 return status;
463 }
464 mpd->state = 5;
465 /* Get the ack from passwd. */ 523 /* Get the ack from passwd. */
466 case 5:
467 status = bio_readline (bio); 524 status = bio_readline (bio);
468 if (status != 0) 525 CHECK_NON_RECOVERABLE (mpd, status);
469 {
470 if (status != EAGAIN && status != EINTR)
471 {
472 mpd->func = NULL;
473 mpd->state = 0;
474 }
475 return status;
476 }
477 mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer); 526 mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
478 if (strncasecmp (bio->buffer, "+OK", 3) != 0) 527 if (strncasecmp (bio->buffer, "+OK", 3) != 0)
479 return EACCES; 528 {
480 }/* Swith state. */ 529 stream_close (bio->stream);
530 CLEAR_STATE (mpd);
531 return EACCES;
532 }
533 break; /* We're outta here. */
534 default:
535 /*
536 fprintf (stderr, "pop_open unknown state\n");
537 */
538 }/* End AUTHORISATION state. */
481 539
482 /* Spawn cleanup functions. */ 540 /* Spawn cleanup functions. */
483 auth_epilogue (mbox->auth); 541 auth_epilogue (mbox->auth);
484 542
485 /* Clear any state. */ 543 /* Clear any state. */
486 mpd->id = mpd->func = NULL; 544 CLEAR_STATE (mpd);
487 mpd->state = 0;
488
489 return 0; 545 return 0;
490 } 546 }
491 547
492 static int 548 static int
493 mailbox_pop_close (mailbox_t mbox) 549 pop_close (mailbox_t mbox)
494 { 550 {
495 mailbox_pop_data_t mpd; 551 pop_data_t mpd;
496 void *func = (void *)mailbox_pop_close; 552 void *func = (void *)pop_close;
497 int status; 553 int status;
498 bio_t bio; 554 bio_t bio;
555 size_t i;
499 556
500 if (mbox == NULL || (mpd = mbox->data) == NULL) 557 if (mbox == NULL || (mpd = mbox->data) == NULL)
501 return EINVAL; 558 return EINVAL;
...@@ -506,65 +563,74 @@ mailbox_pop_close (mailbox_t mbox) ...@@ -506,65 +563,74 @@ mailbox_pop_close (mailbox_t mbox)
506 mpd->func = func; 563 mpd->func = func;
507 bio = mpd->bio; 564 bio = mpd->bio;
508 565
509 if (bio->stream != NULL) 566 /* Ok boys, it's a wrap: UPDATE State. */
567 switch (mpd->state)
568 {
569 case POP_NO_STATE:
570 bio->len = snprintf (bio->buffer, bio->maxlen, "QUIT\r\n");
571 bio->ptr = bio->buffer;
572 mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
573 mpd->state = POP_QUIT_TX;
574
575 case POP_QUIT_TX:
576 /* Send the quit. */
577 status = bio_write (mpd->bio);
578 CHECK_NON_RECOVERABLE (mpd, status);
579 mpd->state = POP_QUIT_ACK;
580
581 case POP_QUIT_ACK:
582 /* Glob the acknowledge. */
583 status = bio_readline (bio);
584 CHECK_NON_RECOVERABLE (mpd, status);
585 mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
586 /* Now what ! and how can we tell them about errors ? So for now
587 lets just be verbose about the error but close the connection
588 anyway. */
589 if (strncasecmp (bio->buffer, "+OK", 3) != 0)
590 fprintf (stderr, "pop_close: %s\n", bio->buffer);
591
592 stream_close (bio->stream);
593 bio->stream = NULL;
594 break;
595 default:
596 /*
597 fprintf (stderr, "pop_close unknow state");
598 */
599 } /* UPDATE state. */
600
601 /* free the messages */
602 for (i = 0; i < mpd->pmessages_count; i++)
510 { 603 {
511 switch (mpd->state) 604 if (mpd->pmessages[i])
512 { 605 {
513 case 0: 606 message_destroy (&(mpd->pmessages[i]->message),
514 bio->len = sprintf (bio->buffer, "QUIT\r\n"); 607 mpd->pmessages[i]);
515 bio->ptr = bio->buffer; 608 free (mpd->pmessages[i]);
516 mpd->state = 1;
517 mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
518 case 1:
519 status = bio_write (mpd->bio);
520 if (status != 0)
521 {
522 if (status != EAGAIN && status != EINTR)
523 {
524 mpd->func = mpd->id = NULL;
525 mpd->state = 0;
526 }
527 return status;
528 }
529 case 2:
530 status = bio_readline (bio);
531 if (status != 0)
532 {
533 if (status != EAGAIN && status != EINTR)
534 {
535 mpd->func = mpd->id = NULL;
536 mpd->state = 0;
537 }
538 return status;
539 }
540 mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
541 if (strncasecmp (bio->buffer, "+OK", 3) != 0)
542 return EINVAL;
543 case 3:
544 stream_close (bio->stream);
545 bio->stream = NULL;
546 } 609 }
547 } 610 }
611 free (mpd->pmessages);
612 mpd->pmessages = NULL;
613 mpd->pmessages_count = 0;
614 mpd->is_updated = 0;
615 bio_destroy (&(mpd->bio));
548 616
549 mpd->func = mpd->id = NULL; 617 CLEAR_STATE (mpd);
550 mpd->state = 0;
551 return 0; 618 return 0;
552 } 619 }
553 620
554 static int 621 static int
555 mailbox_pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg) 622 pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
556 { 623 {
557 mailbox_pop_data_t mpd; 624 pop_data_t mpd;
558 bio_t bio;
559 int status; 625 int status;
626 pop_message_t mpm;
560 size_t i; 627 size_t i;
561 void *func = (void *)mailbox_pop_get_message;
562 628
563 /* Sanity. */ 629 /* Sanity. */
564 if (mbox == NULL || pmsg == NULL || (mpd = mbox->data) == NULL) 630 if (mbox == NULL || pmsg == NULL || (mpd = mbox->data) == NULL)
565 return EINVAL; 631 return EINVAL;
566 632
567 /* See if we already have this message. */ 633 /* See if we have already this message. */
568 for (i = 0; i < mpd->pmessages_count; i++) 634 for (i = 0; i < mpd->pmessages_count; i++)
569 { 635 {
570 if (mpd->pmessages[i]) 636 if (mpd->pmessages[i])
...@@ -577,280 +643,120 @@ mailbox_pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg) ...@@ -577,280 +643,120 @@ mailbox_pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
577 } 643 }
578 } 644 }
579 645
580 /* Are we busy in another function ? */ 646 mpm = calloc (1, sizeof (*mpm));
581 if (mpd->func && mpd->func != func) 647 if (mpm == NULL)
582 return EBUSY; 648 return ENOMEM;
583 649 /* back pointer */
584 /* In the function, but are we busy with an other message/request ? */ 650 mpm->mpd = mpd;
585 if (mpd->id && mpd->id != *pmsg) 651 mpm->num = msgno;
586 return EBUSY;
587
588 mpd->func = func;
589 bio = mpd->bio;
590
591 /* Ok men, we're going in. */
592 switch (mpd->state)
593 {
594 /* The message. */
595 case 0:
596 {
597 message_t msg;
598 mailbox_pop_message_t mpm ;
599
600 mpm = calloc (1, sizeof (*mpm));
601 if (mpm == NULL)
602 return ENOMEM;
603
604 /* We'll use the bio to store headers. */
605 mpm->bio = calloc (1, sizeof (*(mpm->bio)));
606 if (mpm->bio == NULL)
607 {
608 free (mpm);
609 mpd->func = NULL;
610 return ENOMEM;
611 }
612
613 /* Create the message. */
614 status = message_create (&msg, mpm);
615 if (status != 0)
616 {
617 free (mpm->bio);
618 free (mpm);
619 mpd->func = NULL;
620 return status;
621 }
622 652
623 /* The message. */ 653 /* Create the message. */
624 mpm->message = msg; 654 {
625 mpm->num = msgno; 655 message_t msg;
626 mpd->mpm = mpm; 656 status = message_create (&msg, mpm);
627 /* back pointer */ 657 if (status != 0)
628 mpm->mpd = mpd;
629 /* set the busy request state */
630 mpd->id = (void *)msg;
631
632 /* Get the header.
633 FIXME: TOP is an optionnal command, if we want to
634 be compliant we can not count on it to exists.
635 So we should be prepare when it fails and fall to
636 a second scheme. */
637 /*bio->len = snprintf (bio->buffer, POP_BUFSIZ, "TOP %d 0\r\n", msgno);*/
638 bio->len = sprintf (bio->buffer, "TOP %d 0\r\n", msgno);
639 bio->ptr = bio->buffer;
640 mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
641 mpd->state = 1;
642 }
643 /* Send the TOP. */
644 case 1:
645 {
646 status = bio_write (bio);
647 if (status != 0)
648 {
649 if (status != EAGAIN && status != EINTR)
650 {
651 mpd->func = mpd->id = NULL;
652 mpd->state = 0;
653 message_destroy (&(mpd->mpm->message), mpd->mpm);
654 bio_destroy (&(mpd->mpm->bio));
655 free (mpd->mpm);
656 mpd->mpm = NULL;
657 }
658 return status;
659 }
660 mpd->state = 2;
661 }
662 /* Ack from TOP. */
663 case 2:
664 { 658 {
665 status = bio_readline (bio); 659 free (mpm);
666 if (status != 0) 660 return status;
667 {
668 if (status != EAGAIN && status != EINTR)
669 {
670 mpd->func = mpd->id = NULL;
671 mpd->state = 0;
672 message_destroy (&(mpd->mpm->message), mpd->mpm);
673 bio_destroy (&(mpd->mpm->bio));
674 free (mpd->mpm);
675 mpd->mpm = NULL;
676 }
677 return status;
678 }
679 mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
680 if (strncasecmp (bio->buffer, "+OK", 3) != 0)
681 {
682 mpd->func = mpd->id = NULL;
683 mpd->state = 0;
684 message_destroy (&(mpd->mpm->message), mpd->mpm);
685 bio_destroy (&(mpd->mpm->bio));
686 free (mpd->mpm);
687 mpd->mpm = NULL;
688 return ERANGE;
689 }
690 } 661 }
691 mpd->state = 5; 662 /* The message. */
692 /* Get the header. */ 663 mpm->message = msg;
693 case 5: 664 }
694 {
695 char *tbuf;
696 int nread;
697 while (1)
698 {
699 status = bio_readline (bio);
700 if (status != 0)
701 {
702 /* Recoverable. */
703 if (status != EAGAIN && status != EINTR)
704 {
705 mpd->func = mpd->id = NULL;
706 mpd->state = 0;
707 message_destroy (&(mpd->mpm->message), mpd->mpm);
708 bio_destroy (&(mpd->mpm->bio));
709 free (mpd->mpm);
710 mpd->mpm = NULL;
711 }
712 return status;
713 }
714
715 /* Our ticket out. */
716 if (bio->buffer[0] == '\0')
717 break;
718
719 nread = bio->nl - bio->buffer;
720
721 tbuf = realloc (mpd->mpm->bio->buffer,
722 mpd->mpm->bio->maxlen + nread);
723 if (tbuf == NULL)
724 {
725 mpd->func = mpd->id = NULL;
726 mpd->state = 0;
727 message_destroy (&(mpd->mpm->message), mpd->mpm);
728 bio_destroy (&(mpd->mpm->bio));
729 free (mpd->mpm);
730 mpd->mpm = NULL;
731 return ENOMEM;
732 }
733 else
734 mpd->mpm->bio->buffer = tbuf;
735 memcpy (mpd->mpm->bio->buffer + mpd->mpm->bio->maxlen,
736 bio->buffer, nread);
737 mpd->mpm->bio->maxlen += nread;
738 } /* while () */
739 } /* case 5: */
740 break;
741 default:
742 /* Error here unknow case. */
743 fprintf (stderr, "Pop unknown state(get_message)\n");
744 } /* switch (state) */
745
746 /* No need to carry a state anymore. */
747 mpd->func = mpd->id = NULL;
748 mpd->state = 0;
749 665
750 /* Create the header. */ 666 /* Create the header. */
751 { 667 {
752 header_t header; 668 header_t header;
753 status = header_create (&header, mpd->mpm->bio->buffer, 669 stream_t stream;
754 mpd->mpm->bio->maxlen, mpd->mpm); 670 if ((status = header_create (&header, NULL, 0, mpm)) != 0
755 bio_destroy (&(mpd->mpm->bio)); 671 || (status = stream_create (&stream, MU_STREAM_READ, mpm)) != 0)
756 if (status != 0)
757 { 672 {
758 message_destroy (&(mpd->mpm->message), mpd->mpm); 673 message_destroy (&(mpm->message), mpm);
759 free (mpd->mpm); 674 free (mpm);
760 mpd->mpm = NULL;
761 return status; 675 return status;
762 } 676 }
763 message_set_header ((mpd->mpm->message), header, mpd->mpm); 677 stream_set_read (stream, pop_header_read, mpm);
678 stream_set_fd (stream, pop_get_fd, mpm);
679 stream_set_flags (stream, MU_STREAM_READ, mpm);
680 header_set_stream (header, stream, mpm);
681 message_set_header (mpm->message, header, mpm);
764 } 682 }
765 683
766 /* Reallocate the working I/O buffer. */
767 bio_create (&(mpd->mpm->bio), bio->stream);
768
769 /* Create the attribute. */ 684 /* Create the attribute. */
770 { 685 {
771 attribute_t attribute; 686 attribute_t attribute;
772 char hdr_status[64]; 687 status = attribute_create (&attribute, mpm);
773 header_t header = NULL;
774 hdr_status[0] = '\0';
775 message_get_header (mpd->mpm->message, &header);
776 header_get_value (header, "Status", hdr_status, sizeof (hdr_status), NULL);
777 /* Create the attribute. */
778 status = string_to_attribute (hdr_status, &attribute);
779 if (status != 0) 688 if (status != 0)
780 { 689 {
781 message_destroy (&(mpd->mpm->message), mpd->mpm); 690 message_destroy (&(mpm->message), mpm);
782 bio_destroy (&(mpd->mpm->bio)); 691 free (mpm);
783 free (mpd->mpm);
784 mpd->mpm = NULL;
785 return status; 692 return status;
786 } 693 }
787 message_set_attribute (mpd->mpm->message, attribute, mpd->mpm); 694 attribute_set_get_flags (attribute, pop_get_flags, mpm);
695 message_set_attribute (mpm->message, attribute, mpm);
788 } 696 }
789 697
790 /* Create the body. */ 698 /* Create the body and its stream. */
791 { 699 {
792 stream_t stream; 700 stream_t stream;
793 body_t body; 701 body_t body;
794 status = body_create (&body, mpd->mpm); 702 status = body_create (&body, mpm);
795 if (status != 0) 703 if (status != 0)
796 { 704 {
797 message_destroy (&(mpd->mpm->message), mpd->mpm); 705 message_destroy (&(mpm->message), mpm);
798 bio_destroy (&(mpd->mpm->bio)); 706 free (mpm);
799 free (mpd->mpm);
800 mpd->mpm = NULL;
801 return status; 707 return status;
802 } 708 }
803 message_set_body (mpd->mpm->message, body, mpd->mpm); 709 status = stream_create (&stream, MU_STREAM_READ, mpm);
804 status = stream_create (&stream, MU_STREAM_READ, mpd->mpm);
805 if (status != 0) 710 if (status != 0)
806 { 711 {
807 message_destroy (&(mpd->mpm->message), mpd->mpm); 712 message_destroy (&(mpm->message), mpm);
808 bio_destroy (&(mpd->mpm->bio)); 713 free (mpm);
809 free (mpd->mpm);
810 mpd->mpm = NULL;
811 return status; 714 return status;
812 } 715 }
813 stream_set_read (stream, mailbox_pop_readstream, mpd->mpm); 716 stream_set_read (stream, pop_readstream, mpm);
814 stream_set_fd (stream, mailbox_pop_getfd, mpd->mpm); 717 stream_set_fd (stream, pop_get_fd, mpm);
815 stream_set_flags (stream, mpd->flags, mpd->mpm); 718 stream_set_flags (stream, mpd->flags, mpm);
816 body_set_size (body, mailbox_pop_body_size, mpd->mpm); 719 body_set_size (body, pop_body_size, mpm);
817 //body_set_lines (body, mailbox_pop_body_lines, mpd->mpm); 720 body_set_lines (body, pop_body_lines, mpm);
818 body_set_stream (body, stream, mpd->mpm); 721 body_set_stream (body, stream, mpm);
722 message_set_body (mpm->message, body, mpm);
819 } 723 }
820 724
725 /* Set the UIDL call on the message. */
726 message_set_uidl (mpm->message, pop_uidl, mpm);
727
821 /* Add it to the list. */ 728 /* Add it to the list. */
822 { 729 {
823 mailbox_pop_message_t *m ; 730 pop_message_t *m ;
824 m = realloc (mpd->pmessages, (mpd->pmessages_count + 1)*sizeof (*m)); 731 m = realloc (mpd->pmessages, (mpd->pmessages_count + 1)*sizeof (*m));
825 if (m == NULL) 732 if (m == NULL)
826 { 733 {
827 message_destroy (&(mpd->mpm->message), mpd->mpm); 734 message_destroy (&(mpm->message), mpm);
828 free (mpd->mpm); 735 free (mpm);
829 mpd->mpm = NULL;
830 return ENOMEM; 736 return ENOMEM;
831 } 737 }
832 mpd->pmessages = m; 738 mpd->pmessages = m;
833 mpd->pmessages[mpd->pmessages_count] = mpd->mpm; 739 mpd->pmessages[mpd->pmessages_count] = mpm;
834 mpd->pmessages_count++; 740 mpd->pmessages_count++;
835 } 741 }
836 742
837 *pmsg = mpd->mpm->message; 743 *pmsg = mpm->message;
838 744
839 return 0; 745 return 0;
840 } 746 }
841 747
842 static int 748 static int
843 mailbox_pop_messages_count (mailbox_t mbox, size_t *pcount) 749 pop_messages_count (mailbox_t mbox, size_t *pcount)
844 { 750 {
845 mailbox_pop_data_t mpd; 751 pop_data_t mpd;
846 int status; 752 int status;
847 void *func = (void *)mailbox_pop_messages_count; 753 void *func = (void *)pop_messages_count;
848 bio_t bio; 754 bio_t bio;
849 755
850 if (mbox == NULL || (mpd = (mailbox_pop_data_t)mbox->data) == NULL) 756 if (mbox == NULL || (mpd = (pop_data_t)mbox->data) == NULL)
851 return EINVAL; 757 return EINVAL;
852 758
853 if (mailbox_pop_is_updated (mbox)) 759 if (pop_is_updated (mbox))
854 { 760 {
855 if (pcount) 761 if (pcount)
856 *pcount = mpd->messages_count; 762 *pcount = mpd->messages_count;
...@@ -862,34 +768,39 @@ mailbox_pop_messages_count (mailbox_t mbox, size_t *pcount) ...@@ -862,34 +768,39 @@ mailbox_pop_messages_count (mailbox_t mbox, size_t *pcount)
862 768
863 mpd->func = func; 769 mpd->func = func;
864 bio = mpd->bio; 770 bio = mpd->bio;
771
772 /* TRANSACTION state. */
865 switch (mpd->state) 773 switch (mpd->state)
866 { 774 {
867 case 0: 775 case POP_NO_STATE:
868 bio->len = sprintf (bio->buffer, "STAT\r\n"); 776 bio->len = sprintf (bio->buffer, "STAT\r\n");
869 bio->ptr = bio->buffer; 777 bio->ptr = bio->buffer;
870 mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer); 778 mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
871 mpd->state = 1; 779 mpd->state = POP_STAT_TX;
780
781 case POP_STAT_TX:
872 /* Send the STAT. */ 782 /* Send the STAT. */
873 case 1:
874 status = bio_write (bio); 783 status = bio_write (bio);
875 if (status != 0) 784 CHECK_NON_RECOVERABLE (mpd, status);
876 return status; 785 mpd->state = POP_STAT_ACK;
877 mpd->state = 2; 786
787 case POP_STAT_ACK:
878 /* Get the ACK. */ 788 /* Get the ACK. */
879 case 2:
880 status = bio_readline (bio); 789 status = bio_readline (bio);
881 if (status != 0) 790 CHECK_NON_RECOVERABLE (mpd, status);
882 return status;
883 mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer); 791 mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
884 break; 792 break;
885 default: 793 default:
886 fprintf (stderr, "unknow state(messages_count)\n"); 794 /*
795 fprintf (stderr, "pomp_messages_count: unknow state\n");
796 */
887 } 797 }
888 mpd->id = mpd->func = NULL;
889 mpd->state = 0;
890 798
891 status = sscanf (bio->buffer, "+OK %d %d", &(mpd->messages_count), 799 status = sscanf (bio->buffer, "+OK %d %d", &(mpd->messages_count),
892 &(mpd->size)); 800 &(mpd->size));
801
802 CLEAR_STATE (mpd);
803
893 mpd->is_updated = 1; 804 mpd->is_updated = 1;
894 if (pcount) 805 if (pcount)
895 *pcount = mpd->messages_count; 806 *pcount = mpd->messages_count;
...@@ -901,23 +812,24 @@ mailbox_pop_messages_count (mailbox_t mbox, size_t *pcount) ...@@ -901,23 +812,24 @@ mailbox_pop_messages_count (mailbox_t mbox, size_t *pcount)
901 812
902 /* Update and scanning. */ 813 /* Update and scanning. */
903 static int 814 static int
904 mailbox_pop_is_updated (mailbox_t mbox) 815 pop_is_updated (mailbox_t mbox)
905 { 816 {
906 mailbox_pop_data_t mpd; 817 pop_data_t mpd;
907 if ((mpd = (mailbox_pop_data_t)mbox->data) == NULL) 818 if ((mpd = (pop_data_t)mbox->data) == NULL)
908 return 0; 819 return 0;
909 return mpd->is_updated; 820 return mpd->is_updated;
910 } 821 }
911 822
912 static int 823 static int
913 mailbox_pop_num_deleted (mailbox_t mbox, size_t *pnum) 824 pop_num_deleted (mailbox_t mbox, size_t *pnum)
914 { 825 {
915 mailbox_pop_data_t mpd; 826 pop_data_t mpd;
916 size_t i, total; 827 size_t i, total;
917 attribute_t attr; 828 attribute_t attr;
918 if (mbox == NULL || 829
919 (mpd = (mailbox_pop_data_t) mbox->data) == NULL) 830 if (mbox == NULL || (mpd = (pop_data_t) mbox->data) == NULL)
920 return EINVAL; 831 return EINVAL;
832
921 for (i = total = 0; i < mpd->messages_count; i++) 833 for (i = total = 0; i < mpd->messages_count; i++)
922 { 834 {
923 if (message_get_attribute (mpd->pmessages[i]->message, &attr) != 0) 835 if (message_get_attribute (mpd->pmessages[i]->message, &attr) != 0)
...@@ -934,11 +846,12 @@ mailbox_pop_num_deleted (mailbox_t mbox, size_t *pnum) ...@@ -934,11 +846,12 @@ mailbox_pop_num_deleted (mailbox_t mbox, size_t *pnum)
934 846
935 /* We just simulated. */ 847 /* We just simulated. */
936 static int 848 static int
937 mailbox_pop_scan (mailbox_t mbox, size_t msgno, size_t *pcount) 849 pop_scan (mailbox_t mbox, size_t msgno, size_t *pcount)
938 { 850 {
939 int status; 851 int status;
940 size_t i; 852 size_t i;
941 status = mailbox_pop_messages_count (mbox, pcount); 853
854 status = pop_messages_count (mbox, pcount);
942 if (status != 0) 855 if (status != 0)
943 return status; 856 return status;
944 for (i = msgno; i <= *pcount; i++) 857 for (i = msgno; i <= *pcount; i++)
...@@ -949,17 +862,16 @@ mailbox_pop_scan (mailbox_t mbox, size_t msgno, size_t *pcount) ...@@ -949,17 +862,16 @@ mailbox_pop_scan (mailbox_t mbox, size_t msgno, size_t *pcount)
949 862
950 /* This were we actually sending the DELE command. */ 863 /* This were we actually sending the DELE command. */
951 static int 864 static int
952 mailbox_pop_expunge (mailbox_t mbox) 865 pop_expunge (mailbox_t mbox)
953 { 866 {
954 mailbox_pop_data_t mpd; 867 pop_data_t mpd;
955 size_t i; 868 size_t i;
956 attribute_t attr; 869 attribute_t attr;
957 bio_t bio; 870 bio_t bio;
958 int status; 871 int status;
959 void *func = (void *)mailbox_pop_expunge; 872 void *func = (void *)pop_expunge;
960 873
961 if (mbox == NULL || 874 if (mbox == NULL || (mpd = (pop_data_t) mbox->data) == NULL)
962 (mpd = (mailbox_pop_data_t) mbox->data) == NULL)
963 return EINVAL; 875 return EINVAL;
964 876
965 /* Busy ? */ 877 /* Busy ? */
...@@ -969,94 +881,96 @@ mailbox_pop_expunge (mailbox_t mbox) ...@@ -969,94 +881,96 @@ mailbox_pop_expunge (mailbox_t mbox)
969 mpd->func = func; 881 mpd->func = func;
970 bio = mpd->bio; 882 bio = mpd->bio;
971 883
972 for (i = (int)mpd->id; i < mpd->pmessages_count; mpd->id = (void *)++i) 884 for (i = (int)mpd->id; i < mpd->pmessages_count; mpd->id = ++i)
973 { 885 {
974 if (message_get_attribute (mpd->pmessages[i]->message, &attr) == 0) 886 if (message_get_attribute (mpd->pmessages[i]->message, &attr) == 0)
975 { 887 {
976 /* Send DELETE. */
977 if (attribute_is_deleted (attr)) 888 if (attribute_is_deleted (attr))
978 { 889 {
979 switch (mpd->state) 890 switch (mpd->state)
980 { 891 {
981 case 0: 892 case POP_NO_STATE:
982 bio->len = sprintf (bio->buffer, "DELE %d\r\n", 893 bio->len = sprintf (bio->buffer, "DELE %d\r\n",
983 mpd->pmessages[i]->num); 894 mpd->pmessages[i]->num);
984 bio->ptr = bio->buffer; 895 bio->ptr = bio->buffer;
985 mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer); 896 mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
986 mpd->state = 1; 897 mpd->state = POP_DELE_TX;
987 case 1: 898
899 case POP_DELE_TX:
900 /* Send DELETE. */
988 status = bio_write (bio); 901 status = bio_write (bio);
989 if (status != 0) 902 if (status != 0)
990 { 903 {
904 /* Clear the state for non recoverable error. */
991 if (status != EAGAIN && status != EINTR) 905 if (status != EAGAIN && status != EINTR)
992 { 906 {
993 mpd->func = mpd->id = NULL; 907 mpd->func = NULL;
994 mpd->state = 0; 908 mpd->id = 0;
995 fprintf(stderr, "PROBLEM write %d\n", status); 909 mpd->state = POP_NO_STATE;
996 } 910 }
997 return status; 911 return status;
998 } 912 }
999 mpd->state = 2; 913 mpd->state = POP_DELE_ACK;
1000 case 2: 914
915 case POP_DELE_ACK:
1001 status = bio_readline (bio); 916 status = bio_readline (bio);
1002 if (status != 0) 917 if (status != 0)
1003 { 918 {
919 /* Clear the state for non recoverable error. */
1004 if (status != EAGAIN && status != EINTR) 920 if (status != EAGAIN && status != EINTR)
1005 { 921 {
1006 mpd->func = mpd->id = NULL; 922 mpd->func = NULL;
1007 mpd->state = 0; 923 mpd->id = 0;
1008 fprintf(stderr, "PROBLEM readline %d\n", status); 924 mpd->state = POP_NO_STATE;
1009 } 925 }
1010 return status; 926 return status;
1011 } 927 }
1012 mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer); 928 mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
1013 if (strncasecmp (bio->buffer, "+OK", 3) != 0) 929 if (strncasecmp (bio->buffer, "+OK", 3) != 0)
1014 { 930 {
1015 mpd->func = mpd->id = NULL; 931 mpd->func = NULL;
1016 mpd->state = 0; 932 mpd->id = 0;
1017 fprintf(stderr, "PROBLEM strcmp\n"); 933 mpd->state = POP_NO_STATE;
1018 return ERANGE; 934 return ERANGE;
1019 } 935 }
1020 mpd->state = 0; 936 mpd->state = POP_NO_STATE;
937 break;
938 default:
939 /* fprintf (stderr, "pop_expunge: unknow state\n"); */
1021 } /* switch (state) */ 940 } /* switch (state) */
1022 } /* if attribute_is_deleted() */ 941 } /* if attribute_is_deleted() */
1023 } /* message_get_attribute() */ 942 } /* message_get_attribute() */
1024 } /* for */ 943 } /* for */
1025 mpd->func = mpd->id = NULL; 944 mpd->id = 0;
1026 mpd->state = 0; 945 mpd->func = NULL;
1027 /* Invalidate. */ 946 mpd->state = POP_NO_STATE;
947 /* Invalidate. But Really they should shutdown the challen POP protocol
948 is not meant for this like IMAP. */
1028 mpd->is_updated = 0; 949 mpd->is_updated = 0;
1029
1030 return 0; 950 return 0;
1031 } 951 }
1032 952
1033 /* Mailbox size ? */ 953 /* Mailbox size ? */
1034 static int 954 static int
1035 mailbox_pop_size (mailbox_t mbox, off_t *psize) 955 pop_size (mailbox_t mbox, off_t *psize)
1036 { 956 {
1037 mailbox_pop_data_t mpd; 957 pop_data_t mpd;
1038 size_t count; 958 int status = 0;
1039 int status;
1040 959
1041 if (mbox == NULL || (mpd = (mailbox_pop_data_t)mbox->data) == NULL) 960 if (mbox == NULL || (mpd = (pop_data_t)mbox->data) == NULL)
1042 return EINVAL; 961 return EINVAL;
1043 962
1044 if (mailbox_pop_is_updated (mbox)) 963 if (! pop_is_updated (mbox))
1045 { 964 status = pop_messages_count (mbox, &mpd->size);
1046 if (psize)
1047 *psize = mpd->size;
1048 return 0;
1049 }
1050 status = mailbox_pop_messages_count (mbox, &count);
1051 if (psize) 965 if (psize)
1052 *psize = mpd->size; 966 *psize = mpd->size;
1053 return status; 967 return status;
1054 } 968 }
1055 969
1056 static int 970 static int
1057 mailbox_pop_body_size (body_t body, size_t *psize) 971 pop_body_size (body_t body, size_t *psize)
1058 { 972 {
1059 mailbox_pop_message_t mpm; 973 pop_message_t mpm;
1060 if (body == NULL || (mpm = body->owner) == NULL) 974 if (body == NULL || (mpm = body->owner) == NULL)
1061 return EINVAL; 975 return EINVAL;
1062 if (psize) 976 if (psize)
...@@ -1065,29 +979,235 @@ mailbox_pop_body_size (body_t body, size_t *psize) ...@@ -1065,29 +979,235 @@ mailbox_pop_body_size (body_t body, size_t *psize)
1065 } 979 }
1066 980
1067 static int 981 static int
1068 mailbox_pop_getfd (stream_t stream, int *pfd) 982 pop_body_lines (body_t body, size_t *plines)
1069 { 983 {
1070 mailbox_pop_message_t mpm; 984 pop_message_t mpm;
985 if (body == NULL || (mpm = body->owner) == NULL)
986 return EINVAL;
987 if (plines)
988 *plines = mpm->body_lines;
989 return 0;
990 }
991
992 static int
993 pop_get_flags (attribute_t attr, int *pflags)
994 {
995 pop_message_t mpm;
996 char hdr_status[64];
997 header_t header = NULL;
998 int err;
999
1000 if (attr == NULL || (mpm = attr->owner) == NULL)
1001 return EINVAL;
1002 hdr_status[0] = '\0';
1003 message_get_header (mpm->message, &header);
1004 err = header_get_value (header, "Status",
1005 hdr_status, sizeof (hdr_status), NULL);
1006 if (err != 0)
1007 err = string_to_flags (hdr_status, pflags);
1008 return err;
1009 }
1010
1011 static int
1012 pop_get_fd (stream_t stream, int *pfd)
1013 {
1014 pop_message_t mpm;
1071 if (stream == NULL || (mpm = stream->owner) == NULL) 1015 if (stream == NULL || (mpm = stream->owner) == NULL)
1072 return EINVAL; 1016 return EINVAL;
1073 return stream_get_fd (mpm->bio->stream, pfd); 1017 if (mpm->mpd->bio)
1018 return stream_get_fd (mpm->mpd->bio->stream, pfd);
1019 return EINVAL;
1020 }
1021
1022 static int
1023 pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten)
1024 {
1025 pop_message_t mpm;
1026 pop_data_t mpd;
1027 bio_t bio;
1028 int status = 0;
1029 void *func = (void *)pop_uidl;
1030 size_t num;
1031 /* According to the RFC uidl's are no longer then 70 chars. */
1032 char uniq[128];
1033
1034 if (msg == NULL || (mpm = msg->owner) == NULL)
1035 return EINVAL;
1036
1037 mpd = mpm->mpd;
1038 bio = mpd->bio;
1039
1040 /* Busy ? */
1041 if (mpd->func && mpd->func != func)
1042 return EBUSY;
1043
1044 mpd->func = func;
1045
1046 /* Get the UIDL. */
1047 switch (mpd->state)
1048 {
1049 case POP_NO_STATE:
1050 bio->len = sprintf (bio->buffer, "UIDL %d\r\n", mpm->num);
1051 bio->ptr = bio->buffer;
1052 mailbox_debug (mpd->mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
1053 mpd->state = POP_UIDL_TX;
1054
1055 case POP_UIDL_TX:
1056 /* Send the UIDL. */
1057 status = bio_write (bio);
1058 CHECK_NON_RECOVERABLE (mpd, status);
1059 mpd->state = POP_UIDL_ACK;
1060
1061 case POP_UIDL_ACK:
1062 /* Resp from TOP. */
1063 status = bio_readline (bio);
1064 CHECK_NON_RECOVERABLE (mpd, status);
1065 mailbox_debug (mpd->mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
1066 break;
1067 default:
1068 /*
1069 fprintf (stderr, "pop_uidl state\n");
1070 */
1071 }
1072
1073 CLEAR_STATE (mpd);
1074
1075 *uniq = '\0';
1076 status = sscanf (bio->buffer, "+OK %d %127s\n", &num, uniq);
1077 if (status != 2)
1078 {
1079 status = EINVAL;
1080 buflen = 0;
1081 }
1082 else
1083 {
1084 num = strlen (uniq);
1085 uniq[num - 1] = '\0'; /* Nuke newline. */
1086 buflen = (buflen < num) ? buflen : num;
1087 memcpy (buffer, uniq, buflen);
1088 buffer [buflen - 1] = '\0';
1089 status = 0;
1090 }
1091 if (pnwriten)
1092 *pnwriten = buflen;
1093 return status;
1094 }
1095
1096 static int
1097 pop_header_read (stream_t is, char *buffer, size_t buflen,
1098 off_t offset, size_t *pnread)
1099 {
1100 pop_message_t mpm;
1101 pop_data_t mpd;
1102 bio_t bio;
1103 size_t nread = 0;
1104 int status = 0;
1105 void *func = (void *)pop_header_read;
1106
1107 if (is == NULL || (mpm = is->owner) == NULL)
1108 return EINVAL;
1109
1110 (void)offset;
1111 mpd = mpm->mpd;
1112 bio = mpd->bio;
1113
1114 /* Busy ? */
1115 if (mpd->func && mpd->func != func)
1116 return EBUSY;
1117
1118 mpd->func = func;
1119
1120 /* Get the header. */
1121 switch (mpd->state)
1122 {
1123 case POP_NO_STATE:
1124 /* TOP is an optionnal command, if we want to be compliant we can not
1125 count on it to exists. So we should be prepare when it fails and
1126 fall to a second scheme. */
1127 bio->len = sprintf (bio->buffer, "TOP %d 0\r\n", mpm->num);
1128 bio->ptr = bio->buffer;
1129 mailbox_debug (mpd->mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
1130 mpd->state = POP_TOP_TX;
1131
1132 case POP_TOP_TX:
1133 /* Send the TOP. */
1134 status = bio_write (bio);
1135 CHECK_NON_RECOVERABLE (mpd, status);
1136 mpd->state = POP_TOP_ACK;
1137
1138 case POP_TOP_ACK:
1139 /* Ack from TOP. */
1140 status = bio_readline (bio);
1141 CHECK_NON_RECOVERABLE (mpd, status);
1142 mailbox_debug (mpd->mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
1143 if (strncasecmp (bio->buffer, "+OK", 3) != 0)
1144 {
1145 fprintf (stderr, "TOP not implmented\n");
1146 CLEAR_STATE (mpd);
1147 return ENOSYS;
1148 }
1149 mpd->state = POP_TOP_RX;
1150 bio->current = bio->nl;
1151
1152 case POP_TOP_RX:
1153 /* Get the header. */
1154 {
1155 int nleft, n;
1156 /* Do we need to fill up. */
1157 if (bio->current >= bio->nl)
1158 {
1159 bio->current = bio->buffer;
1160 status = bio_readline (bio);
1161 CHECK_NON_RECOVERABLE (mpd, status);
1162 }
1163 n = bio->nl - bio->current;
1164 nleft = buflen - n;
1165 /* We got more then requested. */
1166 if (nleft <= 0)
1167 {
1168 memcpy (buffer, bio->current, buflen);
1169 bio->current += buflen;
1170 nread = buflen;
1171 }
1172 else
1173 {
1174 /* Drain the buffer. */
1175 memcpy (buffer, bio->current, n);
1176 bio->current += n;
1177 nread = n;
1178 }
1179 break;
1180 }
1181 break;
1182 default:
1183 /* fprintf (stderr, "pop_header_blurb unknown state\n"); */
1184 } /* switch (state) */
1185
1186 if (nread == 0)
1187 {
1188 CLEAR_STATE (mpd);
1189 }
1190 if (pnread)
1191 *pnread = nread;
1192 return 0;
1074 } 1193 }
1075 1194
1076 static int 1195 static int
1077 mailbox_pop_readstream (stream_t is, char *buffer, size_t buflen, 1196 pop_readstream (stream_t is, char *buffer, size_t buflen,
1078 off_t offset, size_t *pnread) 1197 off_t offset, size_t *pnread)
1079 { 1198 {
1080 mailbox_pop_message_t mpm; 1199 pop_message_t mpm;
1081 mailbox_pop_data_t mpd; 1200 pop_data_t mpd;
1082 size_t nread = 0; 1201 size_t nread = 0;
1083 bio_t bio; 1202 bio_t bio;
1084 int status = 0; 1203 int status = 0;
1085 void *func = (void *)mailbox_pop_readstream; 1204 void *func = (void *)pop_readstream;
1086 1205
1087 (void)offset; 1206 (void)offset;
1088 if (is == NULL || (mpm = is->owner) == NULL) 1207 if (is == NULL || (mpm = is->owner) == NULL)
1089 return EINVAL; 1208 return EINVAL;
1090 1209
1210 /* Take care of the obvious. */
1091 if (buffer == NULL || buflen == 0) 1211 if (buffer == NULL || buflen == 0)
1092 { 1212 {
1093 if (pnread) 1213 if (pnread)
...@@ -1095,67 +1215,44 @@ mailbox_pop_readstream (stream_t is, char *buffer, size_t buflen, ...@@ -1095,67 +1215,44 @@ mailbox_pop_readstream (stream_t is, char *buffer, size_t buflen,
1095 return 0; 1215 return 0;
1096 } 1216 }
1097 1217
1098 bio = mpm->bio;
1099 mpd = mpm->mpd; 1218 mpd = mpm->mpd;
1219 bio = mpd->bio;
1100 1220
1101 /* Busy ? */ 1221 /* Busy ? */
1102 if (mpd->func && mpd->func != func) 1222 if (mpd->func && mpd->func != func)
1103 return EBUSY; 1223 return EBUSY;
1104 1224
1105 /* Which request. */
1106 if (mpd->id && mpd->id != mpm)
1107 return EBUSY;
1108
1109 mpd->func = func; 1225 mpd->func = func;
1110 mpd->id = mpm;
1111 1226
1112 switch (mpd->state) 1227 switch (mpd->state)
1113 { 1228 {
1114 /* Send the RETR command. */ 1229 case POP_NO_STATE:
1115 case 0:
1116 bio->len = sprintf (bio->buffer, "RETR %d\r\n", mpm->num); 1230 bio->len = sprintf (bio->buffer, "RETR %d\r\n", mpm->num);
1117 mpd->state = 1; 1231 mpd->state = POP_RETR_TX;
1118 case 1: 1232
1233 case POP_RETR_TX:
1234 /* Send the RETR command. */
1119 status = bio_write (bio); 1235 status = bio_write (bio);
1120 if (status != 0) 1236 CHECK_NON_RECOVERABLE (mpd, status);
1121 { 1237 mpd->state = POP_RETR_ACK;
1122 if (status != EAGAIN && status != EINTR) 1238
1123 { 1239 case POP_RETR_ACK:
1124 mpd->func = mpd->id = NULL;
1125 mpd->state = 0;
1126 }
1127 return status;
1128 }
1129 mpd->state = 2;
1130 /* RETR ACK. */ 1240 /* RETR ACK. */
1131 case 2:
1132 status = bio_readline (bio); 1241 status = bio_readline (bio);
1133 if (status != 0) 1242 CHECK_NON_RECOVERABLE (mpd, status);
1243 if (strncasecmp (bio->buffer, "+OK", 3) != 0)
1134 { 1244 {
1135 if (status != EAGAIN && status != EINTR) 1245 CLEAR_STATE (mpd);
1136 { 1246 return EACCES;
1137 mpd->func = mpd->id = NULL;
1138 mpd->state = 0;
1139 }
1140 return status;
1141 } 1247 }
1142 if (strncasecmp (bio->buffer, "+OK", 3) != 0) 1248 mpd->state = POP_RETR_RX_HDR;
1143 return EINVAL; 1249
1144 mpd->state = 3; 1250 case POP_RETR_RX_HDR:
1145 /* Skip the header. */ 1251 /* Skip the header. */
1146 case 3:
1147 while (!mpm->inbody) 1252 while (!mpm->inbody)
1148 { 1253 {
1149 status = bio_readline (bio); 1254 status = bio_readline (bio);
1150 if (status != 0) 1255 CHECK_NON_RECOVERABLE (mpd, status);
1151 {
1152 if (status != EAGAIN && status != EINTR)
1153 {
1154 mpd->func = mpd->id = NULL;
1155 mpd->state = 0;
1156 }
1157 return status;
1158 }
1159 if (bio->buffer[0] == '\n') 1256 if (bio->buffer[0] == '\n')
1160 { 1257 {
1161 mpm->inbody = 1; 1258 mpm->inbody = 1;
...@@ -1164,10 +1261,11 @@ mailbox_pop_readstream (stream_t is, char *buffer, size_t buflen, ...@@ -1164,10 +1261,11 @@ mailbox_pop_readstream (stream_t is, char *buffer, size_t buflen,
1164 } 1261 }
1165 /* Skip the newline. */ 1262 /* Skip the newline. */
1166 bio_readline (bio); 1263 bio_readline (bio);
1167 /* Start taking the header. */ 1264 bio->current = bio->current;
1168 mpd->state = 4; 1265 mpd->state = POP_RETR_RX_BODY;
1169 bio->current = bio->buffer; 1266
1170 case 4: 1267 case POP_RETR_RX_BODY:
1268 /* Start taking the body. */
1171 { 1269 {
1172 int nleft, n; 1270 int nleft, n;
1173 /* Do we need to fill up. */ 1271 /* Do we need to fill up. */
...@@ -1175,14 +1273,7 @@ mailbox_pop_readstream (stream_t is, char *buffer, size_t buflen, ...@@ -1175,14 +1273,7 @@ mailbox_pop_readstream (stream_t is, char *buffer, size_t buflen,
1175 { 1273 {
1176 bio->current = bio->buffer; 1274 bio->current = bio->buffer;
1177 status = bio_readline (bio); 1275 status = bio_readline (bio);
1178 if (status != 0) 1276 CHECK_NON_RECOVERABLE (mpd, status);
1179 {
1180 if (status != EAGAIN && status != EINTR)
1181 {
1182 mpd->func = mpd->id = NULL;
1183 mpd->state = 0;
1184 }
1185 }
1186 } 1277 }
1187 n = bio->nl - bio->current; 1278 n = bio->nl - bio->current;
1188 nleft = buflen - n; 1279 nleft = buflen - n;
...@@ -1200,13 +1291,15 @@ mailbox_pop_readstream (stream_t is, char *buffer, size_t buflen, ...@@ -1200,13 +1291,15 @@ mailbox_pop_readstream (stream_t is, char *buffer, size_t buflen,
1200 bio->current += n; 1291 bio->current += n;
1201 nread = n; 1292 nread = n;
1202 } 1293 }
1294 break;
1203 } 1295 }
1296 default:
1297 /* fprintf (stderr, "pop_readstream unknow state\n"); */
1204 } /* Switch state. */ 1298 } /* Switch state. */
1205 1299
1206 if (nread == 0) 1300 if (nread == 0)
1207 { 1301 {
1208 mpd->func = mpd->id = NULL; 1302 CLEAR_STATE (mpd);
1209 mpd->state = 0;
1210 } 1303 }
1211 if (pnread) 1304 if (pnread)
1212 *pnread = nread; 1305 *pnread = nread;
...@@ -1221,12 +1314,7 @@ bio_create (bio_t *pbio, stream_t stream) ...@@ -1221,12 +1314,7 @@ bio_create (bio_t *pbio, stream_t stream)
1221 if (bio == NULL) 1314 if (bio == NULL)
1222 return ENOMEM; 1315 return ENOMEM;
1223 bio->maxlen = POP_BUFSIZ + 1; 1316 bio->maxlen = POP_BUFSIZ + 1;
1224 bio->current = bio->ptr = bio->buffer = calloc (1, POP_BUFSIZ + 1); 1317 bio->current = bio->ptr = bio->buffer = calloc (1, bio->maxlen);
1225 if (bio->buffer == NULL)
1226 {
1227 free (bio);
1228 return ENOMEM;
1229 }
1230 bio->stream = stream; 1318 bio->stream = stream;
1231 *pbio = bio; 1319 *pbio = bio;
1232 return 0; 1320 return 0;
...@@ -1273,8 +1361,8 @@ bio_read (bio_t bio) ...@@ -1273,8 +1361,8 @@ bio_read (bio_t bio)
1273 status = stream_read (bio->stream, bio->ptr, len, 0, &nread); 1361 status = stream_read (bio->stream, bio->ptr, len, 0, &nread);
1274 if (status != 0) 1362 if (status != 0)
1275 return status; 1363 return status;
1276 else if (nread == 0) 1364 else if (nread == 0) /* EOF ???? We got a situation here ??? */
1277 { /* EOF ???? We got a situation here ??? */ 1365 {
1278 bio->buffer[0] = '.'; 1366 bio->buffer[0] = '.';
1279 bio->buffer[1] = '\r'; 1367 bio->buffer[1] = '\r';
1280 bio->buffer[2] = '\n'; 1368 bio->buffer[2] = '\n';
...@@ -1312,7 +1400,7 @@ bio_readline (bio_t bio) ...@@ -1312,7 +1400,7 @@ bio_readline (bio_t bio)
1312 for (;;) 1400 for (;;)
1313 { 1401 {
1314 status = bio_read (bio); 1402 status = bio_read (bio);
1315 if (status < 0) 1403 if (status != 0)
1316 return status; 1404 return status;
1317 len = bio->ptr - bio->buffer; 1405 len = bio->ptr - bio->buffer;
1318 /* Newline. */ 1406 /* Newline. */
......
...@@ -49,57 +49,57 @@ ...@@ -49,57 +49,57 @@
49 #include <ctype.h> 49 #include <ctype.h>
50 #include <limits.h> 50 #include <limits.h>
51 51
52 static int mailbox_unix_create (mailbox_t *pmbox, const char *name); 52 #define ATTRIBUTE_IS_DELETED(flag) (flag & MU_ATTRIBUTE_DELETED)
53 static void mailbox_unix_destroy (mailbox_t *pmbox); 53 #define ATTRIBUTE_IS_EQUAL(flag1, flag2) (flag1 == flag2)
54
55 static int unix_create (mailbox_t *pmbox, const char *name);
56 static void unix_destroy (mailbox_t *pmbox);
54 57
55 struct mailbox_registrar _mailbox_unix_registrar = 58 struct mailbox_registrar _mailbox_unix_registrar =
56 { 59 {
57 "UNIX MBOX", 60 "UNIX MBOX",
58 mailbox_unix_create, mailbox_unix_destroy 61 unix_create, unix_destroy
59 }; 62 };
60 63
61 /* 64 /* Keep the position of where the header and body starts and ends.
62 * Keep the position of where the header and body starts 65 old_flags is the "Status:" message. */
63 * and ends. old_attr is the "Status:" message. 66 typedef struct _unix_message
64 */
65 typedef struct _mailbox_unix_message
66 { 67 {
67 /* offset of the parts of the messages in the mailbox*/ 68 /* Offset of the parts of the messages in the mailbox. */
68 off_t header_from; 69 off_t header_from;
69 off_t header_from_end; 70 off_t header_from_end;
70 /* little hack to make things easier 71 /* Little hack to make things easier * when updating the attribute. */
71 * when updating the attribute
72 */
73 off_t header_status; 72 off_t header_status;
74 off_t header_status_end; 73 off_t header_status_end;
75 off_t body; 74 off_t body;
76 off_t body_end; 75 off_t body_end;
77 76
78 /* old_attr contains the definition of Header: */ 77 /* The old_flags contains the definition of Header. */
79 /* new_attr what we want when expunging */ 78 int old_flags;
80 attribute_t old_attr; 79 /* The new_flags holds the attributes changes for the current session. We
81 attribute_t new_attr; 80 use this so when expunging we can tell when an attribute been modified.
81 This is a big help so we can jump to the first modify email for speed
82 in expunging (see mark dirty). */
83 int new_flags;
82 84
83 size_t header_lines; 85 size_t header_lines;
84 size_t body_lines; 86 size_t body_lines;
85 stream_t stream; 87 stream_t stream;
86 88
87 /* if we have a message attach to it */ 89 /* A message attach to it. */
88 message_t message; 90 message_t message;
89 91
90 } *mailbox_unix_message_t; 92 } *unix_message_t;
91 93
92 /* 94 /* The umessages is an array of pointers that contains umessages_count of
93 * umessages is an array of pointers that contains umessages_count 95 unix_message_t*; umessages[umessages_count]. We do it this because
94 * of mailbox_unix_message_t*; umessages[umessages_count]. 96 realloc() can move everything to a new memory region and invalidating all
95 * We do it this because realloc() can move everything to 97 the pointers someone has on the messages. Thanks to <Dave Inglis> for
96 * a new memory region and invalidating all the pointers someone 98 pointing this out. The messages_count is the count number of messages
97 * has on the messages. Thanks to <Dave Inglis> for pointing this out. 99 parsed so far. */
98 * messages_count is the count number of messages parsed so far. 100 typedef struct _unix_data
99 */
100 typedef struct _mailbox_unix_data
101 { 101 {
102 mailbox_unix_message_t *umessages; 102 unix_message_t *umessages;
103 size_t umessages_count; 103 size_t umessages_count;
104 size_t messages_count; 104 size_t messages_count;
105 stream_t stream; 105 stream_t stream;
...@@ -110,59 +110,55 @@ typedef struct _mailbox_unix_data ...@@ -110,59 +110,55 @@ typedef struct _mailbox_unix_data
110 #endif 110 #endif
111 off_t size; 111 off_t size;
112 112
113 } *mailbox_unix_data_t; 113 } *unix_data_t;
114
115 static int mailbox_unix_open (mailbox_t mbox, int flag);
116 static int mailbox_unix_close (mailbox_t mbox);
117
118 static int mailbox_unix_get_message (mailbox_t, size_t msgno, message_t *msg);
119 static int mailbox_unix_append_message (mailbox_t, message_t msg);
120 static int mailbox_unix_messages_count (mailbox_t, size_t *msgno);
121 static int mailbox_unix_expunge (mailbox_t);
122 static int mailbox_unix_num_deleted (mailbox_t, size_t *);
123
124 static int mailbox_unix_scan0 (mailbox_t, size_t count, size_t *pcount, int);
125 static int mailbox_unix_scan (mailbox_t, size_t count, size_t *pcount);
126 static int mailbox_unix_is_updated (mailbox_t);
127 114
128 static int mailbox_unix_size (mailbox_t, off_t *size); 115 static int unix_open (mailbox_t mbox, int flag);
116 static int unix_close (mailbox_t mbox);
117 static int unix_get_message (mailbox_t, size_t msgno, message_t *msg);
118 static int unix_append_message (mailbox_t, message_t msg);
119 static int unix_messages_count (mailbox_t, size_t *msgno);
120 static int unix_expunge (mailbox_t);
121 static int unix_num_deleted (mailbox_t, size_t *);
122 static int unix_scan (mailbox_t, size_t count, size_t *pcount);
123 static int unix_is_updated (mailbox_t);
124 static int unix_size (mailbox_t, off_t *size);
129 125
130 126
131 /* private stuff */ 127 /* private stuff */
132 128 static int unix_scan0 (mailbox_t, size_t count, size_t *pcount, int);
133 static int mailbox_unix_get_header (mailbox_unix_message_t mum, char *buffer, 129 static int unix_get_header_read (stream_t is, char *buffer, size_t len,
134 size_t len, off_t off, ssize_t *pnread); 130 off_t off, size_t *pnread);
135 static int mailbox_unix_getfd (stream_t is, int *pfd); 131 static int unix_get_fd (stream_t is, int *pfd);
136 static int mailbox_unix_readstream (stream_t is, char *buffer, size_t buflen, 132 static int unix_get_flags (attribute_t, int *);
133 static int unix_set_flags (attribute_t, int);
134 static int unix_unset_flags (attribute_t, int);
135 static int unix_readstream (stream_t is, char *buffer, size_t buflen,
137 off_t off, size_t *pnread); 136 off_t off, size_t *pnread);
138 static int mailbox_unix_body_size (body_t body, size_t *psize); 137 static int unix_body_size (body_t body, size_t *psize);
139 static int mailbox_unix_body_lines (body_t body, size_t *plines); 138 static int unix_body_lines (body_t body, size_t *plines);
140 static int mailbox_unix_msg_from (message_t msg, char *buf, size_t len, 139 static int unix_msg_from (message_t msg, char *buf, size_t len,
141 size_t *pnwrite); 140 size_t *pnwrite);
142 static int mailbox_unix_msg_received (message_t msg, char *buf, size_t len, 141 static int unix_msg_received (message_t msg, char *buf, size_t len,
143 size_t *pnwrite); 142 size_t *pnwrite);
144 static int mailbox_unix_lock (mailbox_t mbox, int flag); 143 static int unix_lock (mailbox_t mbox, int flag);
145 static int mailbox_unix_touchlock (mailbox_t mbox); 144 static int unix_touchlock (mailbox_t mbox);
146 static int mailbox_unix_unlock (mailbox_t mbox); 145 static int unix_unlock (mailbox_t mbox);
147 static int mailbox_unix_ilock (mailbox_t mbox, int flag); 146 static int unix_ilock (mailbox_t mbox, int flag);
148 static int mailbox_unix_iunlock (mailbox_t mbox); 147 static int unix_iunlock (mailbox_t mbox);
149 148
150 /* We allocate the mailbox_t struct, but don't do any 149 /* We allocate the mailbox_t struct, but don't do any parsing on the name or
151 * parsing on the name or even test for existence. 150 even test for existence. However we do strip any leading "unix:" part of
152 * However we do strip any leading "unix:" part of 151 the name, this is suppose to be the protocol/scheme name. Hopefully there
153 * the name, this is suppose to be the protocol/scheme name. 152 will not be a mailbox name "unix:". */
154 * Hopefully there will not be a mailbox name "unix:"
155 */
156 static int 153 static int
157 mailbox_unix_create (mailbox_t *pmbox, const char *name) 154 unix_create (mailbox_t *pmbox, const char *name)
158 { 155 {
159 mailbox_t mbox; 156 mailbox_t mbox;
160 mailbox_unix_data_t mud; 157 unix_data_t mud;
161 const char *sep; 158 const char *sep;
162 size_t name_len; 159 size_t name_len;
163 int i;
164 160
165 /* sanity check */ 161 /* Sanity check. */
166 if (name == NULL || *name == '\0') 162 if (name == NULL || *name == '\0')
167 return MU_ERROR_INVALID_ARG; 163 return MU_ERROR_INVALID_ARG;
168 164
...@@ -172,7 +168,7 @@ mailbox_unix_create (mailbox_t *pmbox, const char *name) ...@@ -172,7 +168,7 @@ mailbox_unix_create (mailbox_t *pmbox, const char *name)
172 #define UNIX_SCHEME_LEN 5 168 #define UNIX_SCHEME_LEN 5
173 #define SEPARATOR '/' 169 #define SEPARATOR '/'
174 170
175 /* skip the url scheme */ 171 /* Skip the url scheme. */
176 if (name_len > UNIX_SCHEME_LEN && 172 if (name_len > UNIX_SCHEME_LEN &&
177 (name[0] == 'u' || name[0] == 'U') && 173 (name[0] == 'u' || name[0] == 'U') &&
178 (name[1] == 'n' || name[1] == 'N') && 174 (name[1] == 'n' || name[1] == 'N') &&
...@@ -184,50 +180,38 @@ mailbox_unix_create (mailbox_t *pmbox, const char *name) ...@@ -184,50 +180,38 @@ mailbox_unix_create (mailbox_t *pmbox, const char *name)
184 name_len -= UNIX_SCHEME_LEN; 180 name_len -= UNIX_SCHEME_LEN;
185 } 181 }
186 182
187 /* allocate memory for mbox */ 183 /* Allocate memory for mbox. */
188 mbox = calloc (1, sizeof (*mbox)); 184 mbox = calloc (1, sizeof (*mbox));
189 if (mbox == NULL) 185 if (mbox == NULL)
190 return MU_ERROR_OUT_OF_MEMORY; 186 return MU_ERROR_OUT_OF_MEMORY;
191 187
192 /* allocate specific unix mbox data */ 188 /* Allocate specific unix mbox data. */
193 mud = mbox->data = calloc (1, sizeof (*mud)); 189 mud = mbox->data = calloc (1, sizeof (*mud));
194 if (mbox->data == NULL) 190 if (mbox->data == NULL)
195 { 191 {
196 mailbox_unix_destroy (&mbox); 192 unix_destroy (&mbox);
197 return MU_ERROR_OUT_OF_MEMORY; 193 return MU_ERROR_OUT_OF_MEMORY;
198 } 194 }
199 195
200 /* copy the name */ 196 /* Copy the name. */
201 mbox->name = calloc (name_len + 1, sizeof (char)); 197 mbox->name = calloc (name_len + 1, sizeof (char));
202 if (mbox->name == NULL) 198 if (mbox->name == NULL)
203 { 199 {
204 mailbox_unix_destroy (&mbox); 200 unix_destroy (&mbox);
205 return MU_ERROR_OUT_OF_MEMORY; 201 return MU_ERROR_OUT_OF_MEMORY;
206 } 202 }
207 memcpy (mbox->name, name, name_len); 203 memcpy (mbox->name, name, name_len);
208 204
209 /* save the basename and dirname 205 /* Save the basename and dirname. We split the name, but this should
210 * So we split the name. But this should probably be 206 probably be supported via "maildir:" or the mailbox mgr. */
211 * supported via "maildir:" or the mailbox mgr. 207 sep = strrchr (name, SEPARATOR);
212 */
213 /* equivalent to strrchr (name, '/'); */
214 for (i = name_len, sep = NULL; i >= 0; i--)
215 {
216 /* break on the first separator */
217 if (name[i] == SEPARATOR)
218 {
219 sep = &(name[i]);
220 break;
221 }
222 }
223
224 if (sep) 208 if (sep)
225 { 209 {
226 /* split it into two */ 210 /* Split it into two. */
227 mud->dirname = calloc ((sep - name) + 1, sizeof (char)); 211 mud->dirname = calloc ((sep - name) + 1, sizeof (char));
228 if (mud->dirname == NULL) 212 if (mud->dirname == NULL)
229 { 213 {
230 mailbox_unix_destroy (&mbox); 214 unix_destroy (&mbox);
231 return MU_ERROR_OUT_OF_MEMORY; 215 return MU_ERROR_OUT_OF_MEMORY;
232 } 216 }
233 memcpy (mud->dirname, name, sep - name); 217 memcpy (mud->dirname, name, sep - name);
...@@ -236,19 +220,19 @@ mailbox_unix_create (mailbox_t *pmbox, const char *name) ...@@ -236,19 +220,19 @@ mailbox_unix_create (mailbox_t *pmbox, const char *name)
236 mud->basename = calloc (name_len - (sep - name) + 1, sizeof (char)); 220 mud->basename = calloc (name_len - (sep - name) + 1, sizeof (char));
237 if (mud->basename == NULL) 221 if (mud->basename == NULL)
238 { 222 {
239 mailbox_unix_destroy (&mbox); 223 unix_destroy (&mbox);
240 return MU_ERROR_OUT_OF_MEMORY; 224 return MU_ERROR_OUT_OF_MEMORY;
241 } 225 }
242 memcpy (mud->basename, sep, name_len - (sep - name)); 226 memcpy (mud->basename, sep, name_len - (sep - name));
243 } 227 }
244 else 228 else
245 { 229 {
246 /* use the relative directory "." */ 230 /* Use the relative directory ".". */
247 /* FIXME: should we call getcwd() instead ? */ 231 /* FIXME: should we call getcwd () instead ? */
248 mud->dirname = calloc (2 , sizeof (char)); 232 mud->dirname = calloc (2 , sizeof (char));
249 if (mud->dirname == NULL) 233 if (mud->dirname == NULL)
250 { 234 {
251 mailbox_unix_destroy (&mbox); 235 unix_destroy (&mbox);
252 return MU_ERROR_OUT_OF_MEMORY; 236 return MU_ERROR_OUT_OF_MEMORY;
253 } 237 }
254 mud->dirname[0] = '.'; 238 mud->dirname[0] = '.';
...@@ -256,37 +240,37 @@ mailbox_unix_create (mailbox_t *pmbox, const char *name) ...@@ -256,37 +240,37 @@ mailbox_unix_create (mailbox_t *pmbox, const char *name)
256 mud->basename = calloc (name_len + 1, sizeof (char)); 240 mud->basename = calloc (name_len + 1, sizeof (char));
257 if (mud->basename == NULL) 241 if (mud->basename == NULL)
258 { 242 {
259 mailbox_unix_destroy (&mbox); 243 unix_destroy (&mbox);
260 return MU_ERROR_OUT_OF_MEMORY; 244 return MU_ERROR_OUT_OF_MEMORY;
261 } 245 }
262 memcpy (mud->basename, name, name_len); 246 memcpy (mud->basename, name, name_len);
263 } 247 }
264 248
265 #ifdef HAVE_PHTREAD_H 249 #ifdef HAVE_PHTREAD_H
266 /* mutex when accessing the structure fields */ 250 /* Mutex when accessing the structure fields. */
267 /* FIXME: should we use rdwr locks instead ?? */ 251 /* FIXME: should we use rdwr locks instead ?? */
268 pthread_mutex_init (&(mbox->mutex), NULL); 252 pthread_mutex_init (&(mbox->mutex), NULL);
269 #endif 253 #endif
270 254
271 mbox->_create = mailbox_unix_create; 255 mbox->_create = unix_create;
272 mbox->_destroy = mailbox_unix_destroy; 256 mbox->_destroy = unix_destroy;
273 257
274 mbox->_open = mailbox_unix_open; 258 mbox->_open = unix_open;
275 mbox->_close = mailbox_unix_close; 259 mbox->_close = unix_close;
276 260
277 /* messages */ 261 /* Messages. */
278 mbox->_get_message = mailbox_unix_get_message; 262 mbox->_get_message = unix_get_message;
279 mbox->_append_message = mailbox_unix_append_message; 263 mbox->_append_message = unix_append_message;
280 mbox->_messages_count = mailbox_unix_messages_count; 264 mbox->_messages_count = unix_messages_count;
281 mbox->_expunge = mailbox_unix_expunge; 265 mbox->_expunge = unix_expunge;
282 mbox->_num_deleted = mailbox_unix_num_deleted; 266 mbox->_num_deleted = unix_num_deleted;
283 267
284 mbox->_scan = mailbox_unix_scan; 268 mbox->_scan = unix_scan;
285 mbox->_is_updated = mailbox_unix_is_updated; 269 mbox->_is_updated = unix_is_updated;
286 270
287 mbox->_size = mailbox_unix_size; 271 mbox->_size = unix_size;
288 272
289 mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, "mailbox_unix_create (%s/%s)\n", 273 mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, "unix_create (%s/%s)\n",
290 mud->dirname, mud->basename); 274 mud->dirname, mud->basename);
291 (*pmbox) = mbox; 275 (*pmbox) = mbox;
292 276
...@@ -294,40 +278,37 @@ mailbox_unix_create (mailbox_t *pmbox, const char *name) ...@@ -294,40 +278,37 @@ mailbox_unix_create (mailbox_t *pmbox, const char *name)
294 } 278 }
295 279
296 static void 280 static void
297 mailbox_unix_destroy (mailbox_t *pmbox) 281 unix_destroy (mailbox_t *pmbox)
298 { 282 {
299 if (pmbox && *pmbox) 283 if (pmbox && *pmbox)
300 { 284 {
301 mailbox_t mbox = *pmbox; 285 mailbox_t mbox = *pmbox;
302 mailbox_unix_close (mbox); 286 unix_close (mbox);
303 if (mbox->data) 287 if (mbox->data)
304 { 288 {
305 size_t i; 289 size_t i;
306 mailbox_unix_data_t mud = mbox->data; 290 unix_data_t mud = mbox->data;
307 mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, 291 mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE,
308 "mailbox_unix_destroy (%s/%s)\n", 292 "unix_destroy (%s/%s)\n",
309 mud->dirname, mud->basename); 293 mud->dirname, mud->basename);
310 free (mud->dirname); 294 free (mud->dirname);
311 free (mud->basename); 295 free (mud->basename);
312 for (i = 0; i < mud->umessages_count; i++) 296 for (i = 0; i < mud->umessages_count; i++)
313 { 297 {
314 mailbox_unix_message_t mum = mud->umessages[i]; 298 unix_message_t mum = mud->umessages[i];
315 if (mum == NULL) 299 if (mum == NULL)
316 continue; 300 {
317 /* Destroy the attach messages */ 301 message_destroy (&(mum->message), mum);
318 attribute_destroy (&(mum->old_attr)); 302 free (mum);
319 message_destroy (&(mum->message), mum); 303 }
320 /* new_attr free by message_destroy() */
321 /* attribute_destroy (&(mum->new_attr)); */
322 free (mum);
323 } 304 }
324 free (mud->umessages); 305 free (mud->umessages);
325 free (mbox->data); 306 free (mbox->data);
326 } 307 }
327 free (mbox->name); 308 free (mbox->name);
328 /* free the event array */ 309 /* Free the event array. */
329 free (mbox->event); 310 free (mbox->event);
330 /* destroy the url */ 311 /* Destroy the url. */
331 if (mbox->url) 312 if (mbox->url)
332 url_destroy (&(mbox->url)); 313 url_destroy (&(mbox->url));
333 if (mbox->locker) 314 if (mbox->locker)
...@@ -336,38 +317,38 @@ mailbox_unix_destroy (mailbox_t *pmbox) ...@@ -336,38 +317,38 @@ mailbox_unix_destroy (mailbox_t *pmbox)
336 auth_destroy (&(mbox->auth), mbox); 317 auth_destroy (&(mbox->auth), mbox);
337 if(mbox->stream) 318 if(mbox->stream)
338 stream_destroy (&(mbox->stream), mbox); 319 stream_destroy (&(mbox->stream), mbox);
339 mailbox_unix_iunlock (mbox); 320 unix_iunlock (mbox);
340 #ifdef HAVE_PTHREAD_H 321 #ifdef HAVE_PTHREAD_H
341 if (mbox->mutex) 322 if (mbox->mutex)
342 ptread_mutex_destroy (&(mbox->mutex)); 323 ptread_mutex_destroy (&(mbox->mutex));
343 #endif 324 #endif
344 free (*pmbox); 325 free (mbox);
345 *pmbox = NULL; 326 *pmbox = NULL;
346 } 327 }
347 } 328 }
348 329
349 /* Open the file. */ 330 /* Open the file. */
350 static int 331 static int
351 mailbox_unix_open (mailbox_t mbox, int flags) 332 unix_open (mailbox_t mbox, int flags)
352 { 333 {
353 mailbox_unix_data_t mud; 334 unix_data_t mud;
354 int status = 0; 335 int status = 0;
355 336
356 if (mbox == NULL || 337 if (mbox == NULL ||
357 (mud = (mailbox_unix_data_t)mbox->data) == NULL) 338 (mud = (unix_data_t)mbox->data) == NULL)
358 return EINVAL; 339 return EINVAL;
359 340
360 /* Authentication prologues */ 341 /* Authentication prologues. */
361 if (mbox->auth) 342 if (mbox->auth)
362 auth_prologue (mbox->auth); 343 auth_prologue (mbox->auth);
363 344
364 /* get a stream */ 345 /* Get a stream. */
365 if (mbox->stream == NULL) 346 if (mbox->stream == NULL)
366 { 347 {
367 /* FIXME: for small mbox we shout try to mmap() */ 348 /* FIXME: for small mbox we shout try to mmap (). */
368 349
369 status = (flags & MU_STREAM_CREAT) || (flags & MU_STREAM_APPEND); 350 int trymap = (flags & MU_STREAM_CREAT) || (flags & MU_STREAM_APPEND);
370 if (status == 0) 351 if (trymap == 0)
371 status = mapfile_stream_create (&(mbox->stream)); 352 status = mapfile_stream_create (&(mbox->stream));
372 if (status != 0) 353 if (status != 0)
373 { 354 {
...@@ -377,76 +358,55 @@ mailbox_unix_open (mailbox_t mbox, int flags) ...@@ -377,76 +358,55 @@ mailbox_unix_open (mailbox_t mbox, int flags)
377 } 358 }
378 status = stream_open (mbox->stream, mbox->name, 0, flags); 359 status = stream_open (mbox->stream, mbox->name, 0, flags);
379 if (status != 0) 360 if (status != 0)
380 { 361 return status;
381 stream_destroy (&(mbox->stream), mbox);
382 return status;
383 }
384 } 362 }
385 else 363 else
386 { 364 {
387 status = stream_open (mbox->stream, mbox->name, 0, flags); 365 status = stream_open (mbox->stream, mbox->name, 0, flags);
388 if (status != 0) 366 if (status != 0)
389 {
390 stream_destroy (&(mbox->stream), mbox);
391 return status;
392 }
393 }
394
395 /* Authentication */
396 if (mbox->auth)
397 {
398 char *user = NULL;
399 char *passwd = NULL;
400 status = auth_authenticate (mbox->auth, &user, &passwd);
401 free (user);
402 free (passwd);
403 if (status != 0)
404 return status; 367 return status;
405 } 368 }
406 369
407 /* Authentication epilogues */ 370 /* Authentication epilogue. */
408 if (mbox->auth) 371 if (mbox->auth)
409 auth_epilogue (mbox->auth); 372 auth_epilogue (mbox->auth);
410 373
411 mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, "mailbox_unix_open(%s, %d)\n", 374 mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, "unix_open(%s, %d)\n",
412 mbox->name, flags); 375 mbox->name, flags);
413 /* give an appopriate way to lock */ 376
377 /* Give an appopriate way to lock. */
414 if (mbox->locker == NULL) 378 if (mbox->locker == NULL)
415 locker_create (&(mbox->locker), mbox->name, 379 locker_create (&(mbox->locker), mbox->name, strlen (mbox->name),
416 strlen (mbox->name), MU_LOCKER_PID | MU_LOCKER_FCNTL); 380 MU_LOCKER_PID | MU_LOCKER_FCNTL);
417 return 0; 381 return 0;
418 } 382 }
419 383
420 static int 384 static int
421 mailbox_unix_close (mailbox_t mbox) 385 unix_close (mailbox_t mbox)
422 { 386 {
423 mailbox_unix_data_t mud; 387 unix_data_t mud;
424 size_t i; 388 size_t i;
425 389
426 if (mbox == NULL || 390 if (mbox == NULL || (mud = (unix_data_t)mbox->data) == NULL)
427 (mud = (mailbox_unix_data_t)mbox->data) == NULL)
428 return EINVAL; 391 return EINVAL;
429 392
430 /* make sure we do not hold any lock for that file */ 393 /* Make sure we do not hold any lock for that file. */
431 mailbox_unix_unlock (mbox); 394 unix_unlock (mbox);
432 mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, "mailbox_unix_close(%s)\n", 395 mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, "unix_close(%s)\n",
433 mbox->name); 396 mbox->name);
434 397
435 /* before closing we need to remove all the messages 398 /* Before closing we need to remove all the messages
436 * - to reclaim the memory 399 - to reclaim the memory
437 * - to prepare for another scan. 400 - to prepare for another scan. */
438 */
439 for (i = 0; i < mud->umessages_count; i++) 401 for (i = 0; i < mud->umessages_count; i++)
440 { 402 {
441 mailbox_unix_message_t mum = mud->umessages[i]; 403 unix_message_t mum = mud->umessages[i];
404 /* Destroy the attach messages. */
442 if (mum == NULL) 405 if (mum == NULL)
443 continue; 406 {
444 /* Destroy the attach messages */ 407 message_destroy (&(mum->message), mum);
445 attribute_destroy (&(mum->old_attr)); 408 free (mum);
446 message_destroy (&(mum->message), mum); 409 }
447 /* new_attr free by message_destroy() */
448 /* attribute_destroy (&(mum->new_attr)); */
449 free (mum);
450 } 410 }
451 free (mud->umessages); 411 free (mud->umessages);
452 mud->umessages = NULL; 412 mud->umessages = NULL;
...@@ -455,30 +415,26 @@ mailbox_unix_close (mailbox_t mbox) ...@@ -455,30 +415,26 @@ mailbox_unix_close (mailbox_t mbox)
455 return stream_close (mbox->stream); 415 return stream_close (mbox->stream);
456 } 416 }
457 417
458 /* Mailbox Parsing */ 418 /* Mailbox Parsing. */
459 #include "mbx_unixscan.c" 419 #include "mbx_unixscan.c"
460 420
461 static int 421 static int
462 mailbox_unix_scan (mailbox_t mbox, size_t msgno, size_t *pcount) 422 unix_scan (mailbox_t mbox, size_t msgno, size_t *pcount)
463 { 423 {
464 mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, "mailbox_unix_scan(%s)\n", 424 mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, "unix_scan(%s)\n", mbox->name);
465 mbox->name); 425 return unix_scan0 (mbox, msgno, pcount, 1);
466 return mailbox_unix_scan0 (mbox, msgno, pcount, 1);
467 } 426 }
468 427
469 428
470 /* FIXME: How to handle a shrink ? meaning, the &^$^@%#@^& user 429 /* FIXME: How to handle a shrink ? meaning, the &^$^@%#@^& user start two
471 * start two browsers and delete files in one. My views 430 browsers and delete files in one. My views is that we should scream
472 * is that we should scream bloody murder and hunt them with 431 bloody murder and hunt them with a machette. */
473 * a machette.
474 */
475 static int 432 static int
476 mailbox_unix_is_updated (mailbox_t mbox) 433 unix_is_updated (mailbox_t mbox)
477 { 434 {
478 off_t size; 435 off_t size;
479 mailbox_unix_data_t mud; 436 unix_data_t mud;
480 if (mbox == NULL || 437 if (mbox == NULL || (mud = (unix_data_t) mbox->data) == NULL)
481 (mud = (mailbox_unix_data_t) mbox->data) == NULL)
482 return EINVAL; 438 return EINVAL;
483 if (stream_size (mbox->stream, &size) != 0) 439 if (stream_size (mbox->stream, &size) != 0)
484 return 0; 440 return 0;
...@@ -486,18 +442,17 @@ mailbox_unix_is_updated (mailbox_t mbox) ...@@ -486,18 +442,17 @@ mailbox_unix_is_updated (mailbox_t mbox)
486 } 442 }
487 443
488 static int 444 static int
489 mailbox_unix_num_deleted (mailbox_t mbox, size_t *pnum) 445 unix_num_deleted (mailbox_t mbox, size_t *pnum)
490 { 446 {
491 mailbox_unix_data_t mud; 447 unix_data_t mud;
492 mailbox_unix_message_t mum; 448 unix_message_t mum;
493 size_t i, total; 449 size_t i, total;
494 if (mbox == NULL || 450 if (mbox == NULL || (mud = (unix_data_t) mbox->data) == NULL)
495 (mud = (mailbox_unix_data_t) mbox->data) == NULL)
496 return EINVAL; 451 return EINVAL;
497 for (i = total = 0; i < mud->messages_count; i++) 452 for (i = total = 0; i < mud->messages_count; i++)
498 { 453 {
499 mum = mud->umessages[i]; 454 mum = mud->umessages[i];
500 if (attribute_is_deleted (mum->new_attr)) 455 if (ATTRIBUTE_IS_DELETED (mum->new_flags))
501 total++; 456 total++;
502 } 457 }
503 458
...@@ -506,42 +461,41 @@ mailbox_unix_num_deleted (mailbox_t mbox, size_t *pnum) ...@@ -506,42 +461,41 @@ mailbox_unix_num_deleted (mailbox_t mbox, size_t *pnum)
506 return 0; 461 return 0;
507 } 462 }
508 463
509 /* 464 /* FIXME: the use of tmpfile() on some system can lead to race condition, We
510 FIXME: the use of tmpfile() on some system can lead to 465 should use a safer approach. We take a very naive approach for this, it
511 race condition, We should use a safer approach. 466 involves unfortunately two copies. */
512 We take a very naive approach for this, it involves unfortunately
513 two copies.
514 */
515 static FILE * 467 static FILE *
516 mailbox_unix_tmpfile (mailbox_t mbox, char **pbox) 468 unix_tmpfile (mailbox_t mbox, char **pbox)
517 { 469 {
518 mailbox_unix_data_t mud = (mailbox_unix_data_t)mbox->data; 470 const char *tmpdir;
519 int fd; 471 int fd;
520 FILE *fp; 472 FILE *fp;
473 unix_data_t mud = (unix_data_t)mbox->data;
521 474
475 /* P_tmpdir should be define in <stdio.h>. */
522 #ifndef P_tmpdir 476 #ifndef P_tmpdir
523 # define P_tmpdir "/tmp" 477 # define P_tmpdir "/tmp"
524 #endif 478 #endif
525 479
526 *pbox = calloc (1, strlen (P_tmpdir) + strlen ("MBOX_") + 480 tmpdir = getenv ("TEMPDIR") ? getenv ("TEMPDIR") : P_tmpdir;
527 strlen (mud->basename) + 1); 481 *pbox = calloc (1, strlen (tmpdir) + strlen ("MBOX_") +
482 strlen (mud->basename) + 1);
528 if (*pbox == NULL) 483 if (*pbox == NULL)
529 return NULL; 484 return NULL;
530 sprintf (*pbox, "%s/%s%s", P_tmpdir, "MBOX_", mud->basename); 485 sprintf (*pbox, "%s/%s%s", tmpdir, "MBOX_", mud->basename);
531 486
532 /* FIXME: I don't think this is the righ approach 487 /* FIXME: I don't think this is the righ approach, creating an anonymous
533 * Creating an anonymous file would be better ? 488 file would be better ? no trace left behind. */
534 * no trace left behind. 489 /* Create the file. It must not exist. If it does exist, fail. */
535 */ 490 fd = open (*pbox, O_RDWR|O_CREAT|O_EXCL, 0600);
536 /* Create the file. It must not exist. If it does exist, fail. */
537 fd = open(*pbox, O_RDWR|O_CREAT|O_EXCL, 0600);
538 if (fd < 0) 491 if (fd < 0)
539 { 492 {
540 fprintf(stderr,"Can't create %s\n", *pbox); 493 fprintf (stderr,"Can't create %s\n", *pbox);
541 fprintf(stderr,"delete file <%s>, Please\n", *pbox); 494 fprintf (stderr,"delete file <%s>, Please\n", *pbox);
495 fprintf (stderr, "It was likely due to an error when expunging\n");
542 return NULL; 496 return NULL;
543 } 497 }
544 fp = fdopen(fd, "w+"); 498 fp = fdopen (fd, "w+");
545 if (fp == 0) 499 if (fp == 0)
546 { 500 {
547 close(fd); 501 close(fd);
...@@ -549,16 +503,16 @@ mailbox_unix_tmpfile (mailbox_t mbox, char **pbox) ...@@ -549,16 +503,16 @@ mailbox_unix_tmpfile (mailbox_t mbox, char **pbox)
549 *pbox = NULL; 503 *pbox = NULL;
550 } 504 }
551 505
552 /* really I should just remove the file here */ 506 /* Really I should just remove the file here. */
553 /* remove(*pbox); */ 507 /* remove(*pbox); */
554 return fp; 508 return fp;
555 } 509 }
556 510
557 static int 511 static int
558 mailbox_unix_expunge (mailbox_t mbox) 512 unix_expunge (mailbox_t mbox)
559 { 513 {
560 mailbox_unix_data_t mud; 514 unix_data_t mud;
561 mailbox_unix_message_t mum; 515 unix_message_t mum;
562 int status = 0; 516 int status = 0;
563 sigset_t sigset; 517 sigset_t sigset;
564 FILE *tempfile; 518 FILE *tempfile;
...@@ -569,74 +523,65 @@ mailbox_unix_expunge (mailbox_t mbox) ...@@ -569,74 +523,65 @@ mailbox_unix_expunge (mailbox_t mbox)
569 char buffer [BUFSIZ]; 523 char buffer [BUFSIZ];
570 char *tmpmbox = NULL; 524 char *tmpmbox = NULL;
571 525
572 if (mbox == NULL || 526 if (mbox == NULL || (mud = (unix_data_t)mbox->data) == NULL)
573 (mud = (mailbox_unix_data_t)mbox->data) == NULL)
574 return EINVAL; 527 return EINVAL;
575 528
576 /* noop */ 529 /* Noop. */
577 if (mud->messages_count == 0) 530 if (mud->messages_count == 0)
578 return 0; 531 return 0;
579 532
580 /* Do we have a consistent view of the mailbox */ 533 /* Do we have a consistent view of the mailbox. */
581 /* FIXME: this is not enough, we can do better 534 /* FIXME: this is not enough, we can do better
582 * - by checking the file size and scream bloody murder 535 - by checking the file size and scream bloody murder if it has shrink.
583 * if it has shrink. 536 - if its bigger we should be able to handle it before the ftruncate ()
584 * - if its bigger we should be able to handle it 537 by copying back the new messages. */
585 * before the ftruncate() by copying back the new messages. 538 if (! unix_is_updated (mbox))
586 */ 539 {
587 if (! mailbox_unix_is_updated (mbox)) 540 fprintf (stderr, "mailbox is not updated, try again.\n");
588 return EAGAIN; 541 return EAGAIN;
589 542 }
590 /* mark dirty the first mail with an attribute change */ 543
544 /* Mark dirty the first mail with an attribute change. */
591 for (dirty = 0; dirty < mud->messages_count; dirty++) 545 for (dirty = 0; dirty < mud->messages_count; dirty++)
592 { 546 {
593 mum = mud->umessages[dirty]; 547 mum = mud->umessages[dirty];
594 if (mum->new_attr && 548 if (mum->new_flags &&
595 ! attribute_is_equal (mum->old_attr, mum->new_attr)) 549 ! ATTRIBUTE_IS_EQUAL (mum->old_flags, mum->new_flags))
596 break; 550 break;
597 } 551 }
598 552
599 /* did something change ? */ 553 /* Did something change ? */
600 if (dirty == mud->messages_count) 554 if (dirty == mud->messages_count)
601 return 0; /* nothing change, bail out */ 555 return 0; /* Nothing change, bail out. */
602 556
603 mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, "mailbox_unix_expunge (%s)\n", 557 mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, "unix_expunge (%s)\n",
604 mbox->name); 558 mbox->name);
605 559
606 /* Send notification to all the listeners 560 /* This is redundant, we go to the loop again. But it's more secure here
607 * this is redundant, we go to the loop again 561 since we don't want to be disturb when expunging. */
608 * But it's more secure here since we don't
609 * want to be disturb when expunging.
610 */
611 for (j = 0; j < mud->messages_count; j++) 562 for (j = 0; j < mud->messages_count; j++)
612 { 563 {
613 mum = mud->umessages[j]; 564 mum = mud->umessages[j];
614 if (mum && mum->new_attr && attribute_is_deleted (mum->new_attr)) 565 if (mum && mum->new_flags && ATTRIBUTE_IS_DELETED (mum->new_flags))
615 { 566 message_destroy (&(mum->message), mum);
616 attribute_t attr;
617 attribute_create (&attr);
618 attribute_copy (attr, mum->new_attr);
619 /* Hack: message_destroy() will free() the attribute, save it */
620 message_destroy (&(mum->message), mum);
621 mum->new_attr = attr;
622 }
623 } 567 }
624 568
625 /* create a tempory file */ 569 /* Create a tempory file. */
626 tempfile = mailbox_unix_tmpfile (mbox, &tmpmbox); 570 tempfile = unix_tmpfile (mbox, &tmpmbox);
627 if (tempfile == NULL) 571 if (tempfile == NULL)
628 return errno; 572 return errno;
629 573
630 /* Get the lock */ 574 /* Get the lock. */
631 if (mailbox_unix_lock (mbox, MU_LOCKER_WRLOCK) < 0) 575 if (unix_lock (mbox, MU_LOCKER_WRLOCK) < 0)
632 { 576 {
633 fclose (tempfile); 577 fclose (tempfile);
634 remove (tmpmbox); 578 remove (tmpmbox);
635 free (tmpmbox); 579 free (tmpmbox);
580 fprintf (stderr, "Failed to grab the lock\n");
636 return ENOLCK; 581 return ENOLCK;
637 } 582 }
638 583
639 /* Critical section, we can not allowed signal here */ 584 /* Critical section, we can not allowed signal here. */
640 sigemptyset (&sigset); 585 sigemptyset (&sigset);
641 sigaddset (&sigset, SIGTERM); 586 sigaddset (&sigset, SIGTERM);
642 sigaddset (&sigset, SIGHUP); 587 sigaddset (&sigset, SIGHUP);
...@@ -645,21 +590,21 @@ mailbox_unix_expunge (mailbox_t mbox) ...@@ -645,21 +590,21 @@ mailbox_unix_expunge (mailbox_t mbox)
645 sigaddset (&sigset, SIGWINCH); 590 sigaddset (&sigset, SIGWINCH);
646 sigprocmask (SIG_BLOCK, &sigset, 0); 591 sigprocmask (SIG_BLOCK, &sigset, 0);
647 592
648 mailbox_unix_ilock (mbox, MU_LOCKER_RDLOCK); 593 unix_ilock (mbox, MU_LOCKER_RDLOCK);
649 594
650 /* set the marker position */ 595 /* Set the marker position. */
651 total = marker = mud->umessages[dirty]->header_from; 596 total = marker = mud->umessages[dirty]->header_from;
652 597
653 /* copy to tempfile emails not mark deleted */ 598 /* Copy to tempfile emails not mark deleted. */
654 for (first = 1, i = dirty; i < mud->messages_count; i++) 599 for (first = 1, i = dirty; i < mud->messages_count; i++)
655 { 600 {
656 mum = mud->umessages[i]; 601 mum = mud->umessages[i];
657 602
658 /* skip it, if mark for deletion */ 603 /* Skip it, if mark for deletion. */
659 if (attribute_is_deleted (mum->new_attr)) 604 if (ATTRIBUTE_IS_DELETED (mum->new_flags))
660 continue; 605 continue;
661 606
662 /* add a NL separator between messages */ 607 /* Add a NL separator between messages. */
663 if (first) 608 if (first)
664 first = 0; 609 first = 0;
665 else 610 else
...@@ -668,19 +613,18 @@ mailbox_unix_expunge (mailbox_t mbox) ...@@ -668,19 +613,18 @@ mailbox_unix_expunge (mailbox_t mbox)
668 total++; 613 total++;
669 } 614 }
670 615
671 /* Begining of header copy */ 616 /* Begining of header copy. */
672 { 617 {
673 off_t current; 618 off_t current;
674 /* This is done in two parts first we check if the attribute 619 /* This is done in two parts first we check if the attribute changed,
675 * changed, if yes then we have to update the "Status:" field. 620 if yes then we have to update the "Status:" field. Unfortunately
676 * Unfortunately there is no requirement for the "Status:" 621 there is no requirement for the "Status:" to be the last field, so
677 * to be the last field, so we take the long approach; 622 we take the long approach; Copy up to the Status, update the
678 * Copy up to the Status, update the Status and copy the rest. 623 Status and copy the rest. */
679 */ 624
680 625 /* Attribute change ? */
681 /* attribute change ? */ 626 if (mum->new_flags
682 if (mum->new_attr 627 &&! ATTRIBUTE_IS_EQUAL (mum->old_flags, mum->new_flags)
683 &&! attribute_is_equal (mum->old_attr, mum->new_attr)
684 && mum->header_status > mum->header_from) 628 && mum->header_status > mum->header_from)
685 { 629 {
686 size_t n = 0; 630 size_t n = 0;
...@@ -696,6 +640,8 @@ mailbox_unix_expunge (mailbox_t mbox) ...@@ -696,6 +640,8 @@ mailbox_unix_expunge (mailbox_t mbox)
696 { 640 {
697 if (status == 0) 641 if (status == 0)
698 status = errno; 642 status = errno;
643 fprintf (stderr, "expunge:%d: (%s)\n", __LINE__,
644 strerror (status));
699 goto bailout; 645 goto bailout;
700 } 646 }
701 len -= n; 647 len -= n;
...@@ -703,20 +649,20 @@ mailbox_unix_expunge (mailbox_t mbox) ...@@ -703,20 +649,20 @@ mailbox_unix_expunge (mailbox_t mbox)
703 offset += n; 649 offset += n;
704 } 650 }
705 651
706 /* put the new attributes */ 652 /* Put the new attributes. */
707 { 653 {
708 char abuf[64]; 654 char abuf[64];
709 size_t na = 0; 655 size_t na = 0;
710 abuf[0] = '\0'; 656 abuf[0] = '\0';
711 attribute_to_string (mum->new_attr, abuf, sizeof(abuf), &na); 657 flags_to_string (mum->new_flags, abuf, sizeof(abuf), &na);
712 fputs (abuf, tempfile); 658 fputs (abuf, tempfile);
713 total += na; 659 total += na;
714 } 660 }
715 } 661 }
716 else /* attribute did not change */ 662 else /* Attribute did not change. */
717 current = mum->header_from; 663 current = mum->header_from;
718 664
719 /* copy the rest of header without changes */ 665 /* Copy the rest of header without changes. */
720 { 666 {
721 size_t n = 0; 667 size_t n = 0;
722 off_t offset = current; 668 off_t offset = current;
...@@ -730,6 +676,8 @@ mailbox_unix_expunge (mailbox_t mbox) ...@@ -730,6 +676,8 @@ mailbox_unix_expunge (mailbox_t mbox)
730 { 676 {
731 if (status == 0) 677 if (status == 0)
732 status = errno; 678 status = errno;
679 fprintf (stderr, "expunge:%d: %s", __LINE__,
680 strerror (status));
733 goto bailout; 681 goto bailout;
734 } 682 }
735 len -= n; 683 len -= n;
...@@ -737,9 +685,9 @@ mailbox_unix_expunge (mailbox_t mbox) ...@@ -737,9 +685,9 @@ mailbox_unix_expunge (mailbox_t mbox)
737 offset += n; 685 offset += n;
738 } 686 }
739 } 687 }
740 } /* end of header copy */ 688 } /* End of header copy. */
741 689
742 /* copy the body */ 690 /* Copy the body. */
743 { 691 {
744 size_t n = 0; 692 size_t n = 0;
745 off_t offset = mum->body; 693 off_t offset = mum->body;
...@@ -753,21 +701,20 @@ mailbox_unix_expunge (mailbox_t mbox) ...@@ -753,21 +701,20 @@ mailbox_unix_expunge (mailbox_t mbox)
753 { 701 {
754 if (status == 0) 702 if (status == 0)
755 status = errno; 703 status = errno;
704 fprintf (stderr, "expunge:%d: %s", __LINE__,
705 strerror (status));
756 goto bailout; 706 goto bailout;
757 } 707 }
758 len -= n; 708 len -= n;
759 total += n; 709 total += n;
760 offset += n; 710 offset += n;
761 } 711 }
762 } /* end of body copy */ 712 } /* End of body copy. */
763 } /* for (;;) */ 713 } /* for (;;) */
764 714
765 /* 715 /* Caution: before ftruncate()ing the file see if we've receiving new mail
766 * Caution: 716 Some program may not respect the lock, or the lock was held for too
767 * before ftruncate()ing the file see if we've receiving new mail 717 long. */
768 * Some program may not respect the lock, or the lock was held
769 * for too long.
770 */
771 { 718 {
772 off_t size = 0; 719 off_t size = 0;
773 if (stream_size (mbox->stream, &size) == 0) 720 if (stream_size (mbox->stream, &size) == 0)
...@@ -784,6 +731,8 @@ mailbox_unix_expunge (mailbox_t mbox) ...@@ -784,6 +731,8 @@ mailbox_unix_expunge (mailbox_t mbox)
784 { 731 {
785 if (status == 0) 732 if (status == 0)
786 status = errno; 733 status = errno;
734 fprintf (stderr, "expunge:%d: %s", __LINE__,
735 strerror (status));
787 goto bailout; 736 goto bailout;
788 } 737 }
789 len -= n; 738 len -= n;
...@@ -791,9 +740,9 @@ mailbox_unix_expunge (mailbox_t mbox) ...@@ -791,9 +740,9 @@ mailbox_unix_expunge (mailbox_t mbox)
791 offset += n; 740 offset += n;
792 } 741 }
793 } 742 }
794 } /* end of precaution */ 743 } /* End of precaution. */
795 744
796 /* Seek and rewrite it */ 745 /* Seek and rewrite it. */
797 rewind (tempfile); 746 rewind (tempfile);
798 if (total > 0) 747 if (total > 0)
799 { 748 {
...@@ -813,39 +762,42 @@ mailbox_unix_expunge (mailbox_t mbox) ...@@ -813,39 +762,42 @@ mailbox_unix_expunge (mailbox_t mbox)
813 } 762 }
814 } 763 }
815 764
816 /* how can I handle error here ?? */ 765 /* How can I handle error here ?? */
817 clearerr (tempfile); 766 clearerr (tempfile);
818 767
819 /* flush/truncation */ 768 /* Flush/truncation. */
820 stream_flush (mbox->stream); 769 stream_flush (mbox->stream);
821 status = stream_truncate (mbox->stream, total); 770 status = stream_truncate (mbox->stream, total);
822 if (status != 0) 771 if (status != 0)
823 goto bailout; 772 {
773 fprintf (stderr, "expunge:%d: %s", __LINE__,
774 strerror (status));
775 goto bailout;
776 }
824 777
825 /* Don't remove the tmp mbox in case of errors */ 778 /* Don't remove the tmp mbox in case of errors. */
826 remove (tmpmbox); 779 remove (tmpmbox);
827 780
828 bailout: 781 bailout:
829 782
830 free (tmpmbox); 783 free (tmpmbox);
831 /* Release the locks */ 784 /* Release the locks. */
832 mailbox_unix_unlock (mbox); 785 unix_unlock (mbox);
833 mailbox_unix_iunlock (mbox); 786 unix_iunlock (mbox);
834 fclose (tempfile); 787 fclose (tempfile);
835 sigprocmask (SIG_UNBLOCK, &sigset, 0); 788 sigprocmask (SIG_UNBLOCK, &sigset, 0);
836 789
837 /* we need to readjust the pointers */ 790 /* We need to readjust the pointers. */
838 if (status == 0) 791 if (status == 0)
839 { 792 {
840 size_t dlast; 793 size_t dlast;
841 for (j = dirty, dlast = mud->messages_count - 1; 794 for (j = dirty, dlast = mud->messages_count - 1;
842 j < mud->messages_count; j++) 795 j < mud->messages_count; j++)
843 { 796 {
844 /* clear all the references, 797 /* Clear all the references, any attach messages been already
845 * any attach messages been already destroy above 798 destroy above. */
846 */
847 mum = mud->umessages[j]; 799 mum = mud->umessages[j];
848 if (mum->new_attr && attribute_is_deleted (mum->new_attr)) 800 if (mum->new_flags && ATTRIBUTE_IS_DELETED (mum->new_flags))
849 { 801 {
850 memmove (mud->umessages + j, mud->umessages + j + 1, 802 memmove (mud->umessages + j, mud->umessages + j + 1,
851 (dlast - dirty) * sizeof (mum)); 803 (dlast - dirty) * sizeof (mum));
...@@ -853,7 +805,6 @@ mailbox_unix_expunge (mailbox_t mbox) ...@@ -853,7 +805,6 @@ mailbox_unix_expunge (mailbox_t mbox)
853 mum->header_status = mum->header_status_end = 0; 805 mum->header_status = mum->header_status_end = 0;
854 mum->body = mum->body_end = 0; 806 mum->body = mum->body_end = 0;
855 mum->header_lines = mum->body_lines = 0; 807 mum->header_lines = mum->body_lines = 0;
856 attribute_destroy (&(mum->new_attr));
857 mud->umessages[dlast] = mum; 808 mud->umessages[dlast] = mum;
858 dlast--; 809 dlast--;
859 mum = mud->umessages[j]; 810 mum = mud->umessages[j];
...@@ -863,18 +814,17 @@ mailbox_unix_expunge (mailbox_t mbox) ...@@ -863,18 +814,17 @@ mailbox_unix_expunge (mailbox_t mbox)
863 mum->body = mum->body_end = 0; 814 mum->body = mum->body_end = 0;
864 mum->header_lines = mum->body_lines = 0; 815 mum->header_lines = mum->body_lines = 0;
865 } 816 }
866 /* this is should reset the messages_count, the last 817 /* This is should reset the messages_count, the last * argument 0 means
867 * argument 0 means not to send event notification 818 not to send event notification. */
868 */ 819 unix_scan0 (mbox, dirty, NULL, 0);
869 mailbox_unix_scan0 (mbox, dirty, NULL, 0);
870 } 820 }
871 return status; 821 return status;
872 } 822 }
873 823
874 static int 824 static int
875 mailbox_unix_getfd (stream_t is, int *pfd) 825 unix_get_fd (stream_t is, int *pfd)
876 { 826 {
877 mailbox_unix_message_t mum; 827 unix_message_t mum;
878 828
879 if (is == NULL || (mum = is->owner) == NULL) 829 if (is == NULL || (mum = is->owner) == NULL)
880 return EINVAL; 830 return EINVAL;
...@@ -883,13 +833,50 @@ mailbox_unix_getfd (stream_t is, int *pfd) ...@@ -883,13 +833,50 @@ mailbox_unix_getfd (stream_t is, int *pfd)
883 } 833 }
884 834
885 static int 835 static int
886 mailbox_unix_readstream (stream_t is, char *buffer, size_t buflen, 836 unix_get_flags (attribute_t attr, int *pflags)
887 off_t off, size_t *pnread) 837 {
838 unix_message_t mum;
839
840 if (attr == NULL || (mum = attr->owner) == NULL)
841 return EINVAL;
842
843 if (pflags)
844 *pflags = mum->new_flags;
845 return 0;
846 }
847
848 static int
849 unix_set_flags (attribute_t attr, int flags)
850 {
851 unix_message_t mum;
852
853 if (attr == NULL || (mum = attr->owner) == NULL)
854 return EINVAL;
855
856 mum->new_flags |= flags;
857 return 0;
858 }
859
860 static int
861 unix_unset_flags (attribute_t attr, int flags)
862 {
863 unix_message_t mum;
864
865 if (attr == NULL || (mum = attr->owner) == NULL)
866 return EINVAL;
867
868 mum->new_flags &= flags;
869 return 0;
870 }
871
872 static int
873 unix_readstream (stream_t is, char *buffer, size_t buflen,
874 off_t off, size_t *pnread)
888 { 875 {
889 mailbox_unix_message_t mum; 876 unix_message_t mum;
890 size_t nread = 0; 877 size_t nread = 0;
891 878
892 if (is == NULL || (mum = (mailbox_unix_message_t)is->owner) == NULL) 879 if (is == NULL || (mum = (unix_message_t)is->owner) == NULL)
893 return EINVAL; 880 return EINVAL;
894 881
895 if (buffer == NULL || buflen == 0) 882 if (buffer == NULL || buflen == 0)
...@@ -906,7 +893,7 @@ mailbox_unix_readstream (stream_t is, char *buffer, size_t buflen, ...@@ -906,7 +893,7 @@ mailbox_unix_readstream (stream_t is, char *buffer, size_t buflen,
906 if (ln > 0) 893 if (ln > 0)
907 { 894 {
908 nread = ((size_t)ln < buflen) ? ln : buflen; 895 nread = ((size_t)ln < buflen) ? ln : buflen;
909 /* position the file pointer and the buffer */ 896 /* Position the file pointer and the buffer. */
910 status = stream_read (mum->stream, buffer, nread, mum->body + off, &n); 897 status = stream_read (mum->stream, buffer, nread, mum->body + off, &n);
911 if (status != 0) 898 if (status != 0)
912 return status; 899 return status;
...@@ -919,30 +906,34 @@ mailbox_unix_readstream (stream_t is, char *buffer, size_t buflen, ...@@ -919,30 +906,34 @@ mailbox_unix_readstream (stream_t is, char *buffer, size_t buflen,
919 } 906 }
920 907
921 static int 908 static int
922 mailbox_unix_get_header (mailbox_unix_message_t mum, char *buffer, 909 unix_get_header_read (stream_t is, char *buffer, size_t len,
923 size_t len, off_t off, ssize_t *pnread) 910 off_t off, size_t *pnread)
924 { 911 {
912 unix_message_t mum;
925 size_t nread = 0; 913 size_t nread = 0;
926 size_t n = 0; 914 int status = 0;
927 int status; 915 off_t ln;
928 off_t ln = mum->body - (mum->header_from_end + off); 916
917 if (is == NULL || (mum = is->owner) == NULL)
918 return EINVAL;
919
920 ln = mum->body - (mum->header_from_end + off);
929 if (ln > 0) 921 if (ln > 0)
930 { 922 {
931 nread = ((size_t)ln < len) ? ln : len; 923 nread = ((size_t)ln < len) ? ln : len;
932 /* position the file pointer and the buffer */ 924 /* Position the file pointer and the buffer. */
933 status = stream_read (mum->stream, buffer, nread, 925 status = stream_read (mum->stream, buffer, nread,
934 mum->header_from_end + off, &n); 926 mum->header_from_end + off, &nread);
935 if (status != 0)
936 return status;
937 } 927 }
938 *pnread = nread; 928 if (pnread)
939 return 0; 929 *pnread = nread;
930 return status;
940 } 931 }
941 932
942 static int 933 static int
943 mailbox_unix_body_size (body_t body, size_t *psize) 934 unix_body_size (body_t body, size_t *psize)
944 { 935 {
945 mailbox_unix_message_t mum = body->owner; 936 unix_message_t mum = body->owner;
946 if (mum == NULL) 937 if (mum == NULL)
947 return EINVAL; 938 return EINVAL;
948 if (psize) 939 if (psize)
...@@ -951,9 +942,9 @@ mailbox_unix_body_size (body_t body, size_t *psize) ...@@ -951,9 +942,9 @@ mailbox_unix_body_size (body_t body, size_t *psize)
951 } 942 }
952 943
953 static int 944 static int
954 mailbox_unix_body_lines (body_t body, size_t *plines) 945 unix_body_lines (body_t body, size_t *plines)
955 { 946 {
956 mailbox_unix_message_t mum = body->owner; 947 unix_message_t mum = body->owner;
957 if (mum == NULL) 948 if (mum == NULL)
958 return EINVAL; 949 return EINVAL;
959 if (plines) 950 if (plines)
...@@ -962,10 +953,10 @@ mailbox_unix_body_lines (body_t body, size_t *plines) ...@@ -962,10 +953,10 @@ mailbox_unix_body_lines (body_t body, size_t *plines)
962 } 953 }
963 954
964 static int 955 static int
965 mailbox_unix_msg_received (message_t msg, char *buf, size_t len, 956 unix_msg_received (message_t msg, char *buf, size_t len,
966 size_t *pnwrite) 957 size_t *pnwrite)
967 { 958 {
968 mailbox_unix_message_t mum = msg->owner; 959 unix_message_t mum = msg->owner;
969 size_t n = 0; 960 size_t n = 0;
970 int status; 961 int status;
971 char buffer[512]; 962 char buffer[512];
...@@ -975,7 +966,6 @@ mailbox_unix_msg_received (message_t msg, char *buf, size_t len, ...@@ -975,7 +966,6 @@ mailbox_unix_msg_received (message_t msg, char *buf, size_t len,
975 966
976 status = stream_readline (mum->stream, buffer, sizeof(buffer), 967 status = stream_readline (mum->stream, buffer, sizeof(buffer),
977 mum->header_from, &n); 968 mum->header_from, &n);
978
979 if (status != 0) 969 if (status != 0)
980 { 970 {
981 if (pnwrite) 971 if (pnwrite)
...@@ -1008,9 +998,9 @@ mailbox_unix_msg_received (message_t msg, char *buf, size_t len, ...@@ -1008,9 +998,9 @@ mailbox_unix_msg_received (message_t msg, char *buf, size_t len,
1008 } 998 }
1009 999
1010 static int 1000 static int
1011 mailbox_unix_msg_from (message_t msg, char *buf, size_t len, size_t *pnwrite) 1001 unix_msg_from (message_t msg, char *buf, size_t len, size_t *pnwrite)
1012 { 1002 {
1013 mailbox_unix_message_t mum = msg->owner; 1003 unix_message_t mum = msg->owner;
1014 size_t n = 0; 1004 size_t n = 0;
1015 int status; 1005 int status;
1016 char buffer[512]; 1006 char buffer[512];
...@@ -1053,31 +1043,22 @@ mailbox_unix_msg_from (message_t msg, char *buf, size_t len, size_t *pnwrite) ...@@ -1053,31 +1043,22 @@ mailbox_unix_msg_from (message_t msg, char *buf, size_t len, size_t *pnwrite)
1053 } 1043 }
1054 1044
1055 static int 1045 static int
1056 mailbox_unix_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg) 1046 unix_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
1057 { 1047 {
1058 int status; 1048 int status;
1059 ssize_t nread; 1049 unix_data_t mud;
1060 char *pbuf = NULL; 1050 unix_message_t mum;
1061 char *tbuf = NULL;
1062 char buf[BUFSIZ];
1063 off_t offset = 0;
1064 mailbox_unix_data_t mud;
1065 mailbox_unix_message_t mum;
1066 message_t msg = NULL; 1051 message_t msg = NULL;
1067 stream_t stream = NULL; 1052
1068 header_t header = NULL; 1053 /* Sanity checks. */
1069 body_t body = NULL; 1054 if (mbox == NULL || pmsg == NULL || (mud = (unix_data_t)mbox->data) == NULL
1070 int flags = 0; 1055 || (!(mud->messages_count > 0 && msgno > 0
1071 1056 && msgno <= mud->messages_count)))
1072 if (mbox == NULL || pmsg == NULL ||
1073 (mud = (mailbox_unix_data_t)mbox->data) == NULL ||
1074 (!(mud->messages_count > 0 && msgno > 0 &&
1075 msgno <= mud->messages_count)))
1076 return EINVAL; 1057 return EINVAL;
1077 1058
1078 mum = mud->umessages[msgno - 1]; 1059 mum = mud->umessages[msgno - 1];
1079 1060
1080 /* check if we already have it */ 1061 /* Check if we already have it. */
1081 if (mum->message) 1062 if (mum->message)
1082 { 1063 {
1083 if (pmsg) 1064 if (pmsg)
...@@ -1086,89 +1067,72 @@ mailbox_unix_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg) ...@@ -1086,89 +1067,72 @@ mailbox_unix_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
1086 } 1067 }
1087 1068
1088 mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, 1069 mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE,
1089 "mailbox_unix_get_message(%s, %d)\n", mbox->name, msgno); 1070 "unix_get_message(%s, %d)\n", mbox->name, msgno);
1090 /* get the headers */
1091 do
1092 {
1093 status = mailbox_unix_get_header (mum, buf, sizeof(buf), offset, &nread);
1094 if (status != 0)
1095 {
1096 free (pbuf);
1097 return status;
1098 }
1099
1100 if (nread == 0)
1101 break;
1102 1071
1103 tbuf = realloc (pbuf, offset + nread); 1072 /* Get an empty message struct. */
1104 if (tbuf == NULL)
1105 {
1106 free (pbuf);
1107 return ENOMEM;
1108 }
1109 else
1110 pbuf = tbuf;
1111 memcpy (pbuf + offset, buf, nread);
1112 offset += nread;
1113 } while (nread > 0);
1114
1115 /* get an empty message struct */
1116 status = message_create (&msg, mum); 1073 status = message_create (&msg, mum);
1117 if (status != 0) 1074 if (status != 0)
1118 { 1075 return status;
1119 free (pbuf);
1120 return status;
1121 }
1122 1076
1123 /* set the header */ 1077 /* Set the header. */
1124 status = header_create (&header, pbuf, offset, mum); 1078 {
1125 if (status != 0) 1079 header_t header;
1126 { 1080 stream_t stream;
1127 free (pbuf); 1081 if ((status = header_create (&header, NULL, 0, mum)) != 0
1128 message_destroy (&msg, mum); 1082 || (status = stream_create (&stream, MU_STREAM_READ, mum)) != 0)
1129 return status; 1083 {
1130 } 1084 message_destroy (&msg, mum);
1131 free (pbuf); 1085 return status;
1132 message_set_header (msg, header, mum); 1086 }
1087 stream_set_read (stream, unix_get_header_read, mum);
1088 stream_set_fd (stream, unix_get_fd, mum);
1089 stream_set_flags (stream, MU_STREAM_READ, mum);
1090 header_set_stream (header, stream, mum);
1091 message_set_header (msg, header, mum);
1092 }
1133 1093
1134 /* prepare the body */ 1094 /* Set the attribute. */
1135 status = body_create (&body, mum); 1095 {
1136 if (status != 0) 1096 attribute_t attribute;
1137 { 1097 status = attribute_create (&attribute, mum);
1138 message_destroy (&msg, mum); 1098 if (status != 0)
1139 return status; 1099 {
1140 } 1100 message_destroy (&msg, mum);
1141 message_set_body (msg, body, mum); 1101 return status;
1102 }
1103 mum->new_flags = mum->old_flags;
1104 attribute_set_get_flags (attribute, unix_get_flags, mum);
1105 attribute_set_set_flags (attribute, unix_set_flags, mum);
1106 attribute_set_unset_flags (attribute, unix_unset_flags, mum);
1107 message_set_attribute (msg, attribute, mum);
1108 }
1142 1109
1143 status = stream_create (&stream, MU_STREAM_READ, mum); 1110 /* Prepare the body. */
1144 if (status != 0) 1111 {
1145 { 1112 body_t body;
1146 message_destroy (&msg, mum); 1113 stream_t stream;
1147 return status; 1114 int flags = MU_STREAM_READ;
1148 } 1115 if ((status = body_create (&body, mum)) != 0
1149 stream_set_read (stream, mailbox_unix_readstream, mum); 1116 || (status = stream_create (&stream, flags, mum)) != 0)
1150 stream_set_fd (stream, mailbox_unix_getfd, mum); 1117 {
1151 stream_get_flags (mbox->stream, &flags); 1118 message_destroy (&msg, mum);
1152 stream_set_flags (stream, flags, mum); 1119 return status;
1153 body_set_stream (body, stream, mum); 1120 }
1154 body_set_size (body, mailbox_unix_body_size, mum); 1121 stream_set_read (stream, unix_readstream, mum);
1155 body_set_lines (body, mailbox_unix_body_lines, mum); 1122 stream_set_fd (stream, unix_get_fd, mum);
1156 1123 stream_get_flags (mbox->stream, &flags);
1157 /* set the attribute */ 1124 stream_set_flags (stream, flags, mum);
1158 attribute_create (&(mum->new_attr)); 1125 body_set_stream (body, stream, mum);
1159 mum->new_attr->flag = mum->old_attr->flag; 1126 body_set_size (body, unix_body_size, mum);
1160 status = message_set_attribute (msg, mum->new_attr, mum); 1127 body_set_lines (body, unix_body_lines, mum);
1161 if (status != 0) 1128 message_set_body (msg, body, mum);
1162 { 1129 }
1163 message_destroy (&msg, mum);
1164 return status;
1165 }
1166 1130
1167 /* set the envelope */ 1131 /* Set the envelope. */
1168 message_set_from (msg, mailbox_unix_msg_from, mum); 1132 message_set_from (msg, unix_msg_from, mum);
1169 message_set_received (msg, mailbox_unix_msg_received, mum); 1133 message_set_received (msg, unix_msg_received, mum);
1170 1134
1171 /* attach the message to the mailbox unix data */ 1135 /* Attach the message to the mailbox unix data. */
1172 mum->message = msg; 1136 mum->message = msg;
1173 1137
1174 if (pmsg) 1138 if (pmsg)
...@@ -1177,17 +1141,17 @@ mailbox_unix_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg) ...@@ -1177,17 +1141,17 @@ mailbox_unix_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
1177 } 1141 }
1178 1142
1179 static int 1143 static int
1180 mailbox_unix_append_message (mailbox_t mbox, message_t msg) 1144 unix_append_message (mailbox_t mbox, message_t msg)
1181 { 1145 {
1182 mailbox_unix_data_t mud; 1146 unix_data_t mud;
1183 if (mbox == NULL || msg == NULL || 1147 if (mbox == NULL || msg == NULL ||
1184 (mud = (mailbox_unix_data_t)mbox->data) == NULL) 1148 (mud = (unix_data_t)mbox->data) == NULL)
1185 return EINVAL; 1149 return EINVAL;
1186 1150
1187 mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, 1151 mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE,
1188 "mailbox_unix_append_message (%s)\n", mbox->name); 1152 "unix_append_message (%s)\n", mbox->name);
1189 1153
1190 mailbox_unix_lock (mbox, MU_LOCKER_WRLOCK); 1154 unix_lock (mbox, MU_LOCKER_WRLOCK);
1191 { 1155 {
1192 off_t size; 1156 off_t size;
1193 char buffer[BUFSIZ]; 1157 char buffer[BUFSIZ];
...@@ -1199,16 +1163,16 @@ mailbox_unix_append_message (mailbox_t mbox, message_t msg) ...@@ -1199,16 +1163,16 @@ mailbox_unix_append_message (mailbox_t mbox, message_t msg)
1199 size_t n = 0; 1163 size_t n = 0;
1200 char nl = '\n'; 1164 char nl = '\n';
1201 1165
1202 /* move to the end of the file, not necesary if _APPEND mode */ 1166 /* Move to the end of the file, not necesary if _APPEND mode. */
1203 status = stream_size (mbox->stream, &size); 1167 status = stream_size (mbox->stream, &size);
1204 if (status != 0) 1168 if (status != 0)
1205 { 1169 {
1206 mailbox_unix_unlock (mbox); 1170 unix_unlock (mbox);
1207 return status; 1171 return status;
1208 } 1172 }
1209 /* header */ 1173 /* Header. */
1210 message_get_header (msg, &hdr); 1174 message_get_header (msg, &hdr);
1211 /* generate a "From " separator */ 1175 /* Generate a "From " separator. */
1212 { 1176 {
1213 char from[128]; 1177 char from[128];
1214 char date[128]; 1178 char date[128];
...@@ -1249,10 +1213,10 @@ mailbox_unix_append_message (mailbox_t mbox, message_t msg) ...@@ -1249,10 +1213,10 @@ mailbox_unix_append_message (mailbox_t mbox, message_t msg)
1249 } while (nread > 0); 1213 } while (nread > 0);
1250 1214
1251 *buffer = '\0'; 1215 *buffer = '\0';
1252 /* separator */ 1216 /* Separator. */
1253 /*fputc ('\n', mud->file);*/ 1217 /*fputc ('\n', mud->file);*/
1254 1218
1255 /* body */ 1219 /* Body. */
1256 message_get_stream (msg, &is); 1220 message_get_stream (msg, &is);
1257 do { 1221 do {
1258 stream_read (is, buffer, sizeof (buffer), off, &nread); 1222 stream_read (is, buffer, sizeof (buffer), off, &nread);
...@@ -1263,12 +1227,12 @@ mailbox_unix_append_message (mailbox_t mbox, message_t msg) ...@@ -1263,12 +1227,12 @@ mailbox_unix_append_message (mailbox_t mbox, message_t msg)
1263 stream_write (mbox->stream, &nl, 1, size, &n); 1227 stream_write (mbox->stream, &nl, 1, size, &n);
1264 } 1228 }
1265 stream_flush (mbox->stream); 1229 stream_flush (mbox->stream);
1266 mailbox_unix_unlock (mbox); 1230 unix_unlock (mbox);
1267 return 0; 1231 return 0;
1268 } 1232 }
1269 1233
1270 static int 1234 static int
1271 mailbox_unix_size (mailbox_t mbox, off_t *psize) 1235 unix_size (mailbox_t mbox, off_t *psize)
1272 { 1236 {
1273 off_t size; 1237 off_t size;
1274 int status; 1238 int status;
...@@ -1276,7 +1240,7 @@ mailbox_unix_size (mailbox_t mbox, off_t *psize) ...@@ -1276,7 +1240,7 @@ mailbox_unix_size (mailbox_t mbox, off_t *psize)
1276 if (mbox == NULL) 1240 if (mbox == NULL)
1277 return EINVAL; 1241 return EINVAL;
1278 1242
1279 /* maybe was not open yet ?? */ 1243 /* Maybe was not open yet ?? */
1280 status = stream_size (mbox->stream, &size); 1244 status = stream_size (mbox->stream, &size);
1281 if (status != 0) 1245 if (status != 0)
1282 return status; 1246 return status;
...@@ -1286,14 +1250,14 @@ mailbox_unix_size (mailbox_t mbox, off_t *psize) ...@@ -1286,14 +1250,14 @@ mailbox_unix_size (mailbox_t mbox, off_t *psize)
1286 } 1250 }
1287 1251
1288 static int 1252 static int
1289 mailbox_unix_messages_count (mailbox_t mbox, size_t *pcount) 1253 unix_messages_count (mailbox_t mbox, size_t *pcount)
1290 { 1254 {
1291 mailbox_unix_data_t mud; 1255 unix_data_t mud;
1292 if (mbox == NULL || (mud = (mailbox_unix_data_t) mbox->data) == NULL) 1256 if (mbox == NULL || (mud = (unix_data_t) mbox->data) == NULL)
1293 return EINVAL; 1257 return EINVAL;
1294 1258
1295 if (! mailbox_unix_is_updated (mbox)) 1259 if (! unix_is_updated (mbox))
1296 return mailbox_unix_scan0 (mbox, 1, pcount, 1); 1260 return unix_scan0 (mbox, 1, pcount, 1);
1297 1261
1298 if (pcount) 1262 if (pcount)
1299 *pcount = mud->messages_count; 1263 *pcount = mud->messages_count;
...@@ -1301,9 +1265,9 @@ mailbox_unix_messages_count (mailbox_t mbox, size_t *pcount) ...@@ -1301,9 +1265,9 @@ mailbox_unix_messages_count (mailbox_t mbox, size_t *pcount)
1301 return 0; 1265 return 0;
1302 } 1266 }
1303 1267
1304 /* locking */ 1268 /* Locking. */
1305 static int 1269 static int
1306 mailbox_unix_lock (mailbox_t mbox, int flag) 1270 unix_lock (mailbox_t mbox, int flag)
1307 { 1271 {
1308 if (mbox && mbox->locker != NULL) 1272 if (mbox && mbox->locker != NULL)
1309 { 1273 {
...@@ -1314,7 +1278,7 @@ mailbox_unix_lock (mailbox_t mbox, int flag) ...@@ -1314,7 +1278,7 @@ mailbox_unix_lock (mailbox_t mbox, int flag)
1314 } 1278 }
1315 1279
1316 static int 1280 static int
1317 mailbox_unix_touchlock (mailbox_t mbox) 1281 unix_touchlock (mailbox_t mbox)
1318 { 1282 {
1319 if (mbox && mbox->locker != NULL) 1283 if (mbox && mbox->locker != NULL)
1320 { 1284 {
...@@ -1325,7 +1289,7 @@ mailbox_unix_touchlock (mailbox_t mbox) ...@@ -1325,7 +1289,7 @@ mailbox_unix_touchlock (mailbox_t mbox)
1325 } 1289 }
1326 1290
1327 static int 1291 static int
1328 mailbox_unix_unlock (mailbox_t mbox) 1292 unix_unlock (mailbox_t mbox)
1329 { 1293 {
1330 if (mbox && mbox->locker != NULL) 1294 if (mbox && mbox->locker != NULL)
1331 { 1295 {
...@@ -1336,10 +1300,10 @@ mailbox_unix_unlock (mailbox_t mbox) ...@@ -1336,10 +1300,10 @@ mailbox_unix_unlock (mailbox_t mbox)
1336 } 1300 }
1337 1301
1338 static int 1302 static int
1339 mailbox_unix_ilock (mailbox_t mbox, int flag) 1303 unix_ilock (mailbox_t mbox, int flag)
1340 { 1304 {
1341 #ifdef HAVE_PTHREAD_H 1305 #ifdef HAVE_PTHREAD_H
1342 (void)flag; /* we should use rwlocks for more concurency */ 1306 (void)flag; /* We should use rwlocks for more concurency. */
1343 if (mbox == NULL) 1307 if (mbox == NULL)
1344 return EINVAL; 1308 return EINVAL;
1345 return pthread_mutex_lock (&(mbox->mutex)); 1309 return pthread_mutex_lock (&(mbox->mutex));
...@@ -1350,7 +1314,7 @@ mailbox_unix_ilock (mailbox_t mbox, int flag) ...@@ -1350,7 +1314,7 @@ mailbox_unix_ilock (mailbox_t mbox, int flag)
1350 } 1314 }
1351 1315
1352 static int 1316 static int
1353 mailbox_unix_iunlock (mailbox_t mbox) 1317 unix_iunlock (mailbox_t mbox)
1354 { 1318 {
1355 #ifdef HAVE_PTHREAD_H 1319 #ifdef HAVE_PTHREAD_H
1356 if (mbox == NULL) 1320 if (mbox == NULL)
......
...@@ -173,7 +173,7 @@ do \ ...@@ -173,7 +173,7 @@ do \
173 { \ 173 { \
174 if (*s == c0 || *s == c1) \ 174 if (*s == c0 || *s == c1) \
175 { \ 175 { \
176 (mum)->old_attr->flag |= (type); \ 176 (mum)->old_flags |= (type); \
177 break; \ 177 break; \
178 } \ 178 } \
179 } \ 179 } \
...@@ -206,16 +206,16 @@ do \ ...@@ -206,16 +206,16 @@ do \
206 do \ 206 do \
207 { \ 207 { \
208 int bailing = 0; \ 208 int bailing = 0; \
209 mailbox_unix_iunlock (mbox); \ 209 unix_iunlock (mbox); \
210 MAILBOX_NOTIFICATION (mbox, MU_EVT_MBX_MSG_ADD, bailing); \ 210 MAILBOX_NOTIFICATION (mbox, MU_EVT_MBX_MSG_ADD, bailing); \
211 if (bailing != 0) \ 211 if (bailing != 0) \
212 { \ 212 { \
213 if (pcount) \ 213 if (pcount) \
214 *pcount = (mud)->messages_count; \ 214 *pcount = (mud)->messages_count; \
215 mailbox_unix_unlock (mbox); \ 215 unix_unlock (mbox); \
216 return EINTR; \ 216 return EINTR; \
217 } \ 217 } \
218 mailbox_unix_ilock (mbox, MU_LOCKER_WRLOCK); \ 218 unix_ilock (mbox, MU_LOCKER_WRLOCK); \
219 } while (0); 219 } while (0);
220 220
221 /* notification MBX_PROGRESS 221 /* notification MBX_PROGRESS
...@@ -234,33 +234,38 @@ do \ ...@@ -234,33 +234,38 @@ do \
234 { \ 234 { \
235 { \ 235 { \
236 int bailing = 0; \ 236 int bailing = 0; \
237 mailbox_unix_iunlock (mbox); \ 237 unix_iunlock (mbox); \
238 mud->messages_count--; \ 238 mud->messages_count--; \
239 MAILBOX_NOTIFICATION (mbox, MU_EVT_MBX_PROGRESS,bailing); \ 239 MAILBOX_NOTIFICATION (mbox, MU_EVT_MBX_PROGRESS,bailing); \
240 if (bailing != 0) \ 240 if (bailing != 0) \
241 { \ 241 { \
242 if (pcount) \ 242 if (pcount) \
243 *pcount = (mud)->messages_count; \ 243 *pcount = (mud)->messages_count; \
244 mailbox_unix_unlock (mbox); \ 244 unix_unlock (mbox); \
245 return EINTR; \ 245 return EINTR; \
246 } \ 246 } \
247 mud->messages_count++; \ 247 mud->messages_count++; \
248 mailbox_unix_ilock (mbox, MU_LOCKER_WRLOCK); \ 248 unix_ilock (mbox, MU_LOCKER_WRLOCK); \
249 } \ 249 } \
250 } while (0) 250 } while (0)
251 251
252 #if 0
252 /* skip a function call, ?? do we gain that much */ 253 /* skip a function call, ?? do we gain that much */
253 #define ATTRIBUTE_CREATE(attr,mbox) \ 254 #define ATTRIBUTE_CREATE(attr, m, mbox) \
254 do \ 255 do \
255 { \ 256 { \
256 attr = calloc (1, sizeof(*(attr))); \ 257 attr = calloc (1, sizeof(*(attr))); \
258 attr->owner = m; \
257 if ((attr) == NULL) \ 259 if ((attr) == NULL) \
258 { \ 260 { \
259 mailbox_unix_iunlock (mbox); \ 261 unix_iunlock (mbox); \
260 mailbox_unix_unlock (mbox); \ 262 unix_unlock (mbox); \
261 return ENOMEM; \ 263 return ENOMEM; \
262 } \ 264 } \
263 } while (0) 265 } while (0)
266 #else
267 # define ATTRIBUTE_CREATE
268 #endif
264 269
265 /* allocate slots for the new messages */ 270 /* allocate slots for the new messages */
266 /* size_t num = 2 * ((mud)->messages_count) + 10; */ 271 /* size_t num = 2 * ((mud)->messages_count) + 10; */
...@@ -269,38 +274,37 @@ do \ ...@@ -269,38 +274,37 @@ do \
269 { \ 274 { \
270 if ((mud)->messages_count >= (mud)->umessages_count) \ 275 if ((mud)->messages_count >= (mud)->umessages_count) \
271 { \ 276 { \
272 mailbox_unix_message_t *m; \ 277 unix_message_t *m; \
273 size_t num = ((mud)->umessages_count) + 1; \ 278 size_t num = ((mud)->umessages_count) + 1; \
274 m = realloc ((mud)->umessages, num * sizeof (*m)); \ 279 m = realloc ((mud)->umessages, num * sizeof (*m)); \
275 if (m == NULL) \ 280 if (m == NULL) \
276 { \ 281 { \
277 mailbox_unix_iunlock (mbox); \ 282 unix_iunlock (mbox); \
278 mailbox_unix_unlock (mbox); \ 283 unix_unlock (mbox); \
279 return ENOMEM; \ 284 return ENOMEM; \
280 } \ 285 } \
281 (mud)->umessages = m; \ 286 (mud)->umessages = m; \
282 (mud)->umessages[num - 1] = calloc (1, sizeof (*(mum))); \ 287 (mud)->umessages[num - 1] = calloc (1, sizeof (*(mum))); \
283 if ((mud)->umessages[num - 1] == NULL) \ 288 if ((mud)->umessages[num - 1] == NULL) \
284 { \ 289 { \
285 mailbox_unix_iunlock (mbox); \ 290 unix_iunlock (mbox); \
286 mailbox_unix_unlock (mbox); \ 291 unix_unlock (mbox); \
287 return ENOMEM; \ 292 return ENOMEM; \
288 } \ 293 } \
289 ATTRIBUTE_CREATE (((mud)->umessages[num - 1])->old_attr, mbox); \
290 (mud)->umessages_count = num; \ 294 (mud)->umessages_count = num; \
291 } \ 295 } \
292 } while (0) 296 } while (0)
293 297
294 static int 298 static int
295 mailbox_unix_scan0 (mailbox_t mbox, size_t msgno, size_t *pcount, int do_notif) 299 unix_scan0 (mailbox_t mbox, size_t msgno, size_t *pcount, int do_notif)
296 { 300 {
297 #define MSGLINELEN 1024 301 #define MSGLINELEN 1024
298 char buf[MSGLINELEN]; 302 char buf[MSGLINELEN];
299 int inheader; 303 int inheader;
300 int inbody; 304 int inbody;
301 off_t total = 0; 305 off_t total = 0;
302 mailbox_unix_data_t mud; 306 unix_data_t mud;
303 mailbox_unix_message_t mum = NULL; 307 unix_message_t mum = NULL;
304 int status = 0; 308 int status = 0;
305 size_t lines; 309 size_t lines;
306 int newline; 310 int newline;
...@@ -311,7 +315,7 @@ mailbox_unix_scan0 (mailbox_t mbox, size_t msgno, size_t *pcount, int do_notif) ...@@ -311,7 +315,7 @@ mailbox_unix_scan0 (mailbox_t mbox, size_t msgno, size_t *pcount, int do_notif)
311 315
312 /* sanity */ 316 /* sanity */
313 if (mbox == NULL || 317 if (mbox == NULL ||
314 (mud = (mailbox_unix_data_t)mbox->data) == NULL) 318 (mud = (unix_data_t)mbox->data) == NULL)
315 return EINVAL; 319 return EINVAL;
316 320
317 /* save the timestamp and size */ 321 /* save the timestamp and size */
...@@ -320,8 +324,8 @@ mailbox_unix_scan0 (mailbox_t mbox, size_t msgno, size_t *pcount, int do_notif) ...@@ -320,8 +324,8 @@ mailbox_unix_scan0 (mailbox_t mbox, size_t msgno, size_t *pcount, int do_notif)
320 return status; 324 return status;
321 325
322 /* grab the locks */ 326 /* grab the locks */
323 mailbox_unix_ilock (mbox, MU_LOCKER_WRLOCK); 327 unix_ilock (mbox, MU_LOCKER_WRLOCK);
324 mailbox_unix_lock (mbox, MU_LOCKER_RDLOCK); 328 unix_lock (mbox, MU_LOCKER_RDLOCK);
325 329
326 /* seek to the starting point */ 330 /* seek to the starting point */
327 if (mud->umessages && msgno > 0 && mud->messages_count > 0 331 if (mud->umessages && msgno > 0 && mud->messages_count > 0
...@@ -403,7 +407,7 @@ mailbox_unix_scan0 (mailbox_t mbox, size_t msgno, size_t *pcount, int do_notif) ...@@ -403,7 +407,7 @@ mailbox_unix_scan0 (mailbox_t mbox, size_t msgno, size_t *pcount, int do_notif)
403 407
404 /* every 50 mesgs update the lock, it should be every minute */ 408 /* every 50 mesgs update the lock, it should be every minute */
405 if ((mud->messages_count % 50) == 0) 409 if ((mud->messages_count % 50) == 0)
406 mailbox_unix_touchlock (mbox); 410 unix_touchlock (mbox);
407 411
408 /* ping them every 1000 lines */ 412 /* ping them every 1000 lines */
409 if (do_notif) 413 if (do_notif)
...@@ -419,8 +423,8 @@ mailbox_unix_scan0 (mailbox_t mbox, size_t msgno, size_t *pcount, int do_notif) ...@@ -419,8 +423,8 @@ mailbox_unix_scan0 (mailbox_t mbox, size_t msgno, size_t *pcount, int do_notif)
419 if (do_notif) 423 if (do_notif)
420 DISPATCH_ADD_MSG(mbox, mud); 424 DISPATCH_ADD_MSG(mbox, mud);
421 } 425 }
422 mailbox_unix_iunlock (mbox); 426 unix_iunlock (mbox);
423 mailbox_unix_unlock (mbox); 427 unix_unlock (mbox);
424 if (pcount) 428 if (pcount)
425 *pcount = mud->messages_count; 429 *pcount = mud->messages_count;
426 return status; 430 return status;
......
...@@ -68,7 +68,7 @@ message_destroy (message_t *pmsg, void *owner) ...@@ -68,7 +68,7 @@ message_destroy (message_t *pmsg, void *owner)
68 /* header */ 68 /* header */
69 header_destroy (&(msg->header), owner); 69 header_destroy (&(msg->header), owner);
70 /* attribute */ 70 /* attribute */
71 attribute_destroy (&(msg->attribute)); 71 attribute_destroy (&(msg->attribute), owner);
72 /* stream */ 72 /* stream */
73 stream_destroy (&(msg->stream), owner); 73 stream_destroy (&(msg->stream), owner);
74 74
...@@ -325,7 +325,7 @@ message_get_attribute (message_t msg, attribute_t *pattribute) ...@@ -325,7 +325,7 @@ message_get_attribute (message_t msg, attribute_t *pattribute)
325 if (msg->attribute == NULL) 325 if (msg->attribute == NULL)
326 { 326 {
327 attribute_t attribute; 327 attribute_t attribute;
328 int status = attribute_create (&attribute); 328 int status = attribute_create (&attribute, msg);
329 if (status != 0) 329 if (status != 0)
330 return status; 330 return status;
331 msg->attribute = attribute; 331 msg->attribute = attribute;
...@@ -341,7 +341,7 @@ message_set_attribute (message_t msg, attribute_t attribute, void *owner) ...@@ -341,7 +341,7 @@ message_set_attribute (message_t msg, attribute_t attribute, void *owner)
341 return EINVAL; 341 return EINVAL;
342 if (msg->owner != owner) 342 if (msg->owner != owner)
343 return EACCES; 343 return EACCES;
344 attribute_destroy (&(msg->attribute)); 344 attribute_destroy (&(msg->attribute), owner);
345 msg->attribute = attribute; 345 msg->attribute = attribute;
346 return 0; 346 return 0;
347 } 347 }
...@@ -532,7 +532,11 @@ message_read (stream_t is, char *buf, size_t buflen, ...@@ -532,7 +532,11 @@ message_read (stream_t is, char *buf, size_t buflen,
532 header_size (msg->header, &hsize); 532 header_size (msg->header, &hsize);
533 body_size (msg->body, &bsize); 533 body_size (msg->body, &bsize);
534 534
535 if ((size_t)off <= hsize) 535 /* On some remote sever (POP) the size of the header and body is not known
536 until you start reading them. So by checking hsize == bsize == 0, we
537 This kludge of a way of detecting the anomalie and start by the
538 header. */
539 if ((size_t)off <= hsize || (hsize == 0 && bsize == 0))
536 { 540 {
537 header_get_stream (msg->header, &his); 541 header_get_stream (msg->header, &his);
538 stream_read (his, buf, buflen, off, &hread); 542 stream_read (his, buf, buflen, off, &hread);
......
...@@ -25,13 +25,12 @@ ...@@ -25,13 +25,12 @@
25 #include <string.h> 25 #include <string.h>
26 #include <errno.h> 26 #include <errno.h>
27 27
28 /* 28 /* Builtin mailbox types. A circular list is use for the builtin.
29 Builtin mailbox types.
30 A circular list is use for the builtin.
31 Proper locking is not done when accessing the list. 29 Proper locking is not done when accessing the list.
32 FIXME: not thread-safe. */ 30 FIXME: not thread-safe. */
33 31
34 static struct _registrar registrar [] = { 32 static struct _registrar registrar [] =
33 {
35 { NULL, NULL, 0, &registrar[1] }, /* sentinel, head list */ 34 { NULL, NULL, 0, &registrar[1] }, /* sentinel, head list */
36 { &_url_file_registrar, &_mailbox_mbox_registrar, 0, &registrar[2] }, 35 { &_url_file_registrar, &_mailbox_mbox_registrar, 0, &registrar[2] },
37 { &_url_mbox_registrar, &_mailbox_mbox_registrar, 0, &registrar[3] }, 36 { &_url_mbox_registrar, &_mailbox_mbox_registrar, 0, &registrar[3] },
......