Browse Source

added MaxSize configuration variable

fixed --fast to work robustly without relying on the \Recent flag in
messages
Michael Elkins 24 years ago
parent
commit
0527181f45
10 changed files with 348 additions and 160 deletions
  1. 50 0
      ChangeLog
  2. 14 0
      NEWS
  3. 1 1
      configure.in
  4. 51 108
      imap.c
  5. 9 6
      isync.1
  6. 12 5
      isync.h
  7. 2 0
      isyncrc.sample
  8. 162 12
      maildir.c
  9. 13 6
      main.c
  10. 34 22
      sync.c

+ 50 - 0
ChangeLog

@@ -1,5 +1,55 @@
 2000-12-21  Michael Elkins  <me@sigipe.org>
 2000-12-21  Michael Elkins  <me@sigipe.org>
 
 
+	* imap.c, isync.h, maildir.c, sync.c:
+	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.
+
+	* NEWS: updated NEWS for 0.3 release
+
+	* Makefile.am, isync.spec:
+	added support for building RPMS
+
+	* Makefile.am, isync.1:
+	added target for creating html version of the man page
+
+	documented the imaps: prefix to the Host command
+
+	* imap.c, sync.c:
+	can't assume flag order when fetching a message.  just search for the
+	first `{' to find the message size.
+
+	* isync.1, sync.c:
+	added BUGS section to manpage detailing the fact that we break the
+	maildir(5) spec by parsing the filename
+
+	change message delivery to use the method described in maildir(5)
+
+	* configure.in, main.c, sync.c:
+	use getpass() to get the user's password
+
+	unlink the temp file if we are unable to fetch a new message from the
+	server.
+
+	update version to 0.3
+
+	* isync.1: fixed typo in man page for --verbose option
+
+	* Makefile.am, README, TODO, imap.c, isync.h, list.c:
+	added generic IMAP list parser and rewrote imap_exec() to handle
+	arbitrary data instead of hardcoded
+
+	* Makefile.am, README, configure.in, main.c:
+	fixes to compile cleanly under Solaris 2.7
+
+	* configure.in, imap.c, isync.1, isync.h, main.c:
+	added OpenSSL support
+
+	* ChangeLog, configure.in, main.c:
+	config options were not case insensitive
+
 	* imap.c, isync.h, maildir.c, main.c, sync.c:
 	* imap.c, isync.h, maildir.c, main.c, sync.c:
 	don't fetch deleted messages when expunging
 	don't fetch deleted messages when expunging
 
 

+ 14 - 0
NEWS

@@ -1,3 +1,17 @@
+[0.4]
+
+Added MaxSize configuration option to limit downloading of new messages from
+the server to less than some threshold.
+
+More robust --fast option works without using \Recent flags, so the previous
+problem with multiple accesses killing these flags is no longer a problem.
+
+RFC2060 obsoleted RFC822.PEEK, use BODY.PEEK[] instead which does the same
+job.
+
+Don't need to request UID in a FETCH when doing UID FETCH (RFC2060 states
+that its automatically returned).
+
 [0.3]
 [0.3]
 
 
 Fixed to clean up temp maildir files when the fetch of a new message failed.
 Fixed to clean up temp maildir files when the fetch of a new message failed.

+ 1 - 1
configure.in

@@ -1,5 +1,5 @@
 AC_INIT(isync.h)
 AC_INIT(isync.h)
-AM_INIT_AUTOMAKE(isync,0.3)
+AM_INIT_AUTOMAKE(isync,0.4)
 AM_PROG_CC_STDC
 AM_PROG_CC_STDC
 if test $CC = gcc; then
 if test $CC = gcc; then
 	CFLAGS="$CFLAGS -pipe"
 	CFLAGS="$CFLAGS -pipe"

+ 51 - 108
imap.c

@@ -150,9 +150,13 @@ buffer_gets (buffer_t * b, char **s)
 }
 }
 
 
 static int
 static int
-parse_fetch (imap_t * imap, list_t * list, message_t * cur)
+parse_fetch (imap_t * imap, list_t * list)
 {
 {
     list_t *tmp;
     list_t *tmp;
+    unsigned int uid = 0;
+    unsigned int mask = 0;
+    unsigned int size = 0;
+    message_t *cur;
 
 
     if (!is_list (list))
     if (!is_list (list))
 	return -1;
 	return -1;
@@ -165,7 +169,14 @@ parse_fetch (imap_t * imap, list_t * list, message_t * cur)
 	    {
 	    {
 		tmp = tmp->next;
 		tmp = tmp->next;
 		if (is_atom (tmp))
 		if (is_atom (tmp))
-		    cur->uid = atoi (tmp->val);
+		{
+		    uid = atoi (tmp->val);
+		    if (uid < imap->minuid)
+		    {
+			/* already saw this message */
+			return 0;
+		    }
+		}
 		else
 		else
 		    puts ("Error, unable to parse UID");
 		    puts ("Error, unable to parse UID");
 	    }
 	    }
@@ -181,20 +192,17 @@ parse_fetch (imap_t * imap, list_t * list, message_t * cur)
 			if (is_atom (flags))
 			if (is_atom (flags))
 			{
 			{
 			    if (!strcmp ("\\Seen", flags->val))
 			    if (!strcmp ("\\Seen", flags->val))
-				cur->flags |= D_SEEN;
+				mask |= D_SEEN;
 			    else if (!strcmp ("\\Flagged", flags->val))
 			    else if (!strcmp ("\\Flagged", flags->val))
-				cur->flags |= D_FLAGGED;
+				mask |= D_FLAGGED;
 			    else if (!strcmp ("\\Deleted", flags->val))
 			    else if (!strcmp ("\\Deleted", flags->val))
-			    {
-				cur->flags |= D_DELETED;
-				imap->deleted++;
-			    }
+				mask |= D_DELETED;
 			    else if (!strcmp ("\\Answered", flags->val))
 			    else if (!strcmp ("\\Answered", flags->val))
-				cur->flags |= D_ANSWERED;
+				mask |= D_ANSWERED;
 			    else if (!strcmp ("\\Draft", flags->val))
 			    else if (!strcmp ("\\Draft", flags->val))
-				cur->flags |= D_DRAFT;
+				mask |= D_DRAFT;
 			    else if (!strcmp ("\\Recent", flags->val))
 			    else if (!strcmp ("\\Recent", flags->val))
-				cur->flags |= D_RECENT;
+				mask |= D_RECENT;
 			    else
 			    else
 				printf ("Warning, unknown flag %s\n",
 				printf ("Warning, unknown flag %s\n",
 					flags->val);
 					flags->val);
@@ -206,8 +214,26 @@ parse_fetch (imap_t * imap, list_t * list, message_t * cur)
 		else
 		else
 		    puts ("Error, unable to parse FLAGS");
 		    puts ("Error, unable to parse FLAGS");
 	    }
 	    }
+	    else if (!strcmp ("RFC822.SIZE", tmp->val))
+	    {
+		tmp = tmp->next;
+		if (is_atom (tmp))
+		    size = atol (tmp->val);
+	    }
 	}
 	}
     }
     }
+
+    cur = calloc (1, sizeof (message_t));
+    cur->next = imap->msgs;
+    imap->msgs = cur;
+
+    if (mask & D_DELETED)
+	imap->deleted++;
+
+    cur->uid = uid;
+    cur->flags = mask;
+    cur->size = size;
+
     return 0;
     return 0;
 }
 }
 
 
@@ -246,8 +272,6 @@ imap_exec (imap_t * imap, const char *fmt, ...)
     char *cmd;
     char *cmd;
     char *arg;
     char *arg;
     char *arg1;
     char *arg1;
-    message_t **cur = 0;
-    message_t **rec = 0;
 
 
     va_start (ap, fmt);
     va_start (ap, fmt);
     vsnprintf (tmp, sizeof (tmp), fmt, ap);
     vsnprintf (tmp, sizeof (tmp), fmt, ap);
@@ -281,22 +305,6 @@ imap_exec (imap_t * imap, const char *fmt, ...)
 		imap->ns_other = parse_list (cmd, &cmd);
 		imap->ns_other = parse_list (cmd, &cmd);
 		imap->ns_shared = parse_list (cmd, 0);
 		imap->ns_shared = parse_list (cmd, 0);
 	    }
 	    }
-	    else if (!strcmp ("SEARCH", arg))
-	    {
-		if (!rec)
-		{
-		    rec = &imap->recent_msgs;
-		    while (*rec)
-			rec = &(*rec)->next;
-		}
-		/* parse rest of `cmd' */
-		while ((arg = next_arg (&cmd)))
-		{
-		    *rec = calloc (1, sizeof (message_t));
-		    (*rec)->uid = atoi (arg);
-		    rec = &(*rec)->next;
-		}
-	    }
 	    else if (!strcmp ("OK", arg) || !strcmp ("BAD", arg) ||
 	    else if (!strcmp ("OK", arg) || !strcmp ("BAD", arg) ||
 		     !strcmp ("NO", arg) || !strcmp ("PREAUTH", arg) ||
 		     !strcmp ("NO", arg) || !strcmp ("PREAUTH", arg) ||
 		     !strcmp ("BYE", arg))
 		     !strcmp ("BYE", arg))
