From fb81dc06ac3263c6b6d478b7a63752cf6de6df77 Mon Sep 17 00:00:00 2001 From: Ali Gholami Rudi Date: Fri, 1 Nov 2013 10:41:54 +0330 Subject: [PATCH] mbox: support mails containing null bytes Also mime.c can read mime boundaries for multi-line content-type header. --- mailx.c | 26 ++++++++++++++--------- mbox.c | 44 ++++++++++++++++++--------------------- mbox.h | 4 ++-- mime.c | 73 +++++++++++++++++++++++++++++++++++++---------------------------- send.c | 9 +++++--- str.c | 9 ++++++++ str.h | 1 + 7 files changed, 96 insertions(+), 70 deletions(-) diff --git a/mailx.c b/mailx.c index 5c40d6e..c1ee601 100644 --- a/mailx.c +++ b/mailx.c @@ -51,7 +51,7 @@ static int read_line(char *dst, int size) if (nl || nw == size - 1) return nw; cur = 0; - if ((len = read(STDIN_FILENO, buf, BUFSIZE)) <= 0) + if ((len = read(0, buf, BUFSIZE)) <= 0) return -1; } return nw; @@ -73,11 +73,11 @@ static int utf8len(int c) return 2; } -static char *till_eol(char *r, int len, char *s, char *e) +static char *till_eol(char *r, int len, char *s, char *e, int fill) { int i = 0; while (i < len && s && s < e && *s) { - int l = utf8len(*s); + int l = utf8len((unsigned char) *s); memcpy(r, s, l); /* ignoring line breaks */ if (*s != '\r' && *s != '\n') { @@ -86,6 +86,8 @@ static char *till_eol(char *r, int len, char *s, char *e) } s += l; } + while (i++ < fill) + *r++ = ' '; return r; } @@ -242,7 +244,7 @@ static void mimes_add(struct mail *mail) len = mime_decode(mimes_buf[mimes_cur], mail->head, MIN(mail->len, MAILBUF)); memset(mime_mail, 0, sizeof(*mime_mail)); - mail_read(mime_mail, mimes_buf[mimes_cur]); + mail_read(mime_mail, mimes_buf[mimes_cur], mimes_buf[mimes_cur] + len); /* handle ^From_ inside msgs */ mime_mail->body_len += len - mime_mail->len; mime_mail->len = len; @@ -296,21 +298,25 @@ static void cmd_cat(char *pre, char *arg) show_mail(pre, 0); } +static int isreply(char *s) +{ + return tolower(s[0]) == 'r' && tolower(s[1]) == 'e' && s[2] == ':'; +} + static char *put_hdr(struct mail *mail, char *name, char *dst, int wid, int fill) { char *hdr = mail_hdr(mail, name); - char *lim = dst + wid; if (hdr) { hdr = hdr + strlen(name) + 1; - if (TRIM_RE && tolower(hdr[0]) == 'r' && tolower(hdr[1]) == 'e' && - tolower(hdr[2]) == ':') + if (TRIM_RE && isreply(hdr)) hdr += 3; while (*hdr == ' ') hdr++; - dst = till_eol(dst, wid, hdr, hdr + hdr_len(hdr)); + dst = till_eol(dst, wid, hdr, hdr + hdr_len(hdr), fill ? wid : 0); + } else { + while (fill && --wid >= 0) + *dst++ = ' '; } - while (fill && dst < lim) - *dst++ = ' '; return dst; } diff --git a/mbox.c b/mbox.c index 331fa30..5cb2d0e 100644 --- a/mbox.c +++ b/mbox.c @@ -9,6 +9,7 @@ #include #include #include "mbox.h" +#include "str.h" #include "util.h" #define INCSIZE (1 << 22) @@ -23,15 +24,15 @@ static void set_atime(char *filename) utime(filename, ×); } -static char *mail_start(char *r) +static char *mail_start(char *r, char *e) { char *s = r; char *t; - while (*s) { + while (s < e) { if (!strncmp("From ", s, 5) && (s == r || *(s - 1) == '\n')) break; - t = strchr(s + 1, 'F'); - s = t ? t : strchr(s, '\0'); + t = memchr(s + 1, 'F', e - s - 1); + s = t ? t : e; } return s; } @@ -54,17 +55,6 @@ static char *mail_hdrs(struct mail *mail, char *s) return s; } -static int startswith(char *s, char *r) -{ - while (*r) { - int c1 = *s++; - int c2 = *r++; - if (tolower(c1) != tolower(c2)) - return 0; - } - return 1; -} - char *mail_hdr(struct mail *mail, char *hdr) { int i; @@ -111,22 +101,23 @@ static void mail_stat(struct mail *mail) } } -char *mail_read(struct mail *mail, char *s) +char *mail_read(struct mail *mail, char *s, char *e) { char *end; mail->head = s; mail->body = mail_hdrs(mail, s); - end = mail_start(mail->body); + end = mail_start(mail->body, e); mail->len = end - mail->head; mail->body_len = end - mail->body; mail_stat(mail); return end; } -static void read_mails(struct mbox *mbox, char *s) +static int read_mails(struct mbox *mbox, char *s, char *e) { - while (s && *s) - s = mail_read(&mbox->mails[mbox->n++], s); + while (s && *s && mbox->n < MAXMAILS) + s = mail_read(&mbox->mails[mbox->n++], s, e); + return mbox->n == MAXMAILS; } int mbox_inc(struct mbox *mbox) @@ -150,7 +141,9 @@ int mbox_inc(struct mbox *mbox) close(fd); set_atime(mbox->path); if (old_len < mbox->len) - read_mails(mbox, mbox->mbox + old_len); + if (read_mails(mbox, mbox->mbox + old_len, + mbox->mbox + mbox->len + 1)) + return -1; return mbox->n - old_n; } @@ -160,7 +153,10 @@ struct mbox *mbox_alloc(char *filename) mbox = malloc(sizeof(*mbox)); memset(mbox, 0, sizeof(*mbox)); strcpy(mbox->path, filename); - mbox_inc(mbox); + if (mbox_inc(mbox) < 0) { + mbox_free(mbox); + return NULL; + } return mbox; } @@ -205,7 +201,7 @@ void mail_write(struct mail *mail, int fd) char *s = strchr(stat, '\0'); if (mail->stat & STAT_READ) *s++ = 'R'; - if (mail->stat & STAT_OLD) + if (mail->stat & (STAT_OLD | STAT_READ)) *s++ = 'O'; if (mail->stat & STAT_NEW) *s++ = 'N'; @@ -240,7 +236,7 @@ int mbox_write(struct mbox *mbox) { int fd; int i = 0; - if (mbox_inc(mbox) == -1) + if (mbox_inc(mbox) < 0) return -1; if (!mbox_changed(mbox)) return 0; diff --git a/mbox.h b/mbox.h index 15e5e3b..488e3b9 100644 --- a/mbox.h +++ b/mbox.h @@ -1,4 +1,4 @@ -#define MAXMAILS (1 << 14) +#define MAXMAILS (1 << 16) #define MAXHDRS (1 << 6) #define MAXPATHLEN (1 << 12) @@ -37,6 +37,6 @@ int mbox_write(struct mbox *mbox); int mail_head(struct mail *mail, char *dst, int len, char **hdrs, int n); char *mail_hdr(struct mail *mail, char *hdr); -char *mail_read(struct mail *mail, char *s); +char *mail_read(struct mail *mail, char *s, char *e); void mail_write(struct mail *mail, int fd); int hdr_len(char *hdr); diff --git a/mime.c b/mime.c index 2375914..9e10ff2 100644 --- a/mime.c +++ b/mime.c @@ -1,6 +1,8 @@ #include #include +#include "mbox.h" #include "mime.h" +#include "str.h" static char *b64_ch = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; @@ -122,28 +124,20 @@ static void copy_till(struct mime *m, char *s) m->src += len; } -static int starts(char *r, char *s) -{ - while (*s) - if (tolower(*s++) != tolower(*r++)) - return 0; - return 1; -} - -static void read_boundary(struct mime *m, char *s) +static void read_boundary(struct mime *m, char *s, char *hdrend) { char *bound = m->bound[m->depth]; char *e; - s = memchr(s, '=', m->end - s); + s = memchr(s, '=', hdrend - s); if (!s) return; s++; if (*s == '"') { s++; - e = memchr(s, '"', m->end - s); + e = memchr(s, '"', hdrend - s); } else { e = s; - while (e < m->end && !isspace(*e)) + while (e < hdrend && !isspace(*e) && *e != ';') e++; } if (!e) @@ -155,6 +149,15 @@ static void read_boundary(struct mime *m, char *s) m->depth++; } +static char *hdr_nextfield(char *s, char *e) +{ + while (s && s < e && *s != ';') + if (*s++ == '"') + if ((s = memchr(s, '"', e - s))) + s++; + return s && s + 2 < e ? s + 1 : NULL; +} + static int read_hdrs(struct mime *m) { char *s = m->src; @@ -168,29 +171,37 @@ static int read_hdrs(struct mime *m) break; n++; copy_till(m, s); - if (starts(s, "Subject:") || starts(s, "From:")) { + if (startswith(s, "Subject:") || startswith(s, "From:")) { m->dst = dec_qp(m->dst, m->src, n - s); m->src = n; } - if (starts(s, "Content-Type:")) { - char *t = strchr(s, ':') + 1; - while (isspace(*t) && t < e) - t++; - if (starts(t, "text")) - type |= TYPE_TXT; - if (starts(t, "multipart")) { - type |= TYPE_MPART; - read_boundary(m, t); + if (startswith(s, "Content-Type:")) { + char *key = strchr(s, ':') + 1; + char *hdrend = s + hdr_len(s); + while (key) { + while (key < hdrend && isspace(*key)) + key++; + if (startswith(key, "text")) + type |= TYPE_TXT; + if (startswith(key, "multipart")) + type |= TYPE_MPART; + if (startswith(key, "boundary")) + read_boundary(m, key, hdrend); + key = hdr_nextfield(key, hdrend); } } - if (starts(s, "Content-Transfer-Encoding:")) { - char *t = strchr(s, ':') + 1; - while (isspace(*t) && t < e) - t++; - if (starts(t, "quoted-printable")) - type |= ENC_QP; - if (starts(t, "base64")) - type |= ENC_B64; + if (startswith(s, "Content-Transfer-Encoding:")) { + char *key = strchr(s, ':') + 1; + char *hdrend = s + hdr_len(s); + while (key) { + while (key < hdrend && isspace(*key)) + key++; + if (startswith(key, "quoted-printable")) + type |= ENC_QP; + if (startswith(key, "base64")) + type |= ENC_B64; + key = hdr_nextfield(key, hdrend); + } } s = n; @@ -201,7 +212,7 @@ static int read_hdrs(struct mime *m) static int is_bound(struct mime *m, char *s) { - return starts(s, m->bound[m->depth - 1]); + return startswith(s, m->bound[m->depth - 1]); } static void read_bound(struct mime *m) diff --git a/send.c b/send.c index 15c2fec..da1c4dc 100644 --- a/send.c +++ b/send.c @@ -40,12 +40,12 @@ static int parse_addr(char **recips, int size, char *s, int len) return n; } -static int mail_recips(char **recips, int size, char *s) +static int mail_recips(char **recips, int size, char *s, char *e) { struct mail mail = {{0}}; char *to, *cc; int n = 0; - mail_read(&mail, s); + mail_read(&mail, s, e); if ((to = mail_hdr(&mail, "To:"))) n += parse_addr(recips + n, size - n, to + 3, hdr_len(to) - 3); if ((cc = mail_hdr(&mail, "CC:"))) @@ -260,10 +260,13 @@ void draft_send(struct draft *draft) char *send_argv[MAXRECP + 3] = {SENDMAIL, "-i"}; char *beg = strchr(draft->mail, '\n') + 1; char *end = draft->mail + draft->len; + int nrecips; int i; for (i = 0; i < MAXRECP; i++) send_argv[i + 2] = recips[i]; - send_argv[2 + mail_recips(send_argv + 2, MAXRECP, draft->mail)] = NULL; + nrecips = mail_recips(send_argv + 2, MAXRECP, + draft->mail, draft->mail + draft->len); + send_argv[2 + nrecips] = NULL; exec_pipe(SENDMAIL, send_argv, beg, end - beg); } diff --git a/str.c b/str.c index 41cb3d6..ab320d2 100644 --- a/str.c +++ b/str.c @@ -44,3 +44,12 @@ char *cut_word(char *dst, char *s) *dst = '\0'; return s; } + +/* return 1 if r starts with s */ +int startswith(char *r, char *s) +{ + while (*s) + if (tolower(*s++) != tolower(*r++)) + return 0; + return 1; +} diff --git a/str.h b/str.h index 6a1c043..9cdc8b7 100644 --- a/str.h +++ b/str.h @@ -3,3 +3,4 @@ char *put_intz(char *s, int n, int w); char *put_str(char *dst, char *src); char *put_mem(char *dst, char *src, int len); char *cut_word(char *dst, char *s); +int startswith(char *r, char *s); -- 2.11.4.GIT