Эх сурвалжийг харах

make the driver model, sync_chans() and sync_boxes() fully async.
async drivers to follow ...

Oswald Buddenhagen 19 жил өмнө
parent
commit
168e5f3282
6 өөрчлөгдсөн 979 нэмэгдсэн , 555 устгасан
  1. 103 80
      src/drv_imap.c
  2. 124 74
      src/drv_maildir.c
  3. 36 19
      src/isync.h
  4. 169 63
      src/main.c
  5. 545 309
      src/sync.c
  6. 2 10
      src/util.c

+ 103 - 80
src/drv_imap.c

@@ -1199,8 +1199,9 @@ do_cram_auth( imap_store_t *ctx, struct imap_cmd *cmdp, const char *prompt )
 }
 #endif
 
-static store_t *
-imap_open_store( store_conf_t *conf )
+static void
+imap_open_store( store_conf_t *conf,
+                 void (*cb)( store_t *srv, void *aux ), void *aux )
 {
 	imap_store_conf_t *cfg = (imap_store_conf_t *)conf;
 	imap_server_conf_t *srvc = cfg->server;
@@ -1367,12 +1368,12 @@ imap_open_store( store_conf_t *conf )
 		}
 #if HAVE_LIBSSL
 		if (CAP(CRAM)) {
-			struct imap_cmd_cb cb;
+			struct imap_cmd_cb cbd;
 
 			info( "Authenticating with CRAM-MD5\n" );
-			memset( &cb, 0, sizeof(cb) );
-			cb.cont = do_cram_auth;
-			if (imap_exec( ctx, &cb, "AUTHENTICATE CRAM-MD5" ) != RESP_OK)
+			memset( &cbd, 0, sizeof(cbd) );
+			cbd.cont = do_cram_auth;
+			if (imap_exec( ctx, &cbd, "AUTHENTICATE CRAM-MD5" ) != RESP_OK)
 				goto bail;
 		} else if (srvc->require_cram) {
 			error( "IMAP error: CRAM-MD5 authentication is not supported by server\n" );
@@ -1402,8 +1403,10 @@ imap_open_store( store_conf_t *conf )
 	else if (cfg->use_namespace && CAP(NAMESPACE)) {
 		/* get NAMESPACE info */
 		if (!ctx->got_namespace) {
-			if (imap_exec( ctx, 0, "NAMESPACE" ) != RESP_OK)
-				goto bail;
+			if (imap_exec( ctx, 0, "NAMESPACE" ) != RESP_OK) {
+				cb( 0, aux );
+				return;
+			}
 			ctx->got_namespace = 1;
 		}
 		/* XXX for now assume personal namespace */
@@ -1413,11 +1416,13 @@ imap_open_store( store_conf_t *conf )
 			ctx->prefix = ctx->ns_personal->child->child->val;
 	}
 	ctx->trashnc = 1;
-	return &ctx->gen;
+	cb( &ctx->gen, aux );
+	return;
 
   bail:
 	imap_cancel_store( &ctx->gen );
-	return 0;
+	cb( 0, aux );
+	return;
 }
 
 static void
@@ -1433,13 +1438,14 @@ imap_prepare_opts( store_t *gctx, int opts )
 	gctx->opts = opts;
 }
 
-static int
-imap_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs )
+static void
+imap_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs,
+             void (*cb)( int sts, void *aux ), void *aux )
 {
 	imap_store_t *ctx = (imap_store_t *)gctx;
 	const char *prefix;
 	int ret, i, j, bl;
-	struct imap_cmd_cb cb;
+	struct imap_cmd_cb cbd;
 	char buf[1000];
 
 
@@ -1451,10 +1457,10 @@ imap_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs )
 		prefix = ctx->prefix;
 	}
 
-	memset( &cb, 0, sizeof(cb) );
-	cb.create = (gctx->opts & OPEN_CREATE) != 0;
-	cb.trycreate = 1;
-	if ((ret = imap_exec_b( ctx, &cb, "SELECT \"%s%s\"", prefix, gctx->name )) != DRV_OK)
+	memset( &cbd, 0, sizeof(cbd) );
+	cbd.create = (gctx->opts & OPEN_CREATE) != 0;
+	cbd.trycreate = 1;
+	if ((ret = imap_exec_b( ctx, &cbd, "SELECT \"%s%s\"", prefix, gctx->name )) != DRV_OK)
 		goto bail;
 
 	if (gctx->count) {
@@ -1489,19 +1495,20 @@ imap_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs )
   bail:
 	if (excs)
 		free( excs );
-	return ret;
+	cb( ret, aux );
 }
 
-static int
-imap_fetch_msg( store_t *ctx, message_t *msg, msg_data_t *data )
+static void
+imap_fetch_msg( store_t *ctx, message_t *msg, msg_data_t *data,
+                void (*cb)( int sts, void *aux ), void *aux )
 {
-	struct imap_cmd_cb cb;
+	struct imap_cmd_cb cbd;
 
-	memset( &cb, 0, sizeof(cb) );
-	cb.uid = msg->uid;
-	cb.ctx = data;
-	return imap_exec_m( (imap_store_t *)ctx, &cb, "UID FETCH %d (%sBODY.PEEK[])",
-	                    msg->uid, (msg->status & M_FLAGS) ? "" : "FLAGS " );
+	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 );
 }
 
 static int