@@ -313,25 +321,15 @@ imap_exec (imap_t * imap, const char *fmt, ...)
 		{
 		{
 		    list_t *list;
 		    list_t *list;
 
 
-		    if (!cur)
-		    {
-			cur = &imap->msgs;
-			while (*cur)
-			    cur = &(*cur)->next;
-		    }
-
 		    list = parse_list (cmd, 0);
 		    list = parse_list (cmd, 0);
 
 
-		    *cur = calloc (1, sizeof (message_t));
-		    if (parse_fetch (imap, list, *cur))
+		    if (parse_fetch (imap, list))
 		    {
 		    {
 			free_list (list);
 			free_list (list);
 			return -1;
 			return -1;
 		    }
 		    }
 
 
 		    free_list (list);
 		    free_list (list);
-
-		    cur = &(*cur)->next;
 		}
 		}
 	    }
 	    }
 	    else
 	    else
@@ -357,66 +355,20 @@ imap_exec (imap_t * imap, const char *fmt, ...)
     /* not reached */
     /* not reached */
 }
 }
 
 
-static int
-fetch_recent_flags (imap_t * imap)
-{
-    char buf[1024];
-    message_t **cur = &imap->recent_msgs;
-    message_t *tmp;
-    unsigned int start = -1;
-    unsigned int last = -1;
-    int ret = 0;
-
-    buf[0] = 0;
-    while (*cur)
-    {
-	tmp = *cur;
-
-	if (last == (unsigned int) -1)
-	{
-	    /* init */
-	    start = tmp->uid;
-	    last = tmp->uid;
-	}
-	else if (tmp->uid == last + 1)
-	    last++;
-	else
-	{
-	    /* out of sequence */
-	    if (start == last)
-		ret = imap_exec (imap, "UID FETCH %d (UID FLAGS)", start);
-	    else
-		ret =
-		    imap_exec (imap, "UID FETCH %d:%d (UID FLAGS)", start,
-			       last);
-	    start = tmp->uid;
-	    last = tmp->uid;
-	}
-	free (tmp);
-	*cur = (*cur)->next;
-    }
-
-    if (start != (unsigned int) -1)
-    {
-	if (start == last)
-	    ret = imap_exec (imap, "UID FETCH %d (UID FLAGS)", start);
-	else
-	    ret =
-		imap_exec (imap, "UID FETCH %d:%d (UID FLAGS)", start, last);
-    }
-
-    return ret;
-}
-
+/* `box' is the config info for the maildrop to sync.  `minuid' is the
+ * minimum UID to consider.  in normal mode this will be 1, but in --fast
+ * mode we only fetch messages newer than the last one seen in the local
+ * mailbox.
+ */
 imap_t *
 imap_t *
