Przeglądaj źródła

fix error paths wrt sync drivers

Oswald Buddenhagen 18 lat temu
rodzic
commit
023d3ee577
4 zmienionych plików z 198 dodań i 246 usunięć
  1. 26 29
      src/drv_imap.c
  2. 55 90
      src/drv_maildir.c
  3. 14 14
      src/isync.h
  4. 103 113
      src/sync.c

+ 26 - 29
src/drv_imap.c

@@ -1426,7 +1426,6 @@ imap_open_store( store_conf_t *conf,
   bail:
 	imap_cancel_store( &ctx->gen );
 	cb( 0, aux );
-	return;
 }
 
 static void
@@ -1442,9 +1441,9 @@ imap_prepare_opts( store_t *gctx, int opts )
 	gctx->opts = opts;
 }
 
-static void
+static int
 imap_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs,
-             void (*cb)( int sts, void *aux ), void *aux )
+             int (*cb)( int sts, void *aux ), void *aux )
 {
 	imap_store_t *ctx = (imap_store_t *)gctx;
 	const char *prefix;
@@ -1499,20 +1498,20 @@ imap_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs,
   bail:
 	if (excs)
 		free( excs );
-	cb( ret, aux );
+	return cb( ret, aux );
 }
 
-static void
+static int
 imap_fetch_msg( store_t *ctx, message_t *msg, msg_data_t *data,
-                void (*cb)( int sts, void *aux ), void *aux )
+                int (*cb)( int sts, void *aux ), void *aux )
 {
 	struct imap_cmd_cb cbd;
 
 	memset( &cbd, 0, sizeof(cbd) );
 	cbd.uid = msg->uid;
 	cbd.ctx = data;
-	cb( imap_exec_m( (imap_store_t *)ctx, &cbd, "UID FETCH %d (%sBODY.PEEK[])",
-	                 msg->uid, (msg->status & M_FLAGS) ? "" : "FLAGS " ), aux );
+	return cb( imap_exec_m( (imap_store_t *)ctx, &cbd, "UID FETCH %d (%sBODY.PEEK[])",
+	                        msg->uid, (msg->status & M_FLAGS) ? "" : "FLAGS " ), aux );
 }
 
 static int
@@ -1542,9 +1541,9 @@ imap_flags_helper( imap_store_t *ctx, int uid, char what, int flags)
 	return issue_imap_cmd_w( ctx, 0, "UID STORE %d %cFLAGS.SILENT %s", uid, what, buf ) ? DRV_OK : DRV_STORE_BAD;
 }
 
-static void
+static int
 imap_set_flags( store_t *gctx, message_t *msg, int uid, int add, int del,
-                void (*cb)( int sts, void *aux ), void *aux )
+                int (*cb)( int sts, void *aux ), void *aux )
 {
 	imap_store_t *ctx = (imap_store_t *)gctx;
 	int ret;
@@ -1559,32 +1558,32 @@ imap_set_flags( store_t *gctx, message_t *msg, int uid, int add, int del,
 	if ((!add || (ret = imap_flags_helper( ctx, uid, '+', add )) == DRV_OK) &&
 	    (!del || (ret = imap_flags_helper( ctx, uid, '-', del )) == DRV_OK))
 		ret = DRV_OK;
-	cb( ret, aux );
+	return cb( ret, aux );
 }
 
-static void
+static int
 imap_close( store_t *ctx,
-            void (*cb)( int sts, void *aux ), void *aux )
+            int (*cb)( int sts, void *aux ), void *aux )
 {
-	cb( imap_exec_b( (imap_store_t *)ctx, 0, "CLOSE" ), aux );
+	return cb( imap_exec_b( (imap_store_t *)ctx, 0, "CLOSE" ), aux );
 }
 
-static void
+static int
 imap_trash_msg( store_t *gctx, message_t *msg,
-                void (*cb)( int sts, void *aux ), void *aux )
+                int (*cb)( int sts, void *aux ), void *aux )
 {
 	imap_store_t *ctx = (imap_store_t *)gctx;
 	struct imap_cmd_cb cbd;
 
 	memset( &cbd, 0, sizeof(cbd) );
 	cbd.create = 1;
-	cb( imap_exec_m( ctx, &cbd, "UID COPY %d \"%s%s\"",
-	                 msg->uid, ctx->prefix, gctx->conf->trash ), aux );
+	return cb( imap_exec_m( ctx, &cbd, "UID COPY %d \"%s%s\"",
+	                        msg->uid, ctx->prefix, gctx->conf->trash ), aux );
 }
 
-static void
+static int
 imap_store_msg( store_t *gctx, msg_data_t *data, int to_trash,
-                void (*cb)( int sts, int uid, void *aux ), void *aux )
+                int (*cb)( int sts, int uid, void *aux ), void *aux )
 {
 	imap_store_t *ctx = (imap_store_t *)gctx;
 	struct imap_cmd_cb cbd;
@@ -1620,22 +1619,20 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int to_trash,
 	}
 	ret = imap_exec_m( ctx, &cbd, "APPEND \"%s%s\" %s", prefix, box, flagstr );
 	ctx->caps = ctx->rcaps;
-	if (ret != DRV_OK) {
-		cb( ret, -1, aux );
-		return;
-	}
+	if (ret != DRV_OK)
+		return cb( ret, -1, aux );
 	if (to_trash)
 		ctx->trashnc = 0;
 	else {
 		/*ctx->currentnc = 0;*/
 	}
 
-	cb( DRV_OK, uid, aux );
+	return cb( DRV_OK, uid, aux );
 }
 