@@ -1531,8 +1538,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 int
-imap_set_flags( store_t *gctx, message_t *msg, int uid, int add, int del )
+static void
+imap_set_flags( store_t *gctx, message_t *msg, int uid, int add, int del,
+                void (*cb)( int sts, void *aux ), void *aux )
 {
 	imap_store_t *ctx = (imap_store_t *)gctx;
 	int ret;
@@ -1546,35 +1554,38 @@ 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))
-		return DRV_OK;
-	return ret;
+		ret = DRV_OK;
+	cb( ret, aux );
 }
 
-static int
-imap_close( store_t *ctx )
+static void
+imap_close( store_t *ctx,
+            void (*cb)( int sts, void *aux ), void *aux )
 {
-	return imap_exec_b( (imap_store_t *)ctx, 0, "CLOSE" );
+	cb( imap_exec_b( (imap_store_t *)ctx, 0, "CLOSE" ), aux );
 }
 
-static int
-imap_trash_msg( store_t *gctx, message_t *msg )
+static void
+imap_trash_msg( store_t *gctx, message_t *msg,
+                void (*cb)( int sts, void *aux ), void *aux )
 {
 	imap_store_t *ctx = (imap_store_t *)gctx;
-	struct imap_cmd_cb cb;
+	struct imap_cmd_cb cbd;
 
-	memset( &cb, 0, sizeof(cb) );
-	cb.create = 1;
-	return imap_exec_m( ctx, &cb, "UID COPY %d \"%s%s\"",
-	                    msg->uid, ctx->prefix, gctx->conf->trash );
+	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 );
 }
 
-static int
-imap_store_msg( store_t *gctx, msg_data_t *data, int *uid )
+static void
+imap_store_msg( store_t *gctx, msg_data_t *data, int to_trash,
+                void (*cb)( int sts, int uid, void *aux ), void *aux )
 {
 	imap_store_t *ctx = (imap_store_t *)gctx;
-	struct imap_cmd_cb cb;
+	struct imap_cmd_cb cbd;
 	const char *prefix, *box;
-	int ret, d;
+	int ret, d, uid;
 	char flagstr[128];
 
 	d = 0;
@@ -1584,71 +1595,82 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int *uid )
 	}
 	flagstr[d] = 0;
 
-	memset( &cb, 0, sizeof(cb) );
-	cb.dlen = data->len;
-	cb.data = data->data;
-	if (!uid) {
+	memset( &cbd, 0, sizeof(cbd) );
+	cbd.dlen = data->len;
+	cbd.data = data->data;
+	cbd.ctx = &uid;
+	uid = -2;
+
+	if (to_trash) {
 		box = gctx->conf->trash;
 		prefix = ctx->prefix;
-		cb.create = 1;
+		cbd.create = 1;
 		if (ctx->trashnc)
 			ctx->caps = ctx->rcaps & ~(1 << LITERALPLUS);
 	} else {
 		box = gctx->name;
 		prefix = !strcmp( box, "INBOX" ) ? "" : ctx->prefix;
-		cb.create = (gctx->opts & OPEN_CREATE) != 0;
+		cbd.create = (gctx->opts & OPEN_CREATE) != 0;
 		/*if (ctx->currentnc)
 			ctx->caps = ctx->rcaps & ~(1 << LITERALPLUS);*/
-		*uid = -2;
 	}
-	cb.ctx = uid;
-	ret = imap_exec_m( ctx, &cb, "APPEND \"%s%s\" %s", prefix, box, flagstr );
+	ret = imap_exec_m( ctx, &cbd, "APPEND \"%s%s\" %s", prefix, box, flagstr );
 	ctx->caps = ctx->rcaps;
-	if (ret != DRV_OK)
-		return ret;
-	if (!uid)
+	if (ret != DRV_OK) {
+		cb( ret, -1, aux );
+		return;
+	}
+	if (to_trash)
 		ctx->trashnc = 0;
 	else {
 		/*ctx->currentnc = 0;*/
-		gctx->count++;
 	}
 
-	return DRV_OK;
+	cb( DRV_OK, uid, aux );
 }
 
-static int
-imap_find_msg( store_t *gctx, const char *tuid, int *uid )
+static void
+imap_find_msg( store_t *gctx, const char *tuid,
+               void (*cb)( int sts, int uid, void *aux ), void *aux )
 {
 	imap_store_t *ctx = (imap_store_t *)gctx;
-	struct imap_cmd_cb cb;
-	int ret;
-
-	memset( &cb, 0, sizeof(cb) );
-	cb.ctx = uid;
-	cb.uid = -1; /* we're looking for a UID */
-	*uid = -1; /* in case we get no SEARCH response at all */
-	if ((ret = imap_exec_m( ctx, &cb, "UID SEARCH HEADER X-TUID %." stringify(TUIDL) "s", tuid )) != DRV_OK)
-		return ret;
-	return *uid < 0 ? DRV_MSG_BAD : DRV_OK;
+	struct imap_cmd_cb cbd;
+	int ret, uid;
+
+	memset( &cbd, 0, sizeof(cbd) );
+	cbd.uid = -1; /* we're looking for a UID */
+	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 );
+	else
+		cb( uid <= 0 ? DRV_MSG_BAD : DRV_OK, uid, aux );
 }
 