-imap_open (config_t * box, int fast)
+imap_open (config_t * box, unsigned int minuid)
 {
 {
     int ret;
     int ret;
     imap_t *imap;
     imap_t *imap;
     int s;
     int s;
     struct sockaddr_in sin;
     struct sockaddr_in sin;
     struct hostent *he;
     struct hostent *he;
-    char *ns_prefix = 0;
+    char *ns_prefix = "";
 #if HAVE_LIBSSL
 #if HAVE_LIBSSL
     int use_ssl = 0;
     int use_ssl = 0;
 #endif
 #endif
@@ -463,6 +415,7 @@ imap_open (config_t * box, int fast)
     imap->buf = calloc (1, sizeof (buffer_t));
     imap->buf = calloc (1, sizeof (buffer_t));
     imap->buf->sock = imap->sock;
     imap->buf->sock = imap->sock;
     imap->box = box;
     imap->box = box;
+    imap->minuid = minuid;
 
 
 #if HAVE_LIBSSL
 #if HAVE_LIBSSL
     if (!box->use_imaps)
     if (!box->use_imaps)
@@ -520,28 +473,18 @@ imap_open (config_t * box, int fast)
     {
     {
 	fputs ("Selecting mailbox... ", stdout);
 	fputs ("Selecting mailbox... ", stdout);
 	fflush (stdout);
 	fflush (stdout);
-	ret = imap_exec (imap, "SELECT %s%s",
-			 ns_prefix ? ns_prefix : "", box->box);
+	ret = imap_exec (imap, "SELECT %s%s", ns_prefix, box->box);
 	if (!ret)
 	if (!ret)
 	    printf ("%d messages, %d recent\n", imap->count, imap->recent);
 	    printf ("%d messages, %d recent\n", imap->count, imap->recent);
     }
     }
 
 
     if (!ret)
     if (!ret)
     {
     {
-	if (fast)
-	{
-	    if (imap->recent > 0)
-	    {
-		puts ("Fetching info for recent messages");
-		ret = imap_exec (imap, "UID SEARCH RECENT");
-		if (!ret)
-		    ret = fetch_recent_flags (imap);
-	    }
-	}
-	else if (imap->count > 0)
+	puts ("Reading IMAP mailbox index");
+	if (imap->count > 0)
 	{
 	{
-	    puts ("Reading IMAP mailbox index");
-	    ret = imap_exec (imap, "FETCH 1:%d (UID FLAGS)", imap->count);
+	    ret = imap_exec (imap, "UID FETCH %d:* (FLAGS RFC822.SIZE)",
+		    imap->minuid);
 	}
 	}
     }
     }
 
 

+ 9 - 6
isync.1

@@ -66,12 +66,6 @@ Causes
 to skip the step of synchronzing message flags between the local maildir
 to skip the step of synchronzing message flags between the local maildir
 mailbox and the IMAP mailbox.  Only new messages existing on the server will
 mailbox and the IMAP mailbox.  Only new messages existing on the server will
 be fetched into the local mailbox.
 be fetched into the local mailbox.
-.B NOTE:
-This command works by checking the \\Recent flag on messages in the IMAP
-mailbox.  If you access the IMAP mailbox from multiple locations, the
-\\Recent flag will be lost between sessions, so you must do a full
-synchronization to fetch the messages which do not exist in the local
-mailbox.
 .TP
 .TP
 .B -h, --help
 .B -h, --help
 Displays a summary of command line options
 Displays a summary of command line options
@@ -158,6 +152,15 @@ Defines an alias for the mailbox which can be used as a shortcut on the
 command line.
 command line.
 ..
 ..
 .TP
 .TP
+\fBMaxSize\fR \fIbytes\fR
+Sets a threshold for the maximum message size (in bytes) for which
+.B isync
+should fetch from the server.  This is useful for weeding out messages with
+large attachments.  If
+.I bytes
+is 0, the maximum file size is
+.B unlimited.
+.TP
 \fBRequireSSL\fR \fIyes|no\fR
 \fBRequireSSL\fR \fIyes|no\fR
 .B isync
 .B isync
 will abort the connection if a TLS/SSL session to the IMAP
 will abort the connection if a TLS/SSL session to the IMAP

+ 12 - 5
isync.h

@@ -54,6 +54,7 @@ struct config
     char *pass;
     char *pass;
     char *box;
     char *box;
     char *alias;
     char *alias;
+    unsigned int max_size;
     config_t *next;
     config_t *next;
 #if HAVE_LIBSSL
 #if HAVE_LIBSSL
     char *cert_file;
     char *cert_file;
@@ -69,7 +70,9 @@ struct mailbox
     message_t *msgs;
     message_t *msgs;
     unsigned int deleted;	/* # of deleted messages */
     unsigned int deleted;	/* # of deleted messages */
     unsigned int uidvalidity;
     unsigned int uidvalidity;
+    unsigned int maxuid;	/* largest uid we know about */
     unsigned int changed:1;
     unsigned int changed:1;
+    unsigned int maxuidchanged:1;
 };
 };
 
 
 /* message dispositions */
 /* message dispositions */
