From 9fc22b15290a54ef3bac2bbf4831508b1c5c414a Mon Sep 17 00:00:00 2001 From: "Steffen (Daode) Nurpmeso" Date: Thu, 15 Dec 2016 16:28:50 +0100 Subject: [PATCH] Final step to support Base64 with multibyte charsets.. Until now send.c:sendpart(): enabled iconv(3) for FROMB64_T, in order to hook in the intermediate buffer that provides, so in order to avoid that multibyte characters that cross Base64 buffer boundaries get garbled by the makeprint() and delctrl() etc. we apply to the data before showing it on the users' screen. In v15 we will have a filter chain that uses buffers as appropriate, until then hack the support in and keep lingering the buffer around unless we see a NL (or end of message) before performing further modifications and dumping out the data, therefore keeping multibyte sequences (and even charset state machines) intact. --- mime.c | 34 +++++++++++++++++++++++++++++++++- send.c | 22 +++++++++++----------- 2 files changed, 44 insertions(+), 12 deletions(-) diff --git a/mime.c b/mime.c index 3efd9362..489fb9f0 100644 --- a/mime.c +++ b/mime.c @@ -185,8 +185,39 @@ _fwrite_td(struct str const *input, enum tdflags flags, struct str *outrest, if (buf != NULL) free(buf); - } + }else +#endif + /* Else, if we will modify the data bytes and thus introduce the potential + * of messing up multibyte sequences which become splitted over buffer + * boundaries TODO and unless we don't have our filter chain which will + * TODO make these hacks go by, buffer data until we see a NL */ + if((flags & (TD_ISPR | TD_DELCTRL)) && outrest != NULL && +#ifdef HAVE_ICONV + iconvd == (iconv_t)-1 && #endif + (!(flags & _TD_EOF) || outrest->l > 0) + ) { + size_t i; + char *cp; + + for (cp = &in.s[in.l]; cp > in.s && cp[-1] != '\n'; --cp) + ; + i = PTR2SIZE(cp - in.s); + + if (i != in.l) { + if (i > 0) { + n_str_assign_buf(outrest, cp, in.l - i); + cp = smalloc(i +1); + memcpy(cp, in.s, in.l = i); + (in.s = cp)[in.l = i] = '\0'; + flags &= ~_TD_BUFCOPY; + } else { + n_str_add_buf(outrest, input->s, input->l); + rv = 0; + goto jleave; + } + } + } if (flags & TD_ISPR) makeprint(&in, &out); @@ -214,6 +245,7 @@ j__sig: safe_signal(SIGPIPE, __mimefwtd_opipe); if (__mimefwtd_sig != 0) n_raise(__mimefwtd_sig); +jleave: NYD_LEAVE; return rv; } diff --git a/send.c b/send.c index 281ac0e1..87049dea 100644 --- a/send.c +++ b/send.c @@ -986,6 +986,15 @@ jpipe_close: convert = CONV_NONE; } + /* TODO Unless we have filters, ensure iconvd==-1 so that mime.c:fwrite_td() + * TODO cannot mess things up misusing outrest as line buffer */ +#ifdef HAVE_ICONV + if (iconvd != (iconv_t)-1) { + n_iconv_close(iconvd); + iconvd = (iconv_t)-1; + } +#endif + if (action == SEND_DECRYPT || action == SEND_MBOX || action == SEND_RFC822 || action == SEND_SHOW) convert = CONV_NONE; @@ -1000,17 +1009,8 @@ jpipe_close: (mh.mh_flags & MIME_HDL_TYPE_MASK) == MIME_HDL_PTF)) { char const *tcs = charset_get_lc(); - if (iconvd != (iconv_t)-1) - n_iconv_close(iconvd); - /* TODO Since Base64 has an odd 4:3 relation in between input - * TODO and output an input line may end with a partial - * TODO multibyte character; this is no problem at all unless - * TODO we send to the display or whatever, i.e., ensure - * TODO makeprint() or something; to avoid this trap, *force* - * TODO iconv(), in which case this layer will handle leftovers - * TODO correctly. It's a pre-v15 we-have-filters hack */ - if (convert == CONV_FROMB64_T || (asccasecmp(tcs, ip->m_charset) && - asccasecmp(charset_get_7bit(), ip->m_charset))) { + if (asccasecmp(tcs, ip->m_charset) && + asccasecmp(charset_get_7bit(), ip->m_charset)) { iconvd = n_iconv_open(tcs, ip->m_charset); if (iconvd == (iconv_t)-1 && errno == EINVAL) { n_err(_("Cannot convert from %s to %s\n"), ip->m_charset, tcs); -- 2.11.4.GIT