From a8f9af429633a06a6dcf16c6b195108e86653053 Mon Sep 17 00:00:00 2001 From: Michael Elkins Date: Thu, 21 Dec 2000 23:10:18 +0000 Subject: [PATCH] RFC822.PEEK is obsolete in RFC2060. Use BODY.PEEK[] instead, which does the same thing keep track of the uidvalidity so isync can detect if the mailbox on the server has changed since the last sync. --- imap.c | 46 ++++++++++++++++++++++++++++++++++++++++------ isync.h | 3 +++ maildir.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ sync.c | 17 +++++++++++++++++ 4 files changed, 112 insertions(+), 6 deletions(-) diff --git a/imap.c b/imap.c index 79e21ae..c50f083 100644 --- a/imap.c +++ b/imap.c @@ -150,7 +150,7 @@ buffer_gets (buffer_t * b, char **s) } static int -parse_fetch (imap_t * imap, list_t * list, message_t *cur) +parse_fetch (imap_t * imap, list_t * list, message_t * cur) { list_t *tmp; @@ -196,7 +196,8 @@ parse_fetch (imap_t * imap, list_t * list, message_t *cur) else if (!strcmp ("\\Recent", flags->val)) cur->flags |= D_RECENT; else - printf ("Warning, unknown flag %s\n",flags->val); + printf ("Warning, unknown flag %s\n", + flags->val); } else puts ("Error, unable to parse FLAGS list"); @@ -210,6 +211,32 @@ parse_fetch (imap_t * imap, list_t * list, message_t *cur) return 0; } +static void +parse_response_code (imap_t * imap, char *s) +{ + char *arg; + + if (*s != '[') + return; /* no response code */ + s++; + + arg = next_arg (&s); + + if (!strcmp ("UIDVALIDITY", arg)) + { + arg = next_arg (&s); + imap->uidvalidity = atol (arg); + } + else if (!strcmp ("ALERT", arg)) + { + /* RFC2060 says that these messages MUST be displayed + * to the user + */ + fputs ("***ALERT*** ", stdout); + puts (s); + } +} + static int imap_exec (imap_t * imap, const char *fmt, ...) { @@ -270,6 +297,12 @@ imap_exec (imap_t * imap, const char *fmt, ...) rec = &(*rec)->next; } } + else if (!strcmp ("OK", arg) || !strcmp ("BAD", arg) || + !strcmp ("NO", arg) || !strcmp ("PREAUTH", arg) || + !strcmp ("BYE", arg)) + { + parse_response_code (imap, cmd); + } else if ((arg1 = next_arg (&cmd))) { if (!strcmp ("EXISTS", arg1)) @@ -289,7 +322,7 @@ imap_exec (imap_t * imap, const char *fmt, ...) list = parse_list (cmd, 0); - *cur = calloc (1, sizeof(message_t)); + *cur = calloc (1, sizeof (message_t)); if (parse_fetch (imap, list, *cur)) { free_list (list); @@ -315,6 +348,7 @@ imap_exec (imap_t * imap, const char *fmt, ...) else { arg = next_arg (&cmd); + parse_response_code (imap, cmd); if (!strcmp ("OK", arg)) return 0; return -1; @@ -474,8 +508,8 @@ imap_open (config_t * box, int fast) { /* XXX for now assume personal namespace */ if (is_list (imap->ns_personal) && - is_list(imap->ns_personal->child) && - is_atom(imap->ns_personal->child->child)) + is_list (imap->ns_personal->child) && + is_atom (imap->ns_personal->child->child)) { ns_prefix = imap->ns_personal->child->child->val; } @@ -575,7 +609,7 @@ imap_fetch_message (imap_t * imap, unsigned int uid, int fd) size_t n; char buf[1024]; - send_server (imap->sock, "UID FETCH %d (RFC822.PEEK)", uid); + send_server (imap->sock, "UID FETCH %d BODY.PEEK[]", uid); for (;;) { diff --git a/isync.h b/isync.h index 52f36ef..d4ef130 100644 --- a/isync.h +++ b/isync.h @@ -68,6 +68,7 @@ struct mailbox char *path; message_t *msgs; unsigned int deleted; /* # of deleted messages */ + unsigned int uidvalidity; unsigned int changed:1; }; @@ -117,6 +118,7 @@ typedef struct * UID to be used in a FETCH FLAGS command */ unsigned int deleted; /* # of deleted messages */ + unsigned int uidvalidity; /* NAMESPACE info */ list_t *ns_personal; list_t *ns_other; @@ -151,6 +153,7 @@ imap_t *imap_open (config_t *, int); mailbox_t *maildir_open (const char *, int fast); int maildir_expunge (mailbox_t *, int); int maildir_sync (mailbox_t *); +int maildir_set_uidvalidity (mailbox_t *, unsigned int uidvalidity); /* parse an IMAP list construct */ list_t * parse_list (char *s, char **end); diff --git a/maildir.c b/maildir.c index 8c7e170..a03c5bd 100644 --- a/maildir.c +++ b/maildir.c @@ -66,6 +66,7 @@ maildir_open (const char *path, int fast) mailbox_t *m; char *s; int count = 0; + FILE *fp; /* check to make sure this looks like a valid maildir box */ snprintf (buf, sizeof (buf), "%s/new", path); @@ -80,8 +81,20 @@ maildir_open (const char *path, int fast) perror ("access"); return 0; } + m = calloc (1, sizeof (mailbox_t)); m->path = strdup (path); + m->uidvalidity = -1; + + /* check for the uidvalidity value */ + snprintf (buf, sizeof (buf), "%s/isyncuidvalidity", path); + if ((fp = fopen (buf, "r"))) + { + buf[sizeof (buf) - 1] = 0; + if (fgets (buf, sizeof (buf) - 1, fp)) + m->uidvalidity = atol (buf); + fclose (fp); + } if (fast) return m; @@ -208,3 +221,42 @@ maildir_sync (mailbox_t * mbox) } return 0; } + +int +maildir_set_uidvalidity (mailbox_t * mbox, unsigned int uidvalidity) +{ + char path[_POSIX_PATH_MAX]; + char buf[16]; + int fd; + int ret; + + snprintf (path, sizeof (path), "%s/isyncuidvalidity", mbox->path); + fd = open (path, O_WRONLY | O_CREAT | O_EXCL, 0600); + if (fd == -1) + { + perror ("open"); + return -1; + } + snprintf (buf, sizeof (buf), "%u\n", uidvalidity); + + ret = write (fd, buf, strlen (buf)); + + if (ret == -1) + perror("write"); + else if ((size_t) ret != strlen (buf)) + ret = -1; + else + ret = 0; + + if (close (fd)) + { + perror("close"); + ret = -1; + } + + if (ret) + if (unlink (path)) + perror ("unlink"); + + return (ret); +} diff --git a/sync.c b/sync.c index 1166460..73bee17 100644 --- a/sync.c +++ b/sync.c @@ -52,6 +52,23 @@ sync_mailbox (mailbox_t * mbox, imap_t * imap, int flags) int ret; struct stat sb; + if (mbox->uidvalidity != (unsigned int) -1) + { + if (mbox->uidvalidity != imap->uidvalidity) + { + /* if the UIDVALIDITY value has changed, it means all our + * local UIDs are invalid, so we can't sync. + */ + puts ("Error, UIDVALIDITY changed on server (fatal)"); + return -1; + } + } + else if (maildir_set_uidvalidity (mbox, imap->uidvalidity)) + { + puts ("Error, unable to store UIDVALIDITY"); + return -1; + } + for (cur = mbox->msgs; cur; cur = cur->next) { tmp = find_msg (imap->msgs, cur->uid);