maildir.c 4.9 KB

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