maildir.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. /* $Id$
  2. *
  3. * isync - IMAP4 to maildir mailbox synchronizer
  4. * Copyright (C) 2000 Michael R. Elkins <me@mutt.org>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19. */
  20. #include <limits.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include <dirent.h>
  24. #include <fcntl.h>
  25. #include <stdio.h>
  26. #include <unistd.h>
  27. #include "isync.h"
  28. /* 2,<flags> */
  29. static void
  30. parse_info (message_t * m, char *s)
  31. {
  32. if (*s == '2' && *(s + 1) == ',')
  33. {
  34. s += 2;
  35. while (*s)
  36. {
  37. if (*s == 'F')
  38. m->flags |= D_FLAGGED;
  39. else if (*s == 'R')
  40. m->flags |= D_ANSWERED;
  41. else if (*s == 'T')
  42. m->flags |= D_DELETED;
  43. else if (*s == 'S')
  44. m->flags |= D_SEEN;
  45. s++;
  46. }
  47. }
  48. }
  49. /* open a maildir mailbox. if `fast' is nonzero, we just check to make
  50. * sure its a valid mailbox and don't actually parse it. any IMAP messages
  51. * with the \Recent flag set are guaranteed not to be in the mailbox yet,
  52. * so we can save a lot of time when the user just wants to fetch new messages
  53. * without syncing the flags.
  54. */
  55. mailbox_t *
  56. maildir_open (const char *path, int fast)
  57. {
  58. char buf[_POSIX_PATH_MAX];
  59. DIR *d;
  60. struct dirent *e;
  61. message_t **cur;
  62. message_t *p;
  63. mailbox_t *m;
  64. char *s;
  65. int count = 0;
  66. /* check to make sure this looks like a valid maildir box */
  67. snprintf (buf, sizeof (buf), "%s/new", path);
  68. if (access (buf, F_OK))
  69. {
  70. perror ("access");
  71. return 0;
  72. }
  73. snprintf (buf, sizeof (buf), "%s/cur", path);
  74. if (access (buf, F_OK))
  75. {
  76. perror ("access");
  77. return 0;
  78. }
  79. m = calloc (1, sizeof (mailbox_t));
  80. m->path = strdup (path);
  81. if (fast)
  82. return m;
  83. cur = &m->msgs;
  84. for (; count < 2; count++)
  85. {
  86. /* read the msgs from the new subdir */
  87. snprintf (buf, sizeof (buf), "%s/%s", path,
  88. (count == 0) ? "new" : "cur");
  89. d = opendir (buf);
  90. if (!d)
  91. {
  92. perror ("opendir");
  93. return 0;
  94. }
  95. while ((e = readdir (d)))
  96. {
  97. if (*e->d_name == '.')
  98. continue; /* skip dot-files */
  99. *cur = calloc (1, sizeof (message_t));
  100. p = *cur;
  101. p->file = strdup (e->d_name);
  102. p->uid = -1;
  103. p->flags = (count == 1) ? D_SEEN : 0;
  104. p->new = (count == 0);
  105. /* filename format is something like:
  106. * <unique-prefix>.UID<n>:2,<flags>
  107. * This is completely non-standard, but in order for mail
  108. * clients to understand the flags, we have to use the
  109. * standard :info as described by the qmail spec
  110. */
  111. s = strstr (p->file, "UID");
  112. if (!s)
  113. puts ("warning, no uid for message");
  114. else
  115. {
  116. p->uid = strtol (s + 3, &s, 10);
  117. if (*s && *s != ':')
  118. {
  119. puts ("warning, unable to parse uid");
  120. p->uid = -1; /* reset */
  121. }
  122. }
  123. s = strchr (p->file, ':');
  124. if (s)
  125. parse_info (p, s + 1);
  126. if (p->flags & D_DELETED)
  127. m->deleted++;
  128. cur = &p->next;
  129. }
  130. closedir (d);
  131. }
  132. return m;
  133. }
  134. /* permanently remove messages from a maildir mailbox. if `dead' is nonzero,
  135. * we only remove the messags marked dead.
  136. */
  137. int
  138. maildir_expunge (mailbox_t * mbox, int dead)
  139. {
  140. message_t **cur = &mbox->msgs;
  141. message_t *tmp;
  142. char path[_POSIX_PATH_MAX];
  143. while (*cur)
  144. {
  145. if ((dead == 0 && (*cur)->flags & D_DELETED) ||
  146. (dead && (*cur)->dead))
  147. {
  148. tmp = *cur;
  149. *cur = (*cur)->next;
  150. snprintf (path, sizeof (path), "%s/%s/%s",
  151. mbox->path, tmp->new ? "new" : "cur", tmp->file);
  152. if (unlink (path))
  153. perror ("unlink");
  154. free (tmp->file);
  155. free (tmp);
  156. }
  157. else
  158. cur = &(*cur)->next;
  159. }
  160. return 0;
  161. }
  162. int
  163. maildir_sync (mailbox_t * mbox)
  164. {
  165. message_t *cur = mbox->msgs;
  166. char path[_POSIX_PATH_MAX];
  167. char oldpath[_POSIX_PATH_MAX];
  168. char *p;
  169. if (mbox->changed)
  170. {
  171. for (; cur; cur = cur->next)
  172. {
  173. if (cur->changed)
  174. {
  175. /* generate old path */
  176. snprintf (oldpath, sizeof (oldpath), "%s/%s/%s",
  177. mbox->path, cur->new ? "new" : "cur", cur->file);
  178. /* truncate old flags (if present) */
  179. p = strchr (cur->file, ':');
  180. if (p)
  181. *p = 0;
  182. /* generate new path */
  183. snprintf (path, sizeof (path), "%s/%s/%s:2,%s%s%s%s",
  184. mbox->path, (cur->flags & D_SEEN) ? "cur" : "new",
  185. cur->file, (cur->flags & D_FLAGGED) ? "F" : "",
  186. (cur->flags & D_ANSWERED) ? "R" : "",
  187. (cur->flags & D_SEEN) ? "S" : "",
  188. (cur->flags & D_DELETED) ? "T" : "");
  189. if (rename (oldpath, path))
  190. perror ("rename");
  191. }
  192. }
  193. }
  194. return 0;
  195. }