fix error paths wrt sync drivers, take 2

synchronous error codes which are passed through callbacks aren't a
particularly good idea, after all: latest when the callback does stuff
which does not concern the caller, the return code becomes ambiguous.
instead, protect the sync_vars object with a refcount when invoking
driver functions from loops, as the callbacks they call could invalidate
the object and we would have no way of knowing that the loop should be
aborted prematurely. the upcoming async imap driver will also need a
refcount to protect the cancelation marker of the imap socket dispatcher
loop.
This commit is contained in:
Oswald Buddenhagen 2012-07-29 23:14:48 +02:00
parent ec8f440383
commit ea951a697f
4 changed files with 270 additions and 187 deletions

View File

@ -1554,9 +1554,9 @@ imap_prepare_opts( store_t *gctx, int opts )
gctx->opts = opts; gctx->opts = opts;
} }
static int static void
imap_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs, 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; imap_store_t *ctx = (imap_store_t *)gctx;
struct imap_cmd *cmd = new_imap_cmd(); struct imap_cmd *cmd = new_imap_cmd();
@ -1609,17 +1609,17 @@ imap_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs,
bail: bail:
free( excs ); 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, 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(); struct imap_cmd *cmd = new_imap_cmd();
cmd->param.uid = msg->uid; cmd->param.uid = msg->uid;
cmd->param.aux = data; cmd->param.aux = data;
return cb( imap_exec_m( (imap_store_t *)ctx, cmd, "UID FETCH %d (%sBODY.PEEK[])", cb( imap_exec_m( (imap_store_t *)ctx, cmd, "UID FETCH %d (%sBODY.PEEK[])",
msg->uid, (msg->status & M_FLAGS) ? "" : "FLAGS " ), aux ); msg->uid, (msg->status & M_FLAGS) ? "" : "FLAGS " ), aux );
} }
@ -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; 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, 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; imap_store_t *ctx = (imap_store_t *)gctx;
int ret; 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) && if ((!add || (ret = imap_flags_helper( ctx, uid, '+', add )) == DRV_OK) &&
(!del || (ret = imap_flags_helper( ctx, uid, '-', del )) == DRV_OK)) (!del || (ret = imap_flags_helper( ctx, uid, '-', del )) == DRV_OK))
ret = DRV_OK; ret = DRV_OK;
return cb( ret, aux ); cb( ret, aux );
} }
static int static void
imap_close( store_t *ctx, 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, 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; imap_store_t *ctx = (imap_store_t *)gctx;
struct imap_cmd *cmd = new_imap_cmd(); struct imap_cmd *cmd = new_imap_cmd();
cmd->param.create = 1; cmd->param.create = 1;
cmd->param.to_trash = 1; cmd->param.to_trash = 1;
return cb( imap_exec_m( ctx, cmd, "UID COPY %d \"%s%s\"", cb( imap_exec_m( ctx, cmd, "UID COPY %d \"%s%s\"",
msg->uid, ctx->prefix, gctx->conf->trash ), aux ); 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, 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; imap_store_t *ctx = (imap_store_t *)gctx;
struct imap_cmd *cmd = new_imap_cmd(); 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; box = gctx->name;
prefix = !strcmp( box, "INBOX" ) ? "" : ctx->prefix; prefix = !strcmp( box, "INBOX" ) ? "" : ctx->prefix;
} }
ret = imap_exec_m( ctx, cmd, "APPEND \"%s%s\" %s", prefix, box, flagstr ); if ((ret = imap_exec_m( ctx, cmd, "APPEND \"%s%s\" %s", prefix, box, flagstr )) != DRV_OK)
if (ret != DRV_OK) cb( ret, -1, aux );
return cb( ret, -1, aux ); else
cb( DRV_OK, uid, aux );
return cb( DRV_OK, uid, aux );
} }
static int static void
imap_find_msg( store_t *gctx, const char *tuid, 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; imap_store_t *ctx = (imap_store_t *)gctx;
struct imap_cmd *cmd = new_imap_cmd(); struct imap_cmd *cmd = new_imap_cmd();
@ -1741,9 +1740,9 @@ imap_find_msg( store_t *gctx, const char *tuid,
cmd->param.aux = &uid; cmd->param.aux = &uid;
uid = -1; /* in case we get no SEARCH response at all */ 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) 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 else
return cb( uid <= 0 ? DRV_MSG_BAD : DRV_OK, uid, aux ); cb( uid <= 0 ? DRV_MSG_BAD : DRV_OK, uid, aux );
} }
static void static void

View File