@@ -86,6 +89,7 @@ struct message
     char *file;
     char *file;
     unsigned int uid;
     unsigned int uid;
     unsigned int flags;
     unsigned int flags;
+    unsigned int size;
     message_t *next;
     message_t *next;
     unsigned int processed:1;	/* message has already been evaluated */
     unsigned int processed:1;	/* message has already been evaluated */
     unsigned int new:1;		/* message is in the new/ subdir */
     unsigned int new:1;		/* message is in the new/ subdir */
@@ -119,6 +123,8 @@ typedef struct
 				 */
 				 */
     unsigned int deleted;	/* # of deleted messages */
     unsigned int deleted;	/* # of deleted messages */
     unsigned int uidvalidity;
     unsigned int uidvalidity;
+    unsigned int maxuid;
+    unsigned int minuid;
     /* NAMESPACE info */
     /* NAMESPACE info */
     list_t *ns_personal;
     list_t *ns_personal;
     list_t *ns_other;
     list_t *ns_other;
@@ -127,9 +133,8 @@ typedef struct
 imap_t;
 imap_t;
 
 
 /* flags for sync_mailbox */
 /* flags for sync_mailbox */
-#define SYNC_FAST	(1<<0)	/* don't sync flags, only fetch new msgs */
-#define	SYNC_DELETE	(1<<1)	/* delete local that don't exist on server */
-#define SYNC_EXPUNGE	(1<<2)	/* don't fetch deleted messages */
+#define	SYNC_DELETE	(1<<0)	/* delete local that don't exist on server */
+#define SYNC_EXPUNGE	(1<<1)	/* don't fetch deleted messages */
 
 
 extern config_t global;
 extern config_t global;
 extern unsigned int Tag;
 extern unsigned int Tag;
