|
|
@ -126,21 +126,22 @@ typedef struct imap_store { |
|
|
|
buffer_t buf; /* this is BIG, so put it last */ |
|
|
|
buffer_t buf; /* this is BIG, so put it last */ |
|
|
|
} imap_store_t; |
|
|
|
} imap_store_t; |
|
|
|
|
|
|
|
|
|
|
|
struct imap_cmd_cb { |
|
|
|
|
|
|
|
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 *ctx; |
|
|
|
|
|
|
|
char *data; |
|
|
|
|
|
|
|
int dlen; |
|
|
|
|
|
|
|
int uid; |
|
|
|
|
|
|
|
unsigned create:1, trycreate:1; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct imap_cmd { |
|
|
|
struct imap_cmd { |
|
|
|
struct imap_cmd *next; |
|
|
|
struct imap_cmd *next; |
|
|
|
struct imap_cmd_cb cb; |
|
|
|
|
|
|
|
char *cmd; |
|
|
|
char *cmd; |
|
|
|
int tag; |
|
|
|
int tag; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 */ |
|
|
|
|
|
|
|
unsigned |
|
|
|
|
|
|
|
create:1, /* create the mailbox if we get an error ... */ |
|
|
|
|
|
|
|
trycreate:1; /* ... but only if this is true or the server says so. */ |
|
|
|
|
|
|
|
} param; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
#define CAP(cap) (ctx->caps & (1 << (cap))) |
|
|
|
#define CAP(cap) (ctx->caps & (1 << (cap))) |
|
|
@ -475,28 +476,30 @@ buffer_gets( buffer_t * b, char **s ) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static struct imap_cmd * |
|
|
|
static struct imap_cmd * |
|
|
|
v_issue_imap_cmd( imap_store_t *ctx, struct imap_cmd_cb *cb, |
|
|
|
new_imap_cmd( void ) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
struct imap_cmd *cmd = nfmalloc( sizeof(*cmd) ); |
|
|
|
|
|
|
|
memset( &cmd->param, 0, sizeof(cmd->param) ); |
|
|
|
|
|
|
|
return cmd; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static struct imap_cmd * |
|
|
|
|
|
|
|
v_submit_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd, |
|
|
|
const char *fmt, va_list ap ) |
|
|
|
const char *fmt, va_list ap ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
struct imap_cmd *cmd; |
|
|
|
|
|
|
|
int n, bufl; |
|
|
|
int n, bufl; |
|
|
|
char buf[1024]; |
|
|
|
char buf[1024]; |
|
|
|
|
|
|
|
|
|
|
|
cmd = nfmalloc( sizeof(struct imap_cmd) ); |
|
|
|
|
|
|
|
nfvasprintf( &cmd->cmd, fmt, ap ); |
|
|
|
|
|
|
|
cmd->tag = ++ctx->nexttag; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (cb) |
|
|
|
|
|
|
|
cmd->cb = *cb; |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
memset( &cmd->cb, 0, sizeof(cmd->cb) ); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (ctx->literal_pending) |
|
|
|
while (ctx->literal_pending) |
|
|
|
get_cmd_result( ctx, 0 ); |
|
|
|
get_cmd_result( ctx, 0 ); |
|
|
|
|
|
|
|
|
|
|
|
bufl = nfsnprintf( buf, sizeof(buf), cmd->cb.data ? CAP(LITERALPLUS) ? |
|
|
|
if (!cmd) |
|
|
|
|
|
|
|
cmd = new_imap_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", |
|
|
|
"%d %s{%d+}\r\n" : "%d %s{%d}\r\n" : "%d %s\r\n", |
|
|
|
cmd->tag, cmd->cmd, cmd->cb.dlen ); |
|
|
|
cmd->tag, cmd->cmd, cmd->param.data_len ); |
|
|
|
if (DFlags & VERBOSE) { |
|
|
|
if (DFlags & VERBOSE) { |
|
|
|
if (ctx->num_in_progress) |
|
|
|
if (ctx->num_in_progress) |
|
|
|
printf( "(%d in progress) ", ctx->num_in_progress ); |
|
|
|
printf( "(%d in progress) ", ctx->num_in_progress ); |
|
|
@ -506,27 +509,27 @@ v_issue_imap_cmd( imap_store_t *ctx, struct imap_cmd_cb *cb, |
|
|
|
printf( ">>> %d LOGIN <user> <pass>\n", cmd->tag ); |
|
|
|
printf( ">>> %d LOGIN <user> <pass>\n", cmd->tag ); |
|
|
|
} |
|
|
|
} |
|
|
|
if (socket_write( &ctx->buf.sock, buf, bufl ) != bufl) { |
|
|
|
if (socket_write( &ctx->buf.sock, buf, bufl ) != bufl) { |
|
|
|
|
|
|
|
if (cmd->param.data) |
|
|
|
|
|
|
|
free( cmd->param.data ); |
|
|
|
free( cmd->cmd ); |
|
|
|
free( cmd->cmd ); |
|
|
|
free( cmd ); |
|
|
|
free( cmd ); |
|
|
|
if (cb && cb->data) |
|
|
|
|
|
|
|
free( cb->data ); |
|
|
|
|
|
|
|
return NULL; |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
} |
|
|
|
if (cmd->cb.data) { |
|
|
|
if (cmd->param.data) { |
|
|
|
if (CAP(LITERALPLUS)) { |
|
|
|
if (CAP(LITERALPLUS)) { |
|
|
|
n = socket_write( &ctx->buf.sock, cmd->cb.data, cmd->cb.dlen ); |
|
|
|
n = socket_write( &ctx->buf.sock, cmd->param.data, cmd->param.data_len ); |
|
|
|
free( cmd->cb.data ); |
|
|
|
free( cmd->param.data ); |
|
|
|
if (n != cmd->cb.dlen || |
|
|
|
if (n != cmd->param.data_len || |
|
|
|
(n = socket_write( &ctx->buf.sock, "\r\n", 2 )) != 2) |
|
|
|
(n = socket_write( &ctx->buf.sock, "\r\n", 2 )) != 2) |
|
|
|
{ |
|
|
|
{ |
|
|
|
free( cmd->cmd ); |
|
|
|
free( cmd->cmd ); |
|
|
|
free( cmd ); |
|
|
|
free( cmd ); |
|
|
|
return NULL; |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
} |
|
|
|
cmd->cb.data = 0; |
|
|
|
cmd->param.data = 0; |
|
|
|
} else |
|
|
|
} else |
|
|
|
ctx->literal_pending = 1; |
|
|
|
ctx->literal_pending = 1; |
|
|
|
} else if (cmd->cb.cont) |
|
|
|
} else if (cmd->param.cont) |
|
|
|
ctx->literal_pending = 1; |
|
|
|
ctx->literal_pending = 1; |
|
|
|
cmd->next = 0; |
|
|
|
cmd->next = 0; |
|
|
|
*ctx->in_progress_append = cmd; |
|
|
|
*ctx->in_progress_append = cmd; |
|
|
@ -536,40 +539,24 @@ v_issue_imap_cmd( imap_store_t *ctx, struct imap_cmd_cb *cb, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static struct imap_cmd * |
|
|
|
static struct imap_cmd * |
|
|
|
issue_imap_cmd( imap_store_t *ctx, struct imap_cmd_cb *cb, const char *fmt, ... ) |
|
|
|
submit_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd, const char *fmt, ... ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
struct imap_cmd *ret; |
|
|
|
struct imap_cmd *ret; |
|
|
|
va_list ap; |
|
|
|
va_list ap; |
|
|
|
|
|
|
|
|
|
|
|
va_start( ap, fmt ); |
|
|
|
va_start( ap, fmt ); |
|
|
|
ret = v_issue_imap_cmd( ctx, cb, fmt, ap ); |
|
|
|
ret = v_submit_imap_cmd( ctx, cmd, fmt, ap ); |
|
|
|
va_end( ap ); |
|
|
|
va_end( ap ); |
|
|
|
return ret; |
|
|
|
return ret; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static struct imap_cmd * |
|
|
|
|
|
|
|
issue_imap_cmd_w( imap_store_t *ctx, struct imap_cmd_cb *cb, const char *fmt, ... ) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
struct imap_cmd *ret; |
|
|
|
|
|
|
|
va_list ap; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
va_start( ap, fmt ); |
|
|
|
|
|
|
|
ret = v_issue_imap_cmd( ctx, cb, fmt, ap ); |
|
|
|
|
|
|
|
va_end( ap ); |
|
|
|
|
|
|
|
while (ctx->num_in_progress > max_in_progress || |
|
|
|
|
|
|
|
socket_pending( &ctx->buf.sock )) |
|
|
|
|
|
|
|
get_cmd_result( ctx, 0 ); |
|
|
|
|
|
|
|
return ret; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int |
|
|
|
static int |
|
|
|
imap_exec( imap_store_t *ctx, struct imap_cmd_cb *cb, const char *fmt, ... ) |
|
|
|
imap_exec( imap_store_t *ctx, struct imap_cmd *cmdp, const char *fmt, ... ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
va_list ap; |
|
|
|
va_list ap; |
|
|
|
struct imap_cmd *cmdp; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
va_start( ap, fmt ); |
|
|
|
va_start( ap, fmt ); |
|
|
|
cmdp = v_issue_imap_cmd( ctx, cb, fmt, ap ); |
|
|
|
cmdp = v_submit_imap_cmd( ctx, cmdp, fmt, ap ); |
|
|
|
va_end( ap ); |
|
|
|
va_end( ap ); |
|
|
|
if (!cmdp) |
|
|
|
if (!cmdp) |
|
|
|
return RESP_BAD; |
|
|
|
return RESP_BAD; |
|
|
@ -578,13 +565,12 @@ imap_exec( imap_store_t *ctx, struct imap_cmd_cb *cb, const char *fmt, ... ) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int |
|
|
|
static int |
|
|
|
imap_exec_b( imap_store_t *ctx, struct imap_cmd_cb *cb, const char *fmt, ... ) |
|
|
|
imap_exec_b( imap_store_t *ctx, struct imap_cmd *cmdp, const char *fmt, ... ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
va_list ap; |
|
|
|
va_list ap; |
|
|
|
struct imap_cmd *cmdp; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
va_start( ap, fmt ); |
|
|
|
va_start( ap, fmt ); |
|
|
|
cmdp = v_issue_imap_cmd( ctx, cb, fmt, ap ); |
|
|
|
cmdp = v_submit_imap_cmd( ctx, cmdp, fmt, ap ); |
|
|
|
va_end( ap ); |
|
|
|
va_end( ap ); |
|
|
|
if (!cmdp) |
|
|
|
if (!cmdp) |
|
|
|
return DRV_STORE_BAD; |
|
|
|
return DRV_STORE_BAD; |
|
|
@ -597,13 +583,12 @@ imap_exec_b( imap_store_t *ctx, struct imap_cmd_cb *cb, const char *fmt, ... ) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int |
|
|
|
static int |
|
|
|
imap_exec_m( imap_store_t *ctx, struct imap_cmd_cb *cb, const char *fmt, ... ) |
|
|
|
imap_exec_m( imap_store_t *ctx, struct imap_cmd *cmdp, const char *fmt, ... ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
va_list ap; |
|
|
|
va_list ap; |
|
|
|
struct imap_cmd *cmdp; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
va_start( ap, fmt ); |
|
|
|
va_start( ap, fmt ); |
|
|
|
cmdp = v_issue_imap_cmd( ctx, cb, fmt, ap ); |
|
|
|
cmdp = v_submit_imap_cmd( ctx, cmdp, fmt, ap ); |
|
|
|
va_end( ap ); |
|
|
|
va_end( ap ); |
|
|
|
if (!cmdp) |
|
|
|
if (!cmdp) |
|
|
|
return DRV_STORE_BAD; |
|
|
|
return DRV_STORE_BAD; |
|
|
@ -624,6 +609,14 @@ drain_imap_replies( imap_store_t *ctx ) |
|
|
|
} |
|
|
|
} |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
|
|
|
process_imap_replies( imap_store_t *ctx ) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
while (ctx->num_in_progress > max_in_progress || |
|
|
|
|
|
|
|
socket_pending( &ctx->buf.sock )) |
|
|
|
|
|
|
|
get_cmd_result( ctx, 0 ); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int |
|
|
|
static int |
|
|
|
is_atom( list_t *list ) |
|
|
|
is_atom( list_t *list ) |
|
|
|
{ |
|
|
|
{ |
|
|
@ -838,13 +831,13 @@ parse_fetch( imap_store_t *ctx, char *cmd ) /* move this down */ |
|
|
|
|
|
|
|
|
|
|
|
if (body) { |
|
|
|
if (body) { |
|
|
|
for (cmdp = ctx->in_progress; cmdp; cmdp = cmdp->next) |
|
|
|
for (cmdp = ctx->in_progress; cmdp; cmdp = cmdp->next) |
|
|
|
if (cmdp->cb.uid == uid) |
|
|
|
if (cmdp->param.uid == uid) |
|
|
|
goto gotuid; |
|
|
|
goto gotuid; |
|
|
|
error( "IMAP error: unexpected FETCH response (UID %d)\n", uid ); |
|
|
|
error( "IMAP error: unexpected FETCH response (UID %d)\n", uid ); |
|
|
|
free_list( list ); |
|
|
|
free_list( list ); |
|
|
|
return -1; |
|
|
|
return -1; |
|
|
|
gotuid: |
|
|
|
gotuid: |
|
|
|
msgdata = (msg_data_t *)cmdp->cb.ctx; |
|
|
|
msgdata = (msg_data_t *)cmdp->param.aux; |
|
|
|
msgdata->data = body; |
|
|
|
msgdata->data = body; |
|
|
|
msgdata->len = size; |
|
|
|
msgdata->len = size; |
|
|
|
if (status & M_FLAGS) |
|
|
|
if (status & M_FLAGS) |
|
|
@ -880,7 +873,7 @@ parse_capability( imap_store_t *ctx, char *cmd ) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int |
|
|
|
static int |
|
|
|
parse_response_code( imap_store_t *ctx, struct imap_cmd_cb *cb, char *s ) |
|
|
|
parse_response_code( imap_store_t *ctx, struct imap_cmd *cmd, char *s ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
char *arg, *earg, *p; |
|
|
|
char *arg, *earg, *p; |
|
|
|
|
|
|
|
|
|
|
@ -913,10 +906,10 @@ parse_response_code( imap_store_t *ctx, struct imap_cmd_cb *cb, char *s ) |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
for (; isspace( (unsigned char)*p ); p++); |
|
|
|
for (; isspace( (unsigned char)*p ); p++); |
|
|
|
error( "*** IMAP ALERT *** %s\n", p ); |
|
|
|
error( "*** IMAP ALERT *** %s\n", p ); |
|
|
|
} else if (cb && cb->ctx && !strcmp( "APPENDUID", arg )) { |
|
|
|
} else if (cmd && cmd->param.aux && !strcmp( "APPENDUID", arg )) { |
|
|
|
if (!(arg = next_arg( &s )) || |
|
|
|
if (!(arg = next_arg( &s )) || |
|
|
|
(ctx->gen.uidvalidity = strtoll( arg, &earg, 10 ), *earg) || |
|
|
|
(ctx->gen.uidvalidity = strtoll( arg, &earg, 10 ), *earg) || |
|
|
|
!(arg = next_arg( &s )) || !(*(int *)cb->ctx = atoi( arg ))) |
|
|
|
!(arg = next_arg( &s )) || !(*(int *)cmd->param.aux = atoi( arg ))) |
|
|
|
{ |
|
|
|
{ |
|
|
|
error( "IMAP error: malformed APPENDUID status\n" ); |
|
|
|
error( "IMAP error: malformed APPENDUID status\n" ); |
|
|
|
return RESP_BAD; |
|
|
|
return RESP_BAD; |
|
|
@ -947,8 +940,8 @@ parse_search( imap_store_t *ctx, char *cmd ) |
|
|
|
* SEARCH response belongs to which request. |
|
|
|
* SEARCH response belongs to which request. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
for (cmdp = ctx->in_progress; cmdp; cmdp = cmdp->next) |
|
|
|
for (cmdp = ctx->in_progress; cmdp; cmdp = cmdp->next) |
|
|
|
if (cmdp->cb.uid == -1) { |
|
|
|
if (cmdp->param.uid == -1) { |
|
|
|
*(int *)cmdp->cb.ctx = uid; |
|
|
|
*(int *)cmdp->param.aux = uid; |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
error( "IMAP error: unexpected SEARCH response (UID %u)\n", uid ); |
|
|
|
error( "IMAP error: unexpected SEARCH response (UID %u)\n", uid ); |
|
|
@ -1034,14 +1027,14 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd ) |
|
|
|
it enforces a round-trip. */ |
|
|
|
it enforces a round-trip. */ |
|
|
|
cmdp = (struct imap_cmd *)((char *)ctx->in_progress_append - |
|
|
|
cmdp = (struct imap_cmd *)((char *)ctx->in_progress_append - |
|
|
|
offsetof(struct imap_cmd, next)); |
|
|
|
offsetof(struct imap_cmd, next)); |
|
|
|
if (cmdp->cb.data) { |
|
|
|
if (cmdp->param.data) { |
|
|
|
n = socket_write( &ctx->buf.sock, cmdp->cb.data, cmdp->cb.dlen ); |
|
|
|
n = socket_write( &ctx->buf.sock, cmdp->param.data, cmdp->param.data_len ); |
|
|
|
free( cmdp->cb.data ); |
|
|
|
free( cmdp->param.data ); |
|
|
|
cmdp->cb.data = 0; |
|
|
|
cmdp->param.data = 0; |
|
|
|
if (n != (int)cmdp->cb.dlen) |
|
|
|
if (n != (int)cmdp->param.data_len) |
|
|
|
return RESP_BAD; |
|
|
|
return RESP_BAD; |
|
|
|
} else if (cmdp->cb.cont) { |
|
|
|
} else if (cmdp->param.cont) { |
|
|
|
if (cmdp->cb.cont( ctx, cmdp, cmd )) |
|
|
|
if (cmdp->param.cont( ctx, cmdp, cmd )) |
|
|
|
return RESP_BAD; |
|
|
|
return RESP_BAD; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
error( "IMAP error: unexpected command continuation request\n" ); |
|
|
|
error( "IMAP error: unexpected command continuation request\n" ); |
|
|
@ -1049,7 +1042,7 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd ) |
|
|
|
} |
|
|
|
} |
|
|
|
if (socket_write( &ctx->buf.sock, "\r\n", 2 ) != 2) |
|
|
|
if (socket_write( &ctx->buf.sock, "\r\n", 2 ) != 2) |
|
|
|
return RESP_BAD; |
|
|
|
return RESP_BAD; |
|
|
|
if (!cmdp->cb.cont) |
|
|
|
if (!cmdp->param.cont) |
|
|
|
ctx->literal_pending = 0; |
|
|
|
ctx->literal_pending = 0; |
|
|
|
if (!tcmd) |
|
|
|
if (!tcmd) |
|
|
|
return DRV_OK; |
|
|
|
return DRV_OK; |
|
|
@ -1064,23 +1057,25 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd ) |
|
|
|
if (!(*pcmdp = cmdp->next)) |
|
|
|
if (!(*pcmdp = cmdp->next)) |
|
|
|
ctx->in_progress_append = pcmdp; |
|
|
|
ctx->in_progress_append = pcmdp; |
|
|
|
ctx->num_in_progress--; |
|
|
|
ctx->num_in_progress--; |
|
|
|
if (cmdp->cb.cont || cmdp->cb.data) |
|
|
|
if (cmdp->param.cont || cmdp->param.data) |
|
|
|
ctx->literal_pending = 0; |
|
|
|
ctx->literal_pending = 0; |
|
|
|
arg = next_arg( &cmd ); |
|
|
|
arg = next_arg( &cmd ); |
|
|
|
if (!strcmp( "OK", arg )) |
|
|
|
if (!strcmp( "OK", arg )) |
|
|
|
resp = DRV_OK; |
|
|
|
resp = DRV_OK; |
|
|
|
else { |
|
|
|
else { |
|
|
|
if (!strcmp( "NO", arg )) { |
|
|
|
if (!strcmp( "NO", arg )) { |
|
|
|
if (cmdp->cb.create && cmd && (cmdp->cb.trycreate || !memcmp( cmd, "[TRYCREATE]", 11 ))) { /* SELECT, APPEND or UID COPY */ |
|
|
|
if (cmdp->param.create && cmd && (cmdp->param.trycreate || !memcmp( cmd, "[TRYCREATE]", 11 ))) { /* SELECT, APPEND or UID COPY */ |
|
|
|
p = strchr( cmdp->cmd, '"' ); |
|
|
|
p = strchr( cmdp->cmd, '"' ); |
|
|
|
if (!issue_imap_cmd( ctx, 0, "CREATE %.*s", strchr( p + 1, '"' ) - p + 1, p )) { |
|
|
|
if (!submit_imap_cmd( ctx, 0, "CREATE %.*s", strchr( p + 1, '"' ) - p + 1, p )) { |
|
|
|
resp = RESP_BAD; |
|
|
|
resp = RESP_BAD; |
|
|
|
goto normal; |
|
|
|
goto normal; |
|
|
|
} |
|
|
|
} |
|
|
|
/* not waiting here violates the spec, but a server that does not
|
|
|
|
/* not waiting here violates the spec, but a server that does not
|
|
|
|
grok this nonetheless violates it too. */ |
|
|
|
grok this nonetheless violates it too. */ |
|
|
|
cmdp->cb.create = 0; |
|
|
|
ncmdp = nfmalloc( sizeof(*ncmdp) ); |
|
|
|
if (!(ncmdp = issue_imap_cmd( ctx, &cmdp->cb, "%s", cmdp->cmd ))) { |
|
|
|
memcpy( &ncmdp->param, &cmdp->param, sizeof(cmdp->param) ); |
|
|
|
|
|
|
|
ncmdp->param.create = 0; |
|
|
|
|
|
|
|
if (!submit_imap_cmd( ctx, ncmdp, "%s", cmdp->cmd )) { |
|
|
|
resp = RESP_BAD; |
|
|
|
resp = RESP_BAD; |
|
|
|
goto normal; |
|
|
|
goto normal; |
|
|
|
} |
|
|
|
} |
|
|
@ -1099,13 +1094,13 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd ) |
|
|
|
memcmp( cmdp->cmd, "LOGIN", 5 ) ? cmdp->cmd : "LOGIN <user> <pass>", |
|
|
|
memcmp( cmdp->cmd, "LOGIN", 5 ) ? cmdp->cmd : "LOGIN <user> <pass>", |
|
|
|
arg, cmd ? cmd : "" ); |
|
|
|
arg, cmd ? cmd : "" ); |
|
|
|
} |
|
|
|
} |
|
|
|
if ((resp2 = parse_response_code( ctx, &cmdp->cb, cmd )) > resp) |
|
|
|
if ((resp2 = parse_response_code( ctx, cmdp, cmd )) > resp) |
|
|
|
resp = resp2; |
|
|
|
resp = resp2; |
|
|
|
normal: |
|
|
|
normal: |
|
|
|
if (cmdp->cb.done) |
|
|
|
if (cmdp->param.done) |
|
|
|
cmdp->cb.done( ctx, cmdp, resp ); |
|
|
|
cmdp->param.done( ctx, cmdp, resp ); |
|
|
|
if (cmdp->cb.data) |
|
|
|
if (cmdp->param.data) |
|
|
|
free( cmdp->cb.data ); |
|
|
|
free( cmdp->param.data ); |
|
|
|
free( cmdp->cmd ); |
|
|
|
free( cmdp->cmd ); |
|
|
|
free( cmdp ); |
|
|
|
free( cmdp ); |
|
|
|
if (!tcmd || tcmd == cmdp) |
|
|
|
if (!tcmd || tcmd == cmdp) |
|
|
@ -1273,7 +1268,7 @@ do_cram_auth( imap_store_t *ctx, struct imap_cmd *cmdp, const char *prompt ) |
|
|
|
free( resp ); |
|
|
|
free( resp ); |
|
|
|
if (n != l) |
|
|
|
if (n != l) |
|
|
|
return -1; |
|
|
|
return -1; |
|
|
|
cmdp->cb.cont = 0; |
|
|
|
cmdp->param.cont = 0; |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
#endif |
|
|
|
#endif |
|
|
@ -1451,12 +1446,11 @@ imap_open_store( store_conf_t *conf, |
|
|
|
} |
|
|
|
} |
|
|
|
#if HAVE_LIBSSL |
|
|
|
#if HAVE_LIBSSL |
|
|
|
if (CAP(CRAM)) { |
|
|
|
if (CAP(CRAM)) { |
|
|
|
struct imap_cmd_cb cbd; |
|
|
|
struct imap_cmd *cmd = new_imap_cmd(); |
|
|
|
|
|
|
|
|
|
|
|
info( "Authenticating with CRAM-MD5\n" ); |
|
|
|
info( "Authenticating with CRAM-MD5\n" ); |
|
|
|
memset( &cbd, 0, sizeof(cbd) ); |
|
|
|
cmd->param.cont = do_cram_auth; |
|
|
|
cbd.cont = do_cram_auth; |
|
|
|
if (imap_exec( ctx, cmd, "AUTHENTICATE CRAM-MD5" ) != RESP_OK) |
|
|
|
if (imap_exec( ctx, &cbd, "AUTHENTICATE CRAM-MD5" ) != RESP_OK) |
|
|
|
|
|
|
|
goto bail; |
|
|
|
goto bail; |
|
|
|
} else if (srvc->require_cram) { |
|
|
|
} else if (srvc->require_cram) { |
|
|
|
error( "IMAP error: CRAM-MD5 authentication is not supported by server\n" ); |
|
|
|
error( "IMAP error: CRAM-MD5 authentication is not supported by server\n" ); |
|
|
@ -1525,9 +1519,9 @@ imap_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs, |
|
|
|
int (*cb)( int sts, void *aux ), void *aux ) |
|
|
|
int (*cb)( int sts, void *aux ), void *aux ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
imap_store_t *ctx = (imap_store_t *)gctx; |
|
|
|
imap_store_t *ctx = (imap_store_t *)gctx; |
|
|
|
|
|
|
|
struct imap_cmd *cmd = new_imap_cmd(); |
|
|
|
const char *prefix; |
|
|
|
const char *prefix; |
|
|
|
int ret, i, j, bl; |
|
|
|
int ret, i, j, bl; |
|
|
|
struct imap_cmd_cb cbd; |
|
|
|
|
|
|
|
char buf[1000]; |
|
|
|
char buf[1000]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -1539,10 +1533,9 @@ imap_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs, |
|
|
|
prefix = ctx->prefix; |
|
|
|
prefix = ctx->prefix; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
memset( &cbd, 0, sizeof(cbd) ); |
|
|
|
cmd->param.create = (gctx->opts & OPEN_CREATE) != 0; |
|
|
|
cbd.create = (gctx->opts & OPEN_CREATE) != 0; |
|
|
|
cmd->param.trycreate = 1; |
|
|
|
cbd.trycreate = 1; |
|
|
|
if ((ret = imap_exec_b( ctx, cmd, "SELECT \"%s%s\"", prefix, gctx->name )) != DRV_OK) |
|
|
|
if ((ret = imap_exec_b( ctx, &cbd, "SELECT \"%s%s\"", prefix, gctx->name )) != DRV_OK) |
|
|
|
|
|
|
|
goto bail; |
|
|
|
goto bail; |
|
|
|
|
|
|
|
|
|
|
|
if (gctx->count) { |
|
|
|
if (gctx->count) { |
|
|
@ -1584,12 +1577,10 @@ static int |
|
|
|
imap_fetch_msg( store_t *ctx, message_t *msg, msg_data_t *data, |
|
|
|
imap_fetch_msg( store_t *ctx, message_t *msg, msg_data_t *data, |
|
|
|
int (*cb)( int sts, void *aux ), void *aux ) |
|
|
|
int (*cb)( int sts, void *aux ), void *aux ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
struct imap_cmd_cb cbd; |
|
|
|
struct imap_cmd *cmd = new_imap_cmd(); |
|
|
|
|
|
|
|
cmd->param.uid = msg->uid; |
|
|
|
memset( &cbd, 0, sizeof(cbd) ); |
|
|
|
cmd->param.aux = data; |
|
|
|
cbd.uid = msg->uid; |
|
|
|
return cb( imap_exec_m( (imap_store_t *)ctx, cmd, "UID FETCH %d (%sBODY.PEEK[])", |
|
|
|
cbd.ctx = data; |
|
|
|
|
|
|
|
return cb( imap_exec_m( (imap_store_t *)ctx, &cbd, "UID FETCH %d (%sBODY.PEEK[])", |
|
|
|
|
|
|
|
msg->uid, (msg->status & M_FLAGS) ? "" : "FLAGS " ), aux ); |
|
|
|
msg->uid, (msg->status & M_FLAGS) ? "" : "FLAGS " ), aux ); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -1617,7 +1608,10 @@ imap_flags_helper( imap_store_t *ctx, int uid, char what, int flags) |
|
|
|
char buf[256]; |
|
|
|
char buf[256]; |
|
|
|
|
|
|
|
|
|
|
|
buf[imap_make_flags( flags, buf )] = 0; |
|
|
|
buf[imap_make_flags( flags, buf )] = 0; |
|
|
|
return issue_imap_cmd_w( ctx, 0, "UID STORE %d %cFLAGS.SILENT %s", uid, what, buf ) ? DRV_OK : DRV_STORE_BAD; |
|
|
|
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; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int |
|
|
|
static int |
|
|
@ -1652,11 +1646,9 @@ imap_trash_msg( store_t *gctx, message_t *msg, |
|
|
|
int (*cb)( int sts, void *aux ), void *aux ) |
|
|
|
int (*cb)( int sts, void *aux ), void *aux ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
imap_store_t *ctx = (imap_store_t *)gctx; |
|
|
|
imap_store_t *ctx = (imap_store_t *)gctx; |
|
|
|
struct imap_cmd_cb cbd; |
|
|
|
struct imap_cmd *cmd = new_imap_cmd(); |
|
|
|
|
|
|
|
cmd->param.create = 1; |
|
|
|
memset( &cbd, 0, sizeof(cbd) ); |
|
|
|
return cb( imap_exec_m( ctx, cmd, "UID COPY %d \"%s%s\"", |
|
|
|
cbd.create = 1; |
|
|
|
|
|
|
|
return cb( imap_exec_m( ctx, &cbd, "UID COPY %d \"%s%s\"", |
|
|
|
|
|
|
|
msg->uid, ctx->prefix, gctx->conf->trash ), aux ); |
|
|
|
msg->uid, ctx->prefix, gctx->conf->trash ), aux ); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -1665,7 +1657,7 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int to_trash, |
|
|
|
int (*cb)( int sts, int uid, void *aux ), void *aux ) |
|
|
|
int (*cb)( int sts, int uid, void *aux ), void *aux ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
imap_store_t *ctx = (imap_store_t *)gctx; |
|
|
|
imap_store_t *ctx = (imap_store_t *)gctx; |
|
|
|
struct imap_cmd_cb cbd; |
|
|
|
struct imap_cmd *cmd = new_imap_cmd(); |
|
|
|
const char *prefix, *box; |
|
|
|
const char *prefix, *box; |
|
|
|
int ret, d, uid; |
|
|
|
int ret, d, uid; |
|
|
|
char flagstr[128]; |
|
|
|
char flagstr[128]; |
|
|
@ -1677,26 +1669,25 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int to_trash, |
|
|
|
} |
|
|
|
} |
|
|
|
flagstr[d] = 0; |
|
|
|
flagstr[d] = 0; |
|
|
|
|
|
|
|
|
|
|
|
memset( &cbd, 0, sizeof(cbd) ); |
|
|
|
cmd->param.data_len = data->len; |
|
|
|
cbd.dlen = data->len; |
|
|
|
cmd->param.data = data->data; |
|
|
|
cbd.data = data->data; |
|
|
|
cmd->param.aux = &uid; |
|
|
|
cbd.ctx = &uid; |
|
|
|
|
|
|
|
uid = -2; |
|
|
|
uid = -2; |
|
|
|
|
|
|
|
|
|
|
|
if (to_trash) { |
|
|
|
if (to_trash) { |
|
|
|
box = gctx->conf->trash; |
|
|
|
box = gctx->conf->trash; |
|
|
|
prefix = ctx->prefix; |
|
|
|
prefix = ctx->prefix; |
|
|
|
cbd.create = 1; |
|
|
|
cmd->param.create = 1; |
|
|
|
if (ctx->trashnc) |
|
|
|
if (ctx->trashnc) |
|
|
|
ctx->caps = ctx->rcaps & ~(1 << LITERALPLUS); |
|
|
|
ctx->caps = ctx->rcaps & ~(1 << LITERALPLUS); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
box = gctx->name; |
|
|
|
box = gctx->name; |
|
|
|
prefix = !strcmp( box, "INBOX" ) ? "" : ctx->prefix; |
|
|
|
prefix = !strcmp( box, "INBOX" ) ? "" : ctx->prefix; |
|
|
|
cbd.create = (gctx->opts & OPEN_CREATE) != 0; |
|
|
|
cmd->param.create = (gctx->opts & OPEN_CREATE) != 0; |
|
|
|
/*if (ctx->currentnc)
|
|
|
|
/*if (ctx->currentnc)
|
|
|
|
ctx->caps = ctx->rcaps & ~(1 << LITERALPLUS);*/ |
|
|
|
ctx->caps = ctx->rcaps & ~(1 << LITERALPLUS);*/ |
|
|
|
} |
|
|
|
} |
|
|
|
ret = imap_exec_m( ctx, &cbd, "APPEND \"%s%s\" %s", prefix, box, flagstr ); |
|
|
|
ret = imap_exec_m( ctx, cmd, "APPEND \"%s%s\" %s", prefix, box, flagstr ); |
|
|
|
ctx->caps = ctx->rcaps; |
|
|
|
ctx->caps = ctx->rcaps; |
|
|
|
if (ret != DRV_OK) |
|
|
|
if (ret != DRV_OK) |
|
|
|
return cb( ret, -1, aux ); |
|
|
|
return cb( ret, -1, aux ); |
|
|
@ -1714,14 +1705,13 @@ imap_find_msg( store_t *gctx, const char *tuid, |
|
|
|
int (*cb)( int sts, int uid, void *aux ), void *aux ) |
|
|
|
int (*cb)( int sts, int uid, void *aux ), void *aux ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
imap_store_t *ctx = (imap_store_t *)gctx; |
|
|
|
imap_store_t *ctx = (imap_store_t *)gctx; |
|
|
|
struct imap_cmd_cb cbd; |
|
|
|
struct imap_cmd *cmd = new_imap_cmd(); |
|
|
|
int ret, uid; |
|
|
|
int ret, uid; |
|
|
|
|
|
|
|
|
|
|
|
memset( &cbd, 0, sizeof(cbd) ); |
|
|
|
cmd->param.uid = -1; /* we're looking for a UID */ |
|
|
|
cbd.uid = -1; /* we're looking for a UID */ |
|
|
|
cmd->param.aux = &uid; |
|
|
|
cbd.ctx = &uid; |
|
|
|
|
|
|
|
uid = -1; /* in case we get no SEARCH response at all */ |
|
|
|
uid = -1; /* in case we get no SEARCH response at all */ |
|
|
|
if ((ret = imap_exec_m( ctx, &cbd, "UID SEARCH HEADER X-TUID %." stringify(TUIDL) "s", tuid )) != DRV_OK) |
|
|
|
if ((ret = imap_exec_m( ctx, cmd, "UID SEARCH HEADER X-TUID %." stringify(TUIDL) "s", tuid )) != DRV_OK) |
|
|
|
return cb( ret, -1, aux ); |
|
|
|
return cb( ret, -1, aux ); |
|
|
|
else |
|
|
|
else |
|
|
|
return cb( uid <= 0 ? DRV_MSG_BAD : DRV_OK, uid, aux ); |
|
|
|
return cb( uid <= 0 ? DRV_MSG_BAD : DRV_OK, uid, aux ); |
|
|
|