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 <dot@dotat.at> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Tony Finch committed
Aug 1, 2014 at 09:15 UTC
e0d8e3084f47189916e3b1d7bf138a4ab6227798
1 file changed
+31
-50
imap-send.c
+31
-50
@@ -128,7 +128,6 @@ struct imap_cmd_cb {
128
char *data;
129
int dlen;
130
int uid;
131
- unsigned create:1, trycreate:1;
131
};
132
133
struct imap_cmd {
@@ -493,9 +492,9 @@ static int nfsnprintf(char *buf, int blen, const char *fmt, ...)
492
return ret;
493
}
494
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)
498
{
499
struct imap *imap = ctx->imap;
500
struct imap_cmd *cmd;
@@ -558,20 +557,6 @@ static struct imap_cmd *v_issue_imap_cmd(struct imap_store *ctx,
557
return cmd;
558
}
559
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
-
560
__attribute__((format (printf, 3, 4)))
561
static int imap_exec(struct imap_store *ctx, struct imap_cmd_cb *cb,
562
const char *fmt, ...)
@@ -580,7 +565,7 @@ static int imap_exec(struct imap_store *ctx, struct imap_cmd_cb *cb,
565
struct imap_cmd *cmdp;
566
567
va_start(ap, fmt);
583
- cmdp = v_issue_imap_cmd(ctx, cb, fmt, ap);
568
+ cmdp = issue_imap_cmd(ctx, cb, fmt, ap);
569
va_end(ap);
570
if (!cmdp)
571
return RESP_BAD;
@@ -596,7 +581,7 @@ static int imap_exec_m(struct imap_store *ctx, struct imap_cmd_cb *cb,
581
struct imap_cmd *cmdp;
582
583
va_start(ap, fmt);
599
- cmdp = v_issue_imap_cmd(ctx, cb, fmt, ap);
584
+ cmdp = issue_imap_cmd(ctx, cb, fmt, ap);
585
va_end(ap);
586
if (!cmdp)
587
return DRV_STORE_BAD;
@@ -714,8 +699,8 @@ static int parse_response_code(struct imap_store *ctx, struct imap_cmd_cb *cb,
699
static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd)
700
{
701
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;
704
int n, resp, resp2, tag;
705
706
for (;;) {
@@ -801,30 +786,9 @@ static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd)
786
if (!strcmp("OK", arg))
787
resp = DRV_OK;
788
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))
790
resp = RESP_NO;
827
- } else /*if (!strcmp("BAD", arg))*/
791
+ else /*if (!strcmp("BAD", arg))*/
792
resp = RESP_BAD;
793
fprintf(stderr, "IMAP command '%s' returned response (%s) - %s\n",
794
memcmp(cmdp->cmd, "LOGIN", 5) ?
@@ -833,7 +797,6 @@ static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd)
797
}
798
if ((resp2 = parse_response_code(ctx, &cmdp->cb, cmd)) > resp)
799
resp = resp2;
836
- normal:
800
if (cmdp->cb.done)
801
cmdp->cb.done(ctx, cmdp, resp);
802
free(cmdp->cb.data);
@@ -944,7 +907,7 @@ static int auth_cram_md5(struct imap_store *ctx, struct imap_cmd *cmd, const cha
907
return 0;
908
}
909
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)
911
{
912
struct credential cred = CREDENTIAL_INIT;
913
struct imap_store *ctx;
@@ -1156,6 +1119,25 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc)
1119
credential_approve(&cred);
1120
credential_clear(&cred);
1121
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
+
1141
ctx->prefix = "";
1142
return ctx;
1143
@@ -1164,6 +1146,7 @@ bail:
1146
credential_reject(&cred);
1147
credential_clear(&cred);
1148
1149
+ out:
1150
imap_close_store(ctx);
1151
return NULL;
1152
}
@@ -1219,7 +1202,6 @@ static int imap_store_msg(struct imap_store *ctx, struct strbuf *msg)
1202
1203
box = ctx->name;
1204
prefix = !strcmp(box, "INBOX") ? "" : ctx->prefix;
1222
- cb.create = 0;
1205
ret = imap_exec_m(ctx, &cb, "APPEND \"%s%s\" ", prefix, box);
1206
imap->caps = imap->rcaps;
1207
if (ret != DRV_OK)
@@ -1422,14 +1404,13 @@ int main(int argc, char **argv)
1404
}
1405
1406
/* write it to the imap server */
1425
- ctx = imap_open_store(&server);
1407
+ ctx = imap_open_store(&server, imap_folder);
1408
if (!ctx) {
1409
fprintf(stderr, "failed to open store\n");
1410
return 1;
1411
}
1412
1413
fprintf(stderr, "sending %d message%s\n", total, (total != 1) ? "s" : "");
1432
- ctx->name = imap_folder;
1414
while (1) {
1415
unsigned percent = n * 100 / total;
1416