Skip to content

Commit e0d8e30

Browse files
fanf2gitster
authored andcommitted
imap-send: create target mailbox if it is missing
Some MUAs delete their "drafts" folder when it is empty, so git imap-send should be able to create it if necessary. This change checks that the folder exists immediately after login and tries to create it if it is missing. There was some vestigial code to handle a [TRYCREATE] response from the server when an APPEND target is missing. However this code never ran (the create and trycreate flags were never set) and when I tried to make it run I found that the code had already thrown away the contents of the message it was trying to append. Signed-off-by: Tony Finch <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent f07243f commit e0d8e30

File tree

1 file changed

+31
-50
lines changed

1 file changed

+31
-50
lines changed

imap-send.c

Lines changed: 31 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,6 @@ struct imap_cmd_cb {
128128
char *data;
129129
int dlen;
130130
int uid;
131-
unsigned create:1, trycreate:1;
132131
};
133132

134133
struct imap_cmd {
@@ -493,9 +492,9 @@ static int nfsnprintf(char *buf, int blen, const char *fmt, ...)
493492
return ret;
494493
}
495494

496-
static struct imap_cmd *v_issue_imap_cmd(struct imap_store *ctx,
497-
struct imap_cmd_cb *cb,
498-
const char *fmt, va_list ap)
495+
static struct imap_cmd *issue_imap_cmd(struct imap_store *ctx,
496+
struct imap_cmd_cb *cb,
497+
const char *fmt, va_list ap)
499498
{
500499
struct imap *imap = ctx->imap;
501500
struct imap_cmd *cmd;
@@ -558,20 +557,6 @@ static struct imap_cmd *v_issue_imap_cmd(struct imap_store *ctx,
558557
return cmd;
559558
}
560559

561-
__attribute__((format (printf, 3, 4)))
562-
static struct imap_cmd *issue_imap_cmd(struct imap_store *ctx,
563-
struct imap_cmd_cb *cb,
564-
const char *fmt, ...)
565-
{
566-
struct imap_cmd *ret;
567-
va_list ap;
568-
569-
va_start(ap, fmt);
570-
ret = v_issue_imap_cmd(ctx, cb, fmt, ap);
571-
va_end(ap);
572-
return ret;
573-
}
574-
575560
__attribute__((format (printf, 3, 4)))
576561
static int imap_exec(struct imap_store *ctx, struct imap_cmd_cb *cb,
577562
const char *fmt, ...)
@@ -580,7 +565,7 @@ static int imap_exec(struct imap_store *ctx, struct imap_cmd_cb *cb,
580565
struct imap_cmd *cmdp;
581566

582567
va_start(ap, fmt);
583-
cmdp = v_issue_imap_cmd(ctx, cb, fmt, ap);
568+
cmdp = issue_imap_cmd(ctx, cb, fmt, ap);
584569
va_end(ap);
585570
if (!cmdp)
586571
return RESP_BAD;
@@ -596,7 +581,7 @@ static int imap_exec_m(struct imap_store *ctx, struct imap_cmd_cb *cb,
596581
struct imap_cmd *cmdp;
597582

598583
va_start(ap, fmt);
599-
cmdp = v_issue_imap_cmd(ctx, cb, fmt, ap);
584+
cmdp = issue_imap_cmd(ctx, cb, fmt, ap);
600585
va_end(ap);
601586
if (!cmdp)
602587
return DRV_STORE_BAD;
@@ -714,8 +699,8 @@ static int parse_response_code(struct imap_store *ctx, struct imap_cmd_cb *cb,
714699
static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd)
715700
{
716701
struct imap *imap = ctx->imap;
717-
struct imap_cmd *cmdp, **pcmdp, *ncmdp;
718-
char *cmd, *arg, *arg1, *p;
702+
struct imap_cmd *cmdp, **pcmdp;
703+
char *cmd, *arg, *arg1;
719704
int n, resp, resp2, tag;
720705

721706
for (;;) {
@@ -801,30 +786,9 @@ static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd)
801786
if (!strcmp("OK", arg))
802787
resp = DRV_OK;
803788
else {
804-
if (!strcmp("NO", arg)) {
805-
if (cmdp->cb.create && cmd && (cmdp->cb.trycreate || !memcmp(cmd, "[TRYCREATE]", 11))) { /* SELECT, APPEND or UID COPY */
806-
p = strchr(cmdp->cmd, '"');
807-
if (!issue_imap_cmd(ctx, NULL, "CREATE \"%.*s\"", (int)(strchr(p + 1, '"') - p + 1), p)) {
808-
resp = RESP_BAD;
809-
goto normal;
810-
}
811-
/* not waiting here violates the spec, but a server that does not
812-
grok this nonetheless violates it too. */
813-
cmdp->cb.create = 0;
814-
if (!(ncmdp = issue_imap_cmd(ctx, &cmdp->cb, "%s", cmdp->cmd))) {
815-
resp = RESP_BAD;
816-
goto normal;
817-
}
818-
free(cmdp->cmd);
819-
free(cmdp);
820-
if (!tcmd)
821-
return 0; /* ignored */
822-
if (cmdp == tcmd)
823-
tcmd = ncmdp;
824-
continue;
825-
}
789+
if (!strcmp("NO", arg))
826790
resp = RESP_NO;
827-
} else /*if (!strcmp("BAD", arg))*/
791+
else /*if (!strcmp("BAD", arg))*/
828792
resp = RESP_BAD;
829793
fprintf(stderr, "IMAP command '%s' returned response (%s) - %s\n",
830794
memcmp(cmdp->cmd, "LOGIN", 5) ?
@@ -833,7 +797,6 @@ static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd)
833797
}
834798
if ((resp2 = parse_response_code(ctx, &cmdp->cb, cmd)) > resp)
835799
resp = resp2;
836-
normal:
837800
if (cmdp->cb.done)
838801
cmdp->cb.done(ctx, cmdp, resp);
839802
free(cmdp->cb.data);
@@ -944,7 +907,7 @@ static int auth_cram_md5(struct imap_store *ctx, struct imap_cmd *cmd, const cha
944907
return 0;
945908
}
946909

947-
static struct imap_store *imap_open_store(struct imap_server_conf *srvc)
910+
static struct imap_store *imap_open_store(struct imap_server_conf *srvc, char *folder)
948911
{
949912
struct credential cred = CREDENTIAL_INIT;
950913
struct imap_store *ctx;
@@ -1156,6 +1119,25 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc)
11561119
credential_approve(&cred);
11571120
credential_clear(&cred);
11581121

1122+
/* check the target mailbox exists */
1123+
ctx->name = folder;
1124+
switch (imap_exec(ctx, NULL, "EXAMINE \"%s\"", ctx->name)) {
1125+
case RESP_OK:
1126+
/* ok */
1127+
break;
1128+
case RESP_BAD:
1129+
fprintf(stderr, "IMAP error: could not check mailbox\n");
1130+
goto out;
1131+
case RESP_NO:
1132+
if (imap_exec(ctx, NULL, "CREATE \"%s\"", ctx->name) == RESP_OK) {
1133+
imap_info("Created missing mailbox\n");
1134+
} else {
1135+
fprintf(stderr, "IMAP error: could not create missing mailbox\n");
1136+
goto out;
1137+
}
1138+
break;
1139+
}
1140+
11591141
ctx->prefix = "";
11601142
return ctx;
11611143

@@ -1164,6 +1146,7 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc)
11641146
credential_reject(&cred);
11651147
credential_clear(&cred);
11661148

1149+
out:
11671150
imap_close_store(ctx);
11681151
return NULL;
11691152
}
@@ -1219,7 +1202,6 @@ static int imap_store_msg(struct imap_store *ctx, struct strbuf *msg)
12191202

12201203
box = ctx->name;
12211204
prefix = !strcmp(box, "INBOX") ? "" : ctx->prefix;
1222-
cb.create = 0;
12231205
ret = imap_exec_m(ctx, &cb, "APPEND \"%s%s\" ", prefix, box);
12241206
imap->caps = imap->rcaps;
12251207
if (ret != DRV_OK)
@@ -1422,14 +1404,13 @@ int main(int argc, char **argv)
14221404
}
14231405

14241406
/* write it to the imap server */
1425-
ctx = imap_open_store(&server);
1407+
ctx = imap_open_store(&server, imap_folder);
14261408
if (!ctx) {
14271409
fprintf(stderr, "failed to open store\n");
14281410
return 1;
14291411
}
14301412

14311413
fprintf(stderr, "sending %d message%s\n", total, (total != 1) ? "s" : "");
1432-
ctx->name = imap_folder;
14331414
while (1) {
14341415
unsigned percent = n * 100 / total;
14351416

0 commit comments

Comments
 (0)