summaryrefslogtreecommitdiff
path: root/imap-send.c
diff options
context:
space:
mode:
Diffstat (limited to 'imap-send.c')
-rw-r--r--imap-send.c227
1 files changed, 94 insertions, 133 deletions
diff --git a/imap-send.c b/imap-send.c
index d6b65e204c..70bcc7a4e5 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -23,25 +23,11 @@
*/
#include "cache.h"
+#include "credential.h"
#include "exec_cmd.h"
#include "run-command.h"
-#include "prompt.h"
#ifdef NO_OPENSSL
typedef void *SSL;
-#else
-#ifdef APPLE_COMMON_CRYPTO
-#include <CommonCrypto/CommonHMAC.h>
-#define HMAC_CTX CCHmacContext
-#define HMAC_Init(hmac, key, len, algo) CCHmacInit(hmac, algo, key, len)
-#define HMAC_Update CCHmacUpdate
-#define HMAC_Final(hmac, hash, ptr) CCHmacFinal(hmac, hash)
-#define HMAC_CTX_cleanup(ignore)
-#define EVP_md5() kCCHmacAlgMD5
-#else
-#include <openssl/evp.h>
-#include <openssl/hmac.h>
-#endif
-#include <openssl/x509v3.h>
#endif
static const char imap_send_usage[] = "git imap-send < <mbox>";
@@ -83,6 +69,7 @@ struct imap_server_conf {
char *tunnel;
char *host;
int port;
+ char *folder;
char *user;
char *pass;
int use_ssl;
@@ -96,6 +83,7 @@ static struct imap_server_conf server = {
NULL, /* tunnel */
NULL, /* host */
0, /* port */
+ NULL, /* folder */
NULL, /* user */
NULL, /* pass */
0, /* use_ssl */
@@ -142,7 +130,6 @@ struct imap_cmd_cb {
char *data;
int dlen;
int uid;
- unsigned create:1, trycreate:1;
};
struct imap_cmd {
@@ -507,9 +494,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;
@@ -538,7 +525,7 @@ static struct imap_cmd *v_issue_imap_cmd(struct imap_store *ctx,
if (Verbose) {
if (imap->num_in_progress)
printf("(%d in progress) ", imap->num_in_progress);
- if (memcmp(cmd->cmd, "LOGIN", 5))
+ if (!starts_with(cmd->cmd, "LOGIN"))
printf(">>> %s", buf);
else
printf(">>> %d LOGIN <user> <pass>\n", cmd->tag);
@@ -573,20 +560,6 @@ static struct imap_cmd *v_issue_imap_cmd(struct imap_store *ctx,
}
__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, ...)
{
@@ -594,7 +567,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;
@@ -610,7 +583,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;
@@ -728,8 +701,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 (;;) {
@@ -815,39 +788,17 @@ 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) ?
+ !starts_with(cmdp->cmd, "LOGIN") ?
cmdp->cmd : "LOGIN <user> <pass>",
arg, cmd ? cmd : "");
}
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);
@@ -958,33 +909,33 @@ 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;
struct imap *imap;
char *arg, *rsp;
int s = -1, preauth;
- ctx = xcalloc(sizeof(*ctx), 1);
+ ctx = xcalloc(1, sizeof(*ctx));
- ctx->imap = imap = xcalloc(sizeof(*imap), 1);
+ ctx->imap = imap = xcalloc(1, sizeof(*imap));
imap->buf.sock.fd[0] = imap->buf.sock.fd[1] = -1;
imap->in_progress_append = &imap->in_progress;
/* open connection to IMAP server */
if (srvc->tunnel) {
- const char *argv[] = { srvc->tunnel, NULL };
- struct child_process tunnel = {NULL};
+ struct child_process tunnel = CHILD_PROCESS_INIT;
imap_info("Starting tunnel '%s'... ", srvc->tunnel);
- tunnel.argv = argv;
+ argv_array_push(&tunnel.args, srvc->tunnel);
tunnel.use_shell = 1;
tunnel.in = -1;
tunnel.out = -1;
if (start_command(&tunnel))
- die("cannot start proxy %s", argv[0]);
+ die("cannot start proxy %s", srvc->tunnel);
imap->buf.sock.fd[0] = tunnel.out;
imap->buf.sock.fd[1] = tunnel.in;
@@ -1110,25 +1061,23 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc)
}
#endif
imap_info("Logging in...\n");
- if (!srvc->user) {
- fprintf(stderr, "Skipping server %s, no user\n", srvc->host);
- goto bail;
- }
- if (!srvc->pass) {
- struct strbuf prompt = STRBUF_INIT;
- strbuf_addf(&prompt, "Password (%s@%s): ", srvc->user, srvc->host);
- arg = git_getpass(prompt.buf);
- strbuf_release(&prompt);
- if (!*arg) {
- fprintf(stderr, "Skipping account %s@%s, no password\n", srvc->user, srvc->host);
- goto bail;
- }
- /*
- * getpass() returns a pointer to a static buffer. make a copy
- * for long term storage.
- */
- srvc->pass = xstrdup(arg);
+ if (!srvc->user || !srvc->pass) {
+ cred.protocol = xstrdup(srvc->use_ssl ? "imaps" : "imap");
+ cred.host = xstrdup(srvc->host);
+
+ if (srvc->user)
+ cred.username = xstrdup(srvc->user);
+ if (srvc->pass)
+ cred.password = xstrdup(srvc->pass);
+
+ credential_fill(&cred);
+
+ if (!srvc->user)
+ srvc->user = xstrdup(cred.username);
+ if (!srvc->pass)
+ srvc->pass = xstrdup(cred.password);
}
+
if (CAP(NOLOGIN)) {
fprintf(stderr, "Skipping account %s@%s, server forbids LOGIN\n", srvc->user, srvc->host);
goto bail;
@@ -1167,10 +1116,38 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc)
}
} /* !preauth */
+ if (cred.username)
+ 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;
bail:
+ if (cred.username)
+ credential_reject(&cred);
+ credential_clear(&cred);
+
+ out:
imap_close_store(ctx);
return NULL;
}
@@ -1226,7 +1203,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)
@@ -1277,7 +1253,7 @@ static int count_messages(struct strbuf *all_msgs)
char *p = all_msgs->buf;
while (1) {
- if (!prefixcmp(p, "From ")) {
+ if (starts_with(p, "From ")) {
p = strstr(p+5, "\nFrom: ");
if (!p) break;
p = strstr(p+7, "\nDate: ");
@@ -1311,7 +1287,7 @@ static int split_msg(struct strbuf *all_msgs, struct strbuf *msg, int *ofs)
data = &all_msgs->buf[*ofs];
len = all_msgs->len - *ofs;
- if (len < 5 || prefixcmp(data, "From "))
+ if (len < 5 || !starts_with(data, "From "))
return 0;
p = strchr(data, '\n');
@@ -1331,49 +1307,35 @@ static int split_msg(struct strbuf *all_msgs, struct strbuf *msg, int *ofs)
return 1;
}
-static char *imap_folder;
-
-static int git_imap_config(const char *key, const char *val, void *cb)
+static void git_imap_config(void)
{
- char imap_key[] = "imap.";
+ const char *val = NULL;
- if (strncmp(key, imap_key, sizeof imap_key - 1))
- return 0;
+ git_config_get_bool("imap.sslverify", &server.ssl_verify);
+ git_config_get_bool("imap.preformattedhtml", &server.use_html);
+ git_config_get_string("imap.folder", &server.folder);
- key += sizeof imap_key - 1;
-
- /* check booleans first, and barf on others */
- if (!strcmp("sslverify", key))
- server.ssl_verify = git_config_bool(key, val);
- else if (!strcmp("preformattedhtml", key))
- server.use_html = git_config_bool(key, val);
- else if (!val)
- return config_error_nonbool(key);
-
- if (!strcmp("folder", key)) {
- imap_folder = xstrdup(val);
- } else if (!strcmp("host", key)) {
- if (!prefixcmp(val, "imap:"))
- val += 5;
- else if (!prefixcmp(val, "imaps:")) {
- val += 6;
- server.use_ssl = 1;
+ if (!git_config_get_value("imap.host", &val)) {
+ if (!val) {
+ git_die_config("imap.host", "Missing value for 'imap.host'");
+ } else {
+ if (starts_with(val, "imap:"))
+ val += 5;
+ else if (starts_with(val, "imaps:")) {
+ val += 6;
+ server.use_ssl = 1;
+ }
+ if (starts_with(val, "//"))
+ val += 2;
+ server.host = xstrdup(val);
}
- if (!prefixcmp(val, "//"))
- val += 2;
- server.host = xstrdup(val);
- } else if (!strcmp("user", key))
- server.user = xstrdup(val);
- else if (!strcmp("pass", key))
- server.pass = xstrdup(val);
- else if (!strcmp("port", key))
- server.port = git_config_int(key, val);
- else if (!strcmp("tunnel", key))
- server.tunnel = xstrdup(val);
- else if (!strcmp("authmethod", key))
- server.auth_method = xstrdup(val);
+ }
- return 0;
+ git_config_get_string("imap.user", &server.user);
+ git_config_get_string("imap.pass", &server.pass);
+ git_config_get_int("imap.port", &server.port);
+ git_config_get_string("imap.tunnel", &server.tunnel);
+ git_config_get_string("imap.authmethod", &server.auth_method);
}
int main(int argc, char **argv)
@@ -1394,12 +1356,12 @@ int main(int argc, char **argv)
usage(imap_send_usage);
setup_git_directory_gently(&nongit_ok);
- git_config(git_imap_config, NULL);
+ git_imap_config();
if (!server.port)
server.port = server.use_ssl ? 993 : 143;
- if (!imap_folder) {
+ if (!server.folder) {
fprintf(stderr, "no imap store specified\n");
return 1;
}
@@ -1429,14 +1391,13 @@ int main(int argc, char **argv)
}
/* write it to the imap server */
- ctx = imap_open_store(&server);
+ ctx = imap_open_store(&server, server.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;