-static int
-imap_list( store_t *gctx )
+static void
+imap_list( store_t *gctx,
+           void (*cb)( int sts, void *aux ), void *aux )
 {
 	imap_store_t *ctx = (imap_store_t *)gctx;
 	int ret;
 
 	if ((ret = imap_exec_b( ctx, 0, "LIST \"\" \"%s%%\"", ctx->prefix )) == DRV_OK)
 		gctx->listed = 1;
-	return ret;
+	cb( ret, aux );
 }
 
-static int
-imap_check( store_t *gctx )
+static void
+imap_cancel( store_t *gctx,
+             void (*cb)( int sts, void *aux ), void *aux )
+{
+	(void)gctx;
+	cb( DRV_OK, aux );
+}
+
+static void
+imap_commit( store_t *gctx )
 {
-	(void) gctx;
-	/* flush queue here */
-	return DRV_OK;
+	(void)gctx;
 }
 
 imap_server_conf_t *servers, **serverapp = &servers;
@@ -1797,6 +1819,7 @@ struct driver imap_driver = {
 	imap_find_msg,
 	imap_set_flags,
 	imap_trash_msg,
-	imap_check,
-	imap_close
+	imap_close,
+	imap_cancel,
+	imap_commit,
 };

+ 124 - 74
src/drv_maildir.c

@@ -93,20 +93,22 @@ maildir_parse_flags( const char *base )
 	return flags;
 }
 
-static store_t *
-maildir_open_store( store_conf_t *conf )
+static void
+maildir_open_store( store_conf_t *conf,
+                    void (*cb)( store_t *ctx, void *aux ), void *aux )
 {
 	maildir_store_t *ctx;
 	struct stat st;
 
 	if (stat( conf->path, &st ) || !S_ISDIR(st.st_mode)) {
 		error( "Maildir error: cannot open store %s\n", conf->path );
-		return 0;
+		cb( 0, aux );
+		return;
 	}
 	ctx = nfcalloc( sizeof(*ctx) );
 	ctx->gen.conf = conf;
 	ctx->uvfd = -1;
-	return &ctx->gen;
+	cb( &ctx->gen, aux );
 }
 
 static void
@@ -159,15 +161,17 @@ maildir_cleanup_drv( void )
 {
 }
 
-static int
-maildir_list( store_t *gctx )
+static void
+maildir_list( store_t *gctx,
+              void (*cb)( int sts, void *aux ), void *aux )
 {
 	DIR *dir;
 	struct dirent *de;
 
 	if (!(dir = opendir( gctx->conf->path ))) {
 		error( "%s: %s\n", gctx->conf->path, strerror(errno) );
-		return DRV_STORE_BAD;
+		cb( DRV_STORE_BAD, aux );
+		return;
 	}
 	while ((de = readdir( dir ))) {
 		struct stat st;
@@ -183,7 +187,7 @@ maildir_list( store_t *gctx )
 	closedir (dir);
 	gctx->listed = 1;
 
-	return DRV_OK;
+	cb( DRV_OK, aux );
 }
 
 static const char *subdirs[] = { "cur", "new", "tmp" };
@@ -760,8 +764,9 @@ maildir_prepare_opts( store_t *gctx, int opts )
 	gctx->opts = opts;
 }
 
-static int
-maildir_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs )
+static void
+maildir_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs,
+                void (*cb)( int sts, void *aux ), void *aux )
 {
 	maildir_store_t *ctx = (maildir_store_t *)gctx;
 	message_t **msgapp;
@@ -777,14 +782,17 @@ 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)
-		return DRV_BOX_BAD;
+	if (maildir_validate( gctx->path, "", ctx->gen.opts & OPEN_CREATE ) != DRV_OK) {
+		cb( DRV_BOX_BAD, aux );
+		return;
+	}
 
 	nfsnprintf( uvpath, sizeof(uvpath), "%s/.uidvalidity", gctx->path );
 #ifndef USE_DB
 	if ((ctx->uvfd = open( uvpath, O_RDWR|O_CREAT, 0600 )) < 0) {
 		perror( uvpath );
-		return DRV_BOX_BAD;
+		cb( DRV_BOX_BAD, aux );
+		return;
 	}
 #else
 	if ((ctx->uvfd = open( uvpath, O_RDWR, 0600 )) < 0) {
@@ -799,7 +807,8 @@ maildir_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs )
 					goto fnok;
 			}
 			perror( uvpath );
-			return DRV_BOX_BAD;
+			cb( DRV_BOX_BAD, aux );
+			return;
 		}
 	  dbok:
 #if SEEK_SET != 0
@@ -811,7 +820,8 @@ maildir_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs )
 		  bork:
 			close( ctx->uvfd );
 			ctx->uvfd = -1;