@ -771,9 +771,9 @@ maildir_prepare_opts( store_t *gctx, int opts )
gctx->opts = opts; gctx->opts = opts;
} }
static int static void
maildir_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs, 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; maildir_store_t *ctx = (maildir_store_t *)gctx;
message_t **msgapp; 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->excs = nfrealloc( excs, nexcs * sizeof(int) );
ctx->nexcs = nexcs; ctx->nexcs = nexcs;
if ((ret = maildir_validate( gctx->path, "", ctx->gen.opts & OPEN_CREATE, ctx )) != DRV_OK) if ((ret = maildir_validate( gctx->path, "", ctx->gen.opts & OPEN_CREATE, ctx )) != DRV_OK) {
return cb( ret, aux ); cb( ret, aux );
return;
}
nfsnprintf( uvpath, sizeof(uvpath), "%s/.uidvalidity", gctx->path ); nfsnprintf( uvpath, sizeof(uvpath), "%s/.uidvalidity", gctx->path );
#ifndef USE_DB #ifndef USE_DB
if ((ctx->uvfd = open( uvpath, O_RDWR|O_CREAT, 0600 )) < 0) { if ((ctx->uvfd = open( uvpath, O_RDWR|O_CREAT, 0600 )) < 0) {
perror( uvpath ); perror( uvpath );
return cb( DRV_BOX_BAD, aux ); cb( DRV_BOX_BAD, aux );
return;
} }
#else #else
if ((ctx->uvfd = open( uvpath, O_RDWR, 0600 )) < 0) { 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; goto fnok;
} }
perror( uvpath ); perror( uvpath );
return cb( DRV_BOX_BAD, aux ); cb( DRV_BOX_BAD, aux );
return;
} }
dbok: dbok:
#if SEEK_SET != 0 #if SEEK_SET != 0
@ -823,7 +827,8 @@ maildir_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs,
bork: bork:
close( ctx->uvfd ); close( ctx->uvfd );
ctx->uvfd = -1; ctx->uvfd = -1;
return cb( DRV_BOX_BAD, aux ); cb( DRV_BOX_BAD, aux );
return;
} }
if (db_create( &ctx->db, 0, 0 )) { if (db_create( &ctx->db, 0, 0 )) {
fputs( "Maildir error: db_create() failed\n", stderr ); 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: fnok:
#endif /* USE_DB */ #endif /* USE_DB */
if (maildir_scan( ctx, &msglist ) != DRV_OK) if (maildir_scan( ctx, &msglist ) != DRV_OK) {
return cb( DRV_BOX_BAD, aux ); cb( DRV_BOX_BAD, aux );
return;
}
msgapp = &ctx->gen.msgs; msgapp = &ctx->gen.msgs;
for (i = 0; i < msglist.nents; i++) for (i = 0; i < msglist.nents; i++)
maildir_app_msg( ctx, &msgapp, msglist.ents + i ); maildir_app_msg( ctx, &msgapp, msglist.ents + i );
maildir_free_scan( &msglist ); maildir_free_scan( &msglist );
return cb( DRV_OK, aux ); cb( DRV_OK, aux );
} }
static int 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; 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, 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_store_t *ctx = (maildir_store_t *)gctx;
maildir_message_t *msg = (maildir_message_t *)gmsg; 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 ); nfsnprintf( buf, sizeof(buf), "%s/%s/%s", gctx->path, subdirs[gmsg->status & M_RECENT], msg->base );
if ((fd = open( buf, O_RDONLY )) >= 0) if ((fd = open( buf, O_RDONLY )) >= 0)
break; break;
if ((ret = maildir_again( ctx, msg, buf )) != DRV_OK) if ((ret = maildir_again( ctx, msg, buf )) != DRV_OK) {
return cb( ret, aux ); cb( ret, aux );
return;
}
} }
fstat( fd, &st ); fstat( fd, &st );
data->len = st.st_size; 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) { if (read( fd, data->data, data->len ) != data->len) {
perror( buf ); perror( buf );
close( fd ); close( fd );
return cb( DRV_MSG_BAD, aux ); cb( DRV_MSG_BAD, aux );
return;
} }
close( fd ); close( fd );
if (!(gmsg->status & M_FLAGS)) if (!(gmsg->status & M_FLAGS))
data->flags = maildir_parse_flags( msg->base ); data->flags = maildir_parse_flags( msg->base );
return cb( DRV_OK, aux ); cb( DRV_OK, aux );
} }
static int static int
@ -974,9 +984,9 @@ maildir_make_flags( int flags, char *buf )
return d; return d;
} }
static int static void
maildir_store_msg( store_t *gctx, msg_data_t *data, int to_trash, 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; maildir_store_t *ctx = (maildir_store_t *)gctx;
const char *prefix, *box; 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 (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 ); free( data->data );
return cb( ret, 0, aux ); cb( ret, 0, aux );
return;
} }
} else } else
#endif /* USE_DB */ #endif /* USE_DB */
{ {
if ((ret = maildir_uidval_lock( ctx )) != DRV_OK || if ((ret = maildir_uidval_lock( ctx )) != DRV_OK ||
(ret = maildir_obtain_uid( ctx, &uid )) != DRV_OK) (ret = maildir_obtain_uid( ctx, &uid )) != DRV_OK) {
return cb( ret, 0, aux ); cb( ret, 0, aux );
return;
}
maildir_uidval_unlock( ctx ); maildir_uidval_unlock( ctx );
nfsnprintf( base + bl, sizeof(base) - bl, ",U=%d", uid ); 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) { if (errno != ENOENT) {
perror( buf ); perror( buf );
free( data->data ); 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) { if ((ret = maildir_validate( gctx->conf->path, gctx->conf->trash, gctx->opts & OPEN_CREATE, ctx )) != DRV_OK) {
free( data->data ); 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) { if ((fd = open( buf, O_WRONLY|O_CREAT|O_EXCL, 0600 )) < 0) {
perror( buf ); perror( buf );
free( data->data ); free( data->data );
return cb( DRV_BOX_BAD, 0, aux ); cb( DRV_BOX_BAD, 0, aux );
return;
} }
} }
ret = write( fd, data->data, data->len ); 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 else
error( "Maildir error: %s: partial write\n", buf ); error( "Maildir error: %s: partial write\n", buf );
close( fd ); close( fd );
return cb( DRV_BOX_BAD, 0, aux ); cb( DRV_BOX_BAD, 0, aux );
return;
} }
if (close( fd ) < 0) { if (close( fd ) < 0) {
/* Quota exceeded may cause this. */ /* Quota exceeded may cause this. */
perror( buf ); 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. */ /* 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 ); nfsnprintf( nbuf, sizeof(nbuf), "%s%s/%s/%s%s", prefix, box, subdirs[!(data->flags & F_SEEN)], base, fbuf );
if (rename( buf, nbuf )) { if (rename( buf, nbuf )) {
perror( 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, 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; message_t *msg;
/* using a hash table might turn out to be more appropriate ... */ /* using a hash table might turn out to be more appropriate ... */
for (msg = gctx->msgs; msg; msg = msg->next) for (msg = gctx->msgs; msg; msg = msg->next)
if (!(msg->status & M_DEAD) && !memcmp( ((maildir_message_t *)msg)->tuid, tuid, TUIDL )) if (!(msg->status & M_DEAD) && !memcmp( ((maildir_message_t *)msg)->tuid, tuid, TUIDL )) {
return cb( DRV_OK, msg->uid, aux ); cb( DRV_OK, msg->uid, aux );
return cb( DRV_MSG_BAD, -1, 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, 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_store_t *ctx = (maildir_store_t *)gctx;
maildir_message_t *msg = (maildir_message_t *)gmsg; 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 )) if (!rename( buf, nbuf ))
break; break;
if ((ret = maildir_again( ctx, msg, buf )) != DRV_OK) if ((ret = maildir_again( ctx, msg, buf )) != DRV_OK) {
return cb( ret, aux ); cb( ret, aux );
return;
}
} }
free( msg->base ); free( msg->base );
msg->base = nfmalloc( tl + 1 ); 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; msg->gen.flags &= ~del;
gmsg->status &= ~M_RECENT; gmsg->status &= ~M_RECENT;
return cb( DRV_OK, aux ); cb( DRV_OK, aux );
} }
#ifdef USE_DB #ifdef USE_DB
@ -1136,9 +1159,9 @@ maildir_purge_msg( maildir_store_t *ctx, const char *name )
} }
#endif /* USE_DB */ #endif /* USE_DB */
static int static void
maildir_trash_msg( store_t *gctx, message_t *gmsg, 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_store_t *ctx = (maildir_store_t *)gctx;
maildir_message_t *msg = (maildir_message_t *)gmsg; 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 )) if (!rename( buf, nbuf ))
break; break;
if (!stat( buf, &st )) { if (!stat( buf, &st )) {
if ((ret = maildir_validate( gctx->conf->path, gctx->conf->trash, 1, ctx )) != DRV_OK) if ((ret = maildir_validate( gctx->conf->path, gctx->conf->trash, 1, ctx )) != DRV_OK) {
return cb( ret, aux ); cb( ret, aux );
return;
}
if (!rename( buf, nbuf )) if (!rename( buf, nbuf ))
break; break;
if (errno != ENOENT) { if (errno != ENOENT) {
perror( nbuf ); perror( nbuf );
return cb( DRV_BOX_BAD, aux ); cb( DRV_BOX_BAD, aux );
return;
} }
} }
if ((ret = maildir_again( ctx, msg, buf )) != DRV_OK) if ((ret = maildir_again( ctx, msg, buf )) != DRV_OK) {
return cb( ret, aux ); cb( ret, aux );
return;
}
} }
gmsg->status |= M_DEAD; gmsg->status |= M_DEAD;
gctx->count--; gctx->count--;
#ifdef USE_DB #ifdef USE_DB
if (ctx->db) if (ctx->db) {
return cb( maildir_purge_msg( ctx, msg->base ), aux ); cb( maildir_purge_msg( ctx, msg->base ), aux );
return;
}
#endif /* USE_DB */ #endif /* USE_DB */
return cb( DRV_OK, aux ); cb( DRV_OK, aux );
} }
static int static void
maildir_close( store_t *gctx, maildir_close( store_t *gctx,
int (*cb)( int sts, void *aux ), void *aux ) void (*cb)( int sts, void *aux ), void *aux )
{ {
#ifdef USE_DB #ifdef USE_DB
maildir_store_t *ctx = (maildir_store_t *)gctx; maildir_store_t *ctx = (maildir_store_t *)gctx;
@ -1203,15 +1233,21 @@ maildir_close( store_t *gctx,
msg->status |= M_DEAD; msg->status |= M_DEAD;
gctx->count--; gctx->count--;
#ifdef USE_DB #ifdef USE_DB
if (ctx->db && (ret = maildir_purge_msg( ctx, ((maildir_message_t *)msg)->base )) != DRV_OK) if (ctx->db && (ret = maildir_purge_msg( ctx, ((maildir_message_t *)msg)->base )) != DRV_OK) {
return cb( ret, aux ); cb( ret, aux );
return;
}
#endif /* USE_DB */ #endif /* USE_DB */
} }
} }
if (!retry) if (!retry) {
return cb( DRV_OK, aux ); cb( DRV_OK, aux );
if ((ret = maildir_rescan( (maildir_store_t *)gctx )) != DRV_OK) return;
return cb( ret, aux ); }
if ((ret = maildir_rescan( (maildir_store_t *)gctx )) != DRV_OK) {
cb( ret, aux );
return;
}
} }
} }