@@ -142,19 +147,21 @@ extern SSL_CTX *SSLContext;
 
 
 char *next_arg (char **);
 char *next_arg (char **);
 
 
-int sync_mailbox (mailbox_t *, imap_t *, int);
+int sync_mailbox (mailbox_t *, imap_t *, int, unsigned int);
 
 
 void imap_close (imap_t *);
 void imap_close (imap_t *);
 int imap_fetch_message (imap_t *, unsigned int, int);
 int imap_fetch_message (imap_t *, unsigned int, int);
 int imap_set_flags (imap_t *, unsigned int, unsigned int);
 int imap_set_flags (imap_t *, unsigned int, unsigned int);
 int imap_expunge (imap_t *);
 int imap_expunge (imap_t *);
-imap_t *imap_open (config_t *, int);
+imap_t *imap_open (config_t *, unsigned int);
 
 
 mailbox_t *maildir_open (const char *, int fast);
 mailbox_t *maildir_open (const char *, int fast);
 int maildir_expunge (mailbox_t *, int);
 int maildir_expunge (mailbox_t *, int);
 int maildir_sync (mailbox_t *);
 int maildir_sync (mailbox_t *);
 int maildir_set_uidvalidity (mailbox_t *, unsigned int uidvalidity);
 int maildir_set_uidvalidity (mailbox_t *, unsigned int uidvalidity);
 
 
+message_t * find_msg (message_t * list, unsigned int uid);
+
 /* parse an IMAP list construct */
 /* parse an IMAP list construct */
 list_t * parse_list (char *s, char **end);
 list_t * parse_list (char *s, char **end);
 int is_atom (list_t *list);
 int is_atom (list_t *list);

+ 2 - 0
isyncrc.sample

@@ -6,6 +6,8 @@
 User me
 User me
 #Port	143
 #Port	143
 #Box	INBOX
 #Box	INBOX
+# don't download messages larger than 200K bytes
+MaxSize	200000
 
 
 ###
 ###
 ### work mailbox
 ### work mailbox

+ 162 - 12
maildir.c

@@ -25,8 +25,38 @@
 #include <fcntl.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <unistd.h>
+#include <sys/stat.h>
+#include <errno.h>
 #include "isync.h"
 #include "isync.h"
 
 
+static int
+do_lock (int fd, int flag)
+{
+    struct flock lck;
+    struct stat sb;
+
+    if (fstat (fd, &sb))
+    {
+	perror ("fstat");
+	return -1;
+    }
+
+    memset (&lck, 0, sizeof (lck));
+    lck.l_type = flag;
+    lck.l_whence = SEEK_SET;
+    lck.l_start = 0;
+    lck.l_len = sb.st_size;
+
+    if (fcntl (fd, F_SETLK, &lck))
+    {
+	perror ("fcntl");
+	close (fd);
+	return -1;
+    }
+
+    return 0;
+}
+
 /* 2,<flags> */
 /* 2,<flags> */
 static void
 static void
 parse_info (message_t * m, char *s)
 parse_info (message_t * m, char *s)
@@ -49,6 +79,45 @@ parse_info (message_t * m, char *s)
     }
     }
 }
 }
 
 
+static unsigned int
+read_uid (const char *path, const char *file)
+{
+    char full[_POSIX_PATH_MAX];
+    int fd;
+    int ret;
+    int len;
+    char buf[64];
+    unsigned int uid = 0;
+
+    snprintf (full, sizeof (full), "%s/%s", path, file);
+    fd = open (full, O_RDONLY);
+    if (fd == -1)
+    {
+	if (errno != ENOENT)
+	{
+	    perror ("open");
+	    return -1;
+	}
+	return 0;	/* doesn't exist */
+    }
+    ret = do_lock (fd, F_RDLCK);
+    if (!ret)
+    {
+	len = read (fd, buf, sizeof (buf) - 1);
+	if (len == -1)
+	    ret = -1;
+	else
+	{
+	    buf[len] = 0;
+	    uid = atol (buf);
+	}
+    }
+    ret |= do_lock (fd, F_UNLCK);
+    close (fd);
+    return ret ? ret : uid;
+
+}
+
 /* open a maildir mailbox.  if `fast' is nonzero, we just check to make
 /* open a maildir mailbox.  if `fast' is nonzero, we just check to make
  * sure its a valid mailbox and don't actually parse it.  any IMAP messages
  * sure its a valid mailbox and don't actually parse it.  any IMAP messages
  * with the \Recent flag set are guaranteed not to be in the mailbox yet,
  * with the \Recent flag set are guaranteed not to be in the mailbox yet,
@@ -66,7 +135,6 @@ maildir_open (const char *path, int fast)
     mailbox_t *m;
     mailbox_t *m;
     char *s;
     char *s;
     int count = 0;
     int count = 0;
-    FILE *fp;
 
 
     /* check to make sure this looks like a valid maildir box */
     /* check to make sure this looks like a valid maildir box */
     snprintf (buf, sizeof (buf), "%s/new", path);
     snprintf (buf, sizeof (buf), "%s/new", path);