-			return DRV_BOX_BAD;
+			cb( DRV_BOX_BAD, aux );
+			return;
 		}
 		if (db_create( &ctx->db, 0, 0 )) {
 			fputs( "Maildir error: db_create() failed\n", stderr );
@@ -841,14 +851,16 @@ maildir_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs )
   fnok:
 #endif /* USE_DB */
 
-	if (maildir_scan( ctx, &msglist ) != DRV_OK)
-		return DRV_BOX_BAD;
+	if (maildir_scan( ctx, &msglist ) != DRV_OK) {
+		cb( DRV_BOX_BAD, aux );
+		return;
+	}
 	msgapp = &ctx->gen.msgs;
 	for (i = 0; i < msglist.nents; i++)
 		maildir_app_msg( ctx, &msgapp, msglist.ents + i );
 	maildir_free_scan( &msglist );
 
-	return DRV_OK;
+	cb( DRV_OK, aux );
 }
 
 static int
@@ -916,8 +928,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 int
-maildir_fetch_msg( store_t *gctx, message_t *gmsg, msg_data_t *data )
+static void
+maildir_fetch_msg( store_t *gctx, message_t *gmsg, msg_data_t *data,
+                   void (*cb)( int sts, void *aux ), void *aux )
 {
 	maildir_store_t *ctx = (maildir_store_t *)gctx;
 	maildir_message_t *msg = (maildir_message_t *)gmsg;
@@ -929,8 +942,10 @@ 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)
-			return ret;
+		if ((ret = maildir_again( ctx, msg, buf )) != DRV_OK) {
+			cb( ret, aux );
+			return;
+		}
 	}
 	fstat( fd, &st );
 	data->len = st.st_size;
@@ -938,12 +953,13 @@ 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 );
-		return DRV_MSG_BAD;
+		cb( DRV_MSG_BAD, aux );
+		return;
 	}
 	close( fd );
 	if (!(gmsg->status & M_FLAGS))
 		data->flags = maildir_parse_flags( msg->base );
-	return DRV_OK;
+	cb( DRV_OK, aux );
 }
 
 static int
@@ -961,30 +977,34 @@ maildir_make_flags( int flags, char *buf )
 	return d;
 }
 
-static int
-maildir_store_msg( store_t *gctx, msg_data_t *data, int *uid )
+static void
+maildir_store_msg( store_t *gctx, msg_data_t *data, int to_trash,
+                   void (*cb)( int sts, int uid, void *aux ), void *aux )
 {
 	maildir_store_t *ctx = (maildir_store_t *)gctx;
 	const char *prefix, *box;
-	int ret, fd, bl;
+	int ret, fd, bl, uid;
 	char buf[_POSIX_PATH_MAX], nbuf[_POSIX_PATH_MAX], fbuf[NUM_FLAGS + 3], base[128];
 
 	bl = nfsnprintf( base, sizeof(base), "%ld.%d_%d.%s", time( 0 ), Pid, ++MaildirCount, Hostname );
-	if (uid) {
+	if (!to_trash) {
 #ifdef USE_DB
 		if (ctx->db) {
-			if ((ret = maildir_set_uid( ctx, base, uid )) != DRV_OK) {
+			if ((ret = maildir_set_uid( ctx, base, &uid )) != DRV_OK) {
 				free( data->data );
-				return ret;
+				cb( ret, 0, aux );
+				return;
 			}
 		} else
 #endif /* USE_DB */
 		{
 			if ((ret = maildir_uidval_lock( ctx )) != DRV_OK ||
-			    (ret = maildir_obtain_uid( ctx, uid )) != DRV_OK)
-				return ret;
+			    (ret = maildir_obtain_uid( ctx, &uid )) != DRV_OK) {
+				cb( ret, 0, aux );
+				return;
+			}
 			maildir_uidval_unlock( ctx );
-			nfsnprintf( base + bl, sizeof(base) - bl, ",U=%d", *uid );
+			nfsnprintf( base + bl, sizeof(base) - bl, ",U=%d", uid );
 		}
 		prefix = gctx->path;
 		box = "";
@@ -999,16 +1019,19 @@ maildir_store_msg( store_t *gctx, msg_data_t *data, int *uid )
 		if (errno != ENOENT) {
 			perror( buf );
 			free( data->data );
-			return DRV_BOX_BAD;
+			cb( DRV_BOX_BAD, 0, aux );
+			return;
 		}
 		if ((ret = maildir_validate( gctx->conf->path, gctx->conf->trash, gctx->opts & OPEN_CREATE )) != DRV_OK) {
 			free( data->data );
-			return ret;
+			cb( ret, 0, aux );
+			return;
 		}
 		if ((fd = open( buf, O_WRONLY|O_CREAT|O_EXCL, 0600 )) < 0) {
 			perror( buf );
 			free( data->data );
-			return DRV_BOX_BAD;
+			cb( DRV_BOX_BAD, 0, aux );
+			return;
 		}
 	}
 	ret = write( fd, data->data, data->len );
@@ -1019,35 +1042,37 @@ maildir_store_msg( store_t *gctx, msg_data_t *data, int *uid )
 		else
 			error( "Maildir error: %s: partial write\n", buf );
 		close( fd );
-		return DRV_BOX_BAD;
+		cb( DRV_BOX_BAD, 0, aux );
+		return;
 	}
 	close( fd );
 	nfsnprintf( nbuf, sizeof(nbuf), "%s%s/%s/%s%s", prefix, box, subdirs[!(data->flags & F_SEEN)], base, fbuf );
 	if (rename( buf, nbuf )) {
 		perror( nbuf );
-		return DRV_BOX_BAD;
+		cb( DRV_BOX_BAD, 0, aux );
+		return;
 	}
-	if (uid)
-		gctx->count++;
-	return DRV_OK;
+	cb( DRV_OK, uid, aux );
 }
 
