};
struct msg_data {
- char *data;
- int len;
+ struct strbuf data;
unsigned char flags;
};
return d;
}
-static void lf_to_crlf(struct msg_data *msg)
+static void lf_to_crlf(struct strbuf *msg)
{
+ size_t new_len;
char *new;
int i, j, lfnum = 0;
- if (msg->data[0] == '\n')
+ if (msg->buf[0] == '\n')
lfnum++;
for (i = 1; i < msg->len; i++) {
- if (msg->data[i - 1] != '\r' && msg->data[i] == '\n')
+ if (msg->buf[i - 1] != '\r' && msg->buf[i] == '\n')
lfnum++;
}
- new = xmalloc(msg->len + lfnum);
- if (msg->data[0] == '\n') {
+ new_len = msg->len + lfnum;
+ new = xmalloc(new_len + 1);
+ if (msg->buf[0] == '\n') {
new[0] = '\r';
new[1] = '\n';
i = 1;
j = 2;
} else {
- new[0] = msg->data[0];
+ new[0] = msg->buf[0];
i = 1;
j = 1;
}
for ( ; i < msg->len; i++) {
- if (msg->data[i] != '\n') {
- new[j++] = msg->data[i];
+ if (msg->buf[i] != '\n') {
+ new[j++] = msg->buf[i];
continue;
}
- if (msg->data[i - 1] != '\r')
+ if (msg->buf[i - 1] != '\r')
new[j++] = '\r';
/* otherwise it already had CR before */
new[j++] = '\n';
}
- msg->len += lfnum;
- free(msg->data);
- msg->data = new;
+ strbuf_attach(msg, new, new_len, new_len + 1);
}
-static int imap_store_msg(struct store *gctx, struct msg_data *data)
+/*
+ * Store msg to IMAP. Also detach and free the data from msg->data,
+ * leaving msg->data empty.
+ */
+static int imap_store_msg(struct store *gctx, struct msg_data *msg)
{
struct imap_store *ctx = (struct imap_store *)gctx;
struct imap *imap = ctx->imap;
int ret, d;
char flagstr[128];
- lf_to_crlf(data);
+ lf_to_crlf(&msg->data);
memset(&cb, 0, sizeof(cb));
- cb.dlen = data->len;
- cb.data = xmalloc(cb.dlen);
- memcpy(cb.data, data->data, data->len);
+ cb.dlen = msg->data.len;
+ cb.data = strbuf_detach(&msg->data, NULL);
d = 0;
- if (data->flags) {
- d = imap_make_flags(data->flags, flagstr);
+ if (msg->flags) {
+ d = imap_make_flags(msg->flags, flagstr);
flagstr[d++] = ' ';
}
flagstr[d] = 0;
return DRV_OK;
}
-static void encode_html_chars(struct strbuf *p)
-{
- int i;
- for (i = 0; i < p->len; i++) {
- if (p->buf[i] == '&')
- strbuf_splice(p, i, 1, "&", 5);
- if (p->buf[i] == '<')
- strbuf_splice(p, i, 1, "<", 4);
- if (p->buf[i] == '>')
- strbuf_splice(p, i, 1, ">", 4);
- if (p->buf[i] == '"')
- strbuf_splice(p, i, 1, """, 6);
- }
-}
-static void wrap_in_html(struct msg_data *msg)
+static void wrap_in_html(struct strbuf *msg)
{
struct strbuf buf = STRBUF_INIT;
- struct strbuf **lines;
- struct strbuf **p;
static char *content_type = "Content-Type: text/html;\n";
static char *pre_open = "<pre>\n";
static char *pre_close = "</pre>\n";
- int added_header = 0;
-
- strbuf_attach(&buf, msg->data, msg->len, msg->len);
- lines = strbuf_split(&buf, '\n');
- strbuf_release(&buf);
- for (p = lines; *p; p++) {
- if (! added_header) {
- if ((*p)->len == 1 && *((*p)->buf) == '\n') {
- strbuf_addstr(&buf, content_type);
- strbuf_addbuf(&buf, *p);
- strbuf_addstr(&buf, pre_open);
- added_header = 1;
- continue;
- }
- }
- else
- encode_html_chars(*p);
- strbuf_addbuf(&buf, *p);
- }
+ const char *body = strstr(msg->buf, "\n\n");
+
+ if (!body)
+ return; /* Headers but no body; no wrapping needed */
+
+ body += 2;
+
+ strbuf_add(&buf, msg->buf, body - msg->buf - 1);
+ strbuf_addstr(&buf, content_type);
+ strbuf_addch(&buf, '\n');
+ strbuf_addstr(&buf, pre_open);
+ strbuf_addstr_xml_quoted(&buf, body);
strbuf_addstr(&buf, pre_close);
- strbuf_list_free(lines);
- msg->len = buf.len;
- msg->data = strbuf_detach(&buf, NULL);
+
+ strbuf_release(msg);
+ *msg = buf;
}
#define CHUNKSIZE 0x1000
-static int read_message(FILE *f, struct msg_data *msg)
+static int read_message(FILE *f, struct strbuf *all_msgs)
{
- struct strbuf buf = STRBUF_INIT;
-
- memset(msg, 0, sizeof(*msg));
-
do {
- if (strbuf_fread(&buf, CHUNKSIZE, f) <= 0)
+ if (strbuf_fread(all_msgs, CHUNKSIZE, f) <= 0)
break;
} while (!feof(f));
- msg->len = buf.len;
- msg->data = strbuf_detach(&buf, NULL);
- return msg->len;
+ return ferror(f) ? -1 : 0;
}
-static int count_messages(struct msg_data *msg)
+static int count_messages(struct strbuf *all_msgs)
{
int count = 0;
- char *p = msg->data;
+ char *p = all_msgs->buf;
while (1) {
if (!prefixcmp(p, "From ")) {
return count;
}
-static int split_msg(struct msg_data *all_msgs, struct msg_data *msg, int *ofs)
+/*
+ * Copy the next message from all_msgs, starting at offset *ofs, to
+ * msg. Update *ofs to the start of the following message. Return
+ * true iff a message was successfully copied.
+ */
+static int split_msg(struct strbuf *all_msgs, struct strbuf *msg, int *ofs)
{
char *p, *data;
+ size_t len;
- memset(msg, 0, sizeof *msg);
if (*ofs >= all_msgs->len)
return 0;
- data = &all_msgs->data[*ofs];
- msg->len = all_msgs->len - *ofs;
+ data = &all_msgs->buf[*ofs];
+ len = all_msgs->len - *ofs;
- if (msg->len < 5 || prefixcmp(data, "From "))
+ if (len < 5 || prefixcmp(data, "From "))
return 0;
p = strchr(data, '\n');
if (p) {
- p = &p[1];
- msg->len -= p-data;
- *ofs += p-data;
+ p++;
+ len -= p - data;
+ *ofs += p - data;
data = p;
}
p = strstr(data, "\nFrom ");
if (p)
- msg->len = &p[1] - data;
+ len = &p[1] - data;
- msg->data = xmemdupz(data, msg->len);
- *ofs += msg->len;
+ strbuf_add(msg, data, len);
+ *ofs += len;
return 1;
}
int main(int argc, char **argv)
{
- struct msg_data all_msgs, msg;
+ struct strbuf all_msgs = STRBUF_INIT;
+ struct msg_data msg = {STRBUF_INIT, 0};
struct store *ctx = NULL;
int ofs = 0;
int r;
}
/* read the messages */
- if (!read_message(stdin, &all_msgs)) {
+ if (read_message(stdin, &all_msgs)) {
+ fprintf(stderr, "error reading input\n");
+ return 1;
+ }
+
+ if (all_msgs.len == 0) {
fprintf(stderr, "nothing to send\n");
return 1;
}
ctx->name = imap_folder;
while (1) {
unsigned percent = n * 100 / total;
+
fprintf(stderr, "%4u%% (%d/%d) done\r", percent, n, total);
- if (!split_msg(&all_msgs, &msg, &ofs))
+ if (!split_msg(&all_msgs, &msg.data, &ofs))
break;
if (server.use_html)
- wrap_in_html(&msg);
+ wrap_in_html(&msg.data);
r = imap_store_msg(ctx, &msg);
if (r != DRV_OK)
break;