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.
Showing
13 changed files
with
972 additions
and
340 deletions
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; | ... | ... |
-
Please register or sign in to post a comment