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