@@ -84,16 +152,22 @@ maildir_open (const char *path, int fast)
 
 
     m = calloc (1, sizeof (mailbox_t));
     m = calloc (1, sizeof (mailbox_t));
     m->path = strdup (path);
     m->path = strdup (path);
-    m->uidvalidity = -1;
 
 
     /* check for the uidvalidity value */
     /* check for the uidvalidity value */
-    snprintf (buf, sizeof (buf), "%s/isyncuidvalidity", path);
-    if ((fp = fopen (buf, "r")))
+    m->uidvalidity = read_uid (path, "isyncuidvalidity");
+    if (m->uidvalidity == (unsigned int) -1)
     {
     {
-	buf[sizeof (buf) - 1] = 0;
-	if (fgets (buf, sizeof (buf) - 1, fp))
-	    m->uidvalidity = atol (buf);
-	fclose (fp);
+	free (m->path);
+	free (m);
+	return NULL;
+    }
+
+    /* load the current maxuid */
+    if ((m->maxuid = read_uid (path, "isyncmaxuid")) == (unsigned int) -1)
+    {
+	free (m->path);
+	free (m);
+	return NULL;
     }
     }
 
 
     if (fast)
     if (fast)
@@ -108,6 +182,8 @@ maildir_open (const char *path, int fast)
 	d = opendir (buf);
 	d = opendir (buf);
 	if (!d)
 	if (!d)
 	{
 	{
+	    free (m->path);
+	    free (m);
 	    perror ("opendir");
 	    perror ("opendir");
 	    return 0;
 	    return 0;
 	}
 	}
@@ -130,10 +206,15 @@ maildir_open (const char *path, int fast)
 	     */
 	     */
 	    s = strstr (p->file, "UID");
 	    s = strstr (p->file, "UID");
 	    if (!s)
 	    if (!s)
-		puts ("warning, no uid for message");
+		puts ("Warning, no uid for message");
 	    else
 	    else
 	    {
 	    {
 		p->uid = strtol (s + 3, &s, 10);
 		p->uid = strtol (s + 3, &s, 10);
+		if (p->uid > m->maxuid)
+		{
+		    m->maxuid = p->uid;
+		    m->maxuidchanged = 1;
+		}
 		if (*s && *s != ':')
 		if (*s && *s != ':')
 		{
 		{
 		    puts ("warning, unable to parse uid");
 		    puts ("warning, unable to parse uid");
@@ -183,6 +264,70 @@ maildir_expunge (mailbox_t * mbox, int dead)
     return 0;
     return 0;
 }
 }
 
 
+static int
+update_maxuid (mailbox_t * mbox)
+{
+    int fd;
+    char buf[64];
+    size_t len;
+    unsigned int uid;
+    char path[_POSIX_PATH_MAX];
+    int ret = 0;
+
+    snprintf (path, sizeof (path), "%s/isyncmaxuid", mbox->path);
+    fd = open (path, O_RDWR | O_CREAT, 0600);
+    if (fd == -1)
+    {
+	perror ("open");
+	return -1;
+    }
+
+    /* lock the file */
+    if (do_lock (fd, F_WRLCK))
+    {
+	close (fd);
+	return -1;
+    }
+
+    /* read the file again just to make sure it wasn't updated while
+     * we were doing something else
+     */
+    len = read (fd, buf, sizeof (buf) - 1);
+    buf[len] = 0;
+    uid = atol (buf);
+    if (uid > mbox->maxuid)
+    {
+	puts ("Error, maxuid is now higher (fatal)");
+	ret = -1;
+    }
+
+    if (!ret)
+    {
+	/* rewind */
+	lseek (fd, 0, SEEK_SET);
+
+	/* write out the file */
+	snprintf (buf, sizeof (buf), "%u\n", mbox->maxuid);
+	len = write (fd, buf, strlen (buf));
+	if (len == (size_t) - 1)
+	{
+	    perror ("write");
+	    ret = -1;
+	}
+	else
+	{
+	    ret = ftruncate (fd, len);
+	    if (ret)
+		perror ("ftruncate");
+	}
+    }
+
+    ret |= do_lock (fd, F_UNLCK);
+    ret |= close (fd);
+
+    return ret;
+}
+
 int
 int
 maildir_sync (mailbox_t * mbox)
 maildir_sync (mailbox_t * mbox)
 {
 {
@@ -190,6 +335,7 @@ maildir_sync (mailbox_t * mbox)
     char path[_POSIX_PATH_MAX];
     char path[_POSIX_PATH_MAX];
     char oldpath[_POSIX_PATH_MAX];
     char oldpath[_POSIX_PATH_MAX];
     char *p;
     char *p;
+    int ret = 0;
 
 
     if (mbox->changed)
     if (mbox->changed)
     {
     {
@@ -219,7 +365,11 @@ maildir_sync (mailbox_t * mbox)
 	    }
 	    }
 	}
 	}
     }
     }
