Jelajahi Sumber

split create_box() off from open_box()

this allows us to do something else than creating missing boxes
depending on circumstances. hypothetically, that is.
Oswald Buddenhagen 10 tahun lalu
induk
melakukan
7b7304b625
4 mengubah file dengan 106 tambahan dan 18 penghapusan
  1. 7 2
      src/driver.h
  2. 30 9
      src/drv_imap.c
  3. 10 2
      src/drv_maildir.c
  4. 59 5
      src/sync.c

+ 7 - 2
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_*)

+ 30 - 9
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,

+ 10 - 2
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,

+ 59 - 5
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;