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 }
381 if (i > 0)
356 free (pflist->element); 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
...@@ -87,15 +88,23 @@ static void folder_mbox_destroy __P ((folder_t)); ...@@ -87,15 +88,23 @@ 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 *,
92 const char *));
91 static int folder_mbox_list __P ((folder_t, const char *, const char *, 93 static int folder_mbox_list __P ((folder_t, const char *, const char *,
92 struct folder_list *)); 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
532 if (header->_fill == NULL)
533 {
510 status = header_get_stream (header, &is); 534 status = header_get_stream (header, &is);
511 if (status != 0) 535 if (status != 0)
512 return status; 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 {
...@@ -609,6 +691,7 @@ header_get_stream (header_t header, stream_t *pstream) ...@@ -609,6 +691,7 @@ header_get_stream (header_t header, stream_t *pstream)
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;
193 if (mfs->size != (size_t)stbuf.st_size)
194 {
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 {
192 if (psize) 213 if (psize)
193 *psize = stbuf.st_size; 214 *psize = stbuf.st_size;
194 return 0; 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;
...@@ -124,23 +127,35 @@ static int mbox_scan __P ((mailbox_t, size_t, size_t *)); ...@@ -124,23 +127,35 @@ 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 129
127
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 *,
133 int));
134 static int mbox_header_fill __P ((header_t, char *, size_t, off_t,
135 size_t *));
136 static int mbox_get_header_readstream __P ((message_t, char *, size_t, off_t,
137 size_t *, int));
131 static int mbox_get_hdr_fd __P ((stream_t, int *)); 138 static int mbox_get_hdr_fd __P ((stream_t, int *));
132 static int mbox_get_body_fd __P ((stream_t, int *)); 139 static int mbox_get_body_fd __P ((stream_t, int *));
133 static int mbox_get_fd __P ((mbox_message_t, int *)); 140 static int mbox_get_fd __P ((mbox_message_t, int *));
134 static int mbox_get_attr_flags __P ((attribute_t, int *)); 141 static int mbox_get_attr_flags __P ((attribute_t, int *));
135 static int mbox_set_attr_flags __P ((attribute_t, int)); 142 static int mbox_set_attr_flags __P ((attribute_t, int));
136 static int mbox_unset_attr_flags __P ((attribute_t, int)); 143 static int mbox_unset_attr_flags __P ((attribute_t, int));
137 static int mbox_readstream __P ((stream_t, char *, size_t, off_t, size_t *)); 144 static int mbox_body_read __P ((stream_t, char *, size_t, off_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));
138 static int mbox_header_size __P ((header_t, size_t *)); 150 static int mbox_header_size __P ((header_t, size_t *));
139 static int mbox_header_lines __P ((header_t, size_t *)); 151 static int mbox_header_lines __P ((header_t, size_t *));
140 static int mbox_body_size __P ((body_t, size_t *)); 152 static int mbox_body_size __P ((body_t, size_t *));
141 static int mbox_body_lines __P ((body_t, size_t *)); 153 static int mbox_body_lines __P ((body_t, size_t *));
142 static int mbox_envelope_sender __P ((envelope_t, char *, size_t, size_t *)); 154 static int mbox_envelope_sender __P ((envelope_t, char *, size_t,
143 static int mbox_envelope_date __P ((envelope_t, char *, size_t, 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
...@@ -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 {
473 monitor_unlock (mailbox->monitor);
474 return 0; /* Nothing change, bail out. */ 490 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 {
536 fputc ('\n', tempfile);
537 total++;
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 { 566 {
560 nread = (len < sizeof (buffer)) ? len : sizeof (buffer); 567 status = mbox_append_message0 (tmpmailbox, mum->message, &total, 1);
561 if ((status = stream_read (mailbox->stream, buffer, 568 if (status != 0)
562 nread, offset, &n) != 0)
563 || fwrite(buffer, sizeof(*buffer), n, tempfile) != n)
564 { 569 {
565 if (status == 0) 570 fprintf (stderr, "Error expunge:%d: %s", __LINE__,
566 status = errno;
567 fprintf (stderr, "Error expunge:%d: (%s)\n", __LINE__,
568 strerror (status)); 571 strerror (status));
569 goto bailout0; 572 goto bailout0;
570 } 573 }
571 len -= n;
572 total += n;
573 offset += n;
574 }
575
576 /* Put the new attributes. */
577 {
578 char abuf[64];
579 size_t na = 0;
580 abuf[0] = '\0';
581 flags_to_string (mum->new_flags, abuf, sizeof(abuf), &na);
582 fputs (abuf, tempfile);
583 total += na;
584 }
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 }
611 } 598 /* Add the newline separator. */
612 } /* End of header copy. */ 599 status = stream_write (tmpmailbox->stream, "\n", 1, total, &n);
613 600 if (status != 0)
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 { 601 {
626 if (status == 0)
627 status = errno;
628 fprintf (stderr, "Error expunge:%d: %s", __LINE__, 602 fprintf (stderr, "Error expunge:%d: %s", __LINE__,
629 strerror (status)); 603 strerror (status));
630 goto bailout0; 604 goto bailout0;
631 } 605 }
632 len -= n; 606 total++;
633 total += n;
634 offset += n;
635 } 607 }
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) 628 {
629 status = stream_write (tmpmailbox->stream, buffer, n,
630 total, &n);
631 if (status != 0)
655 { 632 {
656 if (status == 0)
657 status = errno;
658 fprintf (stderr, "Error expunge:%d: %s", __LINE__, 633 fprintf (stderr, "Error expunge:%d: %s", __LINE__,
659 strerror (status)); 634 strerror (status));
660 goto bailout0; 635 goto bailout0;
661 } 636 }
662 len -= n;
663 total += n; 637 total += n;
664 offset += n; 638 offset += n;
665 } 639 }
666 } 640 }
641 else if (len < 0)
642 {
643 /* Corrupted mailbox. */
644 fprintf (stderr, "Error expunge:%d: %s", __LINE__,
645 strerror (status));
646 goto bailout0;
647 }
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);
679 {
680 status = stream_write (mailbox->stream, buffer, nread, offset, &n);
681 if (status != 0) 663 if (status != 0)
682 { 664 {
683 fprintf (stderr, "Error expunge:%d: %s\n", __LINE__, 665 fprintf (stderr, "Error expunge:%d: %s\n", __LINE__,
684 strerror (status)); 666 strerror (status));
685 goto bailout; 667 goto bailout;
686 } 668 }
687 nread -= n; 669 off += n;
688 offset += n; 670 offset += n;
689 } 671 }
690 } 672 }
691 }
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,9 +812,23 @@ mbox_unset_attr_flags (attribute_t attr, int flags) ...@@ -834,9 +812,23 @@ 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)
839 { 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)
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);
842 mbox_message_t mum = message_get_owner (msg); 834 mbox_message_t mum = message_get_owner (msg);
...@@ -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,7 +904,10 @@ mbox_get_header_read (stream_t is, char *buffer, size_t len, ...@@ -904,7 +904,10 @@ 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 stream_readline (mum->stream, buffer, nread,
909 mum->header_from_end + off, &nread) :
910 stream_read (mum->stream, buffer, nread,
908 mum->header_from_end + off, &nread); 911 mum->header_from_end + off, &nread);
909 } 912 }
910 monitor_unlock (mum->mud->mailbox->monitor); 913 monitor_unlock (mum->mud->mailbox->monitor);
...@@ -973,6 +976,7 @@ mbox_envelope_date (envelope_t envelope, char *buf, size_t len, ...@@ -973,6 +976,7 @@ mbox_envelope_date (envelope_t envelope, char *buf, size_t len,
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]" */
992 { 994 /* strlen ("From ") == 5 */
993 char *s = strchr (buffer + 5, ' '); 995 if (n > 5 && (s = strchr (buffer + 5, ' ')) != NULL)
994 if (s)
995 { 996 {
996 if (buf && len > 0) 997 if (buf && len > 0)
997 { 998 {
998 strncpy (buf, s + 1, len); 999 len--; /* Leave space for the null. */
999 buffer [len - 1] = '\0'; 1000 strncpy (buf, s + 1, len)[len] = '\0';
1000 } 1001 len = strlen (buf);
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 { 1038 /* strlen ("From ") == 5 */
1039 char *s = strchr (buffer + 5, ' '); 1039 if (n > 5 && (s = strchr (buffer + 5, ' ')) != NULL)
1040 if (s)
1041 { 1040 {
1041 /* Put a NULL to isolate the sender string, make a C string. */
1042 *s = '\0'; 1042 *s = '\0';
1043 if (buf && len > 0) 1043 if (buf && len > 0)
1044 { 1044 {
1045 strncpy (buf, buffer + 5, len); 1045 len--; /* leave space for the null */
1046 buffer [len - 1] = '\0'; 1046 strncpy (buf, buffer + 5, len)[len] = '\0';
1047 } 1047 len = strlen (buf);
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,59 +1188,63 @@ mbox_append_message (mailbox_t mailbox, message_t msg) ...@@ -1190,59 +1188,63 @@ 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. */
1197 pthread_cleanup_push (mbox_cleanup, (void *)mailbox);
1198 #endif
1199 locker_lock (mailbox->locker, MU_LOCKER_WRLOCK); 1194 locker_lock (mailbox->locker, MU_LOCKER_WRLOCK);
1195
1196 default:
1200 { 1197 {
1201 off_t size; 1198 off_t size;
1202 int status; 1199 int status;
1203 size_t n = 0;
1204 char nl = '\n';
1205
1206 /* Move to the end of the file, not necesary if _APPEND mode. */ 1200 /* Move to the end of the file, not necesary if _APPEND mode. */
1207 status = stream_size (mailbox->stream, &size); 1201 if ((status = stream_size (mailbox->stream, &size)) != 0
1208 if (status != 0) 1202 || (status = mbox_append_message0 (mailbox, msg, &size, 0)) != 0)
1209 { 1203 {
1204 if (status != EAGAIN)
1210 locker_unlock (mailbox->locker); 1205 locker_unlock (mailbox->locker);
1211 monitor_unlock (mailbox->monitor);
1212 return status; 1206 return status;
1213 } 1207 }
1208 }
1209 }
1210 locker_unlock (mailbox->locker);
1211 return 0;
1212 }
1213
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';
1214 1222
1215 switch (mud->state) 1223 switch (mud->state)
1216 { 1224 {
1217 case MBOX_NO_STATE: 1225 case MBOX_NO_STATE:
1226 /* Allocate memory for the sender/date buffers. */
1218 mud->sender = calloc (128, sizeof (char)); 1227 mud->sender = calloc (128, sizeof (char));
1219 if (mud->sender == NULL) 1228 if (mud->sender == NULL)
1220 {
1221 locker_unlock (mailbox->locker);
1222 monitor_unlock (mailbox->monitor);
1223 return ENOMEM; 1229 return ENOMEM;
1224 }
1225 mud->date = calloc (128, sizeof (char)); 1230 mud->date = calloc (128, sizeof (char));
1226 if (mud->date == NULL) 1231 if (mud->date == NULL)
1227 { 1232 {
1228 free (mud->sender); 1233 free (mud->sender);
1229 mud->sender = NULL; 1234 mud->sender = NULL;
1230 mud->state = MBOX_NO_STATE;
1231 locker_unlock (mailbox->locker);
1232 monitor_unlock (mailbox->monitor);
1233 return ENOMEM; 1235 return ENOMEM;
1234 } 1236 }
1235 mud->off = 0; 1237 mud->off = 0;
1236 mud->state = MBOX_STATE_FROM; 1238 mud->state = MBOX_STATE_APPEND_SENDER;
1237 1239
1238 case MBOX_STATE_FROM: 1240 case MBOX_STATE_APPEND_SENDER:
1239 /* Generate a "From " separator. */ 1241 /* Generate the sender for the "From " separator. */
1240 { 1242 {
1241 char *s; 1243 char *s;
1242 size_t len = 0; 1244 size_t len = 0;
1243 envelope_t envelope; 1245 envelope_t envelope;
1244 message_get_envelope (msg, &envelope); 1246 message_get_envelope (msg, &envelope);
1245 status = envelope_sender (envelope, mud->sender, 127, &len); 1247 status = envelope_sender (envelope, mud->sender, 128, &len);
1246 if (status != 0) 1248 if (status != 0)
1247 { 1249 {
1248 if (status != EAGAIN) 1250 if (status != EAGAIN)
...@@ -1251,26 +1253,25 @@ mbox_append_message (mailbox_t mailbox, message_t msg) ...@@ -1251,26 +1253,25 @@ mbox_append_message (mailbox_t mailbox, message_t msg)
1251 free (mud->date); 1253 free (mud->date);
1252 mud->date = mud->sender = NULL; 1254 mud->date = mud->sender = NULL;
1253 mud->state = MBOX_NO_STATE; 1255 mud->state = MBOX_NO_STATE;
1254 locker_unlock (mailbox->locker);
1255 } 1256 }
1256 monitor_unlock (mailbox->monitor);
1257 return status; 1257 return status;
1258 } 1258 }
1259
1259 /* Nuke trailing newline. */ 1260 /* Nuke trailing newline. */
1260 s = memchr (mud->sender, nl, len); 1261 s = memchr (mud->sender, nl, len);
1261 if (s) 1262 if (s)
1262 *s = '\0'; 1263 *s = '\0';
1263 mud->state = MBOX_STATE_DATE; 1264 mud->state = MBOX_STATE_APPEND_DATE;
1264 } 1265 }
1265 1266
1266 case MBOX_STATE_DATE: 1267 case MBOX_STATE_APPEND_DATE:
1267 /* Generate a date for the "From " separator. */ 1268 /* Generate a date for the "From " separator. */
1268 { 1269 {
1269 char *s; 1270 char *s;
1270 size_t len = 0; 1271 size_t len = 0;
1271 envelope_t envelope; 1272 envelope_t envelope;
1272 message_get_envelope (msg, &envelope); 1273 message_get_envelope (msg, &envelope);
1273 status = envelope_date (envelope, mud->date, 127, &len); 1274 status = envelope_date (envelope, mud->date, 128, &len);
1274 if (status != 0) 1275 if (status != 0)
1275 { 1276 {
1276 if (status != EAGAIN) 1277 if (status != EAGAIN)
...@@ -1279,39 +1280,134 @@ mbox_append_message (mailbox_t mailbox, message_t msg) ...@@ -1279,39 +1280,134 @@ mbox_append_message (mailbox_t mailbox, message_t msg)
1279 free (mud->date); 1280 free (mud->date);
1280 mud->date = mud->sender = NULL; 1281 mud->date = mud->sender = NULL;
1281 mud->state = MBOX_NO_STATE; 1282 mud->state = MBOX_NO_STATE;
1282 locker_unlock (mailbox->locker);
1283 } 1283 }
1284 monitor_unlock (mailbox->monitor);
1285 return status; 1284 return status;
1286 } 1285 }
1286
1287 /* Nuke trailing newline. */ 1287 /* Nuke trailing newline. */
1288 s = memchr (mud->date, nl, len); 1288 s = memchr (mud->date, nl, len);
1289 if (s) 1289 if (s)
1290 *s = '\0'; 1290 *s = '\0';
1291
1291 /* Write the separator to the mailbox. */ 1292 /* Write the separator to the mailbox. */
1292 stream_write (mailbox->stream, "From ", 5, size, &n); 1293 status = stream_write (mailbox->stream, "From ", 5, *psize, &n);
1293 size += n; 1294 if (status != 0)
1294 stream_write (mailbox->stream, mud->sender, strlen (mud->sender), size, &n); 1295 break;
1295 size += n; 1296 *psize += n;
1296 stream_write (mailbox->stream, " ", 1, size, &n); 1297
1297 size += n; 1298 /* Write sender. */
1298 stream_write (mailbox->stream, mud->date, strlen (mud->date), size, &n); 1299 status = stream_write (mailbox->stream, mud->sender,
1299 size += n; 1300 strlen (mud->sender), *psize, &n);
1300 stream_write (mailbox->stream, &nl , 1, size, &n); 1301 if (status != 0)
1301 size += n; 1302 break;
1303 *psize += n;
1304
1305 status = stream_write (mailbox->stream, " ", 1, *psize, &n);
1306 if (status != 0)
1307 break;
1308 *psize += n;
1309
1310 /* Write date. */
1311 status = stream_write (mailbox->stream, mud->date, strlen(mud->date),
1312 *psize, &n);
1313 if (status != 0)
1314 break;
1315 *psize += n;
1316
1317 status = stream_write (mailbox->stream, &nl , 1, *psize, &n);
1318 if (status != 0)
1319 break;
1320 *psize += n;
1321
1302 free (mud->sender); 1322 free (mud->sender);
1303 free (mud->date); 1323 free (mud->date);
1304 mud->sender = mud->date = NULL; 1324 mud->sender = mud->date = NULL;
1305 mud->state = MBOX_STATE_APPEND; 1325 /* If we are not expunging get the message in one block via the stream
1326 message instead of the header/body. This is good for example for
1327 POP where there is no separtation between header and body. */
1328 if (! is_expunging)
1329 {
1330 mud->state = MBOX_STATE_APPEND_MESSAGE;
1331 break;
1332 }
1333 mud->state = MBOX_STATE_APPEND_HEADER;
1306 } 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;
1343 message_get_header (msg, &header);
1344 header_get_stream (header, &is);
1345 do
1346 {
1347 status = stream_readline (is, buffer, sizeof (buffer), mud->off,
1348 &nread);
1349 if (status != 0)
1350 {
1351 if (status != EAGAIN)
1352 {
1353 mud->state = MBOX_NO_STATE;
1354 mud->off = 0;
1355 }
1356 return status;
1357 }
1358 mud->off += nread;
1359 if (*buffer == '\n')
1360 break;
1361
1362 /* FIXME: We have a problem here the header field may not fit the
1363 buffer. */
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 }
1379
1380 case MBOX_STATE_APPEND_ATTRIBUTE:
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;
1400 }
1401
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);
1315 do 1411 do
1316 { 1412 {
1317 status = stream_read (is, buffer, sizeof (buffer), mud->off, 1413 status = stream_read (is, buffer, sizeof (buffer), mud->off,
...@@ -1321,32 +1417,70 @@ mbox_append_message (mailbox_t mailbox, message_t msg) ...@@ -1321,32 +1417,70 @@ mbox_append_message (mailbox_t mailbox, message_t msg)
1321 if (status != EAGAIN) 1417 if (status != EAGAIN)
1322 { 1418 {
1323 mud->state = MBOX_NO_STATE; 1419 mud->state = MBOX_NO_STATE;
1324 locker_unlock (mailbox->locker); 1420 mud->off = 0;
1325 } 1421 }
1326 stream_flush (mailbox->stream);
1327 monitor_unlock (mailbox->monitor);
1328 return status; 1422 return status;
1329 } 1423 }
1330 stream_write (mailbox->stream, buffer, nread, size, &n);
1331 mud->off += nread; 1424 mud->off += nread;
1332 size += n; 1425 status = stream_write (mailbox->stream, buffer, nread, *psize, &n);
1426 if (status != 0)
1427 break;
1428 *psize += n;
1333 } 1429 }
1334 while (nread > 0); 1430 while (nread > 0);
1335 stream_write (mailbox->stream, &nl, 1, size, &n); 1431 mud->off = 0;
1432 n = 0;
1433 stream_write (mailbox->stream, &nl, 1, *psize, &n);
1434 *psize += n;
1336 } 1435 }
1337 1436
1338 default: 1437 default:
1339 break; 1438 break;
1340 } 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;
1341 } 1463 }
1342 stream_flush (mailbox->stream); 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
...@@ -649,7 +649,7 @@ mime_destroy(mime_t *pmime) ...@@ -649,7 +649,7 @@ mime_destroy(mime_t *pmime)
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;
......