replace DRV_STORE_BAD with a separate bad_callback()

that way we don't have to piggy-back (possibly asynchronous) fatal
errors to particular commands.

internally, the drivers still use synchronous return values as well,
so they don't try to access the invalidated store after calling back.
This commit is contained in:
Oswald Buddenhagen 2012-07-15 12:55:04 +02:00
parent 6d86e5347e
commit b0bbd23512
5 changed files with 122 additions and 61 deletions

View File

@ -172,12 +172,13 @@ static const char *cap_list[] = {
#endif #endif
}; };
#define RESP_OK 0 #define RESP_OK 0
#define RESP_NO 1 #define RESP_NO 1
#define RESP_BAD 2 #define RESP_CANCEL 2
static int get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd ); static int get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd );
static void imap_invoke_bad_callback( imap_store_t *ctx );
static const char *Flags[] = { static const char *Flags[] = {
"Draft", "Draft",
@ -503,8 +504,8 @@ v_submit_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd,
char buf[1024]; char buf[1024];
while (ctx->literal_pending) while (ctx->literal_pending)
if (get_cmd_result( ctx, 0 ) == RESP_BAD) if (get_cmd_result( ctx, 0 ) == RESP_CANCEL)
goto bail; goto bail2;
if (!cmd) if (!cmd)
cmd = new_imap_cmd(); cmd = new_imap_cmd();
@ -549,6 +550,8 @@ v_submit_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd,
return cmd; return cmd;
bail: bail:
imap_invoke_bad_callback( ctx );
bail2:
free( cmd->param.data ); free( cmd->param.data );
free( cmd->cmd ); free( cmd->cmd );
free( cmd ); free( cmd );
@ -576,7 +579,7 @@ imap_exec( imap_store_t *ctx, struct imap_cmd *cmdp, const char *fmt, ... )
cmdp = v_submit_imap_cmd( ctx, cmdp, fmt, ap ); cmdp = v_submit_imap_cmd( ctx, cmdp, fmt, ap );
va_end( ap ); va_end( ap );
if (!cmdp) if (!cmdp)
return RESP_BAD; return RESP_CANCEL;
return get_cmd_result( ctx, cmdp ); return get_cmd_result( ctx, cmdp );
} }
@ -590,10 +593,10 @@ imap_exec_b( imap_store_t *ctx, struct imap_cmd *cmdp, const char *fmt, ... )
cmdp = v_submit_imap_cmd( ctx, cmdp, fmt, ap ); cmdp = v_submit_imap_cmd( ctx, cmdp, fmt, ap );
va_end( ap ); va_end( ap );
if (!cmdp) if (!cmdp)
return DRV_STORE_BAD; return DRV_CANCELED;
switch (get_cmd_result( ctx, cmdp )) { switch (get_cmd_result( ctx, cmdp )) {
case RESP_BAD: return DRV_STORE_BAD; case RESP_CANCEL: return DRV_CANCELED;
case RESP_NO: return DRV_BOX_BAD; case RESP_NO: return DRV_BOX_BAD;
default: return DRV_OK; default: return DRV_OK;
} }
@ -608,10 +611,10 @@ imap_exec_m( imap_store_t *ctx, struct imap_cmd *cmdp, const char *fmt, ... )
cmdp = v_submit_imap_cmd( ctx, cmdp, fmt, ap ); cmdp = v_submit_imap_cmd( ctx, cmdp, fmt, ap );
va_end( ap ); va_end( ap );
if (!cmdp) if (!cmdp)
return DRV_STORE_BAD; return DRV_CANCELED;
switch (get_cmd_result( ctx, cmdp )) { switch (get_cmd_result( ctx, cmdp )) {
case RESP_BAD: return DRV_STORE_BAD; case RESP_CANCEL: return DRV_CANCELED;
case RESP_NO: return DRV_MSG_BAD; case RESP_NO: return DRV_MSG_BAD;
default: return DRV_OK; default: return DRV_OK;
} }
@ -631,8 +634,8 @@ process_imap_replies( imap_store_t *ctx )
{ {
while (ctx->num_in_progress > max_in_progress || while (ctx->num_in_progress > max_in_progress ||
socket_pending( &ctx->buf.sock )) socket_pending( &ctx->buf.sock ))
if (get_cmd_result( ctx, 0 ) == RESP_BAD) if (get_cmd_result( ctx, 0 ) == RESP_CANCEL)
return RESP_BAD; return RESP_CANCEL;
return RESP_OK; return RESP_OK;
} }
@ -905,7 +908,7 @@ parse_response_code( imap_store_t *ctx, struct imap_cmd *cmd, char *s )
s++; s++;
if (!(p = strchr( s, ']' ))) { if (!(p = strchr( s, ']' ))) {
error( "IMAP error: malformed response code\n" ); error( "IMAP error: malformed response code\n" );
return RESP_BAD; return RESP_CANCEL;
} }
*p++ = 0; *p++ = 0;
arg = next_arg( &s ); arg = next_arg( &s );
@ -914,12 +917,12 @@ parse_response_code( imap_store_t *ctx, struct imap_cmd *cmd, char *s )
(ctx->gen.uidvalidity = strtoll( arg, &earg, 10 ), *earg)) (ctx->gen.uidvalidity = strtoll( arg, &earg, 10 ), *earg))
{ {
error( "IMAP error: malformed UIDVALIDITY status\n" ); error( "IMAP error: malformed UIDVALIDITY status\n" );
return RESP_BAD; return RESP_CANCEL;
} }
} else if (!strcmp( "UIDNEXT", arg )) { } else if (!strcmp( "UIDNEXT", arg )) {
if (!(arg = next_arg( &s )) || (ctx->uidnext = strtol( arg, &p, 10 ), *p)) { if (!(arg = next_arg( &s )) || (ctx->uidnext = strtol( arg, &p, 10 ), *p)) {
error( "IMAP error: malformed NEXTUID status\n" ); error( "IMAP error: malformed NEXTUID status\n" );
return RESP_BAD; return RESP_CANCEL;
} }
} else if (!strcmp( "CAPABILITY", arg )) { } else if (!strcmp( "CAPABILITY", arg )) {
parse_capability( ctx, s ); parse_capability( ctx, s );
@ -935,7 +938,7 @@ parse_response_code( imap_store_t *ctx, struct imap_cmd *cmd, char *s )
!(arg = next_arg( &s )) || !(*(int *)cmd->param.aux = atoi( arg ))) !(arg = next_arg( &s )) || !(*(int *)cmd->param.aux = atoi( arg )))
{ {
error( "IMAP error: malformed APPENDUID status\n" ); error( "IMAP error: malformed APPENDUID status\n" );
return RESP_BAD; return RESP_CANCEL;
} }
} }
return RESP_OK; return RESP_OK;
@ -1005,14 +1008,14 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd )
for (;;) { for (;;) {
if (buffer_gets( &ctx->buf, &cmd )) if (buffer_gets( &ctx->buf, &cmd ))
return RESP_BAD; break;
arg = next_arg( &cmd ); arg = next_arg( &cmd );
if (*arg == '*') { if (*arg == '*') {
arg = next_arg( &cmd ); arg = next_arg( &cmd );
if (!arg) { if (!arg) {
error( "IMAP error: unable to parse untagged response\n" ); error( "IMAP error: unable to parse untagged response\n" );
return RESP_BAD; break;
} }
if (!strcmp( "NAMESPACE", arg )) { if (!strcmp( "NAMESPACE", arg )) {
@ -1035,15 +1038,15 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd )
ctx->gen.recent = atoi( arg ); ctx->gen.recent = atoi( arg );
else if(!strcmp ( "FETCH", arg1 )) { else if(!strcmp ( "FETCH", arg1 )) {
if (parse_fetch( ctx, cmd )) if (parse_fetch( ctx, cmd ))
return RESP_BAD; break; /* stream is likely to be useless now */
} }
} else { } else {
error( "IMAP error: unable to parse untagged response\n" ); error( "IMAP error: unrecognized untagged response '%s'\n", arg );
return RESP_BAD; break; /* this may mean anything, so prefer not to spam the log */
} }
} else if (!ctx->in_progress) { } else if (!ctx->in_progress) {
error( "IMAP error: unexpected reply: %s %s\n", arg, cmd ? cmd : "" ); error( "IMAP error: unexpected reply: %s %s\n", arg, cmd ? cmd : "" );
return RESP_BAD; break; /* this may mean anything, so prefer not to spam the log */
} else if (*arg == '+') { } else if (*arg == '+') {
/* This can happen only with the last command underway, as /* This can happen only with the last command underway, as
it enforces a round-trip. */ it enforces a round-trip. */
@ -1055,16 +1058,16 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd )
free( cmdp->param.data ); free( cmdp->param.data );
cmdp->param.data = 0; cmdp->param.data = 0;
if (n != (int)cmdp->param.data_len) if (n != (int)cmdp->param.data_len)
return RESP_BAD; break;
} else if (cmdp->param.cont) { } else if (cmdp->param.cont) {
if (cmdp->param.cont( ctx, cmdp, cmd )) if (cmdp->param.cont( ctx, cmdp, cmd ))
return RESP_BAD; break;
} else { } else {
error( "IMAP error: unexpected command continuation request\n" ); error( "IMAP error: unexpected command continuation request\n" );
return RESP_BAD; break;
} }
if (socket_write( &ctx->buf.sock, "\r\n", 2 ) != 2) if (socket_write( &ctx->buf.sock, "\r\n", 2 ) != 2)
return RESP_BAD; break;
if (!cmdp->param.cont) if (!cmdp->param.cont)
ctx->literal_pending = 0; ctx->literal_pending = 0;
if (!tcmd) if (!tcmd)
@ -1075,7 +1078,7 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd )
if (cmdp->tag == tag) if (cmdp->tag == tag)
goto gottag; goto gottag;
error( "IMAP error: unexpected tag %s\n", arg ); error( "IMAP error: unexpected tag %s\n", arg );
return RESP_BAD; break;
gottag: gottag:
if (!(*pcmdp = cmdp->next)) if (!(*pcmdp = cmdp->next))
ctx->in_progress_append = pcmdp; ctx->in_progress_append = pcmdp;
@ -1092,14 +1095,14 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd )
if (cmdp->param.create && cmd && (cmdp->param.trycreate || !memcmp( cmd, "[TRYCREATE]", 11 ))) { /* SELECT, APPEND or UID COPY */ if (cmdp->param.create && cmd && (cmdp->param.trycreate || !memcmp( cmd, "[TRYCREATE]", 11 ))) { /* SELECT, APPEND or UID COPY */
p = strchr( cmdp->cmd, '"' ); p = strchr( cmdp->cmd, '"' );
if (!submit_imap_cmd( ctx, 0, "CREATE %.*s", strchr( p + 1, '"' ) - p + 1, p )) { if (!submit_imap_cmd( ctx, 0, "CREATE %.*s", strchr( p + 1, '"' ) - p + 1, p )) {
resp = RESP_BAD; resp = RESP_CANCEL;
goto normal; goto normal;
} }
/* not waiting here violates the spec, but a server that does not /* not waiting here violates the spec, but a server that does not
grok this nonetheless violates it too. */ grok this nonetheless violates it too. */
cmdp->param.create = 0; cmdp->param.create = 0;
if (!submit_imap_cmd( ctx, cmdp, 0 )) { if (!submit_imap_cmd( ctx, cmdp, 0 )) {
resp = RESP_BAD; resp = RESP_CANCEL;
goto abnormal; goto abnormal;
} }
if (!tcmd) if (!tcmd)
@ -1108,13 +1111,15 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd )
} }
resp = RESP_NO; resp = RESP_NO;
} else /*if (!strcmp( "BAD", arg ))*/ } else /*if (!strcmp( "BAD", arg ))*/
resp = RESP_BAD; resp = RESP_CANCEL;
error( "IMAP command '%s' returned an error: %s %s\n", error( "IMAP command '%s' returned an error: %s %s\n",
memcmp( cmdp->cmd, "LOGIN", 5 ) ? cmdp->cmd : "LOGIN <user> <pass>", memcmp( cmdp->cmd, "LOGIN", 5 ) ? cmdp->cmd : "LOGIN <user> <pass>",
arg, cmd ? cmd : "" ); arg, cmd ? cmd : "" );
} }
if ((resp2 = parse_response_code( ctx, cmdp, cmd )) > resp) if ((resp2 = parse_response_code( ctx, cmdp, cmd )) > resp)
resp = resp2; resp = resp2;
if (resp == RESP_CANCEL)
imap_invoke_bad_callback( ctx );
normal: normal:
if (cmdp->param.done) if (cmdp->param.done)
cmdp->param.done( ctx, cmdp, resp ); cmdp->param.done( ctx, cmdp, resp );
@ -1126,7 +1131,8 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd )
return resp; return resp;
} }
} }
/* not reached */ imap_invoke_bad_callback( ctx );
return RESP_CANCEL;
} }
static void static void
@ -1150,13 +1156,34 @@ imap_cancel_store( store_t *gctx )
free( ctx ); free( ctx );
} }
static void
imap_invoke_bad_callback( imap_store_t *ctx )
{
if (ctx->gen.bad_callback)
ctx->gen.bad_callback( ctx->gen.bad_callback_aux );
}
static store_t *unowned; static store_t *unowned;
static void
imap_cancel_unowned( void *gctx )
{
store_t *store, **storep;
for (storep = &unowned; (store = *storep); storep = &store->next)
if (store == gctx) {
*storep = store->next;
break;
}
imap_cancel_store( gctx );
}
static void static void
imap_disown_store( store_t *gctx ) imap_disown_store( store_t *gctx )
{ {
free_generic_messages( gctx->msgs ); free_generic_messages( gctx->msgs );
gctx->msgs = 0; gctx->msgs = 0;
set_bad_callback( gctx, imap_cancel_unowned, gctx );
gctx->next = unowned; gctx->next = unowned;
unowned = gctx; unowned = gctx;
} }
@ -1181,7 +1208,9 @@ imap_cleanup( void )
for (ctx = unowned; ctx; ctx = nctx) { for (ctx = unowned; ctx; ctx = nctx) {
nctx = ctx->next; nctx = ctx->next;
imap_exec( (imap_store_t *)ctx, 0, "LOGOUT" ); set_bad_callback( ctx, (void (*)(void *))imap_cancel_store, ctx );
if (imap_exec( (imap_store_t *)ctx, 0, "LOGOUT" ) == RESP_CANCEL)
continue;
imap_cancel_store( ctx ); imap_cancel_store( ctx );
} }
} }
@ -1310,6 +1339,7 @@ imap_open_store( store_conf_t *conf,
ctx->gen.boxes = 0; ctx->gen.boxes = 0;
ctx->gen.listed = 0; ctx->gen.listed = 0;
ctx->gen.conf = conf; ctx->gen.conf = conf;
set_bad_callback( &ctx->gen, 0, 0 );
goto final; goto final;
} }
@ -1618,8 +1648,8 @@ imap_flags_helper( imap_store_t *ctx, int uid, char what, int flags)
buf[imap_make_flags( flags, buf )] = 0; buf[imap_make_flags( flags, buf )] = 0;
if (!submit_imap_cmd( ctx, 0, "UID STORE %d %cFLAGS.SILENT %s", uid, what, buf )) if (!submit_imap_cmd( ctx, 0, "UID STORE %d %cFLAGS.SILENT %s", uid, what, buf ))
return DRV_STORE_BAD; return DRV_CANCELED;
return process_imap_replies( ctx ) == RESP_BAD ? DRV_STORE_BAD : DRV_OK; return process_imap_replies( ctx ) == RESP_CANCEL ? DRV_CANCELED : DRV_OK;
} }
static int static int