-static int
-maildir_find_msg( store_t *gctx, const char *tuid, int *uid )
+static void
+maildir_find_msg( store_t *gctx, const char *tuid,
+                  void (*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 )) {
-			*uid = msg->uid;
-			return DRV_OK;
+			cb( DRV_OK, msg->uid, aux );
+			return;
 		}
-	return DRV_MSG_BAD;
+	cb( DRV_MSG_BAD, -1, aux );
 }
 
-static int
-maildir_set_flags( store_t *gctx, message_t *gmsg, int uid, int add, int del )
+static void
+maildir_set_flags( store_t *gctx, message_t *gmsg, int uid, int add, int del,
+                   void (*cb)( int sts, void *aux ), void *aux )
 {
 	maildir_store_t *ctx = (maildir_store_t *)gctx;
 	maildir_message_t *msg = (maildir_message_t *)gmsg;
@@ -1089,8 +1114,10 @@ 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)
-			return ret;
+		if ((ret = maildir_again( ctx, msg, buf )) != DRV_OK) {
+			cb( ret, aux );
+			return;
+		}
 	}
 	free( msg->base );
 	msg->base = nfmalloc( tl + 1 );
@@ -1099,7 +1126,7 @@ maildir_set_flags( store_t *gctx, message_t *gmsg, int uid, int add, int del )
 	msg->gen.flags &= ~del;
 	gmsg->status &= ~M_RECENT;
 
-	return DRV_OK;
+	cb( DRV_OK, aux );
 }
 
 #ifdef USE_DB
@@ -1119,8 +1146,9 @@ maildir_purge_msg( maildir_store_t *ctx, const char *name )
 }
 #endif /* USE_DB */
 
-static int
-maildir_trash_msg( store_t *gctx, message_t *gmsg )
+static void
+maildir_trash_msg( store_t *gctx, message_t *gmsg,
+                   void (*cb)( int sts, void *aux ), void *aux )
 {
 	maildir_store_t *ctx = (maildir_store_t *)gctx;
 	maildir_message_t *msg = (maildir_message_t *)gmsg;
@@ -1137,30 +1165,38 @@ 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)
-				return ret;
+			if ((ret = maildir_validate( gctx->conf->path, gctx->conf->trash, 1 )) != DRV_OK) {
+				cb( ret, aux );
+				return;
+			}
 			if (!rename( buf, nbuf ))
 				break;
 			if (errno != ENOENT) {
 				perror( nbuf );
-				return DRV_BOX_BAD;
+				cb( DRV_BOX_BAD, aux );
+				return;
 			}
 		}
-		if ((ret = maildir_again( ctx, msg, buf )) != DRV_OK)
-			return ret;
+		if ((ret = maildir_again( ctx, msg, buf )) != DRV_OK) {
+			cb( ret, aux );
+			return;
+		}
 	}
 	gmsg->status |= M_DEAD;
 	gctx->count--;
 
 #ifdef USE_DB
-	if (ctx->db)
-		return maildir_purge_msg( ctx, msg->base );
+	if (ctx->db) {
+		cb( maildir_purge_msg( ctx, msg->base ), aux );
+		return;
+	}
 #endif /* USE_DB */
-	return DRV_OK;
+	cb( DRV_OK, aux );
 }
 
-static int
-maildir_close( store_t *gctx )
+static void
+maildir_close( store_t *gctx,
+               void (*cb)( int sts, void *aux ), void *aux )
 {
 #ifdef USE_DB
 	maildir_store_t *ctx = (maildir_store_t *)gctx;
@@ -1184,23 +1220,36 @@ 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)
-						return ret;
+					if (ctx->db && (ret = maildir_purge_msg( ctx, ((maildir_message_t *)msg)->base )) != DRV_OK) {
+						cb( ret, aux );
+						return;
+					}
 #endif /* USE_DB */
 				}
 			}
-		if (!retry)
-			return DRV_OK;
-		if ((ret = maildir_rescan( (maildir_store_t *)gctx )) != DRV_OK)
-			return ret;
+		if (!retry) {
+			cb( DRV_OK, aux );
+			return;
+		}
+		if ((ret = maildir_rescan( (maildir_store_t *)gctx )) != DRV_OK) {
+			cb( ret, aux );
+			return;
+		}
 	}
 }
 
-static int
-maildir_check( store_t *gctx )
+static void
+maildir_cancel( store_t *gctx,
+                void (*cb)( int sts, void *aux ), void *aux )
+{
+	(void)gctx;
+	cb( DRV_OK, aux );
+}
+
+static void
+maildir_commit( store_t *gctx )
 {
 	(void) gctx;
-	return DRV_OK;
 }
 
 static int
