]> code.citadel.org Git - citadel.git/blobdiff - webcit/messages.c
* HTML messages in foreign character sets are now converted to UTF-8 for
[citadel.git] / webcit / messages.c
index 3b8a61e475a684c9f232bafab4ed3e21f2e26f6c..370454c792a02a3eb3804417b9f1bec73d4da6a0 100644 (file)
 #include <stdarg.h>
 #include <pthread.h>
 #include <signal.h>
+
+#ifdef HAVE_ICONV
+#include <iconv.h>
+#endif
+
 #include "webcit.h"
 #include "vcard.h"
 #include "webserver.h"
@@ -37,6 +42,74 @@ struct addrbookent {
 };
 
 
+
+#ifdef HAVE_ICONV
+/* Handle subjects with RFC2047 encoding, such as:
+ * =?koi8-r?B?78bP0s3Mxc7JxSDXz9rE1dvO2c3JINvB0sHNySDP?=
+ */
+void utf8ify_rfc822_string(char *buf) {
+       char *start, *end;
+       char newbuf[1024];
+       char charset[128];
+       char encoding[16];
+       char istr[1024];
+       iconv_t ic = (iconv_t)(-1) ;
+       char *ibuf;                   /* Buffer of characters to be converted */
+       char *obuf;                   /* Buffer for converted characters      */
+       size_t ibuflen;               /* Length of input buffer               */
+       size_t obuflen;               /* Length of output buffer              */
+       char *isav;                   /* Saved pointer to input buffer        */
+       char *osav;                   /* Saved pointer to output buffer       */
+
+       while (start=strstr(buf, "=?"), end=strstr(buf, "?="),
+               ((start != NULL) && (end != NULL) && (end > start)) )
+       {
+               extract_token(charset, start, 1, '?', sizeof charset);
+               extract_token(encoding, start, 2, '?', sizeof encoding);
+               extract_token(istr, start, 3, '?', sizeof istr);
+
+               strcpy(start, "");
+               ++end;
+               ++end;
+
+               ibuf = malloc(1024);
+               isav = ibuf;
+               if (!strcasecmp(encoding, "B")) {       /* base64 */
+                       ibuflen = CtdlDecodeBase64(ibuf, istr, strlen(istr));
+               }
+               else if (!strcasecmp(encoding, "Q")) {  /* quoted-printable */
+                       ibuflen = CtdlDecodeQuotedPrintable(ibuf, istr, strlen(istr));
+               }
+               else {
+                       strcpy(ibuf, istr);             /* huh? */
+                       ibuflen = strlen(istr);
+               }
+
+               ic = iconv_open("UTF-8", charset);
+               if (ic != (iconv_t)(-1) ) {
+                       obuf = malloc(1024);
+                       obuflen = 1024;
+                       obuf = (char *) malloc(obuflen);
+                       osav = obuf;
+                       iconv(ic, &ibuf, &ibuflen, &obuf, &obuflen);
+                       osav[1024-obuflen] = 0;
+                       snprintf(newbuf, sizeof newbuf, "%s%s%s", buf, osav, end);
+                       strcpy(buf, newbuf);
+                       free(osav);
+                       iconv_close(ic);
+               }
+               else {
+                       snprintf(newbuf, sizeof newbuf, "%s(unreadable)%s", buf, end);
+                       strcpy(buf, newbuf);
+               }
+
+               free(isav);
+       }
+
+}
+#endif
+
+
 /*
  * Look for URL's embedded in a buffer and make them linkable.  We use a
  * target window in order to keep the BBS session in its own window.
@@ -405,24 +478,34 @@ void display_vcard(char *vcard_source, char alpha, int full, char *storename) {
  */
 void read_message(long msgnum) {
        char buf[SIZ];
-       char mime_partnum[SIZ];
-       char mime_filename[SIZ];
-       char mime_content_type[SIZ];
-       char mime_disposition[SIZ];
+       char mime_partnum[256];
+       char mime_filename[256];
+       char mime_content_type[256];
+       char mime_charset[256];
+       char mime_disposition[256];
        int mime_length;
        char mime_http[SIZ];
-       char m_subject[SIZ];
-       char from[SIZ];
-       char node[SIZ];
-       char rfca[SIZ];
+       char m_subject[256];
+       char from[256];
+       char node[256];
+       char rfca[256];
        char reply_to[512];
-       char now[SIZ];
+       char now[256];
        int format_type = 0;
        int nhdr = 0;
        int bq = 0;
-       char vcard_partnum[SIZ];
-       char cal_partnum[SIZ];
+       int i = 0;
+       char vcard_partnum[256];
+       char cal_partnum[256];
        char *part_source = NULL;
+#ifdef HAVE_ICONV
+       iconv_t ic = (iconv_t)(-1) ;
+       char *ibuf;                   /* Buffer of characters to be converted */
+       char *obuf;                   /* Buffer for converted characters      */
+       size_t ibuflen;               /* Length of input buffer               */
+       size_t obuflen;               /* Length of output buffer              */
+       char *osav;                   /* Saved pointer to output buffer       */
+#endif
 
        strcpy(from, "");
        strcpy(node, "");
@@ -431,6 +514,8 @@ void read_message(long msgnum) {
        strcpy(vcard_partnum, "");
        strcpy(cal_partnum, "");
        strcpy(mime_http, "");
+       strcpy(mime_content_type, "text/plain");
+       strcpy(mime_charset, "us-ascii");
 
        serv_printf("MSG4 %ld", msgnum);
        serv_getln(buf, sizeof buf);
@@ -466,6 +551,9 @@ void read_message(long msgnum) {
                if (!strncasecmp(buf, "from=", 5)) {
                        strcpy(from, &buf[5]);
                        wprintf("from <A HREF=\"/showuser&who=");
+#ifdef HAVE_ICONV
+                       utf8ify_rfc822_string(from);
+#endif
                        urlescputs(from);
                        wprintf("\">");
                        escputs(from);
@@ -517,7 +605,7 @@ void read_message(long msgnum) {
                                        "<A HREF=\"/output_mimepart?"
                                        "msgnum=%ld&partnum=%s\" "
                                        "TARGET=\"wc.%ld.%s\">"
-                                       "<IMG SRC=\"/static/attachment.gif\" "
+                                       "<IMG SRC=\"/static/diskette_24x.gif\" "
                                        "BORDER=0 ALIGN=MIDDLE>\n"
                                        "Part %s: %s (%s, %d bytes)</A><br />\n",
                                        msgnum, mime_partnum,
@@ -571,6 +659,9 @@ void read_message(long msgnum) {
        }
 
        wprintf("</SPAN>");
+#ifdef HAVE_ICONV
+       utf8ify_rfc822_string(m_subject);
+#endif
        if (strlen(m_subject) > 0) {
                wprintf("<br />"
                        "<SPAN CLASS=\"message_subject\">"
@@ -622,8 +713,30 @@ void read_message(long msgnum) {
                if (!strncasecmp(buf, "Content-type: ", 14)) {
                        safestrncpy(mime_content_type, &buf[14],
                                sizeof(mime_content_type));
+                       for (i=0; i<strlen(mime_content_type); ++i) {
+                               if (!strncasecmp(&mime_content_type[i], "charset=", 8)) {
+                                       safestrncpy(mime_charset, &mime_content_type[i+8],
+                                               sizeof mime_charset);
+                               }
+                       }
+                       for (i=0; i<strlen(mime_content_type); ++i) {
+                               if (mime_content_type[i] == ';') {
+                                       mime_content_type[i] = 0;
+                               }
+                       }
+               }
+       }
+
+       /* Set up a character set conversion if we need to (and if we can) */
+#ifdef HAVE_ICONV
+       if ( (strcasecmp(mime_charset, "us-ascii"))
+          && (strcasecmp(mime_charset, "UTF-8")) ) {
+               ic = iconv_open("UTF-8", mime_charset);
+               if (ic == (iconv_t)(-1) ) {
+                       lprintf(5, "iconv_open() failed: %s\n", strerror(errno));
                }
        }
+#endif
 
        /* Messages in legacy Citadel variformat get handled thusly... */
        if (!strcasecmp(mime_content_type, "text/x-citadel-variformat")) {
@@ -635,6 +748,21 @@ void read_message(long msgnum) {
                while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
                        if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = 0;
                        if (buf[strlen(buf)-1] == '\r') buf[strlen(buf)-1] = 0;
+
+#ifdef HAVE_ICONV
+                       if (ic != (iconv_t)(-1) ) {
+                               ibuf = buf;
+                               ibuflen = strlen(ibuf);
+                               obuflen = SIZ;
+                               obuf = (char *) malloc(obuflen);
+                               osav = obuf;
+                               iconv(ic, &ibuf, &ibuflen, &obuf, &obuflen);
+                               osav[SIZ-obuflen] = 0;
+                               safestrncpy(buf, osav, sizeof buf);
+                               free(osav);
+                       }
+#endif
+
                        while ((strlen(buf) > 0) && (isspace(buf[strlen(buf) - 1])))
                                buf[strlen(buf) - 1] = 0;
                        if ((bq == 0) &&
@@ -656,7 +784,7 @@ void read_message(long msgnum) {
 
        else /* HTML is fun, but we've got to strip it first */
        if (!strcasecmp(mime_content_type, "text/html")) {
-               output_html();
+               output_html(mime_charset);
        }
 
        /* Unknown weirdness */
@@ -666,7 +794,6 @@ void read_message(long msgnum) {
                while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) { }
        }
 
-
        /* Afterwards, offer links to download attachments 'n' such */
        if (strlen(mime_http) > 0) {
                wprintf("%s", mime_http);
@@ -713,6 +840,12 @@ ENDBODY:
        /* end everythingamundo table */
        wprintf("</TD></TR></TABLE>\n");
        wprintf("</div><br />\n");
+
+#ifdef HAVE_ICONV
+       if (ic != (iconv_t)(-1) ) {
+               iconv_close(ic);
+       }
+#endif
 }
 
 
@@ -743,6 +876,10 @@ void summarize_message(long msgnum, int is_new) {
                if (!strncasecmp(buf, "subj=", 5)) {
                        if (strlen(&buf[5]) > 0) {
                                strcpy(summ.subj, &buf[5]);
+#ifdef HAVE_ICONV
+                               /* Handle subjects with RFC2047 encoding */
+                               utf8ify_rfc822_string(summ.subj);
+#endif
                                if (strlen(summ.subj) > 75) {
                                        strcpy(&summ.subj[72], "...");
                                }
@@ -773,6 +910,10 @@ void summarize_message(long msgnum, int is_new) {
                }
        }
        
+#ifdef HAVE_ICONV
+       /* Handle senders with RFC2047 encoding */
+       utf8ify_rfc822_string(summ.from);
+#endif
        if (strlen(summ.from) > 25) {
                strcpy(&summ.from[22], "...");
        }
@@ -1723,7 +1864,7 @@ void display_enter(void)
                "</script></center><br />\n");
 
        /* Enumerate any attachments which are already in place... */
-       wprintf("<img src=\"/static/attachment.gif\" border=0 "
+       wprintf("<img src=\"/static/diskette_24x.gif\" border=0 "
                "align=middle height=16 width=16> Attachments: ");
        wprintf("<select name=\"which_attachment\" size=1>");
        for (att = WC->first_attachment; att != NULL; att = att->next) {