Merge branch 'tf/imap-send-create'

* tf/imap-send-create:
  imap-send: create target mailbox if it is missing
  imap-send: clarify CRAM-MD5 vs LOGIN documentation
This commit is contained in:
Junio C Hamano 2014-09-09 12:54:08 -07:00
commit c0ad561a46
2 changed files with 33 additions and 51 deletions

View file

@ -75,7 +75,8 @@ imap.preformattedHTML::
imap.authMethod::
Specify authenticate method for authentication with IMAP server.
Current supported method is 'CRAM-MD5' only.
Current supported method is 'CRAM-MD5' only. If this is not set
then 'git imap-send' uses the basic IMAP plaintext LOGIN command.
Examples
~~~~~~~~

View file

@ -128,7 +128,6 @@ struct imap_cmd_cb {
char *data;
int dlen;
int uid;
unsigned create:1, trycreate:1;
};
struct imap_cmd {
@ -493,9 +492,9 @@ static int nfsnprintf(char *buf, int blen, const char *fmt, ...)
return ret;
}
static struct imap_cmd *v_issue_imap_cmd(struct imap_store *ctx,
struct imap_cmd_cb *cb,
const char *fmt, va_list ap)
static struct imap_cmd *issue_imap_cmd(struct imap_store *ctx,
struct imap_cmd_cb *cb,
const char *fmt, va_list ap)
{
struct imap *imap = ctx->imap;
struct imap_cmd *cmd;
@ -558,20 +557,6 @@ static struct imap_cmd *v_issue_imap_cmd(struct imap_store *ctx,
return cmd;
}
__attribute__((format (printf, 3, 4)))
static struct imap_cmd *issue_imap_cmd(struct imap_store *ctx,
struct imap_cmd_cb *cb,
const char *fmt, ...)
{
struct imap_cmd *ret;
va_list ap;
va_start(ap, fmt);
ret = v_issue_imap_cmd(ctx, cb, fmt, ap);
va_end(ap);
return ret;
}
__attribute__((format (printf, 3, 4)))
static int imap_exec(struct imap_store *ctx, struct imap_cmd_cb *cb,
const char *fmt, ...)
@ -580,7 +565,7 @@ static int imap_exec(struct imap_store *ctx, struct imap_cmd_cb *cb,
struct imap_cmd *cmdp;
va_start(ap, fmt);
cmdp = v_issue_imap_cmd(ctx, cb, fmt, ap);
cmdp = issue_imap_cmd(ctx, cb, fmt, ap);
va_end(ap);
if (!cmdp)
return RESP_BAD;
@ -596,7 +581,7 @@ static int imap_exec_m(struct imap_store *ctx, struct imap_cmd_cb *cb,
struct imap_cmd *cmdp;
va_start(ap, fmt);
cmdp = v_issue_imap_cmd(ctx, cb, fmt, ap);
cmdp = issue_imap_cmd(ctx, cb, fmt, ap);
va_end(ap);
if (!cmdp)
return DRV_STORE_BAD;
@ -714,8 +699,8 @@ static int parse_response_code(struct imap_store *ctx, struct imap_cmd_cb *cb,
static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd)
{
struct imap *imap = ctx->imap;
struct imap_cmd *cmdp, **pcmdp, *ncmdp;
char *cmd, *arg, *arg1, *p;
struct imap_cmd *cmdp, **pcmdp;
char *cmd, *arg, *arg1;
int n, resp, resp2, tag;
for (;;) {
@ -801,30 +786,9 @@ static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd)
if (!strcmp("OK", arg))
resp = DRV_OK;
else {
if (!strcmp("NO", arg)) {
if (cmdp->cb.create && cmd && (cmdp->cb.trycreate || !memcmp(cmd, "[TRYCREATE]", 11))) { /* SELECT, APPEND or UID COPY */
p = strchr(cmdp->cmd, '"');
if (!issue_imap_cmd(ctx, NULL, "CREATE \"%.*s\"", (int)(strchr(p + 1, '"') - p + 1), p)) {
resp = RESP_BAD;
goto normal;
}
/* not waiting here violates the spec, but a server that does not
grok this nonetheless violates it too. */
cmdp->cb.create = 0;
if (!(ncmdp = issue_imap_cmd(ctx, &cmdp->cb, "%s", cmdp->cmd))) {
resp = RESP_BAD;
goto normal;
}
free(cmdp->cmd);
free(cmdp);
if (!tcmd)
return 0; /* ignored */
if (cmdp == tcmd)
tcmd = ncmdp;
continue;
}
if (!strcmp("NO", arg))
resp = RESP_NO;
} else /*if (!strcmp("BAD", arg))*/
else /*if (!strcmp("BAD", arg))*/
resp = RESP_BAD;
fprintf(stderr, "IMAP command '%s' returned response (%s) - %s\n",
memcmp(cmdp->cmd, "LOGIN", 5) ?
@ -833,7 +797,6 @@ static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd)
}
if ((resp2 = parse_response_code(ctx, &cmdp->cb, cmd)) > resp)
resp = resp2;
normal:
if (cmdp->cb.done)
cmdp->cb.done(ctx, cmdp, resp);
free(cmdp->cb.data);
@ -944,7 +907,7 @@ static int auth_cram_md5(struct imap_store *ctx, struct imap_cmd *cmd, const cha
return 0;
}
static struct imap_store *imap_open_store(struct imap_server_conf *srvc)
static struct imap_store *imap_open_store(struct imap_server_conf *srvc, char *folder)
{
struct credential cred = CREDENTIAL_INIT;
struct imap_store *ctx;
@ -1156,6 +1119,25 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc)
credential_approve(&cred);
credential_clear(&cred);
/* check the target mailbox exists */
ctx->name = folder;
switch (imap_exec(ctx, NULL, "EXAMINE \"%s\"", ctx->name)) {
case RESP_OK:
/* ok */
break;
case RESP_BAD:
fprintf(stderr, "IMAP error: could not check mailbox\n");
goto out;
case RESP_NO:
if (imap_exec(ctx, NULL, "CREATE \"%s\"", ctx->name) == RESP_OK) {
imap_info("Created missing mailbox\n");
} else {
fprintf(stderr, "IMAP error: could not create missing mailbox\n");
goto out;
}
break;
}
ctx->prefix = "";
return ctx;
@ -1164,6 +1146,7 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc)
credential_reject(&cred);
credential_clear(&cred);
out:
imap_close_store(ctx);
return NULL;
}
@ -1219,7 +1202,6 @@ static int imap_store_msg(struct imap_store *ctx, struct strbuf *msg)
box = ctx->name;
prefix = !strcmp(box, "INBOX") ? "" : ctx->prefix;
cb.create = 0;
ret = imap_exec_m(ctx, &cb, "APPEND \"%s%s\" ", prefix, box);
imap->caps = imap->rcaps;
if (ret != DRV_OK)
@ -1418,14 +1400,13 @@ int main(int argc, char **argv)
}
/* write it to the imap server */
ctx = imap_open_store(&server);
ctx = imap_open_store(&server, imap_folder);
if (!ctx) {
fprintf(stderr, "failed to open store\n");
return 1;
}
fprintf(stderr, "sending %d message%s\n", total, (total != 1) ? "s" : "");
ctx->name = imap_folder;
while (1) {
unsigned percent = n * 100 / total;