-static void
+static int
 imap_find_msg( store_t *gctx, const char *tuid,
-               void (*cb)( int sts, int uid, void *aux ), void *aux )
+               int (*cb)( int sts, int uid, void *aux ), void *aux )
 {
 	imap_store_t *ctx = (imap_store_t *)gctx;
 	struct imap_cmd_cb cbd;
@@ -1646,9 +1643,9 @@ imap_find_msg( store_t *gctx, const char *tuid,
 	cbd.ctx = &uid;
 	uid = -1; /* in case we get no SEARCH response at all */
 	if ((ret = imap_exec_m( ctx, &cbd, "UID SEARCH HEADER X-TUID %." stringify(TUIDL) "s", tuid )) != DRV_OK)
-		cb( ret, -1, aux );
+		return cb( ret, -1, aux );
 	else
-		cb( uid <= 0 ? DRV_MSG_BAD : DRV_OK, uid, aux );
+		return cb( uid <= 0 ? DRV_MSG_BAD : DRV_OK, uid, aux );
 }
 
 static void

+ 55 - 90
src/drv_maildir.c

@@ -767,9 +767,9 @@ maildir_prepare_opts( store_t *gctx, int opts )
 	gctx->opts = opts;
 }
 
-static void
+static int
 maildir_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs,
-                void (*cb)( int sts, void *aux ), void *aux )
+                int (*cb)( int sts, void *aux ), void *aux )
 {
 	maildir_store_t *ctx = (maildir_store_t *)gctx;
 	message_t **msgapp;
@@ -785,17 +785,14 @@ maildir_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs,
 	ctx->excs = nfrealloc( excs, nexcs * sizeof(int) );
 	ctx->nexcs = nexcs;
 
-	if (maildir_validate( gctx->path, "", ctx->gen.opts & OPEN_CREATE ) != DRV_OK) {
-		cb( DRV_BOX_BAD, aux );
-		return;
-	}
+	if (maildir_validate( gctx->path, "", ctx->gen.opts & OPEN_CREATE ) != DRV_OK)
+		return cb( DRV_BOX_BAD, aux );
 
 	nfsnprintf( uvpath, sizeof(uvpath), "%s/.uidvalidity", gctx->path );
 #ifndef USE_DB
 	if ((ctx->uvfd = open( uvpath, O_RDWR|O_CREAT, 0600 )) < 0) {
 		perror( uvpath );
-		cb( DRV_BOX_BAD, aux );
-		return;
+		return cb( DRV_BOX_BAD, aux );
 	}
 #else
 	if ((ctx->uvfd = open( uvpath, O_RDWR, 0600 )) < 0) {
@@ -810,8 +807,7 @@ maildir_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs,
 					goto fnok;
 			}
 			perror( uvpath );
-			cb( DRV_BOX_BAD, aux );
-			return;
+			return cb( DRV_BOX_BAD, aux );
 		}
 	  dbok:
 #if SEEK_SET != 0
@@ -823,8 +819,7 @@ maildir_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs,
 		  bork:
 			close( ctx->uvfd );
 			ctx->uvfd = -1;
-			cb( DRV_BOX_BAD, aux );
-			return;
+			return cb( DRV_BOX_BAD, aux );
 		}
 		if (db_create( &ctx->db, 0, 0 )) {
 			fputs( "Maildir error: db_create() failed\n", stderr );
@@ -854,16 +849,14 @@ maildir_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs,
   fnok:
 #endif /* USE_DB */
 
-	if (maildir_scan( ctx, &msglist ) != DRV_OK) {
-		cb( DRV_BOX_BAD, aux );
-		return;
-	}
+	if (maildir_scan( ctx, &msglist ) != DRV_OK)
+		return cb( DRV_BOX_BAD, aux );
 	msgapp = &ctx->gen.msgs;
 	for (i = 0; i < msglist.nents; i++)
 		maildir_app_msg( ctx, &msgapp, msglist.ents + i );
 	maildir_free_scan( &msglist );
 
-	cb( DRV_OK, aux );
+	return cb( DRV_OK, aux );
 }
 
 static int
@@ -931,9 +924,9 @@ maildir_again( maildir_store_t *ctx, maildir_message_t *msg, const char *fn )
 	return (msg->gen.status & M_DEAD) ? DRV_MSG_BAD : DRV_OK;
 }
 
-static void
+static int
 maildir_fetch_msg( store_t *gctx, message_t *gmsg, msg_data_t *data,
-                   void (*cb)( int sts, void *aux ), void *aux )
+                   int (*cb)( int sts, void *aux ), void *aux )
 {
 	maildir_store_t *ctx = (maildir_store_t *)gctx;
 	maildir_message_t *msg = (maildir_message_t *)gmsg;
@@ -945,10 +938,8 @@ maildir_fetch_msg( store_t *gctx, message_t *gmsg, msg_data_t *data,
 		nfsnprintf( buf, sizeof(buf), "%s/%s/%s", gctx->path, subdirs[gmsg->status & M_RECENT], msg->base );
 		if ((fd = open( buf, O_RDONLY )) >= 0)
 			break;
-		if ((ret = maildir_again( ctx, msg, buf )) != DRV_OK) {
-			cb( ret, aux );
-			return;
-		}
+		if ((ret = maildir_again( ctx, msg, buf )) != DRV_OK)
+			return cb( ret, aux );
 	}
 	fstat( fd, &st );
 	data->len = st.st_size;
@@ -956,13 +947,12 @@ maildir_fetch_msg( store_t *gctx, message_t *gmsg, msg_data_t *data,
 	if (read( fd, data->data, data->len ) != data->len) {
 		perror( buf );
 		close( fd );
-		cb( DRV_MSG_BAD, aux );
-		return;
+		return cb( DRV_MSG_BAD, aux );
 	}
 	close( fd );
 	if (!(gmsg->status & M_FLAGS))
 		data->flags = maildir_parse_flags( msg->base );
-	cb( DRV_OK, aux );
+	return cb( DRV_OK, aux );
 }
 
 static int
@@ -980,9 +970,9 @@ maildir_make_flags( int flags, char *buf )
 	return d;
 }
 
