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

Reply via email to