commit eaa44a9a7e37547ca6eb8ac9b5f133612eb9b3c7 Author: Oswald Buddenhagen <o...@kde.org> Date: Sun Mar 13 15:53:23 2011 +0100
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. src/drv_imap.c | 71 ++++++++++++++------------------------------- src/drv_maildir.c | 16 ++++++---- src/isync.h | 19 +++++++++++- src/main.c | 21 +++++++++---- src/sync.c | 48 ++++++++++++++---------------- 5 files changed, 86 insertions(+), 89 deletions(-) diff --git a/src/drv_imap.c b/src/drv_imap.c index 9602260..5f9450d 100644 --- a/src/drv_imap.c +++ b/src/drv_imap.c @@ -214,8 +214,7 @@ static const char *cap_list[] = { #define RESP_OK 0 #define RESP_NO 1 -#define RESP_BAD 2 -#define RESP_CANCEL 3 +#define RESP_CANCEL 2 static void get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd ); @@ -561,6 +560,7 @@ v_submit_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd, char buf[1024]; assert( ctx ); + assert( ctx->gen.bad_callback ); assert( cmd ); assert( cmd->param.done ); @@ -568,11 +568,8 @@ v_submit_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd, while (ctx->literal_pending) { get_cmd_result( ctx, 0 ); - if (ctx->store_canceled) { - /* ctx (and thus the queue) is invalid by now. */ - cmd->param.done( 0, cmd, RESP_CANCEL ); + if (ctx->store_canceled) goto bail2; - } } if (ctx->buf.sock.fd < 0) @@ -622,8 +619,9 @@ v_submit_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd, return cmd; bail: - cmd->param.done( ctx, cmd, RESP_BAD ); + ctx->gen.bad_callback( ctx->gen.bad_callback_aux ); bail2: + cmd->param.done( ctx, cmd, RESP_CANCEL ); free( cmd->cmd ); free( cmd ); deref_store( ctx ); @@ -666,7 +664,6 @@ transform_box_response( int *response ) { switch (*response) { case RESP_CANCEL: *response = DRV_CANCELED; break; - case RESP_BAD: *response = DRV_STORE_BAD; break; case RESP_NO: *response = DRV_BOX_BAD; break; default: *response = DRV_OK; break; } @@ -687,7 +684,6 @@ transform_msg_response( int *response ) { switch (*response) { case RESP_CANCEL: *response = DRV_CANCELED; break; - case RESP_BAD: *response = DRV_STORE_BAD; break; case RESP_NO: *response = DRV_MSG_BAD; break; default: *response = DRV_OK; break; } @@ -1000,7 +996,7 @@ parse_response_code( imap_store_t *ctx, struct imap_cmd *cmd, char *s ) s++; if (!(p = strchr( s, ']' ))) { error( "IMAP error: malformed response code\n" ); - return RESP_BAD; + return RESP_CANCEL; } *p++ = 0; arg = next_arg( &s ); @@ -1009,12 +1005,12 @@ parse_response_code( imap_store_t *ctx, struct imap_cmd *cmd, char *s ) (ctx->gen.uidvalidity = strtoll( arg, &earg, 10 ), *earg)) { error( "IMAP error: malformed UIDVALIDITY status\n" ); - return RESP_BAD; + return RESP_CANCEL; } } else if (!strcmp( "UIDNEXT", arg )) { if (!(arg = next_arg( &s )) || (ctx->uidnext = strtol( arg, &p, 10 ), *p)) { error( "IMAP error: malformed NEXTUID status\n" ); - return RESP_BAD; + return RESP_CANCEL; } } else if (!strcmp( "CAPABILITY", arg )) { parse_capability( ctx, s ); @@ -1031,7 +1027,7 @@ parse_response_code( imap_store_t *ctx, struct imap_cmd *cmd, char *s ) !(((struct imap_cmd_out_uid *)cmd)->out_uid = atoi( arg ))) { error( "IMAP error: malformed APPENDUID status\n" ); - return RESP_BAD; + return RESP_CANCEL; } } return RESP_OK; @@ -1210,13 +1206,15 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd ) } resp = RESP_NO; } else /*if (!strcmp( "BAD", arg ))*/ - resp = RESP_BAD; + resp = RESP_CANCEL; error( "IMAP command '%s' returned an error: %s %s\n", memcmp( cmdp->cmd, "LOGIN", 5 ) ? cmdp->cmd : "LOGIN <user> <pass>", arg, cmd ? cmd : "" ); } if ((resp2 = parse_response_code( ctx, cmdp, cmd )) > resp) resp = resp2; + if (resp == RESP_CANCEL) + ctx->gen.bad_callback( ctx->gen.bad_callback_aux ); cmdp->param.done( ctx, cmdp, resp ); free( cmdp->param.data ); free( cmdp->cmd ); @@ -1228,22 +1226,7 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd ) return; } } - /* Piggy-back the stream error on the next pending command. */ - if ((cmdp = ctx->in_progress)) { - ctx->in_progress = cmdp->next; /* We're dead, so don't update in_progress_append */ - ctx->num_in_progress--; - cmdp->param.done( ctx, cmdp, RESP_BAD ); - free( cmdp->param.data ); - free( cmdp->cmd ); - free( cmdp ); - deref_store( ctx ); - return; - } - /* Made no callback, so let the next command submission fail. */ - if (ctx->buf.sock.fd != -1) { - close( ctx->buf.sock.fd ); - ctx->buf.sock.fd = -1; - } + ctx->gen.bad_callback( ctx->gen.bad_callback_aux ); } static void @@ -1324,6 +1307,7 @@ imap_cleanup( void ) for (ctx = unowned; ctx; ctx = nctx) { nctx = ctx->next; + set_bad_callback( ctx, (void (*)(void *))imap_cancel_store, ctx ); imap_exec( (imap_store_t *)ctx, 0, imap_cleanup_p2, "LOGOUT" ); } } @@ -1480,6 +1464,7 @@ imap_open_store( store_conf_t *conf, ctx->gen.conf = conf; ctx->callbacks.imap_open = cb; ctx->callback_aux = aux; + set_bad_callback( &ctx->gen, (void (*)(void *))imap_open_store_bail, ctx ); imap_open_store_namespace( ctx ); return; } @@ -1490,6 +1475,7 @@ imap_open_store( store_conf_t *conf, ctx->buf.sock.fd = -1; ctx->callbacks.imap_open = cb; ctx->callback_aux = aux; + set_bad_callback( &ctx->gen, (void (*)(void *))imap_open_store_bail, ctx ); ctx->in_progress_append = &ctx->in_progress; /* open connection to IMAP server */ @@ -1759,6 +1745,7 @@ imap_open_store_namespace2( imap_store_t *ctx ) static void imap_open_store_finalize( imap_store_t *ctx ) { + set_bad_callback( &ctx->gen, 0, 0 ); ctx->trashnc = 1; ctx->callbacks.imap_open( &ctx->gen, ctx->callback_aux ); } @@ -1914,16 +1901,11 @@ imap_select2_p2( imap_store_t *ctx ATTR_UNUSED, struct imap_cmd *cmd, int respon switch (response) { case RESP_CANCEL: - /* sts was already free()d by the BAD callback. We can do that, because we know - * that our fetches are the only commands in flight, so nothing else can cause a - * cancelation. */ - return; - case RESP_BAD: - sts->ret_val = DRV_STORE_BAD; - imap_refcounted_done( sts ); - return; + sts->ret_val = DRV_CANCELED; + break; case RESP_NO: - sts->ret_val = DRV_BOX_BAD; + if (sts->ret_val == DRV_OK) /* Don't override cancelation. */ + sts->ret_val = DRV_BOX_BAD; break; } if (!--sts->ref_count) @@ -2024,17 +2006,8 @@ imap_set_flags_p2( imap_store_t *ctx ATTR_UNUSED, struct imap_cmd *cmd, int resp struct imap_cmd_refcounted_state *sts = ((struct imap_cmd_refcounted *)cmd)->state; switch (response) { case RESP_CANCEL: - if (sts->ret_val == DRV_STORE_BAD) - goto badout; /* Our own command's bad-store callback caused cancelation. */ - sts->ret_val = DRV_CANCELED; /* Unrelated command caused cancelation. */ + sts->ret_val = DRV_CANCELED; break; - case RESP_BAD: - sts->ret_val = DRV_STORE_BAD; - sts->callback( sts->ret_val, sts->callback_aux ); - badout: - if (!--sts->ref_count) - free( sts ); - return; case RESP_NO: if (sts->ret_val == DRV_OK) /* Don't override cancelation. */ sts->ret_val = DRV_MSG_BAD; diff --git a/src/drv_maildir.c b/src/drv_maildir.c index d157be7..301c6a4 100644 --- a/src/drv_maildir.c +++ b/src/drv_maildir.c @@ -168,7 +168,8 @@ maildir_list( store_t *gctx, if (!(dir = opendir( gctx->conf->path ))) { error( "%s: %s\n", gctx->conf->path, strerror(errno) ); - cb( DRV_STORE_BAD, aux ); + gctx->bad_callback( gctx->bad_callback_aux ); + cb( DRV_CANCELED, aux ); return; } while ((de = readdir( dir ))) { @@ -220,7 +221,7 @@ maildir_free_scan( msglist_t *msglist ) #define _24_HOURS (3600 * 24) 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; struct dirent *entry; @@ -236,7 +237,8 @@ maildir_validate( const char *prefix, const char *box, int create ) if (mkdir( buf, 0700 )) { error( "Maildir error: mkdir %s: %s (errno %d)\n", buf, strerror(errno), errno ); - return DRV_STORE_BAD; + ctx->gen.bad_callback( ctx->gen.bad_callback_aux ); + return DRV_CANCELED; } mkdirs: for (i = 0; i < 3; i++) { @@ -782,8 +784,8 @@ maildir_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs, ctx->excs = nfrealloc( excs, nexcs * sizeof(int) ); ctx->nexcs = nexcs; - if (maildir_validate( gctx->path, "", ctx->gen.opts & OPEN_CREATE ) != DRV_OK) { - cb( DRV_BOX_BAD, aux ); + if ((ret = maildir_validate( gctx->path, "", ctx->gen.opts & OPEN_CREATE, ctx )) != DRV_OK) { + cb( ret, aux ); return; } @@ -1022,7 +1024,7 @@ maildir_store_msg( store_t *gctx, msg_data_t *data, int to_trash, cb( DRV_BOX_BAD, 0, aux ); return; } - 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 ); cb( ret, 0, aux ); return; @@ -1166,7 +1168,7 @@ maildir_trash_msg( store_t *gctx, message_t *gmsg, if (!rename( buf, nbuf )) break; if (!stat( buf, &st )) { - if ((ret = maildir_validate( gctx->conf->path, gctx->conf->trash, 1 )) != DRV_OK) { + if ((ret = maildir_validate( gctx->conf->path, gctx->conf->trash, 1, ctx )) != DRV_OK) { cb( ret, aux ); return; } diff --git a/src/isync.h b/src/isync.h index 8dc60d1..b34f08c 100644 --- a/src/isync.h +++ b/src/isync.h @@ -44,6 +44,12 @@ # define ATTR_PRINTFLIKE(fmt,var) #endif +#ifdef __GNUC__ +# define INLINE __inline__ +#else +# define INLINE +#endif + #define EXE "mbsync" typedef struct { @@ -148,6 +154,9 @@ typedef struct store { string_list_t *boxes; /* _list results - own */ unsigned listed:1; /* was _list already run? */ + void (*bad_callback)( void *aux ); + void *bad_callback_aux; + /* currently open mailbox */ const char *name; /* foreign! maybe preset? */ char *path; /* own */ @@ -159,6 +168,13 @@ typedef struct store { int recent; /* # of recent messages - don't trust this beyond the initial read */ } 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 { char *data; int len; @@ -168,8 +184,7 @@ typedef struct { #define DRV_OK 0 #define DRV_MSG_BAD 1 #define DRV_BOX_BAD 2 -#define DRV_STORE_BAD 3 -#define DRV_CANCELED 4 +#define DRV_CANCELED 3 /* All memory belongs to the driver's user. */ diff --git a/src/main.c b/src/main.c index 4776fc7..afe365d 100644 --- a/src/main.c +++ b/src/main.c @@ -673,6 +673,17 @@ sync_chans( main_vars_t *mvars, int ent ) } 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 store_opened( store_t *ctx, void *aux ) { MVARS(aux) @@ -689,9 +700,10 @@ store_opened( store_t *ctx, void *aux ) sync_chans( mvars, E_OPEN ); return; } - if (!mvars->boxlist && mvars->chan->patterns && !ctx->listed) + if (!mvars->boxlist && mvars->chan->patterns && !ctx->listed) { + set_bad_callback( ctx, store_bad, AUX ); mvars->drv[t]->list( ctx, store_listed, AUX ); - else { + } else { mvars->state[t] = ST_OPEN; sync_chans( mvars, E_OPEN ); } @@ -702,19 +714,16 @@ store_listed( int sts, void *aux ) { MVARS(aux) - mvars->state[t] = ST_OPEN; switch (sts) { case DRV_OK: if (mvars->ctx[t]->conf->map_inbox) add_string_list( &mvars->ctx[t]->boxes, mvars->ctx[t]->conf->map_inbox ); break; - case DRV_STORE_BAD: - mvars->drv[t]->cancel_store( mvars->ctx[t] ); - mvars->state[t] = ST_CLOSED; default: mvars->ret = mvars->skip = 1; break; } + mvars->state[t] = ST_OPEN; sync_chans( mvars, E_OPEN ); } diff --git a/src/sync.c b/src/sync.c index b3f57cd..9e73b98 100644 --- a/src/sync.c +++ b/src/sync.c @@ -328,9 +328,6 @@ msg_fetched( int sts, void *aux ) case DRV_MSG_BAD: vars->cb( SYNC_NOGOOD, 0, vars ); break; - case DRV_STORE_BAD: - vars->cb( SYNC_BAD(1-t), 0, vars ); - break; default: vars->cb( SYNC_FAIL, 0, vars ); break; @@ -356,9 +353,6 @@ msg_stored( int sts, int uid, void *aux ) str_ms[t], vars->msg->uid, str_ms[1-t] ); vars->cb( SYNC_NOGOOD, 0, vars ); break; - case DRV_STORE_BAD: - vars->cb( SYNC_BAD(t), 0, vars ); - break; default: vars->cb( SYNC_FAIL, 0, vars ); break; @@ -405,11 +399,6 @@ cancel_sync( sync_vars_t *svars ) svars->cancel = 1; for (t = 0; t < 2; t++) if (svars->ret & SYNC_BAD(t)) { - if (svars->ctx[t]) { - /* this should never recurse into cancel_sync() */ - svars->drv[t]->cancel_store( svars->ctx[t] ); - svars->ctx[t] = 0; - } cancel_done( AUX ); } else if (!(svars->state[t] & ST_SENT_CANCEL)) { /* ignore subsequent failures from in-flight commands */ @@ -431,17 +420,22 @@ cancel_done( void *aux ) } } +static void +store_bad( void *aux ) +{ + SVARS(aux) + + svars->ret |= SYNC_BAD(t); + svars->drv[t]->cancel_store( svars->ctx[t] ); + cancel_sync( svars ); +} static int -check_ret( int sts, sync_vars_t *svars, int t ) +check_ret( int sts, sync_vars_t *svars ) { switch (sts) { case DRV_CANCELED: return 1; - case DRV_STORE_BAD: - svars->ret |= SYNC_BAD(t); - cancel_sync( svars ); - return 1; case DRV_BOX_BAD: svars->ret |= SYNC_FAIL; cancel_sync( svars ); @@ -451,9 +445,9 @@ check_ret( int sts, sync_vars_t *svars, int t ) } static int -check_ret_aux( int sts, sync_vars_t *svars, int t, void *aux ) +check_ret_aux( int sts, sync_vars_t *svars, void *aux ) { - if (!check_ret( sts, svars, t )) + if (!check_ret( sts, svars )) return 0; free( aux ); return 1; @@ -507,6 +501,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] ))) ? "INBOX" : names[t]; ctx[t]->uidvalidity = -1; + set_bad_callback( ctx[t], store_bad, AUX ); svars->drv[t] = ctx[t]->conf->driver; svars->drv[t]->prepare_paths( ctx[t] ); } @@ -891,7 +886,7 @@ box_selected( int sts, void *aux ) find_vars_t *fv; sync_rec_t *srec; - if (check_ret( sts, svars, t )) + if (check_ret( sts, svars )) return; if (svars->uidval[t] >= 0 && svars->uidval[t] != svars->ctx[t]->uidvalidity) { error( "Error: UIDVALIDITY of %s changed (got %d, expected %d)\n", @@ -937,7 +932,7 @@ msg_found_sel( int sts, int uid, void *aux ) find_vars_t *vars = (find_vars_t *)aux; SVARS(vars->aux) - if (check_ret_aux( sts, svars, t, vars )) + if (check_ret_aux( sts, svars, vars )) return; switch (sts) { case DRV_OK: @@ -1409,7 +1404,7 @@ msg_found_new( int sts, int uid, void *aux ) find_vars_t *vars = (find_vars_t *)aux; SVARS(vars->aux) - if (check_ret_aux( sts, svars, t, vars )) + if (check_ret_aux( sts, svars, vars )) return; switch (sts) { case DRV_OK: @@ -1435,7 +1430,7 @@ flags_set_del( int sts, void *aux ) flag_vars_t *vars = (flag_vars_t *)aux; SVARS(vars->aux) - if (check_ret_aux( sts, svars, t, vars )) + if (check_ret_aux( sts, svars, vars )) return; switch (sts) { case DRV_OK: @@ -1456,7 +1451,7 @@ flags_set_sync( int sts, void *aux ) flag_vars_t *vars = (flag_vars_t *)aux; SVARS(vars->aux) - if (check_ret_aux( sts, svars, t, vars )) + if (check_ret_aux( sts, svars, vars )) return; switch (sts) { case DRV_OK: @@ -1559,7 +1554,7 @@ msg_trashed( int sts, void *aux ) if (sts == DRV_MSG_BAD) sts = DRV_BOX_BAD; - if (check_ret( sts, svars, t )) + if (check_ret( sts, svars )) return; svars->trash_done[t]++; stats( svars ); @@ -1613,7 +1608,7 @@ box_closed( int sts, void *aux ) { SVARS(aux) - if (check_ret( sts, svars, t )) + if (check_ret( sts, svars )) return; svars->state[t] |= ST_DID_EXPUNGE; box_closed_p2( svars, t ); @@ -1717,6 +1712,9 @@ sync_bail2( sync_vars_t *svars ) void *aux = svars->aux; int ret = svars->ret; + set_bad_callback( svars->ctx[0], 0, 0 ); + set_bad_callback( svars->ctx[1], 0, 0 ); + free( svars->lname ); free( svars->nname ); free( svars->jname ); ------------------------------------------------------------------------------ Colocation vs. Managed Hosting A question and answer guide to determining the best fit for your organization - today and in the future. http://p.sf.net/sfu/internap-sfd2d _______________________________________________ isync-devel mailing list isync-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/isync-devel