-static void
+static int
 maildir_store_msg( store_t *gctx, msg_data_t *data, int to_trash,
-                   void (*cb)( int sts, int uid, void *aux ), void *aux )
+                   int (*cb)( int sts, int uid, void *aux ), void *aux )
 {
 	maildir_store_t *ctx = (maildir_store_t *)gctx;
 	const char *prefix, *box;
@@ -995,17 +985,14 @@ maildir_store_msg( store_t *gctx, msg_data_t *data, int to_trash,
 		if (ctx->db) {
 			if ((ret = maildir_set_uid( ctx, base, &uid )) != DRV_OK) {
 				free( data->data );
-				cb( ret, 0, aux );
-				return;
+				return cb( ret, 0, aux );
 			}
 		} else
 #endif /* USE_DB */
 		{
 			if ((ret = maildir_uidval_lock( ctx )) != DRV_OK ||
-			    (ret = maildir_obtain_uid( ctx, &uid )) != DRV_OK) {
-				cb( ret, 0, aux );
-				return;
-			}
+			    (ret = maildir_obtain_uid( ctx, &uid )) != DRV_OK)
+				return cb( ret, 0, aux );
 			maildir_uidval_unlock( ctx );
 			nfsnprintf( base + bl, sizeof(base) - bl, ",U=%d", uid );
 		}
@@ -1022,19 +1009,16 @@ maildir_store_msg( store_t *gctx, msg_data_t *data, int to_trash,
 		if (errno != ENOENT) {
 			perror( buf );
 			free( data->data );
-			cb( DRV_BOX_BAD, 0, aux );
-			return;
+			return cb( DRV_BOX_BAD, 0, aux );
 		}
 		if ((ret = maildir_validate( gctx->conf->path, gctx->conf->trash, gctx->opts & OPEN_CREATE )) != DRV_OK) {
 			free( data->data );
-			cb( ret, 0, aux );
-			return;
+			return cb( ret, 0, aux );
 		}
 		if ((fd = open( buf, O_WRONLY|O_CREAT|O_EXCL, 0600 )) < 0) {
 			perror( buf );
 			free( data->data );
-			cb( DRV_BOX_BAD, 0, aux );
-			return;
+			return cb( DRV_BOX_BAD, 0, aux );
 		}
 	}
 	ret = write( fd, data->data, data->len );
@@ -1045,38 +1029,34 @@ maildir_store_msg( store_t *gctx, msg_data_t *data, int to_trash,
 		else
 			error( "Maildir error: %s: partial write\n", buf );
 		close( fd );
-		cb( DRV_BOX_BAD, 0, aux );
-		return;
+		return cb( DRV_BOX_BAD, 0, aux );
 	}
 	close( fd );
 	/* Moving seen messages to cur/ is strictly speaking incorrect, but makes mutt happy. */
 	nfsnprintf( nbuf, sizeof(nbuf), "%s%s/%s/%s%s", prefix, box, subdirs[!(data->flags & F_SEEN)], base, fbuf );
 	if (rename( buf, nbuf )) {
 		perror( nbuf );
-		cb( DRV_BOX_BAD, 0, aux );
-		return;
+		return cb( DRV_BOX_BAD, 0, aux );
 	}
-	cb( DRV_OK, uid, aux );
+	return cb( DRV_OK, uid, aux );
 }
 
-static void
+static int
 maildir_find_msg( store_t *gctx, const char *tuid,
-                  void (*cb)( int sts, int uid, void *aux ), void *aux )
+                  int (*cb)( int sts, int uid, void *aux ), void *aux )
 {
 	message_t *msg;
 
 	/* using a hash table might turn out to be more appropriate ... */
 	for (msg = gctx->msgs; msg; msg = msg->next)
-		if (!(msg->status & M_DEAD) && !memcmp( ((maildir_message_t *)msg)->tuid, tuid, TUIDL )) {
-			cb( DRV_OK, msg->uid, aux );
-			return;
-		}
-	cb( DRV_MSG_BAD, -1, aux );
+		if (!(msg->status & M_DEAD) && !memcmp( ((maildir_message_t *)msg)->tuid, tuid, TUIDL ))
+			return cb( DRV_OK, msg->uid, aux );
+	return cb( DRV_MSG_BAD, -1, aux );
 }
 
-static void
+static int
 maildir_set_flags( store_t *gctx, message_t *gmsg, int uid, int add, int del,
-                   void (*cb)( int sts, void *aux ), void *aux )
+                   int (*cb)( int sts, void *aux ), void *aux )
 {
 	maildir_store_t *ctx = (maildir_store_t *)gctx;
 	maildir_message_t *msg = (maildir_message_t *)gmsg;
@@ -1118,10 +1098,8 @@ maildir_set_flags( store_t *gctx, message_t *gmsg, int uid, int add, int del,
 		}
 		if (!rename( buf, nbuf ))
 			break;
-		if ((ret = maildir_again( ctx, msg, buf )) != DRV_OK) {
-			cb( ret, aux );
-			return;
-		}
+		if ((ret = maildir_again( ctx, msg, buf )) != DRV_OK)
+			return cb( ret, aux );
 	}
 	free( msg->base );
 	msg->base = nfmalloc( tl + 1 );
@@ -1130,7 +1108,7 @@ maildir_set_flags( store_t *gctx, message_t *gmsg, int uid, int add, int del,
 	msg->gen.flags &= ~del;
 	gmsg->status &= ~M_RECENT;
 
-	cb( DRV_OK, aux );
+	return cb( DRV_OK, aux );
 }
 
 #ifdef USE_DB
@@ -1150,9 +1128,9 @@ maildir_purge_msg( maildir_store_t *ctx, const char *name )
 }
 #endif /* USE_DB */
 
