From a8bde44b69e42fdb5640930e28c5005b897053df Mon Sep 17 00:00:00 2001 From: Milan Crha Date: Mon, 13 Dec 2010 16:30:21 +0100 Subject: Bug #436914 - Reply to inline GPG quotes raw GPG message --- em-format/Makefile.am | 2 + em-format/em-format-quote.c | 60 ++++++ em-format/em-inline-filter.c | 444 +++++++++++++++++++++++++++++++++++++++++++ em-format/em-inline-filter.h | 80 ++++++++ mail/Makefile.am | 2 - mail/em-format-html.c | 2 +- mail/em-inline-filter.c | 388 ------------------------------------- mail/em-inline-filter.h | 77 -------- 8 files changed, 587 insertions(+), 468 deletions(-) create mode 100644 em-format/em-inline-filter.c create mode 100644 em-format/em-inline-filter.h delete mode 100644 mail/em-inline-filter.c delete mode 100644 mail/em-inline-filter.h diff --git a/em-format/Makefile.am b/em-format/Makefile.am index 212b45f074..df052fe915 100644 --- a/em-format/Makefile.am +++ b/em-format/Makefile.am @@ -5,6 +5,7 @@ privsolib_LTLIBRARIES = libemformat.la emformatinclude_HEADERS = \ em-format.h \ em-format-quote.h \ + em-inline-filter.h \ em-stripsig-filter.h libemformat_la_CPPFLAGS = \ @@ -18,6 +19,7 @@ libemformat_la_SOURCES = \ $(emformatinclude_HEADERS) \ em-format.c \ em-format-quote.c \ + em-inline-filter.c \ em-stripsig-filter.c libemformat_la_LDFLAGS = $(NO_UNDEFINED) diff --git a/em-format/em-format-quote.c b/em-format/em-format-quote.c index 6d6ed6a4ab..bdb632b252 100644 --- a/em-format/em-format-quote.c +++ b/em-format/em-format-quote.c @@ -30,6 +30,7 @@ #include #include +#include "em-inline-filter.h" #include "em-stripsig-filter.h" #include "em-format-quote.h" @@ -529,6 +530,52 @@ emfq_format_message (EMFormat *emf, cancellable, NULL); } +/* Decodes inline encoded parts of 'part'. The returned pointer, if not NULL, should + be unreffed with g_object_unref(). +*/ +static CamelMimePart * +decode_inline_parts (CamelMimePart *part, GCancellable *cancellable) +{ + CamelMultipart *mp; + CamelStream *null; + CamelStream *filtered_stream; + EMInlineFilter *inline_filter; + + g_return_val_if_fail (part != NULL, NULL); + + null = camel_stream_null_new (); + filtered_stream = camel_stream_filter_new (null); + g_object_unref (null); + + inline_filter = em_inline_filter_new (camel_mime_part_get_encoding (part), camel_mime_part_get_content_type (part)); + camel_stream_filter_add ( + CAMEL_STREAM_FILTER (filtered_stream), + CAMEL_MIME_FILTER (inline_filter)); + camel_data_wrapper_decode_to_stream_sync ( + camel_medium_get_content (CAMEL_MEDIUM (part)), (CamelStream *)filtered_stream, cancellable, NULL); + camel_stream_close ((CamelStream *)filtered_stream, cancellable, NULL); + g_object_unref (filtered_stream); + + if (!em_inline_filter_found_any (inline_filter)) { + g_object_unref (inline_filter); + return NULL; + } + + mp = em_inline_filter_get_multipart (inline_filter); + + g_object_unref (inline_filter); + + if (mp) { + part = camel_mime_part_new (); + camel_medium_set_content (CAMEL_MEDIUM (part), CAMEL_DATA_WRAPPER (mp)); + g_object_unref (mp); + } else { + g_object_ref (part); + } + + return part; +} + static void emfq_text_plain (EMFormat *emf, CamelStream *stream, @@ -541,6 +588,7 @@ emfq_text_plain (EMFormat *emf, CamelStream *filtered_stream; CamelMimeFilter *html_filter; CamelMimeFilter *sig_strip; + CamelMimePart *mp; CamelContentType *type; const gchar *format; guint32 rgb = 0x737373, flags; @@ -548,6 +596,18 @@ emfq_text_plain (EMFormat *emf, if (!part) return; + mp = decode_inline_parts (part, cancellable); + if (mp) { + if (CAMEL_IS_MULTIPART (camel_medium_get_content (CAMEL_MEDIUM (mp)))) { + em_format_part (emf, stream, mp, cancellable); + g_object_unref (mp); + + return; + } + + g_object_unref (mp); + } + flags = emfq->text_html_flags; /* Check for RFC 2646 flowed text. */ diff --git a/em-format/em-inline-filter.c b/em-format/em-inline-filter.c new file mode 100644 index 0000000000..23e5a6f6ed --- /dev/null +++ b/em-format/em-inline-filter.c @@ -0,0 +1,444 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + * + * Authors: + * Michael Zucchi + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "em-inline-filter.h" + +#include "em-format/em-format.h" + +#define d(x) + +G_DEFINE_TYPE (EMInlineFilter, em_inline_filter, CAMEL_TYPE_MIME_FILTER) + +enum { + EMIF_PLAIN, + EMIF_BINHEX, + EMIF_POSTSCRIPT, + EMIF_PGPSIGNED, + EMIF_PGPENCRYPTED +}; + +static const struct { + const gchar *type; + const gchar *subtype; + CamelTransferEncoding encoding; + guint plain:1; +} emif_types[] = { + { "text", "plain", CAMEL_TRANSFER_ENCODING_DEFAULT, 1, }, + { "application", "mac-binhex40", CAMEL_TRANSFER_ENCODING_7BIT, 0, }, + { "application", "postscript", CAMEL_TRANSFER_ENCODING_7BIT, 0, }, + { "application", "x-inlinepgp-signed", CAMEL_TRANSFER_ENCODING_DEFAULT, 0, }, + { "application", "x-inlinepgp-encrypted", CAMEL_TRANSFER_ENCODING_DEFAULT, 0, }, +}; + +static CamelMimePart * +construct_part_from_stream (CamelStream *mem, const GByteArray *data) +{ + CamelMimePart *part = NULL; + CamelMimeParser *parser; + + g_return_val_if_fail (mem != NULL, NULL); + g_return_val_if_fail (data != NULL, NULL); + + if (data->len <= 13 || g_ascii_strncasecmp ((const gchar *) data->data, "Content-Type:", 13) != 0) + return NULL; + + parser = camel_mime_parser_new (); + camel_mime_parser_scan_from (parser, FALSE); + camel_mime_parser_scan_pre_from (parser, FALSE); + + if (camel_mime_parser_init_with_stream (parser, mem, NULL) != -1) { + part = camel_mime_part_new (); + if (!camel_mime_part_construct_from_parser_sync (part, parser, NULL, NULL)) { + g_object_unref (part); + part = NULL; + } + } + + g_object_unref (parser); + + return part; +} + +static void +inline_filter_add_part (EMInlineFilter *emif, const gchar *data, gint len) +{ + CamelTransferEncoding encoding; + CamelContentType *content_type; + CamelDataWrapper *dw; + const gchar *mimetype; + CamelMimePart *part; + CamelStream *mem; + gchar *type; + + if (emif->state == EMIF_PLAIN || emif->state == EMIF_PGPSIGNED || emif->state == EMIF_PGPENCRYPTED) + encoding = emif->base_encoding; + else + encoding = emif_types[emif->state].encoding; + + g_byte_array_append (emif->data, (guchar *)data, len); + /* check the part will actually have content */ + if (emif->data->len <= 0) { + return; + } + + mem = camel_stream_mem_new_with_byte_array (emif->data); + part = construct_part_from_stream (mem, emif->data); + if (part) { + g_object_unref (mem); + emif->data = g_byte_array_new (); + g_free (emif->filename); + emif->filename = NULL; + + emif->parts = g_slist_append (emif->parts, part); + emif->found_any = TRUE; + + return; + } + + emif->data = g_byte_array_new (); + camel_stream_reset (mem, NULL); + + dw = camel_data_wrapper_new (); + if (encoding == emif->base_encoding && (encoding == CAMEL_TRANSFER_ENCODING_BASE64 || encoding == CAMEL_TRANSFER_ENCODING_QUOTEDPRINTABLE)) { + CamelMimeFilter *enc_filter = camel_mime_filter_basic_new (encoding == CAMEL_TRANSFER_ENCODING_BASE64 ? CAMEL_MIME_FILTER_BASIC_BASE64_ENC : CAMEL_MIME_FILTER_BASIC_QP_ENC); + CamelStream *filter_stream; + + filter_stream = camel_stream_filter_new (mem); + camel_stream_filter_add (CAMEL_STREAM_FILTER (filter_stream), enc_filter); + + /* properly encode content */ + camel_data_wrapper_construct_from_stream_sync ( + dw, filter_stream, NULL, NULL); + + g_object_unref (enc_filter); + g_object_unref (filter_stream); + } else { + camel_data_wrapper_construct_from_stream_sync ( + dw, mem, NULL, NULL); + } + g_object_unref (mem); + + if (emif_types[emif->state].plain && emif->base_type) { + /* create a copy */ + type = camel_content_type_format (emif->base_type); + content_type = camel_content_type_decode (type); + g_free (type); + } else { + /* we want to preserve all params */ + type = camel_content_type_format (emif->base_type); + content_type = camel_content_type_decode (type); + g_free (type); + + g_free (content_type->type); + g_free (content_type->subtype); + content_type->type = g_strdup (emif_types[emif->state].type); + content_type->subtype = g_strdup (emif_types[emif->state].subtype); + } + + camel_data_wrapper_set_mime_type_field (dw, content_type); + camel_content_type_unref (content_type); + dw->encoding = encoding; + + part = camel_mime_part_new (); + camel_medium_set_content ((CamelMedium *)part, dw); + camel_mime_part_set_encoding (part, encoding); + g_object_unref (dw); + + if (emif->filename) + camel_mime_part_set_filename (part, emif->filename); + + /* pre-snoop the mime type of unknown objects, and poke and hack it into place */ + if (camel_content_type_is(dw->mime_type, "application", "octet-stream") + && (mimetype = em_format_snoop_type (part)) + && strcmp(mimetype, "application/octet-stream") != 0) { + camel_data_wrapper_set_mime_type (dw, mimetype); + camel_mime_part_set_content_type (part, mimetype); + if (emif->filename) + camel_mime_part_set_filename (part, emif->filename); + } + + g_free (emif->filename); + emif->filename = NULL; + + emif->parts = g_slist_append (emif->parts, part); +} + +static gint +inline_filter_scan (CamelMimeFilter *f, gchar *in, gsize len, gint final) +{ + EMInlineFilter *emif = (EMInlineFilter *)f; + gchar *inptr = in, *inend = in+len; + gchar *data_start = in; + gchar *start = in; + + while (inptr < inend) { + gint rest_len; + + start = inptr; + + while (inptr < inend && *inptr != '\n') + inptr++; + + if (inptr == inend && start == inptr) { + if (!final) { + camel_mime_filter_backup (f, start, inend-start); + inend = start; + } + break; + } + + rest_len = inend - start; + if (inptr < inend) + *inptr++ = 0; + + #define restore_inptr() G_STMT_START { if (inptr < inend) inptr[-1] = '\n'; } G_STMT_END + + switch (emif->state) { + case EMIF_PLAIN: + if (rest_len >= 45 && strncmp (start, "(This file must be converted with BinHex 4.0)", 45) == 0) { + restore_inptr (); + inline_filter_add_part (emif, data_start, start-data_start); + data_start = start; + emif->state = EMIF_BINHEX; + } else if (rest_len >= 11 && strncmp (start, "%!PS-Adobe-", 11) == 0) { + restore_inptr (); + inline_filter_add_part (emif, data_start, start-data_start); + data_start = start; + emif->state = EMIF_POSTSCRIPT; + } else if (rest_len >= 34 && strncmp (start, "-----BEGIN PGP SIGNED MESSAGE-----", 34) == 0) { + restore_inptr (); + inline_filter_add_part (emif, data_start, start-data_start); + data_start = start; + emif->state = EMIF_PGPSIGNED; + } else if (rest_len >= 27 && strncmp (start, "-----BEGIN PGP MESSAGE-----", 27) == 0) { + restore_inptr (); + inline_filter_add_part (emif, data_start, start-data_start); + data_start = start; + emif->state = EMIF_PGPENCRYPTED; + } + + break; + case EMIF_BINHEX: + if (inptr > (start+1) && inptr[-2] == ':') { + restore_inptr (); + inline_filter_add_part (emif, data_start, inptr-data_start); + data_start = inptr; + emif->state = EMIF_PLAIN; + emif->found_any = TRUE; + } + break; + case EMIF_POSTSCRIPT: + if (rest_len >= 5 && strncmp (start, "%%EOF", 5) == 0) { + restore_inptr (); + inline_filter_add_part (emif, data_start, inptr-data_start); + data_start = inptr; + emif->state = EMIF_PLAIN; + emif->found_any = TRUE; + } + break; + case EMIF_PGPSIGNED: + if (rest_len >= 27 && strncmp (start, "-----END PGP SIGNATURE-----", 27) == 0) { + restore_inptr (); + inline_filter_add_part (emif, data_start, inptr-data_start); + data_start = inptr; + emif->state = EMIF_PLAIN; + emif->found_any = TRUE; + } + break; + case EMIF_PGPENCRYPTED: + if (rest_len >= 25 && strncmp (start, "-----END PGP MESSAGE-----", 25) == 0) { + restore_inptr (); + inline_filter_add_part (emif, data_start, inptr-data_start); + data_start = inptr; + emif->state = EMIF_PLAIN; + emif->found_any = TRUE; + } + break; + } + + restore_inptr (); + + #undef restore_inptr + } + + if (final) { + /* always stop as plain, especially when not read those tags fully */ + emif->state = EMIF_PLAIN; + + inline_filter_add_part (emif, data_start, inend - data_start); + } else if (start > data_start) { + /* backup the last line, in case the tag is divided within buffers */ + camel_mime_filter_backup (f, start, inend - start); + g_byte_array_append (emif->data, (guchar *)data_start, start - data_start); + } else { + g_byte_array_append (emif->data, (guchar *)data_start, inend - data_start); + } + + return 0; +} + +static void +inline_filter_finalize (GObject *object) +{ + EMInlineFilter *emif = EM_INLINE_FILTER (object); + + if (emif->base_type) + camel_content_type_unref (emif->base_type); + + camel_mime_filter_reset (CAMEL_MIME_FILTER (object)); + g_byte_array_free (emif->data, TRUE); + g_free (emif->filename); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (em_inline_filter_parent_class)->finalize (object); +} + +static void +inline_filter_filter (CamelMimeFilter *filter, + const gchar *in, + gsize len, + gsize prespace, + gchar **out, + gsize *outlen, + gsize *outprespace) +{ + inline_filter_scan (filter, (gchar *)in, len, FALSE); + + *out = (gchar *)in; + *outlen = len; + *outprespace = prespace; +} + +static void +inline_filter_complete (CamelMimeFilter *filter, + const gchar *in, + gsize len, + gsize prespace, + gchar **out, + gsize *outlen, + gsize *outprespace) +{ + inline_filter_scan (filter, (gchar *)in, len, TRUE); + + *out = (gchar *)in; + *outlen = len; + *outprespace = prespace; +} + +static void +inline_filter_reset (CamelMimeFilter *filter) +{ + EMInlineFilter *emif = EM_INLINE_FILTER (filter); + GSList *l; + + l = emif->parts; + while (l) { + GSList *n = l->next; + + g_object_unref (l->data); + g_slist_free_1 (l); + + l = n; + } + emif->parts = NULL; + g_byte_array_set_size (emif->data, 0); + emif->found_any = FALSE; +} + +static void +em_inline_filter_class_init (EMInlineFilterClass *class) +{ + GObjectClass *object_class; + CamelMimeFilterClass *mime_filter_class; + + object_class = G_OBJECT_CLASS (class); + object_class->finalize = inline_filter_finalize; + + mime_filter_class = CAMEL_MIME_FILTER_CLASS (class); + mime_filter_class->filter = inline_filter_filter; + mime_filter_class->complete = inline_filter_complete; + mime_filter_class->reset = inline_filter_reset; +} + +static void +em_inline_filter_init (EMInlineFilter *emif) +{ + emif->data = g_byte_array_new (); + emif->found_any = FALSE; +} + +/** + * em_inline_filter_new: + * @base_encoding: The base transfer-encoding of the + * raw data being processed. + * @base_type: The base content-type of the raw data, should always be + * text/plain. + * + * Create a filter which will scan a (text) stream for + * embedded parts. You can then retrieve the contents + * as a CamelMultipart object. + * + * Return value: + **/ +EMInlineFilter * +em_inline_filter_new (CamelTransferEncoding base_encoding, CamelContentType *base_type) +{ + EMInlineFilter *emif; + + emif = g_object_new (EM_TYPE_INLINE_FILTER, NULL); + emif->base_encoding = base_encoding; + if (base_type) { + emif->base_type = base_type; + camel_content_type_ref (emif->base_type); + } + + return emif; +} + +CamelMultipart * +em_inline_filter_get_multipart (EMInlineFilter *emif) +{ + GSList *l = emif->parts; + CamelMultipart *mp; + + mp = camel_multipart_new (); + while (l) { + camel_multipart_add_part (mp, l->data); + l = l->next; + } + + return mp; +} + +gboolean +em_inline_filter_found_any (EMInlineFilter *emif) +{ + g_return_val_if_fail (emif != NULL, FALSE); + + return emif->found_any; +} diff --git a/em-format/em-inline-filter.h b/em-format/em-inline-filter.h new file mode 100644 index 0000000000..503ec7c66c --- /dev/null +++ b/em-format/em-inline-filter.h @@ -0,0 +1,80 @@ +/* + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + * + * Authors: + * Michael Zucchi + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef EM_INLINE_FILTER_H +#define EM_INLINE_FILTER_H + +#include + +/* Standard GObject macros */ +#define EM_TYPE_INLINE_FILTER \ + (em_inline_filter_get_type ()) +#define EM_INLINE_FILTER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), EM_TYPE_INLINE_FILTER, EMInlineFilter)) +#define EM_INLINE_FILTER_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), EM_TYPE_INLINE_FILTER, EMInlineFilterClass)) +#define EM_IS_INLINE_FILTER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), EM_TYPE_INLINE_FILTER)) +#define EM_IS_INLINE_FILTER_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), EM_TYPE_INLINE_FILTER)) +#define EM_INLINE_FILTER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), EM_TYPE_INLINE_FILTER, EMInlineFilterClass)) + +G_BEGIN_DECLS + +typedef struct _EMInlineFilter EMInlineFilter; +typedef struct _EMInlineFilterClass EMInlineFilterClass; + +struct _EMInlineFilter { + CamelMimeFilter filter; + + gint state; + + CamelTransferEncoding base_encoding; + CamelContentType *base_type; + + GByteArray *data; + gchar *filename; + GSList *parts; + + gboolean found_any; +}; + +struct _EMInlineFilterClass { + CamelMimeFilterClass filter_class; +}; + +GType em_inline_filter_get_type (void); +EMInlineFilter *em_inline_filter_new (CamelTransferEncoding base_encoding, + CamelContentType *type); +CamelMultipart *em_inline_filter_get_multipart (EMInlineFilter *emif); +gboolean em_inline_filter_found_any (EMInlineFilter *emif); + +G_END_DECLS + +#endif /* EM_INLINE_FILTER_H */ diff --git a/mail/Makefile.am b/mail/Makefile.am index a88a7c889a..520e6876cd 100644 --- a/mail/Makefile.am +++ b/mail/Makefile.am @@ -91,7 +91,6 @@ mailinclude_HEADERS = \ em-format-html-display.h \ em-format-html-print.h \ em-html-stream.h \ - em-inline-filter.h \ em-junk.h \ em-search-context.h \ em-subscription-editor.h \ @@ -164,7 +163,6 @@ libevolution_mail_la_SOURCES = \ em-format-html-display.c \ em-format-html-print.c \ em-html-stream.c \ - em-inline-filter.c \ em-junk.c \ em-search-context.c \ em-subscription-editor.c \ diff --git a/mail/em-format-html.c b/mail/em-format-html.c index de8c0b5961..6b74da70b5 100644 --- a/mail/em-format-html.c +++ b/mail/em-format-html.c @@ -1595,7 +1595,7 @@ efh_object_requested (GtkHTML *html, GtkHTMLEmbedded *eb, EMFormatHTML *efh) } /* ********************************************************************** */ -#include "em-inline-filter.h" +#include "em-format/em-inline-filter.h" /* FIXME: This is duplicated in em-format-html-display, should be exported or in security module */ static const struct { diff --git a/mail/em-inline-filter.c b/mail/em-inline-filter.c deleted file mode 100644 index 7222c03489..0000000000 --- a/mail/em-inline-filter.c +++ /dev/null @@ -1,388 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see - * - * - * Authors: - * Michael Zucchi - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include "em-inline-filter.h" - -#include "em-utils.h" -#include "em-format/em-format.h" - -#define d(x) - -G_DEFINE_TYPE (EMInlineFilter, em_inline_filter, CAMEL_TYPE_MIME_FILTER) - -enum { - EMIF_PLAIN, - EMIF_BINHEX, - EMIF_POSTSCRIPT, - EMIF_PGPSIGNED, - EMIF_PGPENCRYPTED -}; - -static const struct { - const gchar *type; - const gchar *subtype; - CamelTransferEncoding encoding; - guint plain:1; -} emif_types[] = { - { "text", "plain", CAMEL_TRANSFER_ENCODING_DEFAULT, 1, }, - { "application", "mac-binhex40", CAMEL_TRANSFER_ENCODING_7BIT, 0, }, - { "application", "postscript", CAMEL_TRANSFER_ENCODING_7BIT, 0, }, - { "application", "x-inlinepgp-signed", CAMEL_TRANSFER_ENCODING_DEFAULT, 0, }, - { "application", "x-inlinepgp-encrypted", CAMEL_TRANSFER_ENCODING_DEFAULT, 0, }, -}; - -static void -inline_filter_add_part (EMInlineFilter *emif, const gchar *data, gint len) -{ - CamelTransferEncoding encoding; - CamelContentType *content_type; - CamelDataWrapper *dw; - const gchar *mimetype; - CamelMimePart *part; - CamelStream *mem; - gchar *type; - - if (emif->state == EMIF_PLAIN || emif->state == EMIF_PGPSIGNED || emif->state == EMIF_PGPENCRYPTED) - encoding = emif->base_encoding; - else - encoding = emif_types[emif->state].encoding; - - g_byte_array_append (emif->data, (guchar *)data, len); - /* check the part will actually have content */ - if (emif->data->len <= 0) { - return; - } - - mem = camel_stream_mem_new_with_byte_array (emif->data); - emif->data = g_byte_array_new (); - - dw = camel_data_wrapper_new (); - if (encoding == emif->base_encoding && (encoding == CAMEL_TRANSFER_ENCODING_BASE64 || encoding == CAMEL_TRANSFER_ENCODING_QUOTEDPRINTABLE)) { - CamelMimeFilter *enc_filter = camel_mime_filter_basic_new (encoding == CAMEL_TRANSFER_ENCODING_BASE64 ? CAMEL_MIME_FILTER_BASIC_BASE64_ENC : CAMEL_MIME_FILTER_BASIC_QP_ENC); - CamelStream *filter_stream; - - filter_stream = camel_stream_filter_new (mem); - camel_stream_filter_add (CAMEL_STREAM_FILTER (filter_stream), enc_filter); - - /* properly encode content */ - camel_data_wrapper_construct_from_stream_sync ( - dw, filter_stream, NULL, NULL); - - g_object_unref (enc_filter); - g_object_unref (filter_stream); - } else { - camel_data_wrapper_construct_from_stream_sync ( - dw, mem, NULL, NULL); - } - g_object_unref (mem); - - if (emif_types[emif->state].plain && emif->base_type) { - /* create a copy */ - type = camel_content_type_format (emif->base_type); - content_type = camel_content_type_decode (type); - g_free (type); - } else { - /* we want to preserve all params */ - type = camel_content_type_format (emif->base_type); - content_type = camel_content_type_decode (type); - g_free (type); - - g_free (content_type->type); - g_free (content_type->subtype); - content_type->type = g_strdup (emif_types[emif->state].type); - content_type->subtype = g_strdup (emif_types[emif->state].subtype); - } - - camel_data_wrapper_set_mime_type_field (dw, content_type); - camel_content_type_unref (content_type); - dw->encoding = encoding; - - part = camel_mime_part_new (); - camel_medium_set_content ((CamelMedium *)part, dw); - camel_mime_part_set_encoding (part, encoding); - g_object_unref (dw); - - if (emif->filename) - camel_mime_part_set_filename (part, emif->filename); - - /* pre-snoop the mime type of unknown objects, and poke and hack it into place */ - if (camel_content_type_is(dw->mime_type, "application", "octet-stream") - && (mimetype = em_format_snoop_type (part)) - && strcmp(mimetype, "application/octet-stream") != 0) { - camel_data_wrapper_set_mime_type (dw, mimetype); - camel_mime_part_set_content_type (part, mimetype); - if (emif->filename) - camel_mime_part_set_filename (part, emif->filename); - } - - g_free (emif->filename); - emif->filename = NULL; - - emif->parts = g_slist_append (emif->parts, part); -} - -static gint -inline_filter_scan (CamelMimeFilter *f, gchar *in, gsize len, gint final) -{ - EMInlineFilter *emif = (EMInlineFilter *)f; - gchar *inptr = in, *inend = in+len; - gchar *data_start = in; - gchar *start = in; - - while (inptr < inend) { - gint rest_len; - - start = inptr; - - while (inptr < inend && *inptr != '\n') - inptr++; - - if (inptr == inend && start == inptr) { - if (!final) { - camel_mime_filter_backup (f, start, inend-start); - inend = start; - } - break; - } - - rest_len = inend - start; - if (inptr < inend) - *inptr++ = 0; - - #define restore_inptr() G_STMT_START { if (inptr < inend) inptr[-1] = '\n'; } G_STMT_END - - switch (emif->state) { - case EMIF_PLAIN: - if (rest_len >= 45 && strncmp (start, "(This file must be converted with BinHex 4.0)", 45) == 0) { - restore_inptr (); - inline_filter_add_part (emif, data_start, start-data_start); - data_start = start; - emif->state = EMIF_BINHEX; - } else if (rest_len >= 11 && strncmp (start, "%!PS-Adobe-", 11) == 0) { - restore_inptr (); - inline_filter_add_part (emif, data_start, start-data_start); - data_start = start; - emif->state = EMIF_POSTSCRIPT; - } else if (rest_len >= 34 && strncmp (start, "-----BEGIN PGP SIGNED MESSAGE-----", 34) == 0) { - restore_inptr (); - inline_filter_add_part (emif, data_start, start-data_start); - data_start = start; - emif->state = EMIF_PGPSIGNED; - } else if (rest_len >= 27 && strncmp (start, "-----BEGIN PGP MESSAGE-----", 27) == 0) { - restore_inptr (); - inline_filter_add_part (emif, data_start, start-data_start); - data_start = start; - emif->state = EMIF_PGPENCRYPTED; - } - - break; - case EMIF_BINHEX: - if (inptr > (start+1) && inptr[-2] == ':') { - restore_inptr (); - inline_filter_add_part (emif, data_start, inptr-data_start); - data_start = inptr; - emif->state = EMIF_PLAIN; - } - break; - case EMIF_POSTSCRIPT: - if (rest_len >= 5 && strncmp (start, "%%EOF", 5) == 0) { - restore_inptr (); - inline_filter_add_part (emif, data_start, inptr-data_start); - data_start = inptr; - emif->state = EMIF_PLAIN; - } - break; - case EMIF_PGPSIGNED: - if (rest_len >= 27 && strncmp (start, "-----END PGP SIGNATURE-----", 27) == 0) { - restore_inptr (); - inline_filter_add_part (emif, data_start, inptr-data_start); - data_start = inptr; - emif->state = EMIF_PLAIN; - } - break; - case EMIF_PGPENCRYPTED: - if (rest_len >= 25 && strncmp (start, "-----END PGP MESSAGE-----", 25) == 0) { - restore_inptr (); - inline_filter_add_part (emif, data_start, inptr-data_start); - data_start = inptr; - emif->state = EMIF_PLAIN; - } - break; - } - - restore_inptr (); - - #undef restore_inptr - } - - if (final) { - /* always stop as plain, especially when not read those tags fully */ - emif->state = EMIF_PLAIN; - - inline_filter_add_part (emif, data_start, inend - data_start); - } else if (start > data_start) { - /* backup the last line, in case the tag is divided within buffers */ - camel_mime_filter_backup (f, start, inend - start); - g_byte_array_append (emif->data, (guchar *)data_start, start - data_start); - } else { - g_byte_array_append (emif->data, (guchar *)data_start, inend - data_start); - } - - return 0; -} - -static void -inline_filter_finalize (GObject *object) -{ - EMInlineFilter *emif = EM_INLINE_FILTER (object); - - if (emif->base_type) - camel_content_type_unref (emif->base_type); - - camel_mime_filter_reset (CAMEL_MIME_FILTER (object)); - g_byte_array_free (emif->data, TRUE); - g_free (emif->filename); - - /* Chain up to parent's finalize() method. */ - G_OBJECT_CLASS (em_inline_filter_parent_class)->finalize (object); -} - -static void -inline_filter_filter (CamelMimeFilter *filter, - const gchar *in, - gsize len, - gsize prespace, - gchar **out, - gsize *outlen, - gsize *outprespace) -{ - inline_filter_scan (filter, (gchar *)in, len, FALSE); - - *out = (gchar *)in; - *outlen = len; - *outprespace = prespace; -} - -static void -inline_filter_complete (CamelMimeFilter *filter, - const gchar *in, - gsize len, - gsize prespace, - gchar **out, - gsize *outlen, - gsize *outprespace) -{ - inline_filter_scan (filter, (gchar *)in, len, TRUE); - - *out = (gchar *)in; - *outlen = len; - *outprespace = prespace; -} - -static void -inline_filter_reset (CamelMimeFilter *filter) -{ - EMInlineFilter *emif = EM_INLINE_FILTER (filter); - GSList *l; - - l = emif->parts; - while (l) { - GSList *n = l->next; - - g_object_unref (l->data); - g_slist_free_1 (l); - - l = n; - } - emif->parts = NULL; - g_byte_array_set_size (emif->data, 0); -} - -static void -em_inline_filter_class_init (EMInlineFilterClass *class) -{ - GObjectClass *object_class; - CamelMimeFilterClass *mime_filter_class; - - object_class = G_OBJECT_CLASS (class); - object_class->finalize = inline_filter_finalize; - - mime_filter_class = CAMEL_MIME_FILTER_CLASS (class); - mime_filter_class->filter = inline_filter_filter; - mime_filter_class->complete = inline_filter_complete; - mime_filter_class->reset = inline_filter_reset; -} - -static void -em_inline_filter_init (EMInlineFilter *emif) -{ - emif->data = g_byte_array_new (); -} - -/** - * em_inline_filter_new: - * @base_encoding: The base transfer-encoding of the - * raw data being processed. - * @base_type: The base content-type of the raw data, should always be - * text/plain. - * - * Create a filter which will scan a (text) stream for - * embedded parts. You can then retrieve the contents - * as a CamelMultipart object. - * - * Return value: - **/ -EMInlineFilter * -em_inline_filter_new (CamelTransferEncoding base_encoding, CamelContentType *base_type) -{ - EMInlineFilter *emif; - - emif = g_object_new (EM_TYPE_INLINE_FILTER, NULL); - emif->base_encoding = base_encoding; - if (base_type) { - emif->base_type = base_type; - camel_content_type_ref (emif->base_type); - } - - return emif; -} - -CamelMultipart * -em_inline_filter_get_multipart (EMInlineFilter *emif) -{ - GSList *l = emif->parts; - CamelMultipart *mp; - - mp = camel_multipart_new (); - while (l) { - camel_multipart_add_part (mp, l->data); - l = l->next; - } - - return mp; -} diff --git a/mail/em-inline-filter.h b/mail/em-inline-filter.h deleted file mode 100644 index 8ee90a6640..0000000000 --- a/mail/em-inline-filter.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see - * - * - * Authors: - * Michael Zucchi - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef EM_INLINE_FILTER_H -#define EM_INLINE_FILTER_H - -#include - -/* Standard GObject macros */ -#define EM_TYPE_INLINE_FILTER \ - (em_inline_filter_get_type ()) -#define EM_INLINE_FILTER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST \ - ((obj), EM_TYPE_INLINE_FILTER, EMInlineFilter)) -#define EM_INLINE_FILTER_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_CAST \ - ((cls), EM_TYPE_INLINE_FILTER, EMInlineFilterClass)) -#define EM_IS_INLINE_FILTER(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE \ - ((obj), EM_TYPE_INLINE_FILTER)) -#define EM_IS_INLINE_FILTER_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_TYPE \ - ((cls), EM_TYPE_INLINE_FILTER)) -#define EM_INLINE_FILTER_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS \ - ((obj), EM_TYPE_INLINE_FILTER, EMInlineFilterClass)) - -G_BEGIN_DECLS - -typedef struct _EMInlineFilter EMInlineFilter; -typedef struct _EMInlineFilterClass EMInlineFilterClass; - -struct _EMInlineFilter { - CamelMimeFilter filter; - - gint state; - - CamelTransferEncoding base_encoding; - CamelContentType *base_type; - - GByteArray *data; - gchar *filename; - GSList *parts; -}; - -struct _EMInlineFilterClass { - CamelMimeFilterClass filter_class; -}; - -GType em_inline_filter_get_type (void); -EMInlineFilter *em_inline_filter_new (CamelTransferEncoding base_encoding, - CamelContentType *type); -CamelMultipart *em_inline_filter_get_multipart (EMInlineFilter *emif); - -G_END_DECLS - -#endif /* EM_INLINE_FILTER_H */ -- cgit v1.2.3