Merge branch 'mh/imap-send-shrinkage'

Remove a lot of unused code from "git imap-send".

* mh/imap-send-shrinkage:
  imap-send.c: simplify logic in lf_to_crlf()
  imap-send.c: fold struct store into struct imap_store
  imap-send.c: remove unused field imap_store::uidvalidity
  imap-send.c: use struct imap_store instead of struct store
  imap-send.c: remove unused field imap_store::trashnc
  imap-send.c: remove namespace fields from struct imap
  imap-send.c: remove struct imap argument to parse_imap_list_l()
  imap-send.c: inline parse_imap_list() in parse_list()
  imap-send.c: remove some unused fields from struct store
  imap-send.c: remove struct message
  imap-send.c: remove struct store_conf
  iamp-send.c: remove unused struct imap_store_conf
  imap-send.c: remove struct msg_data
  imap-send.c: remove msg_data::flags, which was always zero
This commit is contained in:
Junio C Hamano 2013-01-23 21:16:45 -08:00
commit a29e711814

View File

@ -33,46 +33,6 @@ typedef void *SSL;
#include <openssl/hmac.h> #include <openssl/hmac.h>
#endif #endif
struct store_conf {
char *name;
const char *path; /* should this be here? its interpretation is driver-specific */
char *map_inbox;
char *trash;
unsigned max_size; /* off_t is overkill */
unsigned trash_remote_new:1, trash_only_new:1;
};
/* For message->status */
#define M_RECENT (1<<0) /* unsyncable flag; maildir_* depend on this being 1<<0 */
#define M_DEAD (1<<1) /* expunged */
#define M_FLAGS (1<<2) /* flags fetched */
struct message {
struct message *next;
size_t size; /* zero implies "not fetched" */
int uid;
unsigned char flags, status;
};
struct store {
struct store_conf *conf; /* foreign */
/* currently open mailbox */
const char *name; /* foreign! maybe preset? */
char *path; /* own */
struct message *msgs; /* own */
int uidvalidity;
unsigned char opts; /* maybe preset? */
/* note that the following do _not_ reflect stats from msgs, but mailbox totals */
int count; /* # of messages */
int recent; /* # of recent messages - don't trust this beyond the initial read */
};
struct msg_data {
struct strbuf data;
unsigned char flags;
};
static const char imap_send_usage[] = "git imap-send < <mbox>"; static const char imap_send_usage[] = "git imap-send < <mbox>";
#undef DRV_OK #undef DRV_OK
@ -90,8 +50,6 @@ static void imap_warn(const char *, ...);
static char *next_arg(char **); static char *next_arg(char **);
static void free_generic_messages(struct message *);
__attribute__((format (printf, 3, 4))) __attribute__((format (printf, 3, 4)))
static int nfsnprintf(char *buf, int blen, const char *fmt, ...); static int nfsnprintf(char *buf, int blen, const char *fmt, ...);
@ -135,20 +93,6 @@ static struct imap_server_conf server = {
NULL, /* auth_method */ NULL, /* auth_method */
}; };
struct imap_store_conf {
struct store_conf gen;
struct imap_server_conf *server;
};
#define NIL (void *)0x1
#define LIST (void *)0x2
struct imap_list {
struct imap_list *next, *child;
char *val;
int len;
};
struct imap_socket { struct imap_socket {
int fd[2]; int fd[2];
SSL *ssl; SSL *ssl;
@ -165,7 +109,6 @@ struct imap_cmd;
struct imap { struct imap {
int uidnext; /* from SELECT responses */ int uidnext; /* from SELECT responses */
struct imap_list *ns_personal, *ns_other, *ns_shared; /* NAMESPACE info */
unsigned caps, rcaps; /* CAPABILITY results */ unsigned caps, rcaps; /* CAPABILITY results */
/* command queue */ /* command queue */
int nexttag, num_in_progress, literal_pending; int nexttag, num_in_progress, literal_pending;
@ -174,11 +117,11 @@ struct imap {
}; };
struct imap_store { struct imap_store {
struct store gen; /* currently open mailbox */
const char *name; /* foreign! maybe preset? */
int uidvalidity; int uidvalidity;
struct imap *imap; struct imap *imap;
const char *prefix; const char *prefix;
unsigned /*currentnc:1,*/ trashnc:1;
}; };
struct imap_cmd_cb { struct imap_cmd_cb {
@ -225,14 +168,6 @@ static const char *cap_list[] = {
static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd); static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd);
static const char *Flags[] = {
"Draft",
"Flagged",
"Answered",
"Seen",
"Deleted",
};
#ifndef NO_OPENSSL #ifndef NO_OPENSSL
static void ssl_socket_perror(const char *func) static void ssl_socket_perror(const char *func)
{ {
@ -476,16 +411,6 @@ static char *next_arg(char **s)
return ret; return ret;
} }
static void free_generic_messages(struct message *msgs)
{
struct message *tmsg;
for (; msgs; msgs = tmsg) {
tmsg = msgs->next;
free(msgs);
}
}
static int nfsnprintf(char *buf, int blen, const char *fmt, ...) static int nfsnprintf(char *buf, int blen, const char *fmt, ...)
{ {
int ret; int ret;
@ -613,35 +538,9 @@ static int imap_exec_m(struct imap_store *ctx, struct imap_cmd_cb *cb,
} }
} }
static int is_atom(struct imap_list *list) static int skip_imap_list_l(char **sp, int level)
{ {
return list && list->val && list->val != NIL && list->val != LIST; char *s = *sp;
}
static int is_list(struct imap_list *list)
{
return list && list->val == LIST;
}
static void free_list(struct imap_list *list)
{
struct imap_list *tmp;
for (; list; list = tmp) {
tmp = list->next;
if (is_list(list))
free_list(list->child);
else if (is_atom(list))
free(list->val);
free(list);
}
}
static int parse_imap_list_l(struct imap *imap, char **sp, struct imap_list **curp, int level)
{
struct imap_list *cur;
char *s = *sp, *p;
int n, bytes;
for (;;) { for (;;) {
while (isspace((unsigned char)*s)) while (isspace((unsigned char)*s))
@ -650,68 +549,23 @@ static int parse_imap_list_l(struct imap *imap, char **sp, struct imap_list **cu
s++; s++;
break; break;
} }
*curp = cur = xmalloc(sizeof(*cur));
curp = &cur->next;
cur->val = NULL; /* for clean bail */
if (*s == '(') { if (*s == '(') {
/* sublist */ /* sublist */
s++; s++;
cur->val = LIST; if (skip_imap_list_l(&s, level + 1))
if (parse_imap_list_l(imap, &s, &cur->child, level + 1))
goto bail;
} else if (imap && *s == '{') {
/* literal */
bytes = cur->len = strtol(s + 1, &s, 10);
if (*s != '}')
goto bail;
s = cur->val = xmalloc(cur->len);
/* dump whats left over in the input buffer */
n = imap->buf.bytes - imap->buf.offset;
if (n > bytes)
/* the entire message fit in the buffer */
n = bytes;
memcpy(s, imap->buf.buf + imap->buf.offset, n);
s += n;
bytes -= n;
/* mark that we used part of the buffer */
imap->buf.offset += n;
/* now read the rest of the message */
while (bytes > 0) {
if ((n = socket_read(&imap->buf.sock, s, bytes)) <= 0)
goto bail;
s += n;
bytes -= n;
}
if (buffer_gets(&imap->buf, &s))
goto bail; goto bail;
} else if (*s == '"') { } else if (*s == '"') {
/* quoted string */ /* quoted string */
s++; s++;
p = s;
for (; *s != '"'; s++) for (; *s != '"'; s++)
if (!*s) if (!*s)
goto bail; goto bail;
cur->len = s - p;
s++; s++;
cur->val = xmemdupz(p, cur->len);
} else { } else {
/* atom */ /* atom */
p = s;
for (; *s && !isspace((unsigned char)*s); s++) for (; *s && !isspace((unsigned char)*s); s++)
if (level && *s == ')') if (level && *s == ')')
break; break;
cur->len = s - p;
if (cur->len == 3 && !memcmp("NIL", p, 3))
cur->val = NIL;
else
cur->val = xmemdupz(p, cur->len);
} }
if (!level) if (!level)
@ -720,27 +574,15 @@ static int parse_imap_list_l(struct imap *imap, char **sp, struct imap_list **cu
goto bail; goto bail;
} }
*sp = s; *sp = s;
*curp = NULL;
return 0; return 0;
bail: bail:
*curp = NULL;
return -1; return -1;
} }
static struct imap_list *parse_imap_list(struct imap *imap, char **sp) static void skip_list(char **sp)
{ {
struct imap_list *head; skip_imap_list_l(sp, 0);
if (!parse_imap_list_l(imap, sp, &head, 0))
return head;
free_list(head);
return NULL;
}
static struct imap_list *parse_list(char **sp)
{
return parse_imap_list(NULL, sp);
} }
static void parse_capability(struct imap *imap, char *cmd) static void parse_capability(struct imap *imap, char *cmd)
@ -772,7 +614,7 @@ static int parse_response_code(struct imap_store *ctx, struct imap_cmd_cb *cb,
*p++ = 0; *p++ = 0;
arg = next_arg(&s); arg = next_arg(&s);
if (!strcmp("UIDVALIDITY", arg)) { if (!strcmp("UIDVALIDITY", arg)) {
if (!(arg = next_arg(&s)) || !(ctx->gen.uidvalidity = atoi(arg))) { if (!(arg = next_arg(&s)) || !(ctx->uidvalidity = atoi(arg))) {
fprintf(stderr, "IMAP error: malformed UIDVALIDITY status\n"); fprintf(stderr, "IMAP error: malformed UIDVALIDITY status\n");
return RESP_BAD; return RESP_BAD;
} }
@ -790,7 +632,7 @@ static int parse_response_code(struct imap_store *ctx, struct imap_cmd_cb *cb,
for (; isspace((unsigned char)*p); p++); for (; isspace((unsigned char)*p); p++);
fprintf(stderr, "*** IMAP ALERT *** %s\n", p); fprintf(stderr, "*** IMAP ALERT *** %s\n", p);
} else if (cb && cb->ctx && !strcmp("APPENDUID", arg)) { } else if (cb && cb->ctx && !strcmp("APPENDUID", arg)) {
if (!(arg = next_arg(&s)) || !(ctx->gen.uidvalidity = atoi(arg)) || if (!(arg = next_arg(&s)) || !(ctx->uidvalidity = atoi(arg)) ||
!(arg = next_arg(&s)) || !(*(int *)cb->ctx = atoi(arg))) { !(arg = next_arg(&s)) || !(*(int *)cb->ctx = atoi(arg))) {
fprintf(stderr, "IMAP error: malformed APPENDUID status\n"); fprintf(stderr, "IMAP error: malformed APPENDUID status\n");
return RESP_BAD; return RESP_BAD;
@ -819,20 +661,28 @@ static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd)
} }
if (!strcmp("NAMESPACE", arg)) { if (!strcmp("NAMESPACE", arg)) {
imap->ns_personal = parse_list(&cmd); /* rfc2342 NAMESPACE response. */
imap->ns_other = parse_list(&cmd); skip_list(&cmd); /* Personal mailboxes */
imap->ns_shared = parse_list(&cmd); skip_list(&cmd); /* Others' mailboxes */
skip_list(&cmd); /* Shared mailboxes */
} else if (!strcmp("OK", arg) || !strcmp("BAD", arg) || } else if (!strcmp("OK", arg) || !strcmp("BAD", arg) ||
!strcmp("NO", arg) || !strcmp("BYE", arg)) { !strcmp("NO", arg) || !strcmp("BYE", arg)) {
if ((resp = parse_response_code(ctx, NULL, cmd)) != RESP_OK) if ((resp = parse_response_code(ctx, NULL, cmd)) != RESP_OK)
return resp; return resp;
} else if (!strcmp("CAPABILITY", arg)) } else if (!strcmp("CAPABILITY", arg)) {
parse_capability(imap, cmd); parse_capability(imap, cmd);
else if ((arg1 = next_arg(&cmd))) { } else if ((arg1 = next_arg(&cmd))) {
if (!strcmp("EXISTS", arg1)) ; /*
ctx->gen.count = atoi(arg); * Unhandled response-data with at least two words.
else if (!strcmp("RECENT", arg1)) * Ignore it.
ctx->gen.recent = atoi(arg); *
* NEEDSWORK: Previously this case handled '<num> EXISTS'
* and '<num> RECENT' but as a probably-unintended side
* effect it ignores other unrecognized two-word
* responses. imap-send doesn't ever try to read
* messages or mailboxes these days, so consider
* eliminating this case.
*/
} else { } else {
fprintf(stderr, "IMAP error: unable to parse untagged response\n"); fprintf(stderr, "IMAP error: unable to parse untagged response\n");
return RESP_BAD; return RESP_BAD;
@ -934,16 +784,12 @@ static void imap_close_server(struct imap_store *ictx)
imap_exec(ictx, NULL, "LOGOUT"); imap_exec(ictx, NULL, "LOGOUT");
socket_shutdown(&imap->buf.sock); socket_shutdown(&imap->buf.sock);
} }
free_list(imap->ns_personal);
free_list(imap->ns_other);
free_list(imap->ns_shared);
free(imap); free(imap);
} }
static void imap_close_store(struct store *ctx) static void imap_close_store(struct imap_store *ctx)
{ {
imap_close_server((struct imap_store *)ctx); imap_close_server(ctx);
free_generic_messages(ctx->msgs);
free(ctx); free(ctx);
} }
@ -1028,7 +874,7 @@ static int auth_cram_md5(struct imap_store *ctx, struct imap_cmd *cmd, const cha
return 0; return 0;
} }
static struct store *imap_open_store(struct imap_server_conf *srvc) static struct imap_store *imap_open_store(struct imap_server_conf *srvc)
{ {
struct imap_store *ctx; struct imap_store *ctx;
struct imap *imap; struct imap *imap;
@ -1238,103 +1084,69 @@ static struct store *imap_open_store(struct imap_server_conf *srvc)
} /* !preauth */ } /* !preauth */
ctx->prefix = ""; ctx->prefix = "";
ctx->trashnc = 1; return ctx;
return (struct store *)ctx;
bail: bail:
imap_close_store(&ctx->gen); imap_close_store(ctx);
return NULL; return NULL;
} }
static int imap_make_flags(int flags, char *buf) /*
{ * Insert CR characters as necessary in *msg to ensure that every LF
const char *s; * character in *msg is preceded by a CR.
unsigned i, d; */
for (i = d = 0; i < ARRAY_SIZE(Flags); i++)
if (flags & (1 << i)) {
buf[d++] = ' ';
buf[d++] = '\\';
for (s = Flags[i]; *s; s++)
buf[d++] = *s;
}
buf[0] = '(';
buf[d++] = ')';
return d;
}
static void lf_to_crlf(struct strbuf *msg) static void lf_to_crlf(struct strbuf *msg)
{ {
size_t new_len;
char *new; char *new;
int i, j, lfnum = 0; size_t i, j;
char lastc;
if (msg->buf[0] == '\n') /* First pass: tally, in j, the size of the new string: */
lfnum++; for (i = j = 0, lastc = '\0'; i < msg->len; i++) {
for (i = 1; i < msg->len; i++) { if (msg->buf[i] == '\n' && lastc != '\r')
if (msg->buf[i - 1] != '\r' && msg->buf[i] == '\n') j++; /* a CR will need to be added here */
lfnum++; lastc = msg->buf[i];
j++;
} }
new_len = msg->len + lfnum; new = xmalloc(j + 1);
new = xmalloc(new_len + 1);
if (msg->buf[0] == '\n') { /*
new[0] = '\r'; * Second pass: write the new string. Note that this loop is
new[1] = '\n'; * otherwise identical to the first pass.
i = 1; */
j = 2; for (i = j = 0, lastc = '\0'; i < msg->len; i++) {
} else { if (msg->buf[i] == '\n' && lastc != '\r')
new[0] = msg->buf[0];
i = 1;
j = 1;
}
for ( ; i < msg->len; i++) {
if (msg->buf[i] != '\n') {
new[j++] = msg->buf[i];
continue;
}
if (msg->buf[i - 1] != '\r')
new[j++] = '\r'; new[j++] = '\r';
/* otherwise it already had CR before */ lastc = new[j++] = msg->buf[i];
new[j++] = '\n';
} }
strbuf_attach(msg, new, new_len, new_len + 1); strbuf_attach(msg, new, j, j + 1);
} }
/* /*
* Store msg to IMAP. Also detach and free the data from msg->data, * Store msg to IMAP. Also detach and free the data from msg->data,
* leaving msg->data empty. * leaving msg->data empty.
*/ */
static int imap_store_msg(struct store *gctx, struct msg_data *msg) static int imap_store_msg(struct imap_store *ctx, struct strbuf *msg)
{ {
struct imap_store *ctx = (struct imap_store *)gctx;
struct imap *imap = ctx->imap; struct imap *imap = ctx->imap;
struct imap_cmd_cb cb; struct imap_cmd_cb cb;
const char *prefix, *box; const char *prefix, *box;
int ret, d; int ret;
char flagstr[128];
lf_to_crlf(&msg->data); lf_to_crlf(msg);
memset(&cb, 0, sizeof(cb)); memset(&cb, 0, sizeof(cb));
cb.dlen = msg->data.len; cb.dlen = msg->len;
cb.data = strbuf_detach(&msg->data, NULL); cb.data = strbuf_detach(msg, NULL);
d = 0; box = ctx->name;
if (msg->flags) {
d = imap_make_flags(msg->flags, flagstr);
flagstr[d++] = ' ';
}
flagstr[d] = 0;
box = gctx->name;
prefix = !strcmp(box, "INBOX") ? "" : ctx->prefix; prefix = !strcmp(box, "INBOX") ? "" : ctx->prefix;
cb.create = 0; cb.create = 0;
ret = imap_exec_m(ctx, &cb, "APPEND \"%s%s\" %s", prefix, box, flagstr); ret = imap_exec_m(ctx, &cb, "APPEND \"%s%s\" ", prefix, box);
imap->caps = imap->rcaps; imap->caps = imap->rcaps;
if (ret != DRV_OK) if (ret != DRV_OK)
return ret; return ret;
gctx->count++;
return DRV_OK; return DRV_OK;
} }
@ -1483,8 +1295,8 @@ static int git_imap_config(const char *key, const char *val, void *cb)
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
struct strbuf all_msgs = STRBUF_INIT; struct strbuf all_msgs = STRBUF_INIT;
struct msg_data msg = {STRBUF_INIT, 0}; struct strbuf msg = STRBUF_INIT;
struct store *ctx = NULL; struct imap_store *ctx = NULL;
int ofs = 0; int ofs = 0;
int r; int r;
int total, n = 0; int total, n = 0;
@ -1545,10 +1357,10 @@ int main(int argc, char **argv)
unsigned percent = n * 100 / total; unsigned percent = n * 100 / total;
fprintf(stderr, "%4u%% (%d/%d) done\r", percent, n, total); fprintf(stderr, "%4u%% (%d/%d) done\r", percent, n, total);
if (!split_msg(&all_msgs, &msg.data, &ofs)) if (!split_msg(&all_msgs, &msg, &ofs))
break; break;
if (server.use_html) if (server.use_html)
wrap_in_html(&msg.data); wrap_in_html(&msg);
r = imap_store_msg(ctx, &msg); r = imap_store_msg(ctx, &msg);
if (r != DRV_OK) if (r != DRV_OK)
break; break;