-static void
+static int
 maildir_trash_msg( store_t *gctx, message_t *gmsg,
-                   void (*cb)( int sts, void *aux ), void *aux )
+                   int (*cb)( int sts, void *aux ), void *aux )
 {
 	maildir_store_t *ctx = (maildir_store_t *)gctx;
 	maildir_message_t *msg = (maildir_message_t *)gmsg;
@@ -1169,38 +1147,31 @@ maildir_trash_msg( store_t *gctx, message_t *gmsg,
 		if (!rename( buf, nbuf ))
 			break;
 		if (!stat( buf, &st )) {
-			if ((ret = maildir_validate( gctx->conf->path, gctx->conf->trash, 1 )) != DRV_OK) {
-				cb( ret, aux );
-				return;
-			}
+			if ((ret = maildir_validate( gctx->conf->path, gctx->conf->trash, 1 )) != DRV_OK)
+				return cb( ret, aux );
 			if (!rename( buf, nbuf ))
 				break;
 			if (errno != ENOENT) {
 				perror( nbuf );
-				cb( DRV_BOX_BAD, aux );
-				return;
+				return cb( DRV_BOX_BAD, aux );
 			}
 		}
-		if ((ret = maildir_again( ctx, msg, buf )) != DRV_OK) {
-			cb( ret, aux );
-			return;
-		}
+		if ((ret = maildir_again( ctx, msg, buf )) != DRV_OK)
+			return cb( ret, aux );
 	}
 	gmsg->status |= M_DEAD;
 	gctx->count--;
 
 #ifdef USE_DB
-	if (ctx->db) {
-		cb( maildir_purge_msg( ctx, msg->base ), aux );
-		return;
-	}
+	if (ctx->db)
+		return cb( maildir_purge_msg( ctx, msg->base ), aux );
 #endif /* USE_DB */
-	cb( DRV_OK, aux );
+	return cb( DRV_OK, aux );
 }
 
-static void
+static int
 maildir_close( store_t *gctx,
-               void (*cb)( int sts, void *aux ), void *aux )
+               int (*cb)( int sts, void *aux ), void *aux )
 {
 #ifdef USE_DB
 	maildir_store_t *ctx = (maildir_store_t *)gctx;
@@ -1224,21 +1195,15 @@ maildir_close( store_t *gctx,
 					msg->status |= M_DEAD;
 					gctx->count--;
 #ifdef USE_DB
-					if (ctx->db && (ret = maildir_purge_msg( ctx, ((maildir_message_t *)msg)->base )) != DRV_OK) {
-						cb( ret, aux );
-						return;
-					}
+					if (ctx->db && (ret = maildir_purge_msg( ctx, ((maildir_message_t *)msg)->base )) != DRV_OK)
+						return cb( ret, aux );
 #endif /* USE_DB */
 				}
 			}
-		if (!retry) {
-			cb( DRV_OK, aux );
-			return;
-		}
-		if ((ret = maildir_rescan( (maildir_store_t *)gctx )) != DRV_OK) {
-			cb( ret, aux );
-			return;
-		}
+		if (!retry)
+			return cb( DRV_OK, aux );
+		if ((ret = maildir_rescan( (maildir_store_t *)gctx )) != DRV_OK)
+			return cb( ret, aux );
 	}
 }
 

+ 14 - 14
src/isync.h

@@ -191,20 +191,20 @@ struct driver {
 	              void (*cb)( int sts, void *aux ), void *aux );
 	void (*prepare_paths)( store_t *ctx );
 	void (*prepare_opts)( store_t *ctx, int opts );
-	void (*select)( store_t *ctx, int minuid, int maxuid, int *excs, int nexcs,
-	                void (*cb)( int sts, void *aux ), void *aux );
-	void (*fetch_msg)( store_t *ctx, message_t *msg, msg_data_t *data,
-	                   void (*cb)( int sts, void *aux ), void *aux );
-	void (*store_msg)( store_t *ctx, msg_data_t *data, int to_trash,
-	                   void (*cb)( int sts, int uid, void *aux ), void *aux );
-	void (*find_msg)( store_t *ctx, const char *tuid,
-	                  void (*cb)( int sts, int uid, void *aux ), void *aux );
-	void (*set_flags)( store_t *ctx, message_t *msg, int uid, int add, int del, /* msg can be null, therefore uid as a fallback */
-	                   void (*cb)( int sts, void *aux ), void *aux );
-	void (*trash_msg)( store_t *ctx, message_t *msg, /* This may expunge the original message immediately, but it needn't to */
-	                   void (*cb)( int sts, void *aux ), void *aux );
-	void (*close)( store_t *ctx, /* IMAP-style: expunge inclusive */
-	               void (*cb)( int sts, void *aux ), void *aux );
+	int (*select)( store_t *ctx, int minuid, int maxuid, int *excs, int nexcs,
+	               int (*cb)( int sts, void *aux ), void *aux );
+	int (*fetch_msg)( store_t *ctx, message_t *msg, msg_data_t *data,
+	                  int (*cb)( int sts, void *aux ), void *aux );
+	int (*store_msg)( store_t *ctx, msg_data_t *data, int to_trash,
+	                  int (*cb)( int sts, int uid, void *aux ), void *aux );
+	int (*find_msg)( store_t *ctx, const char *tuid,
+	                 int (*cb)( int sts, int uid, void *aux ), void *aux );
+	int (*set_flags)( store_t *ctx, message_t *msg, int uid, int add, int del, /* msg can be null, therefore uid as a fallback */
+	                  int (*cb)( int sts, void *aux ), void *aux );
+	int (*trash_msg)( store_t *ctx, message_t *msg, /* This may expunge the original message immediately, but it needn't to */
+	                  int (*cb)( int sts, void *aux ), void *aux );
+	int (*close)( store_t *ctx, /* IMAP-style: expunge inclusive */
+	              int (*cb)( int sts, void *aux ), void *aux );
 	void (*cancel)( store_t *ctx, /* only not yet sent commands */
 	                void (*cb)( int sts, void *aux ), void *aux );
 	void (*commit)( store_t *ctx );

+ 103 - 113
src/sync.c

@@ -152,7 +152,7 @@ typedef struct {
 	int flags_total[2], flags_done[2];
 	int trash_total[2], trash_done[2];
 	int maxuid[2], uidval[2], smaxxuid, lfd;
-	unsigned find:1, cancel:1;
+	unsigned find:1;
 } sync_vars_t;
 
 #define AUX &svars->t[t]
