commit 4cf90cedca8823aa7c2a49431c7681518e7dc7ba
Author: Oswald Buddenhagen <o...@kde.org>
Date:   Sat Feb 6 10:25:49 2010 +0100

    fully aync operation, take 2  *** WIP ***
    
    second attempt, starting "from the other end".
    
    this branch will be subject to forced pushes.

 TODO           |   11 +
 src/drv_imap.c |  667 +++++++++++++++++++++++++++++++++++-------------
 2 files changed, 501 insertions(+), 177 deletions(-)

diff --git a/TODO b/TODO
index dd2aafc..b81f0ba 100644
--- a/TODO
+++ b/TODO
@@ -1,3 +1,12 @@
+imap:
+- kill the rcaps hack. make to_trash a generic option. make submit_imap_cmd
+  act upon it and the resp. *nc option. reset resp. *nc when the data is sent
+  (as at that point the command will not fail with TRYCREATE any more).
+- rename cont to data_callback
+- store_msg (to trash) and trash_msg commands must be queued until trashnc is 
0,
+  otherwise they could be executed before the create and run into the same NO
+- do something with the int returned by the callbacks
+
 make SSL certificate validation more automatic.
 
 add deamon mode. primary goal: keep imap password in memory.
@@ -18,6 +27,8 @@ flagging the dummy would fetch the real message. possibly 
remove --renew.
 
 don't SELECT boxes unless really needed; in particular not for appending,
 and in write-only mode not before changes are made.
+problem: UIDVALIDITY change detection is delayed, significantly complicating
+matters.
 
 possibly request message attributes on a per-message basis from the drivers.
 considerations:
diff --git a/src/drv_imap.c b/src/drv_imap.c
index dc90678..cb245c2 100644
--- a/src/drv_imap.c
+++ b/src/drv_imap.c
@@ -111,12 +111,12 @@ struct imap_cmd;
 typedef struct imap_store {
        store_t gen;
        const char *prefix;
-       unsigned /*currentnc:1,*/ trashnc:1;
-       int uidnext; /* from SELECT responses */
+       unsigned /*currentnc:1,*/ trashnc:1; /* suppress LITERAL+ use on first 
STORE */
        unsigned got_namespace:1;
+       int uidnext; /* from SELECT responses */
        list_t *ns_personal, *ns_other, *ns_shared; /* NAMESPACE info */
        message_t **msgapp; /* FETCH results */
-       unsigned caps, rcaps; /* CAPABILITY results */
+       unsigned caps; /* CAPABILITY results */
        /* command queue */
        int nexttag, num_in_progress, literal_pending;
        struct imap_cmd *in_progress, **in_progress_append;
@@ -134,16 +134,42 @@ struct imap_cmd {
        struct {
                int (*cont)( imap_store_t *ctx, struct imap_cmd *cmd, const 
char *prompt );
                void (*done)( imap_store_t *ctx, struct imap_cmd *cmd, int 
response );
-               void *aux;
                char *data;
                int data_len;
-               int uid; /* to identify fetch responses */
+               int uid; /* to identify fetch & search responses */
                unsigned
+                       to_trash:1, /* we are storing to trash, not current. */
                        create:1, /* create the mailbox if we get an error ... 
*/
                        trycreate:1; /* ... but only if this is true or the 
server says so. */
        } param;
 };
 
+struct imap_cmd_simple {
+       struct imap_cmd gen;
+       int (*callback)( int sts, void *aux );
+       void *callback_aux;
+};
+
+struct imap_cmd_fetch_msg {
+       struct imap_cmd_simple gen;
+       msg_data_t *msg_data;
+};
+
+struct imap_cmd_store_msg {
+       struct imap_cmd gen;
+       int (*callback)( int sts, int uid, void *aux );
+       void *callback_aux;
+       int out_uid;
+};
+
+// XXX merge with above: imap_cmd_out_uid
+struct imap_cmd_find_msg {
+       struct imap_cmd gen;
+       int (*callback)( int sts, int uid, void *aux );
+       void *callback_aux;
+       int out_uid;
+};
+
 #define CAP(cap) (ctx->caps & (1 << (cap)))
 
 enum CAPABILITY {
@@ -168,9 +194,10 @@ static const char *cap_list[] = {
 #endif
 };
 
-#define RESP_OK    0
-#define RESP_NO    1
-#define RESP_BAD   2
+#define RESP_OK         0
+#define RESP_TRYCREATE  1
+#define RESP_NO         2
+#define RESP_BAD        3
 
 static int get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd );
 
@@ -476,29 +503,49 @@ buffer_gets( buffer_t * b, char **s )
 }
 
 static struct imap_cmd *
-new_imap_cmd( void )
+new_imap_cmd( int size )
 {
-       struct imap_cmd *cmd = nfmalloc( sizeof(*cmd) );
+       struct imap_cmd *cmd = nfmalloc( size );
        memset( &cmd->param, 0, sizeof(cmd->param) );
        return cmd;
 }
 
