Commit 48832b4a 48832b4ab9ea10b93c70ad756d9814c261b55f7e by Alain Magloire

UIDL is not looking for "X-UIDL" if not do an md5 of the message.

When expunging check if the message as been modified, for example
"X-UIDL" maybe add in the header it will now be save in the message.
expunge reuse the same code of mbox_append_message().
add a new header_set_fill() to get the header of the messages form the mailbox.
1 parent 4737689b
1 /* GNU mailutils - a suite of utilities for electronic mail 1 /* GNU mailutils - a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
3 3
4 This program is free software; you can redistribute it and/or modify 4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Library Public License as published by 5 it under the terms of the GNU General Library Public License as published by
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
25 25
26 #include <attribute0.h> 26 #include <attribute0.h>
27 27
28 static int flags_to_string __P ((int, char *, size_t, size_t *));
29
28 int 30 int
29 attribute_create (attribute_t *pattr, void *owner) 31 attribute_create (attribute_t *pattr, void *owner)
30 { 32 {
...@@ -59,6 +61,12 @@ attribute_get_owner (attribute_t attr) ...@@ -59,6 +61,12 @@ attribute_get_owner (attribute_t attr)
59 } 61 }
60 62
61 int 63 int
64 attribute_is_modified (attribute_t attr)
65 {
66 return (attr) ? attr->flags != 0 : 0;
67 }
68
69 int
62 attribute_get_flags (attribute_t attr, int *pflags) 70 attribute_get_flags (attribute_t attr, int *pflags)
63 { 71 {
64 if (attr == NULL) 72 if (attr == NULL)
...@@ -76,7 +84,7 @@ attribute_set_flags (attribute_t attr, int flags) ...@@ -76,7 +84,7 @@ attribute_set_flags (attribute_t attr, int flags)
76 if (attr == NULL) 84 if (attr == NULL)
77 return EINVAL; 85 return EINVAL;
78 if (attr->_set_flags) 86 if (attr->_set_flags)
79 return attr->_set_flags (attr, flags); 87 attr->_set_flags (attr, flags);
80 attr->flags |= flags; 88 attr->flags |= flags;
81 return 0; 89 return 0;
82 } 90 }
...@@ -446,7 +454,15 @@ string_to_flags (const char *buffer, int *pflags) ...@@ -446,7 +454,15 @@ string_to_flags (const char *buffer, int *pflags)
446 return 0; 454 return 0;
447 } 455 }
448 456
449 int 457 int
458 attribute_to_string (attribute_t attr, char *buffer, size_t len, size_t *pn)
459 {
460 int flags = 0;;
461 attribute_get_flags (attr, &flags);
462 return flags_to_string (flags, buffer, len, pn);
463 }
464
465 static int
450 flags_to_string (int flags, char *buffer, size_t len, size_t *pn) 466 flags_to_string (int flags, char *buffer, size_t len, size_t *pn)
451 { 467 {
452 char status[32]; 468 char status[32];
......
1 /* GNU mailutils - a suite of utilities for electronic mail 1 /* GNU mailutils - a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
3 3
4 This program is free software; you can redistribute it and/or modify 4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Library Public License as published by 5 it under the terms of the GNU General Library Public License as published by
...@@ -307,22 +307,10 @@ body_get_fd (stream_t stream, int *pfd) ...@@ -307,22 +307,10 @@ body_get_fd (stream_t stream, int *pfd)
307 static FILE * 307 static FILE *
308 lazy_create () 308 lazy_create ()
309 { 309 {
310 FILE *file; 310 FILE *file = tmpfile ();
311 #ifdef HAVE_MKSTEMP
312 char tmpbuf[L_tmpnam + 1];
313 int fd;
314
315 if (tmpnam (tmpbuf) == NULL ||
316 (fd = mkstemp (tmpbuf)) == -1 ||
317 (file = fdopen(fd, "w+")) == NULL)
318 return NULL;
319 (void)remove(tmpbuf);
320 #else
321 file = tmpfile ();
322 //file = fopen ("/tmp/mystuff", "w+"); 311 //file = fopen ("/tmp/mystuff", "w+");
323 /* make sure the mode is right */ 312 /* make sure the mode is right */
324 if (file) 313 if (file)
325 fchmod (fileno (file), 0600); 314 fchmod (fileno (file), 0600);
326 #endif
327 return file; 315 return file;
328 } 316 }
......
...@@ -334,11 +334,36 @@ folder_list (folder_t folder, const char *dirname, const char *basename, ...@@ -334,11 +334,36 @@ folder_list (folder_t folder, const char *dirname, const char *basename,
334 struct folder_list *pflist) 334 struct folder_list *pflist)
335 { 335 {
336 if (folder == NULL || folder->_list == NULL) 336 if (folder == NULL || folder->_list == NULL)
337 return ENOSYS; 337 return EINVAL;
338 return folder->_list (folder, dirname, basename, pflist); 338 return folder->_list (folder, dirname, basename, pflist);
339 } 339 }
340 340
341 int 341 int
342 folder_lsub (folder_t folder, const char *dirname, const char *basename,
343 struct folder_list *pflist)
344 {
345 if (folder == NULL || folder->_lsub == NULL)
346 return ENOSYS;
347 return folder->_lsub (folder, dirname, basename, pflist);
348 }
349
350 int
351 folder_subscribe (folder_t folder, const char *name)
352 {
353 if (folder == NULL || folder->_subscribe == NULL)
354 return EINVAL;
355 return folder->_subscribe (folder, name);
356 }
357
358 int
359 folder_unsubscribe (folder_t folder, const char *name)
360 {
361 if (folder == NULL || folder->_unsubscribe == NULL)
362 return EINVAL;
363 return folder->_unsubscribe (folder, name);
364 }
365
366 int
342 folder_list_destroy (struct folder_list *pflist) 367 folder_list_destroy (struct folder_list *pflist)
343 { 368 {
344 size_t i; 369 size_t i;
...@@ -353,7 +378,10 @@ folder_list_destroy (struct folder_list *pflist) ...@@ -353,7 +378,10 @@ folder_list_destroy (struct folder_list *pflist)
353 free (pflist->element[i]); 378 free (pflist->element[i]);
354 } 379 }
355 } 380 }
356 free (pflist->element); 381 if (i > 0)
382 free (pflist->element);
383 pflist->element = NULL;
384 pflist->num = 0;
357 return 0; 385 return 0;
358 } 386 }
359 387
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
24 #include <errno.h> 24 #include <errno.h>
25 #include <string.h> 25 #include <string.h>
26 #include <assert.h> 26 #include <assert.h>
27 #include <fnmatch.h>
27 28
28 #include <imap0.h> 29 #include <imap0.h>
29 30
...@@ -384,17 +385,93 @@ folder_imap_list (folder_t folder, const char *ref, const char *name, ...@@ -384,17 +385,93 @@ folder_imap_list (folder_t folder, const char *ref, const char *name,
384 { 385 {
385 f_imap_t f_imap = folder->data; 386 f_imap_t f_imap = folder->data;
386 int status = 0; 387 int status = 0;
388 char *path = NULL;
389
390 /* NOOP. */
391 if (pflist == NULL)
392 return EINVAL;
387 393
388 if (ref == NULL) 394 if (ref == NULL)
389 ref = ""; 395 ref = "";
390 if (name == NULL) 396 if (name == NULL)
391 name = ""; 397 name = "";
392 398
399 path = strdup ("");
400 if (path == NULL)
401 return ENOMEM;
402
403 /* We break the string to pieces and change the occurences of "*?[" for
404 the imap magic "%" for expansion. Then reassemble the string:
405 "/home/?/Mail/a*lain*" --> "/usr/%/Mail/%". */
406 {
407 int done = 0;
408 size_t i;
409 char **node = NULL;
410 size_t nodelen = 0;
411 const char *p = name;
412 /* Disassemble. */
413 while (!done && *p)
414 {
415 char **n;
416 n = realloc (node, (nodelen + 1) * sizeof (*node));
417 if (n == NULL)
418 break;
419 node = n;
420 if (*p == '/')
421 {
422 node[nodelen] = strdup ("/");
423 p++;
424 }
425 else
426 {
427 const char *s = strchr (p, '/');
428 if (s)
429 {
430 node[nodelen] = calloc (s - p + 1, sizeof (char));
431 if (node[nodelen])
432 memcpy (node[nodelen], p, s - p);
433 p = s;
434 }
435 else
436 {
437 node[nodelen] = strdup (p);
438 done = 1;
439 }
440 if (node[nodelen] && strpbrk (node[nodelen], "*?["))
441 {
442 free (node[nodelen]);
443 node[nodelen] = strdup ("%");
444 }
445 }
446 nodelen++;
447 if (done)
448 break;
449 }
450 /* Reassemble. */
451 for (i = 0; i < nodelen; i++)
452 {
453 if (node[i])
454 {
455 char *pth;
456 pth = realloc (path, strlen (path) + strlen (node[i]) + 1);
457 if (pth)
458 {
459 path = pth;
460 strcat (path, node[i]);
461 }
462 free (node[i]);
463 }
464 }
465 if (node)
466 free (node);
467 }
468
393 switch (f_imap->state) 469 switch (f_imap->state)
394 { 470 {
395 case IMAP_NO_STATE: 471 case IMAP_NO_STATE:
396 status = imap_writeline (f_imap, "g%d LIST \"%s\" \"%s\"\r\n", 472 status = imap_writeline (f_imap, "g%d LIST \"%s\" \"%s\"\r\n",
397 f_imap->seq++, ref, name); 473 f_imap->seq++, ref, path);
474 free (path);
398 CHECK_ERROR (f_imap, status); 475 CHECK_ERROR (f_imap, status);
399 FOLDER_DEBUG0 (folder, MU_DEBUG_PROT, f_imap->buffer); 476 FOLDER_DEBUG0 (folder, MU_DEBUG_PROT, f_imap->buffer);
400 f_imap->state = IMAP_LIST; 477 f_imap->state = IMAP_LIST;
...@@ -412,6 +489,39 @@ folder_imap_list (folder_t folder, const char *ref, const char *name, ...@@ -412,6 +489,39 @@ folder_imap_list (folder_t folder, const char *ref, const char *name,
412 default: 489 default:
413 break; 490 break;
414 } 491 }
492
493 /* Build the folder list. */
494 if (f_imap->callback.flist.num > 0)
495 {
496 struct list_response **plist = NULL;
497 size_t num = f_imap->callback.flist.num;
498 size_t j = 0;
499 plist = calloc (num, sizeof (*plist));
500 if (plist)
501 {
502 size_t i;
503 for (i = 0; i < num; i++)
504 {
505 struct list_response *lr = f_imap->callback.flist.element[i];
506 //printf ("%s --> %s\n", lr->name, name);
507 if (fnmatch (name, lr->name, 0) == 0)
508 {
509 plist[i] = calloc (1, sizeof (**plist));
510 if (plist[i] == NULL
511 || (plist[i]->name = strdup (lr->name)) == NULL)
512 {
513 break;
514 }
515 plist[i]->type = lr->type;
516 plist[i]->separator = lr->separator;
517 j++;
518 }
519 }
520 }
521 pflist->element = plist;
522 pflist->num = j;
523 }
524 folder_list_destroy (&(f_imap->callback.flist));
415 f_imap->state = IMAP_NO_STATE; 525 f_imap->state = IMAP_NO_STATE;
416 return status; 526 return status;
417 } 527 }
...@@ -423,10 +533,13 @@ folder_imap_lsub (folder_t folder, const char *ref, const char *name, ...@@ -423,10 +533,13 @@ folder_imap_lsub (folder_t folder, const char *ref, const char *name,
423 f_imap_t f_imap = folder->data; 533 f_imap_t f_imap = folder->data;
424 int status = 0; 534 int status = 0;
425 535
426 if (ref == NULL) 536 /* NOOP. */
427 ref = ""; 537 if (pflist == NULL)
428 if (name == NULL) 538 return EINVAL;
429 name = ""; 539
540 if (ref == NULL) ref = "";
541 if (name == NULL) name = "";
542
430 switch (f_imap->state) 543 switch (f_imap->state)
431 { 544 {
432 case IMAP_NO_STATE: 545 case IMAP_NO_STATE:
...@@ -449,6 +562,37 @@ folder_imap_lsub (folder_t folder, const char *ref, const char *name, ...@@ -449,6 +562,37 @@ folder_imap_lsub (folder_t folder, const char *ref, const char *name,
449 default: 562 default:
450 break; 563 break;
451 } 564 }
565
566 /* Build the folder list. */
567 if (f_imap->callback.flist.num > 0)
568 {
569 struct list_response **plist = NULL;
570 size_t num = f_imap->callback.flist.num;
571 size_t j = 0;
572 plist = calloc (num, sizeof (*plist));
573 if (plist)
574 {
575 size_t i;
576 for (i = 0; i < num; i++)
577 {
578 struct list_response *lr = f_imap->callback.flist.element[i];
579 //printf ("%s --> %s\n", lr->name, name);
580 plist[i] = calloc (1, sizeof (**plist));
581 if (plist[i] == NULL
582 || (plist[i]->name = strdup (lr->name)) == NULL)
583 {
584 break;
585 }
586 plist[i]->type = lr->type;
587 plist[i]->separator = lr->separator;
588 j++;
589 }
590 }
591 pflist->element = plist;
592 pflist->num = j;
593 folder_list_destroy (&(f_imap->callback.flist));
594 }
595 f_imap->state = IMAP_NO_STATE;
452 f_imap->state = IMAP_NO_STATE; 596 f_imap->state = IMAP_NO_STATE;
453 return 0; 597 return 0;
454 } 598 }
...@@ -755,6 +899,86 @@ imap_string (f_imap_t f_imap) ...@@ -755,6 +899,86 @@ imap_string (f_imap_t f_imap)
755 return status; 899 return status;
756 } 900 }
757 901
902 /* FIXME: does not worl for nobloking. */
903 static int
904 imap_list (f_imap_t f_imap)
905 {
906 char *tok;
907 char *sp = NULL;
908 size_t len = f_imap->nl - f_imap->buffer - 1;
909 char *buffer;
910 struct list_response **plr;
911 struct list_response *lr;
912
913 buffer = alloca (len);
914 memcpy (buffer, f_imap->buffer, len);
915 buffer[len] = '\0';
916 plr = realloc (f_imap->callback.flist.element,
917 (f_imap->callback.flist.num + 1) * sizeof (*plr));
918 if (plr == NULL)
919 return ENOMEM;
920 f_imap->callback.flist.element = plr;
921 lr = plr[f_imap->callback.flist.num] = calloc (1, sizeof (*lr));
922 if (lr == NULL)
923 return ENOMEM;
924 (f_imap->callback.flist.num)++;
925
926 /* Glob untag. */
927 tok = strtok_r (buffer, " ", &sp);
928 /* Glob LIST. */
929 tok = strtok_r (NULL, " ", &sp);
930 /* Get the attibutes. */
931 tok = strtok_r (NULL, ")", &sp);
932 if (tok)
933 {
934 char *s = NULL;
935 char *p = tok;
936 while ((tok = strtok_r (p, " ()", &s)) != NULL)
937 {
938 if (strcasecmp (tok, "\\Noselect") == 0)
939 {
940 }
941 else if (strcasecmp (tok, "\\Marked") == 0)
942 {
943 }
944 else if (strcasecmp (tok, "\\Unmarked") == 0)
945 {
946 }
947 else if (strcasecmp (tok, "\\Noinferiors") == 0)
948 {
949 lr->type |= MU_FOLDER_ATTRIBUTE_FILE;
950 }
951 else
952 {
953 lr->type |= MU_FOLDER_ATTRIBUTE_DIRECTORY;
954 }
955 p = NULL;
956 }
957 }
958 /* Hiearchy delimeter. */
959 tok = strtok_r (NULL, " ", &sp);
960 if (tok && strlen (tok) > 2)
961 lr->separator = tok[1];
962 /* The path. */
963 tok = strtok_r (NULL, " ", &sp);
964 if (tok)
965 {
966 char *s = strchr (tok, '{');
967 if (s)
968 {
969 size_t n = strtoul (s + 1, NULL, 10);
970 lr->name = calloc (n + 1, sizeof (char));
971 f_imap->ptr = f_imap->buffer;
972 imap_readline (f_imap);
973 memcpy (lr->name, f_imap->buffer, n);
974 lr->name[n] = '\0';
975 }
976 else
977 lr->name = strdup (tok);
978 }
979 return 0;
980 }
981
758 /* Helping function to figure out the section name of the message: for example 982 /* Helping function to figure out the section name of the message: for example
759 a 2 part message with the first part being sub in two will be: 983 a 2 part message with the first part being sub in two will be:
760 {1}, {1,1} {1,2} The first subpart of the message and its sub parts 984 {1}, {1,1} {1,2} The first subpart of the message and its sub parts
...@@ -803,6 +1027,7 @@ section_name (msg_imap_t msg_imap) ...@@ -803,6 +1027,7 @@ section_name (msg_imap_t msg_imap)
803 return section; 1027 return section;
804 } 1028 }
805 1029
1030 /* FIXME: This does not work for nonblocking. */
806 /* Recursive call, to parse the dismay of parentesis "()" in a BODYSTRUCTURE 1031 /* Recursive call, to parse the dismay of parentesis "()" in a BODYSTRUCTURE
807 call, not we use the short form of BODYSTRUCTURE, BODY with no argument. */ 1032 call, not we use the short form of BODYSTRUCTURE, BODY with no argument. */
808 static int 1033 static int
...@@ -1231,12 +1456,12 @@ imap_parse (f_imap_t f_imap) ...@@ -1231,12 +1456,12 @@ imap_parse (f_imap_t f_imap)
1231 char *tag, *response, *remainder; 1456 char *tag, *response, *remainder;
1232 char *buffer; 1457 char *buffer;
1233 status = imap_readline (f_imap); 1458 status = imap_readline (f_imap);
1234 /* Comment out to see all reading traffic. */
1235 //fprintf (stderr, "\t\t%s", f_imap->buffer);
1236 if (status != 0) 1459 if (status != 0)
1237 { 1460 {
1238 break; 1461 break;
1239 } 1462 }
1463 /* Comment out to see all reading traffic. */
1464 fprintf (stderr, "\t\t%s", f_imap->buffer);
1240 1465
1241 /* We do not want to step over f_imap->buffer since it can be use 1466 /* We do not want to step over f_imap->buffer since it can be use
1242 further down the chain. */ 1467 further down the chain. */
...@@ -1429,9 +1654,11 @@ imap_parse (f_imap_t f_imap) ...@@ -1429,9 +1654,11 @@ imap_parse (f_imap_t f_imap)
1429 } 1654 }
1430 else if (strcmp (response, "LIST") == 0) 1655 else if (strcmp (response, "LIST") == 0)
1431 { 1656 {
1657 status = imap_list (f_imap);
1432 } 1658 }
1433 else if (strcmp (response, "LSUB") == 0) 1659 else if (strcmp (response, "LSUB") == 0)
1434 { 1660 {
1661 status = imap_list (f_imap);
1435 } 1662 }
1436 else if (strcmp (remainder, "RECENT") == 0) 1663 else if (strcmp (remainder, "RECENT") == 0)
1437 { 1664 {
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
25 #include <unistd.h> 25 #include <unistd.h>
26 #include <string.h> 26 #include <string.h>
27 #include <glob.h> 27 #include <glob.h>
28 #include <fnmatch.h>
28 #include <stdio.h> 29 #include <stdio.h>
29 #include <stdlib.h> 30 #include <stdlib.h>
30 31
...@@ -83,19 +84,27 @@ static struct _record _path_record = ...@@ -83,19 +84,27 @@ static struct _record _path_record =
83 record_t path_record = &_path_record; 84 record_t path_record = &_path_record;
84 85
85 /* lsub/subscribe/unsubscribe are not needed. */ 86 /* lsub/subscribe/unsubscribe are not needed. */
86 static void folder_mbox_destroy __P ((folder_t)); 87 static void folder_mbox_destroy __P ((folder_t));
87 static int folder_mbox_open __P ((folder_t, int)); 88 static int folder_mbox_open __P ((folder_t, int));
88 static int folder_mbox_close __P ((folder_t)); 89 static int folder_mbox_close __P ((folder_t));
89 static int folder_mbox_delete __P ((folder_t, const char *)); 90 static int folder_mbox_delete __P ((folder_t, const char *));
90 static int folder_mbox_rename __P ((folder_t , const char *, const char *)); 91 static int folder_mbox_rename __P ((folder_t , const char *,
91 static int folder_mbox_list __P ((folder_t, const char *, const char *, 92 const char *));
92 struct folder_list *)); 93 static int folder_mbox_list __P ((folder_t, const char *, const char *,
94 struct folder_list *));
95 static int folder_mbox_subscribe __P ((folder_t, const char *));
96 static int folder_mbox_unsubscribe __P ((folder_t, const char *));
97 static int folder_mbox_lsub __P ((folder_t, const char *, const char *,
98 struct folder_list *));
99
93 100
94 static char *get_pathname __P ((const char *, const char *)); 101 static char *get_pathname __P ((const char *, const char *));
95 102
96 struct _fmbox 103 struct _fmbox
97 { 104 {
98 char *dirname; 105 char *dirname;
106 char **subscribe;
107 size_t sublen;
99 }; 108 };
100 typedef struct _fmbox *fmbox_t; 109 typedef struct _fmbox *fmbox_t;
101 110
...@@ -126,9 +135,11 @@ _folder_mbox_init (folder_t folder) ...@@ -126,9 +135,11 @@ _folder_mbox_init (folder_t folder)
126 folder->_close = folder_mbox_close; 135 folder->_close = folder_mbox_close;
127 136
128 folder->_list = folder_mbox_list; 137 folder->_list = folder_mbox_list;
138 folder->_lsub = folder_mbox_lsub;
139 folder->_subscribe = folder_mbox_subscribe;
140 folder->_unsubscribe = folder_mbox_unsubscribe;
129 folder->_delete = folder_mbox_delete; 141 folder->_delete = folder_mbox_delete;
130 folder->_rename = folder_mbox_rename; 142 folder->_rename = folder_mbox_rename;
131
132 return 0; 143 return 0;
133 } 144 }
134 145
...@@ -140,6 +151,8 @@ folder_mbox_destroy (folder_t folder) ...@@ -140,6 +151,8 @@ folder_mbox_destroy (folder_t folder)
140 fmbox_t fmbox = folder->data; 151 fmbox_t fmbox = folder->data;
141 if (fmbox->dirname) 152 if (fmbox->dirname)
142 free (fmbox->dirname); 153 free (fmbox->dirname);
154 if (fmbox->subscribe)
155 free (fmbox->subscribe);
143 free (folder->data); 156 free (folder->data);
144 folder->data = NULL; 157 folder->data = NULL;
145 } 158 }
...@@ -150,7 +163,6 @@ static int ...@@ -150,7 +163,6 @@ static int
150 folder_mbox_open (folder_t folder, int flags) 163 folder_mbox_open (folder_t folder, int flags)
151 { 164 {
152 (void)(folder); 165 (void)(folder);
153
154 (void)(flags); 166 (void)(flags);
155 return 0; 167 return 0;
156 } 168 }
...@@ -281,6 +293,84 @@ folder_mbox_list (folder_t folder, const char *dirname, const char *pattern, ...@@ -281,6 +293,84 @@ folder_mbox_list (folder_t folder, const char *dirname, const char *pattern,
281 return status; 293 return status;
282 } 294 }
283 295
296 static int
297 folder_mbox_lsub (folder_t folder, const char *ref, const char *name,
298 struct folder_list *pflist)
299 {
300 fmbox_t fmbox = folder->data;
301 size_t j = 0;
302
303 if (pflist == NULL)
304 return EINVAL;
305
306 (void)ref;
307 if (name == NULL || *name == '\0')
308 name = "*";
309
310 if (fmbox->sublen > 0)
311 {
312 struct list_response **plist;
313 size_t i;
314 plist = calloc (fmbox->sublen, sizeof (*plist));
315 for (i = 0; i < fmbox->sublen; i++)
316 {
317 if (fmbox->subscribe[i]
318 && fnmatch (name, fmbox->subscribe[i], 0) == 0)
319 {
320 plist[i] = calloc (1, sizeof (**plist));
321 if (plist[i] == NULL
322 || (plist[i]->name = strdup (fmbox->subscribe[i])) == NULL)
323 break;
324 plist[i]->type = MU_FOLDER_ATTRIBUTE_FILE;
325 plist[i]->separator = '/';
326 j++;
327 }
328 }
329 pflist->element = plist;
330 }
331 pflist->num = j;
332 return 0;
333 }
334
335 static int
336 folder_mbox_subscribe (folder_t folder, const char *name)
337 {
338 fmbox_t fmbox = folder->data;
339 char **tmp;
340 size_t i;
341 for (i = 0; i < fmbox->sublen; i++)
342 {
343 if (fmbox->subscribe[i] && strcmp (fmbox->subscribe[i], name) == 0)
344 return 0;
345 }
346 tmp = realloc (fmbox->subscribe, (fmbox->sublen + 1) * sizeof (*tmp));
347 if (tmp == NULL)
348 return ENOMEM;
349 fmbox->subscribe = tmp;
350 fmbox->subscribe[fmbox->sublen] = strdup (name);
351 if (fmbox->subscribe[fmbox->sublen] == NULL)
352 return ENOMEM;
353 fmbox->sublen++;
354 return 0;
355 }
356
357 static int
358 folder_mbox_unsubscribe (folder_t folder, const char *name)
359 {
360 fmbox_t fmbox = folder->data;
361 size_t i;
362 for (i = 0; i < fmbox->sublen; i++)
363 {
364 if (fmbox->subscribe[i] && strcmp (fmbox->subscribe[i], name) == 0)
365 {
366 free (fmbox->subscribe[i]);
367 fmbox->subscribe[i] = NULL;
368 return 0;
369 }
370 }
371 return ENOENT;
372 }
373
284 static char * 374 static char *
285 get_pathname (const char *dirname, const char *basename) 375 get_pathname (const char *dirname, const char *basename)
286 { 376 {
......
...@@ -28,12 +28,14 @@ ...@@ -28,12 +28,14 @@
28 #include <mailutils/stream.h> 28 #include <mailutils/stream.h>
29 #include <header0.h> 29 #include <header0.h>
30 30
31 static int header_parse (header_t h, const char *blurb, int len); 31 #define HEADER_MODIFIED 1
32 static int header_read (stream_t is, char *buf, size_t buflen, 32
33 off_t off, size_t *pnread); 33 static int header_parse __P ((header_t, const char *, int));
34 static int header_write (stream_t os, const char *buf, size_t buflen, 34 static int header_read __P ((stream_t, char *, size_t, off_t, size_t *));
35 off_t off, size_t *pnwrite); 35 static int header_readline __P ((stream_t, char *, size_t, off_t, size_t *));
36 static int fill_blurb (header_t header); 36 static int header_write __P ((stream_t, const char *, size_t, off_t,
37 size_t *));
38 static int fill_blurb __P ((header_t));
37 39
38 int 40 int
39 header_create (header_t *ph, const char *blurb, size_t len, void *owner) 41 header_create (header_t *ph, const char *blurb, size_t len, void *owner)
...@@ -79,6 +81,12 @@ header_get_owner (header_t header) ...@@ -79,6 +81,12 @@ header_get_owner (header_t header)
79 return (header) ? header->owner : NULL; 81 return (header) ? header->owner : NULL;
80 } 82 }
81 83
84 int
85 header_is_modified (header_t header)
86 {
87 return (header) ? (header->flags & HEADER_MODIFIED) : 0;
88 }
89
82 /* Parsing is done in a rather simple fashion. 90 /* Parsing is done in a rather simple fashion.
83 meaning we just consider an entry to be 91 meaning we just consider an entry to be
84 a field-name an a field-value. So they 92 a field-name an a field-value. So they
...@@ -298,6 +306,7 @@ header_set_value (header_t header, const char *fn, const char *fv, int replace) ...@@ -298,6 +306,7 @@ header_set_value (header_t header, const char *fn, const char *fv, int replace)
298 } 306 }
299 header_parse (header, blurb, len + header->blurb_len); 307 header_parse (header, blurb, len + header->blurb_len);
300 free (blurb); 308 free (blurb);
309 header->flags |= HEADER_MODIFIED;
301 return 0; 310 return 0;
302 } 311 }
303 312
...@@ -498,23 +507,43 @@ header_set_stream (header_t header, stream_t stream, void *owner) ...@@ -498,23 +507,43 @@ header_set_stream (header_t header, stream_t stream, void *owner)
498 return 0; 507 return 0;
499 } 508 }
500 509
510 int
511 header_set_fill (header_t header, int
512 (*_fill) __P ((header_t, char *, size_t, off_t, size_t *)),
513 void *owner)
514 {
515 if (header == NULL)
516 return EINVAL;
517 if (header->owner != owner)
518 return EACCES;
519 header->_fill = _fill;
520 return 0;
521 }
522
501 static int 523 static int
502 fill_blurb (header_t header) 524 fill_blurb (header_t header)
503 { 525 {
504 stream_t is; 526 stream_t is = NULL;
505 int status; 527 int status;
506 char buf[1024]; 528 char buf[1024];
507 char *tbuf; 529 char *tbuf;
508 size_t nread = 0; 530 size_t nread = 0;
509 531
510 status = header_get_stream (header, &is); 532 if (header->_fill == NULL)
511 if (status != 0) 533 {
512 return status; 534 status = header_get_stream (header, &is);
535 if (status != 0)
536 return status;
537 }
513 538
514 do 539 do
515 { 540 {
516 status = stream_read (is, buf, sizeof (buf), header->temp_blurb_len, 541 if (header->_fill)
517 &nread); 542 status = header->_fill (header, buf, sizeof (buf),
543 header->temp_blurb_len, &nread) ;
544 else
545 status = stream_read (is, buf, sizeof (buf),
546 header->temp_blurb_len, &nread);
518 if (status != 0) 547 if (status != 0)
519 { 548 {
520 if (status != EAGAIN && status != EINTR) 549 if (status != EAGAIN && status != EINTR)
...@@ -572,8 +601,7 @@ header_write (stream_t os, const char *buf, size_t buflen, ...@@ -572,8 +601,7 @@ header_write (stream_t os, const char *buf, size_t buflen,
572 } 601 }
573 602
574 static int 603 static int
575 header_read (stream_t is, char *buf, size_t buflen, 604 header_read (stream_t is, char *buf, size_t buflen, off_t off, size_t *pnread)
576 off_t off, size_t *pnread)
577 { 605 {
578 header_t header = stream_get_owner (is); 606 header_t header = stream_get_owner (is);
579 int len; 607 int len;
...@@ -581,6 +609,14 @@ header_read (stream_t is, char *buf, size_t buflen, ...@@ -581,6 +609,14 @@ header_read (stream_t is, char *buf, size_t buflen,
581 if (is == NULL || header == NULL) 609 if (is == NULL || header == NULL)
582 return EINVAL; 610 return EINVAL;
583 611
612 /* Try to fill out the buffer, if we know how. */
613 if (header->blurb == NULL)
614 {
615 int err = fill_blurb (header);
616 if (err != 0)
617 return err;
618 }
619
584 len = header->blurb_len - off; 620 len = header->blurb_len - off;
585 if (len > 0) 621 if (len > 0)
586 { 622 {
...@@ -598,6 +634,52 @@ header_read (stream_t is, char *buf, size_t buflen, ...@@ -598,6 +634,52 @@ header_read (stream_t is, char *buf, size_t buflen,
598 return 0; 634 return 0;
599 } 635 }
600 636
637 static int
638 header_readline (stream_t is, char *buf, size_t buflen, off_t off, size_t *pn)
639 {
640 header_t header = stream_get_owner (is);
641 int len;
642
643 if (is == NULL || header == NULL)
644 return EINVAL;
645
646 if (buf == NULL || buflen == 0)
647 {
648 if (pn)
649 *pn = 0;
650 return 0;
651 }
652
653 /* Try to fill out the buffer, if we know how. */
654 if (header->blurb == NULL)
655 {
656 int err = fill_blurb (header);
657 if (err != 0)
658 return err;
659 }
660
661 buflen--; /* Space for the null. */
662
663 len = header->blurb_len - off;
664 if (len > 0)
665 {
666 char *nl = memchr (header->blurb + off, '\n', len);
667 if (nl)
668 len = nl - (header->blurb + off) + 1;
669
670 len = (buflen < (size_t)len) ? buflen : len;
671 memcpy (buf, header->blurb + off, len);
672 buf[len] = '\0';
673 }
674 else
675 len = 0;
676
677 if (pn)
678 *pn = len;
679 return 0;
680 }
681
682
601 int 683 int
602 header_get_stream (header_t header, stream_t *pstream) 684 header_get_stream (header_t header, stream_t *pstream)
603 { 685 {
...@@ -608,7 +690,8 @@ header_get_stream (header_t header, stream_t *pstream) ...@@ -608,7 +690,8 @@ header_get_stream (header_t header, stream_t *pstream)
608 int status = stream_create (&(header->stream), MU_STREAM_RDWR, header); 690 int status = stream_create (&(header->stream), MU_STREAM_RDWR, header);
609 if (status != 0) 691 if (status != 0)
610 return status; 692 return status;
611 stream_set_read (header->stream, header_read, header); 693 stream_set_read (header->stream, header_read, header);
694 stream_set_readline (header->stream, header_readline, header);
612 stream_set_write (header->stream, header_write, header); 695 stream_set_write (header->stream, header_write, header);
613 } 696 }
614 *pstream = header->stream; 697 *pstream = header->stream;
......
1 /* GNU mailutils - a suite of utilities for electronic mail 1 /* GNU mailutils - a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
3 3
4 This program is free software; you can redistribute it and/or modify 4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Library Public License as published by 5 it under the terms of the GNU General Library Public License as published by
...@@ -61,6 +61,7 @@ struct _header ...@@ -61,6 +61,7 @@ struct _header
61 size_t blurb_len; 61 size_t blurb_len;
62 size_t hdr_count; 62 size_t hdr_count;
63 struct _hdr *hdr; 63 struct _hdr *hdr;
64 int flags;
64 65
65 /* Streams. */ 66 /* Streams. */
66 stream_t stream; 67 stream_t stream;
...@@ -68,6 +69,7 @@ struct _header ...@@ -68,6 +69,7 @@ struct _header
68 int (*_set_value) __P ((header_t, const char *, const char *, int)); 69 int (*_set_value) __P ((header_t, const char *, const char *, int));
69 int (*_lines) __P ((header_t, size_t *)); 70 int (*_lines) __P ((header_t, size_t *));
70 int (*_size) __P ((header_t, size_t *)); 71 int (*_size) __P ((header_t, size_t *));
72 int (*_fill) __P ((header_t, char *, size_t, off_t, size_t *));
71 }; 73 };
72 74
73 #ifdef _cplusplus 75 #ifdef _cplusplus
......
...@@ -121,6 +121,7 @@ struct literal_string ...@@ -121,6 +121,7 @@ struct literal_string
121 size_t total; 121 size_t total;
122 msg_imap_t msg_imap; 122 msg_imap_t msg_imap;
123 enum imap_state type; 123 enum imap_state type;
124 struct folder_list flist;
124 size_t nleft; /* nleft to read in the literal. */ 125 size_t nleft; /* nleft to read in the literal. */
125 }; 126 };
126 127
......
1 /* GNU mailutils - a suite of utilities for electronic mail 1 /* GNU mailutils - a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
3 3
4 This program is free software; you can redistribute it and/or modify 4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Library Public License as published by 5 it under the terms of the GNU General Library Public License as published by
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
32 /* 32 /*
33 */ 33 */
34 int 34 int
35 mailer_create (mailer_t *pmailer, const char *name, int id) 35 mailer_create (mailer_t *pmailer, const char *name)
36 { 36 {
37 int status = EINVAL; 37 int status = EINVAL;
38 record_t record = NULL; 38 record_t record = NULL;
...@@ -42,7 +42,6 @@ mailer_create (mailer_t *pmailer, const char *name, int id) ...@@ -42,7 +42,6 @@ mailer_create (mailer_t *pmailer, const char *name, int id)
42 iterator_t iterator; 42 iterator_t iterator;
43 int found = 0; 43 int found = 0;
44 44
45 (void)id;
46 if (pmailer == NULL) 45 if (pmailer == NULL)
47 return EINVAL; 46 return EINVAL;
48 47
......
1 /* GNU mailutils - a suite of utilities for electronic mail 1 /* GNU mailutils - a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
3 3
4 This program is free software; you can redistribute it and/or modify 4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Library Public License as published by 5 it under the terms of the GNU General Library Public License as published by
...@@ -183,15 +183,37 @@ _mapfile_size (stream_t stream, off_t *psize) ...@@ -183,15 +183,37 @@ _mapfile_size (stream_t stream, off_t *psize)
183 { 183 {
184 struct _mapfile_stream *mfs = stream_get_owner (stream); 184 struct _mapfile_stream *mfs = stream_get_owner (stream);
185 struct stat stbuf; 185 struct stat stbuf;
186 int err = 0;
186 187
187 if (mfs == NULL || mfs->ptr == NULL) 188 if (mfs == NULL || mfs->ptr == NULL)
188 return EINVAL; 189 return EINVAL;
189 msync (mfs->ptr, mfs->size, MS_SYNC); 190 msync (mfs->ptr, mfs->size, MS_SYNC);
190 if (fstat(mfs->fd, &stbuf) != 0) 191 if (fstat(mfs->fd, &stbuf) != 0)
191 return errno; 192 return errno;
192 if (psize) 193 if (mfs->size != (size_t)stbuf.st_size)
193 *psize = stbuf.st_size; 194 {
194 return 0; 195 if (munmap (mfs->ptr, mfs->size) == 0)
196 {
197 mfs->size = stbuf.st_size;
198 mfs->ptr = mmap (0, mfs->size, mfs->flags , MAP_SHARED, mfs->fd, 0);
199 if (mfs->ptr == MAP_FAILED)
200 err = errno;
201 }
202 else
203 err = errno;
204 }
205 if (err != 0)
206 {
207 mfs->ptr = NULL;
208 close (mfs->fd);
209 mfs->fd = -1;
210 }
211 else
212 {
213 if (psize)
214 *psize = stbuf.st_size;
215 }
216 return err;
195 } 217 }
196 218
197 static int 219 static int
...@@ -277,6 +299,7 @@ _mapfile_open (stream_t stream, const char *filename, int port, int flags) ...@@ -277,6 +299,7 @@ _mapfile_open (stream_t stream, const char *filename, int port, int flags)
277 { 299 {
278 int err = errno; 300 int err = errno;
279 close (mfs->fd); 301 close (mfs->fd);
302 mfs->ptr = NULL;
280 return err; 303 return err;
281 } 304 }
282 mfs->flags = mflag; 305 mfs->flags = mflag;
......
...@@ -105,7 +105,10 @@ struct _mbox_data ...@@ -105,7 +105,10 @@ struct _mbox_data
105 /* The variables below are use to hold the state when appending messages. */ 105 /* The variables below are use to hold the state when appending messages. */
106 enum mbox_state 106 enum mbox_state
107 { 107 {
108 MBOX_NO_STATE=0, MBOX_STATE_FROM, MBOX_STATE_DATE, MBOX_STATE_APPEND 108 MBOX_NO_STATE = 0,
109 MBOX_STATE_APPEND_SENDER, MBOX_STATE_APPEND_DATE, MBOX_STATE_APPEND_HEADER,
110 MBOX_STATE_APPEND_ATTRIBUTE, MBOX_STATE_APPEND_BODY,
111 MBOX_STATE_APPEND_MESSAGE
109 } state ; 112 } state ;
110 char *sender; 113 char *sender;
111 char *date; 114 char *date;
...@@ -114,35 +117,47 @@ struct _mbox_data ...@@ -114,35 +117,47 @@ struct _mbox_data
114 }; 117 };
115 118
116 /* Mailbox concrete implementation. */ 119 /* Mailbox concrete implementation. */
117 static int mbox_open __P ((mailbox_t, int)); 120 static int mbox_open __P ((mailbox_t, int));
118 static int mbox_close __P ((mailbox_t)); 121 static int mbox_close __P ((mailbox_t));
119 static int mbox_get_message __P ((mailbox_t, size_t, message_t *)); 122 static int mbox_get_message __P ((mailbox_t, size_t, message_t *));
120 static int mbox_append_message __P ((mailbox_t, message_t)); 123 static int mbox_append_message __P ((mailbox_t, message_t));
121 static int mbox_messages_count __P ((mailbox_t, size_t *)); 124 static int mbox_messages_count __P ((mailbox_t, size_t *));
122 static int mbox_expunge __P ((mailbox_t)); 125 static int mbox_expunge __P ((mailbox_t));
123 static int mbox_scan __P ((mailbox_t, size_t, size_t *)); 126 static int mbox_scan __P ((mailbox_t, size_t, size_t *));
124 static int mbox_is_updated __P ((mailbox_t)); 127 static int mbox_is_updated __P ((mailbox_t));
125 static int mbox_size __P ((mailbox_t, off_t *)); 128 static int mbox_size __P ((mailbox_t, off_t *));
126
127 129
128 /* private stuff */ 130 /* private stuff */
129 static int mbox_scan0 __P ((mailbox_t, size_t, size_t *, int)); 131 static int mbox_scan0 __P ((mailbox_t, size_t, size_t *, int));
130 static int mbox_get_header_read __P ((stream_t, char *, size_t, off_t, size_t *)); 132 static int mbox_append_message0 __P ((mailbox_t, message_t, off_t *,
131 static int mbox_get_hdr_fd __P ((stream_t, int *)); 133 int));
132 static int mbox_get_body_fd __P ((stream_t, int *)); 134 static int mbox_header_fill __P ((header_t, char *, size_t, off_t,
133 static int mbox_get_fd __P ((mbox_message_t, int *)); 135 size_t *));
134 static int mbox_get_attr_flags __P ((attribute_t, int *)); 136 static int mbox_get_header_readstream __P ((message_t, char *, size_t, off_t,
135 static int mbox_set_attr_flags __P ((attribute_t, int)); 137 size_t *, int));
136 static int mbox_unset_attr_flags __P ((attribute_t, int)); 138 static int mbox_get_hdr_fd __P ((stream_t, int *));
137 static int mbox_readstream __P ((stream_t, char *, size_t, off_t, size_t *)); 139 static int mbox_get_body_fd __P ((stream_t, int *));
138 static int mbox_header_size __P ((header_t, size_t *)); 140 static int mbox_get_fd __P ((mbox_message_t, int *));
139 static int mbox_header_lines __P ((header_t, size_t *)); 141 static int mbox_get_attr_flags __P ((attribute_t, int *));
140 static int mbox_body_size __P ((body_t, size_t *)); 142 static int mbox_set_attr_flags __P ((attribute_t, int));
141 static int mbox_body_lines __P ((body_t, size_t *)); 143 static int mbox_unset_attr_flags __P ((attribute_t, int));
142 static int mbox_envelope_sender __P ((envelope_t, char *, size_t, size_t *)); 144 static int mbox_body_read __P ((stream_t, char *, size_t, off_t,
143 static int mbox_envelope_date __P ((envelope_t, char *, size_t, size_t *)); 145 size_t *));
146 static int mbox_body_readline __P ((stream_t, char *, size_t, off_t,
147 size_t *));
148 static int mbox_body_readstream __P ((stream_t, char *, size_t, off_t,
149 size_t *, int));
150 static int mbox_header_size __P ((header_t, size_t *));
151 static int mbox_header_lines __P ((header_t, size_t *));
152 static int mbox_body_size __P ((body_t, size_t *));
153 static int mbox_body_lines __P ((body_t, size_t *));
154 static int mbox_envelope_sender __P ((envelope_t, char *, size_t,
155 size_t *));
156 static int mbox_envelope_date __P ((envelope_t, char *, size_t,
157 size_t *));
158 static int mbox_tmpfile __P ((mailbox_t, char **pbox));
144 #ifdef WITH_PTHREAD 159 #ifdef WITH_PTHREAD
145 static void mbox_cleanup __P ((void *)); 160 static void mbox_cleanup __P ((void *));
146 #endif 161 #endif
147 162
148 /* We allocate the mbox_data_t struct, but don't do any parsing on the name or 163 /* We allocate the mbox_data_t struct, but don't do any parsing on the name or
...@@ -253,7 +268,9 @@ mbox_open (mailbox_t mailbox, int flags) ...@@ -253,7 +268,9 @@ mbox_open (mailbox_t mailbox, int flags)
253 { 268 {
254 /* FIXME: for small mbox we should try to mmap (). */ 269 /* FIXME: for small mbox we should try to mmap (). */
255 270
256 status = (flags & MU_STREAM_CREAT) || (mailbox->flags & MU_STREAM_APPEND); 271 /* We do not try to mmap for CREAT or APPEND, it is not supported. */
272 status = (flags & MU_STREAM_CREAT)
273 || (mailbox->flags & MU_STREAM_APPEND);
257 if (status == 0) 274 if (status == 0)
258 status = mapfile_stream_create (&(mailbox->stream)); 275 status = mapfile_stream_create (&(mailbox->stream));
259 if (status != 0) 276 if (status != 0)
...@@ -359,14 +376,12 @@ mbox_is_updated (mailbox_t mailbox) ...@@ -359,14 +376,12 @@ mbox_is_updated (mailbox_t mailbox)
359 return (mud->size == size); 376 return (mud->size == size);
360 } 377 }
361 378
362 /* FIXME: the use of tmpfile() on some system can lead to race condition, We 379 /* Try to create an uniq file. */
363 should use a safer approach. */ 380 static int
364 static FILE *
365 mbox_tmpfile (mailbox_t mailbox, char **pbox) 381 mbox_tmpfile (mailbox_t mailbox, char **pbox)
366 { 382 {
367 const char *tmpdir; 383 const char *tmpdir;
368 int fd; 384 int fd;
369 FILE *fp;
370 const char *basename; 385 const char *basename;
371 mbox_data_t mud = mailbox->data; 386 mbox_data_t mud = mailbox->data;
372 387
...@@ -375,53 +390,53 @@ mbox_tmpfile (mailbox_t mailbox, char **pbox) ...@@ -375,53 +390,53 @@ mbox_tmpfile (mailbox_t mailbox, char **pbox)
375 # define P_tmpdir "/tmp" 390 # define P_tmpdir "/tmp"
376 #endif 391 #endif
377 392
378 tmpdir = getenv ("TEMPDIR") ? getenv ("TEMPDIR") : P_tmpdir; 393 /* FIXME: Use a macro for the separator to be portable. */
379 basename = strrchr (mud->name, '/'); 394 basename = strrchr (mud->name, '/');
380 if (basename) 395 if (basename)
381 basename++; 396 basename++;
382 else 397 else
383 basename = mud->name; 398 basename = mud->name;
384 *pbox = calloc (strlen (tmpdir) + strlen ("MBOX_") +
385 strlen (basename) + 2/* separator + null */, sizeof (char));
386 if (*pbox == NULL)
387 return NULL;
388 sprintf (*pbox, "%s/%s%s", tmpdir, "MBOX_", basename);
389 399
390 /* FIXME: I don't think this is the righ approach, creating an anonymous 400 tmpdir = getenv ("TMPDIR") ? getenv ("TMPDIR") : P_tmpdir;
391 file would be better ? no trace left behind. */ 401 /* (separator + null) == 2 + XXXXXX == 6 + ... */
402 *pbox = calloc (strlen (tmpdir) + /* '/' */ 1 + /*strlen ("MU_")*/ 3 +
403 strlen (basename) + /*strlen ("_XXXXXX")*/ 7 + /*null*/1,
404 sizeof (**pbox));
405 if (*pbox == NULL)
406 return -1;
407 sprintf (*pbox, "%s/MU_%s_XXXXXX", tmpdir, basename);
408 #ifdef HAVE_MKSTEMP
409 fd = mkstemp (*pbox);
410 #else
392 /* Create the file. It must not exist. If it does exist, fail. */ 411 /* Create the file. It must not exist. If it does exist, fail. */
393 fd = open (*pbox, O_RDWR|O_CREAT|O_EXCL, 0600); 412 if (mktemp (*pbox))
394 if (fd < 0)
395 { 413 {
396 fprintf (stderr,"Can't create %s\n", *pbox); 414 fd = open (*pbox, O_RDWR|O_CREAT|O_EXCL, 0600);
397 fprintf (stderr,"delete file <%s>, Please\n", *pbox);
398 fprintf (stderr, "It was likely due to an error when expunging\n");
399 return NULL;
400 } 415 }
401 fp = fdopen (fd, "w+"); 416 else
402 if (fp == 0)
403 { 417 {
404 close(fd);
405 free (*pbox); 418 free (*pbox);
406 *pbox = NULL; 419 fd = -1;
407 } 420 }
408 421 #endif
409 /* Really I should just remove the file here. */ 422 return fd;
410 /* remove(*pbox); */
411 return fp;
412 } 423 }
413 424
414 /* For the expunge bits we took a very cautionnary approach, meaning 425 /* For the expunge bits we took a very cautionnary approach, meaning
415 we create temporary file in the tmpdir copy all the file not mark deleted, 426 we create a temporary mailbox in the tmpdir copy all the message not mark
427 deleted(Actually we copy all the message that may have been modified, we
428 do not have(yet) an api call to tell whether a message was modified)
416 and skip the deleted ones, truncate the real mailbox to the desired size 429 and skip the deleted ones, truncate the real mailbox to the desired size
417 and overwrite with the tmp mailbox. The approach to do everyting 430 and overwrite with the tmp mailbox. The approach to do everyting
418 in core is tempting but require to much memory, it is not rare now 431 in core is tempting but require
419 a day to have 30 Megs mailbox, also there is danger for filesystems 432 - to much memory, it is not rare now a day to have 30 Megs mailbox,
420 with quotas, or some program may not respect the advisory lock and 433 - also there is danger for filesystems with quotas,
421 decide to append a new message while your expunging etc ... 434 - if we run out of disk space everything is lost.
435 - or some program may not respect the advisory lock and decide to append
436 a new message while your expunging etc ...
422 The real downside to the approach we take is that when things go wrong 437 The real downside to the approach we take is that when things go wrong
423 the temporary file bay be left in /tmp, which is not all that bad 438 the temporary file may be left in /tmp, which is not all that bad
424 because at least have something to recuparate when failure. */ 439 because at least, we have something to recuparate when failure. */
425 static int 440 static int
426 mbox_expunge (mailbox_t mailbox) 441 mbox_expunge (mailbox_t mailbox)
427 { 442 {
...@@ -429,13 +444,12 @@ mbox_expunge (mailbox_t mailbox) ...@@ -429,13 +444,12 @@ mbox_expunge (mailbox_t mailbox)
429 mbox_message_t mum; 444 mbox_message_t mum;
430 int status = 0; 445 int status = 0;
431 sigset_t signalset; 446 sigset_t signalset;
432 FILE *tempfile; 447 int tempfile;
433 size_t nread; 448 size_t i, j, dirty;
434 size_t i, j, dirty, first;
435 off_t marker = 0; 449 off_t marker = 0;
436 off_t total = 0; 450 off_t total = 0;
437 char buffer [BUFSIZ]; 451 char *tmpmboxname = NULL;
438 char *tmpmbox = NULL; 452 mailbox_t tmpmailbox = NULL;
439 #ifdef WITH_PTHREAD 453 #ifdef WITH_PTHREAD
440 int state; 454 int state;
441 #endif 455 #endif
...@@ -449,57 +463,76 @@ mbox_expunge (mailbox_t mailbox) ...@@ -449,57 +463,76 @@ mbox_expunge (mailbox_t mailbox)
449 if (mud->messages_count == 0) 463 if (mud->messages_count == 0)
450 return 0; 464 return 0;
451 465
452 /* Do we have a consistent view of the mailbox. */ 466 /* Mark dirty the first mum(concrete message) with a message pointer. */
453 if (! mbox_is_updated (mailbox)) 467 /* FIXME: This is not right, the way to really know if a message is modified
454 { 468 is by changing the API, we should have an message_is_modified (). */
455 fprintf (stderr, "mailbox is not updated, try again.\n");
456 return EAGAIN;
457 }
458
459 monitor_wrlock (mailbox->monitor);
460
461 /* Mark dirty the first mail with an attribute change. */
462 for (dirty = 0; dirty < mud->messages_count; dirty++) 469 for (dirty = 0; dirty < mud->messages_count; dirty++)
463 { 470 {
464 mum = mud->umessages[dirty]; 471 mum = mud->umessages[dirty];
472 #if 0
473 /* No, cheking if the attribute was changed is not enough, for example
474 They may have modified a header, say adding the X-UIDL field. Those
475 changes are not save yet but still in memory part of the header blurb.
476 So unless we have a message_is_modified() call we should assume that
477 the message was modified. */
465 if (mum->new_flags && 478 if (mum->new_flags &&
466 ! ATTRIBUTE_IS_EQUAL (mum->old_flags, mum->new_flags)) 479 ! ATTRIBUTE_IS_EQUAL (mum->old_flags, mum->new_flags))
467 break; 480 break;
481 #else
482 /* Message may have been tampered, break here. */
483 if (mum->message && message_is_modified (mum->message))
484 break;
485 #endif
468 } 486 }
469 487
470 /* Did something change ? */ 488 /* Did something change ? */
471 if (dirty == mud->messages_count) 489 if (dirty == mud->messages_count)
472 { 490 return 0; /* Nothing change, bail out. */
473 monitor_unlock (mailbox->monitor);
474 return 0; /* Nothing change, bail out. */
475 }
476 491
477 /* This is redundant, we go to the loop again. But it's more secure here 492 /* This is redundant, we go to the loop again. But it's more secure here
478 since we don't want to be disturb when expunging. */ 493 since we don't want to be disturb when expunging. Destroy all the
494 messages mark for deletion. */
479 for (j = 0; j < mud->messages_count; j++) 495 for (j = 0; j < mud->messages_count; j++)
480 { 496 {
481 mum = mud->umessages[j]; 497 mum = mud->umessages[j];
482 if (mum && mum->new_flags && ATTRIBUTE_IS_DELETED (mum->new_flags)) 498 if (mum && mum->message && mum->new_flags &&
499 ATTRIBUTE_IS_DELETED (mum->new_flags))
483 message_destroy (&(mum->message), mum); 500 message_destroy (&(mum->message), mum);
484 } 501 }
485 502
486 /* Create a tempory file. */ 503 /* Create a temporary file. */
487 tempfile = mbox_tmpfile (mailbox, &tmpmbox); 504 tempfile = mbox_tmpfile (mailbox, &tmpmboxname);
488 if (tempfile == NULL) 505 if (tempfile == -1)
489 { 506 {
490 free (tmpmbox); 507 free (tmpmboxname);
491 monitor_unlock (mailbox->monitor);
492 fprintf (stderr, "Failed to create temporary file when expunging.\n"); 508 fprintf (stderr, "Failed to create temporary file when expunging.\n");
493 return errno; 509 return errno;
494 } 510 }
511 else
512 {
513 /* strlen ("mbox:") == 5 + strlen (tmpmboxname) + 1 */
514 char *m = alloca (5 + strlen (tmpmboxname) + 1);
515 sprintf (m, "mbox:%s", tmpmboxname);
516 /* Must put create if not the open will try to mmap() the file. */
517 if ((status = mailbox_create (&tmpmailbox, m)) != 0
518 || (status
519 = mailbox_open (tmpmailbox, MU_STREAM_CREAT | MU_STREAM_RDWR)) != 0)
520 {
521 close (tempfile);
522 remove (tmpmboxname);
523 free (tmpmboxname);
524 return status;
525 }
526 close (tempfile);
527 }
495 528
496 /* Get the File lock. */ 529 /* Get the File lock. */
497 if (locker_lock (mailbox->locker, MU_LOCKER_WRLOCK) < 0) 530 if (locker_lock (mailbox->locker, MU_LOCKER_WRLOCK) < 0)
498 { 531 {
499 fclose (tempfile); 532 mailbox_close (tmpmailbox);
500 remove (tmpmbox); 533 mailbox_destroy (&tmpmailbox);
501 free (tmpmbox); 534 remove (tmpmboxname);
502 monitor_unlock (mailbox->monitor); 535 free (tmpmboxname);
503 fprintf (stderr, "Failed to grab the lock\n"); 536 fprintf (stderr, "Failed to grab the lock\n");
504 return ENOLCK; 537 return ENOLCK;
505 } 538 }
...@@ -517,10 +550,11 @@ mbox_expunge (mailbox_t mailbox) ...@@ -517,10 +550,11 @@ mbox_expunge (mailbox_t mailbox)
517 sigprocmask (SIG_BLOCK, &signalset, 0); 550 sigprocmask (SIG_BLOCK, &signalset, 0);
518 551
519 /* Set the marker position. */ 552 /* Set the marker position. */
520 total = marker = mud->umessages[dirty]->header_from; 553 marker = mud->umessages[dirty]->header_from;
554 total = 0;
521 555
522 /* Copy to tempfile emails not mark deleted. */ 556 /* Copy to tempfile emails not mark deleted. */
523 for (first = 1, i = dirty; i < mud->messages_count; i++) 557 for (i = dirty; i < mud->messages_count; i++)
524 { 558 {
525 mum = mud->umessages[i]; 559 mum = mud->umessages[i];
526 560
...@@ -528,78 +562,31 @@ mbox_expunge (mailbox_t mailbox) ...@@ -528,78 +562,31 @@ mbox_expunge (mailbox_t mailbox)
528 if (ATTRIBUTE_IS_DELETED (mum->new_flags)) 562 if (ATTRIBUTE_IS_DELETED (mum->new_flags))
529 continue; 563 continue;
530 564
531 /* Add a NL separator between messages. */ 565 if (mum->message)
532 if (first)
533 first = 0;
534 else
535 { 566 {
536 fputc ('\n', tempfile); 567 status = mbox_append_message0 (tmpmailbox, mum->message, &total, 1);
537 total++; 568 if (status != 0)
538 }
539
540 /* Begining of header copy. */
541 {
542 off_t current;
543 /* This is done in two parts first we check if the attribute changed,
544 if yes then we have to update the "Status:" field. Unfortunately
545 there is no requirement for the "Status:" to be the last field, so
546 we take the long approach; Copy up to the Status, update the
547 Status and copy the rest. */
548
549 /* Attribute change ? */
550 if (mum->new_flags
551 &&! ATTRIBUTE_IS_EQUAL (mum->old_flags, mum->new_flags)
552 && mum->header_status > mum->header_from)
553 {
554 size_t n = 0;
555 off_t offset = mum->header_from;
556 size_t len = mum->header_status - mum->header_from;
557 current = mum->header_status_end;
558 while (len > 0)
559 {
560 nread = (len < sizeof (buffer)) ? len : sizeof (buffer);
561 if ((status = stream_read (mailbox->stream, buffer,
562 nread, offset, &n) != 0)
563 || fwrite(buffer, sizeof(*buffer), n, tempfile) != n)
564 {
565 if (status == 0)
566 status = errno;
567 fprintf (stderr, "Error expunge:%d: (%s)\n", __LINE__,
568 strerror (status));
569 goto bailout0;
570 }
571 len -= n;
572 total += n;
573 offset += n;
574 }
575
576 /* Put the new attributes. */
577 { 569 {
578 char abuf[64]; 570 fprintf (stderr, "Error expunge:%d: %s", __LINE__,
579 size_t na = 0; 571 strerror (status));
580 abuf[0] = '\0'; 572 goto bailout0;
581 flags_to_string (mum->new_flags, abuf, sizeof(abuf), &na);
582 fputs (abuf, tempfile);
583 total += na;
584 } 573 }
585 } 574 }
586 else /* Attribute did not change. */ 575 else
587 current = mum->header_from;
588
589 /* Copy the rest of header without changes. */
590 { 576 {
591 size_t n = 0; 577 /* Nothing changed copy the message straight. */
592 off_t offset = current; 578 char buffer [1024];
593 size_t len = mum->body - current; 579 size_t n;
580 off_t offset = mum->header_from;
581 size_t len = mum->body_end - mum->header_from;
594 while (len > 0) 582 while (len > 0)
595 { 583 {
596 nread = (len < sizeof (buffer)) ? len : sizeof (buffer); 584 n = (len < sizeof (buffer)) ? len : sizeof (buffer);
597 if ((status = stream_read (mailbox->stream, buffer, nread, 585 if ((status = stream_read (mailbox->stream, buffer, n, offset,
598 offset, &n) != 0) 586 &n) != 0)
599 || fwrite(buffer, sizeof(*buffer), n, tempfile) != n) 587 || (status = stream_write (tmpmailbox->stream, buffer, n,
588 total, &n) != 0))
600 { 589 {
601 if (status == 0)
602 status = errno;
603 fprintf (stderr, "Error expunge:%d: %s", __LINE__, 590 fprintf (stderr, "Error expunge:%d: %s", __LINE__,
604 strerror (status)); 591 strerror (status));
605 goto bailout0; 592 goto bailout0;
...@@ -608,110 +595,102 @@ mbox_expunge (mailbox_t mailbox) ...@@ -608,110 +595,102 @@ mbox_expunge (mailbox_t mailbox)
608 total += n; 595 total += n;
609 offset += n; 596 offset += n;
610 } 597 }
598 /* Add the newline separator. */
599 status = stream_write (tmpmailbox->stream, "\n", 1, total, &n);
600 if (status != 0)
601 {
602 fprintf (stderr, "Error expunge:%d: %s", __LINE__,
603 strerror (status));
604 goto bailout0;
605 }
606 total++;
611 } 607 }
612 } /* End of header copy. */
613
614 /* Copy the body. */
615 {
616 size_t n = 0;
617 off_t offset = mum->body;
618 size_t len = mum->body_end - mum->body;
619 while (len > 0)
620 {
621 nread = (len < sizeof (buffer)) ? len : sizeof (buffer);
622 if ((status = stream_read (mailbox->stream, buffer, nread,
623 offset, &n) != 0)
624 || fwrite(buffer, sizeof(*buffer), n, tempfile) != n)
625 {
626 if (status == 0)
627 status = errno;
628 fprintf (stderr, "Error expunge:%d: %s", __LINE__,
629 strerror (status));
630 goto bailout0;
631 }
632 len -= n;
633 total += n;
634 offset += n;
635 }
636 } /* End of body copy. */
637 } /* for (;;) */ 608 } /* for (;;) */
638 609
639 /* Caution: before ftruncate()ing the file see if we've receiving new mail 610 /* Caution: before ftruncate()ing the file see
640 Some program may not respect the lock, or the lock was held for too 611 - if we've receive new mails.
641 long. */ 612 Some programs may not respect the lock, or the lock was held for too
613 long.
614 - The mailbox may not have been properly updated before expunging. */
642 { 615 {
643 off_t size = 0; 616 off_t size = 0;
644 if (stream_size (mailbox->stream, &size) == 0) 617 if (stream_size (mailbox->stream, &size) == 0)
645 { 618 {
619 off_t len = size - mud->size;
620 off_t offset = mud->size;
621 char buffer [1024];
646 size_t n = 0; 622 size_t n = 0;
647 off_t offset = size; 623 if (len > 0 )
648 size_t len = size - mud->size;
649 while (len > 0)
650 { 624 {
651 nread = (len < sizeof (buffer)) ? len : sizeof (buffer); 625 while ((status = stream_read (mailbox->stream, buffer,
652 if ((status = stream_read (mailbox->stream, buffer, nread, 626 sizeof (buffer), offset, &n)) == 0
653 offset, &n) != 0) 627 && n > 0)
654 || fwrite(buffer, sizeof(*buffer), n, tempfile) != n)
655 { 628 {
656 if (status == 0) 629 status = stream_write (tmpmailbox->stream, buffer, n,
657 status = errno; 630 total, &n);
658 fprintf (stderr, "Error expunge:%d: %s", __LINE__, 631 if (status != 0)
659 strerror (status)); 632 {
660 goto bailout0; 633 fprintf (stderr, "Error expunge:%d: %s", __LINE__,
634 strerror (status));
635 goto bailout0;
636 }
637 total += n;
638 offset += n;
661 } 639 }
662 len -= n; 640 }
663 total += n; 641 else if (len < 0)
664 offset += n; 642 {
643 /* Corrupted mailbox. */
644 fprintf (stderr, "Error expunge:%d: %s", __LINE__,
645 strerror (status));
646 goto bailout0;
665 } 647 }
666 } 648 }
667 } /* End of precaution. */ 649 } /* End of precaution. */
668 650
669 /* Seek and rewrite it. */ 651 /* Seek and rewrite it. */
670 rewind (tempfile);
671 if (total > 0) 652 if (total > 0)
672 { 653 {
654 char buffer [1024];
673 size_t n = 0; 655 size_t n = 0;
656 off_t off = 0;
674 off_t offset = marker; 657 off_t offset = marker;
675 while ((nread = fread (buffer, sizeof (*buffer), 658 while ((status = stream_read (tmpmailbox->stream, buffer,
676 sizeof (buffer), tempfile)) != 0) 659 sizeof (buffer), off, &n)) == 0
660 && n > 0)
677 { 661 {
678 while (nread) 662 status = stream_write (mailbox->stream, buffer, n, offset, &n);
663 if (status != 0)
679 { 664 {
680 status = stream_write (mailbox->stream, buffer, nread, offset, &n); 665 fprintf (stderr, "Error expunge:%d: %s\n", __LINE__,
681 if (status != 0) 666 strerror (status));
682 { 667 goto bailout;
683 fprintf (stderr, "Error expunge:%d: %s\n", __LINE__,
684 strerror (status));
685 goto bailout;
686 }
687 nread -= n;
688 offset += n;
689 } 668 }
669 off += n;
670 offset += n;
690 } 671 }
691 } 672 }
692 673
693 /* How can I handle error here ?? */ 674 /* Flush/truncation. Need to flush before truncate. */
694 clearerr (tempfile);
695
696 /* Flush/truncation. */
697 stream_flush (mailbox->stream); 675 stream_flush (mailbox->stream);
698 status = stream_truncate (mailbox->stream, total); 676 status = stream_truncate (mailbox->stream, total + marker);
699 if (status != 0) 677 if (status != 0)
700 { 678 {
701 fprintf (stderr, "Error expunging:%d: %s", __LINE__, strerror (status)); 679 fprintf (stderr, "Error expunging:%d: %s\n", __LINE__, strerror (status));
702 goto bailout; 680 goto bailout;
703 } 681 }
704 682
705 bailout0:
706 /* Don't remove the tmp mbox in case of errors, when writing back. */ 683 /* Don't remove the tmp mbox in case of errors, when writing back. */
707 remove (tmpmbox); 684 bailout0:
685 remove (tmpmboxname);
708 686
709 bailout: 687 bailout:
710 688
711 free (tmpmbox); 689 free (tmpmboxname);
712 /* Release the File lock. */ 690 /* Release the File lock. */
713 locker_unlock (mailbox->locker); 691 locker_unlock (mailbox->locker);
714 fclose (tempfile); 692 mailbox_close (tmpmailbox);
693 mailbox_destroy (&tmpmailbox);
715 #ifdef WITH_PTHREAD 694 #ifdef WITH_PTHREAD
716 pthread_setcancelstate (state, &state); 695 pthread_setcancelstate (state, &state);
717 #endif 696 #endif
...@@ -721,6 +700,7 @@ mbox_expunge (mailbox_t mailbox) ...@@ -721,6 +700,7 @@ mbox_expunge (mailbox_t mailbox)
721 if (status == 0) 700 if (status == 0)
722 { 701 {
723 size_t dlast; 702 size_t dlast;
703 monitor_wrlock (mailbox->monitor);
724 for (j = dirty, dlast = mud->messages_count - 1; 704 for (j = dirty, dlast = mud->messages_count - 1;
725 j <= dlast; j++) 705 j <= dlast; j++)
726 { 706 {
...@@ -758,13 +738,11 @@ mbox_expunge (mailbox_t mailbox) ...@@ -758,13 +738,11 @@ mbox_expunge (mailbox_t mailbox)
758 mum->body = mum->body_end = 0; 738 mum->body = mum->body_end = 0;
759 mum->header_lines = mum->body_lines = 0; 739 mum->header_lines = mum->body_lines = 0;
760 } 740 }
741 monitor_unlock (mailbox->monitor);
761 /* This is should reset the messages_count, the last argument 0 means 742 /* This is should reset the messages_count, the last argument 0 means
762 not to send event notification. */ 743 not to send event notification. */
763 monitor_unlock (mailbox->monitor);
764 mbox_scan0 (mailbox, dirty, NULL, 0); 744 mbox_scan0 (mailbox, dirty, NULL, 0);
765 } 745 }
766 else
767 monitor_unlock (mailbox->monitor);
768 return status; 746 return status;
769 } 747 }
770 748
...@@ -834,8 +812,22 @@ mbox_unset_attr_flags (attribute_t attr, int flags) ...@@ -834,8 +812,22 @@ mbox_unset_attr_flags (attribute_t attr, int flags)
834 } 812 }
835 813
836 static int 814 static int
837 mbox_readstream (stream_t is, char *buffer, size_t buflen, 815 mbox_body_readline (stream_t is, char *buffer, size_t buflen,
838 off_t off, size_t *pnread) 816 off_t off, size_t *pnread)
817 {
818 return mbox_body_readstream (is, buffer, buflen, off, pnread, 1);
819 }
820
821 static int
822 mbox_body_read (stream_t is, char *buffer, size_t buflen,
823 off_t off, size_t *pnread)
824 {
825 return mbox_body_readstream (is, buffer, buflen, off, pnread, 0);
826 }
827
828 static int
829 mbox_body_readstream (stream_t is, char *buffer, size_t buflen,
830 off_t off, size_t *pnread, int isreadline)
839 { 831 {
840 body_t body = stream_get_owner (is); 832 body_t body = stream_get_owner (is);
841 message_t msg = body_get_owner (body); 833 message_t msg = body_get_owner (body);
...@@ -866,7 +858,9 @@ mbox_readstream (stream_t is, char *buffer, size_t buflen, ...@@ -866,7 +858,9 @@ mbox_readstream (stream_t is, char *buffer, size_t buflen,
866 { 858 {
867 nread = ((size_t)ln < buflen) ? ln : buflen; 859 nread = ((size_t)ln < buflen) ? ln : buflen;
868 /* Position the file pointer and the buffer. */ 860 /* Position the file pointer and the buffer. */
869 status = stream_read (mum->stream, buffer, nread, mum->body + off, &n); 861 status = (isreadline) ?
862 stream_readline (mum->stream, buffer, nread, mum->body + off, &n) :
863 stream_read (mum->stream, buffer, nread, mum->body + off, &n);
870 } 864 }
871 } 865 }
872 monitor_unlock (mum->mud->mailbox->monitor); 866 monitor_unlock (mum->mud->mailbox->monitor);
...@@ -880,11 +874,17 @@ mbox_readstream (stream_t is, char *buffer, size_t buflen, ...@@ -880,11 +874,17 @@ mbox_readstream (stream_t is, char *buffer, size_t buflen,
880 } 874 }
881 875
882 static int 876 static int
883 mbox_get_header_read (stream_t is, char *buffer, size_t len, 877 mbox_header_fill (header_t header, char *buffer, size_t len,
884 off_t off, size_t *pnread) 878 off_t off, size_t *pnread)
885 { 879 {
886 header_t header = stream_get_owner (is);
887 message_t msg = header_get_owner (header); 880 message_t msg = header_get_owner (header);
881 return mbox_get_header_readstream (msg, buffer, len, off, pnread, 0);
882 }
883
884 static int
885 mbox_get_header_readstream (message_t msg, char *buffer, size_t len,
886 off_t off, size_t *pnread, int isreadline)
887 {
888 mbox_message_t mum = message_get_owner (msg); 888 mbox_message_t mum = message_get_owner (msg);
889 size_t nread = 0; 889 size_t nread = 0;
890 int status = 0; 890 int status = 0;
...@@ -904,8 +904,11 @@ mbox_get_header_read (stream_t is, char *buffer, size_t len, ...@@ -904,8 +904,11 @@ mbox_get_header_read (stream_t is, char *buffer, size_t len,
904 { 904 {
905 nread = ((size_t)ln < len) ? ln : len; 905 nread = ((size_t)ln < len) ? ln : len;
906 /* Position the file pointer and the buffer. */ 906 /* Position the file pointer and the buffer. */
907 status = stream_read (mum->stream, buffer, nread, 907 status = (isreadline) ?
908 mum->header_from_end + off, &nread); 908 stream_readline (mum->stream, buffer, nread,
909 mum->header_from_end + off, &nread) :
910 stream_read (mum->stream, buffer, nread,
911 mum->header_from_end + off, &nread);
909 } 912 }
910 monitor_unlock (mum->mud->mailbox->monitor); 913 monitor_unlock (mum->mud->mailbox->monitor);
911 #ifdef WITH_PTHREAD 914 #ifdef WITH_PTHREAD
...@@ -966,13 +969,14 @@ mbox_body_lines (body_t body, size_t *plines) ...@@ -966,13 +969,14 @@ mbox_body_lines (body_t body, size_t *plines)
966 969
967 static int 970 static int
968 mbox_envelope_date (envelope_t envelope, char *buf, size_t len, 971 mbox_envelope_date (envelope_t envelope, char *buf, size_t len,
969 size_t *pnwrite) 972 size_t *pnwrite)
970 { 973 {
971 message_t msg = envelope_get_owner (envelope); 974 message_t msg = envelope_get_owner (envelope);
972 mbox_message_t mum = message_get_owner (msg); 975 mbox_message_t mum = message_get_owner (msg);
973 size_t n = 0; 976 size_t n = 0;
974 int status; 977 int status;
975 char buffer[512]; 978 char buffer[512];
979 char *s;
976 980
977 if (mum == NULL) 981 if (mum == NULL)
978 return EINVAL; 982 return EINVAL;
...@@ -983,30 +987,27 @@ mbox_envelope_date (envelope_t envelope, char *buf, size_t len, ...@@ -983,30 +987,27 @@ mbox_envelope_date (envelope_t envelope, char *buf, size_t len,
983 { 987 {
984 if (pnwrite) 988 if (pnwrite)
985 *pnwrite = 0; 989 *pnwrite = 0;
986 if (buf)
987 *buf = '\0';
988 return status; 990 return status;
989 } 991 }
990 992
991 if (n > 5) 993 /* Format: "From [sender] [date]" */
994 /* strlen ("From ") == 5 */
995 if (n > 5 && (s = strchr (buffer + 5, ' ')) != NULL)
992 { 996 {
993 char *s = strchr (buffer + 5, ' '); 997 if (buf && len > 0)
994 if (s)
995 { 998 {
996 if (buf && len > 0) 999 len--; /* Leave space for the null. */
997 { 1000 strncpy (buf, s + 1, len)[len] = '\0';
998 strncpy (buf, s + 1, len); 1001 len = strlen (buf);
999 buffer [len - 1] = '\0';
1000 }
1001 if (pnwrite)
1002 *pnwrite = strlen (s + 1);
1003 return 0;
1004 } 1002 }
1003 else
1004 len = strlen (s + 1);
1005 } 1005 }
1006 else
1007 len = 0;
1008
1006 if (pnwrite) 1009 if (pnwrite)
1007 *pnwrite = 0; 1010 *pnwrite = len;
1008 if (buf)
1009 *buf = '\0';
1010 return 0; 1011 return 0;
1011 } 1012 }
1012 1013
...@@ -1019,6 +1020,7 @@ mbox_envelope_sender (envelope_t envelope, char *buf, size_t len, ...@@ -1019,6 +1020,7 @@ mbox_envelope_sender (envelope_t envelope, char *buf, size_t len,
1019 size_t n = 0; 1020 size_t n = 0;
1020 int status; 1021 int status;
1021 char buffer[512]; 1022 char buffer[512];
1023 char *s;
1022 1024
1023 if (mum == NULL) 1025 if (mum == NULL)
1024 return EINVAL; 1026 return EINVAL;
...@@ -1029,31 +1031,29 @@ mbox_envelope_sender (envelope_t envelope, char *buf, size_t len, ...@@ -1029,31 +1031,29 @@ mbox_envelope_sender (envelope_t envelope, char *buf, size_t len,
1029 { 1031 {
1030 if (pnwrite) 1032 if (pnwrite)
1031 *pnwrite = 0; 1033 *pnwrite = 0;
1032 if (buf)
1033 *buf = '\0';
1034 return status; 1034 return status;
1035 } 1035 }
1036 1036
1037 if (n > 5) 1037 /* Format: "From [sender] [date]" */
1038 /* strlen ("From ") == 5 */
1039 if (n > 5 && (s = strchr (buffer + 5, ' ')) != NULL)
1038 { 1040 {
1039 char *s = strchr (buffer + 5, ' '); 1041 /* Put a NULL to isolate the sender string, make a C string. */
1040 if (s) 1042 *s = '\0';
1043 if (buf && len > 0)
1041 { 1044 {
1042 *s = '\0'; 1045 len--; /* leave space for the null */
1043 if (buf && len > 0) 1046 strncpy (buf, buffer + 5, len)[len] = '\0';
1044 { 1047 len = strlen (buf);
1045 strncpy (buf, buffer + 5, len);
1046 buffer [len - 1] = '\0';
1047 }
1048 if (pnwrite)
1049 *pnwrite = strlen (buffer + 5);
1050 return 0;
1051 } 1048 }
1049 else
1050 len = strlen (buffer + 5);
1052 } 1051 }
1052 else
1053 len = 0;
1054
1053 if (pnwrite) 1055 if (pnwrite)
1054 *pnwrite = 0; 1056 *pnwrite = len;
1055 if (buf)
1056 *buf = '\0';
1057 return 0; 1057 return 0;
1058 } 1058 }
1059 1059
...@@ -1105,17 +1105,15 @@ mbox_get_message (mailbox_t mailbox, size_t msgno, message_t *pmsg) ...@@ -1105,17 +1105,15 @@ mbox_get_message (mailbox_t mailbox, size_t msgno, message_t *pmsg)
1105 { 1105 {
1106 header_t header = NULL; 1106 header_t header = NULL;
1107 stream_t stream = NULL; 1107 stream_t stream = NULL;
1108 if ((status = header_create (&header, NULL, 0, msg)) != 0 1108 status = header_create (&header, NULL, 0, msg);
1109 || (status = stream_create (&stream, mailbox->flags, header)) != 0) 1109 if (status != 0)
1110 { 1110 {
1111 stream_destroy (&stream, header); 1111 //stream_destroy (&stream, header);
1112 header_destroy (&header, msg); 1112 header_destroy (&header, msg);
1113 message_destroy (&msg, mum); 1113 message_destroy (&msg, mum);
1114 return status; 1114 return status;
1115 } 1115 }
1116 stream_set_read (stream, mbox_get_header_read, header); 1116 header_set_fill (header, mbox_header_fill, msg);
1117 stream_set_fd (stream, mbox_get_hdr_fd, header);
1118 header_set_stream (header, stream, msg);
1119 header_set_size (header, mbox_header_size, msg); 1117 header_set_size (header, mbox_header_size, msg);
1120 header_set_lines (header, mbox_header_lines, msg); 1118 header_set_lines (header, mbox_header_lines, msg);
1121 message_set_header (msg, header, mum); 1119 message_set_header (msg, header, mum);
...@@ -1149,7 +1147,8 @@ mbox_get_message (mailbox_t mailbox, size_t msgno, message_t *pmsg) ...@@ -1149,7 +1147,8 @@ mbox_get_message (mailbox_t mailbox, size_t msgno, message_t *pmsg)
1149 message_destroy (&msg, mum); 1147 message_destroy (&msg, mum);
1150 return status; 1148 return status;
1151 } 1149 }
1152 stream_set_read (stream, mbox_readstream, body); 1150 stream_set_read (stream, mbox_body_read, body);
1151 stream_set_readline (stream, mbox_body_readline, body);
1153 stream_set_fd (stream, mbox_get_body_fd, body); 1152 stream_set_fd (stream, mbox_get_body_fd, body);
1154 body_set_stream (body, stream, msg); 1153 body_set_stream (body, stream, msg);
1155 body_set_size (body, mbox_body_size, msg); 1154 body_set_size (body, mbox_body_size, msg);
...@@ -1179,7 +1178,6 @@ mbox_get_message (mailbox_t mailbox, size_t msgno, message_t *pmsg) ...@@ -1179,7 +1178,6 @@ mbox_get_message (mailbox_t mailbox, size_t msgno, message_t *pmsg)
1179 return 0; 1178 return 0;
1180 } 1179 }
1181 1180
1182 /* FIXME: We have to generate a Message-ID: if the message have none. */
1183 static int 1181 static int
1184 mbox_append_message (mailbox_t mailbox, message_t msg) 1182 mbox_append_message (mailbox_t mailbox, message_t msg)
1185 { 1183 {
...@@ -1190,163 +1188,299 @@ mbox_append_message (mailbox_t mailbox, message_t msg) ...@@ -1190,163 +1188,299 @@ mbox_append_message (mailbox_t mailbox, message_t msg)
1190 MAILBOX_DEBUG1 (mailbox, MU_DEBUG_TRACE, "mbox_append_message (%s)\n", 1188 MAILBOX_DEBUG1 (mailbox, MU_DEBUG_TRACE, "mbox_append_message (%s)\n",
1191 mud->name); 1189 mud->name);
1192 1190
1193 monitor_wrlock (mailbox->monitor); 1191 switch (mud->state)
1194 #ifdef WITH_PTHREAD 1192 {
1195 /* write()/read() are cancellation points. Since we're doing a potentially 1193 case MBOX_NO_STATE:
1196 long operation. Lets make sure we clean the state. */ 1194 locker_lock (mailbox->locker, MU_LOCKER_WRLOCK);
1197 pthread_cleanup_push (mbox_cleanup, (void *)mailbox);
1198 #endif
1199 locker_lock (mailbox->locker, MU_LOCKER_WRLOCK);
1200 {
1201 off_t size;
1202 int status;
1203 size_t n = 0;
1204 char nl = '\n';
1205 1195
1206 /* Move to the end of the file, not necesary if _APPEND mode. */ 1196 default:
1207 status = stream_size (mailbox->stream, &size);
1208 if (status != 0)
1209 { 1197 {
1210 locker_unlock (mailbox->locker); 1198 off_t size;
1211 monitor_unlock (mailbox->monitor); 1199 int status;
1212 return status; 1200 /* Move to the end of the file, not necesary if _APPEND mode. */
1201 if ((status = stream_size (mailbox->stream, &size)) != 0
1202 || (status = mbox_append_message0 (mailbox, msg, &size, 0)) != 0)
1203 {
1204 if (status != EAGAIN)
1205 locker_unlock (mailbox->locker);
1206 return status;
1207 }
1213 } 1208 }
1209 }
1210 locker_unlock (mailbox->locker);
1211 return 0;
1212 }
1214 1213
1215 switch (mud->state) 1214 static int
1215 mbox_append_message0 (mailbox_t mailbox, message_t msg, off_t *psize,
1216 int is_expunging)
1217 {
1218 mbox_data_t mud = mailbox->data;
1219 int status = 0;
1220 size_t n = 0;
1221 char nl = '\n';
1222
1223 switch (mud->state)
1224 {
1225 case MBOX_NO_STATE:
1226 /* Allocate memory for the sender/date buffers. */
1227 mud->sender = calloc (128, sizeof (char));
1228 if (mud->sender == NULL)
1229 return ENOMEM;
1230 mud->date = calloc (128, sizeof (char));
1231 if (mud->date == NULL)
1232 {
1233 free (mud->sender);
1234 mud->sender = NULL;
1235 return ENOMEM;
1236 }
1237 mud->off = 0;
1238 mud->state = MBOX_STATE_APPEND_SENDER;
1239
1240 case MBOX_STATE_APPEND_SENDER:
1241 /* Generate the sender for the "From " separator. */
1216 { 1242 {
1217 case MBOX_NO_STATE: 1243 char *s;
1218 mud->sender = calloc (128, sizeof (char)); 1244 size_t len = 0;
1219 if (mud->sender == NULL) 1245 envelope_t envelope;
1246 message_get_envelope (msg, &envelope);
1247 status = envelope_sender (envelope, mud->sender, 128, &len);
1248 if (status != 0)
1220 { 1249 {
1221 locker_unlock (mailbox->locker); 1250 if (status != EAGAIN)
1222 monitor_unlock (mailbox->monitor); 1251 {
1223 return ENOMEM; 1252 free (mud->sender);
1253 free (mud->date);
1254 mud->date = mud->sender = NULL;
1255 mud->state = MBOX_NO_STATE;
1256 }
1257 return status;
1224 } 1258 }
1225 mud->date = calloc (128, sizeof (char)); 1259
1226 if (mud->date == NULL) 1260 /* Nuke trailing newline. */
1261 s = memchr (mud->sender, nl, len);
1262 if (s)
1263 *s = '\0';
1264 mud->state = MBOX_STATE_APPEND_DATE;
1265 }
1266
1267 case MBOX_STATE_APPEND_DATE:
1268 /* Generate a date for the "From " separator. */
1269 {
1270 char *s;
1271 size_t len = 0;
1272 envelope_t envelope;
1273 message_get_envelope (msg, &envelope);
1274 status = envelope_date (envelope, mud->date, 128, &len);
1275 if (status != 0)
1227 { 1276 {
1228 free (mud->sender); 1277 if (status != EAGAIN)
1229 mud->sender = NULL; 1278 {
1230 mud->state = MBOX_NO_STATE; 1279 free (mud->sender);
1231 locker_unlock (mailbox->locker); 1280 free (mud->date);
1232 monitor_unlock (mailbox->monitor); 1281 mud->date = mud->sender = NULL;
1233 return ENOMEM; 1282 mud->state = MBOX_NO_STATE;
1283 }
1284 return status;
1234 } 1285 }
1235 mud->off = 0;
1236 mud->state = MBOX_STATE_FROM;
1237 1286
1238 case MBOX_STATE_FROM: 1287 /* Nuke trailing newline. */
1239 /* Generate a "From " separator. */ 1288 s = memchr (mud->date, nl, len);
1240 { 1289 if (s)
1241 char *s; 1290 *s = '\0';
1242 size_t len = 0;
1243 envelope_t envelope;
1244 message_get_envelope (msg, &envelope);
1245 status = envelope_sender (envelope, mud->sender, 127, &len);
1246 if (status != 0)
1247 {
1248 if (status != EAGAIN)
1249 {
1250 free (mud->sender);
1251 free (mud->date);
1252 mud->date = mud->sender = NULL;
1253 mud->state = MBOX_NO_STATE;
1254 locker_unlock (mailbox->locker);
1255 }
1256 monitor_unlock (mailbox->monitor);
1257 return status;
1258 }
1259 /* Nuke trailing newline. */
1260 s = memchr (mud->sender, nl, len);
1261 if (s)
1262 *s = '\0';
1263 mud->state = MBOX_STATE_DATE;
1264 }
1265 1291
1266 case MBOX_STATE_DATE: 1292 /* Write the separator to the mailbox. */
1267 /* Generate a date for the "From " separator. */ 1293 status = stream_write (mailbox->stream, "From ", 5, *psize, &n);
1268 { 1294 if (status != 0)
1269 char *s; 1295 break;
1270 size_t len = 0; 1296 *psize += n;
1271 envelope_t envelope; 1297
1272 message_get_envelope (msg, &envelope); 1298 /* Write sender. */
1273 status = envelope_date (envelope, mud->date, 127, &len); 1299 status = stream_write (mailbox->stream, mud->sender,
1274 if (status != 0) 1300 strlen (mud->sender), *psize, &n);
1275 { 1301 if (status != 0)
1276 if (status != EAGAIN) 1302 break;
1277 { 1303 *psize += n;
1278 free (mud->sender); 1304
1279 free (mud->date); 1305 status = stream_write (mailbox->stream, " ", 1, *psize, &n);
1280 mud->date = mud->sender = NULL; 1306 if (status != 0)
1281 mud->state = MBOX_NO_STATE; 1307 break;
1282 locker_unlock (mailbox->locker); 1308 *psize += n;
1283 } 1309
1284 monitor_unlock (mailbox->monitor); 1310 /* Write date. */
1285 return status; 1311 status = stream_write (mailbox->stream, mud->date, strlen(mud->date),
1286 } 1312 *psize, &n);
1287 /* Nuke trailing newline. */ 1313 if (status != 0)
1288 s = memchr (mud->date, nl, len); 1314 break;
1289 if (s) 1315 *psize += n;
1290 *s = '\0'; 1316
1291 /* Write the separator to the mailbox. */ 1317 status = stream_write (mailbox->stream, &nl , 1, *psize, &n);
1292 stream_write (mailbox->stream, "From ", 5, size, &n); 1318 if (status != 0)
1293 size += n; 1319 break;
1294 stream_write (mailbox->stream, mud->sender, strlen (mud->sender), size, &n); 1320 *psize += n;
1295 size += n; 1321
1296 stream_write (mailbox->stream, " ", 1, size, &n); 1322 free (mud->sender);
1297 size += n; 1323 free (mud->date);
1298 stream_write (mailbox->stream, mud->date, strlen (mud->date), size, &n); 1324 mud->sender = mud->date = NULL;
1299 size += n; 1325 /* If we are not expunging get the message in one block via the stream
1300 stream_write (mailbox->stream, &nl , 1, size, &n); 1326 message instead of the header/body. This is good for example for
1301 size += n; 1327 POP where there is no separtation between header and body. */
1302 free (mud->sender); 1328 if (! is_expunging)
1303 free (mud->date); 1329 {
1304 mud->sender = mud->date = NULL; 1330 mud->state = MBOX_STATE_APPEND_MESSAGE;
1305 mud->state = MBOX_STATE_APPEND; 1331 break;
1306 } 1332 }
1333 mud->state = MBOX_STATE_APPEND_HEADER;
1334 }
1307 1335
1308 case MBOX_STATE_APPEND: 1336 case MBOX_STATE_APPEND_HEADER:
1309 /* Append the Message. */ 1337 /* Append the Header. */
1310 { 1338 {
1311 char buffer[BUFSIZ]; 1339 char buffer[1024];
1312 size_t nread = 0; 1340 size_t nread = 0;
1313 stream_t is; 1341 stream_t is;
1314 message_get_stream (msg, &is); 1342 header_t header;
1315 do 1343 message_get_header (msg, &header);
1316 { 1344 header_get_stream (header, &is);
1317 status = stream_read (is, buffer, sizeof (buffer), mud->off, 1345 do
1318 &nread); 1346 {
1319 if (status != 0) 1347 status = stream_readline (is, buffer, sizeof (buffer), mud->off,
1320 { 1348 &nread);
1321 if (status != EAGAIN) 1349 if (status != 0)
1322 { 1350 {
1323 mud->state = MBOX_NO_STATE; 1351 if (status != EAGAIN)
1324 locker_unlock (mailbox->locker); 1352 {
1325 } 1353 mud->state = MBOX_NO_STATE;
1326 stream_flush (mailbox->stream); 1354 mud->off = 0;
1327 monitor_unlock (mailbox->monitor); 1355 }
1328 return status; 1356 return status;
1329 } 1357 }
1330 stream_write (mailbox->stream, buffer, nread, size, &n); 1358 mud->off += nread;
1331 mud->off += nread; 1359 if (*buffer == '\n')
1332 size += n; 1360 break;
1333 } 1361
1334 while (nread > 0); 1362 /* FIXME: We have a problem here the header field may not fit the
1335 stream_write (mailbox->stream, &nl, 1, size, &n); 1363 buffer. */
1336 } 1364 /* We do not copy the Status since this is for the attribute. */
1365 if (strncasecmp (buffer, "Status", 6) == 0
1366 || strncasecmp (buffer, "X-Status", 8) == 0)
1367 continue;
1368
1369 status = stream_write (mailbox->stream, buffer, nread,
1370 *psize, &n);
1371 if (status != 0)
1372 break;
1373 *psize += n;
1374 }
1375 while (nread > 0);
1376 mud->off = 0;
1377 mud->state = MBOX_STATE_APPEND_ATTRIBUTE;
1378 }
1337 1379
1338 default: 1380 case MBOX_STATE_APPEND_ATTRIBUTE:
1339 break; 1381 /* Put the new attributes. */
1382 {
1383 char abuf[64];
1384 size_t na = 0;
1385 attribute_t attr = NULL;
1386 abuf[0] = '\0';
1387 message_get_attribute (msg, &attr);
1388 attribute_to_string (attr, abuf, sizeof(abuf), &na);
1389
1390 status = stream_write (mailbox->stream, abuf, na, *psize, &n);
1391 if (status != 0)
1392 break;
1393 *psize += n;
1394
1395 status = stream_write (mailbox->stream, &nl , 1, *psize, &n);
1396 if (status != 0)
1397 break;
1398 *psize += n;
1399 mud->state = MBOX_STATE_APPEND_BODY;
1340 } 1400 }
1341 } 1401
1342 stream_flush (mailbox->stream); 1402 case MBOX_STATE_APPEND_BODY:
1403 /* Append the Body. */
1404 {
1405 char buffer[1024];
1406 size_t nread = 0;
1407 stream_t is;
1408 body_t body;
1409 message_get_body (msg, &body);
1410 body_get_stream (body, &is);
1411 do
1412 {
1413 status = stream_read (is, buffer, sizeof (buffer), mud->off,
1414 &nread);
1415 if (status != 0)
1416 {
1417 if (status != EAGAIN)
1418 {
1419 mud->state = MBOX_NO_STATE;
1420 mud->off = 0;
1421 }
1422 return status;
1423 }
1424 mud->off += nread;
1425 status = stream_write (mailbox->stream, buffer, nread, *psize, &n);
1426 if (status != 0)
1427 break;
1428 *psize += n;
1429 }
1430 while (nread > 0);
1431 mud->off = 0;
1432 n = 0;
1433 stream_write (mailbox->stream, &nl, 1, *psize, &n);
1434 *psize += n;
1435 }
1436
1437 default:
1438 break;
1439 }
1440
1441 /* If not expunging we are taking the stream message. */
1442 if (!is_expunging)
1443 {
1444 switch (mud->state)
1445 {
1446 case MBOX_STATE_APPEND_MESSAGE:
1447 {
1448 /* Append the Message. */
1449 char buffer[1024];
1450 size_t nread = 0;
1451 stream_t is;
1452 message_get_stream (msg, &is);
1453 do
1454 {
1455 status = stream_read (is, buffer, sizeof (buffer), mud->off,
1456 &nread);
1457 if (status != 0)
1458 {
1459 if (status != EAGAIN)
1460 {
1461 mud->state = MBOX_NO_STATE;
1462 mud->off = 0;
1463 }
1464 stream_flush (mailbox->stream);
1465 return status;
1466 }
1467 stream_write (mailbox->stream, buffer, nread, *psize, &n);
1468 mud->off += nread;
1469 *psize += n;
1470 }
1471 while (nread > 0);
1472 n = 0;
1473 stream_write (mailbox->stream, &nl, 1, *psize, &n);
1474 *psize += n;
1475 }
1476
1477 default:
1478 break;
1479 }
1480 } /* is_expunging */
1343 mud->state = MBOX_NO_STATE; 1481 mud->state = MBOX_NO_STATE;
1344 locker_unlock (mailbox->locker); 1482 stream_flush (mailbox->stream);
1345 monitor_unlock (mailbox->monitor); 1483 return status;
1346 #ifdef WITH_PTHREAD
1347 pthread_cleanup_pop (0);
1348 #endif
1349 return 0;
1350 } 1484 }
1351 1485
1352 static int 1486 static int
......
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
28 #include <string.h> 28 #include <string.h>
29 #include <ctype.h> 29 #include <ctype.h>
30 30
31 #include "md5.h"
32
31 #include <misc.h> 33 #include <misc.h>
32 #include <message0.h> 34 #include <message0.h>
33 35
...@@ -155,6 +157,15 @@ message_get_owner (message_t msg) ...@@ -155,6 +157,15 @@ message_get_owner (message_t msg)
155 } 157 }
156 158
157 int 159 int
160 message_is_modified (message_t msg)
161 {
162 int mod = 0;
163 mod |= header_is_modified (msg->header);
164 mod |= attribute_is_modified (msg->attribute);
165 return mod;
166 }
167
168 int
158 message_set_mailbox (message_t msg, mailbox_t mailbox) 169 message_set_mailbox (message_t msg, mailbox_t mailbox)
159 { 170 {
160 if (msg == NULL) 171 if (msg == NULL)
...@@ -400,6 +411,7 @@ message_set_attribute (message_t msg, attribute_t attribute, void *owner) ...@@ -400,6 +411,7 @@ message_set_attribute (message_t msg, attribute_t attribute, void *owner)
400 return 0; 411 return 0;
401 } 412 }
402 413
414 /* FIXME: not nonblocking safe. */
403 int 415 int
404 message_get_uid (message_t msg, char *buffer, size_t buflen, size_t *pwriten) 416 message_get_uid (message_t msg, char *buffer, size_t buflen, size_t *pwriten)
405 { 417 {
...@@ -411,16 +423,19 @@ message_get_uid (message_t msg, char *buffer, size_t buflen, size_t *pwriten) ...@@ -411,16 +423,19 @@ message_get_uid (message_t msg, char *buffer, size_t buflen, size_t *pwriten)
411 return EINVAL; 423 return EINVAL;
412 424
413 buffer[0] = '\0'; 425 buffer[0] = '\0';
426 /* Try the function overload if error fallback. */
414 if (msg->_get_uid) 427 if (msg->_get_uid)
415 return msg->_get_uid (msg, buffer, buflen, pwriten); 428 {
429 status = msg->_get_uid (msg, buffer, buflen, pwriten);
430 if (status == 0)
431 return status;
432 }
416 433
417 /* Be compatible with Qpopper ? qppoper saves the UIDL in "X-UIDL". 434 /* Be compatible with Qpopper ? qppoper saves the UIDL in "X-UIDL".
418 We use "Message-ID" as a fallback. Is this bad ? should we generate 435 We generate a chksum and save it in the header. */
419 a chksum or do the same as Qpopper save it in the header. */
420 message_get_header (msg, &header); 436 message_get_header (msg, &header);
421 if ((status = header_get_value (header, "X-UIDL", buffer, buflen, &n)) == 0 437 status = header_get_value (header, "X-UIDL", buffer, buflen, &n);
422 || (status = header_get_value (header, "Message-ID", buffer, 438 if (status == 0 && n > 0)
423 buflen, &n)) == 0)
424 { 439 {
425 /* FIXME: Is header_get_value suppose to do this ? */ 440 /* FIXME: Is header_get_value suppose to do this ? */
426 /* We need to collapse the header if it was mutiline. e points to the 441 /* We need to collapse the header if it was mutiline. e points to the
...@@ -437,6 +452,32 @@ message_get_uid (message_t msg, char *buffer, size_t buflen, size_t *pwriten) ...@@ -437,6 +452,32 @@ message_get_uid (message_t msg, char *buffer, size_t buflen, size_t *pwriten)
437 } 452 }
438 } 453 }
439 } 454 }
455 else
456 {
457 struct md5_ctx md5context;
458 stream_t stream = NULL;
459 char buf[1024];
460 off_t offset = 0;
461 unsigned char md5digest[16];
462 char *tmp;
463 n = 0;
464 message_get_stream (msg, &stream);
465 md5_init_ctx (&md5context);
466 while (stream_read (stream, buf, sizeof (buf), offset, &n) == 0
467 && n > 0)
468 {
469 md5_process_bytes (buf, n, &md5context);
470 offset += n;
471 }
472 md5_finish_ctx (&md5context, md5digest);
473 tmp = buf;
474 for (n = 0; n < 16; n++, tmp += 2)
475 sprintf (tmp, "%02x", md5digest[n]);
476 *tmp = '\0';
477 header_set_value (header, "X-UIDL", buf, 1);
478 buflen--; /* leave space for the NULL. */
479 strncpy (buffer, buf, buflen)[buflen] = '\0';
480 }
440 return status; 481 return status;
441 } 482 }
442 483
......
1 /* GNU mailutils - a suite of utilities for electronic mail 1 /* GNU mailutils - a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
3 3
4 This program is free software; you can redistribute it and/or modify 4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Library Public License as published by 5 it under the terms of the GNU General Library Public License as published by
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
39 * Need to prevent re-entry into mime lib, but allow non-blocking re-entry into lib. 39 * Need to prevent re-entry into mime lib, but allow non-blocking re-entry into lib.
40 */ 40 */
41 41
42 static int 42 static int
43 _mime_is_multipart_digest(mime_t mime) 43 _mime_is_multipart_digest(mime_t mime)
44 { 44 {
45 if ( mime->content_type ) 45 if ( mime->content_type )
...@@ -47,7 +47,7 @@ _mime_is_multipart_digest(mime_t mime) ...@@ -47,7 +47,7 @@ _mime_is_multipart_digest(mime_t mime)
47 return 0; 47 return 0;
48 } 48 }
49 49
50 static int 50 static int
51 _mime_append_part(mime_t mime, message_t msg, int offset, int len, int lines) 51 _mime_append_part(mime_t mime, message_t msg, int offset, int len, int lines)
52 { 52 {
53 struct _mime_part *mime_part, **part_arr; 53 struct _mime_part *mime_part, **part_arr;
...@@ -131,7 +131,7 @@ char *_strtrim(char *str); ...@@ -131,7 +131,7 @@ char *_strtrim(char *str);
131 || ((c) == '\\') || ((c) == '.') || ((c) == '[') \ 131 || ((c) == '\\') || ((c) == '.') || ((c) == '[') \
132 || ((c) == ']') ) 132 || ((c) == ']') )
133 133
134 static void 134 static void
135 _mime_munge_content_header(char *field_body ) 135 _mime_munge_content_header(char *field_body )
136 { 136 {
137 char *p, *e, *str = field_body; 137 char *p, *e, *str = field_body;
...@@ -195,7 +195,7 @@ _mime_get_param(char *field_body, const char *param, int *len) ...@@ -195,7 +195,7 @@ _mime_get_param(char *field_body, const char *param, int *len)
195 return NULL; 195 return NULL;
196 } 196 }
197 197
198 static int 198 static int
199 _mime_setup_buffers(mime_t mime) 199 _mime_setup_buffers(mime_t mime)
200 { 200 {
201 if ( mime->cur_buf == NULL && ( mime->cur_buf = malloc( mime->buf_size ) ) == NULL ) { 201 if ( mime->cur_buf == NULL && ( mime->cur_buf = malloc( mime->buf_size ) ) == NULL ) {
...@@ -208,7 +208,7 @@ _mime_setup_buffers(mime_t mime) ...@@ -208,7 +208,7 @@ _mime_setup_buffers(mime_t mime)
208 return 0; 208 return 0;
209 } 209 }
210 210
211 static void 211 static void
212 _mime_append_header_line(mime_t mime) 212 _mime_append_header_line(mime_t mime)
213 { 213 {
214 if ( mime->header_length + mime->line_ndx > mime->header_buf_size) { 214 if ( mime->header_length + mime->line_ndx > mime->header_buf_size) {
...@@ -222,7 +222,7 @@ _mime_append_header_line(mime_t mime) ...@@ -222,7 +222,7 @@ _mime_append_header_line(mime_t mime)
222 mime->header_length += mime->line_ndx; 222 mime->header_length += mime->line_ndx;
223 } 223 }
224 224
225 static int 225 static int
226 _mime_parse_mpart_message(mime_t mime) 226 _mime_parse_mpart_message(mime_t mime)
227 { 227 {
228 char *cp, *cp2; 228 char *cp, *cp2;
...@@ -323,7 +323,7 @@ _mime_parse_mpart_message(mime_t mime) ...@@ -323,7 +323,7 @@ _mime_parse_mpart_message(mime_t mime)
323 323
324 /*------ Mime message functions for READING a multipart message -----*/ 324 /*------ Mime message functions for READING a multipart message -----*/
325 325
326 static int 326 static int
327 _mimepart_body_read(stream_t stream, char *buf, size_t buflen, off_t off, size_t *nbytes) 327 _mimepart_body_read(stream_t stream, char *buf, size_t buflen, off_t off, size_t *nbytes)
328 { 328 {
329 body_t body = stream_get_owner(stream); 329 body_t body = stream_get_owner(stream);
...@@ -343,7 +343,7 @@ _mimepart_body_read(stream_t stream, char *buf, size_t buflen, off_t off, size_t ...@@ -343,7 +343,7 @@ _mimepart_body_read(stream_t stream, char *buf, size_t buflen, off_t off, size_t
343 return stream_read(mime_part->mime->stream, buf, read_len, mime_part->offset + off, nbytes ); 343 return stream_read(mime_part->mime->stream, buf, read_len, mime_part->offset + off, nbytes );
344 } 344 }
345 345
346 static int 346 static int
347 _mimepart_body_fd(stream_t stream, int *fd) 347 _mimepart_body_fd(stream_t stream, int *fd)
348 { 348 {
349 body_t body = stream_get_owner(stream); 349 body_t body = stream_get_owner(stream);
...@@ -353,7 +353,7 @@ _mimepart_body_fd(stream_t stream, int *fd) ...@@ -353,7 +353,7 @@ _mimepart_body_fd(stream_t stream, int *fd)
353 return stream_get_fd(mime_part->mime->stream, fd); 353 return stream_get_fd(mime_part->mime->stream, fd);
354 } 354 }
355 355
356 static int 356 static int
357 _mimepart_body_size (body_t body, size_t *psize) 357 _mimepart_body_size (body_t body, size_t *psize)
358 { 358 {
359 message_t msg = body_get_owner(body); 359 message_t msg = body_get_owner(body);
...@@ -366,7 +366,7 @@ _mimepart_body_size (body_t body, size_t *psize) ...@@ -366,7 +366,7 @@ _mimepart_body_size (body_t body, size_t *psize)
366 return 0; 366 return 0;
367 } 367 }
368 368
369 static int 369 static int
370 _mimepart_body_lines (body_t body, size_t *plines) 370 _mimepart_body_lines (body_t body, size_t *plines)
371 { 371 {
372 message_t msg = body_get_owner(body); 372 message_t msg = body_get_owner(body);
...@@ -380,14 +380,14 @@ _mimepart_body_lines (body_t body, size_t *plines) ...@@ -380,14 +380,14 @@ _mimepart_body_lines (body_t body, size_t *plines)
380 } 380 }
381 381
382 /*------ Mime message/header functions for CREATING multipart message -----*/ 382 /*------ Mime message/header functions for CREATING multipart message -----*/
383 static int 383 static int
384 _mime_set_content_type(mime_t mime) 384 _mime_set_content_type(mime_t mime)
385 { 385 {
386 char content_type[256]; 386 char content_type[256];
387 char boundary[128]; 387 char boundary[128];
388 header_t hdr = NULL; 388 header_t hdr = NULL;
389 size_t size; 389 size_t size;
390 390
391 if ( mime->nmtp_parts > 1 ) { 391 if ( mime->nmtp_parts > 1 ) {
392 if ( mime->flags & MIME_ADDED_MULTIPART_CT ) 392 if ( mime->flags & MIME_ADDED_MULTIPART_CT )
393 return 0; 393 return 0;
...@@ -421,7 +421,7 @@ _mime_set_content_type(mime_t mime) ...@@ -421,7 +421,7 @@ _mime_set_content_type(mime_t mime)
421 421
422 #define ADD_CHAR(buf, c, offset, buflen, nbytes) {*(buf)++ = c; (offset)++; (nbytes)++;if (--(buflen) == 0) return 0;} 422 #define ADD_CHAR(buf, c, offset, buflen, nbytes) {*(buf)++ = c; (offset)++; (nbytes)++;if (--(buflen) == 0) return 0;}
423 423
424 static int 424 static int
425 _mime_body_read(stream_t stream, char *buf, size_t buflen, off_t off, size_t *nbytes) 425 _mime_body_read(stream_t stream, char *buf, size_t buflen, off_t off, size_t *nbytes)
426 { 426 {
427 body_t body = stream_get_owner(stream); 427 body_t body = stream_get_owner(stream);
...@@ -470,7 +470,7 @@ _mime_body_read(stream_t stream, char *buf, size_t buflen, off_t off, size_t *nb ...@@ -470,7 +470,7 @@ _mime_body_read(stream_t stream, char *buf, size_t buflen, off_t off, size_t *nb
470 } 470 }
471 while(mime->postamble) { 471 while(mime->postamble) {
472 mime->postamble--; 472 mime->postamble--;
473 ADD_CHAR(buf, '-', mime->cur_offset, buflen, *nbytes); 473 ADD_CHAR(buf, '-', mime->cur_offset, buflen, *nbytes);
474 } 474 }
475 mime->flags &= ~(MIME_INSERT_BOUNDARY|MIME_ADDING_BOUNDARY); 475 mime->flags &= ~(MIME_INSERT_BOUNDARY|MIME_ADDING_BOUNDARY);
476 mime->part_offset = 0; 476 mime->part_offset = 0;
...@@ -502,7 +502,7 @@ _mime_body_read(stream_t stream, char *buf, size_t buflen, off_t off, size_t *nb ...@@ -502,7 +502,7 @@ _mime_body_read(stream_t stream, char *buf, size_t buflen, off_t off, size_t *nb
502 return ret; 502 return ret;
503 } 503 }
504 504
505 static int 505 static int
506 _mime_body_fd(stream_t stream, int *fd) 506 _mime_body_fd(stream_t stream, int *fd)
507 { 507 {
508 body_t body = stream_get_owner(stream); 508 body_t body = stream_get_owner(stream);
...@@ -516,7 +516,7 @@ _mime_body_fd(stream_t stream, int *fd) ...@@ -516,7 +516,7 @@ _mime_body_fd(stream_t stream, int *fd)
516 return stream_get_fd(msg_stream, fd); 516 return stream_get_fd(msg_stream, fd);
517 } 517 }
518 518
519 static int 519 static int
520 _mime_body_size (body_t body, size_t *psize) 520 _mime_body_size (body_t body, size_t *psize)
521 { 521 {
522 message_t msg = body_get_owner(body); 522 message_t msg = body_get_owner(body);
...@@ -541,7 +541,7 @@ _mime_body_size (body_t body, size_t *psize) ...@@ -541,7 +541,7 @@ _mime_body_size (body_t body, size_t *psize)
541 return 0; 541 return 0;
542 } 542 }
543 543
544 static int 544 static int
545 _mime_body_lines (body_t body, size_t *plines) 545 _mime_body_lines (body_t body, size_t *plines)
546 { 546 {
547 message_t msg = body_get_owner(body); 547 message_t msg = body_get_owner(body);
...@@ -563,7 +563,7 @@ _mime_body_lines (body_t body, size_t *plines) ...@@ -563,7 +563,7 @@ _mime_body_lines (body_t body, size_t *plines)
563 return 0; 563 return 0;
564 } 564 }
565 565
566 int 566 int
567 mime_create(mime_t *pmime, message_t msg, int flags) 567 mime_create(mime_t *pmime, message_t msg, int flags)
568 { 568 {
569 mime_t mime = NULL; 569 mime_t mime = NULL;
...@@ -611,7 +611,7 @@ mime_create(mime_t *pmime, message_t msg, int flags) ...@@ -611,7 +611,7 @@ mime_create(mime_t *pmime, message_t msg, int flags)
611 return ret; 611 return ret;
612 } 612 }
613 613
614 void 614 void
615 mime_destroy(mime_t *pmime) 615 mime_destroy(mime_t *pmime)
616 { 616 {
617 mime_t mime; 617 mime_t mime;
...@@ -648,8 +648,8 @@ mime_destroy(mime_t *pmime) ...@@ -648,8 +648,8 @@ mime_destroy(mime_t *pmime)
648 } 648 }
649 } 649 }
650 650
651 int 651 int
652 mime_get_part(mime_t mime, int part, message_t *msg) 652 mime_get_part(mime_t mime, size_t part, message_t *msg)
653 { 653 {
654 size_t nmtp_parts; 654 size_t nmtp_parts;
655 int ret = 0; 655 int ret = 0;
...@@ -681,7 +681,7 @@ mime_get_part(mime_t mime, int part, message_t *msg) ...@@ -681,7 +681,7 @@ mime_get_part(mime_t mime, int part, message_t *msg)
681 return ret; 681 return ret;
682 } 682 }
683 683
684 int 684 int
685 mime_get_num_parts(mime_t mime, size_t *nmtp_parts) 685 mime_get_num_parts(mime_t mime, size_t *nmtp_parts)
686 { 686 {
687 int ret = 0; 687 int ret = 0;
...@@ -698,11 +698,11 @@ mime_get_num_parts(mime_t mime, size_t *nmtp_parts) ...@@ -698,11 +698,11 @@ mime_get_num_parts(mime_t mime, size_t *nmtp_parts)
698 698
699 } 699 }
700 700
701 int 701 int
702 mime_add_part(mime_t mime, message_t msg) 702 mime_add_part(mime_t mime, message_t msg)
703 { 703 {
704 int ret; 704 int ret;
705 705
706 if ( mime == NULL || msg == NULL || ( mime->flags & MIME_NEW_MESSAGE ) == 0 ) 706 if ( mime == NULL || msg == NULL || ( mime->flags & MIME_NEW_MESSAGE ) == 0 )
707 return EINVAL; 707 return EINVAL;
708 if ( ( ret = _mime_append_part(mime, msg, 0, 0, 0) ) == 0 ) 708 if ( ( ret = _mime_append_part(mime, msg, 0, 0, 0) ) == 0 )
...@@ -710,7 +710,7 @@ mime_add_part(mime_t mime, message_t msg) ...@@ -710,7 +710,7 @@ mime_add_part(mime_t mime, message_t msg)
710 return ret; 710 return ret;
711 } 711 }
712 712
713 int 713 int
714 mime_get_message(mime_t mime, message_t *msg) 714 mime_get_message(mime_t mime, message_t *msg)
715 { 715 {
716 stream_t body_stream; 716 stream_t body_stream;
...@@ -749,7 +749,7 @@ mime_get_message(mime_t mime, message_t *msg) ...@@ -749,7 +749,7 @@ mime_get_message(mime_t mime, message_t *msg)
749 return ret; 749 return ret;
750 } 750 }
751 751
752 int 752 int
753 mime_is_multipart(mime_t mime) 753 mime_is_multipart(mime_t mime)
754 { 754 {
755 if ( mime->content_type ) 755 if ( mime->content_type )
......