@@ -185,27 +185,27 @@ typedef struct {
 
 
 typedef struct copy_vars {
-	void (*cb)( int sts, int uid, struct copy_vars *vars );
+	int (*cb)( int sts, int uid, struct copy_vars *vars );
 	void *aux;
 	sync_rec_t *srec; /* also ->tuid */
 	message_t *msg;
 	msg_data_t data;
 } copy_vars_t;
 
-static void msg_fetched( int sts, void *aux );
+static int msg_fetched( int sts, void *aux );
 
-static void
+static int
 copy_msg( copy_vars_t *vars )
 {
 	SVARS(vars->aux)
 
 	vars->data.flags = vars->msg->flags;
-	svars->drv[1-t]->fetch_msg( svars->ctx[1-t], vars->msg, &vars->data, msg_fetched, vars );
+	return svars->drv[1-t]->fetch_msg( svars->ctx[1-t], vars->msg, &vars->data, msg_fetched, vars );
 }
 
-static void msg_stored( int sts, int uid, void *aux );
+static int msg_stored( int sts, int uid, void *aux );
 
-static void
+static int
 msg_fetched( int sts, void *aux )
 {
 	copy_vars_t *vars = (copy_vars_t *)aux;
@@ -254,8 +254,7 @@ msg_fetched( int sts, void *aux )
 				}
 				/* invalid message */
 				free( fmap );
-				vars->cb( SYNC_NOGOOD, 0, vars );
-				break;
+				return vars->cb( SYNC_NOGOOD, 0, vars );
 			}
 		  oke:
 			if (cra || crd)
@@ -310,24 +309,19 @@ msg_fetched( int sts, void *aux )
 			free( fmap );
 		}
 
-		svars->drv[t]->store_msg( svars->ctx[t], &vars->data, !vars->srec, msg_stored, vars );
-		break;
+		return svars->drv[t]->store_msg( svars->ctx[t], &vars->data, !vars->srec, msg_stored, vars );
 	case DRV_CANCELED:
-		vars->cb( SYNC_CANCELED, 0, vars );
-		break;
+		return vars->cb( SYNC_CANCELED, 0, vars );
 	case DRV_MSG_BAD:
-		vars->cb( SYNC_NOGOOD, 0, vars );
-		break;
+		return vars->cb( SYNC_NOGOOD, 0, vars );
 	case DRV_STORE_BAD:
-		vars->cb( SYNC_BAD(1-t), 0, vars );
-		break;
+		return vars->cb( SYNC_BAD(1-t), 0, vars );
 	default:
-		vars->cb( SYNC_FAIL, 0, vars );
-		break;
+		return vars->cb( SYNC_FAIL, 0, vars );
 	}
 }
 
-static void
+static int
 msg_stored( int sts, int uid, void *aux )
 {
 	copy_vars_t *vars = (copy_vars_t *)aux;
@@ -336,17 +330,13 @@ msg_stored( int sts, int uid, void *aux )
 	(void)svars;
 	switch (sts) {
 	case DRV_OK:
-		vars->cb( SYNC_OK, uid, vars );
-		break;
+		return vars->cb( SYNC_OK, uid, vars );
 	case DRV_CANCELED:
-		vars->cb( SYNC_CANCELED, 0, vars );
-		break;
+		return vars->cb( SYNC_CANCELED, 0, vars );
 	case DRV_STORE_BAD:
-		vars->cb( SYNC_BAD(t), 0, vars );
-		break;
+		return vars->cb( SYNC_BAD(t), 0, vars );
 	default:
-		vars->cb( SYNC_FAIL, 0, vars );
-		break;
+		return vars->cb( SYNC_FAIL, 0, vars );
 	}
 }
 
