commit 57e48f0118bacf555ca7b361b6c5f7d44345d700
Author: Oswald Buddenhagen <o...@kde.org>
Date:   Sun Jul 29 23:14:48 2012 +0200

    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.

 src/drv_imap.c    |   55 ++++++------
 src/drv_maildir.c |  148 ++++++++++++++++++-----------
 src/isync.h       |   28 +++---
 src/sync.c        |  226 +++++++++++++++++++++++++++------------------
 4 files changed, 270 insertions(+), 187 deletions(-)

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

------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and 
threat landscape has changed and how IT managers can respond. Discussions 
will include endpoint security, mobile security and the latest in malware 
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
_______________________________________________
isync-devel mailing list
isync-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/isync-devel

Reply via email to