View File

@ -210,20 +210,20 @@ struct driver {
void (*cb)( int sts, void *aux ), void *aux ); void (*cb)( int sts, void *aux ), void *aux );
void (*prepare_paths)( store_t *ctx ); void (*prepare_paths)( store_t *ctx );
void (*prepare_opts)( store_t *ctx, int opts ); void (*prepare_opts)( store_t *ctx, int opts );
int (*select)( store_t *ctx, int minuid, int maxuid, int *excs, int nexcs, void (*select)( store_t *ctx, int minuid, int maxuid, int *excs, int nexcs,
int (*cb)( int sts, void *aux ), void *aux ); void (*cb)( int sts, void *aux ), void *aux );
int (*fetch_msg)( store_t *ctx, message_t *msg, msg_data_t *data, void (*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 );
int (*store_msg)( store_t *ctx, msg_data_t *data, int to_trash, void (*store_msg)( store_t *ctx, 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 );
int (*find_msg)( store_t *ctx, const char *tuid, void (*find_msg)( store_t *ctx, const char *tuid,
int (*cb)( int sts, int uid, void *aux ), void *aux ); void (*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 */ void (*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 ); void (*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 */ void (*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 ); void (*cb)( int sts, void *aux ), void *aux );
int (*close)( store_t *ctx, /* IMAP-style: expunge inclusive */ void (*close)( store_t *ctx, /* IMAP-style: expunge inclusive */
int (*cb)( int sts, void *aux ), void *aux ); void (*cb)( int sts, void *aux ), void *aux );
void (*cancel)( store_t *ctx, /* only not yet sent commands */ void (*cancel)( store_t *ctx, /* only not yet sent commands */
void (*cb)( void *aux ), void *aux ); void (*cb)( void *aux ), void *aux );
void (*commit)( store_t *ctx ); void (*commit)( store_t *ctx );

View File

@ -145,7 +145,7 @@ typedef struct {
channel_conf_t *chan; channel_conf_t *chan;
store_t *ctx[2]; store_t *ctx[2];
driver_t *drv[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 find_old_total[2], find_old_done[2];
int new_total[2], new_done[2]; int new_total[2], new_done[2];
int find_new_total[2], find_new_done[2]; int find_new_total[2], find_new_done[2];
@ -155,6 +155,26 @@ typedef struct {
unsigned find:1; unsigned find:1;
} sync_vars_t; } 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 AUX &svars->t[t]
#define DECL_SVARS \ #define DECL_SVARS \
int t; \ int t; \
@ -192,27 +212,28 @@ typedef struct {
typedef struct copy_vars { 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; void *aux;
sync_rec_t *srec; /* also ->tuid */ sync_rec_t *srec; /* also ->tuid */
message_t *msg; message_t *msg;
msg_data_t data; msg_data_t data;
} copy_vars_t; } copy_vars_t;
static int msg_fetched( int sts, void *aux ); static void msg_fetched( int sts, void *aux );
static int static int
copy_msg( copy_vars_t *vars ) copy_msg( copy_vars_t *vars )
{ {
DECL_INIT_SVARS(vars->aux); DECL_INIT_SVARS(vars->aux);
t ^= 1;
vars->data.flags = vars->msg->flags; 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 ) msg_fetched( int sts, void *aux )
{ {
copy_vars_t *vars = (copy_vars_t *)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", warn( "Warning: message %d from %s has incomplete header.\n",
vars->msg->uid, str_ms[1-t] ); vars->msg->uid, str_ms[1-t] );
free( fmap ); free( fmap );
return vars->cb( SYNC_NOGOOD, 0, vars ); vars->cb( SYNC_NOGOOD, 0, vars );
return;
oke: oke:
extra += 8 + TUIDL + 1 + (tcr && (!scr || hcrs)); extra += 8 + TUIDL + 1 + (tcr && (!scr || hcrs));
} }
@ -327,17 +349,21 @@ msg_fetched( int sts, void *aux )
free( fmap ); 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: case DRV_CANCELED:
return vars->cb( SYNC_CANCELED, 0, vars ); vars->cb( SYNC_CANCELED, 0, vars );
break;
case DRV_MSG_BAD: case DRV_MSG_BAD:
return vars->cb( SYNC_NOGOOD, 0, vars ); vars->cb( SYNC_NOGOOD, 0, vars );
break;
default: 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 ) msg_stored( int sts, int uid, void *aux )
{ {
copy_vars_t *vars = (copy_vars_t *)aux; copy_vars_t *vars = (copy_vars_t *)aux;
@ -345,17 +371,21 @@ msg_stored( int sts, int uid, void *aux )
switch (sts) { switch (sts) {
case DRV_OK: case DRV_OK:
return vars->cb( SYNC_OK, uid, vars ); vars->cb( SYNC_OK, uid, vars );
break;
case DRV_CANCELED: case DRV_CANCELED:
return vars->cb( SYNC_CANCELED, 0, vars ); vars->cb( SYNC_CANCELED, 0, vars );
break;
case DRV_MSG_BAD: case DRV_MSG_BAD:
INIT_SVARS(vars->aux); INIT_SVARS(vars->aux);
(void)svars; (void)svars;
warn( "Warning: %s refuses to store message %d from %s.\n", warn( "Warning: %s refuses to store message %d from %s.\n",
str_ms[t], vars->msg->uid, str_ms[1-t] ); 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: 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 ); 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 static int
check_ret( int sts, void *aux ) check_ret( int sts, void *aux )
@ -454,7 +497,7 @@ check_ret( int sts, void *aux )
#define SVARS_CHECK_RET \ #define SVARS_CHECK_RET \
DECL_SVARS; \ DECL_SVARS; \
if (check_ret( sts, aux )) \ if (check_ret( sts, aux )) \
return 1; \ return; \
INIT_SVARS(aux) INIT_SVARS(aux)
#define SVARS_CHECK_RET_VARS(type) \ #define SVARS_CHECK_RET_VARS(type) \
@ -462,7 +505,7 @@ check_ret( int sts, void *aux )
DECL_SVARS; \ DECL_SVARS; \
if (check_ret( sts, vars->aux )) { \ if (check_ret( sts, vars->aux )) { \
free( vars ); \ free( vars ); \
return 1; \ return; \
} \ } \
INIT_SVARS(vars->aux) INIT_SVARS(vars->aux)
@ -470,7 +513,7 @@ check_ret( int sts, void *aux )
DECL_SVARS; \ DECL_SVARS; \
if (sts == SYNC_CANCELED) { \ if (sts == SYNC_CANCELED) { \
free( vars ); \ free( vars ); \
return 1; \ return; \
} \ } \
INIT_SVARS(vars->aux) 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 = nfcalloc( sizeof(*svars) );
svars->t[1] = 1; svars->t[1] = 1;
svars->ref_count = 1;
svars->cb = cb; svars->cb = cb;
svars->aux = aux; svars->aux = aux;
svars->ctx[0] = ctx[0]; 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 ); 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 static int
select_box( sync_vars_t *svars, int t, int minwuid, int *mexcs, int nmexcs ) 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; maxwuid = 0;
info( "Selecting %s %s...\n", str_ms[t], svars->ctx[t]->name ); 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 ); 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 { typedef struct {
@ -859,10 +903,10 @@ typedef struct {
sync_rec_t *srec; sync_rec_t *srec;
} find_vars_t; } find_vars_t;
static int msg_found_sel( int sts, int uid, void *aux ); static void msg_found_sel( int sts, int uid, void *aux );
static int msgs_found_sel( sync_vars_t *svars, int t ); static void msgs_found_sel( sync_vars_t *svars, int t );
static int static void
box_selected( int sts, void *aux ) box_selected( int sts, void *aux )
{ {
find_vars_t *fv; find_vars_t *fv;
@ -874,7 +918,7 @@ box_selected( int sts, void *aux )
str_ms[t], svars->ctx[t]->uidvalidity, svars->uidval[t] ); str_ms[t], svars->ctx[t]->uidvalidity, svars->uidval[t] );
svars->ret |= SYNC_FAIL; svars->ret |= SYNC_FAIL;
cancel_sync( svars ); cancel_sync( svars );
return 1; return;
} }
info( "%s: %d messages, %d recent\n", str_ms[t], svars->ctx[t]->count, svars->ctx[t]->recent ); 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 = nfmalloc( sizeof(*fv) );
fv->aux = AUX; fv->aux = AUX;
fv->srec = srec; fv->srec = srec;
if (svars->drv[t]->find_msg( svars->ctx[t], srec->tuid, msg_found_sel, fv )) DRIVER_CALL(find_msg( svars->ctx[t], srec->tuid, msg_found_sel, fv ));
return 1;
} }
} }
} }
svars->state[t] |= ST_SENT_FIND_OLD; 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 ) msg_found_sel( int sts, int uid, void *aux )
{ {
SVARS_CHECK_RET_VARS(find_vars_t); SVARS_CHECK_RET_VARS(find_vars_t);
@ -927,7 +970,7 @@ msg_found_sel( int sts, int uid, void *aux )
free( vars ); free( vars );
svars->find_old_done[t]++; svars->find_old_done[t]++;
stats( svars ); stats( svars );
return msgs_found_sel( svars, t ); msgs_found_sel( svars, t );
} }
typedef struct { typedef struct {
@ -936,15 +979,15 @@ typedef struct {
int aflags, dflags; int aflags, dflags;
} flag_vars_t; } flag_vars_t;
static int flags_set_del( int sts, void *aux ); static void flags_set_del( int sts, void *aux );
static int flags_set_sync( 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 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 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 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 ) msgs_found_sel( sync_vars_t *svars, int t )
{ {
sync_rec_t *srec, *nsrec = 0; 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 */ 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]) 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. * 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++) for (t = 0; t < nmexcs; t++)
debugn( " %d", mexcs[t] ); debugn( " %d", mexcs[t] );
debug( "\n" ); 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]) 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) { if (svars->uidval[M] < 0 || svars->uidval[S] < 0) {
svars->uidval[M] = svars->ctx[M]->uidvalidity; 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 ); 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 ); debug( " -> %sing message, TUID %." stringify(TUIDL) "s\n", str_hl[t], srec->tuid );
if (copy_msg( cv )) if (copy_msg( cv ))
return 1; return;
} else { } else {
if (tmsg->srec) { if (tmsg->srec) {
debug( " -> not %sing - still too big\n", str_hl[t] ); 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; svars->state[t] |= ST_SENT_NEW;
if (msgs_copied( svars, t )) msgs_copied( svars, t );
return 1;
} }
debug( "synchronizing old entries\n" ); debug( "synchronizing old entries\n" );
@ -1164,8 +1207,7 @@ msgs_found_sel( sync_vars_t *svars, int t )
fv = nfmalloc( sizeof(*fv) ); fv = nfmalloc( sizeof(*fv) );
fv->aux = AUX; fv->aux = AUX;
fv->srec = srec; 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 )) DRIVER_CALL(set_flags( svars->ctx[t], srec->msg[t], srec->uid[t], F_DELETED, 0, flags_set_del, fv ));
return 1;
} else } else
debug( " not %sing delete\n", str_hl[t] ); debug( " not %sing delete\n", str_hl[t] );
} else if (!srec->msg[1-t]) } else if (!srec->msg[1-t])
@ -1275,8 +1317,7 @@ msgs_found_sel( sync_vars_t *svars, int t )
fv->srec = srec; fv->srec = srec;
fv->aflags = aflags; fv->aflags = aflags;
fv->dflags = dflags; fv->dflags = dflags;
if (svars->drv[t]->set_flags( svars->ctx[t], srec->msg[t], srec->uid[t], aflags, dflags, flags_set_sync, fv )) DRIVER_CALL(set_flags( svars->ctx[t], srec->msg[t], srec->uid[t], aflags, dflags, flags_set_sync, fv ));
return 1;
} else } else
flags_set_sync_p2( svars, srec, t ); 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->drv[t]->commit( svars->ctx[t] );
svars->state[t] |= ST_SENT_FLAGS; svars->state[t] |= ST_SENT_FLAGS;
if (msgs_flags_set( svars, t )) 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 ) msg_copied( int sts, int uid, copy_vars_t *vars )
{ {
SVARS_CHECK_CANCEL_RET; SVARS_CHECK_CANCEL_RET;
@ -1306,12 +1346,12 @@ msg_copied( int sts, int uid, copy_vars_t *vars )
default: default:
cancel_sync( svars ); cancel_sync( svars );
free( vars ); free( vars );
return 1; return;
} }
free( vars ); free( vars );
svars->new_done[t]++; svars->new_done[t]++;
stats( svars ); stats( svars );
return msgs_copied( svars, t ); msgs_copied( svars, t );
} }
static void 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 void msg_found_new( int sts, int uid, void *aux );
static int sync_close( sync_vars_t *svars, int t ); static void sync_close( sync_vars_t *svars, int t );
static int static void
msgs_copied( sync_vars_t *svars, int t ) msgs_copied( sync_vars_t *svars, int t )
{ {
sync_rec_t *srec; sync_rec_t *srec;
find_vars_t *fv; find_vars_t *fv;
if (!(svars->state[t] & ST_SENT_NEW) || svars->new_done[t] < svars->new_total[t]) 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] ); debug( "finding just copied messages on %s\n", str_ms[t] );
for (srec = svars->srecs; srec; srec = srec->next) { 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 = nfmalloc( sizeof(*fv) );
fv->aux = AUX; fv->aux = AUX;
fv->srec = srec; fv->srec = srec;
if (svars->drv[t]->find_msg( svars->ctx[t], srec->tuid, msg_found_new, fv )) DRIVER_CALL(find_msg( svars->ctx[t], srec->tuid, msg_found_new, fv ));
return 1;
} }
} }
svars->state[t] |= ST_SENT_FIND_NEW; 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 ) msg_found_new( int sts, int uid, void *aux )
{ {
SVARS_CHECK_RET_VARS(find_vars_t); SVARS_CHECK_RET_VARS(find_vars_t);
@ -1382,10 +1421,10 @@ msg_found_new( int sts, int uid, void *aux )
free( vars ); free( vars );
svars->find_new_done[t]++; svars->find_new_done[t]++;
stats( svars ); stats( svars );
return sync_close( svars, t ); sync_close( svars, t );
} }
static int static void
flags_set_del( int sts, void *aux ) flags_set_del( int sts, void *aux )
{ {
SVARS_CHECK_RET_VARS(flag_vars_t); SVARS_CHECK_RET_VARS(flag_vars_t);
@ -1399,10 +1438,10 @@ flags_set_del( int sts, void *aux )
free( vars ); free( vars );
svars->flags_done[t]++; svars->flags_done[t]++;
stats( svars ); stats( svars );
return msgs_flags_set( svars, t ); msgs_flags_set( svars, t );
} }
static int static void
flags_set_sync( int sts, void *aux ) flags_set_sync( int sts, void *aux )
{ {
SVARS_CHECK_RET_VARS(flag_vars_t); SVARS_CHECK_RET_VARS(flag_vars_t);
@ -1418,7 +1457,7 @@ flags_set_sync( int sts, void *aux )
free( vars ); free( vars );
svars->flags_done[t]++; svars->flags_done[t]++;
stats( svars ); stats( svars );
return msgs_flags_set( svars, t ); msgs_flags_set( svars, t );
} }
static void 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 void msg_trashed( int sts, void *aux );
static int msg_rtrashed( int sts, int uid, copy_vars_t *vars ); static void msg_rtrashed( int sts, int uid, copy_vars_t *vars );
static int static int
msgs_flags_set( sync_vars_t *svars, int t ) 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 ); debug( "%s: trashing message %d\n", str_ms[t], tmsg->uid );
svars->trash_total[t]++; svars->trash_total[t]++;
stats( svars ); stats( svars );
if (svars->drv[t]->trash_msg( svars->ctx[t], tmsg, msg_trashed, AUX )) sync_ref( svars );
return 1; svars->drv[t]->trash_msg( svars->ctx[t], tmsg, msg_trashed, AUX );
if (deref_check_cancel( svars ))
return -1;
} else } else
debug( "%s: not trashing message %d - not new\n", str_ms[t], tmsg->uid ); debug( "%s: not trashing message %d - not new\n", str_ms[t], tmsg->uid );
} else { } else {
@ -1486,7 +1527,7 @@ msgs_flags_set( sync_vars_t *svars, int t )
cv->srec = 0; cv->srec = 0;
cv->msg = tmsg; cv->msg = tmsg;
if (copy_msg( cv )) if (copy_msg( cv ))
return 1; return -1;
} else } else
debug( "%s: not remote trashing message %d - too big\n", str_ms[t], tmsg->uid ); debug( "%s: not remote trashing message %d - too big\n", str_ms[t], tmsg->uid );
} else } else
@ -1495,10 +1536,11 @@ msgs_flags_set( sync_vars_t *svars, int t )
} }
} }
svars->state[t] |= ST_SENT_TRASH; 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 ) msg_trashed( int sts, void *aux )
{ {
DECL_SVARS; DECL_SVARS;
@ -1506,14 +1548,14 @@ msg_trashed( int sts, void *aux )
if (sts == DRV_MSG_BAD) if (sts == DRV_MSG_BAD)
sts = DRV_BOX_BAD; sts = DRV_BOX_BAD;
if (check_ret( sts, aux )) if (check_ret( sts, aux ))
return 1; return;
INIT_SVARS(aux); INIT_SVARS(aux);
svars->trash_done[t]++; svars->trash_done[t]++;
stats( svars ); 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 ) msg_rtrashed( int sts, int uid, copy_vars_t *vars )
{ {
SVARS_CHECK_CANCEL_RET; SVARS_CHECK_CANCEL_RET;
@ -1525,40 +1567,39 @@ msg_rtrashed( int sts, int uid, copy_vars_t *vars )
default: default:
cancel_sync( svars ); cancel_sync( svars );
free( vars ); free( vars );
return 1; return;
} }
free( vars ); free( vars );
svars->trash_done[t]++; svars->trash_done[t]++;
stats( svars ); 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 void box_closed_p2( sync_vars_t *svars, int t );
static int static void
sync_close( sync_vars_t *svars, int t ) sync_close( sync_vars_t *svars, int t )
{ {
if ((~svars->state[t] & (ST_SENT_FIND_NEW|ST_SENT_TRASH)) || if ((~svars->state[t] & (ST_SENT_FIND_NEW|ST_SENT_TRASH)) ||
svars->find_new_done[t] < svars->find_new_total[t] || svars->find_new_done[t] < svars->find_new_total[t] ||
svars->trash_done[t] < svars->trash_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)*/) { if ((svars->chan->ops[t] & OP_EXPUNGE) /*&& !(svars->state[t] & ST_TRASH_BAD)*/) {
debug( "expunging %s\n", str_ms[t] ); 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 ) box_closed( int sts, void *aux )
{ {
SVARS_CHECK_RET; SVARS_CHECK_RET;
svars->state[t] |= ST_DID_EXPUNGE; svars->state[t] |= ST_DID_EXPUNGE;
box_closed_p2( svars, t ); box_closed_p2( svars, t );
return 0;
} }
static void static void
@ -1655,16 +1696,23 @@ sync_bail1( sync_vars_t *svars )
static void static void
sync_bail2( sync_vars_t *svars ) 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->lname );
free( svars->nname ); free( svars->nname );
free( svars->jname ); free( svars->jname );
free( svars->dname ); free( svars->dname );
free( svars );
error( "" ); 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;
}