@@ -387,7 +377,7 @@ cancel_sync( sync_vars_t *svars )
 {
 	int t;
 
-	svars->cancel = 1;
+	/* the 1st round is guaranteed not to trash svars */
 	for (t = 0; t < 2; t++)
 		if (svars->ret & SYNC_BAD(t))
 			cancel_done( DRV_STORE_BAD, AUX );
@@ -457,7 +447,7 @@ clean_strdup( const char *s )
 
 #define JOURNAL_VERSION "2"
 
-static void select_box( sync_vars_t *svars, int t, int minwuid, int *mexcs, int nmexcs );
+static int select_box( sync_vars_t *svars, int t, int minwuid, int *mexcs, int nmexcs );
 
 void
 sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan,
@@ -494,6 +484,7 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan,
 	if (!strcmp( chan->sync_state ? chan->sync_state : global_sync_state, "*" )) {
 		if (!ctx[S]->path) {
 			error( "Error: store '%s' does not support in-box sync state\n", chan->stores[S]->name );
+			free( svars );
 			cb( SYNC_BAD(S), aux );
 			return;
 		}
@@ -513,6 +504,7 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan,
 	if (!(s = strrchr( svars->dname, '/' ))) {
 		error( "Error: invalid SyncState '%s'\n", svars->dname );
 		free( svars->dname );
+		free( svars );
 		cb( SYNC_BAD(S), aux );
 		return;
 	}
@@ -520,6 +512,7 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan,
 	if (mkdir( svars->dname, 0700 ) && errno != EEXIST) {
 		error( "Error: cannot create SyncState directory '%s': %s\n", svars->dname, strerror(errno) );
 		free( svars->dname );
+		free( svars );
 		cb( SYNC_BAD(S), aux );
 		return;
 	}
@@ -823,14 +816,14 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan,
 	svars->drv[S]->prepare_opts( ctx[S], opts[S] );
 
 	svars->find = line != 0;
-	if (!svars->smaxxuid)
-		select_box( svars, M, (ctx[M]->opts & OPEN_OLD) ? 1 : INT_MAX, 0, 0 );
+	if (!svars->smaxxuid && select_box( svars, M, (ctx[M]->opts & OPEN_OLD) ? 1 : INT_MAX, 0, 0 ))
+		return;
 	select_box( svars, S, (ctx[S]->opts & OPEN_OLD) ? 1 : INT_MAX, 0, 0 );
 }
 
-static void box_selected( int sts, void *aux );
+static int box_selected( int sts, void *aux );
 
-static void
+static int
 select_box( sync_vars_t *svars, int t, int minwuid, int *mexcs, int nmexcs )
 {
 	sync_rec_t *srec;
@@ -849,7 +842,7 @@ select_box( sync_vars_t *svars, int t, int minwuid, int *mexcs, int nmexcs )
 		maxwuid = 0;
 	info( "Selecting %s %s...\n", str_ms[t], svars->ctx[t]->name );
 	debug( maxwuid == INT_MAX ? "selecting %s [%d,inf]\n" : "selecting %s [%d,%d]\n", str_ms[t], minwuid, maxwuid );
-	svars->drv[t]->select( svars->ctx[t], minwuid, maxwuid, mexcs, nmexcs, box_selected, AUX );
+	return svars->drv[t]->select( svars->ctx[t], minwuid, maxwuid, mexcs, nmexcs, box_selected, AUX );
 }
 
 typedef struct {
@@ -857,10 +850,10 @@ typedef struct {
 	sync_rec_t *srec;
 } find_vars_t;
 
-static void msg_found_sel( int sts, int uid, void *aux );
-static void msgs_found_sel( sync_vars_t *svars, int t );
+static int msg_found_sel( int sts, int uid, void *aux );
+static int msgs_found_sel( sync_vars_t *svars, int t );
 
-static void
+static int
 box_selected( int sts, void *aux )
 {
 	SVARS(aux)
@@ -868,13 +861,13 @@ box_selected( int sts, void *aux )
 	sync_rec_t *srec;
 
 	if (check_ret( sts, svars, t ))
-		return;
+		return 1;
 	if (svars->uidval[t] && svars->uidval[t] != svars->ctx[t]->uidvalidity) {
 		error( "Error: UIDVALIDITY of %s changed (got %d, expected %d)\n",
 		         str_ms[t], svars->ctx[t]->uidvalidity, svars->uidval[t] );
 		svars->ret |= SYNC_FAIL;
 		cancel_sync( svars );
-		return;
+		return 1;
 	}
 	info( "%s: %d messages, %d recent\n", str_ms[t], svars->ctx[t]->count, svars->ctx[t]->recent );
 
@@ -897,24 +890,23 @@ box_selected( int sts, void *aux )
 				fv = nfmalloc( sizeof(*fv) );
 				fv->aux = AUX;
 				fv->srec = srec;
-				svars->drv[t]->find_msg( svars->ctx[t], srec->tuid, msg_found_sel, fv );
-				if (svars->cancel)
-					return;
+				if (svars->drv[t]->find_msg( svars->ctx[t], srec->tuid, msg_found_sel, fv ))
+					return 1;
 			}
 		}
 	}
 	svars->state[t] |= ST_SENT_FIND_OLD;
-	msgs_found_sel( svars, t );
+	return msgs_found_sel( svars, t );
 }
 
-static void
+static int
 msg_found_sel( int sts, int uid, void *aux )
 {
 	find_vars_t *vars = (find_vars_t *)aux;
 	SVARS(vars->aux)
 
 	if (check_ret_aux( sts, svars, t, vars ))
-		return;
+		return 1;
 	switch (sts) {
 	case DRV_OK:
 		debug( "  -> new UID %d\n", uid );
@@ -932,7 +924,7 @@ msg_found_sel( int sts, int uid, void *aux )
 	free( vars );
 	svars->find_old_done[t]++;
 	stats( svars );
-	msgs_found_sel( svars, t );
+	return msgs_found_sel( svars, t );
 }
 
 typedef struct {
@@ -941,15 +933,15 @@ typedef struct {
 	int aflags, dflags;
 } flag_vars_t;
 
-static void flags_set_del( int sts, void *aux );
-static void flags_set_sync( int sts, void *aux );
+static int flags_set_del( int sts, void *aux );
+static int flags_set_sync( int sts, void *aux );
 static void flags_set_sync_p2( sync_vars_t *svars, sync_rec_t *srec, int t );
-static void msgs_flags_set( sync_vars_t *svars, int t );
-static void msg_copied( int sts, int uid, copy_vars_t *vars );
+static int msgs_flags_set( sync_vars_t *svars, int t );
+static int msg_copied( int sts, int uid, copy_vars_t *vars );
 static void msg_copied_p2( sync_vars_t *svars, sync_rec_t *srec, int t, message_t *tmsg, int uid );
-static void msgs_copied( sync_vars_t *svars, int t );
+static int msgs_copied( sync_vars_t *svars, int t );
 
-static void
+static int
 msgs_found_sel( sync_vars_t *svars, int t )
 {
 	sync_rec_t *srec, *nsrec = 0;
@@ -962,7 +954,7 @@ msgs_found_sel( sync_vars_t *svars, int t )
 	char fbuf[16]; /* enlarge when support for keywords is added */
 
 	if (!(svars->state[t] & ST_SENT_FIND_OLD) || svars->find_old_done[t] < svars->find_new_total[t])
-		return;
+		return 0;
 
 	/*
 	 * Mapping tmsg -> srec (this variant) is dog slow for new messages.
@@ -1058,12 +1050,11 @@ msgs_found_sel( sync_vars_t *svars, int t )
 		for (t = 0; t < nmexcs; t++)
 			debugn( " %d", mexcs[t] );
 		debug( "\n" );
-		select_box( svars, M, minwuid, mexcs, nmexcs );
-		return;
+		return select_box( svars, M, minwuid, mexcs, nmexcs );
 	}
 
 	if (!(svars->state[1-t] & ST_SENT_FIND_OLD) || svars->find_old_done[1-t] < svars->find_new_total[1-t])
-		return;
+		return 0;
 
 	if (!svars->uidval[M] || !svars->uidval[S]) {
 		svars->uidval[M] = svars->ctx[M]->uidvalidity;
@@ -1118,9 +1109,8 @@ msgs_found_sel( sync_vars_t *svars, int t )
 						cv->msg = tmsg;
 						Fprintf( svars->jfp, "# %d %d %." stringify(TUIDL) "s\n", srec->uid[M], srec->uid[S], srec->tuid );
 						debug( "  -> %sing message, TUID %." stringify(TUIDL) "s\n", str_hl[t], srec->tuid );
-						copy_msg( cv );
-						if (svars->cancel)
-							return;
+						if (copy_msg( cv ))
+							return 1;
 					} else {
 						if (tmsg->srec) {
 							debug( "  -> not %sing - still too big\n", str_hl[t] );
@@ -1132,7 +1122,8 @@ msgs_found_sel( sync_vars_t *svars, int t )
 				}
 			}
 		svars->state[t] |= ST_SENT_NEW;
-		msgs_copied( svars, t );
+		if (msgs_copied( svars, t ))
+			return 1;
 	}
 
 	debug( "synchronizing old entries\n" );
@@ -1170,9 +1161,8 @@ msgs_found_sel( sync_vars_t *svars, int t )
 						fv = nfmalloc( sizeof(*fv) );
 						fv->aux = AUX;
 						fv->srec = srec;
-						svars->drv[t]->set_flags( svars->ctx[t], srec->msg[t], srec->uid[t], F_DELETED, 0, flags_set_del, fv );
-						if (svars->cancel)
-							return;
+						if (svars->drv[t]->set_flags( svars->ctx[t], srec->msg[t], srec->uid[t], F_DELETED, 0, flags_set_del, fv ))
+							return 1;
 					} else
 						debug( "  not %sing delete\n", str_hl[t] );
 				} else if (!srec->msg[1-t])
@@ -1282,9 +1272,8 @@ msgs_found_sel( sync_vars_t *svars, int t )
 				fv->srec = srec;
 				fv->aflags = aflags;
 				fv->dflags = dflags;
-				svars->drv[t]->set_flags( svars->ctx[t], srec->msg[t], srec->uid[t], aflags, dflags, flags_set_sync, fv );
-				if (svars->cancel)
-					return;
+				if (svars->drv[t]->set_flags( svars->ctx[t], srec->msg[t], srec->uid[t], aflags, dflags, flags_set_sync, fv ))
+					return 1;
 			} else
 				flags_set_sync_p2( svars, srec, t );
 		}
@@ -1292,11 +1281,13 @@ msgs_found_sel( sync_vars_t *svars, int t )
 	for (t = 0; t < 2; t++) {
 		svars->drv[t]->commit( svars->ctx[t] );
 		svars->state[t] |= ST_SENT_FLAGS;
-		msgs_flags_set( svars, t );
+		if (msgs_flags_set( svars, t ))
+			return 1;
 	}
+	return 0;
 }
 
-static void
+static int
 msg_copied( int sts, int uid, copy_vars_t *vars )
 {
 	SVARS(vars->aux)
@@ -1314,12 +1305,12 @@ msg_copied( int sts, int uid, copy_vars_t *vars )
 		cancel_sync( svars );
 	case SYNC_CANCELED:
 		free( vars );
-		return;
+		return 1;
 	}
 	free( vars );
 	svars->new_done[t]++;
 	stats( svars );
-	msgs_copied( svars, t );
+	return msgs_copied( svars, t );
 }
 
 static void
@@ -1340,17 +1331,17 @@ msg_copied_p2( sync_vars_t *svars, sync_rec_t *srec, int t, message_t *tmsg, int
 	}
 }
 
-static void msg_found_new( int sts, int uid, void *aux );
-static void sync_close( sync_vars_t *svars, int t );
+static int msg_found_new( int sts, int uid, void *aux );
+static int sync_close( sync_vars_t *svars, int t );
 
-static void
+static int
 msgs_copied( sync_vars_t *svars, int t )
 {
 	sync_rec_t *srec;
 	find_vars_t *fv;
 
 	if (!(svars->state[t] & ST_SENT_NEW) || svars->new_done[t] < svars->new_total[t])
-		return;
+		return 0;
 
 	debug( "finding just copied messages on %s\n", str_ms[t] );
 	for (srec = svars->srecs; srec; srec = srec->next) {
@@ -1363,23 +1354,22 @@ msgs_copied( sync_vars_t *svars, int t )
 			fv = nfmalloc( sizeof(*fv) );
 			fv->aux = AUX;
 			fv->srec = srec;
-			svars->drv[t]->find_msg( svars->ctx[t], srec->tuid, msg_found_new, fv );
-			if (svars->cancel)
-				return;
+			if (svars->drv[t]->find_msg( svars->ctx[t], srec->tuid, msg_found_new, fv ))
+				return 1;
 		}
 	}
 	svars->state[t] |= ST_SENT_FIND_NEW;
-	sync_close( svars, t );
+	return sync_close( svars, t );
 }
 
-static void
+static int
 msg_found_new( int sts, int uid, void *aux )
 {
 	find_vars_t *vars = (find_vars_t *)aux;
 	SVARS(vars->aux)
 
 	if (check_ret_aux( sts, svars, t, vars ))
-		return;
+		return 1;
 	switch (sts) {
 	case DRV_OK:
 		debug( "  -> new UID %d\n", uid );
@@ -1395,17 +1385,17 @@ msg_found_new( int sts, int uid, void *aux )
 	free( vars );
 	svars->find_new_done[t]++;
 	stats( svars );
-	sync_close( svars, t );
+	return sync_close( svars, t );
 }
 
-static void
+static int
 flags_set_del( int sts, void *aux )
 {
 	flag_vars_t *vars = (flag_vars_t *)aux;
 	SVARS(vars->aux)
 
 	if (check_ret_aux( sts, svars, t, vars ))
-		return;
+		return 1;
 	switch (sts) {
 	case DRV_OK:
 		vars->srec->status |= S_DEL(t);
@@ -1416,17 +1406,17 @@ flags_set_del( int sts, void *aux )
 	free( vars );
 	svars->flags_done[t]++;
 	stats( svars );
-	msgs_flags_set( svars, t );
+	return msgs_flags_set( svars, t );
 }
 
-static void
+static int
 flags_set_sync( int sts, void *aux )
 {
 	flag_vars_t *vars = (flag_vars_t *)aux;
 	SVARS(vars->aux)
 
 	if (check_ret_aux( sts, svars, t, vars ))
-		return;
+		return 1;
 	switch (sts) {
 	case DRV_OK:
 		if (vars->aflags & F_DELETED)
@@ -1439,7 +1429,7 @@ flags_set_sync( int sts, void *aux )
 	free( vars );
 	svars->flags_done[t]++;
 	stats( svars );
-	msgs_flags_set( svars, t );
+	return msgs_flags_set( svars, t );
 }
 
 static void
@@ -1469,17 +1459,17 @@ flags_set_sync_p2( sync_vars_t *svars, sync_rec_t *srec, int t )
 	}
 }
 
-static void msg_trashed( int sts, void *aux );
-static void msg_rtrashed( int sts, int uid, copy_vars_t *vars );
+static int msg_trashed( int sts, void *aux );
+static int msg_rtrashed( int sts, int uid, copy_vars_t *vars );
 
-static void
+static int
 msgs_flags_set( sync_vars_t *svars, int t )
 {
 	message_t *tmsg;
 	copy_vars_t *cv;
 
 	if (!(svars->state[t] & ST_SENT_FLAGS) || svars->flags_done[t] < svars->flags_total[t])
-		return;
+		return 0;
 
 	if ((svars->chan->ops[t] & OP_EXPUNGE) &&
 	    (svars->ctx[t]->conf->trash || (svars->ctx[1-t]->conf->trash && svars->ctx[1-t]->conf->trash_remote_new))) {
@@ -1491,9 +1481,8 @@ msgs_flags_set( sync_vars_t *svars, int t )
 						debug( "%s: trashing message %d\n", str_ms[t], tmsg->uid );
 						svars->trash_total[t]++;
 						stats( svars );
-						svars->drv[t]->trash_msg( svars->ctx[t], tmsg, msg_trashed, AUX );
-						if (svars->cancel)
-							return;
+						if (svars->drv[t]->trash_msg( svars->ctx[t], tmsg, msg_trashed, AUX ))
+							return 1;
 					} else
 						debug( "%s: not trashing message %d - not new\n", str_ms[t], tmsg->uid );
 				} else {
@@ -1507,9 +1496,8 @@ msgs_flags_set( sync_vars_t *svars, int t )
 							cv->aux = AUX;
 							cv->srec = 0;
 							cv->msg = tmsg;
-							copy_msg( cv );
-							if (svars->cancel)
-								return;
+							if (copy_msg( cv ))
+								return 1;
 						} else
 							debug( "%s: not remote trashing message %d - too big\n", str_ms[t], tmsg->uid );
 					} else
@@ -1518,10 +1506,10 @@ msgs_flags_set( sync_vars_t *svars, int t )
 			}
 	}
 	svars->state[t] |= ST_SENT_TRASH;
-	sync_close( svars, t );
+	return sync_close( svars, t );
 }
 
-static void
+static int
 msg_trashed( int sts, void *aux )
 {
 	SVARS(aux)
@@ -1529,13 +1517,13 @@ msg_trashed( int sts, void *aux )
 	if (sts == DRV_MSG_BAD)
 		sts = DRV_BOX_BAD;
 	if (check_ret( sts, svars, t ))
-		return;
+		return 1;
 	svars->trash_done[t]++;
 	stats( svars );
-	sync_close( svars, t );
+	return sync_close( svars, t );
 }
 
-static void
+static int
 msg_rtrashed( int sts, int uid, copy_vars_t *vars )
 {
 	SVARS(vars->aux)
@@ -1549,41 +1537,43 @@ msg_rtrashed( int sts, int uid, copy_vars_t *vars )
 		cancel_sync( svars );
 	case SYNC_CANCELED:
 		free( vars );
-		return;
+		return 1;
 	}
 	free( vars );
 	svars->trash_done[t]++;
 	stats( svars );
-	sync_close( svars, t );
+	return sync_close( svars, t );
 }
 
-static void box_closed( int sts, void *aux );
+static int box_closed( int sts, void *aux );
 static void box_closed_p2( sync_vars_t *svars, int t );
 
-static void
+static int
 sync_close( sync_vars_t *svars, int t )
 {
 	if ((~svars->state[t] & (ST_SENT_FIND_NEW|ST_SENT_TRASH)) ||
 	    svars->find_new_done[t] < svars->find_new_total[t] ||
 	    svars->trash_done[t] < svars->trash_total[t])
-		return;
+		return 0;
 
 	if ((svars->chan->ops[t] & OP_EXPUNGE) /*&& !(svars->state[t] & ST_TRASH_BAD)*/) {
 		debug( "expunging %s\n", str_ms[t] );
-		svars->drv[t]->close( svars->ctx[t], box_closed, AUX );
-	} else
-		box_closed_p2( svars, t );
+		return svars->drv[t]->close( svars->ctx[t], box_closed, AUX );
+	}
+	box_closed_p2( svars, t );
+	return 0;
 }
 
-static void
+static int
 box_closed( int sts, void *aux )
 {
 	SVARS(aux)
 
 	if (check_ret( sts, svars, t ))
-		return;
+		return 1;
 	svars->state[t] |= ST_DID_EXPUNGE;
 	box_closed_p2( svars, t );
+	return 0;
 }
 
 static void