diff --git a/src/drv_imap.c b/src/drv_imap.c index 9ad1f03..5faf121 100644 --- a/src/drv_imap.c +++ b/src/drv_imap.c @@ -1554,9 +1554,9 @@ imap_prepare_opts( store_t *gctx, int opts ) gctx->opts = opts; } -static int +static void imap_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs, - int (*cb)( int sts, void *aux ), void *aux ) + void (*cb)( int sts, void *aux ), void *aux ) { imap_store_t *ctx = (imap_store_t *)gctx; struct imap_cmd *cmd = new_imap_cmd(); @@ -1609,18 +1609,18 @@ imap_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs, bail: free( excs ); - return cb( ret, aux ); + cb( ret, aux ); } -static int +static void imap_fetch_msg( store_t *ctx, message_t *msg, msg_data_t *data, - int (*cb)( int sts, void *aux ), void *aux ) + void (*cb)( int sts, void *aux ), void *aux ) { struct imap_cmd *cmd = new_imap_cmd(); cmd->param.uid = msg->uid; cmd->param.aux = data; - return cb( imap_exec_m( (imap_store_t *)ctx, cmd, "UID FETCH %d (%sBODY.PEEK[])", - msg->uid, (msg->status & M_FLAGS) ? "" : "FLAGS " ), aux ); + cb( imap_exec_m( (imap_store_t *)ctx, cmd, "UID FETCH %d (%sBODY.PEEK[])", + msg->uid, (msg->status & M_FLAGS) ? "" : "FLAGS " ), aux ); } static int @@ -1652,9 +1652,9 @@ imap_flags_helper( imap_store_t *ctx, int uid, char what, int flags) return process_imap_replies( ctx ) == RESP_CANCEL ? DRV_CANCELED : DRV_OK; } -static int +static void imap_set_flags( store_t *gctx, message_t *msg, int uid, int add, int del, - int (*cb)( int sts, void *aux ), void *aux ) + void (*cb)( int sts, void *aux ), void *aux ) { imap_store_t *ctx = (imap_store_t *)gctx; int ret; @@ -1669,31 +1669,31 @@ 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; - return cb( ret, aux ); + cb( ret, aux ); } -static int +static void imap_close( store_t *ctx, - int (*cb)( int sts, void *aux ), void *aux ) + void (*cb)( int sts, void *aux ), void *aux ) { - return cb( imap_exec_b( (imap_store_t *)ctx, 0, "CLOSE" ), aux ); + cb( imap_exec_b( (imap_store_t *)ctx, 0, "CLOSE" ), aux ); } -static int +static void imap_trash_msg( store_t *gctx, message_t *msg, - int (*cb)( int sts, void *aux ), void *aux ) + void (*cb)( int sts, void *aux ), void *aux ) { imap_store_t *ctx = (imap_store_t *)gctx; struct imap_cmd *cmd = new_imap_cmd(); cmd->param.create = 1; cmd->param.to_trash = 1; - return cb( imap_exec_m( ctx, cmd, "UID COPY %d \"%s%s\"", - msg->uid, ctx->prefix, gctx->conf->trash ), aux ); + cb( imap_exec_m( ctx, cmd, "UID COPY %d \"%s%s\"", + msg->uid, ctx->prefix, gctx->conf->trash ), aux ); } -static int +static void imap_store_msg( store_t *gctx, msg_data_t *data, int to_trash, - int (*cb)( int sts, int uid, void *aux ), void *aux ) + void (*cb)( int sts, int uid, void *aux ), void *aux ) { imap_store_t *ctx = (imap_store_t *)gctx; struct imap_cmd *cmd = new_imap_cmd(); @@ -1722,16 +1722,15 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int to_trash, box = gctx->name; prefix = !strcmp( box, "INBOX" ) ? "" : ctx->prefix; } - ret = imap_exec_m( ctx, cmd, "APPEND \"%s%s\" %s", prefix, box, flagstr ); - if (ret != DRV_OK) - return cb( ret, -1, aux ); - - return cb( DRV_OK, uid, aux ); + if ((ret = imap_exec_m( ctx, cmd, "APPEND \"%s%s\" %s", prefix, box, flagstr )) != DRV_OK) + cb( ret, -1, aux ); + else + cb( DRV_OK, uid, aux ); } -static int +static void imap_find_msg( store_t *gctx, const char *tuid, - int (*cb)( int sts, int uid, void *aux ), void *aux ) + void (*cb)( int sts, int uid, void *aux ), void *aux ) { imap_store_t *ctx = (imap_store_t *)gctx; struct imap_cmd *cmd = new_imap_cmd(); @@ -1741,9 +1740,9 @@ imap_find_msg( store_t *gctx, const char *tuid, cmd->param.aux = &uid; uid = -1; /* in case we get no SEARCH response at all */ if ((ret = imap_exec_m( ctx, cmd, "UID SEARCH HEADER X-TUID %." stringify(TUIDL) "s", tuid )) != DRV_OK) - return cb( ret, -1, aux ); + cb( ret, -1, aux ); else - return cb( uid <= 0 ? DRV_MSG_BAD : DRV_OK, uid, aux ); + cb( uid <= 0 ? DRV_MSG_BAD : DRV_OK, uid, aux ); } static void diff --git a/src/drv_maildir.c b/src/drv_maildir.c index 91822d9..3a363a6 100644 --- a/src/drv_maildir.c +++ b/src/drv_maildir.c @@ -771,9 +771,9 @@ maildir_prepare_opts( store_t *gctx, int opts ) gctx->opts = opts; } -static int +static void maildir_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs, - int (*cb)( int sts, void *aux ), void *aux ) + void (*cb)( int sts, void *aux ), void *aux ) { maildir_store_t *ctx = (maildir_store_t *)gctx; message_t **msgapp; @@ -789,14 +789,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 ((ret = maildir_validate( gctx->path, "", ctx->gen.opts & OPEN_CREATE, ctx )) != DRV_OK) - return cb( ret, aux ); + if ((ret = maildir_validate( gctx->path, "", ctx->gen.opts & OPEN_CREATE, ctx )) != DRV_OK) { + cb( ret, 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 cb( DRV_BOX_BAD, aux ); + cb( DRV_BOX_BAD, aux ); + return; } #else if ((ctx->uvfd = open( uvpath, O_RDWR, 0600 )) < 0) { @@ -811,7 +814,8 @@ maildir_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs, goto fnok; } perror( uvpath ); - return cb( DRV_BOX_BAD, aux ); + cb( DRV_BOX_BAD, aux ); + return; } dbok: #if SEEK_SET != 0 @@ -823,7 +827,8 @@ maildir_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs, bork: close( ctx->uvfd ); ctx->uvfd = -1; - return cb( DRV_BOX_BAD, aux ); + cb( DRV_BOX_BAD, aux ); + return; } if (db_create( &ctx->db, 0, 0 )) { fputs( "Maildir error: db_create() failed\n", stderr ); @@ -853,14 +858,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 cb( DRV_BOX_BAD, aux ); + 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 cb( DRV_OK, aux ); + cb( DRV_OK, aux ); } static int @@ -928,9 +935,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 +static void maildir_fetch_msg( store_t *gctx, message_t *gmsg, msg_data_t *data, - int (*cb)( int sts, void *aux ), void *aux ) + void (*cb)( int sts, void *aux ), void *aux ) { maildir_store_t *ctx = (maildir_store_t *)gctx; maildir_message_t *msg = (maildir_message_t *)gmsg; @@ -942,8 +949,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 cb( ret, aux ); + if ((ret = maildir_again( ctx, msg, buf )) != DRV_OK) { + cb( ret, aux ); + return; + } } fstat( fd, &st ); data->len = st.st_size; @@ -951,12 +960,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 cb( DRV_MSG_BAD, aux ); + cb( DRV_MSG_BAD, aux ); + return; } close( fd ); if (!(gmsg->status & M_FLAGS)) data->flags = maildir_parse_flags( msg->base ); - return cb( DRV_OK, aux ); + cb( DRV_OK, aux ); } static int @@ -974,9 +984,9 @@ maildir_make_flags( int flags, char *buf ) return d; } -static int +static void maildir_store_msg( store_t *gctx, msg_data_t *data, int to_trash, - int (*cb)( int sts, int uid, void *aux ), void *aux ) + void (*cb)( int sts, int uid, void *aux ), void *aux ) { maildir_store_t *ctx = (maildir_store_t *)gctx; const char *prefix, *box; @@ -989,14 +999,17 @@ 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 ); - return cb( ret, 0, aux ); + 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 cb( ret, 0, aux ); + (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 ); } @@ -1013,16 +1026,19 @@ maildir_store_msg( store_t *gctx, msg_data_t *data, int to_trash, if (errno != ENOENT) { perror( buf ); free( data->data ); - return cb( DRV_BOX_BAD, 0, aux ); + cb( DRV_BOX_BAD, 0, aux ); + return; } if ((ret = maildir_validate( gctx->conf->path, gctx->conf->trash, gctx->opts & OPEN_CREATE, ctx )) != DRV_OK) { free( data->data ); - return cb( ret, 0, aux ); + cb( ret, 0, aux ); + return; } if ((fd = open( buf, O_WRONLY|O_CREAT|O_EXCL, 0600 )) < 0) { perror( buf ); free( data->data ); - return cb( DRV_BOX_BAD, 0, aux ); + cb( DRV_BOX_BAD, 0, aux ); + return; } } ret = write( fd, data->data, data->len ); @@ -1033,38 +1049,43 @@ maildir_store_msg( store_t *gctx, msg_data_t *data, int to_trash, else error( "Maildir error: %s: partial write\n", buf ); close( fd ); - return cb( DRV_BOX_BAD, 0, aux ); + cb( DRV_BOX_BAD, 0, aux ); + return; } if (close( fd ) < 0) { /* Quota exceeded may cause this. */ perror( buf ); - return cb( DRV_BOX_BAD, 0, aux ); + cb( DRV_BOX_BAD, 0, aux ); + return; } /* 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 ); - return cb( DRV_BOX_BAD, 0, aux ); + cb( DRV_BOX_BAD, 0, aux ); + return; } - return cb( DRV_OK, uid, aux ); + cb( DRV_OK, uid, aux ); } -static int +static void maildir_find_msg( store_t *gctx, const char *tuid, - int (*cb)( int sts, int uid, void *aux ), void *aux ) + 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 )) - return 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 )) { + cb( DRV_OK, msg->uid, aux ); + return; + } + cb( DRV_MSG_BAD, -1, aux ); } -static int +static void maildir_set_flags( store_t *gctx, message_t *gmsg, int uid, int add, int del, - int (*cb)( int sts, void *aux ), void *aux ) + void (*cb)( int sts, void *aux ), void *aux ) { maildir_store_t *ctx = (maildir_store_t *)gctx; maildir_message_t *msg = (maildir_message_t *)gmsg; @@ -1106,8 +1127,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 cb( ret, aux ); + if ((ret = maildir_again( ctx, msg, buf )) != DRV_OK) { + cb( ret, aux ); + return; + } } free( msg->base ); msg->base = nfmalloc( tl + 1 ); @@ -1116,7 +1139,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 cb( DRV_OK, aux ); + cb( DRV_OK, aux ); } #ifdef USE_DB @@ -1136,9 +1159,9 @@ maildir_purge_msg( maildir_store_t *ctx, const char *name ) } #endif /* USE_DB */ -static int +static void maildir_trash_msg( store_t *gctx, message_t *gmsg, - int (*cb)( int sts, void *aux ), void *aux ) + void (*cb)( int sts, void *aux ), void *aux ) { maildir_store_t *ctx = (maildir_store_t *)gctx; maildir_message_t *msg = (maildir_message_t *)gmsg; @@ -1155,31 +1178,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, ctx )) != DRV_OK) - return cb( ret, aux ); + if ((ret = maildir_validate( gctx->conf->path, gctx->conf->trash, 1, ctx )) != DRV_OK) { + cb( ret, aux ); + return; + } if (!rename( buf, nbuf )) break; if (errno != ENOENT) { perror( nbuf ); - return cb( DRV_BOX_BAD, aux ); + cb( DRV_BOX_BAD, aux ); + return; } } - if ((ret = maildir_again( ctx, msg, buf )) != DRV_OK) - return cb( ret, aux ); + 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 cb( maildir_purge_msg( ctx, msg->base ), aux ); + if (ctx->db) { + cb( maildir_purge_msg( ctx, msg->base ), aux ); + return; + } #endif /* USE_DB */ - return cb( DRV_OK, aux ); + cb( DRV_OK, aux ); } -static int +static void maildir_close( store_t *gctx, - int (*cb)( int sts, void *aux ), void *aux ) + void (*cb)( int sts, void *aux ), void *aux ) { #ifdef USE_DB maildir_store_t *ctx = (maildir_store_t *)gctx; @@ -1203,15 +1233,21 @@ 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 cb( ret, aux ); + 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 cb( DRV_OK, aux ); - if ((ret = maildir_rescan( (maildir_store_t *)gctx )) != DRV_OK) - return cb( ret, aux ); + if (!retry) { + cb( DRV_OK, aux ); + return; + } + if ((ret = maildir_rescan( (maildir_store_t *)gctx )) != DRV_OK) { + cb( ret, aux ); + return; + } } } diff --git a/src/isync.h b/src/isync.h index c1c6179..b34f08c 100644 --- a/src/isync.h +++ b/src/isync.h @@ -210,20 +210,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 ); - 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 (*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)( void *aux ), void *aux ); void (*commit)( store_t *ctx ); diff --git a/src/sync.c b/src/sync.c index 5fda78a..b356013 100644 --- a/src/sync.c +++ b/src/sync.c @@ -145,7 +145,7 @@ typedef struct { channel_conf_t *chan; store_t *ctx[2]; driver_t *drv[2]; - int state[2], ret; + int state[2], ref_count, ret; int find_old_total[2], find_old_done[2]; int new_total[2], new_done[2]; int find_new_total[2], find_new_done[2]; @@ -155,6 +155,26 @@ typedef struct { unsigned find:1; } sync_vars_t; +static void sync_ref( sync_vars_t *svars ) { ++svars->ref_count; } +static int sync_deref( sync_vars_t *svars ); +static int deref_check_cancel( sync_vars_t *svars ); +static int check_cancel( sync_vars_t *svars ); + +#define DRIVER_CALL_RET(call) \ + do { \ + sync_ref( svars ); \ + svars->drv[t]->call; \ + return deref_check_cancel( svars ); \ + } while (0) + +#define DRIVER_CALL(call) \ + do { \ + sync_ref( svars ); \ + svars->drv[t]->call; \ + if (deref_check_cancel( svars )) \ + return; \ + } while (0) + #define AUX &svars->t[t] #define DECL_SVARS \ int t; \ @@ -192,27 +212,28 @@ typedef struct { typedef struct copy_vars { - int (*cb)( int sts, int uid, struct copy_vars *vars ); + void (*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 int msg_fetched( int sts, void *aux ); +static void msg_fetched( int sts, void *aux ); static int copy_msg( copy_vars_t *vars ) { DECL_INIT_SVARS(vars->aux); + t ^= 1; vars->data.flags = vars->msg->flags; - return svars->drv[1-t]->fetch_msg( svars->ctx[1-t], vars->msg, &vars->data, msg_fetched, vars ); + DRIVER_CALL_RET(fetch_msg( svars->ctx[t], vars->msg, &vars->data, msg_fetched, vars )); } -static int msg_stored( int sts, int uid, void *aux ); +static void msg_stored( int sts, int uid, void *aux ); -static int +static void msg_fetched( int sts, void *aux ) { copy_vars_t *vars = (copy_vars_t *)aux; @@ -260,7 +281,8 @@ msg_fetched( int sts, void *aux ) warn( "Warning: message %d from %s has incomplete header.\n", vars->msg->uid, str_ms[1-t] ); free( fmap ); - return vars->cb( SYNC_NOGOOD, 0, vars ); + vars->cb( SYNC_NOGOOD, 0, vars ); + return; oke: extra += 8 + TUIDL + 1 + (tcr && (!scr || hcrs)); } @@ -327,17 +349,21 @@ msg_fetched( int sts, void *aux ) free( fmap ); } - return svars->drv[t]->store_msg( svars->ctx[t], &vars->data, !vars->srec, msg_stored, vars ); + svars->drv[t]->store_msg( svars->ctx[t], &vars->data, !vars->srec, msg_stored, vars ); + break; case DRV_CANCELED: - return vars->cb( SYNC_CANCELED, 0, vars ); + vars->cb( SYNC_CANCELED, 0, vars ); + break; case DRV_MSG_BAD: - return vars->cb( SYNC_NOGOOD, 0, vars ); + vars->cb( SYNC_NOGOOD, 0, vars ); + break; default: - return vars->cb( SYNC_FAIL, 0, vars ); + vars->cb( SYNC_FAIL, 0, vars ); + break; } } -static int +static void msg_stored( int sts, int uid, void *aux ) { copy_vars_t *vars = (copy_vars_t *)aux; @@ -345,17 +371,21 @@ msg_stored( int sts, int uid, void *aux ) switch (sts) { case DRV_OK: - return vars->cb( SYNC_OK, uid, vars ); + vars->cb( SYNC_OK, uid, vars ); + break; case DRV_CANCELED: - return vars->cb( SYNC_CANCELED, 0, vars ); + vars->cb( SYNC_CANCELED, 0, vars ); + break; case DRV_MSG_BAD: INIT_SVARS(vars->aux); (void)svars; warn( "Warning: %s refuses to store message %d from %s.\n", str_ms[t], vars->msg->uid, str_ms[1-t] ); - return vars->cb( SYNC_NOGOOD, 0, vars ); + vars->cb( SYNC_NOGOOD, 0, vars ); + break; default: - return vars->cb( SYNC_FAIL, 0, vars ); + vars->cb( SYNC_FAIL, 0, vars ); + break; } } @@ -433,6 +463,19 @@ store_bad( void *aux ) cancel_sync( svars ); } +static int +deref_check_cancel( sync_vars_t *svars ) +{ + if (sync_deref( svars )) + return -1; + return check_cancel( svars ); +} + +static int +check_cancel( sync_vars_t *svars ) +{ + return (svars->state[M] | svars->state[S]) & (ST_SENT_CANCEL | ST_CANCELED); +} static int check_ret( int sts, void *aux ) @@ -454,7 +497,7 @@ check_ret( int sts, void *aux ) #define SVARS_CHECK_RET \ DECL_SVARS; \ if (check_ret( sts, aux )) \ - return 1; \ + return; \ INIT_SVARS(aux) #define SVARS_CHECK_RET_VARS(type) \ @@ -462,7 +505,7 @@ check_ret( int sts, void *aux ) DECL_SVARS; \ if (check_ret( sts, vars->aux )) { \ free( vars ); \ - return 1; \ + return; \ } \ INIT_SVARS(vars->aux) @@ -470,7 +513,7 @@ check_ret( int sts, void *aux ) DECL_SVARS; \ if (sts == SYNC_CANCELED) { \ free( vars ); \ - return 1; \ + return; \ } \ INIT_SVARS(vars->aux) @@ -508,6 +551,7 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan, svars = nfcalloc( sizeof(*svars) ); svars->t[1] = 1; + svars->ref_count = 1; svars->cb = cb; svars->aux = aux; svars->ctx[0] = ctx[0]; @@ -830,7 +874,7 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan, select_box( svars, S, (ctx[S]->opts & OPEN_OLD) ? 1 : INT_MAX, 0, 0 ); } -static int box_selected( int sts, void *aux ); +static void box_selected( int sts, void *aux ); static int select_box( sync_vars_t *svars, int t, int minwuid, int *mexcs, int nmexcs ) @@ -851,7 +895,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 ); - return svars->drv[t]->select( svars->ctx[t], minwuid, maxwuid, mexcs, nmexcs, box_selected, AUX ); + DRIVER_CALL_RET(select( svars->ctx[t], minwuid, maxwuid, mexcs, nmexcs, box_selected, AUX )); } typedef struct { @@ -859,10 +903,10 @@ typedef struct { sync_rec_t *srec; } find_vars_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 msg_found_sel( int sts, int uid, void *aux ); +static void msgs_found_sel( sync_vars_t *svars, int t ); -static int +static void box_selected( int sts, void *aux ) { find_vars_t *fv; @@ -874,7 +918,7 @@ box_selected( int sts, void *aux ) str_ms[t], svars->ctx[t]->uidvalidity, svars->uidval[t] ); svars->ret |= SYNC_FAIL; cancel_sync( svars ); - return 1; + return; } info( "%s: %d messages, %d recent\n", str_ms[t], svars->ctx[t]->count, svars->ctx[t]->recent ); @@ -897,16 +941,15 @@ box_selected( int sts, void *aux ) fv = nfmalloc( sizeof(*fv) ); fv->aux = AUX; fv->srec = srec; - if (svars->drv[t]->find_msg( svars->ctx[t], srec->tuid, msg_found_sel, fv )) - return 1; + DRIVER_CALL(find_msg( svars->ctx[t], srec->tuid, msg_found_sel, fv )); } } } svars->state[t] |= ST_SENT_FIND_OLD; - return msgs_found_sel( svars, t ); + msgs_found_sel( svars, t ); } -static int +static void msg_found_sel( int sts, int uid, void *aux ) { SVARS_CHECK_RET_VARS(find_vars_t); @@ -927,7 +970,7 @@ msg_found_sel( int sts, int uid, void *aux ) free( vars ); svars->find_old_done[t]++; stats( svars ); - return msgs_found_sel( svars, t ); + msgs_found_sel( svars, t ); } typedef struct { @@ -936,15 +979,15 @@ typedef struct { int aflags, dflags; } flag_vars_t; -static int flags_set_del( int sts, void *aux ); -static int flags_set_sync( int sts, void *aux ); +static void flags_set_del( int sts, void *aux ); +static void flags_set_sync( int sts, void *aux ); static void flags_set_sync_p2( sync_vars_t *svars, sync_rec_t *srec, int t ); 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( 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 int msgs_copied( sync_vars_t *svars, int t ); +static void msgs_copied( sync_vars_t *svars, int t ); -static int +static void msgs_found_sel( sync_vars_t *svars, int t ) { sync_rec_t *srec, *nsrec = 0; @@ -957,7 +1000,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_old_total[t]) - return 0; + return; /* * Mapping tmsg -> srec (this variant) is dog slow for new messages. @@ -1053,11 +1096,12 @@ msgs_found_sel( sync_vars_t *svars, int t ) for (t = 0; t < nmexcs; t++) debugn( " %d", mexcs[t] ); debug( "\n" ); - return select_box( svars, M, minwuid, mexcs, nmexcs ); + select_box( svars, M, minwuid, mexcs, nmexcs ); + return; } if (!(svars->state[1-t] & ST_SENT_FIND_OLD) || svars->find_old_done[1-t] < svars->find_old_total[1-t]) - return 0; + return; if (svars->uidval[M] < 0 || svars->uidval[S] < 0) { svars->uidval[M] = svars->ctx[M]->uidvalidity; @@ -1113,7 +1157,7 @@ msgs_found_sel( sync_vars_t *svars, int t ) 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 ); if (copy_msg( cv )) - return 1; + return; } else { if (tmsg->srec) { debug( " -> not %sing - still too big\n", str_hl[t] ); @@ -1125,8 +1169,7 @@ msgs_found_sel( sync_vars_t *svars, int t ) } } svars->state[t] |= ST_SENT_NEW; - if (msgs_copied( svars, t )) - return 1; + msgs_copied( svars, t ); } debug( "synchronizing old entries\n" ); @@ -1164,8 +1207,7 @@ msgs_found_sel( sync_vars_t *svars, int t ) fv = nfmalloc( sizeof(*fv) ); fv->aux = AUX; fv->srec = srec; - if (svars->drv[t]->set_flags( svars->ctx[t], srec->msg[t], srec->uid[t], F_DELETED, 0, flags_set_del, fv )) - return 1; + DRIVER_CALL(set_flags( svars->ctx[t], srec->msg[t], srec->uid[t], F_DELETED, 0, flags_set_del, fv )); } else debug( " not %sing delete\n", str_hl[t] ); } else if (!srec->msg[1-t]) @@ -1275,8 +1317,7 @@ msgs_found_sel( sync_vars_t *svars, int t ) fv->srec = srec; fv->aflags = aflags; fv->dflags = dflags; - if (svars->drv[t]->set_flags( svars->ctx[t], srec->msg[t], srec->uid[t], aflags, dflags, flags_set_sync, fv )) - return 1; + DRIVER_CALL(set_flags( svars->ctx[t], srec->msg[t], srec->uid[t], aflags, dflags, flags_set_sync, fv )); } else flags_set_sync_p2( svars, srec, t ); } @@ -1285,12 +1326,11 @@ msgs_found_sel( sync_vars_t *svars, int t ) svars->drv[t]->commit( svars->ctx[t] ); svars->state[t] |= ST_SENT_FLAGS; if (msgs_flags_set( svars, t )) - return 1; + return; } - return 0; } -static int +static void msg_copied( int sts, int uid, copy_vars_t *vars ) { SVARS_CHECK_CANCEL_RET; @@ -1306,12 +1346,12 @@ msg_copied( int sts, int uid, copy_vars_t *vars ) default: cancel_sync( svars ); free( vars ); - return 1; + return; } free( vars ); svars->new_done[t]++; stats( svars ); - return msgs_copied( svars, t ); + msgs_copied( svars, t ); } static void @@ -1332,17 +1372,17 @@ msg_copied_p2( sync_vars_t *svars, sync_rec_t *srec, int t, message_t *tmsg, int } } -static int msg_found_new( int sts, int uid, void *aux ); -static int sync_close( sync_vars_t *svars, int t ); +static void msg_found_new( int sts, int uid, void *aux ); +static void sync_close( sync_vars_t *svars, int t ); -static int +static void 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 0; + return; debug( "finding just copied messages on %s\n", str_ms[t] ); for (srec = svars->srecs; srec; srec = srec->next) { @@ -1355,15 +1395,14 @@ msgs_copied( sync_vars_t *svars, int t ) fv = nfmalloc( sizeof(*fv) ); fv->aux = AUX; fv->srec = srec; - if (svars->drv[t]->find_msg( svars->ctx[t], srec->tuid, msg_found_new, fv )) - return 1; + DRIVER_CALL(find_msg( svars->ctx[t], srec->tuid, msg_found_new, fv )); } } svars->state[t] |= ST_SENT_FIND_NEW; - return sync_close( svars, t ); + sync_close( svars, t ); } -static int +static void msg_found_new( int sts, int uid, void *aux ) { SVARS_CHECK_RET_VARS(find_vars_t); @@ -1382,10 +1421,10 @@ msg_found_new( int sts, int uid, void *aux ) free( vars ); svars->find_new_done[t]++; stats( svars ); - return sync_close( svars, t ); + sync_close( svars, t ); } -static int +static void flags_set_del( int sts, void *aux ) { SVARS_CHECK_RET_VARS(flag_vars_t); @@ -1399,10 +1438,10 @@ flags_set_del( int sts, void *aux ) free( vars ); svars->flags_done[t]++; stats( svars ); - return msgs_flags_set( svars, t ); + msgs_flags_set( svars, t ); } -static int +static void flags_set_sync( int sts, void *aux ) { SVARS_CHECK_RET_VARS(flag_vars_t); @@ -1418,7 +1457,7 @@ flags_set_sync( int sts, void *aux ) free( vars ); svars->flags_done[t]++; stats( svars ); - return msgs_flags_set( svars, t ); + msgs_flags_set( svars, t ); } static void @@ -1448,8 +1487,8 @@ flags_set_sync_p2( sync_vars_t *svars, sync_rec_t *srec, int t ) } } -static int msg_trashed( int sts, void *aux ); -static int msg_rtrashed( int sts, int uid, copy_vars_t *vars ); +static void msg_trashed( int sts, void *aux ); +static void msg_rtrashed( int sts, int uid, copy_vars_t *vars ); static int msgs_flags_set( sync_vars_t *svars, int t ) @@ -1470,8 +1509,10 @@ 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 ); - if (svars->drv[t]->trash_msg( svars->ctx[t], tmsg, msg_trashed, AUX )) - return 1; + sync_ref( svars ); + svars->drv[t]->trash_msg( svars->ctx[t], tmsg, msg_trashed, AUX ); + if (deref_check_cancel( svars )) + return -1; } else debug( "%s: not trashing message %d - not new\n", str_ms[t], tmsg->uid ); } else { @@ -1486,7 +1527,7 @@ msgs_flags_set( sync_vars_t *svars, int t ) cv->srec = 0; cv->msg = tmsg; if (copy_msg( cv )) - return 1; + return -1; } else debug( "%s: not remote trashing message %d - too big\n", str_ms[t], tmsg->uid ); } else @@ -1495,10 +1536,11 @@ msgs_flags_set( sync_vars_t *svars, int t ) } } svars->state[t] |= ST_SENT_TRASH; - return sync_close( svars, t ); + sync_close( svars, t ); + return 0; } -static int +static void msg_trashed( int sts, void *aux ) { DECL_SVARS; @@ -1506,14 +1548,14 @@ msg_trashed( int sts, void *aux ) if (sts == DRV_MSG_BAD) sts = DRV_BOX_BAD; if (check_ret( sts, aux )) - return 1; + return; INIT_SVARS(aux); svars->trash_done[t]++; stats( svars ); - return sync_close( svars, t ); + sync_close( svars, t ); } -static int +static void msg_rtrashed( int sts, int uid, copy_vars_t *vars ) { SVARS_CHECK_CANCEL_RET; @@ -1525,40 +1567,39 @@ msg_rtrashed( int sts, int uid, copy_vars_t *vars ) default: cancel_sync( svars ); free( vars ); - return 1; + return; } free( vars ); svars->trash_done[t]++; stats( svars ); - return sync_close( svars, t ); + sync_close( svars, t ); } -static int box_closed( int sts, void *aux ); +static void box_closed( int sts, void *aux ); static void box_closed_p2( sync_vars_t *svars, int t ); -static int +static void 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 0; + return; if ((svars->chan->ops[t] & OP_EXPUNGE) /*&& !(svars->state[t] & ST_TRASH_BAD)*/) { debug( "expunging %s\n", str_ms[t] ); - return svars->drv[t]->close( svars->ctx[t], box_closed, AUX ); + svars->drv[t]->close( svars->ctx[t], box_closed, AUX ); + } else { + box_closed_p2( svars, t ); } - box_closed_p2( svars, t ); - return 0; } -static int +static void box_closed( int sts, void *aux ) { SVARS_CHECK_RET; svars->state[t] |= ST_DID_EXPUNGE; box_closed_p2( svars, t ); - return 0; } static void @@ -1655,16 +1696,23 @@ sync_bail1( sync_vars_t *svars ) static void sync_bail2( sync_vars_t *svars ) { - void (*cb)( int sts, void *aux ) = svars->cb; - void *aux = svars->aux; - int ret = svars->ret; - free( svars->lname ); free( svars->nname ); free( svars->jname ); free( svars->dname ); - free( svars ); error( "" ); - cb( ret, aux ); + sync_deref( svars ); } +static int sync_deref( sync_vars_t *svars ) +{ + if (!--svars->ref_count) { + void (*cb)( int sts, void *aux ) = svars->cb; + void *aux = svars->aux; + int ret = svars->ret; + free( svars ); + cb( ret, aux ); + return -1; + } + return 0; +}