From 7b7304b6254db1dea3e567753df47b94dd11e573 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 29 Dec 2014 01:42:17 +0100 Subject: [PATCH] split create_box() off from open_box() this allows us to do something else than creating missing boxes depending on circumstances. hypothetically, that is. --- src/driver.h | 9 +++++-- src/drv_imap.c | 39 ++++++++++++++++++++++------- src/drv_maildir.c | 12 +++++++-- src/sync.c | 64 +++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 106 insertions(+), 18 deletions(-) diff --git a/src/driver.h b/src/driver.h index b56677c..217d624 100644 --- 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 index 7600471..2db2670 100644 --- 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 ", 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 index 9ee61a7..443d4cc 100644 --- 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; } @@ -1046,6 +1046,13 @@ maildir_open_box( store_t *gctx, int create, cb( DRV_OK, aux ); } +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 ) { @@ -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 index 889af28..016a1f4 100644 --- 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,27 +987,78 @@ 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; } sync_deref( svars ); } +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;