New patches to improve claws' handling of long lines in attachments. Mails with attached text files with long lines are rejected by OpenSMTPd.
Christopher Index: Makefile =================================================================== RCS file: /cvs/ports/mail/claws-mail/Makefile,v retrieving revision 1.51 diff -u -p -r1.51 Makefile --- Makefile 23 Jan 2012 18:57:33 -0000 1.51 +++ Makefile 3 Apr 2012 13:33:20 -0000 @@ -12,6 +12,8 @@ DISTNAME= claws-mail-${V} PKGNAME-main= ${DISTNAME} PKGNAME-bogofilter= claws-mail-bogofilter-${V} PKGNAME-spamassassin= claws-mail-spamassassin-${V} +REVISION= 0 + CATEGORIES= mail news HOMEPAGE= http://www.claws-mail.org/ Index: patches/patch-autogen_sh =================================================================== RCS file: patches/patch-autogen_sh diff -N patches/patch-autogen_sh --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-autogen_sh 3 Apr 2012 13:33:20 -0000 @@ -0,0 +1,12 @@ +$OpenBSD$ +--- autogen.sh.orig Fri Dec 16 09:09:32 2011 ++++ autogen.sh Tue Apr 3 13:07:33 2012 +@@ -55,7 +55,7 @@ if [ "$bisonver" = "" ]; then + exit 1 + fi + +-flexver=`flex --version|sed "s/.* //"` ++flexver=`($LEX --version || flex --version)|sed "s/.* //"` + + if [ "$flexver" = "" ]; then + echo Flex 2.5.31 or greater is needed to compile Claws Mail CVS Index: patches/patch-src_common_defs_h =================================================================== RCS file: patches/patch-src_common_defs_h diff -N patches/patch-src_common_defs_h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-src_common_defs_h 3 Apr 2012 13:33:20 -0000 @@ -0,0 +1,13 @@ +$OpenBSD$ +--- src/common/defs.h.orig Fri Dec 16 09:09:34 2011 ++++ src/common/defs.h Tue Apr 3 13:07:33 2012 +@@ -148,6 +148,9 @@ + + #define BUFFSIZE 8192 + ++/* according to RFC 821 1000 characters including CRLF */ ++#define MAXSMTPTEXTLEN 1000 ++ + #ifndef MAXPATHLEN + # define MAXPATHLEN 4095 + #endif Index: patches/patch-src_common_quoted-printable_c =================================================================== RCS file: patches/patch-src_common_quoted-printable_c diff -N patches/patch-src_common_quoted-printable_c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-src_common_quoted-printable_c 3 Apr 2012 13:33:20 -0000 @@ -0,0 +1,133 @@ +$OpenBSD$ +--- src/common/quoted-printable.c.orig Fri Dec 16 09:09:34 2011 ++++ src/common/quoted-printable.c Tue Apr 3 13:07:33 2012 +@@ -22,66 +22,78 @@ + + #include "utils.h" + ++/* Processes at most 78 characters from in buffer, ++ * and stores one NULL-terminated line of at most 76 characters (excl. \0) of ++ * quoted-printable output without terminating newline characters in out buffer. ++ * Except when encoding text, every output line ends in a soft line break. ++ * Therefore the caller can chain multiple lines of encoded data resulting from ++ * sequential runs by glueing them together with line breaks. ++ * The number of processed input characters is returned. */ ++ + #define MAX_LINELEN 76 + + #define IS_LBREAK(p) \ +- (*(p) == '\0' || *(p) == '\n' || (*(p) == '\r' && *((p) + 1) == '\n')) ++ ((p)[0] == '\n' ? 1 : ((p)[0] == '\r' && (p)[1] == '\n') ? 2 : 0) + +-#define SOFT_LBREAK_IF_REQUIRED(n) \ +- if (len + (n) > MAX_LINELEN || \ +- (len + (n) == MAX_LINELEN && (!IS_LBREAK(inp + 1)))) { \ +- *outp++ = '='; \ +- *outp++ = '\n'; \ +- len = 0; \ +- } +- +-void qp_encode_line(gchar *out, const guchar *in) ++gint qp_encode(gboolean text, gchar *out, const guchar *in, gint len) + { +- const guchar *inp = in; +- gchar *outp = out; +- guchar ch; +- gint len = 0; ++ /* counters of input/output characters */ ++ gint inc = 0; ++ gint outc = 1; /* one character reserved for '=' soft line break */ + +- while (*inp != '\0') { +- ch = *inp; +- +- if (IS_LBREAK(inp)) { +- *outp++ = '\n'; +- len = 0; +- if (*inp == '\r') +- inp++; +- inp++; +- } else if (ch == '\t' || ch == ' ') { +- if (IS_LBREAK(inp + 1)) { +- SOFT_LBREAK_IF_REQUIRED(3); +- *outp++ = '='; +- get_hex_str(outp, ch); +- outp += 2; +- len += 3; +- inp++; +- } else { +- SOFT_LBREAK_IF_REQUIRED(1); +- *outp++ = *inp++; +- len++; ++ while(inc < len) { ++ /* allow literal linebreaks in text */ ++ if(text) { ++ if(IS_LBREAK(in)) { ++ /* inserting linebreaks is the job of our caller */ ++ g_assert(outc <= MAX_LINELEN); ++ *out = '\0'; ++ return inc + IS_LBREAK(in); + } +- } else if ((ch >= 33 && ch <= 60) || (ch >= 62 && ch <= 126)) { +- SOFT_LBREAK_IF_REQUIRED(1); +- *outp++ = *inp++; +- len++; +- } else { +- SOFT_LBREAK_IF_REQUIRED(3); +- *outp++ = '='; +- get_hex_str(outp, ch); +- outp += 2; +- len += 3; +- inp++; ++ if(IS_LBREAK(in+1)) { ++ /* free the reserved character since no softbreak ++ * will be needed after the current character */ ++ outc--; ++ /* guard against whitespace before a literal linebreak */ ++ if(*in == ' ' || *in == '\t') { ++ goto escape; ++ } ++ } + } ++ if(*in == '=') { ++ goto escape; ++ } ++ /* Cave: Whitespace is unconditionally output literally, ++ * but according to the RFC it must not be output before a ++ * linebreak. ++ * This requirement is obeyed by quoting all linebreaks ++ * and therefore ending all lines with '='. */ ++ else if((*in >= ' ' && *in <= '~') || *in == '\t') { ++ if(outc + 1 <= MAX_LINELEN) { ++ *out++ = *in++; ++ outc++; ++ inc++; ++ } ++ else break; ++ } ++ else { ++escape: ++ if(outc + 3 <= MAX_LINELEN) { ++ *out++ = '='; ++ outc++; ++ get_hex_str(out, *in); ++ out += 2; ++ outc += 2; ++ in++; ++ inc++; ++ } ++ else break; ++ } + } +- +- if (len > 0) +- *outp++ = '\n'; +- +- *outp = '\0'; ++ g_assert(outc <= MAX_LINELEN); ++ *out++ = '='; ++ *out = '\0'; ++ return inc; + } + + gint qp_decode_line(gchar *str) Index: patches/patch-src_common_quoted-printable_h =================================================================== RCS file: patches/patch-src_common_quoted-printable_h diff -N patches/patch-src_common_quoted-printable_h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-src_common_quoted-printable_h 3 Apr 2012 13:33:20 -0000 @@ -0,0 +1,16 @@ +$OpenBSD$ +--- src/common/quoted-printable.h.orig Fri Dec 16 09:09:34 2011 ++++ src/common/quoted-printable.h Tue Apr 3 13:07:33 2012 +@@ -22,8 +22,10 @@ + + #include <glib.h> + +-void qp_encode_line (gchar *out, +- const guchar *in); ++gint qp_encode (gboolean text, ++ gchar *out, ++ const guchar *in, ++ gint len); + gint qp_decode_line (gchar *str); + gint qp_decode_const (gchar *out, + gint avail, Index: patches/patch-src_common_smtp_c =================================================================== RCS file: /cvs/ports/mail/claws-mail/patches/patch-src_common_smtp_c,v retrieving revision 1.1 diff -u -p -r1.1 patch-src_common_smtp_c --- patches/patch-src_common_smtp_c 17 Oct 2008 12:46:33 -0000 1.1 +++ patches/patch-src_common_smtp_c 3 Apr 2012 13:33:20 -0000 @@ -1,6 +1,6 @@ $OpenBSD: patch-src_common_smtp_c,v 1.1 2008/10/17 12:46:33 landry Exp $ ---- src/common/smtp.c.orig Sat Oct 4 16:19:23 2008 -+++ src/common/smtp.c Sat Oct 4 16:21:59 2008 +--- src/common/smtp.c.orig Fri Dec 16 09:09:34 2011 ++++ src/common/smtp.c Tue Apr 3 13:03:02 2012 @@ -124,7 +124,7 @@ static void smtp_session_destroy(Session *session) gint smtp_from(SMTPSession *session) @@ -9,8 +9,8 @@ $OpenBSD: patch-src_common_smtp_c,v 1.1 + gchar buf[MESSAGEBUFSIZE]; gchar *mail_size = NULL; - g_return_val_if_fail(session->from != NULL, SM_ERROR); -@@ -182,7 +182,7 @@ static gint smtp_auth(SMTPSession *session) + cm_return_val_if_fail(session->from != NULL, SM_ERROR); +@@ -188,7 +188,7 @@ static gint smtp_auth(SMTPSession *session) static gint smtp_auth_recv(SMTPSession *session, const gchar *msg) { @@ -19,7 +19,7 @@ $OpenBSD: patch-src_common_smtp_c,v 1.1 switch (session->auth_type) { case SMTPAUTH_LOGIN: -@@ -258,7 +258,7 @@ static gint smtp_auth_recv(SMTPSession *session, const +@@ -264,7 +264,7 @@ static gint smtp_auth_recv(SMTPSession *session, const static gint smtp_auth_login_user_recv(SMTPSession *session, const gchar *msg) { @@ -28,7 +28,7 @@ $OpenBSD: patch-src_common_smtp_c,v 1.1 session->state = SMTP_AUTH_LOGIN_PASS; -@@ -278,7 +278,7 @@ static gint smtp_auth_login_user_recv(SMTPSession *ses +@@ -284,7 +284,7 @@ static gint smtp_auth_login_user_recv(SMTPSession *ses static gint smtp_ehlo(SMTPSession *session) { @@ -37,7 +37,7 @@ $OpenBSD: patch-src_common_smtp_c,v 1.1 session->state = SMTP_EHLO; -@@ -357,7 +357,7 @@ static gint smtp_auth_cram_md5(SMTPSession *session) +@@ -363,7 +363,7 @@ static gint smtp_auth_cram_md5(SMTPSession *session) static gint smtp_auth_plain(SMTPSession *session) { @@ -46,7 +46,7 @@ $OpenBSD: patch-src_common_smtp_c,v 1.1 /* * +1 +1 +1 -@@ -422,7 +422,7 @@ static gint smtp_auth_login(SMTPSession *session) +@@ -428,7 +428,7 @@ static gint smtp_auth_login(SMTPSession *session) static gint smtp_helo(SMTPSession *session) { @@ -55,7 +55,7 @@ $OpenBSD: patch-src_common_smtp_c,v 1.1 session->state = SMTP_HELO; -@@ -437,7 +437,7 @@ static gint smtp_helo(SMTPSession *session) +@@ -443,7 +443,7 @@ static gint smtp_helo(SMTPSession *session) static gint smtp_rcpt(SMTPSession *session) { @@ -63,4 +63,4 @@ $OpenBSD: patch-src_common_smtp_c,v 1.1 + gchar buf[MESSAGEBUFSIZE]; gchar *to; - g_return_val_if_fail(session->cur_to != NULL, SM_ERROR); + cm_return_val_if_fail(session->cur_to != NULL, SM_ERROR); Index: patches/patch-src_inc_c =================================================================== RCS file: /cvs/ports/mail/claws-mail/patches/patch-src_inc_c,v retrieving revision 1.6 diff -u -p -r1.6 patch-src_inc_c --- patches/patch-src_inc_c 17 Oct 2008 12:46:33 -0000 1.6 +++ patches/patch-src_inc_c 3 Apr 2012 13:33:20 -0000 @@ -1,6 +1,6 @@ $OpenBSD: patch-src_inc_c,v 1.6 2008/10/17 12:46:33 landry Exp $ ---- src/inc.c.orig Thu Sep 18 05:44:28 2008 -+++ src/inc.c Sat Oct 4 16:02:19 2008 +--- src/inc.c.orig Fri Dec 16 09:09:32 2011 ++++ src/inc.c Tue Apr 3 13:03:02 2012 @@ -85,7 +85,7 @@ static GdkPixbuf *currentpix; static GdkPixbuf *errorpix; static GdkPixbuf *okpix; @@ -10,7 +10,7 @@ $OpenBSD: patch-src_inc_c,v 1.6 2008/10/ static void inc_finished (MainWindow *mainwin, gboolean new_messages, -@@ -946,7 +946,7 @@ static void inc_progress_dialog_set_label(IncProgressD +@@ -949,7 +949,7 @@ static void inc_progress_dialog_set_label(IncProgressD static void inc_progress_dialog_set_progress(IncProgressDialog *inc_dialog, IncSession *inc_session) { Index: patches/patch-src_messageview_c =================================================================== RCS file: patches/patch-src_messageview_c diff -N patches/patch-src_messageview_c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-src_messageview_c 3 Apr 2012 13:33:20 -0000 @@ -0,0 +1,15 @@ +$OpenBSD$ +--- src/messageview.c.orig Fri Dec 16 09:09:32 2011 ++++ src/messageview.c Tue Apr 3 13:07:33 2012 +@@ -977,8 +977,9 @@ static gint disposition_notification_send(MsgInfo *msg + extract_address(orig_to); + } + if (msginfo->subject && *(msginfo->subject)) { +- enc_sub = g_malloc0(strlen(msginfo->subject)*8); +- qp_encode_line(enc_sub, (const guchar *)msginfo->subject); ++ gint len = strlen(msginfo->subject); ++ enc_sub = g_malloc0(len*8); ++ qp_encode(TRUE, enc_sub, (const guchar *)msginfo->subject, len); + g_strstrip(enc_sub); + } + ok = fprintf(fp,"MIME-Version: 1.0\n" Index: patches/patch-src_procmime_c =================================================================== RCS file: /cvs/ports/mail/claws-mail/patches/patch-src_procmime_c,v retrieving revision 1.6 diff -u -p -r1.6 patch-src_procmime_c --- patches/patch-src_procmime_c 17 Oct 2008 12:46:33 -0000 1.6 +++ patches/patch-src_procmime_c 3 Apr 2012 13:33:20 -0000 @@ -1,7 +1,87 @@ $OpenBSD: patch-src_procmime_c,v 1.6 2008/10/17 12:46:33 landry Exp $ ---- src/procmime.c.orig Wed Oct 1 03:10:29 2008 -+++ src/procmime.c Sat Oct 4 16:02:19 2008 -@@ -1085,7 +1085,7 @@ GList *procmime_get_mime_type_list(void) +--- src/procmime.c.orig Fri Dec 16 09:09:32 2011 ++++ src/procmime.c Tue Apr 3 14:59:40 2012 +@@ -562,16 +562,29 @@ gboolean procmime_encode_content(MimeInfo *mimeinfo, E + g_free(tmp_file); + } + } else if (encoding == ENC_QUOTED_PRINTABLE) { +- gchar inbuf[BUFFSIZE], outbuf[BUFFSIZE * 4]; ++ gchar inbuf[79], outbuf[77]; ++ gint n, len = 0; ++ gboolean firstrun = TRUE; + +- while (fgets(inbuf, sizeof(inbuf), infp) != NULL) { +- qp_encode_line(outbuf, inbuf); ++ while ((len += fread(inbuf + len, 1, ++ sizeof(inbuf) - len - 1, ++ infp)) > 0) ++ { ++ if (firstrun == FALSE) ++ if (fputs("\r\n", outfp) == EOF) ++ err = TRUE; + ++ inbuf[len] = '\0'; ++ n = qp_encode(mimeinfo->type == MIMETYPE_TEXT, ++ outbuf, inbuf, len); ++ len -= n; ++ memmove(inbuf, inbuf + n, len); ++ + if (!strncmp("From ", outbuf, sizeof("From ")-1)) { + gchar *tmpbuf = outbuf; +- ++ + tmpbuf += sizeof("From ")-1; +- ++ + if (fputs("=46rom ", outfp) == EOF) + err = TRUE; + if (fputs(tmpbuf, outfp) == EOF) +@@ -580,14 +593,40 @@ gboolean procmime_encode_content(MimeInfo *mimeinfo, E + if (fputs(outbuf, outfp) == EOF) + err = TRUE; + } ++ firstrun = FALSE; + } + } else { +- gchar buf[BUFFSIZE]; ++ gchar buf[MAXSMTPTEXTLEN+1]; ++ gint leftover = 0; + +- while (fgets(buf, sizeof(buf), infp) != NULL) { +- strcrchomp(buf); +- if (fputs(buf, outfp) == EOF) ++ while (fgets(buf + leftover, ++ sizeof(buf) - leftover, ++ infp) != NULL) ++ { ++ gchar *l, *c = buf; ++ leftover = 0; ++ ++ while (*c != '\0') { ++ if ( ++ *c == '\n' ++ || (*c == '\r' && *(c+1) == '\n')) ++ { ++ *c = '\0'; ++ break; ++ } ++ c++; ++ } ++ while (c - buf > MAXSMTPTEXTLEN - 2) { ++ *c = *(c-1); ++ *--c = '\0'; ++ leftover++; ++ } ++ ++ if (fputs(buf, outfp) == EOF || putc('\n', outfp) == EOF) + err = TRUE; ++ ++ for (l = buf; l-buf < leftover; l++) ++ *l = *++c; + } + } + +@@ -1094,7 +1133,7 @@ GList *procmime_get_mime_type_list(void) #endif { fp_is_glob_file = FALSE; @@ -10,3 +90,74 @@ $OpenBSD: patch-src_procmime_c,v 1.6 200 if ((fp = g_fopen(SYSCONFDIR "/mime.types", "rb")) == NULL) { FILE_OP_ERROR(SYSCONFDIR "/mime.types", +@@ -1174,11 +1213,12 @@ EncodingType procmime_get_encoding_for_text_file(const + { + FILE *fp; + guchar buf[BUFFSIZE]; ++ gboolean cr = FALSE; + size_t len; ++ gint linelen = 0, maxlinelen = 0; + size_t octet_chars = 0; + size_t total_len = 0; + gfloat octet_percentage; +- gboolean force_b64 = FALSE; + + if ((fp = g_fopen(file, "rb")) == NULL) { + FILE_OP_ERROR(file, "fopen"); +@@ -1190,11 +1230,27 @@ EncodingType procmime_get_encoding_for_text_file(const + gint i; + + for (p = buf, i = 0; i < len; ++p, ++i) { +- if (*p & 0x80) +- ++octet_chars; +- if (*p == '\0') { +- force_b64 = TRUE; ++ switch (*p) { ++ case '\n': ++ if (cr) linelen--; ++ maxlinelen = MAX(linelen, maxlinelen); ++ linelen = 0; ++ cr = FALSE; ++ break; ++ case '\r': ++ cr = TRUE; ++ linelen++; ++ break; ++ case '\0': + *has_binary = TRUE; ++ maxlinelen = G_MAXINT; ++ cr = FALSE; ++ break; ++ default: ++ if (*p & 0x80) ++ octet_chars++; ++ linelen++; ++ cr = FALSE; + } + } + total_len += len; +@@ -1208,15 +1264,20 @@ EncodingType procmime_get_encoding_for_text_file(const + octet_percentage = 0.0; + + debug_print("procmime_get_encoding_for_text_file(): " +- "8bit chars: %zd / %zd (%f%%)\n", octet_chars, total_len, +- 100.0 * octet_percentage); ++ "8bit chars: %zd / %zd (%f%%). " ++ "maximum line length: %d chars\n", ++ octet_chars, total_len, 100.0 * octet_percentage, ++ maxlinelen); + +- if (octet_percentage > 0.20 || force_b64) { ++ if (octet_percentage > 0.20) { + debug_print("using BASE64\n"); + return ENC_BASE64; +- } else if (octet_chars > 0) { ++ } else if (maxlinelen > MAXSMTPTEXTLEN-2) { + debug_print("using quoted-printable\n"); + return ENC_QUOTED_PRINTABLE; ++ } else if (octet_chars > 0) { ++ debug_print("using 8bit\n"); ++ return ENC_8BIT; + } else { + debug_print("using 7bit\n"); + return ENC_7BIT;