The previous patch didn't work if the webcit/ prefix wasn't used.
This patch covers the case when webcit/ prefix is not used.
Sam
Index: debian/control
===================================================================
--- debian/control (revision 6707)
+++ debian/control (working copy)
@@ -3,7 +3,7 @@
Priority: optional
Maintainer: Wilfried Goesgens <[EMAIL PROTECTED]>
Build-Depends: debhelper (>= 4), po-debconf, libical-dev (>=0.30), gettext, locales,
- libcitadel-dev
+ libcitadel-dev, libtidy-dev, libxml-dev
Standards-Version: 3.7.2
Package: citadel-webcit
Index: webserver.c
===================================================================
--- webserver.c (revision 6707)
+++ webserver.c (working copy)
@@ -610,6 +610,11 @@
unlink(pid_file);
}
ShutDownLibCitadel ();
+#ifdef HAVE_XSLT
+ xsltCleanupGlobals();
+ xmlCleanupParser();
+ xmlCleanupThreads();
+#endif
exit(WEXITSTATUS(status));
}
@@ -870,6 +875,11 @@
perror("chdir");
}
LoadIconDir(static_icon_dir);
+#ifdef HAVE_XSLT
+ xsltInit();
+ xsltRegisterAllExtras();
+ exsltRegisterAll();
+#endif
InitTemplateCache();
initialise_modules();
Index: configure.ac
===================================================================
--- configure.ac (revision 6707)
+++ configure.ac (working copy)
@@ -191,10 +191,42 @@
]
)
+dnl Checks for libtidy
+PKG_CHECK_MODULES([TIDY], [libtidy], [
+ ok_libtidy=yes
+ LIBS="$TIDY_LIBS $LIBS"
+ CFLAGS="$TIDY_CFLAGS $LIBS"
+ AC_DEFINE(HAVE_TIDY,[],[whether we have libtidy])
+],[ dnl find libtidy the hard way
+ for location in /usr /usr/local/
+ do
+ for suffix in include include/tidy
+ do
+ test -r "$location/$suffix/tidy.h" && break
+ done
+ test -r "$location/$suffix/tidy.h" && break
+ done
+ if test -r "$location/$suffix/tidy.h"
+ then
+ LIBS="-ltidy $LIBS"
+ CFLAGS="-I$location/$suffix"
+ AC_DEFINE(HAVE_TIDY,[],[whether we have libtidy])
+ fi
+])
+
+dnl Checks for libxslt AND libexslt (same package)
+PKG_CHECK_MODULES([XSLT], [libxslt >= 1.1 libexslt >= 0.8 libxml >= 1.8.4], [
+ ok_libxslt=yes
+ LIBS="$XSLT_LIBS $LIBS"
+ CFLAGS="$XSLT_CFLAGS $CFLAGS"
+ AC_DEFINE(HAVE_XSLT,[],[whether we have libxslt])
+])
+
dnl Checks for the libical iCalendar library.
+dnl icalcomponent_as_ical_string_r,
AC_CHECK_HEADER(libical/ical.h,
- [AC_CHECK_LIB(ical, icalcomponent_as_ical_string_r,
+ [AC_CHECK_LIB(ical, icalcomponent_new,
[
LIBS="-lical $LIBS"
],
@@ -209,6 +241,10 @@
)
+if test "x$ok_zlib" = xyes ; then
+ LIBS="-lz $LIBS"
+ AC_DEFINE(HAVE_ZLIB,[],[whether we have zlib])
+fi
# The big search for OpenSSL
if test "$with_ssl" != "no"; then
Index: tiny_mce/themes/advanced/image.htm
===================================================================
--- tiny_mce/themes/advanced/image.htm (revision 6707)
+++ tiny_mce/themes/advanced/image.htm (working copy)
@@ -5,6 +5,7 @@
<script language="javascript" type="text/javascript" src="../../utils/mctabs.js"></script>
<script language="javascript" type="text/javascript" src="../../utils/form_utils.js"></script>
<script language="javascript" type="text/javascript" src="jscripts/image.js"></script>
+ <script language="javascript" type="text/javascript" src="/webcit/postpart/image/images.js"></script>
<base target="_self" />
</head>
<body id="image" onload="tinyMCEPopup.executeOnLoad('init();');" style="display: none">
Index: html2html.c
===================================================================
--- html2html.c (revision 6707)
+++ html2html.c (working copy)
@@ -9,8 +9,25 @@
/[EMAIL PROTECTED]/
#include "webcit.h"
#include "webserver.h"
+#ifdef HAVE_TIDY
+#include <tidy.h>
+#include <buffio.h>
+#endif
+#ifdef HAVE_XSLT
+#include <libxml/xmlmemory.h>
+#include <libxml/debugXML.h>
+#include <libxml/HTMLtree.h>
+#include <libxml/xmlIO.h>
+#include <libxml/xinclude.h>
+#include <libxml/catalog.h>
+#include <libxslt/xslt.h>
+#include <libxslt/xsltInternals.h>
+#include <libxslt/transform.h>
+#include <libxslt/xsltutils.h>
+#include "libexslt/exslt.h"
+#include <libexslt/exsltconfig.h>
+#endif
-
/**
* \brief Strip surrounding single or double quotes from a string.
*
@@ -73,18 +90,8 @@
}
}
-
-
-/**
- * \brief Sanitize and enhance an HTML message for display.
- * Also convert weird character sets to UTF-8 if necessary.
- * Also fixup img src="cid:..." type inline images to fetch the image
- *
- * \param supplied_charset the input charset as declared in the MIME headers
- */
-void output_html(char *supplied_charset, int treat_as_wiki, int msgnum) {
- char buf[SIZ];
- char *msg;
+#ifndef HAVE_XSLT
+StrBuf * clean_html(char* msg, int treat_as_wiki, int msgnum) {
char *ptr;
char *msgstart;
char *msgend;
@@ -109,160 +116,6 @@
char *osav; /**< Saved pointer to output buffer */
#endif
- safestrncpy(charset, supplied_charset, sizeof charset);
- msg = strdup("");
- sprintf(new_window, "<a target=\"%s\" href=", TARGET);
-
- while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
- line_length = strlen(buf);
- buffer_length = content_length + line_length + 2;
- ptr = realloc(msg, buffer_length);
- if (ptr == NULL) {
- wprintf("<b>");
- wprintf(_("realloc() error! couldn't get %d bytes: %s"),
- buffer_length + 1,
- strerror(errno));
- wprintf("</b><br /><br />\n");
- while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
- /** flush */
- }
- free(msg);
- return;
- }
- msg = ptr;
- strcpy(&msg[content_length], buf);
- content_length += line_length;
- strcpy(&msg[content_length], "\n");
- content_length += 1;
- }
-
- /** Do a first pass to isolate the message body */
- ptr = msg + 1;
- msgstart = msg;
- msgend = &msg[content_length];
-
- while (ptr < msgend) {
-
- /** Advance to next tag */
- ptr = strchr(ptr, '<');
- if ((ptr == NULL) || (ptr >= msgend)) break;
- ++ptr;
- if ((ptr == NULL) || (ptr >= msgend)) break;
-
- /**
- * Look for META tags. Some messages (particularly in
- * Asian locales) illegally declare a message's character
- * set in the HTML instead of in the MIME headers. This
- * is wrong but we have to work around it anyway.
- */
- if (!strncasecmp(ptr, "META", 4)) {
-
- char *meta_start;
- char *meta_end;
- int meta_length;
- char *meta;
- char *meta_http_equiv;
- char *meta_content;
- char *spaceptr;
-
- meta_start = &ptr[4];
- meta_end = strchr(ptr, '>');
- if ((meta_end != NULL) && (meta_end <= msgend)) {
- meta_length = meta_end - meta_start + 1;
- meta = malloc(meta_length + 1);
- safestrncpy(meta, meta_start, meta_length);
- meta[meta_length] = 0;
- striplt(meta);
- if (!strncasecmp(meta, "HTTP-EQUIV=", 11)) {
- meta_http_equiv = strdup(&meta[11]);
- spaceptr = strchr(meta_http_equiv, ' ');
- if (spaceptr != NULL) {
- *spaceptr = 0;
- meta_content = strdup(++spaceptr);
- if (!strncasecmp(meta_content, "content=", 8)) {
- strcpy(meta_content, &meta_content[8]);
- stripquotes(meta_http_equiv);
- stripquotes(meta_content);
- extract_charset_from_meta(charset,
- meta_http_equiv, meta_content);
- }
- free(meta_content);
- }
- free(meta_http_equiv);
- }
- free(meta);
- }
- }
-
- /**
- * Any of these tags cause everything up to and including
- * the tag to be removed.
- */
- if ( (!strncasecmp(ptr, "HTML", 4))
- ||(!strncasecmp(ptr, "HEAD", 4))
- ||(!strncasecmp(ptr, "/HEAD", 5))
- ||(!strncasecmp(ptr, "BODY", 4)) ) {
- ptr = strchr(ptr, '>');
- if ((ptr == NULL) || (ptr >= msgend)) break;
- ++ptr;
- if ((ptr == NULL) || (ptr >= msgend)) break;
- msgstart = ptr;
- }
-
- /**
- * Any of these tags cause everything including and following
- * the tag to be removed.
- */
- if ( (!strncasecmp(ptr, "/HTML", 5))
- ||(!strncasecmp(ptr, "/BODY", 5)) ) {
- --ptr;
- msgend = ptr;
- strcpy(ptr, "");
-
- }
-
- ++ptr;
- }
- if (msgstart > msg) {
- strcpy(msg, msgstart);
- }
-
- /** Convert foreign character sets to UTF-8 if necessary. */
-#ifdef HAVE_ICONV
- if ( (strcasecmp(charset, "us-ascii"))
- && (strcasecmp(charset, "UTF-8"))
- && (strcasecmp(charset, ""))
- ) {
- lprintf(9, "Converting %s to UTF-8\n", charset);
- ic = ctdl_iconv_open("UTF-8", charset);
- if (ic == (iconv_t)(-1) ) {
- lprintf(5, "%s:%d iconv_open() failed: %s\n",
- __FILE__, __LINE__, strerror(errno));
- }
- }
- if (ic != (iconv_t)(-1) ) {
- ibuf = msg;
- ibuflen = content_length;
- obuflen = content_length + (content_length / 2) ;
- obuf = (char *) malloc(obuflen);
- osav = obuf;
- iconv(ic, &ibuf, &ibuflen, &obuf, &obuflen);
- content_length = content_length + (content_length / 2) - obuflen;
- osav[content_length] = 0;
- free(msg);
- msg = osav;
- iconv_close(ic);
- }
-#endif
-
- /**
- * At this point, the message has been stripped down to
- * only the content inside the <BODY></BODY> tags, and has
- * been converted to UTF-8 if it was originally in a foreign
- * character set. The text is also guaranteed to be null
- * terminated now.
- */
-
/** Now go through the message, parsing tags as necessary. */
converted_msg = NewStrBufPlain(NULL, content_length + 8192);
if (converted_msg == NULL) {
@@ -443,12 +296,294 @@
if (!strncasecmp(ptr, "</A>", 3)) --alevel;
}
+ return converted_msg;
+BAIL:
+ FreeStrBuf(&converted_msg);
+ return NULL;
+}
+
+#else
+
+StrBuf *clean_html(const char* input, int treat_as_wiki, int msgnum) {
+ xsltStylesheetPtr cur = NULL;
+ xmlDocPtr doc=NULL;
+ xmlDocPtr res = NULL;
+ const char *params[16 + 1];
+ char *_output=NULL;
+ StrBuf *output=NULL;
+ int len=0;
+ char _msgnum[10];
+
+ xmlSubstituteEntitiesDefault(1);
+ xmlLoadExtDtdDefaultValue = 0;
+#ifdef HAVE_TIDY
+ {
+ uint len=0;
+ char* xhtml=NULL;
+ TidyDoc tdoc = tidyCreate(); // Initialize "document"
+
+ if (tdoc) {
+ /* my favourite generate xhtml spell is:
+ * tidy -f /dev/stderr -n --output-xhtml y --indent "auto"
+ * --wrap "900" -q --force-output yes -asxhtml --add-xml-decl yes "$@"
+ */
+ tidyOptSetBool(tdoc, TidyXhtmlOut, yes); // --output-xhtml y | -asxhtml
+ tidyOptSetBool(tdoc, TidyForceOutput, yes); //--force-output yes
+ tidyOptSetInt(tdoc, TidyIndentContent, TidyAutoState); // --indent "auto"
+ tidyOptSetBool(tdoc, TidyXmlDecl, yes); // --add-xml-decl yes
+ tidyOptSetBool(tdoc, TidyQuiet, yes); // -q
+ tidyOptSetBool(tdoc, TidyNumEntities, yes); // -n
+ tidySetInCharEncoding(tdoc, "utf8");
+ tidySetOutCharEncoding(tdoc, "utf8");
+ //--wrap "900" -f /dev/stderr -n
+
+ tidyParseString(tdoc, input);
+ tidyCleanAndRepair(tdoc);
+ tidySaveString(tdoc, NULL, &len);
+ xhtml=malloc(len+1);
+ if (xhtml) {
+ tidySaveString(tdoc, xhtml, &len);
+ tidyRelease(tdoc);
+ doc = htmlParseDoc((const xmlChar*)xhtml,"utf8");
+ free(xhtml);
+ } else {
+ tidyRelease(tdoc);
+ }
+ }
+ }
+#endif
+ /* also a fallback if tidy fails */
+ if (! doc) doc = htmlParseDoc((const xmlChar*)input, "utf8");
+ if (! doc) goto done;
+
+ /* Setup xslt arguments msgnum and treat_as_wiki */
+ snprintf(_msgnum, sizeof(_msgnum) -1, "%d", msgnum);
+ params[0]="msgnum";
+ params[1]=_msgnum;
+ params[2]="treat_as_wiki";
+ params[3]=treat_as_wiki?"yes":"no";
+ params[4]=NULL;
+
+ /* parse template. This should probably be done at startup */
+ cur = xsltParseStylesheetFile((const xmlChar *)WWWDIR "/static/clean_html.xslt");
+
+ res = xsltApplyStylesheet(cur, doc, params);
+ if (res) {
+
+ xsltSaveResultToString(&_output, &len, res, cur);
+ }
+
+ output=_NewConstStrBuf(_output, len);
+ if (! output) free(_output);
+
+done:
+ if (cur) xsltFreeStylesheet(cur);
+ if (res) xmlFreeDoc(res);
+ if (doc) xmlFreeDoc(doc);
+
+ return output;
+}
+
+#endif
+
+/**
+ * \brief Sanitize and enhance an HTML message for display.
+ * Also convert weird character sets to UTF-8 if necessary.
+ * Also fixup img src="cid:..." type inline images to fetch the image
+ *
+ * \param supplied_charset the input charset as declared in the MIME headers
+ */
+void output_html(char *supplied_charset, int treat_as_wiki, int msgnum) {
+ char buf[SIZ];
+ char *msg;
+ char *ptr;
+ char *msgstart;
+ char *msgend;
+ StrBuf *converted_msg;
+ int buffer_length = 1;
+ int line_length = 0;
+ int content_length = 0;
+ char new_window[SIZ];
+ int brak = 0;
+ int alevel = 0;
+ int scriptlevel = 0;
+ int script_start_pos = (-1);
+ int i;
+ int linklen;
+ char charset[128];
+#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
+
+ safestrncpy(charset, supplied_charset, sizeof charset);
+ msg = strdup("");
+ sprintf(new_window, "<a target=\"%s\" href=", TARGET);
+
+ while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
+ line_length = strlen(buf);
+ buffer_length = content_length + line_length + 2;
+ ptr = realloc(msg, buffer_length);
+ if (ptr == NULL) {
+ wprintf("<b>");
+ wprintf(_("realloc() error! couldn't get %d bytes: %s"),
+ buffer_length + 1,
+ strerror(errno));
+ wprintf("</b><br /><br />\n");
+ while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
+ /** flush */
+ }
+ free(msg);
+ return;
+ }
+ msg = ptr;
+ strcpy(&msg[content_length], buf);
+ content_length += line_length;
+ strcpy(&msg[content_length], "\n");
+ content_length += 1;
+ }
+
+ /** Do a first pass to isolate the message body */
+ ptr = msg + 1;
+ msgstart = msg;
+ msgend = &msg[content_length];
+
+ while (ptr < msgend) {
+
+ /** Advance to next tag */
+ ptr = strchr(ptr, '<');
+ if ((ptr == NULL) || (ptr >= msgend)) break;
+ ++ptr;
+ if ((ptr == NULL) || (ptr >= msgend)) break;
+
+ /**
+ * Look for META tags. Some messages (particularly in
+ * Asian locales) illegally declare a message's character
+ * set in the HTML instead of in the MIME headers. This
+ * is wrong but we have to work around it anyway.
+ */
+ if (!strncasecmp(ptr, "META", 4)) {
+
+ char *meta_start;
+ char *meta_end;
+ int meta_length;
+ char *meta;
+ char *meta_http_equiv;
+ char *meta_content;
+ char *spaceptr;
+
+ meta_start = &ptr[4];
+ meta_end = strchr(ptr, '>');
+ if ((meta_end != NULL) && (meta_end <= msgend)) {
+ meta_length = meta_end - meta_start + 1;
+ meta = malloc(meta_length + 1);
+ safestrncpy(meta, meta_start, meta_length);
+ meta[meta_length] = 0;
+ striplt(meta);
+ if (!strncasecmp(meta, "HTTP-EQUIV=", 11)) {
+ meta_http_equiv = strdup(&meta[11]);
+ spaceptr = strchr(meta_http_equiv, ' ');
+ if (spaceptr != NULL) {
+ *spaceptr = 0;
+ meta_content = strdup(++spaceptr);
+ if (!strncasecmp(meta_content, "content=", 8)) {
+ strcpy(meta_content, &meta_content[8]);
+ stripquotes(meta_http_equiv);
+ stripquotes(meta_content);
+ extract_charset_from_meta(charset,
+ meta_http_equiv, meta_content);
+ }
+ free(meta_content);
+ }
+ free(meta_http_equiv);
+ }
+ free(meta);
+ }
+ }
+
+ /**
+ * Any of these tags cause everything up to and including
+ * the tag to be removed.
+ */
+ if ( (!strncasecmp(ptr, "HTML", 4))
+ ||(!strncasecmp(ptr, "HEAD", 4))
+ ||(!strncasecmp(ptr, "/HEAD", 5))
+ ||(!strncasecmp(ptr, "BODY", 4)) ) {
+ ptr = strchr(ptr, '>');
+ if ((ptr == NULL) || (ptr >= msgend)) break;
+ ++ptr;
+ if ((ptr == NULL) || (ptr >= msgend)) break;
+ msgstart = ptr;
+ }
+
+ /**
+ * Any of these tags cause everything including and following
+ * the tag to be removed.
+ */
+ if ( (!strncasecmp(ptr, "/HTML", 5))
+ ||(!strncasecmp(ptr, "/BODY", 5)) ) {
+ --ptr;
+ msgend = ptr;
+ strcpy(ptr, "");
+
+ }
+
+ ++ptr;
+ }
+ if (msgstart > msg) {
+ strcpy(msg, msgstart);
+ }
+
+ /** Convert foreign character sets to UTF-8 if necessary. */
+#ifdef HAVE_ICONV
+ if ( (strcasecmp(charset, "us-ascii"))
+ && (strcasecmp(charset, "UTF-8"))
+ && (strcasecmp(charset, ""))
+ ) {
+ lprintf(9, "Converting %s to UTF-8\n", charset);
+ ic = ctdl_iconv_open("UTF-8", charset);
+ if (ic == (iconv_t)(-1) ) {
+ lprintf(5, "%s:%d iconv_open() failed: %s\n",
+ __FILE__, __LINE__, strerror(errno));
+ }
+ }
+ if (ic != (iconv_t)(-1) ) {
+ ibuf = msg;
+ ibuflen = content_length;
+ obuflen = content_length + (content_length / 2) ;
+ obuf = (char *) malloc(obuflen);
+ osav = obuf;
+ iconv(ic, &ibuf, &ibuflen, &obuf, &obuflen);
+ content_length = content_length + (content_length / 2) - obuflen;
+ osav[content_length] = 0;
+ free(msg);
+ msg = osav;
+ iconv_close(ic);
+ }
+#endif
+
+ /**
+ * At this point, the message has been stripped down to
+ * only the content inside the <BODY></BODY> tags, and has
+ * been converted to UTF-8 if it was originally in a foreign
+ * character set. The text is also guaranteed to be null
+ * terminated now.
+ */
+
+ converted_msg = clean_html(msg, treat_as_wiki, msgnum);
+
/** uncomment these two lines to override conversion */
/** memcpy(converted_msg, msg, content_length); */
/** output_length = content_length; */
/** Output our big pile of markup */
- StrBufAppendBuf(WC->WBuf, converted_msg, 0);
+ if (converted_msg) {
+ StrBufAppendBuf(WC->WBuf, converted_msg, 0);
+ }
BAIL: /** A little trailing vertical whitespace... */
wprintf("<br /><br />\n");
@@ -459,3 +594,4 @@
}
/[EMAIL PROTECTED]/
+
Index: sieve.c
===================================================================
--- sieve.c (revision 6707)
+++ sieve.c (working copy)
@@ -5,7 +5,7 @@
#include "webcit.h"
#define MAX_SCRIPTS 100
-#define MAX_RULES 25
+#define MAX_RULES 50
#define RULES_SCRIPT "__WebCit_Generated_Script__"
Index: webcit.c
===================================================================
--- webcit.c (revision 6707)
+++ webcit.c (working copy)
@@ -959,9 +959,34 @@
void postpart(const char *partnum, const char *filename, int force_download)
{
char content_type[256];
- int num = atoi(partnum);
+ char *mime=NULL;
+ int num = strtol(partnum, &mime, 10);
struct wc_attachment *part = WC->first_attachment;
+ if (mime == partnum) {
+ int len = strlen(mime);
+ int count = 0;
+ /* Must be a mime type prefix, out put js list of parts */
+ output_headers(0, 0, 0, 0, 0, 0);
+ while(part) {
+ if (strncmp(mime, part->content_type, len)==0 && part->is_inline) {
+ if (! count) {
+ StrBufAppendBufPlain(WC->WBuf, "var tinyMCEImageList = new Array(\n", -1, 0);
+ } else {
+ StrBufAppendBufPlain(WC->WBuf, ", ", -1, 0);
+ }
+ StrBufAppendPrintf(WC->WBuf, "[\"%s\", \"/webcit/postpart/%d/%s\"]", part->filename, count, part->filename);
+ count++;
+ }
+ part=part->next;
+ }
+ if (count) {
+ StrBufAppendBufPlain(WC->WBuf, ");", -1, 0);
+ }
+ http_transmit_thing("application/x-javascript", 0);
+ return;
+ }
+
while(num && part) {
num--;
part=part->next;
Index: webcit.h
===================================================================
--- webcit.h (revision 6707)
+++ webcit.h (working copy)
@@ -388,6 +388,7 @@
char filename[SIZ]; /* the filename hooked to this content ??? */
char *data; /* the data pool; aka this content */
long lvalue; /* if we put a long... */
+ int is_inline; /* if this will be multipart/related with the main message */
};
/*
Index: static/clean_html.xslt
===================================================================
--- static/clean_html.xslt (revision 0)
+++ static/clean_html.xslt (revision 0)
@@ -0,0 +1,182 @@
+<xsl:transform version="1.0"
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xhtml="http://www.w3.org/1999/xhtml"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:date="http://exslt.org/dates-and-times"
+ xmlns:str="http://exslt.org/strings"
+ xmlns:func="http://exslt.org/functions"
+ xmlns:exsl="http://exslt.org/common"
+ extension-element-prefixes="date str func exsl"
+ exclude-result-prefixes="xhtml"
+>
+ <xsl:namespace-alias stylesheet-prefix="#default" result-prefix="xhtml"/>
+<!-- <xsl:output method = "xml" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" indent="yes" /> -->
+ <xsl:output method = "xml" indent="yes" omit-xml-declaration="yes"/>
+<!-- <xsl:strip-space elements="*" /> -->
+ <xsl:param name="msgnum" select="1"/>
+ <xsl:param name="treat_as_wiki">no</xsl:param>
+
+
+ <xsl:template match="/">
+ <div>
+ <!-- output only the body -->
+ <xsl:choose>
+ <xsl:when test="//node()[local-name()='body']">
+ <xsl:apply-templates select="//node()[local-name()='body']/node()"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates select="node()"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </div>
+ </xsl:template>
+
+ <!-- Convert mailto links to webcit compose links -->
+ <xsl:template match="@href[starts-with(.,'mailto:')]">
+ <xsl:attribute name="{name()}">
+ <xsl:value-of select="concat('/webcit/display_enter?force_room=_MAIL_&recp=',substring-after(.,'mailto:'))"/>
+ </xsl:attribute>
+ </xsl:template>
+
+ <!-- convert cid: links or src, to fetch the mime-part -->
+ <xsl:template match="@src[starts-with(.,'cid:')]|@href[starts-with(.,'cid:')]">
+ <xsl:attribute name="{name()}">
+ <xsl:value-of select="concat('/webcit/mimepart/',$msgnum,'/',substring-after(.,'cid:'),'/')"/>
+ </xsl:attribute>
+ </xsl:template>
+
+ <!-- remove all script linkes -->
+ <xsl:template match="node()[local-name()='script']"/>
+
+ <!-- remove all script handler attributes, for now defined as any attribute beginning with "on" -->
+ <xsl:template match="@onclick|@*[starts-with(.,'on')]" />
+
+ <!-- remove all target links from href tags -->
+ <xsl:template match="node()[local-name()='a']/@target"/>
+
+ <!-- add a target tag for all links except mailto: tags -->
+ <!-- TODO: and wiki tags and CERTAIN other non absolute tags -->
+ <xsl:template match="node()[local-name()='a' and @href and not(starts-with(@href,'mailto:'))]">
+ <xsl:copy>
+ <xsl:attribute name="target">_blank</xsl:attribute>
+ <xsl:apply-templates select="@*[local-name()!='target']|node()" />
+ </xsl:copy>
+ </xsl:template>
+
+ <!-- enhance text by making <a>'s out of urls and email addresses -->
+ <xsl:template match="text()">
+ <xsl:for-each select="str:tokenalize(.)">
+ <xsl:choose>
+ <xsl:when test="starts-with(., 'http:')">
+ <a href="{.}" target="_blank"><xsl:value-of select="."/></a>
+ </xsl:when>
+ <xsl:when test="starts-with(., 'www.')">
+ <a href="http://{.}" target="_blank"><xsl:value-of select="."/></a>
+ </xsl:when>
+ <xsl:when test="starts-with(., 'mailto:')">
+ <a href="{concat('/webcit/display_enter?force_room=_MAIL_&recp=',substring-after(.,'mailto:'))}"><xsl:value-of select="."/></a>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="."/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+ </xsl:template>
+
+ <!-- default pass-through all other attributes -->
+ <xsl:template match="@*" name="fixup-text">
+ <xsl:copy/>
+ </xsl:template>
+
+ <!-- default pass-through all other tags -->
+ <xsl:template match="node()">
+ <xsl:copy>
+ <!-- with libxslt xsltproc we can't do @*|node() or the nodes may get processed before the attributes -->
+ <xsl:apply-templates select="@*"/>
+ <xsl:apply-templates select="node()"/>
+ </xsl:copy>
+ </xsl:template>
+
+<!-- str:tokenalize - like str:tokenize, but also returns the tokens
+ based on str:tokenize by Jeni Tennison
+ from: http://www.exslt.org/str/functions/tokenize/str.tokenize.function.xsl -->
+
+<!-- <xsl:if test="not(function-available('str:tokenalize'))"> -->
+<func:function name="str:tokenalize">
+ <xsl:param name="string" select="''" />
+ <xsl:param name="delimiters" select="' 	
'" />
+ <xsl:choose>
+ <xsl:when test="not($string)">
+ <func:result select="/.." />
+ </xsl:when>
+ <xsl:when test="not(function-available('exsl:node-set'))">
+
+ <xsl:message terminate="yes">
+ ERROR: EXSLT - Functions implementation of str:tokenalize relies on exsl:node-set().
+ </xsl:message>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:variable name="tokens">
+ <xsl:choose>
+ <xsl:when test="not($delimiters)">
+ <xsl:call-template name="str:_tokenalize-characters">
+ <xsl:with-param name="string" select="$string" />
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="str:_tokenalize-delimiters">
+ <xsl:with-param name="string" select="$string" />
+ <xsl:with-param name="delimiters" select="$delimiters" />
+ </xsl:call-template>
+ </xsl:otherwise>
+
+ </xsl:choose>
+ </xsl:variable>
+ <func:result select="exsl:node-set($tokens)/*" />
+ </xsl:otherwise>
+ </xsl:choose>
+</func:function>
+
+<xsl:template name="str:_tokenalize-characters">
+ <xsl:param name="string" />
+ <xsl:if test="$string">
+ <token><xsl:value-of select="substring($string, 1, 1)" /></token>
+ <xsl:call-template name="str:_tokenalize-characters">
+ <xsl:with-param name="string" select="substring($string, 2)" />
+ </xsl:call-template>
+ </xsl:if>
+</xsl:template>
+
+<xsl:template name="str:_tokenalize-delimiters">
+ <xsl:param name="string" />
+ <xsl:param name="delimiters" />
+
+ <xsl:variable name="delimiter" select="substring($delimiters, 1, 1)" />
+ <xsl:choose>
+ <xsl:when test="not($delimiter)">
+ <token><xsl:value-of select="$string" /></token>
+ </xsl:when>
+ <xsl:when test="contains($string, $delimiter)">
+ <xsl:if test="not(starts-with($string, $delimiter))">
+ <xsl:call-template name="str:_tokenalize-delimiters">
+ <xsl:with-param name="string" select="substring-before($string, $delimiter)" />
+ <xsl:with-param name="delimiters" select="substring($delimiters, 2)" />
+ </xsl:call-template>
+ </xsl:if>
+ <delimiter><xsl:value-of select="$delimiter"/></delimiter>
+ <xsl:call-template name="str:_tokenalize-delimiters">
+ <xsl:with-param name="string" select="substring-after($string, $delimiter)" />
+ <xsl:with-param name="delimiters" select="$delimiters" />
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="str:_tokenalize-delimiters">
+ <xsl:with-param name="string" select="$string" />
+ <xsl:with-param name="delimiters" select="substring($delimiters, 2)" />
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+<!-- </xsl:if> -->
+
+</xsl:transform>
Index: static/post_html.xslt
===================================================================
--- static/post_html.xslt (revision 0)
+++ static/post_html.xslt (revision 0)
@@ -0,0 +1,184 @@
+<xsl:transform version="1.0"
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xhtml="http://www.w3.org/1999/xhtml"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:date="http://exslt.org/dates-and-times"
+ xmlns:str="http://exslt.org/strings"
+ xmlns:func="http://exslt.org/functions"
+ xmlns:exsl="http://exslt.org/common"
+ extension-element-prefixes="date str func exsl"
+ exclude-result-prefixes="xhtml"
+>
+ <xsl:namespace-alias stylesheet-prefix="#default" result-prefix="xhtml"/>
+<!-- <xsl:output method = "xml" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" indent="yes" /> -->
+ <xsl:output method = "xml" indent="yes" omit-xml-declaration="yes"/>
+<!-- <xsl:strip-space elements="*" /> -->
+ <xsl:param name="cid-prefix" select="'part.'"/>
+ <xsl:param name="msgnum" select="1"/>
+ <xsl:param name="treat_as_wiki">no</xsl:param>
+
+
+ <xsl:template match="/">
+ <div>
+ <!-- output only the body -->
+ <xsl:choose>
+ <xsl:when test="//node()[local-name()='body']">
+ <xsl:apply-templates select="//node()[local-name()='body']/node()"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates select="node()"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </div>
+ </xsl:template>
+
+ <!-- Convert mailto links to webcit compose links -->
+ <xsl:template match="@href[starts-with(.,'mailto:')]">
+ <xsl:attribute name="{name()}">
+ <xsl:value-of select="concat('/webcit/display_enter?force_room=_MAIL_&recp=',substring-after(.,'mailto:'))"/>
+ </xsl:attribute>
+ </xsl:template>
+
+ <!-- convert src relative url's to cid format -->
+ <xsl:template match="@src[starts-with(.,'/webcit/postpart/') or starts-with(.,'webcit/postpart/') or starts-with(., '/postpart/') or starts-with(., 'postpart/')]">
+ <xsl:variable name="part" select="substring-before(substring-after(., 'postpart/'),'/')"/>
+ <xsl:attribute name="{name()}">
+ <xsl:value-of select="concat('cid:',$cid-prefix,$part)"/>
+ </xsl:attribute>
+ </xsl:template>
+
+ <!-- remove all script linkes -->
+ <xsl:template match="node()[local-name()='script']"/>
+
+ <!-- remove all script handler attributes, for now defined as any attribute beginning with "on" -->
+ <xsl:template match="@onclick|@*[starts-with(.,'on')]" />
+
+ <!-- remove all target links from href tags -->
+ <xsl:template match="node()[local-name()='a']/@target"/>
+
+ <!-- add a target tag for all links except mailto: tags -->
+ <!-- TODO: and wiki tags and CERTAIN other non absolute tags -->
+ <xsl:template match="node()[local-name()='a' and @href and not(starts-with(@href,'mailto:'))]">
+ <xsl:copy>
+ <xsl:attribute name="target">_blank</xsl:attribute>
+ <xsl:apply-templates select="@*[local-name()!='target']|node()" />
+ </xsl:copy>
+ </xsl:template>
+
+ <!-- enhance text by making <a>'s out of urls and email addresses -->
+ <xsl:template match="text()">
+ <xsl:for-each select="str:tokenalize(.)">
+ <xsl:choose>
+ <xsl:when test="starts-with(., 'http:')">
+ <a href="{.}" target="_blank"><xsl:value-of select="."/></a>
+ </xsl:when>
+ <xsl:when test="starts-with(., 'www.')">
+ <a href="http://{.}" target="_blank"><xsl:value-of select="."/></a>
+ </xsl:when>
+ <xsl:when test="starts-with(., 'mailto:')">
+ <a href="{concat('/webcit/display_enter?force_room=_MAIL_&recp=',substring-after(.,'mailto:'))}"><xsl:value-of select="."/></a>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="."/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+ </xsl:template>
+
+ <!-- default pass-through all other attributes -->
+ <xsl:template match="@*" name="fixup-text">
+ <xsl:copy/>
+ </xsl:template>
+
+ <!-- default pass-through all other tags -->
+ <xsl:template match="node()">
+ <xsl:copy>
+ <!-- with libxslt xsltproc we can't do @*|node() or the nodes may get processed before the attributes -->
+ <xsl:apply-templates select="@*"/>
+ <xsl:apply-templates select="node()"/>
+ </xsl:copy>
+ </xsl:template>
+
+<!-- str:tokenalize - like str:tokenize, but also returns the tokens
+ based on str:tokenize by Jeni Tennison
+ from: http://www.exslt.org/str/functions/tokenize/str.tokenize.function.xsl -->
+
+<!-- <xsl:if test="not(function-available('str:tokenalize'))"> -->
+<func:function name="str:tokenalize">
+ <xsl:param name="string" select="''" />
+ <xsl:param name="delimiters" select="' 	
'" />
+ <xsl:choose>
+ <xsl:when test="not($string)">
+ <func:result select="/.." />
+ </xsl:when>
+ <xsl:when test="not(function-available('exsl:node-set'))">
+
+ <xsl:message terminate="yes">
+ ERROR: EXSLT - Functions implementation of str:tokenalize relies on exsl:node-set().
+ </xsl:message>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:variable name="tokens">
+ <xsl:choose>
+ <xsl:when test="not($delimiters)">
+ <xsl:call-template name="str:_tokenalize-characters">
+ <xsl:with-param name="string" select="$string" />
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="str:_tokenalize-delimiters">
+ <xsl:with-param name="string" select="$string" />
+ <xsl:with-param name="delimiters" select="$delimiters" />
+ </xsl:call-template>
+ </xsl:otherwise>
+
+ </xsl:choose>
+ </xsl:variable>
+ <func:result select="exsl:node-set($tokens)/*" />
+ </xsl:otherwise>
+ </xsl:choose>
+</func:function>
+
+<xsl:template name="str:_tokenalize-characters">
+ <xsl:param name="string" />
+ <xsl:if test="$string">
+ <token><xsl:value-of select="substring($string, 1, 1)" /></token>
+ <xsl:call-template name="str:_tokenalize-characters">
+ <xsl:with-param name="string" select="substring($string, 2)" />
+ </xsl:call-template>
+ </xsl:if>
+</xsl:template>
+
+<xsl:template name="str:_tokenalize-delimiters">
+ <xsl:param name="string" />
+ <xsl:param name="delimiters" />
+
+ <xsl:variable name="delimiter" select="substring($delimiters, 1, 1)" />
+ <xsl:choose>
+ <xsl:when test="not($delimiter)">
+ <token><xsl:value-of select="$string" /></token>
+ </xsl:when>
+ <xsl:when test="contains($string, $delimiter)">
+ <xsl:if test="not(starts-with($string, $delimiter))">
+ <xsl:call-template name="str:_tokenalize-delimiters">
+ <xsl:with-param name="string" select="substring-before($string, $delimiter)" />
+ <xsl:with-param name="delimiters" select="substring($delimiters, 2)" />
+ </xsl:call-template>
+ </xsl:if>
+ <delimiter><xsl:value-of select="$delimiter"/></delimiter>
+ <xsl:call-template name="str:_tokenalize-delimiters">
+ <xsl:with-param name="string" select="substring-after($string, $delimiter)" />
+ <xsl:with-param name="delimiters" select="$delimiters" />
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="str:_tokenalize-delimiters">
+ <xsl:with-param name="string" select="$string" />
+ <xsl:with-param name="delimiters" select="substring($delimiters, 2)" />
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+<!-- </xsl:if> -->
+
+</xsl:transform>
Index: messages.c
===================================================================
--- messages.c (revision 6707)
+++ messages.c (working copy)
@@ -8,6 +8,20 @@
#include "webcit.h"
#include "webserver.h"
#include "groupdav.h"
+#ifdef HAVE_XSLT
+#include <libxml/xmlmemory.h>
+#include <libxml/debugXML.h>
+#include <libxml/HTMLtree.h>
+#include <libxml/xmlIO.h>
+#include <libxml/xinclude.h>
+#include <libxml/catalog.h>
+#include <libxslt/xslt.h>
+#include <libxslt/xsltInternals.h>
+#include <libxslt/transform.h>
+#include <libxslt/xsltutils.h>
+#include "libexslt/exslt.h"
+#include <libexslt/exsltconfig.h>
+#endif
#define SUBJ_COL_WIDTH_PCT 50 /**< Mailbox view column width */
#define SENDER_COL_WIDTH_PCT 30 /**< Mailbox view column width */
@@ -2977,6 +2991,8 @@
void post_mime_to_server(void) {
char top_boundary[SIZ];
char alt_boundary[SIZ];
+ char rel_boundary[SIZ];
+ char cid_prefix[SIZ];
int is_multipart = 0;
static int seq = 0;
struct wc_attachment *att;
@@ -2985,6 +3001,8 @@
size_t encoded_strlen;
char *txtmail = NULL;
+ sprintf(cid_prefix, "part.");
+
sprintf(top_boundary, "Citadel--Multipart--%s--%04x--%04x",
serv_info.serv_fqdn,
getpid(),
@@ -3027,19 +3045,91 @@
serv_printf("--%s", alt_boundary);
+ /* start multi-part related block */
+ sprintf(rel_boundary, "Citadel--Multipart--%s--%04x--%04x",
+ serv_info.serv_fqdn,
+ getpid(),
+ ++seq
+ );
+ serv_printf("Content-type: multipart/related; "
+ "boundary=\"%s\"\n", rel_boundary);
+ serv_puts("");
+
+ serv_printf("--%s", rel_boundary);
serv_puts("Content-type: text/html; charset=utf-8");
serv_puts("Content-Transfer-Encoding: quoted-printable");
serv_puts("");
+
+#ifdef HAVE_XSLT
+ /* purify the html and fixup inline urls to cid: */
+ {
+ const char *params[16 + 1];
+ xmlDocPtr doc=NULL;
+ xmlDocPtr res=NULL;
+ xsltStylesheetPtr format=NULL;
+
+ doc = htmlParseDoc((const xmlChar*)bstr("msgtext"), "utf8");
+ format = xsltParseStylesheetFile((const xmlChar *)WWWDIR "/static/post_html.xslt");
+ params[0]="cid-prefix";
+ params[1]=cid_prefix;
+ params[0]=NULL;
+
+ res=xsltApplyStylesheet(format, doc, params);
+ if (res) {
+ char* output;
+ int len=0;
+ xsltSaveResultToString(&output, &len, res, format);
+ serv_puts("<html><body>\r\n");
+ text_to_server_qp(output); /* Transmit message in quoted-printable encoding */
+ serv_puts("</body></html>\r\n");
+ if (output) free(output);
+ }
+
+ if (format) xsltFreeStylesheet(format);
+ if (res) xmlFreeDoc(res);
+ if (doc) xmlFreeDoc(doc);
+
+ }
+#else
serv_puts("<html><body>\r\n");
text_to_server_qp(bstr("msgtext")); /* Transmit message in quoted-printable encoding */
serv_puts("</body></html>\r\n");
+#endif
+ /* Now output related inline attachments */
+ if (is_multipart) {
+ int count=0;
+
+ /* Add in the attachments; NOTE: we count++ ALL attachments */
+ for (att = WC->first_attachment; att!=NULL; count++, att=att->next) if (att->is_inline) {
+
+ encoded_length = ((att->length * 150) / 100);
+ encoded = malloc(encoded_length);
+ if (encoded == NULL) break;
+ encoded_strlen = CtdlEncodeBase64(encoded, att->data, att->length, 1);
+
+ serv_printf("--%s", rel_boundary);
+ serv_printf("Content-type: %s", att->content_type);
+ serv_printf("Content-ID: <%s%d>", cid_prefix, count);
+ serv_printf("Content-disposition: attachment; filename=\"%s\"", att->filename);
+ serv_puts("Content-transfer-encoding: base64");
+ serv_puts("");
+ serv_write(encoded, encoded_strlen);
+ serv_puts("");
+ serv_puts("");
+ free(encoded);
+ }
+ }
+
+ serv_printf("--%s--", rel_boundary);
+
serv_printf("--%s--", alt_boundary);
if (is_multipart) {
+ int count=0;
- /* Add in the attachments */
- for (att = WC->first_attachment; att!=NULL; att=att->next) {
+ /* Add in the attachments; NOTE: we count++ ALL attachments */
+ for (att = WC->first_attachment; att!=NULL; count++, att=att->next) if (! att->is_inline) {
encoded_length = ((att->length * 150) / 100);
encoded = malloc(encoded_length);
@@ -3048,6 +3138,7 @@
serv_printf("--%s", top_boundary);
serv_printf("Content-type: %s", att->content_type);
+ serv_printf("Content-ID: <part.%d>", count, serv_info.serv_fqdn);
serv_printf("Content-disposition: attachment; filename=\"%s\"", att->filename);
serv_puts("Content-transfer-encoding: base64");
serv_puts("");
@@ -3134,6 +3225,8 @@
* to the attachment struct.
*/
att->data = WCC->upload;
+ if (havebstr("insert_button"))
+ att->is_inline=1;
WCC->upload_length = 0;
WCC->upload = NULL;
display_enter();
@@ -3143,7 +3236,7 @@
if (havebstr("cancel_button")) {
sprintf(WCC->ImportantMessage,
_("Cancelled. Message was not posted."));
- } else if (havebstr("attach_button")) {
+ } else if (havebstr("attach_button") || havebstr("insert_button")) {
display_enter();
return;
} else if (lbstr("postseq") == dont_post) {
@@ -3679,9 +3772,11 @@
/** Now offer the ability to attach additional files... */
wprintf(" ");
wprintf(_("Attach file:"));
- wprintf(" <input name=\"attachfile\" class=\"attachfile\" "
+ wprintf("<input name=\"attachfile\" class=\"attachfile\" "
"size=16 type=\"file\">\n "
"<input type=\"submit\" name=\"attach_button\" value=\"%s\">\n", _("Add"));
+ wprintf(" "
+ "<input type=\"submit\" name=\"insert_button\" value=\"%s\">\n", _("Insert"));
wprintf("</div>"); /* End of "attachment buttons" div */