-    return 0;
+
+    if (mbox->maxuidchanged)
+	ret = update_maxuid (mbox);
+
+    return ret;
 }
 }
 
 
 int
 int
@@ -242,7 +392,7 @@ maildir_set_uidvalidity (mailbox_t * mbox, unsigned int uidvalidity)
     ret = write (fd, buf, strlen (buf));
     ret = write (fd, buf, strlen (buf));
 
 
     if (ret == -1)
     if (ret == -1)
-	perror("write");
+	perror ("write");
     else if ((size_t) ret != strlen (buf))
     else if ((size_t) ret != strlen (buf))
 	ret = -1;
 	ret = -1;
     else
     else
@@ -250,7 +400,7 @@ maildir_set_uidvalidity (mailbox_t * mbox, unsigned int uidvalidity)
 
 
     if (close (fd))
     if (close (fd))
     {
     {
-	perror("close");
+	perror ("close");
 	ret = -1;
 	ret = -1;
     }
     }
 
 

+ 13 - 6
main.c

@@ -95,6 +95,7 @@ config_defaults (config_t * conf)
     conf->port = global.port;
     conf->port = global.port;
     conf->box = global.box;
     conf->box = global.box;
     conf->host = global.host;
     conf->host = global.host;
+    conf->max_size = global.max_size;
 #if HAVE_LIBSSL
 #if HAVE_LIBSSL
     conf->require_ssl = global.require_ssl;
     conf->require_ssl = global.require_ssl;
     conf->use_imaps = global.use_imaps;
     conf->use_imaps = global.use_imaps;
@@ -206,6 +207,13 @@ load_config (char *where)
 	    if (*cur)
 	    if (*cur)
 		(*cur)->alias = strdup (p);
 		(*cur)->alias = strdup (p);
 	}
 	}