+#define INIT_IMAP_CMD(type, cmdp, cb, aux) \
+       cmdp = (struct type *)new_imap_cmd( sizeof(*cmdp) ); \
+       cmdp->callback = cb; \
+       cmdp->callback_aux = aux;
+
+#define INIT_IMAP_CMD_X(type, cmdp, cb, aux) \
+       cmdp = (struct type *)new_imap_cmd( sizeof(*cmdp) ); \
+       cmdp->gen.callback = cb; \
+       cmdp->gen.callback_aux = aux;
+
 static struct imap_cmd *
 v_submit_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd,
                    const char *fmt, va_list ap )
 {
-       int n, bufl;
+       int n, bufl, litplus;
+       const char *buffmt;
        char buf[1024];
 
        while (ctx->literal_pending)
                get_cmd_result( ctx, 0 );
 
        if (!cmd)
-               cmd = new_imap_cmd();
+               cmd = new_imap_cmd( sizeof(*cmd) );
        cmd->tag = ++ctx->nexttag;
        nfvasprintf( &cmd->cmd, fmt, ap );
-       bufl = nfsnprintf( buf, sizeof(buf), cmd->param.data ? CAP(LITERALPLUS) 
?
-                          "%d %s{%d+}\r\n" : "%d %s{%d}\r\n" : "%d %s\r\n",
+       if (!cmd->param.data) {
+               buffmt = "%d %s\r\n";
+               litplus = 0;
+       } else if ((cmd->param.to_trash && ctx->trashnc) || !CAP(LITERALPLUS)) {
+               buffmt = "%d %s{%d}\r\n";
+               litplus = 0;
+       } else {
+               buffmt = "%d %s{%d+}\r\n";
+               litplus = 1;
+       }
+       bufl = nfsnprintf( buf, sizeof(buf), buffmt,
                           cmd->tag, cmd->cmd, cmd->param.data_len );
        if (DFlags & VERBOSE) {
                if (ctx->num_in_progress)
@@ -511,31 +558,30 @@ v_submit_imap_cmd( imap_store_t *ctx, struct imap_cmd 
*cmd,
        if (socket_write( &ctx->buf.sock, buf, bufl ) != bufl) {
                if (cmd->param.data)
                        free( cmd->param.data );
-               free( cmd->cmd );
-               free( cmd );
-               return NULL;
+               goto bail;
        }
-       if (cmd->param.data) {
-               if (CAP(LITERALPLUS)) {
-                       n = socket_write( &ctx->buf.sock, cmd->param.data, 
cmd->param.data_len );
-                       free( cmd->param.data );
-                       if (n != cmd->param.data_len ||
-                           (n = socket_write( &ctx->buf.sock, "\r\n", 2 )) != 
2)
-                       {
-                               free( cmd->cmd );
-                               free( cmd );
-                               return NULL;
-                       }
-                       cmd->param.data = 0;
-               } else
-                       ctx->literal_pending = 1;
-       } else if (cmd->param.cont)
+       if (litplus) {
+               n = socket_write( &ctx->buf.sock, cmd->param.data, 
cmd->param.data_len );
+               free( cmd->param.data );
+               if (n != cmd->param.data_len ||
+                   (n = socket_write( &ctx->buf.sock, "\r\n", 2 )) != 2)
+                       goto bail;
+               cmd->param.data = 0;
+       } else if (cmd->param.cont || cmd->param.data) {
                ctx->literal_pending = 1;
+       }
        cmd->next = 0;
        *ctx->in_progress_append = cmd;
        ctx->in_progress_append = &cmd->next;
        ctx->num_in_progress++;
        return cmd;
+
+  bail:
+       if (cmd->param.done)
+               cmd->param.done( ctx, cmd, RESP_BAD );
+       free( cmd->cmd );
+       free( cmd );
+       return NULL;
 }
 
 static struct imap_cmd *
@@ -550,22 +596,23 @@ submit_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd, 
const char *fmt, ... )
        return ret;
 }
 
-static int
-imap_exec( imap_store_t *ctx, struct imap_cmd *cmdp, const char *fmt, ... )
+static void
+imap_run( imap_store_t *ctx, struct imap_cmd *cmdp,
+          void (*done)( imap_store_t *ctx, struct imap_cmd *cmd, int response 
),
+          const char *fmt, ... )
 {
        va_list ap;
 
+       cmdp->param.done = done;
        va_start( ap, fmt );
        cmdp = v_submit_imap_cmd( ctx, cmdp, fmt, ap );
        va_end( ap );
-       if (!cmdp)
-               return RESP_BAD;
-
-       return get_cmd_result( ctx, cmdp );
+       if (cmdp)
+               get_cmd_result( ctx, cmdp );
 }
 
 static int
-imap_exec_b( imap_store_t *ctx, struct imap_cmd *cmdp, const char *fmt, ... )
+imap_exec( imap_store_t *ctx, struct imap_cmd *cmdp, const char *fmt, ... )
 {
        va_list ap;
 
@@ -573,33 +620,51 @@ imap_exec_b( imap_store_t *ctx, struct imap_cmd *cmdp, 
const char *fmt, ... )
        cmdp = v_submit_imap_cmd( ctx, cmdp, fmt, ap );
        va_end( ap );
        if (!cmdp)
-               return DRV_STORE_BAD;
+               return RESP_BAD;
 
-       switch (get_cmd_result( ctx, cmdp )) {
-       case RESP_BAD: return DRV_STORE_BAD;
-       case RESP_NO: return DRV_BOX_BAD;
-       default: return DRV_OK;
+       return get_cmd_result( ctx, cmdp );
+}
+
+static void
+transform_box_response( int *response )
+{
+       switch (*response) {
+       case RESP_BAD: *response = DRV_STORE_BAD; break;
+       case RESP_NO: *response = DRV_BOX_BAD; break;
+       default: *response = DRV_OK; break;
        }
 }
 
-static int
-imap_exec_m( imap_store_t *ctx, struct imap_cmd *cmdp, const char *fmt, ... )
+static void
+imap_done_simple_box( imap_store_t *ctx ATTR_UNUSED,
+                      struct imap_cmd *cmd, int response )
 {
-       va_list ap;
+       struct imap_cmd_simple *cmdp = (struct imap_cmd_simple *)cmd;
 
-       va_start( ap, fmt );
-       cmdp = v_submit_imap_cmd( ctx, cmdp, fmt, ap );
-       va_end( ap );
-       if (!cmdp)
-               return DRV_STORE_BAD;
+       transform_box_response( &response );
+       cmdp->callback( response, cmdp->callback_aux );
+}
 
-       switch (get_cmd_result( ctx, cmdp )) {
-       case RESP_BAD: return DRV_STORE_BAD;
-       case RESP_NO: return DRV_MSG_BAD;
-       default: return DRV_OK;
+static void
+transform_msg_response( int *response )
+{
+       switch (*response) {
+       case RESP_BAD: *response = DRV_STORE_BAD; break;
+       case RESP_NO: *response = DRV_MSG_BAD; break;
+       default: *response = DRV_OK; break;
        }
 }
 
+static void
+imap_done_simple_msg( imap_store_t *ctx ATTR_UNUSED,
+                      struct imap_cmd *cmd, int response )
+{
+       struct imap_cmd_simple *cmdp = (struct imap_cmd_simple *)cmd;
+
+       transform_msg_response( &response );
+       cmdp->callback( response, cmdp->callback_aux );
+}
+
 /*
 static void
 drain_imap_replies( imap_store_t *ctx )
@@ -837,7 +902,7 @@ parse_fetch( imap_store_t *ctx, char *cmd ) /* move this 
down */
                free_list( list );
                return -1;
          gotuid:
-               msgdata = (msg_data_t *)cmdp->param.aux;
+               msgdata = ((struct imap_cmd_fetch_msg *)cmdp)->msg_data;
                msgdata->data = body;
                msgdata->len = size;
                if (status & M_FLAGS)
@@ -869,7 +934,6 @@ parse_capability( imap_store_t *ctx, char *cmd )
                for (i = 0; i < as(cap_list); i++)
                        if (!strcmp( cap_list[i], arg ))
                                ctx->caps |= 1 << i;
-       ctx->rcaps = ctx->caps;
 }
 
 static int
@@ -906,10 +970,11 @@ parse_response_code( imap_store_t *ctx, struct imap_cmd 
*cmd, char *s )
                 */
                for (; isspace( (unsigned char)*p ); p++);
                error( "*** IMAP ALERT *** %s\n", p );
-       } else if (cmd && cmd->param.aux && !strcmp( "APPENDUID", arg )) {
+       } else if (cmd && !strcmp( "APPENDUID", arg )) {
                if (!(arg = next_arg( &s )) ||
                    (ctx->gen.uidvalidity = strtoll( arg, &earg, 10 ), *earg) ||
-                   !(arg = next_arg( &s )) || !(*(int *)cmd->param.aux = atoi( 
arg )))
+                   !(arg = next_arg( &s )) ||
+                   !(((struct imap_cmd_store_msg *)cmd)->out_uid = atoi( arg 
)))
                {
                        error( "IMAP error: malformed APPENDUID status\n" );
                        return RESP_BAD;
@@ -941,7 +1006,7 @@ parse_search( imap_store_t *ctx, char *cmd )
         */
        for (cmdp = ctx->in_progress; cmdp; cmdp = cmdp->next)
                if (cmdp->param.uid == -1) {
-                       *(int *)cmdp->param.aux = uid;
+                       ((struct imap_cmd_find_msg *)cmdp)->out_uid = uid;
                        return;
                }
        error( "IMAP error: unexpected SEARCH response (UID %u)\n", uid );
@@ -976,8 +1041,8 @@ parse_list_rsp( imap_store_t *ctx, char *cmd )
 static int
 get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd )
 {
-       struct imap_cmd *cmdp, **pcmdp, *ncmdp;
-       char *cmd, *arg, *arg1, *p;
+       struct imap_cmd *cmdp, **pcmdp;
+       char *cmd, *arg, *arg1;
        int n, resp, resp2, tag;
 
        for (;;) {
@@ -1028,6 +1093,14 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd 
)
                        cmdp = (struct imap_cmd *)((char 
*)ctx->in_progress_append -
                               offsetof(struct imap_cmd, next));
                        if (cmdp->param.data) {
+                               /* If we get here, we will not get NO 
[TRYCREATE] any more.
+                                * This code assumes that only STORE provides 
direct data. */
+                               if (cmdp->param.to_trash)
+                                       ctx->trashnc = 0;
+#if 0
+                               else
+                                       ctx->currentnc = 0;
+#endif
                                n = socket_write( &ctx->buf.sock, 
cmdp->param.data, cmdp->param.data_len );
                                free( cmdp->param.data );
                                cmdp->param.data = 0;
@@ -1064,28 +1137,12 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd 
*tcmd )
                                resp = DRV_OK;
                        else {
                                if (!strcmp( "NO", arg )) {
-                                       if (cmdp->param.create && cmd && 
(cmdp->param.trycreate || !memcmp( cmd, "[TRYCREATE]", 11 ))) { /* SELECT, 
APPEND or UID COPY */
-                                               p = strchr( cmdp->cmd, '"' );
-                                               if (!submit_imap_cmd( ctx, 0, 
"CREATE %.*s", strchr( p + 1, '"' ) - p + 1, p )) {
-                                                       resp = RESP_BAD;
-                                                       goto normal;
-                                               }
-                                               /* not waiting here violates 
the spec, but a server that does not
-                                                  grok this nonetheless 
violates it too. */
-                                               ncmdp = nfmalloc( 
sizeof(*ncmdp) );
-                                               memcpy( &ncmdp->param, 
&cmdp->param, sizeof(cmdp->param) );
-                                               ncmdp->param.create = 0;
-                                               if (!submit_imap_cmd( ctx, 
ncmdp, "%s", cmdp->cmd )) {
-                                                       resp = RESP_BAD;
-                                                       goto normal;
-                                               }
-                                               free( cmdp->cmd );
-                                               free( cmdp );
-                                               if (!tcmd)
-                                                       return 0;       /* 
ignored */
-                                               if (cmdp == tcmd)
-                                                       tcmd = ncmdp;
-                                               continue;
+                                       if (cmdp->param.create &&
+                                           (cmdp->param.trycreate ||
+                                            (cmd && !memcmp( cmd, 
"[TRYCREATE]", 11 ))))
+                                       { /* SELECT, APPEND or UID COPY */
+                                               resp = RESP_TRYCREATE;
+                                               goto normal;
                                        }
                                        resp = RESP_NO;
                                } else /*if (!strcmp( "BAD", arg ))*/
@@ -1101,7 +1158,8 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd )
                                cmdp->param.done( ctx, cmdp, resp );
                        if (cmdp->param.data)
                                free( cmdp->param.data );
-                       free( cmdp->cmd );
+                       if (cmdp->cmd) /* "done" might transfer ownership */
+                               free( cmdp->cmd );
                        free( cmdp );
                        if (!tcmd || tcmd == cmdp)
                                return resp;
@@ -1154,14 +1212,21 @@ imap_own_store( store_conf_t *conf )
 }
 
 static void
+imap_cleanup_p2( imap_store_t *ctx,
+                 struct imap_cmd *cmd ATTR_UNUSED, int response ATTR_UNUSED )
+{
+       imap_cancel_store( &ctx->gen );
+}
+
+static void
 imap_cleanup( void )
 {
        store_t *ctx, *nctx;
 
        for (ctx = unowned; ctx; ctx = nctx) {
                nctx = ctx->next;
-               imap_exec( (imap_store_t *)ctx, 0, "LOGOUT" );
-               imap_cancel_store( ctx );
+               imap_run( (imap_store_t *)ctx, new_imap_cmd( sizeof(struct 
imap_cmd) ),
+                         imap_cleanup_p2, "LOGOUT" );
        }
 }
 
@@ -1446,7 +1511,7 @@ imap_open_store( store_conf_t *conf,
                }
 #if HAVE_LIBSSL
                if (CAP(CRAM)) {
-                       struct imap_cmd *cmd = new_imap_cmd();
+                       struct imap_cmd *cmd = new_imap_cmd( sizeof(*cmd) );
 
                        info( "Authenticating with CRAM-MD5\n" );
                        cmd->param.cont = do_cram_auth;
@@ -1514,16 +1579,160 @@ imap_prepare_opts( store_t *gctx, int opts )
        gctx->opts = opts;
 }
 
+static void
+imap_select_p4( imap_store_t *ctx, struct imap_cmd *cmd, int response )
+{
+       struct imap_cmd_simple *cmdp = (struct imap_cmd_simple *)cmd;
+
+       transform_box_response( &response );
+       if (response != DRV_OK) {
+               cmdp->callback( response, cmdp->callback_aux );
+       } else {
+               struct imap_cmd_simple *cmd2;
+               char *p;
+
+               INIT_IMAP_CMD(imap_cmd_simple, cmd2,
+                             cmdp->callback, cmdp->callback_aux)
+               p = strchr( cmd->cmd, '"' );
+               imap_run( ctx, &cmd2->gen, imap_done_simple_box,
+                         "SELECT %.*s", strchr( p + 1, '"' ) - p + 1, p );
+       }
+}
+
+struct imap_select2_state {
+       int (*callback)( int sts, void *aux );
+       void *callback_aux;
+       int ref_count;
+       int ret_val;
+};
+
+struct imap_cmd_select2 {
+       struct imap_cmd gen;
+       struct imap_select2_state *state;
+};
+
+static void
+imap_select_bail( struct imap_select2_state *sts )
+{
+       sts->callback( sts->ret_val, sts->callback_aux );
+       free( sts );
+}
+
+static void
+imap_select_p3( imap_store_t *ctx ATTR_UNUSED, struct imap_cmd *cmd, int 
response )
+{
+       struct imap_select2_state *sts = ((struct imap_cmd_select2 
*)cmd)->state;
+
+       switch (response) {
+       case RESP_BAD:
+               sts->ret_val = DRV_STORE_BAD;
+               break;
+       case RESP_NO:
+               if (sts->ret_val != DRV_STORE_BAD)
+                       sts->ret_val = DRV_BOX_BAD;
+               break;
+       }
+       if (!--sts->ref_count)
+               imap_select_bail( sts );
+}
+
+static int
+imap_submit_select2( imap_store_t *ctx, struct imap_select2_state *sts,
+                     const char *buf, struct imap_cmd_select2 **cmd2p )
+{
+       struct imap_cmd_select2 *cmd2 =
+               (struct imap_cmd_select2 *)new_imap_cmd( sizeof(*cmd2) );
+       cmd2->gen.param.done = imap_select_p3;
+       cmd2->state = sts;
+       sts->ref_count++;
+       if (submit_imap_cmd( ctx, &cmd2->gen,
+                            "UID FETCH %s (UID%s%s)", buf,
+                            (ctx->gen.opts & OPEN_FLAGS) ? " FLAGS" : "",
+                            (ctx->gen.opts & OPEN_SIZE) ? " RFC822.SIZE" : "" 
))
+       {
+               *cmd2p = cmd2;
+               return 1;
+       }
+       sts->ref_count--;
+       return 0;
+}
+
+struct imap_cmd_select {
+       struct imap_cmd_simple gen;
+       int minuid, maxuid, *excs, nexcs;
+};
+
+static void
+imap_select_p2( imap_store_t *ctx, struct imap_cmd *cmd, int response )
+{
+       struct imap_cmd_select *cmdp = (struct imap_cmd_select *)cmd;
+       int i, j, bl;
+       char buf[1000];
+
+       if (response == RESP_TRYCREATE) {
+               struct imap_cmd_simple *cmd2;
+               char *p;
+
+               if (cmdp->excs)
+                       free( cmdp->excs );
+               INIT_IMAP_CMD(imap_cmd_simple, cmd2,
+                             cmdp->gen.callback, cmdp->gen.callback_aux)
+               p = strchr( cmd->cmd, '"' );
+               imap_run( ctx, &cmd2->gen, imap_select_p4,
+                         "CREATE %.*s", strchr( p + 1, '"' ) - p + 1, p );
+       } else {
+               transform_box_response( &response );
+               if (response != DRV_OK || !ctx->gen.count) {
+                       if (cmdp->excs)
+                               free( cmdp->excs );
+                       cmdp->gen.callback( response, cmdp->gen.callback_aux );
+               } else {
+                       struct imap_cmd_select2 *cmd2 = 0;
+                       struct imap_select2_state *sts = nfmalloc( sizeof(*sts) 
);
+                       sts->callback = cmdp->gen.callback;
+                       sts->callback_aux = cmdp->gen.callback_aux;
+                       sts->ref_count = 1; /* so forced sync does not cause an 
early exit */
+                       sts->ret_val = DRV_OK;
+
+                       ctx->msgapp = &ctx->gen.msgs;
+                       sort_ints( cmdp->excs, cmdp->nexcs );
+                       for (i = 0; i < cmdp->nexcs; ) {
+                               for (bl = 0; i < cmdp->nexcs && bl < 960; i++) {
+                                       if (bl)
+                                               buf[bl++] = ',';
+                                       bl += sprintf( buf + bl, "%d", 
cmdp->excs[i] );
+                                       j = i;
+                                       for (; i + 1 < cmdp->nexcs && 
cmdp->excs[i + 1] == cmdp->excs[i] + 1; i++);
+                                       if (i != j)
+                                               bl += sprintf( buf + bl, ":%d", 
cmdp->excs[i] );
+                               }
+                               if (!imap_submit_select2( ctx, sts, buf, &cmd2 
))
+                                       goto bail;
+                       }
+                       if (cmdp->maxuid == INT_MAX)
+                               cmdp->maxuid = ctx->uidnext ? ctx->uidnext - 1 
: 1000000000;
+                       if (cmdp->maxuid >= cmdp->minuid) {
+                               sprintf( buf, "%d:%d", cmdp->minuid, 
cmdp->maxuid );
+                               imap_submit_select2( ctx, sts, buf, &cmd2 );
+                       }
+                 bail:
+                       if (cmdp->excs)
+                               free( cmdp->excs );
+                       if (!--sts->ref_count)
+                               imap_select_bail( sts );
+                       else
+                               get_cmd_result( ctx, &cmd2->gen );
+               }
+       }
+}
+
 static int
 imap_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs,
              int (*cb)( int sts, void *aux ), void *aux )
 {
        imap_store_t *ctx = (imap_store_t *)gctx;
-       struct imap_cmd *cmd = new_imap_cmd();
+       struct imap_cmd_select *cmd;
        const char *prefix;
-       int ret, i, j, bl;
-       char buf[1000];
-
 
        if (!strcmp( gctx->name, "INBOX" )) {
 //             ctx->currentnc = 0;
@@ -1533,55 +1742,31 @@ imap_select( store_t *gctx, int minuid, int maxuid, int 
*excs, int nexcs,
                prefix = ctx->prefix;
        }
 
-       cmd->param.create = (gctx->opts & OPEN_CREATE) != 0;
-       cmd->param.trycreate = 1;
-       if ((ret = imap_exec_b( ctx, cmd, "SELECT \"%s%s\"", prefix, gctx->name 
)) != DRV_OK)
-               goto bail;
-
-       if (gctx->count) {
-               ctx->msgapp = &gctx->msgs;
-               sort_ints( excs, nexcs );
-               for (i = 0; i < nexcs; ) {
-                       for (bl = 0; i < nexcs && bl < 960; i++) {
-                               if (bl)
-                                       buf[bl++] = ',';
-                               bl += sprintf( buf + bl, "%d", excs[i] );
-                               j = i;
-                               for (; i + 1 < nexcs && excs[i + 1] == excs[i] 
+ 1; i++);
-                               if (i != j)
-                                       bl += sprintf( buf + bl, ":%d", excs[i] 
);
-                       }
-                       if ((ret = imap_exec_b( ctx, 0, "UID FETCH %s 
(UID%s%s)", buf,
-                                               (gctx->opts & OPEN_FLAGS) ? " 
FLAGS" : "",
-                                               (gctx->opts & OPEN_SIZE) ? " 
RFC822.SIZE" : "" )) != DRV_OK)
-                               goto bail;
-               }
-               if (maxuid == INT_MAX)
-                       maxuid = ctx->uidnext ? ctx->uidnext - 1 : 1000000000;
-               if (maxuid >= minuid &&
-                   (ret = imap_exec_b( ctx, 0, "UID FETCH %d:%d (UID%s%s)", 
minuid, maxuid,
-                                       (gctx->opts & OPEN_FLAGS) ? " FLAGS" : 
"",
-                                       (gctx->opts & OPEN_SIZE) ? " 
RFC822.SIZE" : "" )) != DRV_OK)
-                       goto bail;
-       }
-
-       ret = DRV_OK;
-
-  bail:
-       if (excs)
-               free( excs );
-       return cb( ret, aux );
+       INIT_IMAP_CMD_X(imap_cmd_select, cmd, cb, aux)
+       cmd->gen.gen.param.create = (gctx->opts & OPEN_CREATE) != 0;
+       cmd->gen.gen.param.trycreate = 1;
+       cmd->minuid = minuid;
+       cmd->maxuid = maxuid;
+       cmd->excs = excs;
+       cmd->nexcs = nexcs;
+       imap_run( ctx, &cmd->gen.gen, imap_select_p2,
+                 "SELECT \"%s%s\"", prefix, gctx->name );
+       return 0;
 }
 
 static int
 imap_fetch_msg( store_t *ctx, message_t *msg, msg_data_t *data,
                 int (*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 );
+       struct imap_cmd_fetch_msg *cmd;
+
+       INIT_IMAP_CMD_X(imap_cmd_fetch_msg, cmd, cb, aux)
+       cmd->gen.gen.param.uid = msg->uid;
+       cmd->msg_data = data;
+       imap_run( (imap_store_t *)ctx, &cmd->gen.gen, imap_done_simple_msg,
+                 "UID FETCH %d (%sBODY.PEEK[])",
+                 msg->uid, (msg->status & M_FLAGS) ? "" : "FLAGS " );
+       return 0;
 }
 
 static int
@@ -1638,7 +1823,56 @@ static int
 imap_close( store_t *ctx,
             int (*cb)( int sts, void *aux ), void *aux )
 {
-       return cb( imap_exec_b( (imap_store_t *)ctx, 0, "CLOSE" ), aux );
+       struct imap_cmd_simple *cmd;
+
+       INIT_IMAP_CMD(imap_cmd_simple, cmd, cb, aux)
+       imap_run( (imap_store_t *)ctx, &cmd->gen, imap_done_simple_box, "CLOSE" 
);
+       return 0;
+}
+
+struct imap_cmd_trash_msg {
+       struct imap_cmd_simple gen;
+       char *orig_cmd;
+};
+
+static void
+imap_trash_msg_p3( imap_store_t *ctx, struct imap_cmd *cmd, int response )
+{
+       struct imap_cmd_trash_msg *cmdp = (struct imap_cmd_trash_msg *)cmd;
+
+       transform_msg_response( &response ); /* XXX no code to indicate trash 
failure */
+       if (response != DRV_OK) {
+               cmdp->gen.callback( response, cmdp->gen.callback_aux );
+       } else {
+               struct imap_cmd_simple *cmd2;
+               INIT_IMAP_CMD(imap_cmd_simple, cmd2,
+                             cmdp->gen.callback, cmdp->gen.callback_aux)
+               imap_run( ctx, &cmd2->gen, imap_done_simple_msg,
+                         "%s", cmdp->orig_cmd );
+       }
+       free( cmdp->orig_cmd );
+}
+
+static void
+imap_trash_msg_p2( imap_store_t *ctx, struct imap_cmd *cmd, int response )
+{
+       struct imap_cmd_simple *cmdp = (struct imap_cmd_simple *)cmd;
+
+       if (response != RESP_TRYCREATE) {
+               transform_msg_response( &response );
+               cmdp->callback( response, cmdp->callback_aux );
+       } else {
+               struct imap_cmd_trash_msg *cmd2;
+               char *p;
+
+               INIT_IMAP_CMD_X(imap_cmd_trash_msg, cmd2,
+                               cmdp->callback, cmdp->callback_aux)
+               cmd2->orig_cmd = cmd->cmd;
+               cmd->cmd = 0;
+               p = strchr( cmd2->orig_cmd, '"' );
+               imap_run( ctx, &cmd2->gen.gen, imap_trash_msg_p3,
+                         "CREATE %.*s", strchr( p + 1, '"' ) - p + 1, p );
+       }
 }
 
 static int
@@ -1646,10 +1880,68 @@ imap_trash_msg( store_t *gctx, message_t *msg,
                 int (*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;
-       return cb( imap_exec_m( ctx, cmd, "UID COPY %d \"%s%s\"",
-                               msg->uid, ctx->prefix, gctx->conf->trash ), aux 
);
+       struct imap_cmd_simple *cmd;
+
+       INIT_IMAP_CMD(imap_cmd_simple, cmd, cb, aux)
+       cmd->gen.param.create = 1;
+       imap_run( ctx, &cmd->gen, imap_trash_msg_p2,
+                 "UID COPY %d \"%s%s\"",
+                 msg->uid, ctx->prefix, gctx->conf->trash );
+       return 0;
+}
+
+static void
+imap_store_msg_p4( imap_store_t *ctx ATTR_UNUSED, struct imap_cmd *cmd, int 
response )
+{
+       struct imap_cmd_store_msg *cmdp = (struct imap_cmd_store_msg *)cmd;
+
+       transform_msg_response( &response );
+       cmdp->callback( response, cmdp->out_uid, cmdp->callback_aux );
+}
+
+struct imap_cmd_store_msg2 {
+       struct imap_cmd_store_msg gen;
+       char *orig_cmd;
+};
+
+static void
+imap_store_msg_p3( imap_store_t *ctx, struct imap_cmd *cmd, int response )
+{
+       struct imap_cmd_store_msg2 *cmdp = (struct imap_cmd_store_msg2 *)cmd;
+
+       transform_msg_response( &response );
+       if (response != DRV_OK) {
+               cmdp->gen.callback( response, -1, cmdp->gen.callback_aux );
+       } else {
+               struct imap_cmd_store_msg *cmd2;
+               INIT_IMAP_CMD(imap_cmd_store_msg, cmd2,
+                             cmdp->gen.callback, cmdp->gen.callback_aux)
+               imap_run( ctx, &cmd2->gen, imap_store_msg_p4,
+                         "%s", cmdp->orig_cmd );
+       }
+       free( cmdp->orig_cmd );
+}
+
+static void
+imap_store_msg_p2( imap_store_t *ctx, struct imap_cmd *cmd, int response )
+{
+       struct imap_cmd_store_msg *cmdp = (struct imap_cmd_store_msg *)cmd;
+
+       if (response != RESP_TRYCREATE) {
+               transform_msg_response( &response );
+               cmdp->callback( response, cmdp->out_uid, cmdp->callback_aux );
+       } else {
+               struct imap_cmd_store_msg2 *cmd2;
+               char *p;
+
+               INIT_IMAP_CMD_X(imap_cmd_store_msg2, cmd2,
+                               cmdp->callback, cmdp->callback_aux)
+               cmd2->orig_cmd = cmd->cmd;
+               cmd->cmd = 0;
+               p = strchr( cmd2->orig_cmd, '"' );
+               imap_run( ctx, &cmd2->gen.gen, imap_store_msg_p3,
+                         "CREATE %.*s", strchr( p + 1, '"' ) - p + 1, p );
+       }
 }
 
 static int
@@ -1657,9 +1949,9 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int 
to_trash,
                 int (*cb)( int sts, int uid, void *aux ), void *aux )
 {
        imap_store_t *ctx = (imap_store_t *)gctx;
-       struct imap_cmd *cmd = new_imap_cmd();
+       struct imap_cmd_store_msg *cmd;
        const char *prefix, *box;
-       int ret, d, uid;
+       int d;
        char flagstr[128];
 
        d = 0;
@@ -1669,35 +1961,41 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int 
to_trash,
        }
        flagstr[d] = 0;
 
-       cmd->param.data_len = data->len;
-       cmd->param.data = data->data;
-       cmd->param.aux = &uid;
-       uid = -2;
+       INIT_IMAP_CMD(imap_cmd_store_msg, cmd, cb, aux)
+       cmd->gen.param.data_len = data->len;
+       cmd->gen.param.data = data->data;
+       cmd->out_uid = -1;
 
        if (to_trash) {
                box = gctx->conf->trash;
                prefix = ctx->prefix;
-               cmd->param.create = 1;
-               if (ctx->trashnc)
-                       ctx->caps = ctx->rcaps & ~(1 << LITERALPLUS);
+               cmd->gen.param.create = 1;
+               cmd->gen.param.to_trash = 1;
        } else {
                box = gctx->name;
                prefix = !strcmp( box, "INBOX" ) ? "" : ctx->prefix;
-               cmd->param.create = (gctx->opts & OPEN_CREATE) != 0;
-               /*if (ctx->currentnc)
-                       ctx->caps = ctx->rcaps & ~(1 << LITERALPLUS);*/
-       }
-       ret = imap_exec_m( ctx, cmd, "APPEND \"%s%s\" %s", prefix, box, flagstr 
);
-       ctx->caps = ctx->rcaps;
-       if (ret != DRV_OK)
-               return cb( ret, -1, aux );
-       if (to_trash)
-               ctx->trashnc = 0;
-       else {
-               /*ctx->currentnc = 0;*/
+#if 0
+               /* This is useless as we always SELECT the mailbox first
+                * (to obtain the UIDVALIDITY upfront). */
+               cmd->gen.param.create = (gctx->opts & OPEN_CREATE) != 0;
+#endif
        }
+       imap_run( ctx, &cmd->gen, imap_store_msg_p2,
+                 "APPEND \"%s%s\" %s", prefix, box, flagstr );
+       return 0;
+}
+
+static void
+imap_find_msg_p2( imap_store_t *ctx ATTR_UNUSED, struct imap_cmd *cmd, int 
response )
+{
+       struct imap_cmd_find_msg *cmdp = (struct imap_cmd_find_msg *)cmd;
 
-       return cb( DRV_OK, uid, aux );
+       transform_msg_response( &response );
+       if (response != DRV_OK)
+               cmdp->callback( response, -1, cmdp->callback_aux );
+       else
+               cmdp->callback( cmdp->out_uid <= 0 ? DRV_MSG_BAD : DRV_OK,
+                               cmdp->out_uid, cmdp->callback_aux );
 }
 
 static int
@@ -1705,16 +2003,31 @@ imap_find_msg( store_t *gctx, const char *tuid,
                int (*cb)( int sts, int uid, void *aux ), void *aux )
 {
        imap_store_t *ctx = (imap_store_t *)gctx;
-       struct imap_cmd *cmd = new_imap_cmd();
-       int ret, uid;
-
-       cmd->param.uid = -1; /* we're looking for a UID */
-       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 );
-       else
-               return cb( uid <= 0 ? DRV_MSG_BAD : DRV_OK, uid, aux );
+       struct imap_cmd_find_msg *cmd;
+
+       INIT_IMAP_CMD(imap_cmd_find_msg, cmd, cb, aux)
+       cmd->gen.param.uid = -1; /* we're looking for a UID */
+       cmd->out_uid = -1; /* in case we get no SEARCH response at all */
+       imap_run( ctx, &cmd->gen, imap_find_msg_p2,
+                 "UID SEARCH HEADER X-TUID %." stringify(TUIDL) "s", tuid );
+       return 0;
+}
+
+struct imap_cmd_list {
+       struct imap_cmd gen;
+       void (*callback)( int sts, void *aux );
+       void *callback_aux;
+};
+
+static void
+imap_list_p2( imap_store_t *ctx, struct imap_cmd *cmd, int response )
+{
+       struct imap_cmd_list *cmdp = (struct imap_cmd_list *)cmd;
+
+       transform_box_response( &response );
+       if (response == DRV_OK)
+               ctx->gen.listed = 1;
+       cmdp->callback( response, cmdp->callback_aux );
 }
 
 static void
@@ -1722,11 +2035,11 @@ imap_list( store_t *gctx,
            void (*cb)( int sts, void *aux ), void *aux )
 {
        imap_store_t *ctx = (imap_store_t *)gctx;
-       int ret;
+       struct imap_cmd_list *cmd;
 
-       if ((ret = imap_exec_b( ctx, 0, "LIST \"\" \"%s%%\"", ctx->prefix )) == 
DRV_OK)
-               gctx->listed = 1;
-       cb( ret, aux );
+       INIT_IMAP_CMD(imap_cmd_list, cmd, cb, aux)
+       imap_run( ctx, &cmd->gen, imap_list_p2,
+                 "LIST \"\" \"%s%%\"", ctx->prefix );
 }
 
 static void

------------------------------------------------------------------------------
The Planet: dedicated and managed hosting, cloud storage, colocation
Stay online with enterprise data centers and the best network in the business
Choose flexible plans and management services without long-term contracts
Personal 24x7 support from experience hosting pros just a phone call away.
http://p.sf.net/sfu/theplanet-com
_______________________________________________
isync-devel mailing list
isync-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/isync-devel

Reply via email to