@@ -1248,6 +1297,7 @@ struct driver maildir_driver = {
 	maildir_find_msg,
 	maildir_set_flags,
 	maildir_trash_msg,
-	maildir_check,
-	maildir_close
+	maildir_close,
+	maildir_cancel,
+	maildir_commit,
 };

+ 36 - 19
src/isync.h

@@ -166,9 +166,13 @@ typedef struct {
 } msg_data_t;
 
 #define DRV_OK          0
-#define DRV_MSG_BAD     -1
-#define DRV_BOX_BAD     -2
-#define DRV_STORE_BAD   -3
+#define DRV_MSG_BAD     1
+#define DRV_BOX_BAD     2
+#define DRV_STORE_BAD   3
+#define DRV_SERVER_BAD  4
+#define DRV_CANCELED    5
+
+/* All memory belongs to the driver's user. */
 
 #define DRV_CRLF        1
 
@@ -178,21 +182,32 @@ struct driver {
 	int flags;
 	int (*parse_store)( conffile_t *cfg, store_conf_t **storep, int *err );
 	void (*cleanup)( void );
-	store_t *(*open_store)( store_conf_t *conf );
+	void (*open_store)( store_conf_t *conf,
+	                    void (*cb)( store_t *ctx, void *aux ), void *aux );
 	void (*disown_store)( store_t *ctx );
 	store_t *(*own_store)( store_conf_t *conf );
 	void (*cancel_store)( store_t *ctx );
-	int (*list)( store_t *ctx );
+	void (*list)( store_t *ctx,
+	              void (*cb)( int sts, void *aux ), void *aux );
 	void (*prepare_paths)( store_t *ctx );
 	void (*prepare_opts)( store_t *ctx, int opts );
-	int (*select)( store_t *ctx, int minuid, int maxuid, int *excs, int nexcs );
-	int (*fetch_msg)( store_t *ctx, message_t *msg, msg_data_t *data );
-	int (*store_msg)( store_t *ctx, msg_data_t *data, int *uid ); /* if uid is null, store to trash */
-	int (*find_msg)( store_t *ctx, const char *tuid, int *uid );
-	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 (*trash_msg)( store_t *ctx, message_t *msg ); /* This may expunge the original message immediately, but it needn't to */
-	int (*check)( store_t *ctx ); /* IMAP-style: flush */
-	int (*close)( store_t *ctx ); /* IMAP-style: expunge inclusive */
+	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 );
+	void (*cancel)( store_t *ctx, /* only not yet sent commands */
+	                void (*cb)( int sts, void *aux ), void *aux );
+	void (*commit)( store_t *ctx );
 };
 
 
@@ -217,7 +232,6 @@ void debug( const char *, ... );
 void debugn( const char *, ... );
 void info( const char *, ... );
 void infon( const char *, ... );
-void infoc( char );
 void warn( const char *, ... );
 void error( const char *, ... );
 
@@ -248,12 +262,15 @@ unsigned char arc4_getbyte( void );
 
 extern const char *str_ms[2], *str_hl[2];
 
-#define SYNC_OK      0
-#define SYNC_FAIL    1
-#define SYNC_BAD(ms) (2+(ms))
-#define SYNC_NOGOOD  4 /* internal */
+#define SYNC_OK       0 /* assumed to be 0 */
+#define SYNC_FAIL     1
+#define SYNC_BAD(ms)  (2<<(ms))
+#define SYNC_NOGOOD   8 /* internal */
+#define SYNC_CANCELED 16 /* internal */
 
-int sync_boxes( store_t *ctx[], const char *names[], channel_conf_t * );
+/* All passed pointers must stay alive until cb is called. */
+void sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan,
+                 void (*cb)( int sts, void *aux ), void *aux );
 
 /* config.c */
 

+ 169 - 63
src/main.c

@@ -24,6 +24,7 @@
 #include "isync.h"
 
 #include <stdlib.h>
+#include <stddef.h>
 #include <unistd.h>
 #include <string.h>
 #include <fcntl.h>
@@ -198,7 +199,16 @@ typedef struct {
 	unsigned done:1, skip:1, cben:1;
 } main_vars_t;
 
-static void sync_chans( main_vars_t *mvars );
+#define AUX &mvars->t[t]
+#define MVARS(aux) \
+	int t = *(int *)aux; \
+	main_vars_t *mvars = (main_vars_t *)(((char *)(&((int *)aux)[-t])) - offsetof(main_vars_t, t));
+
+#define E_START  0
+#define E_OPEN   1
+#define E_SYNC   2
+
+static void sync_chans( main_vars_t *mvars, int ent );
 
 int
 main( int argc, char **argv )
@@ -460,19 +470,36 @@ main( int argc, char **argv )
 				break;
 			}
 	mvars->argv = argv;
-	sync_chans( mvars );
+	mvars->cben = 1;
+	sync_chans( mvars, E_START );
 	return mvars->ret;
 }
 