+	else if (!strncasecmp ("maxsize", buf, 7))
+	{
+	    if (*cur)
+		(*cur)->max_size = atol (p);
+	    else
+		global.max_size = atol (p);
+	}
 #if HAVE_LIBSSL
 #if HAVE_LIBSSL
 	else if (!strncasecmp ("CertificateFile", buf, 15))
 	else if (!strncasecmp ("CertificateFile", buf, 15))
 	{
 	{
@@ -285,6 +293,7 @@ main (int argc, char **argv)
     global.port = 143;
     global.port = 143;
     global.box = "INBOX";
     global.box = "INBOX";
     global.user = strdup (pw->pw_name);
     global.user = strdup (pw->pw_name);
+    global.max_size = 100000;
 #if HAVE_LIBSSL
 #if HAVE_LIBSSL
     /* this will probably annoy people, but its the best default just in
     /* this will probably annoy people, but its the best default just in
      * case people forget to turn it on
      * case people forget to turn it on
@@ -380,16 +389,14 @@ main (int argc, char **argv)
 	exit (1);
 	exit (1);
     }
     }
 
 
-    imap = imap_open (box, fast);
+    imap = imap_open (box, fast ? mail->maxuid + 1 : 1);
     if (!imap)
     if (!imap)
 	exit (1);
 	exit (1);
 
 
     puts ("Synchronizing");
     puts ("Synchronizing");
-    i = 0;
-    i |= (fast) ? SYNC_FAST : 0;
-    i |= (delete) ? SYNC_DELETE : 0;
-    i |= (expunge) ? SYNC_EXPUNGE : 0;
-    if (sync_mailbox (mail, imap, i))
+    i = delete ? SYNC_DELETE : 0;
+    i |= expunge ? SYNC_EXPUNGE : 0;
+    if (sync_mailbox (mail, imap, i, box->max_size))
 	exit (1);
 	exit (1);
 
 
     if (!fast)
     if (!fast)

+ 34 - 22
sync.c

@@ -31,7 +31,7 @@
 
 
 static unsigned int MaildirCount = 0;
 static unsigned int MaildirCount = 0;
 
 
-static message_t *
+message_t *
 find_msg (message_t * list, unsigned int uid)
 find_msg (message_t * list, unsigned int uid)
 {
 {
     for (; list; list = list->next)
     for (; list; list = list->next)
@@ -41,7 +41,7 @@ find_msg (message_t * list, unsigned int uid)
 }
 }
 
 
 int
 int
-sync_mailbox (mailbox_t * mbox, imap_t * imap, int flags)
+sync_mailbox (mailbox_t * mbox, imap_t * imap, int flags, unsigned int max_size)
 {
 {
     message_t *cur;
     message_t *cur;
     message_t *tmp;
     message_t *tmp;
@@ -69,12 +69,21 @@ sync_mailbox (mailbox_t * mbox, imap_t * imap, int flags)
 	return -1;
 	return -1;
     }
     }
 
 
+    if (mbox->maxuid == (unsigned int) -1 || imap->maxuid > mbox->maxuid)
+    {
+	mbox->maxuid = imap->maxuid;
+	mbox->maxuidchanged = 1;
+    }
+
+    /* if we are --fast mode, the mailbox wont have been loaded, so
+     * this next step is skipped.
+     */
     for (cur = mbox->msgs; cur; cur = cur->next)
     for (cur = mbox->msgs; cur; cur = cur->next)
     {
     {
 	tmp = find_msg (imap->msgs, cur->uid);
 	tmp = find_msg (imap->msgs, cur->uid);
 	if (!tmp)
 	if (!tmp)
 	{
 	{
-	    printf ("warning, uid %d doesn't exist on server\n", cur->uid);
+	    printf ("Warning, uid %d doesn't exist on server\n", cur->uid);
 	    if (flags & SYNC_DELETE)
 	    if (flags & SYNC_DELETE)
 	    {
 	    {
 		cur->flags |= D_DELETED;
 		cur->flags |= D_DELETED;
@@ -85,25 +94,22 @@ sync_mailbox (mailbox_t * mbox, imap_t * imap, int flags)
 	}
 	}
 	tmp->processed = 1;
 	tmp->processed = 1;
 
 
-	if (!(flags & SYNC_FAST))
+	/* check if local flags are different from server flags.
+	 * ignore \Recent and \Draft
+	 */
+	if (cur->flags != (tmp->flags & ~(D_RECENT | D_DRAFT)))
 	{
 	{
-	    /* check if local flags are different from server flags.
-	     * ignore \Recent and \Draft
-	     */
-	    if (cur->flags != (tmp->flags & ~(D_RECENT | D_DRAFT)))
-	    {
-		/* set local flags that don't exist on the server */
-		if (!(tmp->flags & D_DELETED) && (cur->flags & D_DELETED))
-		    imap->deleted++;
-		imap_set_flags (imap, cur->uid, cur->flags & ~tmp->flags);
-
-		/* update local flags */
-		if((cur->flags & D_DELETED) == 0 && (tmp->flags & D_DELETED))
-		    mbox->deleted++;
-		cur->flags |= (tmp->flags & ~(D_RECENT | D_DRAFT));
-		cur->changed = 1;
-		mbox->changed = 1;
-	    }
+	    /* set local flags that don't exist on the server */
+	    if (!(tmp->flags & D_DELETED) && (cur->flags & D_DELETED))
+		imap->deleted++;
+	    imap_set_flags (imap, cur->uid, cur->flags & ~tmp->flags);
+
+	    /* update local flags */
+	    if((cur->flags & D_DELETED) == 0 && (tmp->flags & D_DELETED))
+		mbox->deleted++;
+	    cur->flags |= (tmp->flags & ~(D_RECENT | D_DRAFT));
+	    cur->changed = 1;
+	    mbox->changed = 1;
 	}
 	}
     }
     }
 
 
@@ -124,6 +130,13 @@ sync_mailbox (mailbox_t * mbox, imap_t * imap, int flags)
 		continue;
 		continue;
 	    }
 	    }
 
 
+	    if (max_size && cur->size > max_size)
+	    {
+		printf ("Warning, message skipped because it is too big (%u)\n",
+			cur->size);
+		continue;
+	    }
+
 	    for (;;)
 	    for (;;)
 	    {
 	    {
 		/* create new file */
 		/* create new file */
@@ -150,7 +163,6 @@ sync_mailbox (mailbox_t * mbox, imap_t * imap, int flags)
 			  (cur->flags & D_ANSWERED) ? "R" : "",
 			  (cur->flags & D_ANSWERED) ? "R" : "",
 			  (cur->flags & D_SEEN) ? "S" : "",
 			  (cur->flags & D_SEEN) ? "S" : "",
 			  (cur->flags & D_DELETED) ? "T" : "");
 			  (cur->flags & D_DELETED) ? "T" : "");
-
 	    }
 	    }
 
 
 	    /* give some visual feedback that something is happening */
 	    /* give some visual feedback that something is happening */