commit 7b7304b6254db1dea3e567753df47b94dd11e573
parent f1809ddd2b32d01d8fd7161040768ab4377285ce
Author: Oswald Buddenhagen <ossi@users.sf.net>
Date: Mon, 29 Dec 2014 01:42:17 +0100
split create_box() off from open_box()
this allows us to do something else than creating missing boxes
depending on circumstances. hypothetically, that is.
Diffstat:
4 files changed, 106 insertions(+), 18 deletions(-)
diff --git a/src/driver.h b/src/driver.h
@@ -165,8 +165,13 @@ struct driver {
* As a side effect, this should resolve ctx->path if applicable. */
int (*select_box)( store_t *ctx, const char *name );
- /* Open the selected mailbox. Optionally create missing boxes. */
- void (*open_box)( store_t *ctx, int create,
+ /* Create the selected mailbox. */
+ void (*create_box)( store_t *ctx,
+ void (*cb)( int sts, void *aux ), void *aux );
+
+ /* Open the selected mailbox.
+ * Note that this should not directly complain about failure to open. */
+ void (*open_box)( store_t *ctx,
void (*cb)( int sts, void *aux ), void *aux );
/* Invoked before load_box(), this informs the driver which operations (OP_*)
diff --git a/src/drv_imap.c b/src/drv_imap.c
@@ -143,8 +143,8 @@ struct imap_cmd {
int uid; /* to identify fetch responses */
char high_prio; /* if command is queued, put it at the front of the queue. */
char to_trash; /* we are storing to trash, not current. */
- char create; /* create the mailbox if we get an error ... */
- char trycreate; /* ... but only if this is true or the server says so. */
+ char create; /* create the mailbox if we get an error which suggests so. */
+ char failok; /* Don't complain about NO response. */
} param;
};
@@ -1333,10 +1333,7 @@ imap_socket_read( void *aux )
resp = RESP_OK;
} else {
if (!strcmp( "NO", arg )) {
- if (cmdp->param.create &&
- (cmdp->param.trycreate ||
- (cmd && starts_with( cmd, -1, "[TRYCREATE]", 11 ))))
- { /* SELECT, APPEND or UID COPY */
+ if (cmdp->param.create && cmd && starts_with( cmd, -1, "[TRYCREATE]", 11 )) { /* APPEND or UID COPY */
struct imap_cmd_trycreate *cmd2 =
(struct imap_cmd_trycreate *)new_imap_cmd( sizeof(*cmd2) );
cmd2->orig_cmd = cmdp;
@@ -1348,12 +1345,15 @@ imap_socket_read( void *aux )
continue;
}
resp = RESP_NO;
+ if (cmdp->param.failok)
+ goto doresp;
} 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>",
arg, cmd ? cmd : "" );
}
+ doresp:
if ((resp2 = parse_response_code( ctx, cmdp, cmd )) > resp)
resp = resp2;
imap_ref( ctx );
@@ -2124,7 +2124,7 @@ imap_select_box( store_t *gctx, const char *name )
}
static void
-imap_open_box( store_t *gctx, int create,
+imap_open_box( store_t *gctx,
void (*cb)( int sts, void *aux ), void *aux )
{
imap_store_t *ctx = (imap_store_t *)gctx;
@@ -2139,13 +2139,33 @@ imap_open_box( store_t *gctx, int create,
ctx->gen.uidnext = 0;
INIT_IMAP_CMD(imap_cmd_simple, cmd, cb, aux)
- cmd->gen.param.create = create;
- cmd->gen.param.trycreate = 1;
+ cmd->gen.param.failok = 1;
imap_exec( ctx, &cmd->gen, imap_done_simple_box,
"SELECT \"%\\s\"", buf );
free( buf );
}
+/******************* imap_create_box *******************/
+
+static void
+imap_create_box( store_t *gctx,
+ void (*cb)( int sts, void *aux ), void *aux )
+{
+ imap_store_t *ctx = (imap_store_t *)gctx;
+ struct imap_cmd_simple *cmd;
+ char *buf;
+
+ if (prepare_box( &buf, ctx ) < 0) {
+ cb( DRV_BOX_BAD, aux );
+ return;
+ }
+
+ INIT_IMAP_CMD(imap_cmd_simple, cmd, cb, aux)
+ imap_exec( ctx, &cmd->gen, imap_done_simple_box,
+ "CREATE \"%\\s\"", buf );
+ free( buf );
+}
+
/******************* imap_load_box *******************/
static void
@@ -2788,6 +2808,7 @@ struct driver imap_driver = {
imap_cancel_store,
imap_list_store,
imap_select_box,
+ imap_create_box,
imap_open_box,
imap_prepare_load_box,
imap_load_box,
diff --git a/src/drv_maildir.c b/src/drv_maildir.c
@@ -951,7 +951,7 @@ maildir_select_box( store_t *gctx, const char *name )
}
static void
-maildir_open_box( store_t *gctx, int create,
+maildir_open_box( store_t *gctx,
void (*cb)( int sts, void *aux ), void *aux )
{
maildir_store_t *ctx = (maildir_store_t *)gctx;
@@ -961,7 +961,7 @@ maildir_open_box( store_t *gctx, int create,
#endif /* USE_DB */
char uvpath[_POSIX_PATH_MAX];
- if ((ret = maildir_validate( gctx->path, create, ctx )) != DRV_OK) {
+ if ((ret = maildir_validate( gctx->path, 0, ctx )) != DRV_OK) {
cb( ret, aux );
return;
}
@@ -1047,6 +1047,13 @@ maildir_open_box( store_t *gctx, int create,
}
static void
+maildir_create_box( store_t *gctx,
+ void (*cb)( int sts, void *aux ), void *aux )
+{
+ cb( maildir_validate( gctx->path, 1, (maildir_store_t *)gctx ), aux );
+}
+
+static void
maildir_prepare_load_box( store_t *gctx, int opts )
{
if (opts & OPEN_SETFLAGS)
@@ -1538,6 +1545,7 @@ struct driver maildir_driver = {
maildir_disown_store, /* _cancel_, but it's the same */
maildir_list_store,
maildir_select_box,
+ maildir_create_box,
maildir_open_box,
maildir_prepare_load_box,
maildir_load_box,
diff --git a/src/sync.c b/src/sync.c
@@ -923,7 +923,10 @@ load_state( sync_vars_t *svars )
return 1;
}
+static void box_confirmed( int sts, void *aux );
+static void box_created( int sts, void *aux );
static void box_opened( int sts, void *aux );
+static void box_opened2( sync_vars_t *svars, int t );
static void load_box( sync_vars_t *svars, int t, int minwuid, int *mexcs, int nmexcs );
void
@@ -984,7 +987,7 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan,
sync_ref( svars );
for (t = 0; ; t++) {
info( "Opening %s box %s...\n", str_ms[t], svars->orig_name[t] );
- svars->drv[t]->open_box( ctx[t], (chan->ops[t] & OP_CREATE) != 0, box_opened, AUX );
+ svars->drv[t]->open_box( ctx[t], box_confirmed, AUX );
if (t || check_cancel( svars ))
break;
}
@@ -992,19 +995,70 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan,
}
static void
+box_confirmed( int sts, void *aux )
+{
+ DECL_SVARS;
+
+ if (sts == DRV_CANCELED)
+ return;
+ INIT_SVARS(aux);
+ if (check_cancel( svars ))
+ return;
+
+ if (sts == DRV_BOX_BAD) {
+ if (!(svars->chan->ops[t] & OP_CREATE)) {
+ box_opened( sts, aux );
+ } else {
+ info( "Creating %s %s...\n", str_ms[t], svars->orig_name[t] );
+ svars->drv[t]->create_box( svars->ctx[t], box_created, AUX );
+ }
+ } else {
+ box_opened2( svars, t );
+ }
+}
+
+static void
+box_created( int sts, void *aux )
+{
+ DECL_SVARS;
+
+ if (check_ret( sts, aux ))
+ return;
+ INIT_SVARS(aux);
+
+ svars->drv[t]->open_box( svars->ctx[t], box_opened, AUX );
+}
+
+static void
box_opened( int sts, void *aux )
{
DECL_SVARS;
+
+ if (sts == DRV_CANCELED)
+ return;
+ INIT_SVARS(aux);
+ if (check_cancel( svars ))
+ return;
+
+ if (sts == DRV_BOX_BAD) {
+ error( "Error: channel %s: %s %s cannot be opened.\n",
+ svars->chan->name, str_ms[t], svars->orig_name[t] );
+ svars->ret = SYNC_FAIL;
+ sync_bail( svars );
+ } else {
+ box_opened2( svars, t );
+ }
+}
+
+static void
+box_opened2( sync_vars_t *svars, int t )
+{
store_t *ctx[2];
channel_conf_t *chan;
sync_rec_t *srec;
int opts[2], fails;
int *mexcs, nmexcs, rmexcs, minwuid;
- if (check_ret( sts, aux ))
- return;
- INIT_SVARS(aux);
-
svars->state[t] |= ST_SELECTED;
if (!(svars->state[1-t] & ST_SELECTED))
return;