소스 검색

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.

Michael Elkins 24 년 전
부모
커밋
a8f9af4296
4개의 변경된 파일112개의 추가작업 그리고 6개의 파일을 삭제
  1. 40 6
      imap.c
  2. 3 0
      isync.h
  3. 52 0
      maildir.c
  4. 17 0
      sync.c

+ 40 - 6
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 (;;)
     {

+ 3 - 0
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);

+ 52 - 0
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);
+}

+ 17 - 0
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);