|
|
|
@ -267,7 +267,7 @@ done_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd, int response )
|
|
|
|
|
free( cmd ); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int |
|
|
|
|
static void |
|
|
|
|
send_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd ) |
|
|
|
|
{ |
|
|
|
|
int bufl, litplus, iovcnt = 1; |
|
|
|
@ -313,8 +313,7 @@ send_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd )
|
|
|
|
|
iov[2].takeOwn = KeepOwn; |
|
|
|
|
iovcnt = 3; |
|
|
|
|
} |
|
|
|
|
if (socket_write( &ctx->conn, iov, iovcnt ) < 0) |
|
|
|
|
goto bail; |
|
|
|
|
socket_write( &ctx->conn, iov, iovcnt ); |
|
|
|
|
if (cmd->param.to_trash && ctx->trashnc == TrashUnknown) |
|
|
|
|
ctx->trashnc = TrashChecking; |
|
|
|
|
cmd->next = 0; |
|
|
|
@ -322,15 +321,10 @@ send_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd )
|
|
|
|
|
ctx->in_progress_append = &cmd->next; |
|
|
|
|
ctx->num_in_progress++; |
|
|
|
|
socket_expect_read( &ctx->conn, 1 ); |
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
bail: |
|
|
|
|
done_imap_cmd( ctx, cmd, RESP_CANCEL ); |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int |
|
|
|
|
cmd_submittable( imap_store_t *ctx, struct imap_cmd *cmd ) |
|
|
|
|
cmd_sendable( imap_store_t *ctx, struct imap_cmd *cmd ) |
|
|
|
|
{ |
|
|
|
|
struct imap_cmd *cmdp; |
|
|
|
|
|
|
|
|
@ -343,18 +337,16 @@ cmd_submittable( imap_store_t *ctx, struct imap_cmd *cmd )
|
|
|
|
|
ctx->num_in_progress < ((imap_store_conf_t *)ctx->gen.conf)->server->max_in_progress; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int |
|
|
|
|
static void |
|
|
|
|
flush_imap_cmds( imap_store_t *ctx ) |
|
|
|
|
{ |
|
|
|
|
struct imap_cmd *cmd; |
|
|
|
|
|
|
|
|
|
while ((cmd = ctx->pending) && cmd_submittable( ctx, cmd )) { |
|
|
|
|
if ((cmd = ctx->pending) && cmd_sendable( ctx, cmd )) { |
|
|
|
|
if (!(ctx->pending = cmd->next)) |
|
|
|
|
ctx->pending_append = &ctx->pending; |
|
|
|
|
if (send_imap_cmd( ctx, cmd ) < 0) |
|
|
|
|
return -1; |
|
|
|
|
send_imap_cmd( ctx, cmd ); |
|
|
|
|
} |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
@ -370,7 +362,7 @@ cancel_pending_imap_cmds( imap_store_t *ctx )
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
cancel_submitted_imap_cmds( imap_store_t *ctx ) |
|
|
|
|
cancel_sent_imap_cmds( imap_store_t *ctx ) |
|
|
|
|
{ |
|
|
|
|
struct imap_cmd *cmd; |
|
|
|
|
|
|
|
|
@ -382,7 +374,7 @@ cancel_submitted_imap_cmds( imap_store_t *ctx )
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int |
|
|
|
|
static void |
|
|
|
|
submit_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd ) |
|
|
|
|
{ |
|
|
|
|
assert( ctx ); |
|
|
|
@ -390,7 +382,7 @@ submit_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd )
|
|
|
|
|
assert( cmd ); |
|
|
|
|
assert( cmd->param.done ); |
|
|
|
|
|
|
|
|
|
if ((ctx->pending && !cmd->param.high_prio) || !cmd_submittable( ctx, cmd )) { |
|
|
|
|
if ((ctx->pending && !cmd->param.high_prio) || !cmd_sendable( ctx, cmd )) { |
|
|
|
|
if (ctx->pending && cmd->param.high_prio) { |
|
|
|
|
cmd->next = ctx->pending; |
|
|
|
|
ctx->pending = cmd; |
|
|
|
@ -399,10 +391,9 @@ submit_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd )
|
|
|
|
|
*ctx->pending_append = cmd; |
|
|
|
|
ctx->pending_append = &cmd->next; |
|
|
|
|
} |
|
|
|
|
return 0; |
|
|
|
|
} else { |
|
|
|
|
send_imap_cmd( ctx, cmd ); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return send_imap_cmd( ctx, cmd ); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Minimal printf() replacement that supports an %\s format sequence to print backslash-escaped
|
|
|
|
@ -487,7 +478,7 @@ imap_vprintf( const char *fmt, va_list ap )
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int |
|
|
|
|
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, ... ) |
|
|
|
@ -500,7 +491,7 @@ imap_exec( imap_store_t *ctx, struct imap_cmd *cmdp,
|
|
|
|
|
va_start( ap, fmt ); |
|
|
|
|
cmdp->cmd = imap_vprintf( fmt, ap ); |
|
|
|
|
va_end( ap ); |
|
|
|
|
return submit_imap_cmd( ctx, cmdp ); |
|
|
|
|
submit_imap_cmd( ctx, cmdp ); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
@ -1337,8 +1328,7 @@ imap_socket_read( void *aux )
|
|
|
|
|
iov[1].buf = "\r\n"; |
|
|
|
|
iov[1].len = 2; |
|
|
|
|
iov[1].takeOwn = KeepOwn; |
|
|
|
|
if (socket_write( &ctx->conn, iov, 2 ) < 0) |
|
|
|
|
return; |
|
|
|
|
socket_write( &ctx->conn, iov, 2 ); |
|
|
|
|
} else if (cmdp->param.cont) { |
|
|
|
|
if (cmdp->param.cont( ctx, cmdp, cmd )) |
|
|
|
|
return; |
|
|
|
@ -1376,9 +1366,8 @@ imap_socket_read( void *aux )
|
|
|
|
|
cmd2->orig_cmd = cmdp; |
|
|
|
|
cmd2->gen.param.high_prio = 1; |
|
|
|
|
p = strchr( cmdp->cmd, '"' ); |
|
|
|
|
if (imap_exec( ctx, &cmd2->gen, get_cmd_result_p2, |
|
|
|
|
"CREATE %.*s", imap_strchr( p + 1, '"' ) - p + 1, p ) < 0) |
|
|
|
|
return; |
|
|
|
|
imap_exec( ctx, &cmd2->gen, get_cmd_result_p2, |
|
|
|
|
"CREATE %.*s", imap_strchr( p + 1, '"' ) - p + 1, p ); |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
resp = RESP_NO; |
|
|
|
@ -1387,7 +1376,11 @@ imap_socket_read( void *aux )
|
|
|
|
|
} else /*if (!strcmp( "BAD", arg ))*/ |
|
|
|
|
resp = RESP_CANCEL; |
|
|
|
|
error( "IMAP command '%s' returned an error: %s %s\n", |
|
|
|
|
!starts_with( cmdp->cmd, -1, "LOGIN", 5 ) ? cmdp->cmd : "LOGIN <user> <pass>", |
|
|
|
|
starts_with( cmdp->cmd, -1, "LOGIN", 5 ) ? |
|
|
|
|
"LOGIN <user> <pass>" : |
|
|
|
|
starts_with( cmdp->cmd, -1, "AUTHENTICATE PLAIN", 18 ) ? |
|
|
|
|
"AUTHENTICATE PLAIN <authdata>" : |
|
|
|
|
cmdp->cmd, |
|
|
|
|
arg, cmd ? cmd : "" ); |
|
|
|
|
} |
|
|
|
|
doresp: |
|
|
|
@ -1405,8 +1398,7 @@ imap_socket_read( void *aux )
|
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (flush_imap_cmds( ctx ) < 0) |
|
|
|
|
return; |
|
|
|
|
flush_imap_cmds( ctx ); |
|
|
|
|
} |
|
|
|
|
imap_invoke_bad_callback( ctx ); |
|
|
|
|
} |
|
|
|
@ -1440,7 +1432,7 @@ imap_cancel_store( store_t *gctx )
|
|
|
|
|
sasl_dispose( &ctx->sasl ); |
|
|
|
|
#endif |
|
|
|
|
socket_close( &ctx->conn ); |
|
|
|
|
cancel_submitted_imap_cmds( ctx ); |
|
|
|
|
cancel_sent_imap_cmds( ctx ); |
|
|
|
|
cancel_pending_imap_cmds( ctx ); |
|
|
|
|
free_generic_messages( ctx->gen.msgs ); |
|
|
|
|
free_string_list( ctx->gen.boxes ); |
|
|
|
@ -1603,7 +1595,7 @@ imap_open_store( store_conf_t *conf, const char *label,
|
|
|
|
|
|
|
|
|
|
socket_init( &ctx->conn, &srvc->sconf, |
|
|
|
|
(void (*)( void * ))imap_invoke_bad_callback, |
|
|
|
|
imap_socket_read, (int (*)(void *))flush_imap_cmds, ctx ); |
|
|
|
|
imap_socket_read, (void (*)(void *))flush_imap_cmds, ctx ); |
|
|
|
|
socket_connect( &ctx->conn, imap_open_store_connected ); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -1929,7 +1921,8 @@ do_sasl_auth( imap_store_t *ctx, struct imap_cmd *cmdp ATTR_UNUSED, const char *
|
|
|
|
|
iov[iovcnt].len = 2; |
|
|
|
|
iov[iovcnt].takeOwn = KeepOwn; |
|
|
|
|
iovcnt++; |
|
|
|
|
return socket_write( &ctx->conn, iov, iovcnt ); |
|
|
|
|
socket_write( &ctx->conn, iov, iovcnt ); |
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
bail: |
|
|
|
|
imap_open_store_bail( ctx, FAIL_FINAL ); |
|
|
|
@ -2289,7 +2282,7 @@ imap_prepare_load_box( store_t *gctx, int opts )
|
|
|
|
|
gctx->opts = opts; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int imap_submit_load( imap_store_t *, const char *, int, struct imap_cmd_refcounted_state * ); |
|
|
|
|
static void imap_submit_load( imap_store_t *, const char *, int, struct imap_cmd_refcounted_state * ); |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
imap_load_box( store_t *gctx, int minuid, int maxuid, int newuid, int *excs, int nexcs, |
|
|
|
@ -2316,16 +2309,14 @@ imap_load_box( store_t *gctx, int minuid, int maxuid, int newuid, int *excs, int
|
|
|
|
|
if (i != j) |
|
|
|
|
bl += sprintf( buf + bl, ":%d", excs[i] ); |
|
|
|
|
} |
|
|
|
|
if (imap_submit_load( ctx, buf, 0, sts ) < 0) |
|
|
|
|
goto done; |
|
|
|
|
imap_submit_load( ctx, buf, 0, sts ); |
|
|
|
|
} |
|
|
|
|
if (maxuid == INT_MAX) |
|
|
|
|
maxuid = ctx->gen.uidnext ? ctx->gen.uidnext - 1 : 1000000000; |
|
|
|
|
if (maxuid >= minuid) { |
|
|
|
|
if ((ctx->gen.opts & OPEN_FIND) && minuid < newuid) { |
|
|
|
|
sprintf( buf, "%d:%d", minuid, newuid - 1 ); |
|
|
|
|
if (imap_submit_load( ctx, buf, 0, sts ) < 0) |
|
|
|
|
goto done; |
|
|
|
|
imap_submit_load( ctx, buf, 0, sts ); |
|
|
|
|
if (newuid > maxuid) |
|
|
|
|
goto done; |
|
|
|
|
sprintf( buf, "%d:%d", newuid, maxuid ); |
|
|
|
@ -2340,14 +2331,14 @@ imap_load_box( store_t *gctx, int minuid, int maxuid, int newuid, int *excs, int
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int |
|
|
|
|
static void |
|
|
|
|
imap_submit_load( imap_store_t *ctx, const char *buf, int tuids, struct imap_cmd_refcounted_state *sts ) |
|
|
|
|
{ |
|
|
|
|
return imap_exec( ctx, imap_refcounted_new_cmd( sts ), imap_refcounted_done_box, |
|
|
|
|
"UID FETCH %s (UID%s%s%s)", buf, |
|
|
|
|
(ctx->gen.opts & OPEN_FLAGS) ? " FLAGS" : "", |
|
|
|
|
(ctx->gen.opts & OPEN_SIZE) ? " RFC822.SIZE" : "", |
|
|
|
|
tuids ? " BODY.PEEK[HEADER.FIELDS (X-TUID)]" : ""); |
|
|
|
|
imap_exec( ctx, imap_refcounted_new_cmd( sts ), imap_refcounted_done_box, |
|
|
|
|
"UID FETCH %s (UID%s%s%s)", buf, |
|
|
|
|
(ctx->gen.opts & OPEN_FLAGS) ? " FLAGS" : "", |
|
|
|
|
(ctx->gen.opts & OPEN_SIZE) ? " RFC822.SIZE" : "", |
|
|
|
|
tuids ? " BODY.PEEK[HEADER.FIELDS (X-TUID)]" : ""); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/******************* imap_fetch_msg *******************/ |
|
|
|
@ -2404,15 +2395,15 @@ imap_make_flags( int flags, char *buf )
|
|
|
|
|
return d; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int |
|
|
|
|
static void |
|
|
|
|
imap_flags_helper( imap_store_t *ctx, int uid, char what, int flags, |
|
|
|
|
struct imap_cmd_refcounted_state *sts ) |
|
|
|
|
{ |
|
|
|
|
char buf[256]; |
|
|
|
|
|
|
|
|
|
buf[imap_make_flags( flags, buf )] = 0; |
|
|
|
|
return imap_exec( ctx, imap_refcounted_new_cmd( sts ), imap_set_flags_p2, |
|
|
|
|
"UID STORE %d %cFLAGS.SILENT %s", uid, what, buf ); |
|
|
|
|
imap_exec( ctx, imap_refcounted_new_cmd( sts ), imap_set_flags_p2, |
|
|
|
|
"UID STORE %d %cFLAGS.SILENT %s", uid, what, buf ); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
@ -2430,8 +2421,10 @@ imap_set_msg_flags( store_t *gctx, message_t *msg, int uid, int add, int del,
|
|
|
|
|
} |
|
|
|
|
if (add || del) { |
|
|
|
|
struct imap_cmd_refcounted_state *sts = imap_refcounted_new_state( cb, aux ); |
|
|
|
|
if ((add && imap_flags_helper( ctx, uid, '+', add, sts ) < 0) || |
|
|
|
|
(del && imap_flags_helper( ctx, uid, '-', del, sts ) < 0)) {} |
|
|
|
|
if (add) |
|
|
|
|
imap_flags_helper( ctx, uid, '+', add, sts ); |
|
|
|
|
if (del) |
|
|
|
|
imap_flags_helper( ctx, uid, '-', del, sts ); |
|
|
|
|
imap_refcounted_done( sts ); |
|
|
|
|
} else { |
|
|
|
|
cb( DRV_OK, aux ); |
|
|
|
@ -2482,9 +2475,8 @@ imap_close_box( store_t *gctx,
|
|
|
|
|
} |
|
|
|
|
if (!bl) |
|
|
|
|
break; |
|
|
|
|
if (imap_exec( ctx, imap_refcounted_new_cmd( sts ), imap_refcounted_done_box, |
|
|
|
|
"UID EXPUNGE %s", buf ) < 0) |
|
|
|
|
break; |
|
|
|
|
imap_exec( ctx, imap_refcounted_new_cmd( sts ), imap_refcounted_done_box, |
|
|
|
|
"UID EXPUNGE %s", buf ); |
|
|
|
|
} |
|
|
|
|
imap_refcounted_done( sts ); |
|
|
|
|
} else { |
|
|
|
@ -2625,13 +2617,12 @@ imap_list_store( store_t *gctx, int flags,
|
|
|
|
|
imap_store_t *ctx = (imap_store_t *)gctx; |
|
|
|
|
struct imap_cmd_refcounted_state *sts = imap_refcounted_new_state( cb, aux ); |
|
|
|
|
|
|
|
|
|
if (((flags & LIST_PATH) && (!(flags & LIST_INBOX) || !is_inbox( ctx, ctx->prefix, -1 )) && |
|
|
|
|
imap_exec( ctx, imap_refcounted_new_cmd( sts ), imap_refcounted_done_box, |
|
|
|
|
"LIST \"\" \"%\\s*\"", ctx->prefix ) < 0) || |
|
|
|
|
((flags & LIST_INBOX) && (!(flags & LIST_PATH) || *ctx->prefix) && |
|
|
|
|
imap_exec( ctx, imap_refcounted_new_cmd( sts ), imap_refcounted_done_box, |
|
|
|
|
"LIST \"\" INBOX*" ) < 0)) |
|
|
|
|
{} |
|
|
|
|
if ((flags & LIST_PATH) && (!(flags & LIST_INBOX) || !is_inbox( ctx, ctx->prefix, -1 ))) |
|
|
|
|
imap_exec( ctx, imap_refcounted_new_cmd( sts ), imap_refcounted_done_box, |
|
|
|
|
"LIST \"\" \"%\\s*\"", ctx->prefix ); |
|
|
|
|
if ((flags & LIST_INBOX) && (!(flags & LIST_PATH) || *ctx->prefix)) |
|
|
|
|
imap_exec( ctx, imap_refcounted_new_cmd( sts ), imap_refcounted_done_box, |
|
|
|
|
"LIST \"\" INBOX*" ); |
|
|
|
|
imap_refcounted_done( sts ); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -2695,8 +2686,9 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep )
|
|
|
|
|
/* Legacy SSL options */ |
|
|
|
|
int require_ssl = -1, use_imaps = -1; |
|
|
|
|
int use_sslv2 = -1, use_sslv3 = -1, use_tlsv1 = -1, use_tlsv11 = -1, use_tlsv12 = -1; |
|
|
|
|
int require_cram = -1; |
|
|
|
|
#endif |
|
|
|
|
/* Legacy SASL option */ |
|
|
|
|
int require_cram = -1; |
|
|
|
|
|
|
|
|
|
if (!strcasecmp( "IMAPAccount", cfg->cmd )) { |
|
|
|
|
server = nfcalloc( sizeof(*server) ); |
|
|
|
@ -2829,6 +2821,7 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep )
|
|
|
|
|
use_tlsv11 = parse_bool( cfg ); |
|
|
|
|
else if (!strcasecmp( "UseTLSv1.2", cfg->cmd )) |
|
|
|
|
use_tlsv12 = parse_bool( cfg ); |
|
|
|
|
#endif |
|
|
|
|
else if (!strcasecmp( "AuthMech", cfg->cmd ) || |
|
|
|
|
!strcasecmp( "AuthMechs", cfg->cmd )) { |
|
|
|
|
arg = cfg->val; |
|
|
|
@ -2837,7 +2830,6 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep )
|
|
|
|
|
while ((arg = get_arg( cfg, ARG_OPTIONAL, 0 ))); |
|
|
|
|
} else if (!strcasecmp( "RequireCRAM", cfg->cmd )) |
|
|
|
|
require_cram = parse_bool( cfg ); |
|
|
|
|
#endif |
|
|
|
|
else if (!strcasecmp( "Tunnel", cfg->cmd )) |
|
|
|
|
server->sconf.tunnel = nfstrdup( cfg->val ); |
|
|
|
|
else if (store) { |
|
|
|
@ -2917,7 +2909,6 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep )
|
|
|
|
|
server->ssl_type = server->sconf.tunnel ? SSL_None : SSL_STARTTLS; |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
#ifdef HAVE_LIBSSL |
|
|
|
|
if (require_cram >= 0) { |
|
|
|
|
if (server->auth_mechs) { |
|
|
|
|
error( "%s '%s': The deprecated RequireCRAM option is mutually exlusive with AuthMech.\n", type, name ); |
|
|
|
@ -2928,7 +2919,6 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep )
|
|
|
|
|
if (require_cram) |
|
|
|
|
add_string_list(&server->auth_mechs, "CRAM-MD5"); |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
if (!server->auth_mechs) |
|
|
|
|
add_string_list( &server->auth_mechs, "*" ); |
|
|
|
|
if (!server->sconf.port) |
|
|
|
|