+#define ST_FRESH     0
+#define ST_OPEN      1
+#define ST_CLOSED    2
+
+static void store_opened( store_t *ctx, void *aux );
+static void store_listed( int sts, void *aux );
+static void done_sync_dyn( int sts, void *aux );
+static void done_sync( int sts, void *aux );
+
 static void
-sync_chans( main_vars_t *mvars )
+sync_chans( main_vars_t *mvars, int ent )
 {
 	group_conf_t *group;
 	channel_conf_t *chan;
+	store_t *store;
 	string_list_t *mbox, *sbox, **mboxp, **sboxp;
 	char *channame;
 	int t;
 
+	if (!mvars->cben)
+		return;
+	switch (ent) {
+	case E_OPEN: goto opened;
+	case E_SYNC: goto syncone;
+	}
 	for (;;) {
 		mvars->boxlist = 0;
 		if (!mvars->all) {
@@ -503,36 +530,32 @@ sync_chans( main_vars_t *mvars )
 		merge_actions( mvars->chan, mvars->ops, XOP_HAVE_CREATE, OP_CREATE, 0 );
 		merge_actions( mvars->chan, mvars->ops, XOP_HAVE_EXPUNGE, OP_EXPUNGE, 0 );
 
+		mvars->state[M] = mvars->state[S] = ST_FRESH;
 		info( "Channel %s\n", mvars->chan->name );
 		mvars->boxes[M] = mvars->boxes[S] = mvars->cboxes = 0;
+		mvars->skip = mvars->cben = 0;
 		for (t = 0; t < 2; t++) {
 			mvars->drv[t] = mvars->chan->stores[t]->driver;
-			mvars->ctx[t] = mvars->drv[t]->own_store( mvars->chan->stores[t] );
+			if ((store = mvars->drv[t]->own_store( mvars->chan->stores[t] )))
+				store_opened( store, AUX );
 		}
-		for (t = 0; t < 2; t++)
-			if (!mvars->ctx[t]) {
+		for (t = 0; t < 2 && !mvars->skip; t++)
+			if (mvars->state[t] == ST_FRESH) {
 				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;
-				}
+				mvars->drv[t]->open_store( mvars->chan->stores[t], store_opened, AUX );
 			}
+		mvars->cben = 1;
+	  opened:
+		if (mvars->skip)
+			goto next;
+		if (mvars->state[M] != ST_OPEN || mvars->state[S] != ST_OPEN)
+			return;
+
 		if (mvars->boxlist)
 			mvars->boxp = mvars->boxlist;
 		else if (mvars->chan->patterns) {
-			for (t = 0; t < 2; t++) {
-				if (!mvars->ctx[t]->listed) {
-					if (mvars->drv[t]->list( mvars->ctx[t] ) != DRV_OK) {
-					  screwt:
-						mvars->drv[t]->cancel_store( mvars->ctx[t] );
-						mvars->ctx[t] = 0;
-						mvars->ret = 1;
-						goto next;
-					} else if (mvars->ctx[t]->conf->map_inbox)
-						add_string_list( &mvars->ctx[t]->boxes, mvars->ctx[t]->conf->map_inbox );
-				}
-				mvars->boxes[t] = filter_boxes( mvars->ctx[t]->boxes, mvars->chan->patterns );
-			}
+			mvars->boxes[M] = filter_boxes( mvars->ctx[M]->boxes, mvars->chan->patterns );
+			mvars->boxes[S] = filter_boxes( mvars->ctx[S]->boxes, mvars->chan->patterns );
 			for (mboxp = &mvars->boxes[M]; (mbox = *mboxp); ) {
 				for (sboxp = &mvars->boxes[S]; (sbox = *sboxp); sboxp = &sbox->next)
 					if (!strcmp( sbox->string, mbox->string )) {
@@ -550,60 +573,70 @@ sync_chans( main_vars_t *mvars )
 
 		if (mvars->list && mvars->multiple)
 			printf( "%s:\n", mvars->chan->name );
+	  syncml:
+		mvars->done = mvars->cben = 0;
+	  syncmlx:
 		if (mvars->boxlist) {
-			while ((mvars->names[S] = strsep( &mvars->boxp, ",\n" ))) {
-				if (mvars->list)
-					puts( mvars->names[S] );
-				else {
+			if ((mvars->names[S] = strsep( &mvars->boxp, ",\n" ))) {
+				if (!mvars->list) {
 					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: mvars->ret = 1;
-					}
+					sync_boxes( mvars->ctx, mvars->names, mvars->chan, done_sync, mvars );
+					goto syncw;
 				}
+				puts( mvars->names[S] );
+				goto syncmlx;
 			}
 		} else if (mvars->chan->patterns) {
-			for (mbox = mvars->cboxes; mbox; mbox = mbox->next)
-				if (mvars->list)
-					puts( mbox->string );
-				else {
+			if ((mbox = mvars->cboxes)) {
+				mvars->cboxes = mbox->next;
+				if (!mvars->list) {
 					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: mvars->ret = 1;
-					}
+					sync_boxes( mvars->ctx, mvars->names, mvars->chan, done_sync_dyn, mvars );
+					goto syncw;
 				}
+				puts( mbox->string );
+				free( mbox );
+				goto syncmlx;
+			}
 			for (t = 0; t < 2; t++)
-				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 {
+				if ((mbox = mvars->boxes[t])) {
+					mvars->boxes[t] = mbox->next;
+					if ((mvars->chan->ops[1-t] & OP_MASK_TYPE) && (mvars->chan->ops[1-t] & OP_CREATE)) {
+						if (!mvars->list) {
 							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: mvars->ret = 1;
-							}
+							sync_boxes( mvars->ctx, mvars->names, mvars->chan, done_sync_dyn, mvars );
+							goto syncw;
 						}
+						puts( mbox->string );
+					}
+					free( mbox );
+					goto syncmlx;
 				}
-		} else
-			if (mvars->list)
+		} else {
+			if (!mvars->list) {
+				sync_boxes( mvars->ctx, mvars->chan->boxes, mvars->chan, done_sync, mvars );
+				mvars->skip = 1;
+			  syncw:
+				mvars->cben = 1;
+				if (!mvars->done)
+					return;
+			  syncone:
+				if (!mvars->skip)
+					goto syncml;
+			} else
 				printf( "%s <=> %s\n", mvars->chan->boxes[M], mvars->chan->boxes[S] );
-			else
-				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: mvars->ret = 1;
-				}
+		}
 
 	  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] );
+		for (t = 0; t < 2; t++)
+			if (mvars->state[t] == ST_OPEN) {
+				mvars->drv[t]->disown_store( mvars->ctx[t] );
+				mvars->state[t] = ST_CLOSED;
+			}
+		if (mvars->state[M] != ST_CLOSED || mvars->state[S] != ST_CLOSED) {
+			mvars->skip = mvars->cben = 1;
+			return;
+		}
 		free_string_list( mvars->cboxes );
 		free_string_list( mvars->boxes[M] );
 		free_string_list( mvars->boxes[S] );
@@ -621,3 +654,76 @@ sync_chans( main_vars_t *mvars )
 	for (t = 0; t < N_DRIVERS; t++)
 		drivers[t]->cleanup();
 }
+
+static void
+store_opened( store_t *ctx, void *aux )
+{
+	MVARS(aux)
+
+	if (!ctx) {
+		mvars->state[t] = ST_CLOSED;
+		mvars->ret = mvars->skip = 1;
+		return;
+	}
+	mvars->ctx[t] = ctx;
+	if (mvars->skip) {
+		mvars->state[t] = ST_OPEN;
+		sync_chans( mvars, E_OPEN );
+		return;
+	}
+	if (!mvars->boxlist && mvars->chan->patterns && !ctx->listed)
+		mvars->drv[t]->list( ctx, store_listed, AUX );
+	else {
+		mvars->state[t] = ST_OPEN;
+		sync_chans( mvars, E_OPEN );
+	}
+}
+
+static void
+store_listed( int sts, void *aux )
+{
+	MVARS(aux)
+
+	mvars->state[t] = ST_OPEN;
+	switch (sts) {
+	case DRV_OK:
+		if (mvars->ctx[t]->conf->map_inbox)
+			add_string_list( &mvars->ctx[t]->boxes, mvars->ctx[t]->conf->map_inbox );
+		break;
+	case DRV_STORE_BAD:
+		mvars->drv[t]->cancel_store( mvars->ctx[t] );
+		mvars->state[t] = ST_CLOSED;
+	default:
+		mvars->ret = mvars->skip = 1;
+		break;
+	}
+	sync_chans( mvars, E_OPEN );
+}
+
+static void
+done_sync_dyn( int sts, void *aux )
+{
+	main_vars_t *mvars = (main_vars_t *)aux;
+
+	free( ((char *)mvars->names[S]) - offsetof(string_list_t, string) );
+	done_sync( sts, aux );
+}
+
+static void
+done_sync( int sts, void *aux )
+{
+	main_vars_t *mvars = (main_vars_t *)aux;
+
+	mvars->done = 1;
+	if (sts) {
+		mvars->ret = 1;
+		if (sts & (SYNC_BAD(M) | SYNC_BAD(S))) {
+			mvars->skip = 1;
+			if (sts & SYNC_BAD(M))
+				mvars->state[M] = ST_CLOSED;
+			if (sts & SYNC_BAD(S))
+				mvars->state[S] = ST_CLOSED;
+		}
+	}
+	sync_chans( mvars, E_SYNC );
+}

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 545 - 309
src/sync.c


+ 2 - 10
src/util.c

@@ -43,6 +43,7 @@ debug( const char *msg, ... )
 		vprintf( msg, va );
 		va_end( va );
 		fflush( stdout );
+		need_nl = 0;
 	}
 }
 
@@ -70,6 +71,7 @@ info( const char *msg, ... )
 		vprintf( msg, va );
 		va_end( va );
 		fflush( stdout );
+		need_nl = 0;
 	}
 }
 
@@ -87,16 +89,6 @@ infon( const char *msg, ... )
 	}
 }
 
-void
-infoc( char c )
-{
-	if (!(DFlags & QUIET)) {
-		putchar( c );
-		fflush( stdout );
-		need_nl = Ontty;
-	}
-}
-
 void
 warn( const char *msg, ... )
 {

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно