diff options
Diffstat (limited to 'em-format/em-format.c')
-rw-r--r-- | em-format/em-format.c | 2676 |
1 files changed, 0 insertions, 2676 deletions
diff --git a/em-format/em-format.c b/em-format/em-format.c deleted file mode 100644 index 9603dbd4cb..0000000000 --- a/em-format/em-format.c +++ /dev/null @@ -1,2676 +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 <http://www.gnu.org/licenses/> - * - * - * Authors: - * Michael Zucchi <notzed@ximian.com> - * Jeffrey Stedfast <fejj@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <string.h> -#include <gio/gio.h> -#include <glib/gi18n-lib.h> -#include <libsoup/soup-uri.h> - -#include "em-format.h" -#include "e-util/e-util.h" -#include "shell/e-shell.h" -#include "shell/e-shell-settings.h" - -#define d(x) - -#define EM_FORMAT_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE \ - ((obj), EM_TYPE_FORMAT, EMFormatPrivate)) - -struct _EMFormatPrivate { - GNode *current_node; - - CamelSession *session; - - CamelURL *base_url; - - gchar *charset; - gchar *default_charset; - gboolean composer; - - gint last_error; -}; - -enum { - PROP_0, - PROP_BASE_URL, - PROP_CHARSET, - PROP_COMPOSER, - PROP_DEFAULT_CHARSET, - PROP_SESSION -}; - -enum { - REDRAW_REQUESTED, - LAST_SIGNAL -}; - -gint signals[LAST_SIGNAL]; - -static gpointer parent_class; - -/* PARSERS */ -static void emf_parse_application_xpkcs7mime (EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable); -static void emf_parse_application_mbox (EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable); -static void emf_parse_multipart_alternative (EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable); -static void emf_parse_multipart_appledouble (EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable); -static void emf_parse_multipart_encrypted (EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable); -static void emf_parse_multipart_mixed (EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable); -static void emf_parse_multipart_signed (EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable); -static void emf_parse_multipart_related (EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable); -static void emf_parse_multipart_digest (EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable); -static void emf_parse_message_deliverystatus (EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable); -static void emf_parse_inlinepgp_signed (EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable); -static void emf_parse_inlinepgp_encrypted (EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable); -static void emf_parse_message (EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable); -static void emf_parse_headers (EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable); -static void emf_parse_post_headers (EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable); -static void emf_parse_source (EMFormat *emf, CamelMimePart *part, GString *part_id, EMFormatParserInfo *info, GCancellable *cancellable); - -/* WRITERS */ -static void emf_write_text (EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable); -static void emf_write_source (EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable); -static void emf_write_error (EMFormat *emf, EMFormatPURI *puri, CamelStream *stream, EMFormatWriterInfo *info, GCancellable *cancellable); - -/**************************************************************************/ - -static gboolean -is_secured (CamelMimePart *part) -{ - CamelContentType *ct = camel_mime_part_get_content_type (part); - - return (camel_content_type_is (ct, "multipart", "signed") || - camel_content_type_is (ct, "multipart", "encrypted") || - camel_content_type_is (ct, "application", "x-inlinepgp-signed") || - camel_content_type_is (ct, "application", "x-inlinepgp-encrypted") || - camel_content_type_is (ct, "application", "x-pkcs7-mime") || - camel_content_type_is (ct, "application", "pkcs7-mime")); -} - -static void -preserve_charset_in_content_type (CamelMimePart *ipart, - CamelMimePart *opart) -{ - CamelDataWrapper *data_wrapper; - CamelContentType *content_type; - const gchar *charset; - - g_return_if_fail (ipart != NULL); - g_return_if_fail (opart != NULL); - - data_wrapper = camel_medium_get_content (CAMEL_MEDIUM (ipart)); - content_type = camel_data_wrapper_get_mime_type_field (data_wrapper); - - if (content_type == NULL) - return; - - charset = camel_content_type_param (content_type, "charset"); - - if (charset == NULL || *charset == '\0') - return; - - data_wrapper = camel_medium_get_content (CAMEL_MEDIUM (opart)); - content_type = camel_data_wrapper_get_mime_type_field (data_wrapper); - if (content_type) - camel_content_type_set_param (content_type, "charset", charset); - - /* update charset also on the part itself */ - data_wrapper = CAMEL_DATA_WRAPPER (opart); - content_type = camel_data_wrapper_get_mime_type_field (data_wrapper); - if (content_type) - camel_content_type_set_param (content_type, "charset", charset); -} - -static CamelMimePart * -get_related_display_part (CamelMimePart *part, - gint *out_displayid) -{ - CamelMultipart *mp; - CamelMimePart *body_part, *display_part = NULL; - CamelContentType *content_type; - const gchar *start; - gint i, nparts, displayid = 0; - - mp = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part); - - if (!CAMEL_IS_MULTIPART (mp)) - return NULL; - - nparts = camel_multipart_get_number (mp); - content_type = camel_mime_part_get_content_type (part); - start = camel_content_type_param (content_type, "start"); - if (start && strlen (start) > 2) { - gint len; - const gchar *cid; - - /* strip <>'s from CID */ - len = strlen (start) - 2; - start++; - - for (i = 0; i < nparts; i++) { - body_part = camel_multipart_get_part (mp, i); - cid = camel_mime_part_get_content_id (body_part); - - if (cid && !strncmp (cid, start, len) && strlen (cid) == len) { - display_part = body_part; - displayid = i; - break; - } - } - } else { - display_part = camel_multipart_get_part (mp, 0); - } - - if (out_displayid) - *out_displayid = displayid; - - return display_part; -} - -static gboolean -related_display_part_is_attachment (EMFormat *emf, - CamelMimePart *part) -{ - CamelMimePart *display_part; - - display_part = get_related_display_part (part, NULL); - return display_part && em_format_is_attachment (emf, display_part); -} - -/**************************************************************************/ -void -em_format_empty_parser (EMFormat *emf, - CamelMimePart *part, - GString *part_id, - EMFormatParserInfo *info, - GCancellable *cancellable) -{ - /* DO NOTHING */ -} - -#ifdef ENABLE_SMIME -static void -emf_parse_application_xpkcs7mime (EMFormat *emf, - CamelMimePart *part, - GString *part_id, - EMFormatParserInfo *info, - GCancellable *cancellable) -{ - CamelCipherContext *context; - CamelMimePart *opart; - CamelCipherValidity *valid; - GError *local_error = NULL; - - if (g_cancellable_is_cancelled (cancellable)) - return; - - context = camel_smime_context_new (emf->priv->session); - - opart = camel_mime_part_new (); - valid = camel_cipher_context_decrypt_sync ( - context, part, opart, cancellable, &local_error); - preserve_charset_in_content_type (part, opart); - if (valid == NULL) { - em_format_format_error ( - emf, "%s", - local_error->message ? local_error->message : - _("Could not parse S/MIME message: Unknown error")); - g_clear_error (&local_error); - } else { - EMFormatParserInfo encinfo = { - info->handler, - info->validity_type | EM_FORMAT_VALIDITY_FOUND_ENCRYPTED | EM_FORMAT_VALIDITY_FOUND_SMIME, - valid - }; - gint len = part_id->len; - - g_string_append (part_id, ".encrypted"); - em_format_parse_part (emf, opart, part_id, &encinfo, cancellable); - g_string_truncate (part_id, len); - - /* Add a widget with details about the encryption, but only when - * the encrypted isn't itself secured, in that case it has created - * the button itself */ - if (!is_secured (opart)) { - g_string_append (part_id, ".encrypted.button"); - em_format_parse_part_as (emf, part, part_id, &encinfo, - "x-evolution/message/x-secure-button", cancellable); - g_string_truncate (part_id, len); - } - - camel_cipher_validity_free (valid); - } - - g_object_unref (opart); - g_object_unref (context); -} -#endif - -/* RFC 4155 */ -static void -emf_parse_application_mbox (EMFormat *emf, - CamelMimePart *mime_part, - GString *part_id, - EMFormatParserInfo *info, - GCancellable *cancellable) -{ - CamelMimeParser *parser; - CamelStream *mem_stream; - camel_mime_parser_state_t state; - gint old_len; - gint messages; - - if (g_cancellable_is_cancelled (cancellable)) - return; - - /* Extract messages from the application/mbox part and - * render them as a flat list of messages. */ - - /* XXX If the mbox has multiple messages, maybe render them - * as a multipart/digest so each message can be expanded - * or collapsed individually. - * - * See attachment_handler_mail_x_uid_list() for example. */ - - /* XXX This is based on em_utils_read_messages_from_stream(). - * Perhaps refactor that function to return an array of - * messages instead of assuming we want to append them - * to a folder? */ - - parser = camel_mime_parser_new (); - camel_mime_parser_scan_from (parser, TRUE); - - mem_stream = camel_stream_mem_new (); - camel_data_wrapper_decode_to_stream_sync ( - camel_medium_get_content (CAMEL_MEDIUM (mime_part)), - mem_stream, NULL, NULL); - g_seekable_seek (G_SEEKABLE (mem_stream), 0, G_SEEK_SET, NULL, NULL); - camel_mime_parser_init_with_stream (parser, mem_stream, NULL); - g_object_unref (mem_stream); - - old_len = part_id->len; - - /* Extract messages from the mbox. */ - messages = 0; - state = camel_mime_parser_step (parser, NULL, NULL); - - while (state == CAMEL_MIME_PARSER_STATE_FROM) { - CamelMimeMessage *message; - - message = camel_mime_message_new (); - mime_part = CAMEL_MIME_PART (message); - - if (!camel_mime_part_construct_from_parser_sync ( - mime_part, parser, NULL, NULL)) { - g_object_unref (message); - break; - } - - g_string_append_printf (part_id, ".mbox.%d", messages); - em_format_parse_part_as (emf, CAMEL_MIME_PART (message), - part_id, info, "message/rfc822", cancellable); - g_string_truncate (part_id, old_len); - - g_object_unref (message); - - /* Skip past CAMEL_MIME_PARSER_STATE_FROM_END. */ - camel_mime_parser_step (parser, NULL, NULL); - - state = camel_mime_parser_step (parser, NULL, NULL); - - messages++; - } - - g_object_unref (parser); -} - -/* RFC 1740 */ -static void -emf_parse_multipart_alternative (EMFormat *emf, - CamelMimePart *part, - GString *part_id, - EMFormatParserInfo *info, - GCancellable *cancellable) -{ - CamelMultipart *mp; - gint i, nparts, bestid = 0; - CamelMimePart *best = NULL; - - if (g_cancellable_is_cancelled (cancellable)) - return; - - mp = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part); - - if (!CAMEL_IS_MULTIPART (mp)) { - emf_parse_source (emf, part, part_id, info, cancellable); - return; - } - - /* as per rfc, find the last part we know how to display */ - nparts = camel_multipart_get_number (mp); - for (i = 0; i < nparts; i++) { - CamelMimePart *mpart; - CamelDataWrapper *data_wrapper; - CamelContentType *type; - CamelStream *null_stream; - gchar *mime_type; - gsize content_size; - - if (g_cancellable_is_cancelled (cancellable)) - return; - - /* is it correct to use the passed in *part here? */ - mpart = camel_multipart_get_part (mp, i); - - if (mpart == NULL) - continue; - - /* This may block even though the stream does not. - * XXX Pretty inefficient way to test if the MIME part - * is empty. Surely there's a quicker way? */ - null_stream = camel_stream_null_new (); - data_wrapper = camel_medium_get_content (CAMEL_MEDIUM (mpart)); - camel_data_wrapper_decode_to_stream_sync ( - data_wrapper, null_stream, cancellable, NULL); - content_size = CAMEL_STREAM_NULL (null_stream)->written; - g_object_unref (null_stream); - - if (content_size == 0) - continue; - - type = camel_mime_part_get_content_type (mpart); - mime_type = camel_content_type_simple (type); - - camel_strdown (mime_type); - - if (!em_format_is_attachment (emf, mpart) && - ((camel_content_type_is (type, "multipart", "related") == 0) || - !related_display_part_is_attachment (emf, mpart)) && - (em_format_find_handler (emf, mime_type) - || (best == NULL && em_format_fallback_handler (emf, mime_type)))) { - best = mpart; - bestid = i; - } - - g_free (mime_type); - } - - if (best) { - gint len = part_id->len; - - g_string_append_printf(part_id, ".alternative.%d", bestid); - em_format_parse_part (emf, best, part_id, info, cancellable); - g_string_truncate (part_id, len); - } else - emf_parse_multipart_mixed (emf, part, part_id, info, cancellable); -} - -/* RFC 1740 */ -static void -emf_parse_multipart_appledouble (EMFormat *emf, - CamelMimePart *part, - GString *part_id, - EMFormatParserInfo *info, - GCancellable *cancellable) -{ - CamelMultipart *mp; - CamelMimePart *mime_part; - - if (g_cancellable_is_cancelled (cancellable)) - return; - - mp = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part); - - if (!CAMEL_IS_MULTIPART (mp)) { - emf_parse_source (emf, part, part_id, info, cancellable); - return; - } - - mime_part = camel_multipart_get_part (mp, 1); - if (mime_part) { - gint len; - /* try the data fork for something useful, doubtful but who knows */ - len = part_id->len; - g_string_append_printf(part_id, ".appledouble.1"); - em_format_parse_part (emf, mime_part, part_id, info, cancellable); - g_string_truncate (part_id, len); - } else { - emf_parse_source (emf, part, part_id, info, cancellable); - } -} - -static void -emf_parse_multipart_encrypted (EMFormat *emf, - CamelMimePart *part, - GString *part_id, - EMFormatParserInfo *info, - GCancellable *cancellable) -{ - CamelCipherContext *context; - const gchar *protocol; - CamelMimePart *opart; - CamelCipherValidity *valid; - CamelMultipartEncrypted *mpe; - GError *local_error = NULL; - - if (g_cancellable_is_cancelled (cancellable)) - return; - - mpe = (CamelMultipartEncrypted *) camel_medium_get_content ((CamelMedium *) part); - if (!CAMEL_IS_MULTIPART_ENCRYPTED (mpe)) { - em_format_format_error ( - emf, _("Could not parse MIME message. " - "Displaying as source.")); - emf_parse_source (emf, part, part_id, info, cancellable); - return; - } - - /* Currently we only handle RFC2015-style PGP encryption. */ - protocol = camel_content_type_param ( - ((CamelDataWrapper *)mpe)->mime_type, "protocol"); - if (!protocol || g_ascii_strcasecmp (protocol, "application/pgp-encrypted") != 0) { - em_format_format_error (emf, _("Unsupported encryption type for multipart/encrypted")); - emf_parse_multipart_mixed (emf, part, part_id, info, cancellable); - return; - } - - context = camel_gpg_context_new (emf->priv->session); - opart = camel_mime_part_new (); - valid = camel_cipher_context_decrypt_sync ( - context, part, opart, cancellable, &local_error); - preserve_charset_in_content_type (part, opart); - if (valid == NULL) { - em_format_format_error ( - emf, local_error->message ? - _("Could not parse PGP/MIME message") : - _("Could not parse PGP/MIME message: Unknown error")); - if (local_error->message != NULL) - em_format_format_error ( - emf, "%s", local_error->message); - g_clear_error (&local_error); - emf_parse_multipart_mixed (emf, part, part_id, info, cancellable); - } else { - gint len = part_id->len; - - EMFormatParserInfo encinfo = { - info->handler, - info->validity_type | EM_FORMAT_VALIDITY_FOUND_ENCRYPTED | EM_FORMAT_VALIDITY_FOUND_PGP, - }; - - if (info->validity) - camel_cipher_validity_envelope (valid, info->validity); - - encinfo.validity = valid; - - g_string_append (part_id, ".encrypted"); - em_format_parse_part (emf, opart, part_id, &encinfo, cancellable); - g_string_truncate (part_id, len); - - /* Add a widget with details about the encryption, but only when - * the encrypted isn't itself secured, in that case it has created - * the button itself */ - if (!is_secured (opart)) { - g_string_append (part_id, ".encrypted.button"); - em_format_parse_part_as (emf, part, part_id, &encinfo, - "x-evolution/message/x-secure-button", cancellable); - g_string_truncate (part_id, len); - } - - camel_cipher_validity_free (valid); - } - - /* TODO: Make sure when we finalize this part, it is zero'd out */ - g_object_unref (opart); - g_object_unref (context); -} - -/* RFC 2046 */ -static void -emf_parse_multipart_mixed (EMFormat *emf, - CamelMimePart *part, - GString *part_id, - EMFormatParserInfo *info, - GCancellable *cancellable) -{ - CamelMultipart *mp; - gint i, nparts, len; - - if (g_cancellable_is_cancelled (cancellable)) - return; - - mp = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part); - - if (!CAMEL_IS_MULTIPART (mp)) { - emf_parse_source (emf, part, part_id, info, cancellable); - return; - } - - len = part_id->len; - nparts = camel_multipart_get_number (mp); - for (i = 0; i < nparts; i++) { - CamelMimePart *subpart; - - subpart = camel_multipart_get_part (mp, i); - - g_string_append_printf(part_id, ".mixed.%d", i); - em_format_parse_part (emf, subpart, part_id, info, cancellable); - g_string_truncate (part_id, len); - } -} - -static void -emf_parse_multipart_signed (EMFormat *emf, - CamelMimePart *part, - GString *part_id, - EMFormatParserInfo *info, - GCancellable *cancellable) -{ - CamelMimePart *cpart; - CamelMultipartSigned *mps; - CamelCipherContext *cipher = NULL; - guint32 validity_type; - - if (g_cancellable_is_cancelled (cancellable)) - return; - - mps = (CamelMultipartSigned *) camel_medium_get_content ((CamelMedium *) part); - if (!CAMEL_IS_MULTIPART_SIGNED (mps) - || (cpart = camel_multipart_get_part ((CamelMultipart *) mps, - CAMEL_MULTIPART_SIGNED_CONTENT)) == NULL) { - em_format_format_error ( - emf, _("Could not parse MIME message. " - "Displaying as source.")); - emf_parse_source (emf, part, part_id, info, cancellable); - return; - } - - /* FIXME: Should be done via a plugin interface */ - /* FIXME: duplicated in em-format-html-display.c */ - if (mps->protocol) { -#ifdef ENABLE_SMIME - if (g_ascii_strcasecmp("application/x-pkcs7-signature", mps->protocol) == 0 - || g_ascii_strcasecmp("application/pkcs7-signature", mps->protocol) == 0) { - cipher = camel_smime_context_new (emf->priv->session); - validity_type = EM_FORMAT_VALIDITY_FOUND_SMIME; - } else -#endif - if (g_ascii_strcasecmp("application/pgp-signature", mps->protocol) == 0) { - cipher = camel_gpg_context_new (emf->priv->session); - validity_type = EM_FORMAT_VALIDITY_FOUND_PGP; - } - } - - if (cipher == NULL) { - em_format_format_error(emf, _("Unsupported signature format")); - emf_parse_multipart_mixed (emf, part, part_id, info, cancellable); - } else { - CamelCipherValidity *valid; - GError *local_error = NULL; - - valid = camel_cipher_context_verify_sync ( - cipher, part, cancellable, &local_error); - if (valid == NULL) { - em_format_format_error ( - emf, local_error->message ? - _("Error verifying signature") : - _("Unknown error verifying signature")); - if (local_error->message != NULL) - em_format_format_error ( - emf, "%s", - local_error->message); - g_clear_error (&local_error); - emf_parse_multipart_mixed (emf, part, part_id,info, cancellable); - } else { - gint i, nparts, len = part_id->len; - gboolean secured; - - EMFormatParserInfo signinfo = { - info->handler, - info->validity_type | validity_type | EM_FORMAT_VALIDITY_FOUND_SIGNED, - }; - - if (info->validity) - camel_cipher_validity_envelope (valid, info->validity); - signinfo.validity = valid; - - nparts = camel_multipart_get_number (CAMEL_MULTIPART (mps)); - secured = FALSE; - for (i = 0; i < nparts; i++) { - CamelMimePart *subpart; - subpart = camel_multipart_get_part (CAMEL_MULTIPART (mps), i); - - g_string_append_printf(part_id, ".signed.%d", i); - em_format_parse_part (emf, subpart, part_id, &signinfo, cancellable); - g_string_truncate (part_id, len); - - if (!secured) - secured = is_secured (subpart); - } - - /* Add a widget with details about the encryption, but only when - * the encrypted isn't itself secured, in that case it has created - * the button itself */ - if (!secured) { - g_string_append (part_id, ".signed.button"); - em_format_parse_part_as (emf, part, part_id, &signinfo, - "x-evolution/message/x-secure-button", cancellable); - g_string_truncate (part_id, len); - } - - camel_cipher_validity_free (valid); - } - } - - g_object_unref (cipher); -} - -/* RFC 2046 */ -static void -emf_parse_multipart_digest (EMFormat *emf, - CamelMimePart *part, - GString *part_id, - EMFormatParserInfo *info, - GCancellable *cancellable) -{ - CamelMultipart *mp; - gint i, nparts, len; - - if (g_cancellable_is_cancelled (cancellable)) - return; - - mp = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part); - - if (!CAMEL_IS_MULTIPART (mp)) { - emf_parse_source (emf, part, part_id, info, cancellable); - return; - } - - len = part_id->len; - nparts = camel_multipart_get_number (mp); - for (i = 0; i < nparts; i++) { - CamelMimePart *subpart; - CamelContentType *ct; - gchar *cts; - const EMFormatHandler *handler; - - subpart = camel_multipart_get_part (mp, i); - - if (!subpart) - continue; - - g_string_append_printf(part_id, ".digest.%d", i); - - ct = camel_mime_part_get_content_type (subpart); - /* According to RFC this shouldn't happen, but who knows... */ - if (ct && !camel_content_type_is (ct, "message", "rfc822")) { - cts = camel_content_type_simple (ct); - em_format_parse_part_as (emf, part, part_id, info, cts, cancellable); - g_free (cts); - g_string_truncate (part_id, len); - continue; - } - - handler = em_format_find_handler (emf, "message/rfc822"); - if (handler && handler->parse_func) - handler->parse_func (emf, subpart, part_id, info, cancellable); - - g_string_truncate (part_id, len); - } -} - -/* RFC 2387 */ -static void -emf_parse_multipart_related (EMFormat *emf, - CamelMimePart *part, - GString *part_id, - EMFormatParserInfo *info, - GCancellable *cancellable) -{ - CamelMultipart *mp; - CamelMimePart *body_part, *display_part = NULL; - gint i, nparts, partidlen, displayid = 0; - - if (g_cancellable_is_cancelled (cancellable)) - return; - - mp = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part); - - if (!CAMEL_IS_MULTIPART (mp)) { - emf_parse_source (emf, part, part_id, info, cancellable); - return; - } - - display_part = get_related_display_part (part, &displayid); - - if (display_part == NULL) { - emf_parse_multipart_mixed ( - emf, part, part_id, info, cancellable); - return; - } - - /* The to-be-displayed part goes first */ - partidlen = part_id->len; - g_string_append_printf(part_id, ".related.%d", displayid); - em_format_parse_part (emf, display_part, part_id, info, cancellable); - g_string_truncate (part_id, partidlen); - - /* Process the related parts */ - nparts = camel_multipart_get_number (mp); - for (i = 0; i < nparts; i++) { - body_part = camel_multipart_get_part (mp, i); - if (body_part != display_part) { - g_string_append_printf(part_id, ".related.%d", i); - em_format_parse_part (emf, body_part, part_id, info, cancellable); - g_string_truncate (part_id, partidlen); - } - } -} - -static void -emf_parse_message_deliverystatus (EMFormat *emf, - CamelMimePart *part, - GString *part_id, - EMFormatParserInfo *info, - GCancellable *cancellable) -{ - EMFormatPURI *puri; - gint len; - - if (g_cancellable_is_cancelled (cancellable)) - return; - - len = part_id->len; - g_string_append (part_id, ".deliverystatus"); - - puri = em_format_puri_new (emf, sizeof (EMFormatPURI), part, part_id->str); - puri->write_func = emf_write_text; - puri->mime_type = g_strdup ("text/html"); - puri->validity = info->validity ? camel_cipher_validity_clone (info->validity) : NULL; - puri->validity_type = info->validity_type; - - g_string_truncate (part_id, len); - - em_format_add_puri (emf, puri); -} - -static void -emf_parse_inlinepgp_signed (EMFormat *emf, - CamelMimePart *ipart, - GString *part_id, - EMFormatParserInfo *info, - GCancellable *cancellable) -{ - CamelStream *filtered_stream; - CamelMimeFilterPgp *pgp_filter; - CamelContentType *content_type; - CamelCipherContext *cipher; - CamelCipherValidity *valid; - CamelDataWrapper *dw; - CamelMimePart *opart; - CamelStream *ostream; - gchar *type; - gint len; - GError *local_error = NULL; - EMFormatParserInfo signinfo; - GByteArray *ba; - - if (g_cancellable_is_cancelled (cancellable)) - return; - - if (!ipart) { - em_format_format_error(emf, _("Unknown error verifying signature")); - return; - } - - cipher = camel_gpg_context_new (emf->priv->session); - /* Verify the signature of the message */ - valid = camel_cipher_context_verify_sync ( - cipher, ipart, cancellable, &local_error); - if (!valid) { - em_format_format_error ( - emf, local_error->message ? - _("Error verifying signature") : - _("Unknown error verifying signature")); - if (local_error->message) - em_format_format_error ( - emf, "%s", local_error->message); - emf_parse_source (emf, ipart, part_id, info, cancellable); - /* XXX I think this will loop: - * em_format_part_as(emf, stream, part, "text/plain"); */ - g_clear_error (&local_error); - g_object_unref (cipher); - return; - } - - /* Setup output stream */ - ostream = camel_stream_mem_new (); - filtered_stream = camel_stream_filter_new (ostream); - - /* Add PGP header / footer filter */ - pgp_filter = (CamelMimeFilterPgp *) camel_mime_filter_pgp_new (); - camel_stream_filter_add ( - CAMEL_STREAM_FILTER (filtered_stream), - CAMEL_MIME_FILTER (pgp_filter)); - g_object_unref (pgp_filter); - - /* Pass through the filters that have been setup */ - dw = camel_medium_get_content ((CamelMedium *) ipart); - camel_data_wrapper_decode_to_stream_sync ( - dw, (CamelStream *) filtered_stream, cancellable, NULL); - camel_stream_flush ((CamelStream *) filtered_stream, cancellable, NULL); - g_object_unref (filtered_stream); - - /* Create a new text/plain MIME part containing the signed - * content preserving the original part's Content-Type params. */ - content_type = camel_mime_part_get_content_type (ipart); - type = camel_content_type_format (content_type); - content_type = camel_content_type_decode (type); - g_free (type); - - g_free (content_type->type); - content_type->type = g_strdup ("text"); - g_free (content_type->subtype); - content_type->subtype = g_strdup ("plain"); - type = camel_content_type_format (content_type); - camel_content_type_unref (content_type); - - ba = camel_stream_mem_get_byte_array ((CamelStreamMem *) ostream); - opart = camel_mime_part_new (); - camel_mime_part_set_content (opart, (gchar *) ba->data, ba->len, type); - g_free (type); - - if (info->validity) - camel_cipher_validity_envelope (valid, info->validity); - - /* Pass it off to the real formatter */ - len = part_id->len; - g_string_append (part_id, ".inlinepgp_signed"); - signinfo.handler = info->handler; - signinfo.validity_type = info->validity_type | EM_FORMAT_VALIDITY_FOUND_SIGNED | EM_FORMAT_VALIDITY_FOUND_PGP; - signinfo.validity = valid; - em_format_parse_part (emf, opart, part_id, &signinfo, cancellable); - g_string_truncate (part_id, len); - - /* Add a widget with details about the encryption, but only when - * the encrypted isn't itself secured, in that case it has created - * the button itself */ - if (!is_secured (opart)) { - g_string_append (part_id, ".inlinepgp_signed.button"); - em_format_parse_part_as (emf, opart, part_id, &signinfo, - "x-evolution/message/x-secure-button", cancellable); - g_string_truncate (part_id, len); - } - - /* Clean Up */ - camel_cipher_validity_free (valid); - g_object_unref (dw); - g_object_unref (opart); - g_object_unref (ostream); - g_object_unref (cipher); -} - -static void -emf_parse_inlinepgp_encrypted (EMFormat *emf, - CamelMimePart *ipart, - GString *part_id, - EMFormatParserInfo *info, - GCancellable *cancellable) -{ - CamelCipherContext *cipher; - CamelCipherValidity *valid; - CamelMimePart *opart; - CamelDataWrapper *dw; - gchar *mime_type; - gint len; - GError *local_error = NULL; - EMFormatParserInfo encinfo; - - if (g_cancellable_is_cancelled (cancellable)) - return; - - cipher = camel_gpg_context_new (emf->priv->session); - opart = camel_mime_part_new (); - - /* Decrypt the message */ - valid = camel_cipher_context_decrypt_sync ( - cipher, ipart, opart, cancellable, &local_error); - - if (!valid) { - em_format_format_error ( - emf, _("Could not parse PGP message: ")); - if (local_error->message != NULL) - em_format_format_error ( - emf, "%s", local_error->message); - else - em_format_format_error ( - emf, _("Unknown error")); - emf_parse_source (emf, ipart, part_id, info, cancellable); - /* XXX I think this will loop: - * em_format_part_as(emf, stream, part, "text/plain"); */ - - g_clear_error (&local_error); - g_object_unref (cipher); - g_object_unref (opart); - return; - } - - dw = camel_medium_get_content ((CamelMedium *) opart); - mime_type = camel_data_wrapper_get_mime_type (dw); - - /* this ensures to show the 'opart' as inlined, if possible */ - if (mime_type && g_ascii_strcasecmp (mime_type, "application/octet-stream") == 0) { - const gchar *snoop = em_format_snoop_type (opart); - - if (snoop) - camel_data_wrapper_set_mime_type (dw, snoop); - } - - preserve_charset_in_content_type (ipart, opart); - g_free (mime_type); - - if (info->validity) - camel_cipher_validity_envelope (valid, info->validity); - - /* Pass it off to the real formatter */ - len = part_id->len; - g_string_append (part_id, ".inlinepgp_encrypted"); - encinfo.handler = info->handler; - encinfo.validity_type = info->validity_type | EM_FORMAT_VALIDITY_FOUND_ENCRYPTED | EM_FORMAT_VALIDITY_FOUND_PGP; - encinfo.validity = valid; - em_format_parse_part (emf, opart, part_id, &encinfo, cancellable); - g_string_truncate (part_id, len); - - /* Add a widget with details about the encryption, but only when - * the encrypted isn't itself secured, in that case it has created - * the button itself */ - if (!is_secured (opart)) { - g_string_append (part_id, ".inlinepgp_encrypted.button"); - em_format_parse_part_as (emf, opart, part_id, &encinfo, - "x-evolution/message/x-secure-button", cancellable); - g_string_truncate (part_id, len); - } - - /* Clean Up */ - camel_cipher_validity_free (valid); - g_object_unref (opart); - g_object_unref (cipher); -} - -static void -emf_parse_message (EMFormat *emf, - CamelMimePart *part, - GString *part_id, - EMFormatParserInfo *info, - GCancellable *cancellable) -{ - /* Headers */ - info->force_handler = TRUE; - em_format_parse_part_as (emf, part, part_id, info, - "x-evolution/message/headers", cancellable); - - /* Anything that comes between headers and message body */ - info->force_handler = TRUE; - em_format_parse_part_as (emf, part, part_id, info, - "x-evolution/message/post-headers", cancellable); - - /* Begin parsing the message */ - info->force_handler = FALSE; - em_format_parse_part (emf, part, part_id, info, cancellable); -} - -static void -emf_parse_headers (EMFormat *emf, - CamelMimePart *part, - GString *part_id, - EMFormatParserInfo *info, - GCancellable *cancellable) -{ - EMFormatPURI *puri; - gint len; - - len = part_id->len; - g_string_append (part_id, ".headers"); - - puri = em_format_puri_new (emf, sizeof (EMFormatPURI), part, part_id->str); - puri->write_func = info->handler->write_func; - puri->mime_type = g_strdup ("text/html"); - em_format_add_puri (emf, puri); - - g_string_truncate (part_id, len); -} - -static void -emf_parse_post_headers (EMFormat *emf, - CamelMimePart *part, - GString *part_id, - EMFormatParserInfo *info, - GCancellable *cancellable) -{ - /* Add attachment bar */ - info->force_handler = TRUE; - em_format_parse_part_as (emf, part, part_id, info, - "x-evolution/message/attachment-bar", cancellable); -} - -static void -emf_parse_source (EMFormat *emf, - CamelMimePart *part, - GString *part_id, - EMFormatParserInfo *info, - GCancellable *cancellable) -{ - EMFormatPURI *puri; - gint len; - - if (g_cancellable_is_cancelled (cancellable)) - return; - - len = part_id->len; - g_string_append (part_id, ".source"); - - puri = em_format_puri_new (emf, sizeof (EMFormatPURI), part, part_id->str); - puri->write_func = info->handler->write_func; - puri->mime_type = g_strdup ("text/html"); - g_string_truncate (part_id, len); - - em_format_add_puri (emf, puri); -} - -/**************************************************************************/ - -void -em_format_empty_writer (EMFormat *emf, - EMFormatPURI *puri, - CamelStream *stream, - EMFormatWriterInfo *info, - GCancellable *cancellable) -{ - /* DO NOTHING */ -} - -static void -emf_write_error (EMFormat *emf, - EMFormatPURI *puri, - CamelStream *stream, - EMFormatWriterInfo *info, - GCancellable *cancellable) -{ - camel_data_wrapper_decode_to_stream_sync ((CamelDataWrapper *) puri->part, - stream, cancellable, NULL); -} - -static void -emf_write_text (EMFormat *emf, - EMFormatPURI *puri, - CamelStream *stream, - EMFormatWriterInfo *info, - GCancellable *cancellable) -{ - CamelContentType *ct; - - ct = camel_mime_part_get_content_type (puri->part); - if (!camel_content_type_is (ct, "text", "plain")) { - camel_stream_write_string (stream, _("Cannot proccess non-text mime/part"), - cancellable, NULL); - return; - } - - camel_data_wrapper_decode_to_stream_sync ((CamelDataWrapper *) puri->part, - stream, cancellable, NULL); -} - -static void -emf_write_source (EMFormat *emf, - EMFormatPURI *puri, - CamelStream *stream, - EMFormatWriterInfo *info, - GCancellable *cancellable) -{ - GByteArray *ba; - gchar *data; - - g_return_if_fail (EM_IS_FORMAT (emf)); - - ba = camel_data_wrapper_get_byte_array ((CamelDataWrapper *) puri->part); - - data = g_strndup ((gchar *) ba->data, ba->len); - camel_stream_write_string (stream, data, cancellable, NULL); - g_free (data); -} - -/**************************************************************************/ - -static gboolean -emf_is_inline (EMFormat *emf, - const gchar *part_id, - CamelMimePart *mime_part, - const EMFormatHandler *handle) -{ - //EMFormatCache *emfc; - const gchar *disposition; - - if (handle == NULL) - return FALSE; - - /* Some types need to override the disposition. - * e.g. application/x-pkcs7-mime */ - if (handle->flags & EM_FORMAT_HANDLER_INLINE_DISPOSITION) - return TRUE; - - disposition = camel_mime_part_get_disposition (mime_part); - if (disposition != NULL) - return g_ascii_strcasecmp (disposition, "inline") == 0; - - /* Otherwise, use the default for this handler type. */ - return (handle->flags & EM_FORMAT_HANDLER_INLINE) != 0; -} - -/**************************************************************************/ - -static EMFormatHandler type_handlers[] = { -#ifdef ENABLE_SMIME - { (gchar *) "application/x-pkcs7-mime", emf_parse_application_xpkcs7mime, 0, EM_FORMAT_HANDLER_INLINE_DISPOSITION }, -#endif - { (gchar *) "application/mbox", emf_parse_application_mbox, 0, EM_FORMAT_HANDLER_INLINE | EM_FORMAT_HANDLER_COMPOUND_TYPE }, - { (gchar *) "multipart/alternative", emf_parse_multipart_alternative, }, - { (gchar *) "multipart/appledouble", emf_parse_multipart_appledouble, }, - { (gchar *) "multipart/encrypted", emf_parse_multipart_encrypted, }, - { (gchar *) "multipart/mixed", emf_parse_multipart_mixed, }, - { (gchar *) "multipart/signed", emf_parse_multipart_signed, }, - { (gchar *) "multipart/related", emf_parse_multipart_related, }, - { (gchar *) "multipart/digest", emf_parse_multipart_digest, 0, EM_FORMAT_HANDLER_COMPOUND_TYPE }, - { (gchar *) "multipart/*", emf_parse_multipart_mixed, 0, EM_FORMAT_HANDLER_COMPOUND_TYPE }, - { (gchar *) "message/deliverystatus", emf_parse_message_deliverystatus, 0, }, - - /* Ignore PGP signature part */ - { (gchar *) "application/pgp-signature", em_format_empty_parser, }, - - /* Insert brokenly-named parts here */ -#ifdef ENABLE_SMIME - { (gchar *) "application/pkcs7-mime", emf_parse_application_xpkcs7mime, 0, EM_FORMAT_HANDLER_INLINE_DISPOSITION }, -#endif - - /* internal types */ - { (gchar *) "application/x-inlinepgp-signed", emf_parse_inlinepgp_signed, }, - { (gchar *) "application/x-inlinepgp-encrypted", emf_parse_inlinepgp_encrypted, }, - { (gchar *) "x-evolution/message", emf_parse_message, 0, EM_FORMAT_HANDLER_COMPOUND_TYPE }, - { (gchar *) "x-evolution/message/headers", emf_parse_headers, }, - { (gchar *) "x-evolution/message/post-headers", emf_parse_post_headers, }, - { (gchar *) "x-evolution/message/source", emf_parse_source, emf_write_source }, -}; - -/* note: also copied in em-mailer-prefs.c */ -static const struct { - const gchar *name; - guint32 flags; -} default_headers[] = { - { N_("From"), EM_FORMAT_HEADER_BOLD }, - { N_("Reply-To"), EM_FORMAT_HEADER_BOLD }, - { N_("To"), EM_FORMAT_HEADER_BOLD }, - { N_("Cc"), EM_FORMAT_HEADER_BOLD }, - { N_("Bcc"), EM_FORMAT_HEADER_BOLD }, - { N_("Subject"), EM_FORMAT_HEADER_BOLD }, - { N_("Date"), EM_FORMAT_HEADER_BOLD }, - { N_("Newsgroups"), EM_FORMAT_HEADER_BOLD }, - { N_("Face"), 0 }, -}; - -static void -em_format_set_session (EMFormat *emf, - CamelSession *session) -{ - g_return_if_fail (CAMEL_IS_SESSION (session)); - g_return_if_fail (emf->priv->session == NULL); - - emf->priv->session = g_object_ref (session); -} - -static void -em_format_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_BASE_URL: - em_format_set_base_url ( - EM_FORMAT (object), - g_value_get_object (value)); - return; - - case PROP_CHARSET: - em_format_set_charset ( - EM_FORMAT (object), - g_value_get_string (value)); - return; - - case PROP_COMPOSER: - em_format_set_composer ( - EM_FORMAT (object), - g_value_get_boolean (value)); - return; - - case PROP_DEFAULT_CHARSET: - em_format_set_default_charset ( - EM_FORMAT (object), - g_value_get_string (value)); - return; - - case PROP_SESSION: - em_format_set_session ( - EM_FORMAT (object), - g_value_get_object (value)); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - -} - -static void -em_format_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_BASE_URL: - g_value_set_object ( - value, em_format_get_base_url ( - EM_FORMAT (object))); - return; - - case PROP_CHARSET: - g_value_set_string ( - value, em_format_get_charset ( - EM_FORMAT (object))); - return; - - case PROP_COMPOSER: - g_value_set_boolean ( - value, em_format_get_composer ( - EM_FORMAT (object))); - return; - - case PROP_DEFAULT_CHARSET: - g_value_set_string ( - value, em_format_get_default_charset ( - EM_FORMAT (object))); - return; - - case PROP_SESSION: - g_value_set_object ( - value, em_format_get_session ( - EM_FORMAT (object))); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -em_format_finalize (GObject *object) -{ - EMFormat *emf = EM_FORMAT (object); - - if (emf->message_uid) { - g_free (emf->message_uid); - emf->message_uid = NULL; - } - - if (emf->uri_base) { - g_free (emf->uri_base); - emf->uri_base = NULL; - } - - if (emf->message) { - g_object_unref (emf->message); - emf->message = NULL; - } - - if (emf->folder) { - g_object_unref (emf->folder); - emf->folder = NULL; - } - - if (emf->mail_part_table) { - /* This will destroy all the EMFormatPURI objects stored - * inside!!!! */ - g_hash_table_destroy (emf->mail_part_table); - emf->mail_part_table = NULL; - } - - if (emf->mail_part_list) { - g_list_free (emf->mail_part_list); - emf->mail_part_list = NULL; - } - - if (emf->priv->base_url) { - camel_url_free (emf->priv->base_url); - emf->priv->base_url = NULL; - } - - if (emf->priv->session) { - g_object_unref (emf->priv->session); - emf->priv->session = NULL; - } - - if (emf->priv->charset) { - g_free (emf->priv->charset); - emf->priv->charset = NULL; - } - - em_format_clear_headers (emf); - - /* Chain up to parent's finalize() method */ - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -em_format_base_init (EMFormatClass *class) -{ - gint i; - - class->type_handlers = g_hash_table_new (g_str_hash, g_str_equal); - - for (i = 0; i < G_N_ELEMENTS (type_handlers); i++) { - g_hash_table_insert (class->type_handlers, - type_handlers[i].mime_type, - &type_handlers[i]); - } -} - -static void -em_format_class_init (EMFormatClass *class) -{ - GObjectClass *object_class; - - parent_class = g_type_class_peek_parent (class); - - g_type_class_add_private (class, sizeof (EMFormatPrivate)); - - class->is_inline = emf_is_inline; - - object_class = G_OBJECT_CLASS (class); - object_class->set_property = em_format_set_property; - object_class->get_property = em_format_get_property; - object_class->finalize = em_format_finalize; - - g_object_class_install_property ( - object_class, - PROP_BASE_URL, - g_param_spec_pointer ( - "base-url", - NULL, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property ( - object_class, - PROP_CHARSET, - g_param_spec_string ( - "charset", - NULL, - NULL, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property ( - object_class, - PROP_COMPOSER, - g_param_spec_boolean ( - "composer", - NULL, - NULL, - FALSE, - G_PARAM_READWRITE)); - - g_object_class_install_property ( - object_class, - PROP_DEFAULT_CHARSET, - g_param_spec_string ( - "default-charset", - NULL, - NULL, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property ( - object_class, - PROP_SESSION, - g_param_spec_object ( - "session", - "Session", - "A CamelSession", - CAMEL_TYPE_SESSION, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY)); - - signals[REDRAW_REQUESTED] = g_signal_new ( - "redraw-requested", - G_TYPE_FROM_CLASS (class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EMFormatClass, redraw_requested), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE,0); -} - -static void -mail_part_table_item_free (gpointer data) -{ - GList *iter = data; - EMFormatPURI *puri = iter->data; - - em_format_puri_free (puri); -} - -static void -em_format_init (EMFormat *emf) -{ - emf->priv = EM_FORMAT_GET_PRIVATE (emf); - - emf->message = NULL; - emf->folder = NULL; - emf->mail_part_list = NULL; - emf->mail_part_table = g_hash_table_new_full (g_str_hash, g_str_equal, - NULL, (GDestroyNotify) mail_part_table_item_free); - /* No need to free the key, because it's owned and free'd by the PURI */ - - emf->priv->last_error = 0; - - em_format_default_headers (emf); -} - -EMFormat * -em_format_new (void) -{ - return g_object_new (EM_TYPE_FORMAT, NULL); -} - -GType -em_format_get_type (void) -{ - static GType type = 0; - - if (G_UNLIKELY (type == 0)) { - static const GTypeInfo type_info = { - sizeof (EMFormatClass), - (GBaseInitFunc) em_format_base_init, - (GBaseFinalizeFunc) NULL, - (GClassInitFunc) em_format_class_init, - (GClassFinalizeFunc) NULL, - NULL, /* class_data */ - sizeof (EMFormat), - 0, /* n_preallocs */ - (GInstanceInitFunc) em_format_init, - NULL /* value_table */ - }; - - type = g_type_register_static ( - G_TYPE_OBJECT, "EMFormat", &type_info, 0); - } - - return type; -} - -void -em_format_set_charset (EMFormat *emf, - const gchar *charset) -{ - g_return_if_fail (EM_IS_FORMAT (emf)); - - if (emf->priv->charset) - g_free (emf->priv->charset); - - emf->priv->charset = g_strdup (charset); - - g_object_notify (G_OBJECT (emf), "charset"); -} - -const gchar * -em_format_get_charset (EMFormat *emf) -{ - g_return_val_if_fail (EM_IS_FORMAT (emf), NULL); - - return emf->priv->charset; -} - -void -em_format_set_default_charset (EMFormat *emf, - const gchar *charset) -{ - g_return_if_fail (EM_IS_FORMAT (emf)); - - if (emf->priv->default_charset) - g_free (emf->priv->default_charset); - - emf->priv->default_charset = g_strdup (charset); - - g_object_notify (G_OBJECT (emf), "default-charset"); -} - -const gchar * -em_format_get_default_charset (EMFormat *emf) -{ - g_return_val_if_fail (EM_IS_FORMAT (emf), NULL); - - return emf->priv->default_charset; -} - -void -em_format_set_composer (EMFormat *emf, - gboolean composer) -{ - g_return_if_fail (EM_IS_FORMAT (emf)); - - if (emf->priv->composer && composer) - return; - - emf->priv->composer = composer; - - g_object_notify (G_OBJECT (emf), "composer"); -} - -gboolean -em_format_get_composer (EMFormat *emf) -{ - g_return_val_if_fail (EM_IS_FORMAT (emf), FALSE); - - return emf->priv->composer; -} - -CamelSession * -em_format_get_session (EMFormat *emf) -{ - g_return_val_if_fail (EM_IS_FORMAT (emf), NULL); - - return emf->priv->session; -} - -void -em_format_set_base_url (EMFormat *emf, - CamelURL *url) -{ - g_return_if_fail (EM_IS_FORMAT (emf)); - g_return_if_fail (url); - - if (emf->priv->base_url) - camel_url_free (emf->priv->base_url); - - emf->priv->base_url = camel_url_copy (url); - - g_object_notify (G_OBJECT (emf), "base-url"); -} - -void -em_format_set_base_url_string (EMFormat *emf, - const gchar *url_string) -{ - g_return_if_fail (EM_IS_FORMAT (emf)); - g_return_if_fail (url_string && *url_string); - - if (emf->priv->base_url) - camel_url_free (emf->priv->base_url); - - emf->priv->base_url = camel_url_new (url_string, NULL); - - g_object_notify (G_OBJECT (emf), "base-url"); -} - -CamelURL * -em_format_get_base_url (EMFormat *emf) -{ - g_return_val_if_fail (EM_IS_FORMAT (emf), NULL); - - return emf->priv->base_url; -} - -/** - * em_format_clear_headers: - * @emf: - * - * Clear the list of headers to be displayed. This will force all headers to - * be shown. - **/ -void -em_format_clear_headers (EMFormat *emf) -{ - EMFormatHeader *eh; - - g_return_if_fail (EM_IS_FORMAT (emf)); - - while ((eh = g_queue_pop_head (&emf->header_list)) != NULL) { - em_format_header_free (eh); - } - -} - -void -em_format_default_headers (EMFormat *emf) -{ - gint ii; - - g_return_if_fail (EM_IS_FORMAT (emf)); - - /* Set the default headers */ - em_format_clear_headers (emf); - for (ii = 0; ii < G_N_ELEMENTS (default_headers); ii++) - em_format_add_header ( - emf, default_headers[ii].name, NULL, - default_headers[ii].flags); -} - -/** - * em_format_add_header: - * @emf: - * @name: The name of the header, as it will appear during output. - * @value: Value of the header. Can be NULL. - * @flags: EM_FORMAT_HEAD_* defines to control display attributes. - * - * Add a specific header to show. If any headers are set, they will - * be displayed in the order set by this function. Certain known - * headers included in this list will be shown using special - * formatting routines. - **/ -void -em_format_add_header (EMFormat *emf, - const gchar *name, - const gchar *value, - guint32 flags) -{ - EMFormatHeader *h; - - g_return_if_fail (EM_IS_FORMAT (emf)); - g_return_if_fail (name && *name); - - h = em_format_header_new (name, value); - h->flags = flags; - g_queue_push_tail (&emf->header_list, h); -} - -void -em_format_add_header_struct (EMFormat *emf, - EMFormatHeader *header) -{ - g_return_if_fail (EM_IS_FORMAT (emf)); - g_return_if_fail (header && header->name); - - em_format_add_header (emf, header->name, header->value, header->flags); -} - -void -em_format_remove_header (EMFormat *emf, - const gchar *name, - const gchar *value) -{ - GList *iter = NULL; - - g_return_if_fail (EM_IS_FORMAT (emf)); - g_return_if_fail (name && *name); - - iter = g_queue_peek_head_link (&emf->header_list); - while (iter) { - EMFormatHeader *header = iter->data; - - if (!header->value || !*header->value) { - GList *next = iter->next; - if (g_strcmp0 (name, header->name) == 0) - g_queue_delete_link (&emf->header_list, iter); - - iter = next; - continue; - } - - if (value && *value) { - if ((g_strcmp0 (name, header->name) == 0) && - (g_strcmp0 (value, header->value) == 0)) - break; - } else { - if (g_strcmp0 (name, header->name) == 0) - break; - } - - iter = iter->next; - } - - if (iter) { - em_format_header_free (iter->data); - g_queue_delete_link (&emf->header_list, iter); - } -} - -void -em_format_remove_header_struct (EMFormat *emf, - const EMFormatHeader *header) -{ - g_return_if_fail (header); - - em_format_remove_header (emf, header->name, header->value); -} - -void -em_format_add_puri (EMFormat *emf, - EMFormatPURI *puri) -{ - GList *item; - - g_return_if_fail (EM_IS_FORMAT (emf)); - g_return_if_fail (puri != NULL); - - emf->mail_part_list = g_list_append (emf->mail_part_list, puri); - item = g_list_last (emf->mail_part_list); - - g_hash_table_insert (emf->mail_part_table, - puri->uri, item); - - d(printf("Added PURI %s\n", puri->uri)); -} - -EMFormatPURI * -em_format_find_puri (EMFormat *emf, - const gchar *id) -{ - GList *list_iter; - - /* First handle CIDs... */ - if (g_str_has_prefix (id, "CID:") || g_str_has_prefix (id, "cid:")) { - GHashTableIter iter; - gpointer key, value; - - g_hash_table_iter_init (&iter, emf->mail_part_table); - while (g_hash_table_iter_next (&iter, &key, &value)) { - EMFormatPURI *puri = ((GList *) value)->data; - if (g_strcmp0 (puri->cid, id) == 0) - return puri; - } - - return NULL; - } - - list_iter = g_hash_table_lookup (emf->mail_part_table, id); - if (list_iter) - return list_iter->data; - - return NULL; -} - -void -em_format_class_add_handler (EMFormatClass *emfc, - EMFormatHandler *handler) -{ - EMFormatHandler *old_handler; - - g_return_if_fail (EM_IS_FORMAT_CLASS (emfc)); - g_return_if_fail (handler); - - old_handler = g_hash_table_lookup ( - emfc->type_handlers, handler->mime_type); - - handler->old = old_handler; - - /* If parse_func or write_func of the new handler is not set, - * use function from the old handler (if it exists). - * This way we can assign a new write_func for to an existing - * parse_func */ - if (old_handler && handler->parse_func == NULL) { - handler->parse_func = old_handler->parse_func; - } - - if (old_handler && handler->write_func == NULL) { - handler->write_func = old_handler->write_func; - } - - g_hash_table_insert (emfc->type_handlers, - handler->mime_type, handler); -} - -void -em_format_class_remove_handler (EMFormatClass *emfc, - EMFormatHandler *handler) -{ - g_return_if_fail (EM_IS_FORMAT_CLASS (emfc)); - g_return_if_fail (handler); - - g_hash_table_remove (emfc->type_handlers, handler->mime_type); -} - -const EMFormatHandler * -em_format_find_handler (EMFormat *emf, - const gchar *mime_type) -{ - EMFormatClass *emfc; - gchar *s; - const EMFormatHandler *handler; - - g_return_val_if_fail (EM_IS_FORMAT (emf), NULL); - g_return_val_if_fail (mime_type && *mime_type, NULL); - - emfc = (EMFormatClass *) G_OBJECT_GET_CLASS (emf); - - s = g_ascii_strdown (mime_type, -1); - - handler = g_hash_table_lookup ( - emfc->type_handlers, s); - - g_free (s); - - return handler; -} - -/** - * em_format_fallback_handler: - * @emf: - * @mime_type: - * - * Try to find a format handler based on the major type of the @mime_type. - * - * The subtype is replaced with "*" and a lookup performed. - * - * Return value: - **/ -const EMFormatHandler * -em_format_fallback_handler (EMFormat *emf, - const gchar *mime_type) -{ - gchar *mime, *s; - - s = strchr (mime_type, '/'); - if (s == NULL) - mime = (gchar *) mime_type; - else { - gsize len = (s - mime_type) + 1; - - mime = g_alloca (len + 2); - strncpy (mime, mime_type, len); - strcpy(mime+len, "*"); - } - - return em_format_find_handler (emf, mime); -} - -void -em_format_parse (EMFormat *emf, - CamelMimeMessage *message, - CamelFolder *folder, - GCancellable *cancellable) -{ - GString *part_id; - EMFormatPURI *puri; - EMFormatParserInfo info = { 0 }; - - g_return_if_fail (EM_IS_FORMAT (emf)); - - if (g_cancellable_is_cancelled (cancellable)) - return; - - if (message) { - g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message)); - - if (emf->message) - g_object_unref (emf->message); - emf->message = g_object_ref (message); - } - - if (folder) { - g_return_if_fail (CAMEL_IS_FOLDER (folder)); - - if (emf->folder) - g_object_unref (emf->folder); - emf->folder = g_object_ref (folder); - } - - /* Before the actual parsing starts, - * let child classes prepare themselves. */ - if (EM_FORMAT_GET_CLASS (emf)->preparse) - EM_FORMAT_GET_CLASS (emf)->preparse (emf); - - part_id = g_string_new (".message"); - - /* Create a special PURI with entire message */ - puri = em_format_puri_new (emf, sizeof (EMFormatPURI), - (CamelMimePart *) emf->message, part_id->str); - puri->mime_type = g_strdup ("text/html"); - em_format_add_puri (emf, puri); - - info.force_handler = TRUE; - em_format_parse_part_as (emf, CAMEL_MIME_PART (emf->message), part_id, &info, - "x-evolution/message", cancellable); - - g_string_free (part_id, TRUE); -} - -void -em_format_write (EMFormat *emf, - CamelStream *stream, - EMFormatWriterInfo *info, - GCancellable *cancellable) -{ - EMFormatClass *emf_class; - - g_return_if_fail (EM_IS_FORMAT (emf)); - g_return_if_fail (CAMEL_IS_STREAM (stream)); - - emf_class = EM_FORMAT_GET_CLASS (emf); - if (emf_class->write) - emf_class->write (emf, stream, info, cancellable); -} - -static void -emf_start_async_parser (GSimpleAsyncResult *result, - GObject *object, - GCancellable *cancellable) -{ - em_format_parse (EM_FORMAT (object), NULL, NULL, cancellable); -} - -void -em_format_parse_async (EMFormat *emf, - CamelMimeMessage *message, - CamelFolder *folder, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *simple; - - g_return_if_fail (EM_IS_FORMAT (emf)); - - if (g_cancellable_is_cancelled (cancellable)) - return; - - if (message) { - g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message)); - - if (emf->message) - g_object_unref (emf->message); - - emf->message = g_object_ref (message); - - } - - if (folder) { - g_return_if_fail (CAMEL_IS_FOLDER (folder)); - - if (emf->folder) - g_object_unref (emf->folder); - - emf->folder = g_object_ref (folder); - - } - - simple = g_simple_async_result_new ( - G_OBJECT (emf), callback, - user_data, em_format_parse_async); - - g_simple_async_result_set_check_cancellable (simple, cancellable); - - g_simple_async_result_run_in_thread ( - simple, emf_start_async_parser, - G_PRIORITY_DEFAULT, cancellable); - - g_object_unref (simple); -} - -void -em_format_parse_part_as (EMFormat *emf, - CamelMimePart *part, - GString *part_id, - EMFormatParserInfo *info, - const gchar *mime_type, - GCancellable *cancellable) -{ - const EMFormatHandler *handler; - const CamelContentDisposition *disposition; - EMFormatParserInfo ninfo = { - .handler = 0, - .validity_type = info ? info->validity_type : 0, - .validity = info ? info->validity : 0, - .force_handler = 0 - }; - - /* Let everything that claims to be an attachment or inlined - * part to be parsed as an attachment. The parser will decide - * how to display it. */ - disposition = camel_mime_part_get_content_disposition (part); - if (!info->force_handler && disposition && - (g_strcmp0 (disposition->disposition, "attachment") == 0)) { - ninfo.is_attachment = TRUE; - handler = em_format_find_handler (emf, "x-evolution/message/attachment"); - ninfo.handler = handler; - - if (handler && handler->parse_func) - handler->parse_func (emf, part, part_id, &ninfo, cancellable); - - return; - } - - handler = em_format_find_handler (emf, mime_type); - if (handler && handler->parse_func) { - ninfo.handler = handler; - handler->parse_func (emf, part, part_id, &ninfo, cancellable); - } else { - handler = em_format_find_handler (emf, "x-evolution/message/attachment"); - ninfo.handler = handler; - - /* When this fails, something is probably very wrong...*/ - if (handler && handler->parse_func) - handler->parse_func (emf, part, part_id, &ninfo, cancellable); - } -} - -void -em_format_parse_part (EMFormat *emf, - CamelMimePart *part, - GString *part_id, - EMFormatParserInfo *info, - GCancellable *cancellable) -{ - CamelContentType *ct; - gchar *mime_type; - - ct = camel_mime_part_get_content_type (part); - if (ct) { - mime_type = camel_content_type_simple (ct); - } else { - mime_type = (gchar *) "text/plain"; - } - - em_format_parse_part_as (emf, part, part_id, info, mime_type, cancellable); - - if (ct) - g_free (mime_type); -} - -gboolean -em_format_is_inline (EMFormat *emf, - const gchar *part_id, - CamelMimePart *part, - const EMFormatHandler *handler) -{ - EMFormatClass *class; - - g_return_val_if_fail (EM_IS_FORMAT (emf), FALSE); - g_return_val_if_fail (part_id && *part_id, FALSE); - g_return_val_if_fail (CAMEL_IS_MIME_PART (part), FALSE); - g_return_val_if_fail (handler, FALSE); - - class = EM_FORMAT_GET_CLASS (emf); - g_return_val_if_fail (class->is_inline != NULL, FALSE); - - return class->is_inline (emf, part_id, part, handler); - -} - -void -em_format_format_error (EMFormat *emf, - const gchar *format, - ...) -{ - EMFormatPURI *puri; - CamelMimePart *part; - const EMFormatHandler *handler; - gchar *errmsg; - gchar *uri; - va_list ap; - - g_return_if_fail (EM_IS_FORMAT (emf)); - g_return_if_fail (format != NULL); - - va_start (ap, format); - errmsg = g_strdup_vprintf (format, ap); - - part = camel_mime_part_new (); - camel_mime_part_set_content (part, errmsg, strlen (errmsg), "text/plain"); - g_free (errmsg); - va_end (ap); - - handler = em_format_find_handler (emf, "x-evolution/error"); - - emf->priv->last_error++; - uri = g_strdup_printf (".error.%d", emf->priv->last_error); - puri = em_format_puri_new (emf, sizeof (EMFormatPURI), part, uri); - puri->mime_type = g_strdup ("text/html"); - if (handler && handler->write_func) - puri->write_func = handler->write_func; - else - puri->write_func = emf_write_error; - - em_format_add_puri (emf, puri); - - g_free (uri); - g_object_unref (part); -} - -/** - * em_format_format_text: - * @emf: - * @stream: Where to write the converted text - * @part: Part whose container is to be formatted - * @cancellable: optional #GCancellable object, or %NULL - * - * Decode/output a part's content to @stream. - **/ -void -em_format_format_text (EMFormat *emf, - CamelStream *stream, - CamelDataWrapper *dw, - GCancellable *cancellable) -{ - CamelStream *filter_stream; - CamelMimeFilter *filter; - const gchar *charset = NULL; - CamelMimeFilterWindows *windows = NULL; - CamelStream *mem_stream = NULL; - - if (g_cancellable_is_cancelled (cancellable)) - return; - - if (emf->priv->charset) { - charset = emf->priv->charset; - } else if (dw->mime_type - && (charset = camel_content_type_param (dw->mime_type, "charset")) - && g_ascii_strncasecmp(charset, "iso-8859-", 9) == 0) { - CamelStream *null; - - /* Since a few Windows mailers like to claim they sent - * out iso-8859-# encoded text when they really sent - * out windows-cp125#, do some simple sanity checking - * before we move on... */ - - null = camel_stream_null_new (); - filter_stream = camel_stream_filter_new (null); - g_object_unref (null); - - windows = (CamelMimeFilterWindows *) camel_mime_filter_windows_new (charset); - camel_stream_filter_add ( - CAMEL_STREAM_FILTER (filter_stream), - CAMEL_MIME_FILTER (windows)); - - camel_data_wrapper_decode_to_stream_sync ( - dw, (CamelStream *) filter_stream, cancellable, NULL); - camel_stream_flush ((CamelStream *) filter_stream, cancellable, NULL); - g_object_unref (filter_stream); - - charset = camel_mime_filter_windows_real_charset (windows); - } else if (charset == NULL) { - charset = emf->priv->default_charset; - } - - mem_stream = (CamelStream *) camel_stream_mem_new (); - filter_stream = camel_stream_filter_new (mem_stream); - - if ((filter = camel_mime_filter_charset_new (charset, "UTF-8"))) { - camel_stream_filter_add ( - CAMEL_STREAM_FILTER (filter_stream), - CAMEL_MIME_FILTER (filter)); - g_object_unref (filter); - } - - camel_data_wrapper_decode_to_stream_sync ( - camel_medium_get_content ((CamelMedium *) dw), - (CamelStream *) filter_stream, cancellable, NULL); - camel_stream_flush ((CamelStream *) filter_stream, cancellable, NULL); - g_object_unref (filter_stream); - - g_seekable_seek (G_SEEKABLE (mem_stream), 0, G_SEEK_SET, NULL, NULL); - - camel_stream_write_to_stream ( - mem_stream, (CamelStream *) stream, cancellable, NULL); - camel_stream_flush ((CamelStream *) mem_stream, cancellable, NULL); - - if (windows) - g_object_unref (windows); - - g_object_unref (mem_stream); -} - -/** - * em_format_describe_part: - * @part: - * @mimetype: - * - * Generate a simple textual description of a part, @mime_type represents - * the content. - * - * Return value: - **/ -gchar * -em_format_describe_part (CamelMimePart *part, - const gchar *mime_type) -{ - GString *stext; - const gchar *filename, *description; - gchar *content_type, *desc; - - stext = g_string_new(""); - content_type = g_content_type_from_mime_type (mime_type); - desc = g_content_type_get_description ( - content_type != NULL ? content_type : mime_type); - g_free (content_type); - g_string_append_printf ( - stext, _("%s attachment"), desc ? desc : mime_type); - g_free (desc); - - filename = camel_mime_part_get_filename (part); - description = camel_mime_part_get_description (part); - - if (!filename || !*filename) { - CamelDataWrapper *content; - - content = camel_medium_get_content (CAMEL_MEDIUM (part)); - - if (CAMEL_IS_MIME_MESSAGE (content)) - filename = camel_mime_message_get_subject ( - CAMEL_MIME_MESSAGE (content)); - } - - if (filename != NULL && *filename != '\0') { - gchar *basename = g_path_get_basename (filename); - g_string_append_printf (stext, " (%s)", basename); - g_free (basename); - } - - if (description != NULL && *description != '\0' && - g_strcmp0 (filename, description) != 0) - g_string_append_printf (stext, ", \"%s\"", description); - - return g_string_free (stext, FALSE); -} - -/** - * em_format_is_attachment: - * @emf: - * @part: Part to check. - * - * Returns true if the part is an attachment. - * - * A part is not considered an attachment if it is a - * multipart, or a text part with no filename. It is used - * to determine if an attachment header should be displayed for - * the part. - * - * Content-Disposition is not checked. - * - * Return value: TRUE/FALSE - **/ -gint -em_format_is_attachment (EMFormat *emf, - CamelMimePart *part) -{ - /*CamelContentType *ct = camel_mime_part_get_content_type(part);*/ - CamelDataWrapper *dw = camel_medium_get_content ((CamelMedium *) part); - - if (!dw) - return 0; - - d(printf("checking is attachment %s/%s\n", dw->mime_type->type, dw->mime_type->subtype)); - return !(camel_content_type_is (dw->mime_type, "multipart", "*") - || camel_content_type_is ( - dw->mime_type, "application", "x-pkcs7-mime") - || camel_content_type_is ( - dw->mime_type, "application", "pkcs7-mime") - || camel_content_type_is ( - dw->mime_type, "application", "x-inlinepgp-signed") - || camel_content_type_is ( - dw->mime_type, "application", "x-inlinepgp-encrypted") - || camel_content_type_is ( - dw->mime_type, "x-evolution", "evolution-rss-feed") - || camel_content_type_is (dw->mime_type, "text", "calendar") - || camel_content_type_is (dw->mime_type, "text", "x-calendar") - || (camel_content_type_is (dw->mime_type, "text", "*") - && camel_mime_part_get_filename (part) == NULL)); -} - -/** - * em_format_snoop_type: - * @part: - * - * Tries to snoop the mime type of a part. - * - * Return value: NULL if unknown (more likely application/octet-stream). - **/ -const gchar * -em_format_snoop_type (CamelMimePart *part) -{ - /* cache is here only to be able still return const gchar * */ - static GHashTable *types_cache = NULL; - - const gchar *filename; - gchar *name_type = NULL, *magic_type = NULL, *res, *tmp; - CamelDataWrapper *dw; - - filename = camel_mime_part_get_filename (part); - if (filename != NULL) - name_type = e_util_guess_mime_type (filename, FALSE); - - dw = camel_medium_get_content ((CamelMedium *) part); - if (!camel_data_wrapper_is_offline (dw)) { - GByteArray *byte_array; - CamelStream *stream; - - byte_array = g_byte_array_new (); - stream = camel_stream_mem_new_with_byte_array (byte_array); - - if (camel_data_wrapper_decode_to_stream_sync (dw, stream, NULL, NULL) > 0) { - gchar *content_type; - - content_type = g_content_type_guess ( - filename, byte_array->data, - byte_array->len, NULL); - - if (content_type != NULL) - magic_type = g_content_type_get_mime_type (content_type); - - g_free (content_type); - } - - g_object_unref (stream); - } - - /* If gvfs doesn't recognize the data by magic, but it - * contains English words, it will call it text/plain. If the - * filename-based check came up with something different, use - * that instead and if it returns "application/octet-stream" - * try to do better with the filename check. - */ - - if (magic_type) { - if (name_type - && (!strcmp(magic_type, "text/plain") - || !strcmp(magic_type, "application/octet-stream"))) - res = name_type; - else - res = magic_type; - } else - res = name_type; - - if (res != name_type) - g_free (name_type); - - if (res != magic_type) - g_free (magic_type); - - if (!types_cache) - types_cache = g_hash_table_new_full ( - g_str_hash, g_str_equal, - (GDestroyNotify) g_free, - (GDestroyNotify) NULL); - - if (res) { - tmp = g_hash_table_lookup (types_cache, res); - if (tmp) { - g_free (res); - res = tmp; - } else { - g_hash_table_insert (types_cache, res, res); - } - } - - return res; - - /* We used to load parts to check their type, we don't anymore, - * see bug #211778 for some discussion */ -} - -/** - * Construct a URI for message. - * - * The URI can contain multiple query parameters. The list of parameters must be - * NULL-terminated. Each query must contain name, GType of value and value. - * - * @param folder Folder wit the message - * @param message_uid ID of message within the \p folder - * @param first_param_name Name of first query parameter followed by GType of it's value and value. - */ -gchar * -em_format_build_mail_uri (CamelFolder *folder, - const gchar *message_uid, - const gchar *first_param_name, - ...) -{ - CamelStore *store; - gchar *uri, *tmp; - va_list ap; - const gchar *name; - const gchar *service_uid, *folder_name; - gchar separator; - - g_return_val_if_fail (message_uid && *message_uid, NULL); - - if (!folder) { - folder_name = "generic"; - service_uid = "generic"; - } else { - tmp = (gchar *) camel_folder_get_full_name (folder); - folder_name = (const gchar *) soup_uri_encode (tmp, NULL); - store = camel_folder_get_parent_store (folder); - if (store) - service_uid = camel_service_get_uid (CAMEL_SERVICE (store)); - else - service_uid = "generic"; - } - - tmp = g_strdup_printf ("mail://%s/%s/%s", - service_uid, - folder_name, - message_uid); - - if (folder) { - g_free ((gchar *) folder_name); - } - - va_start (ap, first_param_name); - name = first_param_name; - separator = '?'; - while (name) { - gchar *tmp2; - gint type = va_arg (ap, gint); - switch (type) { - case G_TYPE_INT: - case G_TYPE_BOOLEAN: { - gint val = va_arg (ap, gint); - tmp2 = g_strdup_printf ("%s%c%s=%d", tmp, - separator, name, val); - break; - } - case G_TYPE_FLOAT: - case G_TYPE_DOUBLE: { - gdouble val = va_arg (ap, double); - tmp2 = g_strdup_printf ("%s%c%s=%f", tmp, - separator, name, val); - break; - } - case G_TYPE_STRING: { - gchar *val = va_arg (ap, gchar *); - gchar *escaped = soup_uri_encode (val, NULL); - tmp2 = g_strdup_printf ("%s%c%s=%s", tmp, - separator, name, escaped); - g_free (escaped); - break; - } - default: - g_warning ("Invalid param type %s", g_type_name (type)); - return NULL; - } - - g_free (tmp); - tmp = tmp2; - - if (separator == '?') - separator = '&'; - - name = va_arg (ap, gchar *); - } - va_end (ap); - - uri = tmp; - if (uri == NULL) - return NULL; - - /* For some reason, webkit won't accept URL with username, but - * without password (mail://store@host/folder/mail), so we - * will replace the '@' symbol by '/' to get URL like - * mail://store/host/folder/mail which is OK - */ - while ((tmp = strchr (uri, '@')) != NULL) { - tmp[0] = '/'; - } - - return uri; -} - -void -em_format_redraw (EMFormat *emf) -{ - g_return_if_fail (EM_IS_FORMAT (emf)); - - g_signal_emit (emf, signals[REDRAW_REQUESTED], 0); -} - -/**************************************************************************/ -EMFormatPURI * -em_format_puri_new (EMFormat *emf, - gsize puri_size, - CamelMimePart *part, - const gchar *uri) -{ - EMFormatPURI *puri; - - g_return_val_if_fail (EM_IS_FORMAT (emf), NULL); - g_return_val_if_fail (puri_size >= sizeof (EMFormatPURI), NULL); - - puri = (EMFormatPURI *) g_malloc0 (puri_size); - puri->emf = emf; - - if (part) - puri->part = g_object_ref (part); - - if (uri) - puri->uri = g_strdup (uri); - - return puri; -} - -void -em_format_puri_free (EMFormatPURI *puri) -{ - g_return_if_fail (puri); - - if (puri->part) - g_object_unref (puri->part); - - if (puri->uri) - g_free (puri->uri); - - if (puri->cid) - g_free (puri->cid); - - if (puri->mime_type) - g_free (puri->mime_type); - - if (puri->validity) - camel_cipher_validity_free (puri->validity); - - if (puri->validity_parent) - camel_cipher_validity_free (puri->validity_parent); - - if (puri->free) - puri->free (puri); - - g_free (puri); -} - -void -em_format_puri_write (EMFormatPURI *puri, - CamelStream *stream, - EMFormatWriterInfo *info, - GCancellable *cancellable) -{ - g_return_if_fail (puri); - g_return_if_fail (CAMEL_IS_STREAM (stream)); - - if (info->mode == EM_FORMAT_WRITE_MODE_SOURCE) { - const EMFormatHandler *handler; - handler = em_format_find_handler (puri->emf, "x-evolution/message/source"); - handler->write_func (puri->emf, puri, stream, info, cancellable); - return; - } - - if (puri->write_func) { - puri->write_func (puri->emf, puri, stream, info, cancellable); - } else { - const EMFormatHandler *handler; - const gchar *mime_type; - - if (puri->mime_type) { - mime_type = puri->mime_type; - } else { - mime_type = (gchar *) "plain/text"; - } - - handler = em_format_find_handler (puri->emf, mime_type); - if (handler && handler->write_func) { - handler->write_func (puri->emf, - puri, stream, info, cancellable); - } - } -} - -EMFormatHeader * -em_format_header_new (const gchar *name, - const gchar *value) -{ - EMFormatHeader *header; - - g_return_val_if_fail (name && *name, NULL); - - header = g_new0 (EMFormatHeader, 1); - header->name = g_strdup (name); - if (value && *value) - header->value = g_strdup (value); - - return header; -} - -void -em_format_header_free (EMFormatHeader *header) -{ - g_return_if_fail (header != NULL); - - if (header->name) { - g_free (header->name); - header->name = NULL; - } - - if (header->value) { - g_free (header->value); - header->value = NULL; - } - - g_free (header); -} |