View File

@ -159,6 +159,12 @@ maildir_cleanup_drv( void )
{ {
} }
static void
maildir_invoke_bad_callback( store_t *ctx )
{
ctx->bad_callback( ctx->bad_callback_aux );
}
static void static void
maildir_list( store_t *gctx, maildir_list( store_t *gctx,
void (*cb)( int sts, void *aux ), void *aux ) void (*cb)( int sts, void *aux ), void *aux )
@ -168,7 +174,8 @@ maildir_list( store_t *gctx,
if (!(dir = opendir( gctx->conf->path ))) { if (!(dir = opendir( gctx->conf->path ))) {
error( "%s: %s\n", gctx->conf->path, strerror(errno) ); error( "%s: %s\n", gctx->conf->path, strerror(errno) );
cb( DRV_STORE_BAD, aux ); maildir_invoke_bad_callback( gctx );
cb( DRV_CANCELED, aux );
return; return;
} }
while ((de = readdir( dir ))) { while ((de = readdir( dir ))) {
@ -219,7 +226,7 @@ maildir_free_scan( msglist_t *msglist )
#define _24_HOURS (3600 * 24) #define _24_HOURS (3600 * 24)
static int static int
maildir_validate( const char *prefix, const char *box, int create ) maildir_validate( const char *prefix, const char *box, int create, maildir_store_t *ctx )
{ {
DIR *dirp; DIR *dirp;
struct dirent *entry; struct dirent *entry;
@ -235,7 +242,8 @@ maildir_validate( const char *prefix, const char *box, int create )
if (mkdir( buf, 0700 )) { if (mkdir( buf, 0700 )) {
error( "Maildir error: mkdir %s: %s (errno %d)\n", error( "Maildir error: mkdir %s: %s (errno %d)\n",
buf, strerror(errno), errno ); buf, strerror(errno), errno );
return DRV_STORE_BAD; maildir_invoke_bad_callback( &ctx->gen );
return DRV_CANCELED;
} }
mkdirs: mkdirs:
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
@ -781,8 +789,8 @@ 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 (maildir_validate( gctx->path, "", ctx->gen.opts & OPEN_CREATE ) != DRV_OK) if ((ret = maildir_validate( gctx->path, "", ctx->gen.opts & OPEN_CREATE, ctx )) != DRV_OK)
return cb( DRV_BOX_BAD, aux ); return cb( ret, aux );
nfsnprintf( uvpath, sizeof(uvpath), "%s/.uidvalidity", gctx->path ); nfsnprintf( uvpath, sizeof(uvpath), "%s/.uidvalidity", gctx->path );
#ifndef USE_DB #ifndef USE_DB
@ -1007,7 +1015,7 @@ maildir_store_msg( store_t *gctx, msg_data_t *data, int to_trash,
free( data->data ); free( data->data );
return cb( DRV_BOX_BAD, 0, aux ); return cb( DRV_BOX_BAD, 0, aux );
} }
if ((ret = maildir_validate( gctx->conf->path, gctx->conf->trash, gctx->opts & OPEN_CREATE )) != 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 ); return cb( ret, 0, aux );
} }
@ -1147,7 +1155,7 @@ 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 )) != DRV_OK) if ((ret = maildir_validate( gctx->conf->path, gctx->conf->trash, 1, ctx )) != DRV_OK)
return cb( ret, aux ); return cb( ret, aux );
if (!rename( buf, nbuf )) if (!rename( buf, nbuf ))
break; break;

