فهرست منبع

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 سال پیش
والد
کامیت
7b7304b625
4فایلهای تغییر یافته به همراه106 افزوده شده و 18 حذف شده
  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;