diff options
-rw-r--r-- | camel/ChangeLog | 6 | ||||
-rw-r--r-- | camel/camel-mime-filter-enriched.c | 278 |
2 files changed, 243 insertions, 41 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog index 518237af2e..a7022b0cc7 100644 --- a/camel/ChangeLog +++ b/camel/ChangeLog @@ -1,3 +1,9 @@ +2003-03-31 Jeffrey Stedfast <fejj@ximian.com> + + * camel-mime-filter-enriched.c (enriched_to_html): Use strncasecmp + for matching the nofill and /nofill tags. Also fixed to handle + enriched tags that require <param> tags. + 2003-03-28 Not Zed <NotZed@Ximian.com> * providers/local/camel-spool-store.c (get_folder): remove unused diff --git a/camel/camel-mime-filter-enriched.c b/camel/camel-mime-filter-enriched.c index 349a56d07b..23ffd73493 100644 --- a/camel/camel-mime-filter-enriched.c +++ b/camel/camel-mime-filter-enriched.c @@ -32,38 +32,62 @@ #include "camel-mime-filter-enriched.h" +/* text/enriched is rfc1896 */ + +typedef char * (*EnrichedParamParser) (const char *inptr, int inlen); + +static char *param_parse_colour (const char *inptr, int inlen); +static char *param_parse_font (const char *inptr, int inlen); +static char *param_parse_lang (const char *inptr, int inlen); + static struct { char *enriched; char *html; + gboolean needs_param; + EnrichedParamParser parse_param; /* parses *and* validates the input */ } enriched_tags[] = { - { "bold", "<b>" }, - { "/bold", "</b>" }, - { "italic", "<i>" }, - { "/italic", "</i>" }, - { "fixed", "<tt>" }, - { "/fixed", "</tt>" }, - { "smaller", "<font size=-1>" }, - { "/smaller", "</font>" }, - { "bigger", "<font size=+1>" }, - { "/bigger", "</font>" }, - { "underline", "<u>" }, - { "/underline", "</u>" }, - { "center", "<p align=center>" }, - { "/center", "</p>" }, - { "flushleft", "<p align=left>" }, - { "/flushleft", "</p>" }, - { "flushright", "<p align=right>" }, - { "/flushright", "</p>" }, - { "excerpt", "<blockquote>" }, - { "/excerpt", "</blockquote>" }, - { "paragraph", "<p>" }, - { "signature", "<address>" }, - { "/signature", "</address>" }, - { "comment", "<!-- " }, - { "/comment", " -->" }, - { "param", "<!-- " }, - { "/param", " -->" }, - { "np", "<hr>" } + { "bold", "<b>", FALSE, NULL }, + { "/bold", "</b>", FALSE, NULL }, + { "italic", "<i>", FALSE, NULL }, + { "/italic", "</i>", FALSE, NULL }, + { "fixed", "<tt>", FALSE, NULL }, + { "/fixed", "</tt>", FALSE, NULL }, + { "smaller", "<font size=-1>", FALSE, NULL }, + { "/smaller", "</font>", FALSE, NULL }, + { "bigger", "<font size=+1>", FALSE, NULL }, + { "/bigger", "</font>", FALSE, NULL }, + { "underline", "<u>", FALSE, NULL }, + { "/underline", "</u>", FALSE, NULL }, + { "center", "<p align=center>", FALSE, NULL }, + { "/center", "</p>", FALSE, NULL }, + { "flushleft", "<p align=left>", FALSE, NULL }, + { "/flushleft", "</p>", FALSE, NULL }, + { "flushright", "<p align=right>", FALSE, NULL }, + { "/flushright", "</p>", FALSE, NULL }, + { "excerpt", "<blockquote>", FALSE, NULL }, + { "/excerpt", "</blockquote>", FALSE, NULL }, + { "paragraph", "<p>", FALSE, NULL }, + { "signature", "<address>", FALSE, NULL }, + { "/signature", "</address>", FALSE, NULL }, + { "comment", "<!-- ", FALSE, NULL }, + { "/comment", " -->", FALSE, NULL }, + { "np", "<hr>", FALSE, NULL }, + { "fontfamily", "<font face=\"%s\">", TRUE, param_parse_font }, + { "/fontfamily", "</font>", FALSE, NULL }, + { "color", "<font color=\"%s\">", TRUE, param_parse_colour }, + { "/color", "</font>", FALSE, NULL }, + { "lang", "<span lang=\"%s\">", TRUE, param_parse_lang }, + { "/lang", "</span>", FALSE, NULL }, + + /* don't handle this tag yet... */ + { "paraindent", "<!-- ", /* TRUE */ FALSE, NULL }, + { "/paraindent", " -->", FALSE, NULL }, + + /* as soon as we support all the tags that can have a param + * tag argument, these should be unnecessary, but we'll keep + * them anyway just in case? */ + { "param", "<!-- ", FALSE, NULL }, + { "/param", " -->", FALSE, NULL }, }; #define NUM_ENRICHED_TAGS (sizeof (enriched_tags) / sizeof (enriched_tags[0])) @@ -137,6 +161,119 @@ camel_mime_filter_enriched_init (CamelMimeFilterEnriched *filter) filter->nofill = 0; } + +#if 0 +static gboolean +enriched_tag_needs_param (const char *tag) +{ + int i; + + for (i = 0; i < NUM_ENRICHED_TAGS; i++) + if (!strcasecmp (tag, enriched_tags[i].enriched)) + return enriched_tags[i].needs_param; + + return FALSE; +} +#endif + +static gboolean +html_tag_needs_param (const char *tag) +{ + return strstr (tag, "%s") != NULL; +} + +static const char *valid_colours[] = { + "red", "green", "blue", "yellow", "cyan", "magenta", "black", "white" +}; + +#define NUM_VALID_COLOURS (sizeof (valid_colours) / sizeof (valid_colours[0])) + +static char * +param_parse_colour (const char *inptr, int inlen) +{ + const char *inend, *end; + guint32 rgb = 0; + guint v; + int i; + + for (i = 0; i < NUM_VALID_COLOURS; i++) { + if (!strncasecmp (inptr, valid_colours[i], inlen)) + return g_strdup (valid_colours[i]); + } + + /* check for numeric r/g/b in the format: ####,####,#### */ + if (inptr[4] != ',' || inptr[9] != ',') { + /* okay, mailer must have used a string name that + * rfc1896 did not specify? do some simple scanning + * action, a colour name MUST be [a-zA-Z] */ + end = inptr; + inend = inptr + inlen; + while (end < inend && ((*end >= 'a' && *end <= 'z') || (*end >= 'A' && *end <= 'Z'))) + end++; + + return g_strndup (inptr, end - inptr); + } + + for (i = 0; i < 3; i++) { + v = strtoul (inptr, (char **) &end, 16); + if (end != inptr + 4) + goto invalid_format; + + v >>= 8; + rgb = (rgb << 8) | (v & 0xff); + + inptr += 5; + } + + return g_strdup_printf ("#%.6X", rgb); + + invalid_format: + + /* default colour? */ + return g_strdup ("black"); +} + +static char * +param_parse_font (const char *fontfamily, int inlen) +{ + register const char *inptr = fontfamily; + const char *inend = inptr + inlen; + + /* don't allow any of '"', '<', nor '>' */ + while (inptr < inend && *inptr != '"' && *inptr != '<' && *inptr != '>') + inptr++; + + return g_strndup (fontfamily, inptr - fontfamily); +} + +static char * +param_parse_lang (const char *lang, int inlen) +{ + register const char *inptr = lang; + const char *inend = inptr + inlen; + + /* don't allow any of '"', '<', nor '>' */ + while (inptr < inend && *inptr != '"' && *inptr != '<' && *inptr != '>') + inptr++; + + return g_strndup (lang, inptr - lang); +} + +static char * +param_parse (const char *enriched, const char *inptr, int inlen) +{ + int i; + + for (i = 0; i < NUM_ENRICHED_TAGS; i++) { + if (!strcasecmp (enriched, enriched_tags[i].enriched)) + return enriched_tags[i].parse_param (inptr, inlen); + } + + g_assert_not_reached (); + + return NULL; +} + #define IS_RICHTEXT CAMEL_MIME_FILTER_ENRICHED_IS_RICHTEXT static void @@ -155,7 +292,7 @@ enriched_to_html (CamelMimeFilter *filter, char *in, size_t inlen, size_t prespa outptr = filter->outbuf; outend = filter->outbuf + filter->outsize; - loop: + retry: do { while (inptr < inend && outptr < outend && !strchr (" <>&\n", *inptr)) *outptr++ = *inptr++; @@ -242,7 +379,7 @@ enriched_to_html (CamelMimeFilter *filter, char *in, size_t inlen, size_t prespa goto backup; } } - + tag = inptr; while (inptr < inend && *inptr != '>') inptr++; @@ -252,7 +389,7 @@ enriched_to_html (CamelMimeFilter *filter, char *in, size_t inlen, size_t prespa goto need_input; } - if (!strncmp (tag, "nofill>", 7)) { + if (!strncasecmp (tag, "nofill>", 7)) { if ((outptr + 5) < outend) { memcpy (outptr, "<pre>", 5); enriched->nofill++; @@ -261,7 +398,7 @@ enriched_to_html (CamelMimeFilter *filter, char *in, size_t inlen, size_t prespa inptr = tag - 1; goto backup; } - } else if (!strncmp (tag, "/nofill>", 8)) { + } else if (!strncasecmp (tag, "/nofill>", 8)) { if ((outptr + 6) < outend) { memcpy (outptr, "</pre>", 6); enriched->nofill--; @@ -275,21 +412,80 @@ enriched_to_html (CamelMimeFilter *filter, char *in, size_t inlen, size_t prespa char *enriched_tag; int len; - enriched_tag = g_strndup (tag, (inptr - tag)); + len = inptr - tag; + enriched_tag = g_alloca (len + 1); + memcpy (enriched_tag, tag, len); + enriched_tag[len] = '\0'; + html_tag = g_hash_table_lookup (enriched_hash, enriched_tag); - g_free (enriched_tag); + if (html_tag) { - len = strlen (html_tag); - if ((outptr + len) < outend) { - memcpy (outptr, html_tag, len); - outptr += len; + if (html_tag_needs_param (html_tag)) { + const char *start; + char *param; + + while (inptr < inend && *inptr != '<') + inptr++; + +#define PARAM_TAG_MIN_LEN (sizeof ("<param>") + sizeof ("</param>") - 1) + if (inptr == inend || (inend - inptr) <= PARAM_TAG_MIN_LEN) { + inptr = tag - 1; + goto need_input; + } + + if (strncasecmp (inptr, "<param>", 7) != 0) { + /* ignore the enriched command tag... */ + inptr -= 1; + goto loop; + } + + inptr += 7; + start = inptr; + + while (inptr < inend && *inptr != '<') + inptr++; + + if (inptr == inend || (inend - inptr) <= 8) { + inptr = tag - 1; + goto need_input; + } + + if (strncasecmp (inptr, "</param>", 8) != 0) { + /* ignore the enriched command tag... */ + inptr += 7; + goto loop; + } + + len = inptr - start; + param = param_parse (enriched_tag, start, len); + len = strlen (param); + + inptr += 7; + + len += strlen (html_tag); + + if ((outptr + len) < outend) { + outptr += snprintf (outptr, len, html_tag, param); + g_free (param); + } else { + g_free (param); + inptr = tag - 1; + goto backup; + } } else { - inptr = tag - 1; - goto backup; + len = strlen (html_tag); + if ((outptr + len) < outend) { + memcpy (outptr, html_tag, len); + outptr += len; + } else { + inptr = tag - 1; + goto backup; + } } } } + loop: inptr++; break; default: @@ -323,7 +519,7 @@ enriched_to_html (CamelMimeFilter *filter, char *in, size_t inlen, size_t prespa outend = filter->outbuf + filter->outsize; outptr = filter->outbuf + offset; - goto loop; + goto retry; } else { camel_mime_filter_backup (filter, inptr, (unsigned) (inend - inptr)); } |