View File

@ -44,6 +44,12 @@
# define ATTR_PRINTFLIKE(fmt,var) # define ATTR_PRINTFLIKE(fmt,var)
#endif #endif
#ifdef __GNUC__
# define INLINE __inline__
#else
# define INLINE
#endif
#define EXE "mbsync" #define EXE "mbsync"
typedef struct { typedef struct {
@ -148,6 +154,9 @@ typedef struct store {
string_list_t *boxes; /* _list results - own */ string_list_t *boxes; /* _list results - own */
unsigned listed:1; /* was _list already run? */ unsigned listed:1; /* was _list already run? */
void (*bad_callback)( void *aux );
void *bad_callback_aux;
/* currently open mailbox */ /* currently open mailbox */
const char *name; /* foreign! maybe preset? */ const char *name; /* foreign! maybe preset? */
char *path; /* own */ char *path; /* own */
@ -159,6 +168,13 @@ typedef struct store {
int recent; /* # of recent messages - don't trust this beyond the initial read */ int recent; /* # of recent messages - don't trust this beyond the initial read */
} store_t; } store_t;
static INLINE void
set_bad_callback( store_t *ctx, void (*cb)( void *aux ), void *aux )
{
ctx->bad_callback = cb;
ctx->bad_callback_aux = aux;
}
typedef struct { typedef struct {
char *data; char *data;
int len; int len;
@ -168,8 +184,7 @@ typedef struct {
#define DRV_OK 0 #define DRV_OK 0
#define DRV_MSG_BAD 1 #define DRV_MSG_BAD 1
#define DRV_BOX_BAD 2 #define DRV_BOX_BAD 2
#define DRV_STORE_BAD 3 #define DRV_CANCELED 3
#define DRV_CANCELED 4
/* All memory belongs to the driver's user. */ /* All memory belongs to the driver's user. */

View File

@ -672,6 +672,17 @@ sync_chans( main_vars_t *mvars, int ent )
drivers[t]->cleanup(); drivers[t]->cleanup();
} }
static void
store_bad( void *aux )
{
MVARS(aux)
mvars->drv[t]->cancel_store( mvars->ctx[t] );
mvars->ret = mvars->skip = 1;
mvars->state[t] = ST_CLOSED;
sync_chans( mvars, E_OPEN );
}
static void static void
store_opened( store_t *ctx, void *aux ) store_opened( store_t *ctx, void *aux )
{ {
@ -685,6 +696,7 @@ store_opened( store_t *ctx, void *aux )
} }
mvars->ctx[t] = ctx; mvars->ctx[t] = ctx;
if (!mvars->skip && !mvars->boxlist && mvars->chan->patterns && !ctx->listed) { if (!mvars->skip && !mvars->boxlist && mvars->chan->patterns && !ctx->listed) {
set_bad_callback( ctx, store_bad, AUX );
mvars->drv[t]->list( ctx, store_listed, AUX ); mvars->drv[t]->list( ctx, store_listed, AUX );
} else { } else {
mvars->state[t] = ST_OPEN; mvars->state[t] = ST_OPEN;
@ -697,20 +709,19 @@ store_listed( int sts, void *aux )
{ {
MVARS(aux) MVARS(aux)
mvars->state[t] = ST_OPEN;
switch (sts) { switch (sts) {
case DRV_CANCELED:
return;
case DRV_OK: case DRV_OK:
mvars->ctx[t]->listed = 1; mvars->ctx[t]->listed = 1;
if (mvars->ctx[t]->conf->map_inbox) if (mvars->ctx[t]->conf->map_inbox)
add_string_list( &mvars->ctx[t]->boxes, mvars->ctx[t]->conf->map_inbox ); add_string_list( &mvars->ctx[t]->boxes, mvars->ctx[t]->conf->map_inbox );
break; break;
case DRV_STORE_BAD:
mvars->drv[t]->cancel_store( mvars->ctx[t] );
mvars->state[t] = ST_CLOSED;
default: default:
mvars->ret = mvars->skip = 1; mvars->ret = mvars->skip = 1;
break; break;
} }
mvars->state[t] = ST_OPEN;
sync_chans( mvars, E_OPEN ); sync_chans( mvars, E_OPEN );
} }

View File

@ -331,10 +331,6 @@ msg_fetched( int sts, void *aux )
return vars->cb( SYNC_CANCELED, 0, vars ); return vars->cb( SYNC_CANCELED, 0, vars );
case DRV_MSG_BAD: case DRV_MSG_BAD:
return vars->cb( SYNC_NOGOOD, 0, vars ); return vars->cb( SYNC_NOGOOD, 0, vars );
case DRV_STORE_BAD:
INIT_SVARS(vars->aux);
(void)svars;
return vars->cb( SYNC_BAD(1-t), 0, vars );
default: default:
return vars->cb( SYNC_FAIL, 0, vars ); return vars->cb( SYNC_FAIL, 0, vars );
} }
@ -357,10 +353,6 @@ msg_stored( int sts, int uid, void *aux )
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 ); return vars->cb( SYNC_NOGOOD, 0, vars );
case DRV_STORE_BAD:
INIT_SVARS(vars->aux);
(void)svars;
return vars->cb( SYNC_BAD(t), 0, vars );
default: default:
return vars->cb( SYNC_FAIL, 0, vars ); return vars->cb( SYNC_FAIL, 0, vars );
} }
@ -406,7 +398,6 @@ cancel_sync( sync_vars_t *svars )
for (t = 0; t < 2; t++) { for (t = 0; t < 2; t++) {
int other_state = svars->state[1-t]; int other_state = svars->state[1-t];
if (svars->ret & SYNC_BAD(t)) { if (svars->ret & SYNC_BAD(t)) {
svars->drv[t]->cancel_store( svars->ctx[t] );
cancel_done( AUX ); cancel_done( AUX );
} else { } else {
svars->drv[t]->cancel( svars->ctx[t], cancel_done, AUX ); svars->drv[t]->cancel( svars->ctx[t], cancel_done, AUX );
@ -429,6 +420,16 @@ cancel_done( void *aux )
} }
} }
static void
store_bad( void *aux )
{
DECL_INIT_SVARS(aux);
svars->drv[t]->cancel_store( svars->ctx[t] );
svars->ret |= SYNC_BAD(t);
cancel_sync( svars );
}
static int static int
check_ret( int sts, void *aux ) check_ret( int sts, void *aux )
@ -438,11 +439,6 @@ check_ret( int sts, void *aux )
switch (sts) { switch (sts) {
case DRV_CANCELED: case DRV_CANCELED:
return 1; return 1;
case DRV_STORE_BAD:
INIT_SVARS(aux);
svars->ret |= SYNC_BAD(t);
cancel_sync( svars );
return 1;
case DRV_BOX_BAD: case DRV_BOX_BAD:
INIT_SVARS(aux); INIT_SVARS(aux);
svars->ret |= SYNC_FAIL; svars->ret |= SYNC_FAIL;
@ -522,6 +518,7 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan,
(!names[t] || (ctx[t]->conf->map_inbox && !strcmp( ctx[t]->conf->map_inbox, names[t] ))) ? (!names[t] || (ctx[t]->conf->map_inbox && !strcmp( ctx[t]->conf->map_inbox, names[t] ))) ?
"INBOX" : names[t]; "INBOX" : names[t];
ctx[t]->uidvalidity = -1; ctx[t]->uidvalidity = -1;
set_bad_callback( ctx[t], store_bad, AUX );
svars->drv[t] = ctx[t]->conf->driver; svars->drv[t] = ctx[t]->conf->driver;
svars->drv[t]->prepare_paths( ctx[t] ); svars->drv[t]->prepare_paths( ctx[t] );
} }