commit 8b3bb9ade881d203b54f7495feb2c9530dcbf5be
Author: Oswald Buddenhagen <[email protected]>
Date: Sun Mar 13 11:34:04 2011 +0100
make imap_exec() result reporting callback-based
this makes the IMAP command submission interface asynchronous.
the imap context is now refcounted, so it can be kept alive after
imap_cancel_store() is called from a callback, so it can hold a
cancelation indicator which can be queried by loops (which must hold a
reference, obviously).
as a "side effect", properly sequence commands after CREATE resulting
from [TRYCREATE].
src/drv_imap.c | 917 +++++++++++++++++++++++++++++++++++-------------
1 files changed, 677 insertions(+), 240 deletions(-)
diff --git a/src/drv_imap.c b/src/drv_imap.c
index 92777b7..be083a5 100644
--- a/src/drv_imap.c
+++ b/src/drv_imap.c
@@ -121,12 +121,22 @@ typedef struct imap_store {
list_t *ns_personal, *ns_other, *ns_shared; /* NAMESPACE info */
message_t **msgapp; /* FETCH results */
unsigned caps; /* CAPABILITY results */
+ int ref_count; /* for ordered destruction */
+ int store_canceled; /* context is invalid, only ref_count keeps it
alive */
/* command queue */
int nexttag, num_in_progress, literal_pending;
struct imap_cmd *in_progress, **in_progress_append;
#if HAVE_LIBSSL
SSL_CTX *SSLContext;
#endif
+
+ /* Used during sequential operations like connect */
+ int preauth;
+ union {
+ void (*imap_open)( store_t *srv, void *aux );
+ } callbacks;
+ void *callback_aux;
+
buffer_t buf; /* this is BIG, so put it last */
} imap_store_t;
@@ -138,7 +148,6 @@ 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 */
@@ -149,6 +158,36 @@ struct imap_cmd {
} param;
};
+struct imap_cmd_simple {
+ struct imap_cmd gen;
+ void (*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_out_uid {
+ struct imap_cmd gen;
+ void (*callback)( int sts, int uid, void *aux );
+ void *callback_aux;
+ int out_uid;
+};
+
+struct imap_cmd_refcounted_state {
+ void (*callback)( int sts, void *aux );
+ void *callback_aux;
+ int ref_count;
+ int ret_val;
+};
+
+struct imap_cmd_refcounted {
+ struct imap_cmd gen;
+ struct imap_cmd_refcounted_state *state;
+};
+
#define CAP(cap) (ctx->caps & (1 << (cap)))
enum CAPABILITY {
@@ -173,11 +212,12 @@ static const char *cap_list[] = {
#endif
};
-#define RESP_OK 0
-#define RESP_NO 1
-#define RESP_BAD 2
+#define RESP_OK 0
+#define RESP_NO 1
+#define RESP_BAD 2
+#define RESP_CANCEL 3
-static int get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd );
+static void get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd );
static const char *Flags[] = {
@@ -487,14 +527,31 @@ buffer_gets( buffer_t * b, char **s )
/* not reached */
}
+static void
+deref_store( imap_store_t *ctx )
+{
+ if (!--ctx->ref_count)
+ free( ctx );
+}
+
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 )
@@ -503,11 +560,24 @@ v_submit_imap_cmd( imap_store_t *ctx, struct imap_cmd
*cmd,
const char *buffmt;
char buf[1024];
- while (ctx->literal_pending)
+ assert( ctx );
+ assert( cmd );
+ assert( cmd->param.done );
+
+ ctx->ref_count++;
+
+ 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 );
+ goto bail2;
+ }
+ }
+
+ if (ctx->buf.sock.fd < 0)
+ goto bail; /* We got disconnected and had no chance to report
it yet. */
- if (!cmd)
- cmd = new_imap_cmd();
cmd->tag = ++ctx->nexttag;
if (fmt)
nfvasprintf( &cmd->cmd, fmt, ap );
@@ -552,8 +622,11 @@ v_submit_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd,
return cmd;
bail:
+ cmd->param.done( ctx, cmd, RESP_BAD );
+ bail2:
free( cmd->cmd );
free( cmd );
+ deref_store( ctx );
return NULL;
}
@@ -569,54 +642,72 @@ 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_exec( 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;
+ if (!cmdp)
+ cmdp = new_imap_cmd( sizeof(*cmdp) );
+ 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;
- return get_cmd_result( ctx, cmdp );
+ get_cmd_result( ctx, cmdp );
}
-static int
-imap_exec_b( imap_store_t *ctx, struct imap_cmd *cmdp, const char *fmt, ... )
+static void
+transform_box_response( int *response )
{
- va_list ap;
+ 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;
+ }
+}
- va_start( ap, fmt );
- cmdp = v_submit_imap_cmd( ctx, cmdp, fmt, ap );
- va_end( ap );
- if (!cmdp)
- return DRV_STORE_BAD;
+static void
+imap_done_simple_box( imap_store_t *ctx ATTR_UNUSED,
+ struct imap_cmd *cmd, int response )
+{
+ struct imap_cmd_simple *cmdp = (struct imap_cmd_simple *)cmd;
- switch (get_cmd_result( ctx, cmdp )) {
- case RESP_BAD: return DRV_STORE_BAD;
- case RESP_NO: return DRV_BOX_BAD;
- default: return DRV_OK;
+ transform_box_response( &response );
+ cmdp->callback( response, cmdp->callback_aux );
+}
+
+static void
+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;
}
}
-static int
-imap_exec_m( imap_store_t *ctx, struct imap_cmd *cmdp, const char *fmt, ... )
+static void
+imap_done_simple_msg( 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_msg_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
+imap_refcounted_done( struct imap_cmd_refcounted_state *sts )
+{
+ sts->callback( sts->ret_val, sts->callback_aux );
+ free( sts );
}
/*
@@ -628,12 +719,16 @@ drain_imap_replies( imap_store_t *ctx )
}
*/
+/* call with a ref on ctx! */
static void
process_imap_replies( imap_store_t *ctx )
{
while (ctx->num_in_progress > max_in_progress ||
- socket_pending( &ctx->buf.sock ))
+ socket_pending( &ctx->buf.sock )) {
get_cmd_result( ctx, 0 );
+ if (ctx->store_canceled)
+ break;
+ }
}
static int
@@ -861,7 +956,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)
@@ -929,10 +1024,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_out_uid *)cmd)->out_uid = atoi( arg )))
{
error( "IMAP error: malformed APPENDUID status\n" );
return RESP_BAD;
@@ -964,7 +1060,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_out_uid *)cmdp)->out_uid = uid;
return;
}
error( "IMAP error: unexpected SEARCH response (UID %u)\n", uid );
@@ -996,23 +1092,27 @@ parse_list_rsp( imap_store_t *ctx, char *cmd )
add_string_list( &ctx->gen.boxes, arg );
}
-static int
+struct imap_cmd_trycreate {
+ struct imap_cmd gen;
+ struct imap_cmd *orig_cmd;
+};
+
+static void get_cmd_result_p2( imap_store_t *, struct imap_cmd *, int );
+
+static void
get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd )
{
struct imap_cmd *cmdp, **pcmdp;
char *cmd, *arg, *arg1, *p;
int n, resp, resp2, tag;
- for (;;) {
- if (buffer_gets( &ctx->buf, &cmd ))
- return RESP_BAD;
-
+ while (!buffer_gets( &ctx->buf, &cmd )) {
arg = next_arg( &cmd );
if (*arg == '*') {
arg = next_arg( &cmd );
if (!arg) {
error( "IMAP error: unable to parse untagged
response\n" );
- return RESP_BAD;
+ break;
}
if (!strcmp( "NAMESPACE", arg )) {
@@ -1035,15 +1135,15 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd
*tcmd )
ctx->gen.recent = atoi( arg );
else if(!strcmp ( "FETCH", arg1 )) {
if (parse_fetch( ctx, cmd ))
- return RESP_BAD;
+ break; /* stream is likely to
be useless now */
}
} else {
- error( "IMAP error: unable to parse untagged
response\n" );
- return RESP_BAD;
+ error( "IMAP error: unrecognized untagged
response '%s'\n", arg );
+ break; /* this may mean anything, so prefer not
to spam the log */
}
} else if (!ctx->in_progress) {
error( "IMAP error: unexpected reply: %s %s\n", arg,
cmd ? cmd : "" );
- return RESP_BAD;
+ break; /* this may mean anything, so prefer not to spam
the log */
} else if (*arg == '+') {
/* This can happen only with the last command underway,
as
it enforces a round-trip. */
@@ -1056,27 +1156,27 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd
*tcmd )
free( cmdp->param.data );
cmdp->param.data = 0;
if (n != (int)cmdp->param.data_len)
- return RESP_BAD;
+ break;
} else if (cmdp->param.cont) {
if (cmdp->param.cont( ctx, cmdp, cmd ))
- return RESP_BAD;
+ break;
} else {
error( "IMAP error: unexpected command
continuation request\n" );
- return RESP_BAD;
+ break;
}
if (socket_write( &ctx->buf.sock, "\r\n", 2 ) != 2)
- return RESP_BAD;
+ break;
if (!cmdp->param.cont)
ctx->literal_pending = 0;
if (!tcmd)
- return DRV_OK;
+ return;
} else {
tag = atoi( arg );
for (pcmdp = &ctx->in_progress; (cmdp = *pcmdp); pcmdp
= &cmdp->next)
if (cmdp->tag == tag)
goto gottag;
error( "IMAP error: unexpected tag %s\n", arg );
- return RESP_BAD;
+ break;
gottag:
if (!(*pcmdp = cmdp->next))
ctx->in_progress_append = pcmdp;
@@ -1087,24 +1187,25 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd
*tcmd )
if (!strcmp( "OK", arg )) {
if (cmdp->param.to_trash)
ctx->trashnc = 0; /* Can't get NO
[TRYCREATE] any more. */
- resp = DRV_OK;
+ resp = RESP_OK;
} else {
if (!strcmp( "NO", arg )) {
- if (cmdp->param.create && cmd &&
(cmdp->param.trycreate || !memcmp( cmd, "[TRYCREATE]", 11 ))) { /* SELECT,
APPEND or UID COPY */
+ if (cmdp->param.create &&
+ (cmdp->param.trycreate ||
+ (cmd && !memcmp( cmd,
"[TRYCREATE]", 11 ))))
+ { /* SELECT, APPEND or UID COPY */
+ struct imap_cmd_trycreate *cmd2
=
+ (struct
imap_cmd_trycreate *)new_imap_cmd( sizeof(*cmd2) );
+ cmd2->orig_cmd = cmdp;
+ cmd2->gen.param.done =
get_cmd_result_p2;
+ ctx->ref_count++;
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. */
- cmdp->param.create = 0;
- if (!submit_imap_cmd( ctx,
cmdp, 0 )) {
- resp = RESP_BAD;
- goto normal;
- }
+ submit_imap_cmd( ctx,
&cmd2->gen, "CREATE %.*s", strchr( p + 1, '"' ) - p + 1, p );
+ if (ctx->store_canceled)
+ tcmd = 0;
+ deref_store( ctx );
if (!tcmd)
- return 0; /*
ignored */
+ return;
continue;
}
resp = RESP_NO;
@@ -1116,17 +1217,52 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd
*tcmd )
}
if ((resp2 = parse_response_code( ctx, cmdp, cmd )) >
resp)
resp = resp2;
- normal:
- if (cmdp->param.done)
- cmdp->param.done( ctx, cmdp, resp );
+ cmdp->param.done( ctx, cmdp, resp );
free( cmdp->param.data );
free( cmdp->cmd );
free( cmdp );
+ if (ctx->store_canceled)
+ tcmd = 0;
+ deref_store( ctx );
if (!tcmd || tcmd == cmdp)
- return resp;
+ return;
}
}
- /* not reached */
+ /* 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;
+ }
+}
+
+static void
+get_cmd_result_p2( imap_store_t *ctx, struct imap_cmd *cmd, int response )
+{
+ struct imap_cmd_trycreate *cmdp = (struct imap_cmd_trycreate *)cmd;
+ struct imap_cmd *ocmd = cmdp->orig_cmd;
+
+ if (response != RESP_OK) {
+ ocmd->param.done( ctx, ocmd, response );
+ free( ocmd->param.data );
+ free( ocmd->cmd );
+ free( ocmd );
+ deref_store( ctx );
+ } else {
+ ctx->uidnext = 0;
+ ocmd->param.create = 0;
+ submit_imap_cmd( ctx, ocmd, 0 );
+ }
}
static void
@@ -1151,7 +1287,8 @@ imap_cancel_store( store_t *gctx )
free_list( ctx->ns_personal );
free_list( ctx->ns_other );
free_list( ctx->ns_shared );
- free( ctx );
+ ctx->store_canceled = 1;
+ deref_store( ctx );
}
static store_t *unowned;
@@ -1178,6 +1315,8 @@ imap_own_store( store_conf_t *conf )
return 0;
}
+static void imap_cleanup_p2( imap_store_t *, struct imap_cmd *, int );
+
static void
imap_cleanup( void )
{
@@ -1185,11 +1324,17 @@ imap_cleanup( void )
for (ctx = unowned; ctx; ctx = nctx) {
nctx = ctx->next;
- imap_exec( (imap_store_t *)ctx, 0, "LOGOUT" );
- imap_cancel_store( ctx );
+ imap_exec( (imap_store_t *)ctx, 0, imap_cleanup_p2, "LOGOUT" );
}
}
+static void
+imap_cleanup_p2( imap_store_t *ctx,
+ struct imap_cmd *cmd ATTR_UNUSED, int response ATTR_UNUSED )
+{
+ imap_cancel_store( &ctx->gen );
+}
+
#ifdef HAVE_LIBSSL
static int
start_tls( imap_store_t *ctx )
@@ -1298,6 +1443,19 @@ do_cram_auth( imap_store_t *ctx, struct imap_cmd *cmdp,
const char *prompt )
}
#endif
+static void imap_open_store_p2( imap_store_t *, struct imap_cmd *, int );
+static void imap_open_store_authenticate( imap_store_t * );
+static void imap_open_store_authenticate_p2( imap_store_t *, struct imap_cmd
*, int );
+static void imap_open_store_authenticate_p3( imap_store_t *, struct imap_cmd
*, int );
+static void imap_open_store_authenticate2( imap_store_t * );
+static void imap_open_store_authenticate2_p2( imap_store_t *, struct imap_cmd
*, int );
+static void imap_open_store_namespace( imap_store_t * );
+static void imap_open_store_namespace_p2( imap_store_t *, struct imap_cmd *,
int );
+static void imap_open_store_namespace2( imap_store_t * );
+static void imap_open_store_finalize( imap_store_t * );
+static void imap_open_store_ssl_bail( imap_store_t * );
+static void imap_open_store_bail( imap_store_t * );
+
static void
imap_open_store( store_conf_t *conf,
void (*cb)( store_t *srv, void *aux ), void *aux )
@@ -1309,7 +1467,7 @@ imap_open_store( store_conf_t *conf,
char *arg, *rsp;
struct hostent *he;
struct sockaddr_in addr;
- int s, a[2], preauth;
+ int s, a[2];
for (ctxp = &unowned; (ctx = (imap_store_t *)*ctxp); ctxp =
&ctx->gen.next)
if (((imap_store_conf_t *)ctx->gen.conf)->server == srvc) {
@@ -1320,12 +1478,18 @@ imap_open_store( store_conf_t *conf,
ctx->gen.boxes = 0;
ctx->gen.listed = 0;
ctx->gen.conf = conf;
- goto final;
+ ctx->callbacks.imap_open = cb;
+ ctx->callback_aux = aux;
+ imap_open_store_namespace( ctx );
+ return;
}
ctx = nfcalloc( sizeof(*ctx) );
+ ctx->ref_count = 1;
ctx->gen.conf = conf;
ctx->buf.sock.fd = -1;
+ ctx->callbacks.imap_open = cb;
+ ctx->callback_aux = aux;
ctx->in_progress_append = &ctx->in_progress;
/* open connection to IMAP server */
@@ -1389,8 +1553,10 @@ imap_open_store( store_conf_t *conf,
#if HAVE_LIBSSL
if (srvc->use_imaps) {
- if (start_tls( ctx ))
- goto ssl_bail;
+ if (start_tls( ctx )) {
+ imap_open_store_ssl_bail( ctx );
+ return;
+ }
}
#endif
@@ -1402,121 +1568,217 @@ imap_open_store( store_conf_t *conf,
error( "IMAP error: invalid greeting response\n" );
goto bail;
}
- preauth = 0;
if (!strcmp( "PREAUTH", arg ))
- preauth = 1;
+ ctx->preauth = 1;
else if (strcmp( "OK", arg ) != 0) {
error( "IMAP error: unknown greeting response\n" );
goto bail;
}
parse_response_code( ctx, 0, rsp );
- if (!ctx->caps && imap_exec( ctx, 0, "CAPABILITY" ) != RESP_OK)
- goto bail;
+ if (!ctx->caps)
+ imap_exec( ctx, 0, imap_open_store_p2, "CAPABILITY" );
+ else
+ imap_open_store_authenticate( ctx );
+ return;
+
+ bail:
+ imap_open_store_bail( ctx );
+}
- if (!preauth) {
+static void
+imap_open_store_p2( imap_store_t *ctx, struct imap_cmd *cmd ATTR_UNUSED, int
response )
+{
+ if (response != RESP_OK)
+ imap_open_store_bail( ctx );
+ else
+ imap_open_store_authenticate( ctx );
+}
+
+static void
+imap_open_store_authenticate( imap_store_t *ctx )
+{
+ if (!ctx->preauth) {
#if HAVE_LIBSSL
+ imap_store_conf_t *cfg = (imap_store_conf_t *)ctx->gen.conf;
+ imap_server_conf_t *srvc = cfg->server;
+
if (!srvc->use_imaps && (srvc->use_sslv2 || srvc->use_sslv3 ||
srvc->use_tlsv1)) {
/* always try to select SSL support if available */
if (CAP(STARTTLS)) {
- if (imap_exec( ctx, 0, "STARTTLS" ) != RESP_OK)
- goto bail;
- if (start_tls( ctx ))
- goto ssl_bail;
-
- if (imap_exec( ctx, 0, "CAPABILITY" ) !=
RESP_OK)
- goto bail;
+ imap_exec( ctx, 0,
imap_open_store_authenticate_p2, "STARTTLS" );
+ return;
} else {
if (srvc->require_ssl) {
error( "IMAP error: SSL support not
available\n" );
- goto bail;
- } else
+ imap_open_store_bail( ctx );
+ return;
+ } else {
warn( "IMAP warning: SSL support not
available\n" );
+ }
}
}
#endif
+ imap_open_store_authenticate2( ctx );
+ } else {
+ imap_open_store_namespace( ctx );
+ }
+}
- info ("Logging in...\n");
- if (!srvc->user) {
- error( "Skipping account %s, no user\n", srvc->name );
- goto bail;
+#if HAVE_LIBSSL
+static void
+imap_open_store_authenticate_p2( imap_store_t *ctx, struct imap_cmd *cmd
ATTR_UNUSED, int response )
+{
+ if (response != RESP_OK)
+ imap_open_store_bail( ctx );
+ else if (start_tls( ctx ))
+ imap_open_store_ssl_bail( ctx );
+ else
+ imap_exec( ctx, 0, imap_open_store_authenticate_p3,
"CAPABILITY" );
+}
+
+static void
+imap_open_store_authenticate_p3( imap_store_t *ctx, struct imap_cmd *cmd
ATTR_UNUSED, int response )
+{
+ if (response != RESP_OK)
+ imap_open_store_bail( ctx );
+ else
+ imap_open_store_authenticate2( ctx );
+}
+#endif
+
+static void
+imap_open_store_authenticate2( imap_store_t *ctx )
+{
+ imap_store_conf_t *cfg = (imap_store_conf_t *)ctx->gen.conf;
+ imap_server_conf_t *srvc = cfg->server;
+ char *arg;
+
+ info ("Logging in...\n");
+ if (!srvc->user) {
+ error( "Skipping account %s, no user\n", srvc->name );
+ goto bail;
+ }
+ if (!srvc->pass) {
+ char prompt[80];
+ sprintf( prompt, "Password (%s): ", srvc->name );
+ arg = getpass( prompt );
+ if (!arg) {
+ perror( "getpass" );
+ exit( 1 );
}
- if (!srvc->pass) {
- char prompt[80];
- sprintf( prompt, "Password (%s): ", srvc->name );
- arg = getpass( prompt );
- if (!arg) {
- perror( "getpass" );
- exit( 1 );
- }
- if (!*arg) {
- error( "Skipping account %s, no password\n",
srvc->name );
- goto bail;
- }
- /*
- * getpass() returns a pointer to a static buffer.
make a copy
- * for long term storage.
- */
- srvc->pass = nfstrdup( arg );
+ if (!*arg) {
+ error( "Skipping account %s, no password\n", srvc->name
);
+ goto bail;
}
+ /*
+ * getpass() returns a pointer to a static buffer. make a copy
+ * for long term storage.
+ */
+ srvc->pass = nfstrdup( arg );
+ }
#if HAVE_LIBSSL
- if (CAP(CRAM)) {
- struct imap_cmd *cmd = new_imap_cmd();
+ if (CAP(CRAM)) {
+ struct imap_cmd *cmd = new_imap_cmd( sizeof(*cmd) );
- info( "Authenticating with CRAM-MD5\n" );
- cmd->param.cont = do_cram_auth;
- if (imap_exec( ctx, cmd, "AUTHENTICATE CRAM-MD5" ) !=
RESP_OK)
- goto bail;
- } else if (srvc->require_cram) {
- error( "IMAP error: CRAM-MD5 authentication is not
supported by server\n" );
- goto bail;
- } else
+ info( "Authenticating with CRAM-MD5\n" );
+ cmd->param.cont = do_cram_auth;
+ imap_exec( ctx, cmd, imap_open_store_authenticate2_p2,
"AUTHENTICATE CRAM-MD5" );
+ return;
+ }
+ if (srvc->require_cram) {
+ error( "IMAP error: CRAM-MD5 authentication is not supported by
server\n" );
+ goto bail;
+ }
#endif
- {
- if (CAP(NOLOGIN)) {
- error( "Skipping account %s, server forbids
LOGIN\n", srvc->name );
- goto bail;
- }
+ if (CAP(NOLOGIN)) {
+ error( "Skipping account %s, server forbids LOGIN\n",
srvc->name );
+ goto bail;
+ }
#if HAVE_LIBSSL
- if (!ctx->buf.sock.use_ssl)
+ if (!ctx->buf.sock.use_ssl)
#endif
- warn( "*** IMAP Warning *** Password is being
sent in the clear\n" );
- if (imap_exec( ctx, 0, "LOGIN \"%s\" \"%s\"",
srvc->user, srvc->pass ) != RESP_OK) {
- error( "IMAP error: LOGIN failed\n" );
- goto bail;
- }
- }
- } /* !preauth */
+ warn( "*** IMAP Warning *** Password is being sent in the
clear\n" );
+ imap_exec( ctx, 0, imap_open_store_authenticate2_p2,
+ "LOGIN \"%s\" \"%s\"", srvc->user, srvc->pass );
+ return;
+
+ bail:
+ imap_open_store_bail( ctx );
+}
+
+static void
+imap_open_store_authenticate2_p2( imap_store_t *ctx, struct imap_cmd *cmd
ATTR_UNUSED, int response )
+{
+ if (response != RESP_OK)
+ imap_open_store_bail( ctx );
+ else
+ imap_open_store_namespace( ctx );
+}
+
+static void
+imap_open_store_namespace( imap_store_t *ctx )
+{
+ imap_store_conf_t *cfg = (imap_store_conf_t *)ctx->gen.conf;
- final:
ctx->prefix = "";
- if (*conf->path)
- ctx->prefix = conf->path;
+ if (*cfg->gen.path)
+ ctx->prefix = cfg->gen.path;
else if (cfg->use_namespace && CAP(NAMESPACE)) {
/* get NAMESPACE info */
- if (!ctx->got_namespace) {
- if (imap_exec( ctx, 0, "NAMESPACE" ) != RESP_OK) {
- cb( 0, aux );
- return;
- }
- ctx->got_namespace = 1;
- }
- /* XXX for now assume personal namespace */
- if (is_list( ctx->ns_personal ) &&
- is_list( ctx->ns_personal->child ) &&
- is_atom( ctx->ns_personal->child->child ))
- ctx->prefix = ctx->ns_personal->child->child->val;
+ if (!ctx->got_namespace)
+ imap_exec( ctx, 0, imap_open_store_namespace_p2,
"NAMESPACE" );
+ else
+ imap_open_store_namespace2( ctx );
+ return;
}
+ imap_open_store_finalize( ctx );
+}
+
+static void
+imap_open_store_namespace_p2( imap_store_t *ctx, struct imap_cmd *cmd
ATTR_UNUSED, int response )
+{
+ if (response != RESP_OK) {
+ imap_open_store_bail( ctx );
+ } else {
+ ctx->got_namespace = 1;
+ imap_open_store_namespace2( ctx );
+ }
+}
+
+static void
+imap_open_store_namespace2( imap_store_t *ctx )
+{
+ /* XXX for now assume personal namespace */
+ if (is_list( ctx->ns_personal ) &&
+ is_list( ctx->ns_personal->child ) &&
+ is_atom( ctx->ns_personal->child->child ))
+ ctx->prefix = ctx->ns_personal->child->child->val;
+ imap_open_store_finalize( ctx );
+}
+
+static void
+imap_open_store_finalize( imap_store_t *ctx )
+{
ctx->trashnc = 1;
- cb( &ctx->gen, aux );
- return;
+ ctx->callbacks.imap_open( &ctx->gen, ctx->callback_aux );
+}
#if HAVE_LIBSSL
- ssl_bail:
+static void
+imap_open_store_ssl_bail( imap_store_t *ctx )
+{
/* This avoids that we try to send LOGOUT to an unusable socket. */
close( ctx->buf.sock.fd );
ctx->buf.sock.fd = -1;
+ imap_open_store_bail( ctx );
+}
#endif
- bail:
+
+static void
+imap_open_store_bail( imap_store_t *ctx )
+{
+ void (*cb)( store_t *srv, void *aux ) = ctx->callbacks.imap_open;
+ void *aux = ctx->callback_aux;
imap_cancel_store( &ctx->gen );
cb( 0, aux );
}
@@ -1534,16 +1796,23 @@ imap_prepare_opts( store_t *gctx, int opts )
gctx->opts = opts;
}
+struct imap_cmd_select {
+ struct imap_cmd_simple gen;
+ int minuid, maxuid, *excs, nexcs;
+};
+
+static void imap_select_p2( imap_store_t *, struct imap_cmd *, int );
+static void imap_submit_select2( imap_store_t *, const char *, struct
imap_cmd_refcounted_state *,
+ struct imap_cmd_refcounted ** );
+static void imap_select2_p2( imap_store_t *, struct imap_cmd *, int );
+
static void
imap_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs,
void (*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" )) {
prefix = "";
@@ -1553,56 +1822,130 @@ imap_select( store_t *gctx, int minuid, int maxuid,
int *excs, int nexcs,
ctx->uidnext = -1;
- 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;
+ 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_exec( ctx, &cmd->gen.gen, imap_select_p2,
+ "SELECT \"%s%s\"", prefix, gctx->name );
+}
- if (gctx->count) {
- ctx->msgapp = &gctx->msgs;
- sort_ints( excs, nexcs );
- for (i = 0; i < nexcs; ) {
- for (bl = 0; i < nexcs && bl < 960; i++) {
+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];
+
+ transform_box_response( &response );
+ if (response != DRV_OK || !ctx->gen.count) {
+ free( cmdp->excs );
+ cmdp->gen.callback( response, cmdp->gen.callback_aux );
+ } else {
+ struct imap_cmd_refcounted *cmd2 = 0;
+ struct imap_cmd_refcounted_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->ref_count++;
+
+ 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", excs[i] );
+ bl += sprintf( buf + bl, "%d", cmdp->excs[i] );
j = i;
- for (; i + 1 < nexcs && excs[i + 1] == excs[i]
+ 1; i++);
+ for (; i + 1 < cmdp->nexcs && cmdp->excs[i + 1]
== cmdp->excs[i] + 1; i++);
if (i != j)
- bl += sprintf( buf + bl, ":%d", excs[i]
);
+ bl += sprintf( buf + bl, ":%d",
cmdp->excs[i] );
+ }
+ imap_submit_select2( ctx, buf, sts, &cmd2 );
+ if (ctx->store_canceled) {
+ deref_store( ctx );
+ free( cmdp->excs );
+ return;
}
- 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 >= 0 ? 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;
+ if (cmdp->maxuid == INT_MAX)
+ cmdp->maxuid = ctx->uidnext >= 0 ? ctx->uidnext - 1 :
1000000000;
+ if (cmdp->maxuid >= cmdp->minuid) {
+ sprintf( buf, "%d:%d", cmdp->minuid, cmdp->maxuid );
+ imap_submit_select2( ctx, buf, sts, &cmd2 );
+ if (ctx->store_canceled) {
+ deref_store( ctx );
+ free( cmdp->excs );
+ return;
+ }
+ }
+ deref_store( ctx );
+ free( cmdp->excs );
+ if (!--sts->ref_count)
+ imap_refcounted_done( sts );
+ else
+ get_cmd_result( ctx, &cmd2->gen );
}
+}
+
+static void
+imap_submit_select2( imap_store_t *ctx, const char *buf, struct
imap_cmd_refcounted_state *sts,
+ struct imap_cmd_refcounted **cmdp )
+{
+ struct imap_cmd_refcounted *cmd = (struct imap_cmd_refcounted
*)new_imap_cmd( sizeof(*cmd) );
+ cmd->gen.param.done = imap_select2_p2;
+ cmd->state = sts;
+ sts->ref_count++;
+ *cmdp = cmd;
+ submit_imap_cmd( ctx, &cmd->gen,
+ "UID FETCH %s (UID%s%s)", buf,
+ (ctx->gen.opts & OPEN_FLAGS) ? " FLAGS" : "",
+ (ctx->gen.opts & OPEN_SIZE) ? " RFC822.SIZE" : "" );
+}
- ret = DRV_OK;
+static void
+imap_select2_p2( imap_store_t *ctx ATTR_UNUSED, struct imap_cmd *cmd, int
response )
+{
+ struct imap_cmd_refcounted_state *sts = ((struct imap_cmd_refcounted
*)cmd)->state;
- bail:
- free( excs );
- cb( ret, aux );
+ 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;
+ case RESP_NO:
+ sts->ret_val = DRV_BOX_BAD;
+ break;
+ }
+ if (!--sts->ref_count)
+ imap_refcounted_done( sts );
}
static void
imap_fetch_msg( store_t *ctx, message_t *msg, msg_data_t *data,
void (*cb)( int sts, void *aux ), void *aux )
{
- struct imap_cmd *cmd = new_imap_cmd();
- cmd->param.uid = msg->uid;
- cmd->param.aux = data;
- 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_exec( (imap_store_t *)ctx, &cmd->gen.gen, imap_done_simple_msg,
+ "UID FETCH %d (%sBODY.PEEK[])",
+ msg->uid, (msg->status & M_FLAGS) ? "" : "FLAGS " );
}
+static void imap_set_flags_p2( imap_store_t *, struct imap_cmd *, int );
+
static int
imap_make_flags( int flags, char *buf )
{
@@ -1622,15 +1965,18 @@ imap_make_flags( int flags, char *buf )
}
static int
-imap_flags_helper( imap_store_t *ctx, int uid, char what, int flags)
+imap_flags_helper( imap_store_t *ctx, int uid, char what, int flags,
+ struct imap_cmd_refcounted_state *sts )
{
char buf[256];
+ struct imap_cmd_refcounted *cmd = (struct imap_cmd_refcounted
*)new_imap_cmd( sizeof(*cmd) );
+ cmd->gen.param.done = imap_set_flags_p2;
+ cmd->state = sts;
+ sts->ref_count++;
buf[imap_make_flags( flags, buf )] = 0;
- if (!submit_imap_cmd( ctx, 0, "UID STORE %d %cFLAGS.SILENT %s", uid,
what, buf ))
- return DRV_STORE_BAD;
- process_imap_replies( ctx );
- return DRV_OK;
+ submit_imap_cmd( ctx, &cmd->gen, "UID STORE %d %cFLAGS.SILENT %s", uid,
what, buf );
+ return ctx->store_canceled;
}
static void
@@ -1638,7 +1984,6 @@ imap_set_flags( store_t *gctx, message_t *msg, int uid,
int add, int del,
void (*cb)( int sts, void *aux ), void *aux )
{
imap_store_t *ctx = (imap_store_t *)gctx;
- int ret;
if (msg) {
uid = msg->uid;
@@ -1647,17 +1992,66 @@ imap_set_flags( store_t *gctx, message_t *msg, int uid,
int add, int del,
msg->flags |= add;
msg->flags &= ~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;
- cb( ret, aux );
+
+ if (add || del) {
+ struct imap_cmd_refcounted_state *sts = nfmalloc( sizeof(*sts)
);
+ sts->callback = cb;
+ sts->callback_aux = aux;
+ sts->ref_count = 1; /* so forced sync does not cause an early
exit */
+ sts->ret_val = DRV_OK;
+ ctx->ref_count++;
+ if ((add && imap_flags_helper( ctx, uid, '+', add, sts )) ||
+ (del && imap_flags_helper( ctx, uid, '-', del, sts )))
+ {
+ deref_store( ctx );
+ if (!--sts->ref_count)
+ free( sts );
+ return;
+ }
+ if (!--sts->ref_count)
+ imap_refcounted_done( sts );
+ else
+ process_imap_replies( ctx );
+ deref_store( ctx );
+ } else {
+ cb( DRV_OK, aux );
+ }
+}
+
+static void
+imap_set_flags_p2( imap_store_t *ctx ATTR_UNUSED, struct imap_cmd *cmd, int
response )
+{
+ 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. */
+ 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;
+ break;
+ }
+ if (!--sts->ref_count)
+ imap_refcounted_done( sts );
}
static void
imap_close( store_t *ctx,
void (*cb)( int sts, void *aux ), void *aux )
{
- 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_exec( (imap_store_t *)ctx, &cmd->gen, imap_done_simple_box,
"CLOSE" );
}
static void
@@ -1665,21 +2059,26 @@ imap_trash_msg( store_t *gctx, message_t *msg,
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;
- 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;
+ cmd->gen.param.to_trash = 1;
+ imap_exec( ctx, &cmd->gen, imap_done_simple_msg,
+ "UID COPY %d \"%s%s\"",
+ msg->uid, ctx->prefix, gctx->conf->trash );
}
+static void imap_store_msg_p2( imap_store_t *, struct imap_cmd *, int );
+
static void
imap_store_msg( store_t *gctx, msg_data_t *data, int to_trash,
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();
+ struct imap_cmd_out_uid *cmd;
const char *prefix, *box;
- int ret, d, uid;
+ int d;
char flagstr[128];
d = 0;
@@ -1689,53 +2088,91 @@ 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_out_uid, 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;
- cmd->param.to_trash = 1;
+ cmd->gen.param.create = 1;
+ cmd->gen.param.to_trash = 1;
} else {
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)
- uid = -1;
- cb( ret, uid, aux );
+ imap_exec( ctx, &cmd->gen, imap_store_msg_p2,
+ "APPEND \"%s%s\" %s", prefix, box, flagstr );
+}
+
+static void
+imap_store_msg_p2( imap_store_t *ctx ATTR_UNUSED, struct imap_cmd *cmd, int
response )
+{
+ struct imap_cmd_out_uid *cmdp = (struct imap_cmd_out_uid *)cmd;
+
+ transform_msg_response( &response );
+ cmdp->callback( response, cmdp->out_uid, cmdp->callback_aux );
}
+static void imap_find_msg_p2( imap_store_t *, struct imap_cmd *, int );
+
static void
imap_find_msg( store_t *gctx, const char *tuid,
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();
- 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)
- cb( ret, -1, aux );
+ struct imap_cmd_out_uid *cmd;
+
+ INIT_IMAP_CMD(imap_cmd_out_uid, 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_exec( ctx, &cmd->gen, imap_find_msg_p2,
+ "UID SEARCH HEADER X-TUID %." stringify(TUIDL) "s", tuid );
+}
+
+static void
+imap_find_msg_p2( imap_store_t *ctx ATTR_UNUSED, struct imap_cmd *cmd, int
response )
+{
+ struct imap_cmd_out_uid *cmdp = (struct imap_cmd_out_uid *)cmd;
+
+ transform_msg_response( &response );
+ if (response != DRV_OK)
+ cmdp->callback( response, -1, cmdp->callback_aux );
else
- cb( uid <= 0 ? DRV_MSG_BAD : DRV_OK, uid, aux );
+ cmdp->callback( cmdp->out_uid <= 0 ? DRV_MSG_BAD : DRV_OK,
+ cmdp->out_uid, cmdp->callback_aux );
}
+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 *, struct imap_cmd *, int );
+
static void
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;
+
+ INIT_IMAP_CMD(imap_cmd_list, cmd, cb, aux)
+ imap_exec( ctx, &cmd->gen, imap_list_p2,
+ "LIST \"\" \"%s%%\"", ctx->prefix );
+}
+
+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;
- if ((ret = imap_exec_b( ctx, 0, "LIST \"\" \"%s%%\"", ctx->prefix )) ==
DRV_OK)
- gctx->listed = 1;
- cb( ret, aux );
+ transform_box_response( &response );
+ if (response == DRV_OK)
+ ctx->gen.listed = 1;
+ cmdp->callback( response, cmdp->callback_aux );
}
static void
------------------------------------------------------------------------------
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
[email protected]
https://lists.sourceforge.net/lists/listinfo/isync-devel