Browse Source

async merge: aggregate most variables of main() & sync_boxes() in
main_vars_t resp. sync_vars_t.
also some minor var renames, whitespace, comments.

Oswald Buddenhagen 19 years ago
parent
commit
b5d70aa596
2 changed files with 373 additions and 340 deletions
  1. 151 131
      src/main.c
  2. 222 209
      src/sync.c

+ 151 - 131
src/main.c

@@ -186,18 +186,27 @@ merge_actions( channel_conf_t *chan, int ops[], int have, int mask, int def )
 	}
 }
 
+typedef struct {
+	int t[2];
+	channel_conf_t *chan;
+	driver_t *drv[2];
+	store_t *ctx[2];
+	string_list_t *boxes[2], *cboxes, *chanptr;
+	const char *names[2];
+	char **argv, *boxlist, *boxp;
+	int oind, ret, multiple, all, list, ops[2], state[2];
+	unsigned done:1, skip:1, cben:1;
+} main_vars_t;
+
+static void sync_chans( main_vars_t *mvars );
+
 int
 main( int argc, char **argv )
 {
-	channel_conf_t *chan;
+	main_vars_t mvars[1];
 	group_conf_t *group;
-	driver_t *driver[2];
-	store_t *ctx[2];
-	string_list_t *boxes[2], *mbox, *sbox, **mboxp, **sboxp, *cboxes, *chanptr;
-	char *config = 0, *channame, *boxlist, *boxp, *opt, *ochar;
-	const char *names[2];
-	int all = 0, list = 0, cops = 0, ops[2] = { 0, 0 };
-	int oind, ret, op, multiple, pseudo = 0, t;
+	char *config = 0, *opt, *ochar;
+	int cops = 0, op, pseudo = 0;
 
 	gethostname( Hostname, sizeof(Hostname) );
 	if ((ochar = strchr( Hostname, '.' )))
@@ -210,26 +219,28 @@ main( int argc, char **argv )
 	Ontty = isatty( 1 ) && isatty( 2 );
 	arc4_init();
 
-	for (oind = 1, ochar = 0; oind < argc; ) {
+	memset( mvars, 0, sizeof(*mvars) );
+
+	for (mvars->oind = 1, ochar = 0; mvars->oind < argc; ) {
 		if (!ochar || !*ochar) {
-			if (argv[oind][0] != '-')
+			if (argv[mvars->oind][0] != '-')
 				break;
-			if (argv[oind][1] == '-') {
-				opt = argv[oind++] + 2;
+			if (argv[mvars->oind][1] == '-') {
+				opt = argv[mvars->oind++] + 2;
 				if (!*opt)
 					break;
 				if (!strcmp( opt, "config" )) {
-					if (oind >= argc) {
+					if (mvars->oind >= argc) {
 						error( "--config requires an argument.\n" );
 						return 1;
 					}
-					config = argv[oind++];
+					config = argv[mvars->oind++];
 				} else if (!memcmp( opt, "config=", 7 ))
 					config = opt + 7;
 				else if (!strcmp( opt, "all" ))
-					all = 1;
+					mvars->all = 1;
 				else if (!strcmp( opt, "list" ))
-					list = 1;
+					mvars->list = 1;
 				else if (!strcmp( opt, "help" ))
 					usage( 0 );
 				else if (!strcmp( opt, "version" ))
@@ -244,9 +255,9 @@ main( int argc, char **argv )
 				else if (!strcmp( opt, "debug" ))
 					DFlags |= DEBUG | QUIET;
 				else if (!strcmp( opt, "pull" ))
-					cops |= XOP_PULL, ops[M] |= XOP_HAVE_TYPE;
+					cops |= XOP_PULL, mvars->ops[M] |= XOP_HAVE_TYPE;
 				else if (!strcmp( opt, "push" ))
-					cops |= XOP_PUSH, ops[M] |= XOP_HAVE_TYPE;
+					cops |= XOP_PUSH, mvars->ops[M] |= XOP_HAVE_TYPE;
 				else if (!memcmp( opt, "create", 6 )) {
 					opt += 6;
 					op = OP_CREATE|XOP_HAVE_CREATE;
@@ -254,24 +265,24 @@ main( int argc, char **argv )
 					if (!*opt)
 						cops |= op;
 					else if (!strcmp( opt, "-master" ))
-						ops[M] |= op, ochar++;
+						mvars->ops[M] |= op, ochar++;
 					else if (!strcmp( opt, "-slave" ))
-						ops[S] |= op, ochar++;
+						mvars->ops[S] |= op, ochar++;
 					else
 						goto badopt;
-					ops[M] |= op & (XOP_HAVE_CREATE|XOP_HAVE_EXPUNGE);
+					mvars->ops[M] |= op & (XOP_HAVE_CREATE|XOP_HAVE_EXPUNGE);
 				} else if (!memcmp( opt, "expunge", 7 )) {
 					opt += 7;
 					op = OP_EXPUNGE|XOP_HAVE_EXPUNGE;
 					goto lcop;
 				} else if (!strcmp( opt, "no-expunge" ))
-					ops[M] |= XOP_HAVE_EXPUNGE;
+					mvars->ops[M] |= XOP_HAVE_EXPUNGE;
 				else if (!strcmp( opt, "no-create" ))
-					ops[M] |= XOP_HAVE_CREATE;
+					mvars->ops[M] |= XOP_HAVE_CREATE;
 				else if (!strcmp( opt, "full" ))
-					ops[M] |= XOP_HAVE_TYPE|XOP_PULL|XOP_PUSH;
+					mvars->ops[M] |= XOP_HAVE_TYPE|XOP_PULL|XOP_PUSH;
 				else if (!strcmp( opt, "noop" ))
-					ops[M] |= XOP_HAVE_TYPE;
+					mvars->ops[M] |= XOP_HAVE_TYPE;
 				else if (!memcmp( opt, "pull", 4 )) {
 					op = XOP_PULL;
 				  lcac:
@@ -299,19 +310,19 @@ main( int argc, char **argv )
 						op |= OP_FLAGS;
 					else {
 					  badopt:
-						error( "Unknown option '%s'\n", argv[oind - 1] );
+						error( "Unknown option '%s'\n", argv[mvars->oind - 1] );
 						return 1;
 					}
 					switch (op & XOP_MASK_DIR) {
-					case XOP_PULL: ops[S] |= op & OP_MASK_TYPE; break;
-					case XOP_PUSH: ops[M] |= op & OP_MASK_TYPE; break;
+					case XOP_PULL: mvars->ops[S] |= op & OP_MASK_TYPE; break;
+					case XOP_PUSH: mvars->ops[M] |= op & OP_MASK_TYPE; break;
 					default: cops |= op; break;
 					}
-					ops[M] |= XOP_HAVE_TYPE;
+					mvars->ops[M] |= XOP_HAVE_TYPE;
 				}
 				continue;
 			}
-			ochar = argv[oind++] + 1;
+			ochar = argv[mvars->oind++] + 1;
 			if (!*ochar) {
 				error( "Invalid option '-'\n" );
 				return 1;
@@ -319,34 +330,34 @@ main( int argc, char **argv )
 		}
 		switch (*ochar++) {
 		case 'a':
-			all = 1;
+			mvars->all = 1;
 			break;
 		case 'l':
-			list = 1;
+			mvars->list = 1;
 			break;
 		case 'c':
 			if (*ochar == 'T') {
 				ochar++;
 				pseudo = 1;
 			}
-			if (oind >= argc) {
+			if (mvars->oind >= argc) {
 				error( "-c requires an argument.\n" );
 				return 1;
 			}
-			config = argv[oind++];
+			config = argv[mvars->oind++];
 			break;
 		case 'C':
 			op = OP_CREATE|XOP_HAVE_CREATE;
 		  cop:
 			if (*ochar == 'm')
-				ops[M] |= op, ochar++;
+				mvars->ops[M] |= op, ochar++;
 			else if (*ochar == 's')
-				ops[S] |= op, ochar++;
+				mvars->ops[S] |= op, ochar++;
 			else if (*ochar == '-')
 				ochar++;
 			else
 				cops |= op;
-			ops[M] |= op & (XOP_HAVE_CREATE|XOP_HAVE_EXPUNGE);
+			mvars->ops[M] |= op & (XOP_HAVE_CREATE|XOP_HAVE_EXPUNGE);
 			break;
 		case 'X':
 			op = OP_EXPUNGE|XOP_HAVE_EXPUNGE;
@@ -354,7 +365,7 @@ main( int argc, char **argv )
 		case 'F':
 			cops |= XOP_PULL|XOP_PUSH;
 		case '0':
-			ops[M] |= XOP_HAVE_TYPE;
+			mvars->ops[M] |= XOP_HAVE_TYPE;
 			break;
 		case 'n':
 		case 'd':
@@ -377,13 +388,13 @@ main( int argc, char **argv )
 			}
 			if (op & OP_MASK_TYPE)
 				switch (op & XOP_MASK_DIR) {
-				case XOP_PULL: ops[S] |= op & OP_MASK_TYPE; break;
-				case XOP_PUSH: ops[M] |= op & OP_MASK_TYPE; break;
+				case XOP_PULL: mvars->ops[S] |= op & OP_MASK_TYPE; break;
+				case XOP_PUSH: mvars->ops[M] |= op & OP_MASK_TYPE; break;
 				default: cops |= op; break;
 				}
 			else
 				cops |= op;
-			ops[M] |= XOP_HAVE_TYPE;
+			mvars->ops[M] |= XOP_HAVE_TYPE;
 			break;
 		case 'L':
 			op = XOP_PULL;
@@ -422,13 +433,13 @@ main( int argc, char **argv )
 		signal( SIGILL, crashHandler );
 	}
 
-	if (merge_ops( cops, ops ))
+	if (merge_ops( cops, mvars->ops ))
 		return 1;
 
 	if (load_config( config, pseudo ))
 		return 1;
 
-	if (!all && !argv[oind]) {
+	if (!mvars->all && !argv[mvars->oind]) {
 		fputs( "No channel specified. Try '" EXE " -h'\n", stderr );
 		return 1;
 	}
@@ -437,88 +448,99 @@ main( int argc, char **argv )
 		return 1;
 	}
 
-	ret = 0;
-	chan = channels;
-	chanptr = 0;
-	if (all)
-		multiple = channels->next != 0;
-	else if (argv[oind + 1])
-		multiple = 1;
-	else {
-		multiple = 0;
+	mvars->chan = channels;
+	if (mvars->all)
+		mvars->multiple = channels->next != 0;
+	else if (argv[mvars->oind + 1])
+		mvars->multiple = 1;
+	else
 		for (group = groups; group; group = group->next)
-			if (!strcmp( group->name, argv[oind] )) {
-				multiple = 1;
+			if (!strcmp( group->name, argv[mvars->oind] )) {
+				mvars->multiple = 1;
 				break;
 			}
-	}
+	mvars->argv = argv;
+	sync_chans( mvars );
+	return mvars->ret;
+}
+
+static void
+sync_chans( main_vars_t *mvars )
+{
+	group_conf_t *group;
+	channel_conf_t *chan;
+	string_list_t *mbox, *sbox, **mboxp, **sboxp;
+	char *channame;
+	int t;
+
 	for (;;) {
-		boxlist = 0;
-		if (!all) {
-			if (chanptr)
-				channame = chanptr->string;
+		mvars->boxlist = 0;
+		if (!mvars->all) {
+			if (mvars->chanptr)
+				channame = mvars->chanptr->string;
 			else {
 				for (group = groups; group; group = group->next)
-					if (!strcmp( group->name, argv[oind] )) {
-						chanptr = group->channels;
-						channame = chanptr->string;
+					if (!strcmp( group->name, mvars->argv[mvars->oind] )) {
+						mvars->chanptr = group->channels;
+						channame = mvars->chanptr->string;
 						goto gotgrp;
 					}
-				channame = argv[oind];
+				channame = mvars->argv[mvars->oind];
 			  gotgrp: ;
 			}
-			if ((boxlist = strchr( channame, ':' )))
-				*boxlist++ = 0;
+			if ((mvars->boxlist = strchr( channame, ':' )))
+				*mvars->boxlist++ = 0;
 			for (chan = channels; chan; chan = chan->next)
 				if (!strcmp( chan->name, channame ))
 					goto gotchan;
 			error( "No channel or group named '%s' defined.\n", channame );
-			ret = 1;
+			mvars->ret = 1;
 			goto gotnone;
-		  gotchan: ;
+		  gotchan:
+			mvars->chan = chan;
 		}
-		merge_actions( chan, ops, XOP_HAVE_TYPE, OP_MASK_TYPE, OP_MASK_TYPE );
-		merge_actions( chan, ops, XOP_HAVE_CREATE, OP_CREATE, 0 );
-		merge_actions( chan, ops, XOP_HAVE_EXPUNGE, OP_EXPUNGE, 0 );
+		merge_actions( mvars->chan, mvars->ops, XOP_HAVE_TYPE, OP_MASK_TYPE, OP_MASK_TYPE );
+		merge_actions( mvars->chan, mvars->ops, XOP_HAVE_CREATE, OP_CREATE, 0 );
+		merge_actions( mvars->chan, mvars->ops, XOP_HAVE_EXPUNGE, OP_EXPUNGE, 0 );
 
-		info( "Channel %s\n", chan->name );
-		boxes[M] = boxes[S] = cboxes = 0;
+		info( "Channel %s\n", mvars->chan->name );
+		mvars->boxes[M] = mvars->boxes[S] = mvars->cboxes = 0;
 		for (t = 0; t < 2; t++) {
-			driver[t] = chan->stores[t]->driver;
-			ctx[t] = driver[t]->own_store( chan->stores[t] );
+			mvars->drv[t] = mvars->chan->stores[t]->driver;
+			mvars->ctx[t] = mvars->drv[t]->own_store( mvars->chan->stores[t] );
 		}
 		for (t = 0; t < 2; t++)
-			if (!ctx[t]) {
-				info( "Opening %s %s...\n", str_ms[t], chan->stores[t]->name );
-				if (!(ctx[t] = driver[t]->open_store( chan->stores[t] ))) {
-					ret = 1;
+			if (!mvars->ctx[t]) {
+				info( "Opening %s %s...\n", str_ms[t], mvars->chan->stores[t]->name );
+				if (!(mvars->ctx[t] = mvars->drv[t]->open_store( mvars->chan->stores[t] ))) {
+					mvars->ret = 1;
 					goto next;
 				}
 			}
-		if (boxlist)
-			boxp = boxlist;
-		else if (chan->patterns) {
+		if (mvars->boxlist)
+			mvars->boxp = mvars->boxlist;
+		else if (mvars->chan->patterns) {
 			for (t = 0; t < 2; t++) {
-				if (!ctx[t]->listed) {
-					if (driver[t]->list( ctx[t] ) != DRV_OK) {
+				if (!mvars->ctx[t]->listed) {
+					if (mvars->drv[t]->list( mvars->ctx[t] ) != DRV_OK) {
 					  screwt:
-						driver[t]->cancel_store( ctx[t] );
-						ctx[t] = 0;
-						ret = 1;
+						mvars->drv[t]->cancel_store( mvars->ctx[t] );
+						mvars->ctx[t] = 0;
+						mvars->ret = 1;
 						goto next;
-					} else if (ctx[t]->conf->map_inbox)
-						add_string_list( &ctx[t]->boxes, ctx[t]->conf->map_inbox );
+					} else if (mvars->ctx[t]->conf->map_inbox)
+						add_string_list( &mvars->ctx[t]->boxes, mvars->ctx[t]->conf->map_inbox );
 				}
-				boxes[t] = filter_boxes( ctx[t]->boxes, chan->patterns );
+				mvars->boxes[t] = filter_boxes( mvars->ctx[t]->boxes, mvars->chan->patterns );
 			}
-			for (mboxp = &boxes[M]; (mbox = *mboxp); ) {
-				for (sboxp = &boxes[S]; (sbox = *sboxp); sboxp = &sbox->next)
+			for (mboxp = &mvars->boxes[M]; (mbox = *mboxp); ) {
+				for (sboxp = &mvars->boxes[S]; (sbox = *sboxp); sboxp = &sbox->next)
 					if (!strcmp( sbox->string, mbox->string )) {
 						*sboxp = sbox->next;
 						free( sbox );
 						*mboxp = mbox->next;
-						mbox->next = cboxes;
-						cboxes = mbox;
+						mbox->next = mvars->cboxes;
+						mvars->cboxes = mbox;
 						goto gotdupe;
 					}
 				mboxp = &mbox->next;
@@ -526,78 +548,76 @@ main( int argc, char **argv )
 			}
 		}
 
-		if (list && multiple)
-			printf( "%s:\n", chan->name );
-		if (boxlist) {
-			while ((names[S] = strsep( &boxp, ",\n" ))) {
-				if (list)
-					puts( names[S] );
+		if (mvars->list && mvars->multiple)
+			printf( "%s:\n", mvars->chan->name );
+		if (mvars->boxlist) {
+			while ((mvars->names[S] = strsep( &mvars->boxp, ",\n" ))) {
+				if (mvars->list)
+					puts( mvars->names[S] );
 				else {
-					names[M] = names[S];
-					switch (sync_boxes( ctx, names, chan )) {
+					mvars->names[M] = mvars->names[S];
+					switch (sync_boxes( mvars->ctx, mvars->names, mvars->chan )) {
 					case SYNC_BAD(M): t = M; goto screwt;
 					case SYNC_BAD(S): t = S; goto screwt;
-					case SYNC_FAIL: ret = 1;
+					case SYNC_FAIL: mvars->ret = 1;
 					}
 				}
 			}
-		} else if (chan->patterns) {
-			for (mbox = cboxes; mbox; mbox = mbox->next)
-				if (list)
+		} else if (mvars->chan->patterns) {
+			for (mbox = mvars->cboxes; mbox; mbox = mbox->next)
+				if (mvars->list)
 					puts( mbox->string );
 				else {
-					names[M] = names[S] = mbox->string;
-					switch (sync_boxes( ctx, names, chan )) {
+					mvars->names[M] = mvars->names[S] = mbox->string;
+					switch (sync_boxes( mvars->ctx, mvars->names, mvars->chan )) {
 					case SYNC_BAD(M): t = M; goto screwt;
 					case SYNC_BAD(S): t = S; goto screwt;
-					case SYNC_FAIL: ret = 1;
+					case SYNC_FAIL: mvars->ret = 1;
 					}
 				}
 			for (t = 0; t < 2; t++)
-				if ((chan->ops[1-t] & OP_MASK_TYPE) && (chan->ops[1-t] & OP_CREATE)) {
-					for (mbox = boxes[t]; mbox; mbox = mbox->next)
-						if (list)
+				if ((mvars->chan->ops[1-t] & OP_MASK_TYPE) && (mvars->chan->ops[1-t] & OP_CREATE)) {
+					for (mbox = mvars->boxes[t]; mbox; mbox = mbox->next)
+						if (mvars->list)
 							puts( mbox->string );
 						else {
-							names[M] = names[S] = mbox->string;
-							switch (sync_boxes( ctx, names, chan )) {
+							mvars->names[M] = mvars->names[S] = mbox->string;
+							switch (sync_boxes( mvars->ctx, mvars->names, mvars->chan )) {
 							case SYNC_BAD(M): t = M; goto screwt;
 							case SYNC_BAD(S): t = S; goto screwt;
-							case SYNC_FAIL: ret = 1;
+							case SYNC_FAIL: mvars->ret = 1;
 							}
 						}
 				}
 		} else
-			if (list)
-				printf( "%s <=> %s\n", chan->boxes[M], chan->boxes[S] );
+			if (mvars->list)
+				printf( "%s <=> %s\n", mvars->chan->boxes[M], mvars->chan->boxes[S] );
 			else
-				switch (sync_boxes( ctx, chan->boxes, chan )) {
+				switch (sync_boxes( mvars->ctx, mvars->chan->boxes, mvars->chan )) {
 				case SYNC_BAD(M): t = M; goto screwt;
 				case SYNC_BAD(S): t = S; goto screwt;
-				case SYNC_FAIL: ret = 1;
+				case SYNC_FAIL: mvars->ret = 1;
 				}
 
 	  next:
-		free_string_list( cboxes );
-		free_string_list( boxes[M] );
-		free_string_list( boxes[S] );
-		if (ctx[M])
-			driver[M]->disown_store( ctx[M] );
-		if (ctx[S])
-			driver[S]->disown_store( ctx[S] );
-		if (all) {
-			if (!(chan = chan->next))
+		if (mvars->ctx[M])
+			mvars->drv[M]->disown_store( mvars->ctx[M] );
+		if (mvars->ctx[S])
+			mvars->drv[S]->disown_store( mvars->ctx[S] );
+		free_string_list( mvars->cboxes );
+		free_string_list( mvars->boxes[M] );
+		free_string_list( mvars->boxes[S] );
+		if (mvars->all) {
+			if (!(mvars->chan = mvars->chan->next))
 				break;
 		} else {
-			if (chanptr && (chanptr = chanptr->next))
+			if (mvars->chanptr && (mvars->chanptr = mvars->chanptr->next))
 				continue;
 		  gotnone:
-			if (!argv[++oind])
+			if (!mvars->argv[++mvars->oind])
 				break;
 		}
 	}
 	for (t = 0; t < N_DRIVERS; t++)
 		drivers[t]->cleanup();
-
-	return ret;
 }

+ 222 - 209
src/sync.c

@@ -353,6 +353,19 @@ copy_msg( store_t *ctx[], int t, message_t *tmsg, const char *tuid, int *uid )
    impossible cases: both uid[M] & uid[S] 0 or -1, both not scanned
 */
 
+typedef struct {
+	char *dname, *jname, *nname, *lname;
+	FILE *jfp, *nfp;
+	sync_rec_t *srecs, **srecadd, **osrecadd;
+	channel_conf_t *chan;
+	store_t *ctx[2];
+	driver_t *drv[2];
+	int state[2], ret;
+	int maxuid[2], uidval[2], smaxxuid, lfd;
+} sync_vars_t;
+
+#define ST_DID_EXPUNGE     (1<<16)
+
 static char *
 clean_strdup( const char *s )
 {
@@ -371,32 +384,33 @@ clean_strdup( const char *s )
 int
 sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
 {
-	driver_t *driver[2];
+	sync_vars_t svars[1];
 	message_t *tmsg;
-	sync_rec_t *recs, *srec, **srecadd, *nsrec, **osrecadd;
-	char *dname, *jname, *nname, *lname, *s, *cmname, *csname;
-	FILE *dfp, *jfp, *nfp;
-	int opts[2];
-	int nom, nos, del[2], ex[2], nex;
-	int uidval[2], smaxxuid, maxuid[2], minwuid;
-	int t1, t2, t3, t, uid, nmsgs;
-	int lfd, ret, line, sline, todel, *mexcs, nmexcs, rmexcs;
+	sync_rec_t *srec, *nsrec;
+	char *s, *cmname, *csname;
+	FILE *jfp;
+	int no[2], del[2], nex, minwuid, uid, nmsgs;
+	int todel, *mexcs, nmexcs, rmexcs;
+	int opts[2], line, t1, t2, t3, t;
 	unsigned char nflags, sflags, aflags, dflags;
 	struct stat st;
 	struct flock lck;
 	char fbuf[16]; /* enlarge when support for keywords is added */
 	char buf[64];
 
-	ret = SYNC_OK;
-	recs = 0, srecadd = &recs;
+	memset( svars, 0, sizeof(svars[0]) );
+	svars->ctx[0] = ctx[0];
+	svars->ctx[1] = ctx[1];
+	svars->chan = chan;
+	svars->srecadd = &svars->srecs;
 
 	for (t = 0; t < 2; t++) {
 		ctx[t]->name =
 			(!names[t] || (ctx[t]->conf->map_inbox && !strcmp( ctx[t]->conf->map_inbox, names[t] ))) ?
 				"INBOX" : names[t];
 		ctx[t]->uidvalidity = 0;
-		driver[t] = ctx[t]->conf->driver;
-		driver[t]->prepare_paths( ctx[t] );
+		svars->drv[t] = ctx[t]->conf->driver;
+		svars->drv[t]->prepare_paths( ctx[t] );
 	}
 
 	if (!strcmp( chan->sync_state ? chan->sync_state : global_sync_state, "*" )) {
@@ -404,35 +418,34 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
 			error( "Error: store '%s' does not support in-box sync state\n", chan->stores[S]->name );
 			return SYNC_BAD(S);
 		}
-		nfasprintf( &dname, "%s/." EXE "state", ctx[S]->path );
+		nfasprintf( &svars->dname, "%s/." EXE "state", ctx[S]->path );
 	} else {
 		csname = clean_strdup( ctx[S]->name );
 		if (chan->sync_state)
-			nfasprintf( &dname, "%s%s", chan->sync_state, csname );
+			nfasprintf( &svars->dname, "%s%s", chan->sync_state, csname );
 		else {
 			cmname = clean_strdup( ctx[M]->name );
-			nfasprintf( &dname, "%s:%s:%s_:%s:%s", global_sync_state,
+			nfasprintf( &svars->dname, "%s:%s:%s_:%s:%s", global_sync_state,
 			            chan->stores[M]->name, cmname, chan->stores[S]->name, csname );
 			free( cmname );
 		}
 		free( csname );
 	}
-	if (!(s = strrchr( dname, '/' ))) {
-		error( "Error: invalid SyncState '%s'\n", dname );
-		free( dname );
+	if (!(s = strrchr( svars->dname, '/' ))) {
+		error( "Error: invalid SyncState '%s'\n", svars->dname );
+		free( svars->dname );
 		return SYNC_BAD(S);
 	}
 	*s = 0;
-	if (mkdir( dname, 0700 ) && errno != EEXIST) {
-		error( "Error: cannot create SyncState directory '%s': %s\n", dname, strerror(errno) );
-		free( dname );
+	if (mkdir( svars->dname, 0700 ) && errno != EEXIST) {
+		error( "Error: cannot create SyncState directory '%s': %s\n", svars->dname, strerror(errno) );
+		free( svars->dname );
 		return SYNC_BAD(S);
 	}
 	*s = '/';
-	nfasprintf( &jname, "%s.journal", dname );
-	nfasprintf( &nname, "%s.new", dname );
-	nfasprintf( &lname, "%s.lock", dname );
-	uidval[M] = uidval[S] = smaxxuid = maxuid[M] = maxuid[S] = 0;
+	nfasprintf( &svars->jname, "%s.journal", svars->dname );
+	nfasprintf( &svars->nname, "%s.new", svars->dname );
+	nfasprintf( &svars->lname, "%s.lock", svars->dname );
 	memset( &lck, 0, sizeof(lck) );
 #if SEEK_SET != 0
 	lck.l_whence = SEEK_SET;
@@ -440,45 +453,45 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
 #if F_WRLCK != 0
 	lck.l_type = F_WRLCK;
 #endif
-	if ((lfd = open( lname, O_WRONLY|O_CREAT, 0666 )) < 0) {
-		error( "Error: cannot create lock file %s: %s\n", lname, strerror(errno) );
-		ret = SYNC_FAIL;
+	if ((svars->lfd = open( svars->lname, O_WRONLY|O_CREAT, 0666 )) < 0) {
+		error( "Error: cannot create lock file %s: %s\n", svars->lname, strerror(errno) );
+		svars->ret = SYNC_FAIL;
 		goto bail2;
 	}
-	if (fcntl( lfd, F_SETLK, &lck )) {
+	if (fcntl( svars->lfd, F_SETLK, &lck )) {
 		error( "Error: channel :%s:%s-:%s:%s is locked\n",
 		         chan->stores[M]->name, ctx[M]->name, chan->stores[S]->name, ctx[S]->name );
-		ret = SYNC_FAIL;
+		svars->ret = SYNC_FAIL;
 		goto bail1;
 	}
-	if ((dfp = fopen( dname, "r" ))) {
-		debug( "reading sync state %s ...\n", dname );
-		if (!fgets( buf, sizeof(buf), dfp ) || !(t = strlen( buf )) || buf[t - 1] != '\n') {
-			error( "Error: incomplete sync state header in %s\n", dname );
-			fclose( dfp );
-			ret = SYNC_FAIL;
+	if ((jfp = fopen( svars->dname, "r" ))) {
+		debug( "reading sync state %s ...\n", svars->dname );
+		if (!fgets( buf, sizeof(buf), jfp ) || !(t = strlen( buf )) || buf[t - 1] != '\n') {
+			error( "Error: incomplete sync state header in %s\n", svars->dname );
+			fclose( jfp );
+			svars->ret = SYNC_FAIL;
 			goto bail;
 		}
-		if (sscanf( buf, "%d:%d %d:%d:%d", &uidval[M], &maxuid[M], &uidval[S], &smaxxuid, &maxuid[S]) != 5) {
-			error( "Error: invalid sync state header in %s\n", dname );
-			fclose( dfp );
-			ret = SYNC_FAIL;
+		if (sscanf( buf, "%d:%d %d:%d:%d", &svars->uidval[M], &svars->maxuid[M], &svars->uidval[S], &svars->smaxxuid, &svars->maxuid[S]) != 5) {
+			error( "Error: invalid sync state header in %s\n", svars->dname );
+			fclose( jfp );
+			svars->ret = SYNC_FAIL;
 			goto bail;
 		}
-		sline = 1;
-		while (fgets( buf, sizeof(buf), dfp )) {
-			sline++;
+		line = 1;
+		while (fgets( buf, sizeof(buf), jfp )) {
+			line++;
 			if (!(t = strlen( buf )) || buf[t - 1] != '\n') {
-				error( "Error: incomplete sync state entry at %s:%d\n", dname, sline );
-				fclose( dfp );
-				ret = SYNC_FAIL;
+				error( "Error: incomplete sync state entry at %s:%d\n", svars->dname, line );
+				fclose( jfp );
+				svars->ret = SYNC_FAIL;
 				goto bail;
 			}
 			fbuf[0] = 0;
 			if (sscanf( buf, "%d %d %15s", &t1, &t2, fbuf ) < 2) {
-				error( "Error: invalid sync state entry at %s:%d\n", dname, sline );
-				fclose( dfp );
-				ret = SYNC_FAIL;
+				error( "Error: invalid sync state entry at %s:%d\n", svars->dname, line );
+				fclose( jfp );
+				svars->ret = SYNC_FAIL;
 				goto bail;
 			}
 			srec = nfmalloc( sizeof(*srec) );
@@ -495,32 +508,32 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
 			srec->msg[M] = srec->msg[S] = 0;
 			srec->tuid[0] = 0;
 			srec->next = 0;
-			*srecadd = srec;
-			srecadd = &srec->next;
+			*svars->srecadd = srec;
+			svars->srecadd = &srec->next;
 		}
-		fclose( dfp );
+		fclose( jfp );
 	} else {
 		if (errno != ENOENT) {
-			error( "Error: cannot read sync state %s\n", dname );
-			ret = SYNC_FAIL;
+			error( "Error: cannot read sync state %s\n", svars->dname );
+			svars->ret = SYNC_FAIL;
 			goto bail;
 		}
 	}
 	line = 0;
-	if ((jfp = fopen( jname, "r" ))) {
-		if (!stat( nname, &st ) && fgets( buf, sizeof(buf), jfp )) {
+	if ((jfp = fopen( svars->jname, "r" ))) {
+		if (!stat( svars->nname, &st ) && fgets( buf, sizeof(buf), jfp )) {
 			debug( "recovering journal ...\n" );
 			if (!(t = strlen( buf )) || buf[t - 1] != '\n') {
-				error( "Error: incomplete journal header in %s\n", jname );
+				error( "Error: incomplete journal header in %s\n", svars->jname );
 				fclose( jfp );
-				ret = SYNC_FAIL;
+				svars->ret = SYNC_FAIL;
 				goto bail;
 			}
 			if (memcmp( buf, JOURNAL_VERSION "\n", strlen(JOURNAL_VERSION) + 1 )) {
 				error( "Error: incompatible journal version "
 				                 "(got %.*s, expected " JOURNAL_VERSION ")\n", t - 1, buf );
 				fclose( jfp );
-				ret = SYNC_FAIL;
+				svars->ret = SYNC_FAIL;
 				goto bail;
 			}
 			srec = 0;
@@ -528,9 +541,9 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
 			while (fgets( buf, sizeof(buf), jfp )) {
 				line++;
 				if (!(t = strlen( buf )) || buf[t - 1] != '\n') {
-					error( "Error: incomplete journal entry at %s:%d\n", jname, line );
+					error( "Error: incomplete journal entry at %s:%d\n", svars->jname, line );
 					fclose( jfp );
-					ret = SYNC_FAIL;
+					svars->ret = SYNC_FAIL;
 					goto bail;
 				}
 				if (buf[0] == '#' ?
@@ -541,18 +554,18 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
 				          (sscanf( buf + 2, "%d %d", &t1, &t2 ) != 2) :
 				          (sscanf( buf + 2, "%d %d %d", &t1, &t2, &t3 ) != 3))
 				{
-					error( "Error: malformed journal entry at %s:%d\n", jname, line );
+					error( "Error: malformed journal entry at %s:%d\n", svars->jname, line );
 					fclose( jfp );
-					ret = SYNC_FAIL;
+					svars->ret = SYNC_FAIL;
 					goto bail;
 				}
 				if (buf[0] == '(')
-					maxuid[M] = t1;
+					svars->maxuid[M] = t1;
 				else if (buf[0] == ')')
-					maxuid[S] = t1;
+					svars->maxuid[S] = t1;
 				else if (buf[0] == '|') {
-					uidval[M] = t1;
-					uidval[S] = t2;
+					svars->uidval[M] = t1;
+					svars->uidval[S] = t2;
 				} else if (buf[0] == '+') {
 					srec = nfmalloc( sizeof(*srec) );
 					srec->uid[M] = t1;
@@ -563,18 +576,18 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
 					srec->flags = 0;
 					srec->tuid[0] = 0;
 					srec->next = 0;
-					*srecadd = srec;
-					srecadd = &srec->next;
+					*svars->srecadd = srec;
+					svars->srecadd = &srec->next;
 				} else {
 					for (nsrec = srec; srec; srec = srec->next)
 						if (srec->uid[M] == t1 && srec->uid[S] == t2)
 							goto syncfnd;
-					for (srec = recs; srec != nsrec; srec = srec->next)
+					for (srec = svars->srecs; srec != nsrec; srec = srec->next)
 						if (srec->uid[M] == t1 && srec->uid[S] == t2)
 							goto syncfnd;
-					error( "Error: journal entry at %s:%d refers to non-existing sync state entry\n", jname, line );
+					error( "Error: journal entry at %s:%d refers to non-existing sync state entry\n", svars->jname, line );
 					fclose( jfp );
-					ret = SYNC_FAIL;
+					svars->ret = SYNC_FAIL;
 					goto bail;
 				  syncfnd:
 					debugn( "  entry(%d,%d,%u) ", srec->uid[M], srec->uid[S], srec->flags );
@@ -625,16 +638,16 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
 						t3 = (srec->status & S_EXPIRE);
 						debug( "expired now %d\n", t3 / S_EXPIRE );
 						if (t3) {
-							if (smaxxuid < srec->uid[S])
-								smaxxuid = srec->uid[S];
+							if (svars->smaxxuid < srec->uid[S])
+								svars->smaxxuid = srec->uid[S];
 							srec->status |= S_EXPIRED;
 						} else
 							srec->status &= ~S_EXPIRED;
 						break;
 					default:
-						error( "Error: unrecognized journal entry at %s:%d\n", jname, line );
+						error( "Error: unrecognized journal entry at %s:%d\n", svars->jname, line );
 						fclose( jfp );
-						ret = SYNC_FAIL;
+						svars->ret = SYNC_FAIL;
 						goto bail;
 					}
 				}
@@ -643,25 +656,25 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
 		fclose( jfp );
 	} else {
 		if (errno != ENOENT) {
-			error( "Error: cannot read journal %s\n", jname );
-			ret = SYNC_FAIL;
+			error( "Error: cannot read journal %s\n", svars->jname );
+			svars->ret = SYNC_FAIL;
 			goto bail;
 		}
 	}
-	if (!(nfp = fopen( nname, "w" ))) {
-		error( "Error: cannot write new sync state %s\n", nname );
-		ret = SYNC_FAIL;
+	if (!(svars->nfp = fopen( svars->nname, "w" ))) {
+		error( "Error: cannot write new sync state %s\n", svars->nname );
+		svars->ret = SYNC_FAIL;
 		goto bail;
 	}
-	if (!(jfp = fopen( jname, "a" ))) {
-		error( "Error: cannot write journal %s\n", jname );
-		fclose( nfp );
-		ret = SYNC_FAIL;
+	if (!(svars->jfp = fopen( svars->jname, "a" ))) {
+		error( "Error: cannot write journal %s\n", svars->jname );
+		fclose( svars->nfp );
+		svars->ret = SYNC_FAIL;
 		goto bail;
 	}
-	setlinebuf( jfp );
+	setlinebuf( svars->jfp );
 	if (!line)
-		Fprintf( jfp, JOURNAL_VERSION "\n" );
+		Fprintf( svars->jfp, JOURNAL_VERSION "\n" );
 
 	opts[M] = opts[S] = 0;
 	for (t = 0; t < 2; t++) {
@@ -697,7 +710,7 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
 	if ((chan->ops[S] & (OP_NEW|OP_RENEW)) && chan->max_messages)
 		opts[S] |= OPEN_OLD|OPEN_NEW|OPEN_FLAGS;
 	if (line)
-		for (srec = recs; srec; srec = srec->next) {
+		for (srec = svars->srecs; srec; srec = srec->next) {
 			if (srec->status & S_DEAD)
 				continue;
 			if ((mvBit(srec->status, S_EXPIRE, S_EXPIRED) ^ srec->status) & S_EXPIRED)
@@ -709,55 +722,55 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
 					opts[S] |= OPEN_OLD|OPEN_FIND;
 			}
 		}
-	driver[M]->prepare_opts( ctx[M], opts[M] );
-	driver[S]->prepare_opts( ctx[S], opts[S] );
+	svars->drv[M]->prepare_opts( ctx[M], opts[M] );
+	svars->drv[S]->prepare_opts( ctx[S], opts[S] );
 
-	if ((ret = select_box( recs, ctx, maxuid, uidval, S, (ctx[S]->opts & OPEN_OLD) ? 1 : INT_MAX, 0, 0, line ? jfp : 0 )) != SYNC_OK)
+	if ((svars->ret = select_box( svars->srecs, svars->ctx, svars->maxuid, svars->uidval, S, (ctx[S]->opts & OPEN_OLD) ? 1 : INT_MAX, 0, 0, line ? svars->jfp : 0 )) != SYNC_OK)
 		goto finish;
 
 	mexcs = 0;
 	nmexcs = rmexcs = 0;
 	minwuid = INT_MAX;
-	if (smaxxuid) {
-		debug( "preparing master selection - max expired slave uid is %d\n", smaxxuid );
-		for (srec = recs; srec; srec = srec->next) {
+	if (svars->smaxxuid) {
+		debug( "preparing master selection - max expired slave uid is %d\n", svars->smaxxuid );
+		for (srec = svars->srecs; srec; srec = srec->next) {
 			if (srec->status & S_DEAD)
 				continue;
 			if (srec->status & S_EXPIRED) {
-				if (!srec->uid[S] || ((ctx[S]->opts & OPEN_OLD) && !srec->msg[S])) {
+				if (!srec->uid[S] || ((svars->ctx[S]->opts & OPEN_OLD) && !srec->msg[S])) {
 					srec->status |= S_EXP_S;
 					continue;
 				}
 			} else {
-				if (smaxxuid >= srec->uid[S])
+				if (svars->smaxxuid >= srec->uid[S])
 					continue;
 			}
 			if (minwuid > srec->uid[M])
 				minwuid = srec->uid[M];
 		}
 		debug( "  min non-orphaned master uid is %d\n", minwuid );
-		for (srec = recs; srec; srec = srec->next) {
+		for (srec = svars->srecs; srec; srec = srec->next) {
 			if (srec->status & S_DEAD)
 				continue;
 			if (srec->status & S_EXP_S) {
-				if (minwuid > srec->uid[M] && maxuid[M] >= srec->uid[M]) {
+				if (minwuid > srec->uid[M] && svars->maxuid[M] >= srec->uid[M]) {
 					debug( "  -> killing (%d,%d)\n", srec->uid[M], srec->uid[S] );
 					srec->status = S_DEAD;
-					Fprintf( jfp, "- %d %d\n", srec->uid[M], srec->uid[S] );
+					Fprintf( svars->jfp, "- %d %d\n", srec->uid[M], srec->uid[S] );
 				} else if (srec->uid[S]) {
 					debug( "  -> orphaning (%d,[%d])\n", srec->uid[M], srec->uid[S] );
-					Fprintf( jfp, "> %d %d 0\n", srec->uid[M], srec->uid[S] );
+					Fprintf( svars->jfp, "> %d %d 0\n", srec->uid[M], srec->uid[S] );
 					srec->uid[S] = 0;
 				}
 			} else if (minwuid > srec->uid[M]) {
 				if (srec->uid[S] < 0) {
-					if (maxuid[M] >= srec->uid[M]) {
+					if (svars->maxuid[M] >= srec->uid[M]) {
 						debug( "  -> killing (%d,%d)\n", srec->uid[M], srec->uid[S] );
 						srec->status = S_DEAD;
-						Fprintf( jfp, "- %d %d\n", srec->uid[M], srec->uid[S] );
+						Fprintf( svars->jfp, "- %d %d\n", srec->uid[M], srec->uid[S] );
 					}
-				} else if (srec->uid[M] > 0 && srec->uid[S] && (ctx[M]->opts & OPEN_OLD) &&
-				           (!(ctx[M]->opts & OPEN_NEW) || maxuid[M] >= srec->uid[M])) {
+				} else if (srec->uid[M] > 0 && srec->uid[S] && (svars->ctx[M]->opts & OPEN_OLD) &&
+				           (!(svars->ctx[M]->opts & OPEN_NEW) || svars->maxuid[M] >= srec->uid[M])) {
 					if (nmexcs == rmexcs) {
 						rmexcs = rmexcs * 2 + 100;
 						mexcs = nfrealloc( mexcs, rmexcs * sizeof(int) );
@@ -772,24 +785,24 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
 		debug( "\n" );
 	} else if (ctx[M]->opts & OPEN_OLD)
 		minwuid = 1;
-	if ((ret = select_box( recs, ctx, maxuid, uidval, M, minwuid, mexcs, nmexcs, line ? jfp : 0 )) != SYNC_OK)
+	if ((svars->ret = select_box( svars->srecs, svars->ctx, svars->maxuid, svars->uidval, M, minwuid, mexcs, nmexcs, line ? svars->jfp : 0 )) != SYNC_OK)
 		goto finish;
 
-	if (!uidval[M] || !uidval[S]) {
-		uidval[M] = ctx[M]->uidvalidity;
-		uidval[S] = ctx[S]->uidvalidity;
-		Fprintf( jfp, "| %d %d\n", uidval[M], uidval[S] );
+	if (!svars->uidval[M] || !svars->uidval[S]) {
+		svars->uidval[M] = svars->ctx[M]->uidvalidity;
+		svars->uidval[S] = svars->ctx[S]->uidvalidity;
+		Fprintf( svars->jfp, "| %d %d\n", svars->uidval[M], svars->uidval[S] );
 	}
 
 	info( "Synchronizing...\n" );
 
 	debug( "synchronizing new entries\n" );
-	osrecadd = srecadd;
+	svars->osrecadd = svars->srecadd;
 	for (t = 0; t < 2; t++) {
-		for (nmsgs = 0, tmsg = ctx[1-t]->msgs; tmsg; tmsg = tmsg->next)
-			if (tmsg->srec ? tmsg->srec->uid[t] < 0 && (tmsg->srec->uid[t] == -1 ? (chan->ops[t] & OP_RENEW) : (chan->ops[t] & OP_NEW)) : (chan->ops[t] & OP_NEW)) {
+		for (nmsgs = 0, tmsg = svars->ctx[1-t]->msgs; tmsg; tmsg = tmsg->next)
+			if (tmsg->srec ? tmsg->srec->uid[t] < 0 && (tmsg->srec->uid[t] == -1 ? (svars->chan->ops[t] & OP_RENEW) : (svars->chan->ops[t] & OP_NEW)) : (svars->chan->ops[t] & OP_NEW)) {
 				debug( "new message %d on %s\n", tmsg->uid, str_ms[1-t] );
-				if ((chan->ops[t] & OP_EXPUNGE) && (tmsg->flags & F_DELETED))
+				if ((svars->chan->ops[t] & OP_EXPUNGE) && (tmsg->flags & F_DELETED))
 					debug( "  -> not %sing - would be expunged anyway\n", str_hl[t] );
 				else {
 					if (tmsg->srec) {
@@ -799,17 +812,17 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
 					} else {
 						srec = nfmalloc( sizeof(*srec) );
 						srec->next = 0;
-						*srecadd = srec;
-						srecadd = &srec->next;
+						*svars->srecadd = srec;
+						svars->srecadd = &srec->next;
 						srec->status = S_DONE;
 						srec->flags = 0;
 						srec->tuid[0] = 0;
 						srec->uid[1-t] = tmsg->uid;
 						srec->uid[t] = -2;
-						Fprintf( jfp, "+ %d %d\n", srec->uid[M], srec->uid[S] );
+						Fprintf( svars->jfp, "+ %d %d\n", srec->uid[M], srec->uid[S] );
 						debug( "  -> pair(%d,%d) created\n", srec->uid[M], srec->uid[S] );
 					}
-					if ((tmsg->flags & F_FLAGGED) || !chan->stores[t]->max_size || tmsg->size <= chan->stores[t]->max_size) {
+					if ((tmsg->flags & F_FLAGGED) || !svars->chan->stores[t]->max_size || tmsg->size <= svars->chan->stores[t]->max_size) {
 						if (!nmsgs)
 							infon( t ? "Pulling new messages..." : "Pushing new messages..." );
 						else
@@ -817,22 +830,22 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
 						nmsgs++;
 						if (tmsg->flags) {
 							srec->flags = tmsg->flags;
-							Fprintf( jfp, "* %d %d %u\n", srec->uid[M], srec->uid[S], srec->flags );
+							Fprintf( svars->jfp, "* %d %d %u\n", srec->uid[M], srec->uid[S], srec->flags );
 							debug( "  -> updated flags to %u\n", tmsg->flags );
 						}
 						for (t1 = 0; t1 < TUIDL; t1++) {
 							t2 = arc4_getbyte() & 0x3f;
 							srec->tuid[t1] = t2 < 26 ? t2 + 'A' : t2 < 52 ? t2 + 'a' - 26 : t2 < 62 ? t2 + '0' - 52 : t2 == 62 ? '+' : '/';
 						}
-						Fprintf( jfp, "# %d %d %." stringify(TUIDL) "s\n", srec->uid[M], srec->uid[S], srec->tuid );
+						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 );
-						switch ((ret = copy_msg( ctx, t, tmsg, srec->tuid, &uid ))) {
+						switch ((svars->ret = copy_msg( svars->ctx, t, tmsg, srec->tuid, &uid ))) {
 						case SYNC_OK: break;
 						case SYNC_NOGOOD:
 							/* The error is either transient or the message is gone. */
 							debug( "  -> killing (%d,%d)\n", srec->uid[M], srec->uid[S] );
 							srec->status = S_DEAD;
-							Fprintf( jfp, "- %d %d\n", srec->uid[M], srec->uid[S] );
+							Fprintf( svars->jfp, "- %d %d\n", srec->uid[M], srec->uid[S] );
 							continue;
 						default: goto finish;
 						}
@@ -846,15 +859,15 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
 					}
 					if (srec->uid[t] != uid) {
 						debug( "  -> new UID %d\n", uid );
-						Fprintf( jfp, "%c %d %d %d\n", "<>"[t], srec->uid[M], srec->uid[S], uid );
+						Fprintf( svars->jfp, "%c %d %d %d\n", "<>"[t], srec->uid[M], srec->uid[S], uid );
 						srec->uid[t] = uid;
 						srec->tuid[0] = 0;
 					}
 					if (!tmsg->srec) {
 						tmsg->srec = srec;
-						if (maxuid[1-t] < tmsg->uid) {
-							maxuid[1-t] = tmsg->uid;
-							Fprintf( jfp, "%c %d\n", ")("[t], tmsg->uid );
+						if (svars->maxuid[1-t] < tmsg->uid) {
+							svars->maxuid[1-t] = tmsg->uid;
+							Fprintf( svars->jfp, "%c %d\n", ")("[t], tmsg->uid );
 						}
 					}
 				}
@@ -863,14 +876,14 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
 			info( " %d messages\n", nmsgs );
 	}
 	debug( "finding just copied messages\n" );
-	for (srec = recs; srec; srec = srec->next) {
+	for (srec = svars->srecs; srec; srec = srec->next) {
 		if (srec->status & S_DEAD)
 			continue;
 		if (srec->tuid[0]) {
 			t = (srec->uid[M] == -2) ? M : S;
 			debug( "  pair(%d,%d): lookup %s, TUID %." stringify(TUIDL) "s\n", srec->uid[M], srec->uid[S], str_ms[t], srec->tuid );
-			switch (driver[t]->find_msg( ctx[t], srec->tuid, &uid )) {
-			case DRV_STORE_BAD: ret = SYNC_BAD(t); goto finish;
+			switch (svars->drv[t]->find_msg( svars->ctx[t], srec->tuid, &uid )) {
+			case DRV_STORE_BAD: svars->ret = SYNC_BAD(t); goto finish;
 			case DRV_OK:
 				debug( "  -> new UID %d\n", uid );
 				break;
@@ -879,27 +892,27 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
 				uid = 0;
 				break;
 			}
-			Fprintf( jfp, "%c %d %d %d\n", "<>"[t], srec->uid[M], srec->uid[S], uid );
+			Fprintf( svars->jfp, "%c %d %d %d\n", "<>"[t], srec->uid[M], srec->uid[S], uid );
 			srec->uid[t] = uid;
 			srec->tuid[0] = 0;
 		}
 	}
 
 	debug( "synchronizing old entries\n" );
-	for (srec = recs; srec != *osrecadd; srec = srec->next) {
+	for (srec = svars->srecs; srec != *svars->osrecadd; srec = srec->next) {
 		if (srec->status & (S_DEAD|S_DONE))
 			continue;
 		debug( "pair (%d,%d)\n", srec->uid[M], srec->uid[S] );
-		nom = !srec->msg[M] && (ctx[M]->opts & OPEN_OLD);
-		nos = !srec->msg[S] && (ctx[S]->opts & OPEN_OLD);
-		if (nom && nos) {
+		no[M] = !srec->msg[M] && (svars->ctx[M]->opts & OPEN_OLD);
+		no[S] = !srec->msg[S] && (svars->ctx[S]->opts & OPEN_OLD);
+		if (no[M] && no[S]) {
 			debug( "  vanished\n" );
 			/* d.1) d.5) d.6) d.10) d.11) */
 			srec->status = S_DEAD;
-			Fprintf( jfp, "- %d %d\n", srec->uid[M], srec->uid[S] );
+			Fprintf( svars->jfp, "- %d %d\n", srec->uid[M], srec->uid[S] );
 		} else {
-			del[M] = nom && (srec->uid[M] > 0);
-			del[S] = nos && (srec->uid[S] > 0);
+			del[M] = no[M] && (srec->uid[M] > 0);
+			del[S] = no[S] && (srec->uid[S] > 0);
 
 			for (t = 0; t < 2; t++) {
 				srec->aflags[t] = srec->dflags[t] = 0;
@@ -913,15 +926,15 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
 					/* c.4) d.9) / b.4) d.4) */
 					if (srec->msg[t] && (srec->msg[t]->status & M_FLAGS) && srec->msg[t]->flags != srec->flags)
 						info( "Info: conflicting changes in (%d,%d)\n", srec->uid[M], srec->uid[S] );
-					if (chan->ops[t] & OP_DELETE) {
+					if (svars->chan->ops[t] & OP_DELETE) {
 						debug( "  %sing delete\n", str_hl[t] );
-						switch (driver[t]->set_flags( ctx[t], srec->msg[t], srec->uid[t], F_DELETED, 0 )) {
-						case DRV_STORE_BAD: ret = SYNC_BAD(t); goto finish;
-						case DRV_BOX_BAD: ret = SYNC_FAIL; goto finish;
+						switch (svars->drv[t]->set_flags( svars->ctx[t], srec->msg[t], srec->uid[t], F_DELETED, 0 )) {
+						case DRV_STORE_BAD: svars->ret = SYNC_BAD(t); goto finish;
+						case DRV_BOX_BAD: svars->ret = SYNC_FAIL; goto finish;
 						default: /* ok */ break;
 						case DRV_OK:
 							srec->status |= S_DEL(t);
-							Fprintf( jfp, "%c %d %d 0\n", "><"[t], srec->uid[M], srec->uid[S] );
+							Fprintf( svars->jfp, "%c %d %d 0\n", "><"[t], srec->uid[M], srec->uid[S] );
 							srec->uid[1-t] = 0;
 						}
 					} else
@@ -931,10 +944,10 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
 					;
 				else if (srec->uid[t] < 0)
 					/* b.2) / c.2) */
-					; /* handled above */
+					; /* handled as new messages (sort of) */
 				else if (!del[t]) {
 					/* a) & b.3) / c.3) */
-					if (chan->ops[t] & OP_FLAGS) {
+					if (svars->chan->ops[t] & OP_FLAGS) {
 						sflags = srec->msg[1-t]->flags;
 						if ((srec->status & (S_EXPIRE|S_EXPIRED)) && !t)
 							sflags &= ~F_DELETED;
@@ -953,18 +966,18 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
 		}
 	}
 
-	if ((chan->ops[S] & (OP_NEW|OP_RENEW|OP_FLAGS)) && chan->max_messages) {
+	if ((svars->chan->ops[S] & (OP_NEW|OP_RENEW|OP_FLAGS)) && svars->chan->max_messages) {
 		/* Flagged and not yet synced messages older than the first not
 		 * expired message are not counted. */
-		todel = ctx[S]->count - chan->max_messages;
+		todel = svars->ctx[S]->count - svars->chan->max_messages;
 		debug( "scheduling %d excess messages for expiration\n", todel );
-		for (tmsg = ctx[S]->msgs; tmsg && todel > 0; tmsg = tmsg->next)
+		for (tmsg = svars->ctx[S]->msgs; tmsg && todel > 0; tmsg = tmsg->next)
 			if (!(tmsg->status & M_DEAD) && (srec = tmsg->srec) &&
 			    ((tmsg->flags | srec->aflags[S]) & ~srec->dflags[S] & F_DELETED) &&
 			    !(srec->status & (S_EXPIRE|S_EXPIRED)))
 				todel--;
 		debug( "%d non-deleted excess messages\n", todel );
-		for (tmsg = ctx[S]->msgs; tmsg; tmsg = tmsg->next) {
+		for (tmsg = svars->ctx[S]->msgs; tmsg; tmsg = tmsg->next) {
 			if (tmsg->status & M_DEAD)
 				continue;
 			if (!(srec = tmsg->srec) || srec->uid[M] <= 0)
@@ -986,13 +999,13 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
 			}
 		}
 		debug( "%d excess messages remain\n", todel );
-		for (srec = recs; srec; srec = srec->next) {
+		for (srec = svars->srecs; srec; srec = srec->next) {
 			if ((srec->status & (S_DEAD|S_DONE)) || !srec->msg[S])
 				continue;
 			nex = (srec->status / S_NEXPIRE) & 1;
 			if (nex != ((srec->status / S_EXPIRED) & 1)) {
 				if (nex != ((srec->status / S_EXPIRE) & 1)) {
-					Fprintf( jfp, "~ %d %d %d\n", srec->uid[M], srec->uid[S], nex );
+					Fprintf( svars->jfp, "~ %d %d %d\n", srec->uid[M], srec->uid[S], nex );
 					debug( "  pair(%d,%d): %d (pre)\n", srec->uid[M], srec->uid[S], nex );
 					srec->status = (srec->status & ~S_EXPIRE) | (nex * S_EXPIRE);
 				} else
@@ -1000,21 +1013,22 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
 			}
 		}
 	}
+
 	debug( "synchronizing flags\n" );
-	for (srec = recs; srec != *osrecadd; srec = srec->next) {
+	for (srec = svars->srecs; srec != *svars->osrecadd; srec = srec->next) {
 		if (srec->status & (S_DEAD|S_DONE))
 			continue;
 		for (t = 0; t < 2; t++) {
 			aflags = srec->aflags[t];
 			dflags = srec->dflags[t];
-			if (t && ((mvBit(srec->status, S_EXPIRE, S_EXPIRED) ^ srec->status) & S_EXPIRED)) {
+			if ((t == S) && ((mvBit(srec->status, S_EXPIRE, S_EXPIRED) ^ srec->status) & S_EXPIRED)) {
 				if (srec->status & S_NEXPIRE)
 					aflags |= F_DELETED;
 				else
 					dflags |= F_DELETED;
 			}
-			if ((chan->ops[t] & OP_EXPUNGE) && (((srec->msg[t] ? srec->msg[t]->flags : 0) | aflags) & ~dflags & F_DELETED) &&
-			    (!ctx[t]->conf->trash || ctx[t]->conf->trash_only_new))
+			if ((svars->chan->ops[t] & OP_EXPUNGE) && (((srec->msg[t] ? srec->msg[t]->flags : 0) | aflags) & ~dflags & F_DELETED) &&
+			    (!svars->ctx[t]->conf->trash || svars->ctx[t]->conf->trash_only_new))
 			{
 				srec->aflags[t] &= F_DELETED;
 				aflags &= F_DELETED;
@@ -1024,9 +1038,9 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
 				aflags &= ~srec->msg[t]->flags;
 				dflags &= srec->msg[t]->flags;
 			}
-			switch ((aflags | dflags) ? driver[t]->set_flags( ctx[t], srec->msg[t], srec->uid[t], aflags, dflags ) : DRV_OK) {
-			case DRV_STORE_BAD: ret = SYNC_BAD(t); goto finish;
-			case DRV_BOX_BAD: ret = SYNC_FAIL; goto finish;
+			switch ((aflags | dflags) ? svars->drv[t]->set_flags( svars->ctx[t], srec->msg[t], srec->uid[t], aflags, dflags ) : DRV_OK) {
+			case DRV_STORE_BAD: svars->ret = SYNC_BAD(t); goto finish;
+			case DRV_BOX_BAD: svars->ret = SYNC_FAIL; goto finish;
 			default: /* ok */ srec->aflags[t] = srec->dflags[t] = 0; break;
 			case DRV_OK:
 				if (aflags & F_DELETED)
@@ -1036,13 +1050,13 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
 				if (t) {
 					nex = (srec->status / S_NEXPIRE) & 1;
 					if (nex != ((srec->status / S_EXPIRED) & 1)) {
-						if (nex && (smaxxuid < srec->uid[S]))
-							smaxxuid = srec->uid[S];
-						Fprintf( jfp, "/ %d %d\n", srec->uid[M], srec->uid[S] );
+						if (nex && (svars->smaxxuid < srec->uid[S]))
+							svars->smaxxuid = srec->uid[S];
+						Fprintf( svars->jfp, "/ %d %d\n", srec->uid[M], srec->uid[S] );
 						debug( "  pair(%d,%d): expired %d (commit)\n", srec->uid[M], srec->uid[S], nex );
 						srec->status = (srec->status & ~S_EXPIRED) | (nex * S_EXPIRED);
 					} else if (nex != ((srec->status / S_EXPIRE) & 1)) {
-						Fprintf( jfp, "\\ %d %d\n", srec->uid[M], srec->uid[S] );
+						Fprintf( svars->jfp, "\\ %d %d\n", srec->uid[M], srec->uid[S] );
 						debug( "  pair(%d,%d): expire %d (cancel)\n", srec->uid[M], srec->uid[S], nex );
 						srec->status = (srec->status & ~S_EXPIRE) | (nex * S_EXPIRE);
 					}
@@ -1053,34 +1067,33 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
 		if (srec->flags != nflags) {
 			debug( "  pair(%d,%d): updating flags (%u -> %u)\n", srec->uid[M], srec->uid[S], srec->flags, nflags );
 			srec->flags = nflags;
-			Fprintf( jfp, "* %d %d %u\n", srec->uid[M], srec->uid[S], nflags );
+			Fprintf( svars->jfp, "* %d %d %u\n", srec->uid[M], srec->uid[S], nflags );
 		}
 	}
 
 	for (t = 0; t < 2; t++) {
-		ex[t] = 0;
-		if (chan->ops[t] & OP_EXPUNGE) {
+		if (svars->chan->ops[t] & OP_EXPUNGE) {
 			info( "Expunging %s\n", str_ms[t] );
 			debug( "expunging %s\n", str_ms[t] );
-			for (tmsg = ctx[t]->msgs; tmsg; tmsg = tmsg->next)
+			for (tmsg = svars->ctx[t]->msgs; tmsg; tmsg = tmsg->next)
 				if (tmsg->flags & F_DELETED) {
-					if (ctx[t]->conf->trash) {
-						if (!ctx[t]->conf->trash_only_new || !tmsg->srec || tmsg->srec->uid[1-t] < 0) {
+					if (svars->ctx[t]->conf->trash) {
+						if (!svars->ctx[t]->conf->trash_only_new || !tmsg->srec || tmsg->srec->uid[1-t] < 0) {
 							debug( "  trashing message %d\n", tmsg->uid );
-							switch (driver[t]->trash_msg( ctx[t], tmsg )) {
+							switch (svars->drv[t]->trash_msg( svars->ctx[t], tmsg )) {
 							case DRV_OK: break;
-							case DRV_STORE_BAD: ret = SYNC_BAD(t); goto finish;
-							default: ret = SYNC_FAIL; goto nexex;
+							case DRV_STORE_BAD: svars->ret = SYNC_BAD(t); goto finish;
+							default: svars->ret = SYNC_FAIL; goto nexex;
 							}
 						} else
 							debug( "  not trashing message %d - not new\n", tmsg->uid );
-					} else if (ctx[1-t]->conf->trash && ctx[1-t]->conf->trash_remote_new) {
+					} else if (svars->ctx[1-t]->conf->trash && svars->ctx[1-t]->conf->trash_remote_new) {
 						if (!tmsg->srec || tmsg->srec->uid[1-t] < 0) {
-							if (!ctx[1-t]->conf->max_size || tmsg->size <= ctx[1-t]->conf->max_size) {
+							if (!svars->ctx[1-t]->conf->max_size || tmsg->size <= svars->ctx[1-t]->conf->max_size) {
 								debug( "  remote trashing message %d\n", tmsg->uid );
-								switch ((ret = copy_msg( ctx, 1 - t, tmsg, 0, 0 ))) {
+								switch ((svars->ret = copy_msg( svars->ctx, 1 - t, tmsg, 0, 0 ))) {
 								case SYNC_OK: break;
-								case SYNC_NOGOOD: ret = SYNC_FAIL; goto nexex;
+								case SYNC_NOGOOD: svars->ret = SYNC_FAIL; goto nexex;
 								case SYNC_FAIL: goto nexex;
 								default: goto finish;
 								}
@@ -1091,89 +1104,89 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan )
 					}
 				}
 
-			switch (driver[t]->close( ctx[t] )) {
-			case DRV_OK: ex[t] = 1; break;
-			case DRV_STORE_BAD: ret = SYNC_BAD(t); goto finish;
+			switch (svars->drv[t]->close( svars->ctx[t] )) {
+			case DRV_OK: svars->state[t] |= ST_DID_EXPUNGE; break;
+			case DRV_STORE_BAD: svars->ret = SYNC_BAD(t); goto finish;
 			default: break;
 			}
 		}
 	  nexex: ;
 	}
-	if (ex[M] || ex[S]) {
+	if ((svars->state[M] | svars->state[S]) & ST_DID_EXPUNGE) {
 		/* This cleanup is not strictly necessary, as the next full sync
 		   would throw out the dead entries anyway. But ... */
 
 		minwuid = INT_MAX;
-		if (smaxxuid) {
-			debug( "preparing entry purge - max expired slave uid is %d\n", smaxxuid );
-			for (srec = recs; srec; srec = srec->next) {
+		if (svars->smaxxuid) {
+			debug( "preparing entry purge - max expired slave uid is %d\n", svars->smaxxuid );
+			for (srec = svars->srecs; srec; srec = srec->next) {
 				if (srec->status & S_DEAD)
 					continue;
-				if (!((srec->uid[S] <= 0 || ((srec->status & S_DEL(S)) && ex[S])) &&
-				      (srec->uid[M] <= 0 || ((srec->status & S_DEL(M)) && ex[M]) || (srec->status & S_EXPIRED))) &&
-				    smaxxuid < srec->uid[S] && minwuid > srec->uid[M])
+				if (!((srec->uid[S] <= 0 || ((srec->status & S_DEL(S)) && (svars->state[S] & ST_DID_EXPUNGE))) &&
+				      (srec->uid[M] <= 0 || ((srec->status & S_DEL(M)) && (svars->state[M] & ST_DID_EXPUNGE)) || (srec->status & S_EXPIRED))) &&
+				    svars->smaxxuid < srec->uid[S] && minwuid > srec->uid[M])
 					minwuid = srec->uid[M];
 			}
 			debug( "  min non-orphaned master uid is %d\n", minwuid );
 		}
 
-		for (srec = recs; srec; srec = srec->next) {
+		for (srec = svars->srecs; srec; srec = srec->next) {
 			if (srec->status & S_DEAD)
 				continue;
-			if (srec->uid[S] <= 0 || ((srec->status & S_DEL(S)) && ex[S])) {
-				if (srec->uid[M] <= 0 || ((srec->status & S_DEL(M)) && ex[M]) ||
-				    ((srec->status & S_EXPIRED) && maxuid[M] >= srec->uid[M] && minwuid > srec->uid[M])) {
+			if (srec->uid[S] <= 0 || ((srec->status & S_DEL(S)) && (svars->state[S] & ST_DID_EXPUNGE))) {
+				if (srec->uid[M] <= 0 || ((srec->status & S_DEL(M)) && (svars->state[M] & ST_DID_EXPUNGE)) ||
+				    ((srec->status & S_EXPIRED) && svars->maxuid[M] >= srec->uid[M] && minwuid > srec->uid[M])) {
 					debug( "  -> killing (%d,%d)\n", srec->uid[M], srec->uid[S] );
 					srec->status = S_DEAD;
-					Fprintf( jfp, "- %d %d\n", srec->uid[M], srec->uid[S] );
+					Fprintf( svars->jfp, "- %d %d\n", srec->uid[M], srec->uid[S] );
 				} else if (srec->uid[S] > 0) {
 					debug( "  -> orphaning (%d,[%d])\n", srec->uid[M], srec->uid[S] );
-					Fprintf( jfp, "> %d %d 0\n", srec->uid[M], srec->uid[S] );
+					Fprintf( svars->jfp, "> %d %d 0\n", srec->uid[M], srec->uid[S] );
 					srec->uid[S] = 0;
 				}
-			} else if (srec->uid[M] > 0 && ((srec->status & S_DEL(M)) && ex[M])) {
+			} else if (srec->uid[M] > 0 && ((srec->status & S_DEL(M)) && (svars->state[M] & ST_DID_EXPUNGE))) {
 				debug( "  -> orphaning ([%d],%d)\n", srec->uid[M], srec->uid[S] );
-				Fprintf( jfp, "< %d %d 0\n", srec->uid[M], srec->uid[S] );
+				Fprintf( svars->jfp, "< %d %d 0\n", srec->uid[M], srec->uid[S] );
 				srec->uid[M] = 0;
 			}
 		}
 	}
 
-	Fprintf( nfp, "%d:%d %d:%d:%d\n", uidval[M], maxuid[M], uidval[S], smaxxuid, maxuid[S] );
-	for (srec = recs; srec; srec = srec->next) {
+	Fprintf( svars->nfp, "%d:%d %d:%d:%d\n", svars->uidval[M], svars->maxuid[M], svars->uidval[S], svars->smaxxuid, svars->maxuid[S] );
+	for (srec = svars->srecs; srec; srec = srec->next) {
 		if (srec->status & S_DEAD)
 			continue;
 		make_flags( srec->flags, fbuf );
-		Fprintf( nfp, "%d %d %s%s\n", srec->uid[M], srec->uid[S],
+		Fprintf( svars->nfp, "%d %d %s%s\n", srec->uid[M], srec->uid[S],
 		         srec->status & S_EXPIRED ? "X" : "", fbuf );
 	}
 
-	Fclose( nfp );
-	Fclose( jfp );
+	Fclose( svars->nfp );
+	Fclose( svars->jfp );
 	if (!(DFlags & KEEPJOURNAL)) {
 		/* order is important! */
-		rename( nname, dname );
-		unlink( jname );
+		rename( svars->nname, svars->dname );
+		unlink( svars->jname );
 	}
 
   bail:
-	for (srec = recs; srec; srec = nsrec) {
+	for (srec = svars->srecs; srec; srec = nsrec) {
 		nsrec = srec->next;
 		free( srec );
 	}
-	unlink( lname );
+	unlink( svars->lname );
   bail1:
-	close( lfd );
+	close( svars->lfd );
   bail2:
-	free( lname );
-	free( nname );
-	free( jname );
-	free( dname );
-	return ret;
+	free( svars->lname );
+	free( svars->nname );
+	free( svars->jname );
+	free( svars->dname );
+	return svars->ret;
 
   finish:
-	Fclose( nfp );
-	Fclose( jfp );
+	Fclose( svars->nfp );
+	Fclose( svars->jfp );
 	goto bail;
 }