diff options
Diffstat (limited to 'mail/em-utils.c')
-rw-r--r-- | mail/em-utils.c | 2324 |
1 files changed, 0 insertions, 2324 deletions
diff --git a/mail/em-utils.c b/mail/em-utils.c deleted file mode 100644 index e2da2fa6d3..0000000000 --- a/mail/em-utils.c +++ /dev/null @@ -1,2324 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Authors: Jeffrey Stedfast <fejj@ximian.com> - * - * Copyright 2003 Ximian, Inc. (www.ximian.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <errno.h> -#include <time.h> - -#include <camel/camel-stream-fs.h> -#include <camel/camel-url-scanner.h> - -#include <filter/filter-editor.h> - -#include "mail-component.h" -#include "mail-mt.h" -#include "mail-ops.h" -#include "mail-tools.h" -#include "mail-config.h" -#include "mail-config-druid.h" -#include "message-tag-followup.h" - -#include <e-util/e-mktemp.h> -#include <e-util/e-dialog-utils.h> - -#include "em-utils.h" -#include "em-composer-utils.h" -#include "em-format-quote.h" - -static EAccount *guess_account (CamelMimeMessage *message); - -/** - * em_utils_prompt_user: - * @parent: parent window - * @def: default response - * @promptkey: gconf key to check if we should prompt the user or not. - * @fmt: prompt format - * @Varargs: varargs - * - * Convenience function to query the user with a Yes/No dialog and a - * "Don't show this dialog again" checkbox. If the user checks that - * checkbox, then @promptkey is set to %FALSE, otherwise it is set to - * %TRUE. - * - * Returns %TRUE if the user clicks Yes or %FALSE otherwise. - **/ -gboolean -em_utils_prompt_user(GtkWindow *parent, int def, const char *promptkey, const char *fmt, ...) -{ - GtkWidget *mbox, *check = NULL; - va_list ap; - int button; - char *str; - GConfClient *gconf = mail_config_get_gconf_client(); - - if (promptkey - && !gconf_client_get_bool(gconf, promptkey, NULL)) - return TRUE; - - va_start (ap, fmt); - str = g_strdup_vprintf (fmt, ap); - va_end (ap); - mbox = gtk_message_dialog_new (parent, GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, - "%s", str); - g_free (str); - gtk_dialog_set_default_response ((GtkDialog *) mbox, def); - if (promptkey) { - check = gtk_check_button_new_with_label (_("Don't show this message again.")); - gtk_box_pack_start ((GtkBox *)((GtkDialog *) mbox)->vbox, check, TRUE, TRUE, 10); - gtk_widget_show (check); - } - - button = gtk_dialog_run ((GtkDialog *) mbox); - if (promptkey) - gconf_client_set_bool(gconf, promptkey, !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check)), NULL); - - gtk_widget_destroy(mbox); - - return button == GTK_RESPONSE_YES; -} - -/** - * em_utils_uids_copy: - * @uids: array of uids - * - * Duplicates the array of uids held by @uids into a new - * GPtrArray. Use em_utils_uids_free() to free the resultant uid - * array. - * - * Returns a duplicate copy of @uids. - **/ -GPtrArray * -em_utils_uids_copy (GPtrArray *uids) -{ - GPtrArray *copy; - int i; - - copy = g_ptr_array_new (); - g_ptr_array_set_size (copy, uids->len); - - for (i = 0; i < uids->len; i++) - copy->pdata[i] = g_strdup (uids->pdata[i]); - - return copy; -} - -/** - * em_utils_uids_free: - * @uids: array of uids - * - * Frees the array of uids pointed to by @uids back to the system. - **/ -void -em_utils_uids_free (GPtrArray *uids) -{ - int i; - - for (i = 0; i < uids->len; i++) - g_free (uids->pdata[i]); - - g_ptr_array_free (uids, TRUE); -} - -static void -druid_destroy_cb (gpointer user_data, GObject *deadbeef) -{ - gtk_main_quit (); -} - -/** - * em_utils_configure_account: - * @parent: parent window for the druid to be a child of. - * - * Displays a druid allowing the user to configure an account. If - * @parent is non-NULL, then the druid will be created as a child - * window of @parent's toplevel window. - * - * Returns %TRUE if an account has been configured or %FALSE - * otherwise. - **/ -gboolean -em_utils_configure_account (GtkWidget *parent) -{ - MailConfigDruid *druid; - - druid = mail_config_druid_new (); - - if (parent != NULL) - e_dialog_set_transient_for ((GtkWindow *) druid, parent); - - g_object_weak_ref ((GObject *) druid, (GWeakNotify) druid_destroy_cb, NULL); - gtk_widget_show ((GtkWidget *) druid); - gtk_grab_add ((GtkWidget *) druid); - gtk_main (); - - return mail_config_is_configured (); -} - -/** - * em_utils_check_user_can_send_mail: - * @parent: parent window for the druid to be a child of. - * - * If no accounts have been configured, the user will be given a - * chance to configure an account. In the case that no accounts are - * configured, a druid will be created. If @parent is non-NULL, then - * the druid will be created as a child window of @parent's toplevel - * window. - * - * Returns %TRUE if the user has an account configured (to send mail) - * or %FALSE otherwise. - **/ -gboolean -em_utils_check_user_can_send_mail (GtkWidget *parent) -{ - EAccount *account; - - if (!mail_config_is_configured ()) { - if (!em_utils_configure_account (parent)) - return FALSE; - } - - if (!(account = mail_config_get_default_account ())) - return FALSE; - - /* Check for a transport */ - if (!account->transport->url) - return FALSE; - - return TRUE; -} - -/* Editing Filters/vFolders... */ - -static GtkWidget *filter_editor = NULL; - -static void -filter_editor_response (GtkWidget *dialog, int button, gpointer user_data) -{ - FilterContext *fc; - - if (button == GTK_RESPONSE_ACCEPT) { - char *user; - - fc = g_object_get_data ((GObject *) dialog, "context"); - user = g_strdup_printf ("%s/mail/filters.xml", - mail_component_peek_base_directory (mail_component_peek ())); - rule_context_save ((RuleContext *) fc, user); - g_free (user); - } - - gtk_widget_destroy (dialog); - - filter_editor = NULL; -} - -static const char *filter_source_names[] = { - "incoming", - "outgoing", - NULL, -}; - -/** - * em_utils_edit_filters: - * @parent: parent window - * - * Opens or raises the filters editor dialog so that the user may edit - * his/her filters. If @parent is non-NULL, then the dialog will be - * created as a child window of @parent's toplevel window. - **/ -void -em_utils_edit_filters (GtkWidget *parent) -{ - const char *base_directory = mail_component_peek_base_directory (mail_component_peek ()); - char *user, *system; - FilterContext *fc; - - if (filter_editor) { - gdk_window_raise (GTK_WIDGET (filter_editor)->window); - return; - } - - fc = filter_context_new (); - user = g_strdup_printf ("%s/mail/filters.xml", base_directory); - system = EVOLUTION_PRIVDATADIR "/filtertypes.xml"; - rule_context_load ((RuleContext *) fc, system, user); - g_free (user); - - if (((RuleContext *) fc)->error) { - e_notice (parent, GTK_MESSAGE_ERROR, - _("Error loading filter information:\n%s"), - ((RuleContext *) fc)->error); - return; - } - - filter_editor = (GtkWidget *) filter_editor_new (fc, filter_source_names); - if (parent != NULL) - e_dialog_set_transient_for ((GtkWindow *) filter_editor, parent); - - gtk_window_set_title (GTK_WINDOW (filter_editor), _("Filters")); - g_object_set_data_full ((GObject *) filter_editor, "context", fc, (GtkDestroyNotify) g_object_unref); - g_signal_connect (filter_editor, "response", G_CALLBACK (filter_editor_response), NULL); - gtk_widget_show (GTK_WIDGET (filter_editor)); -} - -/* Composing messages... */ - -static EMsgComposer * -create_new_composer (void) -{ - EMsgComposer *composer; - - composer = e_msg_composer_new (); - - em_composer_utils_setup_default_callbacks (composer); - - return composer; -} - -/** - * em_utils_compose_new_message: - * - * Opens a new composer window as a child window of @parent's toplevel - * window. - **/ -void -em_utils_compose_new_message (void) -{ - GtkWidget *composer; - - composer = (GtkWidget *) create_new_composer (); - - gtk_widget_show (composer); -} - -/** - * em_utils_compose_new_message_with_mailto: - * @url: mailto url - * - * Opens a new composer window as a child window of @parent's toplevel - * window. If @url is non-NULL, the composer fields will be filled in - * according to the values in the mailto url. - **/ -void -em_utils_compose_new_message_with_mailto (const char *url) -{ - EMsgComposer *composer; - - if (url != NULL) - composer = e_msg_composer_new_from_url (url); - else - composer = e_msg_composer_new (); - - em_composer_utils_setup_default_callbacks (composer); - - gtk_widget_show ((GtkWidget *) composer); -} - -/** - * em_utils_post_to_url: - * @url: mailto url - * - * Opens a new composer window as a child window of @parent's toplevel - * window. If @url is non-NULL, the composer will default to posting - * mail to the folder specified by @url. - **/ -void -em_utils_post_to_url (const char *url) -{ - EMsgComposer *composer; - - composer = e_msg_composer_new_post (); - - if (url != NULL) - e_msg_composer_hdrs_set_post_to ((EMsgComposerHdrs *) ((EMsgComposer *) composer)->hdrs, url); - - em_composer_utils_setup_default_callbacks (composer); - - e_msg_composer_unset_changed (composer); - e_msg_composer_drop_editor_undo (composer); - - gtk_widget_show ((GtkWidget *) composer); -} - -/* Editing messages... */ - -static void -edit_message (CamelMimeMessage *message, CamelFolder *drafts, const char *uid) -{ - EMsgComposer *composer; - - composer = e_msg_composer_new_with_message (message); - em_composer_utils_setup_callbacks (composer, NULL, NULL, 0, 0, drafts, uid); - e_msg_composer_unset_changed (composer); - e_msg_composer_drop_editor_undo (composer); - - gtk_widget_show (GTK_WIDGET (composer)); -} - -/** - * em_utils_edit_message: - * @message: message to edit - * - * Opens a composer filled in with the headers/mime-parts/etc of - * @message. - **/ -void -em_utils_edit_message (CamelMimeMessage *message) -{ - g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message)); - - edit_message (message, NULL, NULL); -} - -static void -edit_messages (CamelFolder *folder, GPtrArray *uids, GPtrArray *msgs, void *user_data) -{ - int i; - - if (msgs == NULL) - return; - - for (i = 0; i < msgs->len; i++) { - camel_medium_remove_header (CAMEL_MEDIUM (msgs->pdata[i]), "X-Mailer"); - - edit_message (msgs->pdata[i], folder, uids->pdata[i]); - } -} - -/** - * em_utils_edit_messages: - * @folder: folder containing messages to edit - * @uids: uids of messages to edit - * - * Opens a composer for each message to be edited. - **/ -void -em_utils_edit_messages (CamelFolder *folder, GPtrArray *uids) -{ - g_return_if_fail (CAMEL_IS_FOLDER (folder)); - g_return_if_fail (uids != NULL); - - mail_get_messages (folder, uids, edit_messages, NULL); -} - -/* Forwarding messages... */ - -static void -forward_attached (CamelFolder *folder, GPtrArray *messages, CamelMimePart *part, char *subject, void *user_data) -{ - EMsgComposer *composer; - - if (part == NULL) - return; - - composer = create_new_composer (); - e_msg_composer_set_headers (composer, NULL, NULL, NULL, NULL, subject); - e_msg_composer_attach (composer, part); - - e_msg_composer_unset_changed (composer); - e_msg_composer_drop_editor_undo (composer); - - gtk_widget_show (GTK_WIDGET (composer)); -} - -/** - * em_utils_forward_attached: - * @folder: folder containing messages to forward - * @uids: uids of messages to forward - * - * If there is more than a single message in @uids, a multipart/digest - * will be constructed and attached to a new composer window preset - * with the appropriate header defaults for forwarding the first - * message in the list. If only one message is to be forwarded, it is - * forwarded as a simple message/rfc822 attachment. - **/ -void -em_utils_forward_attached (CamelFolder *folder, GPtrArray *uids) -{ - g_return_if_fail (CAMEL_IS_FOLDER (folder)); - g_return_if_fail (uids != NULL); - - mail_build_attachment (folder, uids, forward_attached, NULL); -} - -static void -forward_non_attached (GPtrArray *messages, int style) -{ - CamelMimeMessage *message; - CamelDataWrapper *wrapper; - EMsgComposer *composer; - char *subject, *text; - int i; - guint32 flags; - - if (messages->len == 0) - return; - - flags = EM_FORMAT_QUOTE_HEADERS; - if (style == MAIL_CONFIG_FORWARD_QUOTED) - flags |= EM_FORMAT_QUOTE_CITE; - - for (i = 0; i < messages->len; i++) { - message = messages->pdata[i]; - subject = mail_tool_generate_forward_subject (message); - - text = em_utils_message_to_html (message, _("-------- Forwarded Message --------"), flags); - - if (text) { - composer = create_new_composer (); - e_msg_composer_set_headers (composer, NULL, NULL, NULL, NULL, subject); - e_msg_composer_set_body_text (composer, text); - - wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (message)); - if (CAMEL_IS_MULTIPART (wrapper)) - e_msg_composer_add_message_attachments (composer, message, FALSE); - - e_msg_composer_unset_changed (composer); - e_msg_composer_drop_editor_undo (composer); - - gtk_widget_show (GTK_WIDGET (composer)); - - g_free (text); - } - - g_free (subject); - } -} - -static void -forward_inline (CamelFolder *folder, GPtrArray *uids, GPtrArray *messages, void *user_data) -{ - forward_non_attached (messages, MAIL_CONFIG_FORWARD_INLINE); -} - -/** - * em_utils_forward_inline: - * @folder: folder containing messages to forward - * @uids: uids of messages to forward - * - * Forwards each message in the 'inline' form, each in its own composer window. - **/ -void -em_utils_forward_inline (CamelFolder *folder, GPtrArray *uids) -{ - g_return_if_fail (CAMEL_IS_FOLDER (folder)); - g_return_if_fail (uids != NULL); - - mail_get_messages (folder, uids, forward_inline, NULL); -} - -static void -forward_quoted (CamelFolder *folder, GPtrArray *uids, GPtrArray *messages, void *user_data) -{ - forward_non_attached (messages, MAIL_CONFIG_FORWARD_QUOTED); -} - -/** - * em_utils_forward_quoted: - * @folder: folder containing messages to forward - * @uids: uids of messages to forward - * - * Forwards each message in the 'quoted' form (each line starting with - * a "> "), each in its own composer window. - **/ -void -em_utils_forward_quoted (CamelFolder *folder, GPtrArray *uids) -{ - g_return_if_fail (CAMEL_IS_FOLDER (folder)); - g_return_if_fail (uids != NULL); - - mail_get_messages (folder, uids, forward_quoted, NULL); -} - -/** - * em_utils_forward_message: - * @parent: parent window - * @message: message to be forwarded - * - * Forwards a message in the user's configured default style. - **/ -void -em_utils_forward_message (CamelMimeMessage *message) -{ - GPtrArray *messages; - CamelMimePart *part; - GConfClient *gconf; - char *subject; - int mode; - - messages = g_ptr_array_new (); - g_ptr_array_add (messages, message); - - gconf = mail_config_get_gconf_client (); - mode = gconf_client_get_int (gconf, "/apps/evolution/mail/format/forward_style", NULL); - - switch (mode) { - case MAIL_CONFIG_FORWARD_ATTACHED: - default: - part = mail_tool_make_message_attachment (message); - - subject = mail_tool_generate_forward_subject (message); - - forward_attached (NULL, messages, part, subject, NULL); - camel_object_unref (part); - g_free (subject); - break; - case MAIL_CONFIG_FORWARD_INLINE: - forward_non_attached (messages, MAIL_CONFIG_FORWARD_INLINE); - break; - case MAIL_CONFIG_FORWARD_QUOTED: - forward_non_attached (messages, MAIL_CONFIG_FORWARD_QUOTED); - break; - } - - g_ptr_array_free (messages, TRUE); -} - -/** - * em_utils_forward_messages: - * @folder: folder containing messages to forward - * @uids: uids of messages to forward - * - * Forwards a group of messages in the user's configured default - * style. - **/ -void -em_utils_forward_messages (CamelFolder *folder, GPtrArray *uids) -{ - GConfClient *gconf; - int mode; - - gconf = mail_config_get_gconf_client (); - mode = gconf_client_get_int (gconf, "/apps/evolution/mail/format/forward_style", NULL); - - switch (mode) { - case MAIL_CONFIG_FORWARD_ATTACHED: - default: - em_utils_forward_attached (folder, uids); - break; - case MAIL_CONFIG_FORWARD_INLINE: - em_utils_forward_inline (folder, uids); - break; - case MAIL_CONFIG_FORWARD_QUOTED: - em_utils_forward_quoted (folder, uids); - break; - } -} - -/* Redirecting messages... */ - -static EMsgComposer * -redirect_get_composer (CamelMimeMessage *message) -{ - EMsgComposer *composer; - EAccount *account; - - /* QMail will refuse to send a message if it finds one of - it's Delivered-To headers in the message, so remove all - Delivered-To headers. Fixes bug #23635. */ - while (camel_medium_get_header (CAMEL_MEDIUM (message), "Delivered-To")) - camel_medium_remove_header (CAMEL_MEDIUM (message), "Delivered-To"); - - account = guess_account (message); - - composer = e_msg_composer_new_redirect (message, account ? account->name : NULL); - - em_composer_utils_setup_default_callbacks (composer); - - return composer; -} - -/** - * em_utils_redirect_message: - * @message: message to redirect - * - * Opens a composer to redirect @message (Note: only headers will be - * editable). Adds Resent-From/Resent-To/etc headers. - **/ -void -em_utils_redirect_message (CamelMimeMessage *message) -{ - EMsgComposer *composer; - CamelDataWrapper *wrapper; - - g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message)); - - composer = redirect_get_composer (message); - - wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (message)); - if (CAMEL_IS_MULTIPART (wrapper)) - e_msg_composer_add_message_attachments (composer, message, FALSE); - - gtk_widget_show (GTK_WIDGET (composer)); - e_msg_composer_unset_changed (composer); - e_msg_composer_drop_editor_undo (composer); -} - -static void -redirect_msg (CamelFolder *folder, const char *uid, CamelMimeMessage *message, void *user_data) -{ - if (message == NULL) - return; - - em_utils_redirect_message (message); -} - -/** - * em_utils_redirect_message_by_uid: - * @folder: folder containing message to be redirected - * @uid: uid of message to be redirected - * - * Opens a composer to redirect the message (Note: only headers will - * be editable). Adds Resent-From/Resent-To/etc headers. - **/ -void -em_utils_redirect_message_by_uid (CamelFolder *folder, const char *uid) -{ - g_return_if_fail (CAMEL_IS_FOLDER (folder)); - g_return_if_fail (uid != NULL); - - mail_get_message (folder, uid, redirect_msg, NULL, mail_thread_new); -} - -/* Replying to messages... */ - -static GHashTable * -generate_account_hash (void) -{ - GHashTable *account_hash; - EAccount *account, *def; - EAccountList *accounts; - EIterator *iter; - - accounts = mail_config_get_accounts (); - account_hash = g_hash_table_new (camel_strcase_hash, camel_strcase_equal); - - /* add the default account to the hash first */ - if ((def = mail_config_get_default_account ())) { - if (def->id->address) - g_hash_table_insert (account_hash, (char *) def->id->address, (void *) def); - } - - iter = e_list_get_iterator ((EList *) accounts); - while (e_iterator_is_valid (iter)) { - account = (EAccount *) e_iterator_get (iter); - - if (account->id->address) { - EAccount *acnt; - - /* Accounts with identical email addresses that are enabled - * take precedence over the accounts that aren't. If all - * accounts with matching email addresses are disabled, then - * the first one in the list takes precedence. The default - * account always takes precedence no matter what. - */ - acnt = g_hash_table_lookup (account_hash, account->id->address); - if (acnt && acnt != def && !acnt->enabled && account->enabled) { - g_hash_table_remove (account_hash, acnt->id->address); - acnt = NULL; - } - - if (!acnt) - g_hash_table_insert (account_hash, (char *) account->id->address, (void *) account); - } - - e_iterator_next (iter); - } - - g_object_unref (iter); - - return account_hash; -} - -static EABDestination ** -em_utils_camel_address_to_destination (CamelInternetAddress *iaddr) -{ - EABDestination *dest, **destv; - int n, i, j; - - if (iaddr == NULL) - return NULL; - - if ((n = camel_address_length ((CamelAddress *) iaddr)) == 0) - return NULL; - - destv = g_malloc (sizeof (EABDestination *) * (n + 1)); - for (i = 0, j = 0; i < n; i++) { - const char *name, *addr; - - if (camel_internet_address_get (iaddr, i, &name, &addr)) { - dest = eab_destination_new (); - eab_destination_set_name (dest, name); - eab_destination_set_email (dest, addr); - - destv[j++] = dest; - } - } - - if (j == 0) { - g_free (destv); - return NULL; - } - - destv[j] = NULL; - - return destv; -} - -static EMsgComposer * -reply_get_composer (CamelMimeMessage *message, EAccount *account, - CamelInternetAddress *to, CamelInternetAddress *cc) -{ - const char *message_id, *references; - EABDestination **tov, **ccv; - EMsgComposer *composer; - char *subject; - - g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL); - g_return_val_if_fail (to == NULL || CAMEL_IS_INTERNET_ADDRESS (to), NULL); - g_return_val_if_fail (cc == NULL || CAMEL_IS_INTERNET_ADDRESS (cc), NULL); - - composer = e_msg_composer_new (); - - /* construct the tov/ccv */ - tov = em_utils_camel_address_to_destination (to); - ccv = em_utils_camel_address_to_destination (cc); - - /* Set the subject of the new message. */ - if ((subject = (char *) camel_mime_message_get_subject (message))) { - if (strncasecmp (subject, "Re: ", 4) != 0) - subject = g_strdup_printf ("Re: %s", subject); - else - subject = g_strdup (subject); - } else { - subject = g_strdup (""); - } - - e_msg_composer_set_headers (composer, account ? account->name : NULL, tov, ccv, NULL, subject); - - g_free (subject); - - /* Add In-Reply-To and References. */ - message_id = camel_medium_get_header (CAMEL_MEDIUM (message), "Message-Id"); - references = camel_medium_get_header (CAMEL_MEDIUM (message), "References"); - if (message_id) { - char *reply_refs; - - e_msg_composer_add_header (composer, "In-Reply-To", message_id); - - if (references) - reply_refs = g_strdup_printf ("%s %s", references, message_id); - else - reply_refs = g_strdup (message_id); - - e_msg_composer_add_header (composer, "References", reply_refs); - g_free (reply_refs); - } else if (references) { - e_msg_composer_add_header (composer, "References", references); - } - - e_msg_composer_drop_editor_undo (composer); - - return composer; -} - -static EAccount * -guess_account (CamelMimeMessage *message) -{ - const CamelInternetAddress *to, *cc; - GHashTable *account_hash; - EAccount *account = NULL; - const char *addr; - int i; - - to = camel_mime_message_get_recipients (message, CAMEL_RECIPIENT_TYPE_TO); - cc = camel_mime_message_get_recipients (message, CAMEL_RECIPIENT_TYPE_CC); - - if (to == NULL && cc == NULL) - return NULL; - - account_hash = generate_account_hash (); - - if (to) { - for (i = 0; camel_internet_address_get (to, i, NULL, &addr); i++) { - account = g_hash_table_lookup (account_hash, addr); - if (account) - goto found; - } - } - - if (cc) { - for (i = 0; camel_internet_address_get (cc, i, NULL, &addr); i++) { - account = g_hash_table_lookup (account_hash, addr); - if (account) - goto found; - } - } - - found: - - g_hash_table_destroy (account_hash); - - return account; -} - -static void -get_reply_sender (CamelMimeMessage *message, CamelInternetAddress **to) -{ - const CamelInternetAddress *reply_to; - const char *name, *addr; - int i; - - reply_to = camel_mime_message_get_reply_to (message); - if (!reply_to) - reply_to = camel_mime_message_get_from (message); - - if (reply_to) { - *to = camel_internet_address_new (); - - for (i = 0; camel_internet_address_get (reply_to, i, &name, &addr); i++) - camel_internet_address_add (*to, name, addr); - } -} - -static gboolean -get_reply_list (CamelMimeMessage *message, CamelInternetAddress **to) -{ - const char *header, *p; - char *addr; - - /* Examples: - * - * List-Post: <mailto:list@host.com> - * List-Post: <mailto:moderator@host.com?subject=list%20posting> - * List-Post: NO (posting not allowed on this list) - */ - if (!(header = camel_medium_get_header ((CamelMedium *) message, "List-Post"))) - return FALSE; - - while (*header == ' ' || *header == '\t') - header++; - - /* check for NO */ - if (!strncasecmp (header, "NO", 2)) - return FALSE; - - /* Search for the first mailto angle-bracket enclosed URL. - * (See rfc2369, Section 2, paragraph 3 for details) */ - if (!(header = camel_strstrcase (header, "<mailto:"))) - return FALSE; - - header += 8; - - p = header; - while (*p && !strchr ("?>", *p)) - p++; - - addr = g_strndup (header, p - header); - - *to = camel_internet_address_new (); - camel_internet_address_add (*to, NULL, addr); - - g_free (addr); - - return TRUE; -} - -static void -concat_unique_addrs (CamelInternetAddress *dest, const CamelInternetAddress *src, GHashTable *rcpt_hash) -{ - const char *name, *addr; - int i; - - for (i = 0; camel_internet_address_get (src, i, &name, &addr); i++) { - if (!g_hash_table_lookup (rcpt_hash, addr)) { - camel_internet_address_add (dest, name, addr); - g_hash_table_insert (rcpt_hash, (char *) addr, GINT_TO_POINTER (1)); - } - } -} - -static void -get_reply_all (CamelMimeMessage *message, CamelInternetAddress **to, CamelInternetAddress **cc) -{ - const CamelInternetAddress *reply_to, *to_addrs, *cc_addrs; - const char *name, *addr; - GHashTable *rcpt_hash; - int i; - - rcpt_hash = generate_account_hash (); - - reply_to = camel_mime_message_get_reply_to (message); - if (!reply_to) - reply_to = camel_mime_message_get_from (message); - - to_addrs = camel_mime_message_get_recipients (message, CAMEL_RECIPIENT_TYPE_TO); - cc_addrs = camel_mime_message_get_recipients (message, CAMEL_RECIPIENT_TYPE_CC); - - *to = camel_internet_address_new (); - *cc = camel_internet_address_new (); - - if (reply_to) { - for (i = 0; camel_internet_address_get (reply_to, i, &name, &addr); i++) { - /* ignore references to the Reply-To address in the To and Cc lists */ - if (addr && !g_hash_table_lookup (rcpt_hash, addr)) { - /* In the case that we are doing a Reply-To-All, we do not want - to include the user's email address because replying to oneself - is kinda silly. */ - - camel_internet_address_add (*to, name, addr); - g_hash_table_insert (rcpt_hash, (char *) addr, GINT_TO_POINTER (1)); - } - } - } - - concat_unique_addrs (*cc, to_addrs, rcpt_hash); - concat_unique_addrs (*cc, cc_addrs, rcpt_hash); - - /* promote the first Cc: address to To: if To: is empty */ - if (camel_address_length ((CamelAddress *) *to) == 0 && camel_address_length ((CamelAddress *) *cc) > 0) { - camel_internet_address_get (*cc, 0, &name, &addr); - camel_internet_address_add (*to, name, addr); - camel_address_remove ((CamelAddress *) *cc, 0); - } - - g_hash_table_destroy (rcpt_hash); -} - -static void -composer_set_body (EMsgComposer *composer, CamelMimeMessage *message) -{ - const CamelInternetAddress *sender; - char *text, *credits, format[256]; - const char *name, *addr; - CamelMimePart *part; - GConfClient *gconf; - time_t date; - int date_offset; - - gconf = mail_config_get_gconf_client (); - - switch (gconf_client_get_int (gconf, "/apps/evolution/mail/format/reply_style", NULL)) { - case MAIL_CONFIG_REPLY_DO_NOT_QUOTE: - /* do nothing */ - break; - case MAIL_CONFIG_REPLY_ATTACH: - /* attach the original message as an attachment */ - part = mail_tool_make_message_attachment (message); - e_msg_composer_attach (composer, part); - camel_object_unref (part); - break; - case MAIL_CONFIG_REPLY_QUOTED: - default: - /* do what any sane user would want when replying... */ - sender = camel_mime_message_get_from (message); - if (sender != NULL && camel_address_length (CAMEL_ADDRESS (sender)) > 0) { - camel_internet_address_get (sender, 0, &name, &addr); - } else { - name = _("an unknown sender"); - } - - date = camel_mime_message_get_date(message, &date_offset); - /* Convert to UTC */ - date += (date_offset / 100) * 60 * 60; - date += (date_offset % 100) * 60; - - /* translators: attribution string used when quoting messages, - it must contain a single single %%+05d followed by a single '%%s' */ - e_utf8_strftime(format, sizeof(format), _("On %a, %Y-%m-%d at %H:%M %%+05d, %%s wrote:"), gmtime(&date)); - credits = g_strdup_printf(format, date_offset, name && *name ? name : addr); - text = em_utils_message_to_html(message, credits, EM_FORMAT_QUOTE_CITE); - g_free (credits); - e_msg_composer_set_body_text(composer, text); - g_free (text); - break; - } - - e_msg_composer_drop_editor_undo (composer); -} - -/** - * em_utils_reply_to_message: - * @message: message to reply to - * @mode: reply mode - * - * Creates a new composer ready to reply to @message. - **/ -void -em_utils_reply_to_message (CamelMimeMessage *message, int mode) -{ - CamelInternetAddress *to = NULL, *cc = NULL; - EMsgComposer *composer; - EAccount *account; - - account = guess_account (message); - - switch (mode) { - case REPLY_MODE_SENDER: - get_reply_sender (message, &to); - break; - case REPLY_MODE_LIST: - if (get_reply_list (message, &to)) - break; - case REPLY_MODE_ALL: - get_reply_all (message, &to, &cc); - break; - } - - composer = reply_get_composer (message, account, to, cc); - e_msg_composer_add_message_attachments (composer, message, TRUE); - - if (to != NULL) - camel_object_unref (to); - - if (cc != NULL) - camel_object_unref (cc); - - composer_set_body (composer, message); - - em_composer_utils_setup_default_callbacks (composer); - - gtk_widget_show (GTK_WIDGET (composer)); - e_msg_composer_unset_changed (composer); -} - -static void -reply_to_message (CamelFolder *folder, const char *uid, CamelMimeMessage *message, void *user_data) -{ - CamelInternetAddress *to = NULL, *cc = NULL; - EMsgComposer *composer; - EAccount *account; - guint32 flags; - int mode; - - mode = GPOINTER_TO_INT (user_data); - - account = guess_account (message); - flags = CAMEL_MESSAGE_ANSWERED | CAMEL_MESSAGE_SEEN; - - switch (mode) { - case REPLY_MODE_SENDER: - get_reply_sender (message, &to); - break; - case REPLY_MODE_LIST: - flags |= CAMEL_MESSAGE_ANSWERED_ALL; - if (get_reply_list (message, &to)) - break; - case REPLY_MODE_ALL: - flags |= CAMEL_MESSAGE_ANSWERED_ALL; - get_reply_all (message, &to, &cc); - break; - } - - composer = reply_get_composer (message, account, to, cc); - e_msg_composer_add_message_attachments (composer, message, TRUE); - - if (to != NULL) - camel_object_unref (to); - - if (cc != NULL) - camel_object_unref (cc); - - composer_set_body (composer, message); - - em_composer_utils_setup_callbacks (composer, folder, uid, flags, flags, NULL, NULL); - - gtk_widget_show (GTK_WIDGET (composer)); - e_msg_composer_unset_changed (composer); -} - -/** - * em_utils_reply_to_message_by_uid: - * @folder: folder containing message to reply to - * @uid: message uid - * @mode: reply mode - * - * Creates a new composer ready to reply to the message referenced by - * @folder and @uid. - **/ -void -em_utils_reply_to_message_by_uid (CamelFolder *folder, const char *uid, int mode) -{ - g_return_if_fail (CAMEL_IS_FOLDER (folder)); - g_return_if_fail (uid != NULL); - - mail_get_message (folder, uid, reply_to_message, GINT_TO_POINTER (mode), mail_thread_new); -} - -/* Posting replies... */ - -static void -post_reply_to_message (CamelFolder *folder, const char *uid, CamelMimeMessage *message, void *user_data) -{ - /* FIXME: would be nice if this shared more code with reply_get_composer() */ - const char *message_id, *references; - CamelInternetAddress *to = NULL; - EABDestination **tov = NULL; - EMsgComposer *composer; - char *subject, *url; - EAccount *account; - guint32 flags; - - account = guess_account (message); - flags = CAMEL_MESSAGE_ANSWERED | CAMEL_MESSAGE_SEEN; - - get_reply_sender (message, &to); - - composer = e_msg_composer_new_post (); - - /* construct the tov/ccv */ - tov = em_utils_camel_address_to_destination (to); - - /* Set the subject of the new message. */ - if ((subject = (char *) camel_mime_message_get_subject (message))) { - if (strncasecmp (subject, "Re: ", 4) != 0) - subject = g_strdup_printf ("Re: %s", subject); - else - subject = g_strdup (subject); - } else { - subject = g_strdup (""); - } - - e_msg_composer_set_headers (composer, account ? account->name : NULL, tov, NULL, NULL, subject); - - g_free (subject); - - url = mail_tools_folder_to_url (folder); - e_msg_composer_hdrs_set_post_to ((EMsgComposerHdrs *) composer->hdrs, url); - g_free (url); - - /* Add In-Reply-To and References. */ - message_id = camel_medium_get_header (CAMEL_MEDIUM (message), "Message-Id"); - references = camel_medium_get_header (CAMEL_MEDIUM (message), "References"); - if (message_id) { - char *reply_refs; - - e_msg_composer_add_header (composer, "In-Reply-To", message_id); - - if (references) - reply_refs = g_strdup_printf ("%s %s", references, message_id); - else - reply_refs = g_strdup (message_id); - - e_msg_composer_add_header (composer, "References", reply_refs); - g_free (reply_refs); - } else if (references) { - e_msg_composer_add_header (composer, "References", references); - } - - e_msg_composer_drop_editor_undo (composer); - - e_msg_composer_add_message_attachments (composer, message, TRUE); - - if (to != NULL) - camel_object_unref (to); - - composer_set_body (composer, message); - - em_composer_utils_setup_callbacks (composer, folder, uid, flags, flags, NULL, NULL); - - gtk_widget_show (GTK_WIDGET (composer)); - e_msg_composer_unset_changed (composer); -} - -/** - * em_utils_post_reply_to_message_by_uid: - * @folder: folder containing message to reply to - * @uid: message uid - * @mode: reply mode - * - * Creates a new composer (post mode) ready to reply to the message - * referenced by @folder and @uid. - **/ -void -em_utils_post_reply_to_message_by_uid (CamelFolder *folder, const char *uid) -{ - g_return_if_fail (CAMEL_IS_FOLDER (folder)); - g_return_if_fail (uid != NULL); - - mail_get_message (folder, uid, post_reply_to_message, NULL, mail_thread_new); -} - -/* Saving messages... */ - -static GtkFileSelection * -emu_get_save_filesel (GtkWidget *parent, const char *title, const char *name) -{ - GtkFileSelection *filesel; - char *gdir, *mname = NULL, *filename; - const char *realname, *dir; - GConfClient *gconf; - - filesel = (GtkFileSelection *)gtk_file_selection_new(title); - if (parent) - e_dialog_set_transient_for((GtkWindow *)filesel, parent); - - gconf = gconf_client_get_default(); - dir = gdir = gconf_client_get_string(gconf, "/apps/evolution/mail/save_dir", NULL); - g_object_unref(gconf); - if (dir == NULL) - dir = g_get_home_dir(); - - if (name && name[0]) { - realname = mname = g_strdup(name); - e_filename_make_safe(mname); - } else { - realname = "/"; - } - - filename = g_build_filename(dir, realname, NULL); - gtk_file_selection_set_filename(filesel, filename); - g_free(filename); - g_free(mname); - g_free (gdir); - - return filesel; -} - -static void -emu_update_save_path(const char *filename) -{ - char *dir = g_path_get_dirname(filename); - GConfClient *gconf = gconf_client_get_default(); - - gconf_client_set_string(gconf, "/apps/evolution/mail/save_dir", dir, NULL); - g_object_unref(gconf); - g_free(dir); -} - -static gboolean -emu_can_save(GtkWindow *parent, const char *path) -{ - struct stat st; - - if (path[0] == 0) - return FALSE; - - /* make sure we can actually save to it... */ - if (stat (path, &st) != -1 && !S_ISREG (st.st_mode)) - return FALSE; - - if (access (path, F_OK) == 0) { - if (access (path, W_OK) != 0) { - e_notice (parent, GTK_MESSAGE_ERROR, - _("Cannot save to `%s'\n %s"), path, g_strerror (errno)); - return FALSE; - } - - return em_utils_prompt_user (parent, GTK_RESPONSE_NO, NULL, - _("`%s' already exists.\nOverwrite it?"), path); - } - - return TRUE; -} - -static void -emu_save_part_response(GtkFileSelection *filesel, int response, CamelMimePart *part) -{ - if (response == GTK_RESPONSE_OK) { - const char *path = gtk_file_selection_get_filename(filesel); - - if (!emu_can_save((GtkWindow *)filesel, path)) - return; - - emu_update_save_path(path); - /* FIXME: popup error if it fails? */ - mail_save_part(part, path, NULL, NULL); - } - - gtk_widget_destroy((GtkWidget *)filesel); - camel_object_unref(part); -} - -/** - * em_utils_save_part: - * @parent: parent window - * @prompt: prompt string - * @part: part to save - * - * Saves a mime part to disk (prompting the user for filename). - **/ -void -em_utils_save_part(GtkWidget *parent, const char *prompt, CamelMimePart *part) -{ - const char *name; - GtkFileSelection *filesel; - - name = camel_mime_part_get_filename(part); - if (name == NULL) { - if (CAMEL_IS_MIME_MESSAGE(part)) { - name = camel_mime_message_get_subject((CamelMimeMessage *)part); - if (name == NULL) - name = _("message"); - } else { - name = _("attachment"); - } - } - - filesel = emu_get_save_filesel(parent, prompt, name); - camel_object_ref(part); - g_signal_connect(filesel, "response", G_CALLBACK(emu_save_part_response), part); - gtk_widget_show((GtkWidget *)filesel); -} - - -struct _save_messages_data { - CamelFolder *folder; - GPtrArray *uids; -}; - -static void -emu_save_messages_response(GtkFileSelection *filesel, int response, struct _save_messages_data *data) -{ - if (response == GTK_RESPONSE_OK) { - const char *path = gtk_file_selection_get_filename(filesel); - - if (!emu_can_save((GtkWindow *)filesel, path)) - return; - - emu_update_save_path(path); - mail_save_messages(data->folder, data->uids, path, NULL, NULL); - data->uids = NULL; - } - - camel_object_unref(data->folder); - if (data->uids) - em_utils_uids_free(data->uids); - g_free(data); - gtk_widget_destroy((GtkWidget *)filesel); -} - -/** - * em_utils_save_messages: - * @parent: parent window - * @folder: folder containing messages to save - * @uids: uids of messages to save - * - * Saves a group of messages to disk in mbox format (prompting the - * user for filename). - **/ -void -em_utils_save_messages (GtkWidget *parent, CamelFolder *folder, GPtrArray *uids) -{ - struct _save_messages_data *data; - GtkFileSelection *filesel; - - g_return_if_fail (CAMEL_IS_FOLDER (folder)); - g_return_if_fail (uids != NULL); - - filesel = emu_get_save_filesel(parent, _("Save Message..."), NULL); - camel_object_ref(folder); - - data = g_malloc(sizeof(struct _save_messages_data)); - data->folder = folder; - data->uids = uids; - - g_signal_connect(filesel, "response", G_CALLBACK(emu_save_messages_response), data); - gtk_widget_show((GtkWidget *)filesel); -} - -/* ********************************************************************** */ - -static void -emu_add_address_cb(BonoboListener *listener, const char *name, const CORBA_any *any, CORBA_Environment *ev, void *data) -{ - char *type = bonobo_event_subtype(name); - - if (!strcmp(type, "Destroy")) - gtk_widget_destroy((GtkWidget *)data); - - g_free(type); -} - -/** - * em_utils_add_address: - * @parent: - * @email: - * - * Add address @email to the addressbook. - **/ -void em_utils_add_address(struct _GtkWidget *parent, const char *email) -{ - GtkWidget *win; - GtkWidget *control; - /*GtkWidget *socket;*/ - - win = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_title((GtkWindow *)win, _("Add address")); - - control = bonobo_widget_new_control("OAFIID:GNOME_Evolution_Addressbook_AddressPopup:" BASE_VERSION, CORBA_OBJECT_NIL); - bonobo_widget_set_property((BonoboWidget *)control, "email", TC_CORBA_string, email, NULL); - - bonobo_event_source_client_add_listener(bonobo_widget_get_objref((BonoboWidget *)control), emu_add_address_cb, NULL, NULL, win); - - /*socket = find_socket (GTK_CONTAINER (control)); - g_object_weak_ref ((GObject *) socket, (GWeakNotify) gtk_widget_destroy, win);*/ - - gtk_container_add((GtkContainer *)win, control); - gtk_widget_show_all(win); -} - -/* ********************************************************************** */ -/* Flag-for-Followup... */ - -/* tag-editor callback data */ -struct ted_t { - MessageTagEditor *editor; - CamelFolder *folder; - GPtrArray *uids; -}; - -static void -ted_free (struct ted_t *ted) -{ - camel_object_unref (ted->folder); - em_utils_uids_free (ted->uids); - g_free (ted); -} - -static void -tag_editor_response (GtkWidget *dialog, int button, struct ted_t *ted) -{ - CamelFolder *folder; - CamelTag *tags, *t; - GPtrArray *uids; - int i; - - if (button == GTK_RESPONSE_OK && (tags = message_tag_editor_get_tag_list (ted->editor))) { - folder = ted->folder; - uids = ted->uids; - - camel_folder_freeze (folder); - for (i = 0; i < uids->len; i++) { - for (t = tags; t; t = t->next) - camel_folder_set_message_user_tag (folder, uids->pdata[i], t->name, t->value); - } - - camel_folder_thaw (folder); - camel_tag_list_free (&tags); - } - - gtk_widget_destroy (dialog); -} - -/** - * em_utils_flag_for_followup: - * @parent: parent window - * @folder: folder containing messages to flag - * @uids: uids of messages to flag - * - * Open the Flag-for-Followup editor for the messages specified by - * @folder and @uids. - **/ -void -em_utils_flag_for_followup (GtkWidget *parent, CamelFolder *folder, GPtrArray *uids) -{ - GtkWidget *editor; - struct ted_t *ted; - int i; - - g_return_if_fail (CAMEL_IS_FOLDER (folder)); - g_return_if_fail (uids != NULL); - - editor = (GtkWidget *) message_tag_followup_new (); - - if (parent != NULL) - e_dialog_set_transient_for ((GtkWindow *) editor, parent); - - camel_object_ref (folder); - - ted = g_new (struct ted_t, 1); - ted->editor = MESSAGE_TAG_EDITOR (editor); - ted->folder = folder; - ted->uids = uids; - - for (i = 0; i < uids->len; i++) { - CamelMessageInfo *info; - - info = camel_folder_get_message_info (folder, uids->pdata[i]); - message_tag_followup_append_message (MESSAGE_TAG_FOLLOWUP (editor), - camel_message_info_from (info), - camel_message_info_subject (info)); - } - - /* special-case... */ - if (uids->len == 1) { - CamelMessageInfo *info; - - info = camel_folder_get_message_info (folder, uids->pdata[0]); - if (info) { - if (info->user_tags) - message_tag_editor_set_tag_list (MESSAGE_TAG_EDITOR (editor), info->user_tags); - camel_folder_free_message_info (folder, info); - } - } - - g_signal_connect (editor, "response", G_CALLBACK (tag_editor_response), ted); - g_object_weak_ref ((GObject *) editor, (GWeakNotify) ted_free, ted); - - gtk_widget_show (editor); -} - -/** - * em_utils_flag_for_followup_clear: - * @parent: parent window - * @folder: folder containing messages to unflag - * @uids: uids of messages to unflag - * - * Clears the Flag-for-Followup flag on the messages referenced by - * @folder and @uids. - **/ -void -em_utils_flag_for_followup_clear (GtkWidget *parent, CamelFolder *folder, GPtrArray *uids) -{ - int i; - - g_return_if_fail (CAMEL_IS_FOLDER (folder)); - g_return_if_fail (uids != NULL); - - camel_folder_freeze (folder); - for (i = 0; i < uids->len; i++) { - camel_folder_set_message_user_tag (folder, uids->pdata[i], "follow-up", ""); - camel_folder_set_message_user_tag (folder, uids->pdata[i], "due-by", ""); - camel_folder_set_message_user_tag (folder, uids->pdata[i], "completed-on", ""); - } - camel_folder_thaw (folder); - - em_utils_uids_free (uids); -} - -/** - * em_utils_flag_for_followup_completed: - * @parent: parent window - * @folder: folder containing messages to 'complete' - * @uids: uids of messages to 'complete' - * - * Sets the completed state (and date/time) for each message - * referenced by @folder and @uids that is marked for - * Flag-for-Followup. - **/ -void -em_utils_flag_for_followup_completed (GtkWidget *parent, CamelFolder *folder, GPtrArray *uids) -{ - char *now; - int i; - - g_return_if_fail (CAMEL_IS_FOLDER (folder)); - g_return_if_fail (uids != NULL); - - now = camel_header_format_date (time (NULL), 0); - - camel_folder_freeze (folder); - for (i = 0; i < uids->len; i++) { - const char *tag; - - tag = camel_folder_get_message_user_tag (folder, uids->pdata[i], "follow-up"); - if (tag == NULL || *tag == '\0') - continue; - - camel_folder_set_message_user_tag (folder, uids->pdata[i], "completed-on", now); - } - camel_folder_thaw (folder); - - g_free (now); - - em_utils_uids_free (uids); -} - -#include "camel/camel-stream-mem.h" -#include "camel/camel-stream-filter.h" -#include "camel/camel-mime-filter-from.h" - -/* This kind of sucks, because for various reasons most callers need to run synchronously - in the gui thread, however this could take a long, blocking time, to run */ -static int -em_utils_write_messages_to_stream(CamelFolder *folder, GPtrArray *uids, CamelStream *stream) -{ - CamelStreamFilter *filtered_stream; - CamelMimeFilterFrom *from_filter; - int i, res = 0; - - from_filter = camel_mime_filter_from_new(); - filtered_stream = camel_stream_filter_new_with_stream(stream); - camel_stream_filter_add(filtered_stream, (CamelMimeFilter *)from_filter); - camel_object_unref(from_filter); - - for (i=0; i<uids->len; i++) { - CamelMimeMessage *message; - char *from; - - message = camel_folder_get_message(folder, uids->pdata[i], NULL); - if (message == NULL) { - res = -1; - break; - } - - /* we need to flush after each stream write since we are writing to the same stream */ - from = camel_mime_message_build_mbox_from(message); - - if (camel_stream_write_string(stream, from) == -1 - || camel_stream_flush(stream) == -1 - || camel_data_wrapper_write_to_stream((CamelDataWrapper *)message, (CamelStream *)filtered_stream) == -1 - || camel_stream_flush((CamelStream *)filtered_stream) == -1) - res = -1; - - g_free(from); - camel_object_unref(message); - - if (res == -1) - break; - } - - camel_object_unref(filtered_stream); - - return res; -} - -/* This kind of sucks, because for various reasons most callers need to run synchronously - in the gui thread, however this could take a long, blocking time, to run */ -static int -em_utils_read_messages_from_stream(CamelFolder *folder, CamelStream *stream) -{ - CamelException *ex = camel_exception_new(); - CamelMimeParser *mp = camel_mime_parser_new(); - int res = -1; - - camel_mime_parser_scan_from(mp, TRUE); - camel_mime_parser_init_with_stream(mp, stream); - camel_object_unref(stream); - - while (camel_mime_parser_step(mp, 0, 0) == CAMEL_MIME_PARSER_STATE_FROM) { - CamelMimeMessage *msg; - - /* NB: de-from filter, once written */ - msg = camel_mime_message_new(); - if (camel_mime_part_construct_from_parser((CamelMimePart *)msg, mp) == -1) { - camel_object_unref(msg); - break; - } - - camel_folder_append_message(folder, msg, NULL, NULL, ex); - camel_object_unref(msg); - - if (camel_exception_is_set (ex)) - break; - - camel_mime_parser_step(mp, 0, 0); - } - - camel_object_unref(mp); - if (!camel_exception_is_set(ex)) - res = 0; - camel_exception_free(ex); - - return res; -} - -/** - * em_utils_selection_set_mailbox: - * @data: selection data - * @folder: folder containign messages to copy into the selection - * @uids: uids of the messages to copy into the selection - * - * Creates a mailbox-format selection. - * Warning: Could be BIG! - * Warning: This could block the ui for an extended period. - **/ -void -em_utils_selection_set_mailbox(GtkSelectionData *data, CamelFolder *folder, GPtrArray *uids) -{ - CamelStream *stream; - - stream = camel_stream_mem_new(); - if (em_utils_write_messages_to_stream(folder, uids, stream) == 0) - gtk_selection_data_set(data, data->target, 8, - ((CamelStreamMem *)stream)->buffer->data, - ((CamelStreamMem *)stream)->buffer->len); - - camel_object_unref(stream); -} - -/** - * em_utils_selection_get_mailbox: - * @data: selection data - * @folder: - * - * Receive a mailbox selection/dnd - * Warning: Could be BIG! - * Warning: This could block the ui for an extended period. - * FIXME: Exceptions? - **/ -void -em_utils_selection_get_mailbox(GtkSelectionData *data, CamelFolder *folder) -{ - CamelStream *stream; - - if (data->data == NULL || data->length == -1) - return; - - /* TODO: a stream mem with read-only access to existing data? */ - /* NB: Although copying would let us run this async ... which it should */ - stream = camel_stream_mem_new_with_buffer(data->data, data->length); - em_utils_read_messages_from_stream(folder, stream); - camel_object_unref(stream); -} - -/** - * em_utils_selection_set_uidlist: - * @data: selection data - * @uri: - * @uids: - * - * Sets a "x-uid-list" format selection data. - * - * FIXME: be nice if this could take a folder argument rather than uri - **/ -void -em_utils_selection_set_uidlist(GtkSelectionData *data, const char *uri, GPtrArray *uids) -{ - GByteArray *array = g_byte_array_new(); - int i; - - /* format: "uri\0uid1\0uid2\0uid3\0...\0uidn\0" */ - - g_byte_array_append(array, uri, strlen(uri)+1); - - for (i=0; i<uids->len; i++) - g_byte_array_append(array, uids->pdata[i], strlen(uids->pdata[i])+1); - - gtk_selection_data_set(data, data->target, 8, array->data, array->len); - g_byte_array_free(array, TRUE); -} - -/** - * em_utils_selection_get_uidlist: - * @data: selection data - * @urip: Pointer to uri string, to be free'd by caller - * @uidsp: Pointer to an array of uid's. - * - * Convert an x-uid-list type to a uri and a uid list. - * - * Return value: The number of uid's found. If 0, then @urip and - * @uidsp will be empty. - **/ -int -em_utils_selection_get_uidlist(GtkSelectionData *data, char **urip, GPtrArray **uidsp) -{ - /* format: "uri\0uid1\0uid2\0uid3\0...\0uidn" */ - char *inptr, *inend; - GPtrArray *uids; - int res; - - *urip = NULL; - *uidsp = NULL; - - if (data == NULL || data->data == NULL || data->length == -1) - return 0; - - uids = g_ptr_array_new(); - - inptr = data->data; - inend = data->data + data->length; - while (inptr < inend) { - char *start = inptr; - - while (inptr < inend && *inptr) - inptr++; - - if (start > (char *)data->data) - g_ptr_array_add(uids, g_strndup(start, inptr-start)); - - inptr++; - } - - if (uids->len == 0) { - g_ptr_array_free(uids, TRUE); - res = 0; - } else { - *urip = g_strdup(data->data); - *uidsp = uids; - res = uids->len; - } - - return res; -} - -/** - * em_utils_selection_set_urilist: - * @data: - * @folder: - * @uids: - * - * Set the selection data @data to a uri which points to a file, which is - * a berkely mailbox format mailbox. The file is automatically cleaned - * up when the application quits. - **/ -void -em_utils_selection_set_urilist(GtkSelectionData *data, CamelFolder *folder, GPtrArray *uids) -{ - const char *tmpdir; - CamelStream *fstream; - char *uri, *p; - int fd; - - tmpdir = e_mkdtemp("drag-n-drop-XXXXXX"); - if (tmpdir == NULL) - return; - - /* FIXME: this used to save a single message with the subject - as the filename but it was unsafe, and makes this messier, - the pain */ - - p = uri = g_alloca (strlen (tmpdir) + 16); - p += sprintf (uri, "file:///%s/mbox", tmpdir); - - fd = open(uri + 7, O_WRONLY | O_CREAT | O_EXCL, 0666); - if (fd == -1) - return; - - fstream = camel_stream_fs_new_with_fd(fd); - if (fstream) { - /* terminate with \r\n to be compliant with the spec */ - strcpy (p, "\r\n"); - - if (em_utils_write_messages_to_stream(folder, uids, fstream) == 0) - gtk_selection_data_set(data, data->target, 8, uri, strlen(uri)); - - camel_object_unref(fstream); - } -} - -static void -emu_save_part_done(CamelMimePart *part, char *name, int done, void *data) -{ - ((int *)data)[0] = done; -} - -/** - * em_utils_temp_save_part: - * @parent: - * @part: - * - * Save a part's content to a temporary file, and return the - * filename. - * - * Return value: NULL if anything failed. - **/ -char * -em_utils_temp_save_part(GtkWidget *parent, CamelMimePart *part) -{ - const char *tmpdir, *filename; - char *path, *mfilename = NULL; - int done; - - tmpdir = e_mkdtemp("evolution-tmp-XXXXXX"); - if (tmpdir == NULL) { - e_notice(parent, GTK_MESSAGE_ERROR, - _("Could not create temporary directory: %s"), - g_strerror (errno)); - - return NULL; - } - - filename = camel_mime_part_get_filename (part); - if (filename == NULL) { - /* This is the default filename used for temporary file creation */ - filename = _("Unknown"); - } else { - mfilename = g_strdup(filename); - e_filename_make_safe(mfilename); - filename = mfilename; - } - - path = g_build_filename(tmpdir, filename, NULL); - g_free(mfilename); - - /* FIXME: This doesn't handle default charsets */ - mail_msg_wait(mail_save_part(part, path, emu_save_part_done, &done)); - - if (!done) { - /* mail_save_part should popup an error box automagically */ - g_free(path); - path = NULL; - } - - return path; -} - -extern CamelFolder *drafts_folder, *sent_folder, *outbox_folder; - -/** - * em_utils_folder_is_drafts: - * @folder: folder - * @uri: uri for this folder, if known - * - * Decides if @folder is a Drafts folder. - * - * Returns %TRUE if this is a Drafts folder or %FALSE otherwise. - **/ -gboolean -em_utils_folder_is_drafts(CamelFolder *folder, const char *uri) -{ - EAccountList *accounts; - EAccount *account; - EIterator *iter; - int is = FALSE; - - if (folder == drafts_folder) - return TRUE; - - if (uri == NULL) - return FALSE; - - accounts = mail_config_get_accounts(); - iter = e_list_get_iterator((EList *)accounts); - while (e_iterator_is_valid(iter)) { - account = (EAccount *)e_iterator_get(iter); - if (account->drafts_folder_uri && - camel_store_uri_cmp(folder->parent_store, account->drafts_folder_uri, uri)) { - is = TRUE; - break; - } - - e_iterator_next(iter); - } - - g_object_unref(iter); - - return is; -} - -/** - * em_utils_folder_is_sent: - * @folder: folder - * @uri: uri for this folder, if known - * - * Decides if @folder is a Sent folder - * - * Returns %TRUE if this is a Sent folder or %FALSE otherwise. - **/ -gboolean -em_utils_folder_is_sent(CamelFolder *folder, const char *uri) -{ - EAccountList *accounts; - EAccount *account; - EIterator *iter; - int is = FALSE; - - if (folder == sent_folder) - return TRUE; - - if (uri == NULL) - return FALSE; - - accounts = mail_config_get_accounts(); - iter = e_list_get_iterator((EList *)accounts); - while (e_iterator_is_valid(iter)) { - account = (EAccount *)e_iterator_get(iter); - if (account->sent_folder_uri && - camel_store_uri_cmp(folder->parent_store, account->sent_folder_uri, uri)) { - is = TRUE; - break; - } - - e_iterator_next(iter); - } - - g_object_unref(iter); - - return is; -} - -/** - * em_utils_folder_is_outbox: - * @folder: folder - * @uri: uri for this folder, if known - * - * Decides if @folder is an Outbox folder - * - * Returns %TRUE if this is an Outbox folder or %FALSE otherwise. - **/ -gboolean -em_utils_folder_is_outbox(CamelFolder *folder, const char *uri) -{ - /* <Highlander>There can be only one.</Highlander> */ - return folder == outbox_folder; -} - -/** - * em_utils_adjustment_page: - * @adj: - * @down: - * - * Move an adjustment up/down forward/back one page. - **/ -void -em_utils_adjustment_page(GtkAdjustment *adj, gboolean down) -{ - float page_size = adj->page_size - adj->step_increment; - - if (down) { - if (adj->value < adj->upper - adj->page_size - page_size) - adj->value += page_size; - else if (adj->upper >= adj->page_size) - adj->value = adj->upper - adj->page_size; - else - adj->value = adj->lower; - } else { - if (adj->value > adj->lower + page_size) - adj->value -= page_size; - else - adj->value = adj->lower; - } - - gtk_adjustment_value_changed(adj); -} - -/* ********************************************************************** */ -static char *emu_proxy_uri; - -static void -emu_set_proxy(GConfClient *client) -{ - char *server; - int port; - - if (!gconf_client_get_bool(client, "/system/http_proxy/use_http_proxy", NULL)) { - g_free(emu_proxy_uri); - emu_proxy_uri = NULL; - - return; - } - - /* TODO: Should lock ... */ - - server = gconf_client_get_string(client, "/system/http_proxy/host", NULL); - port = gconf_client_get_int(client, "/system/http_proxy/port", NULL); - - if (server && server[0]) { - g_free(emu_proxy_uri); - - if (gconf_client_get_bool(client, "/system/http_proxy/use_authentication", NULL)) { - char *user = gconf_client_get_string(client, "/system/http_proxy/authentication_user", NULL); - char *pass = gconf_client_get_string(client, "/system/http_proxy/authentication_password", NULL); - - emu_proxy_uri = g_strdup_printf("http://%s:%s@%s:%d", user, pass, server, port); - g_free(user); - g_free(pass); - } else { - emu_proxy_uri = g_strdup_printf("http://%s:%d", server, port); - } - } - - g_free(server); -} - -static void -emu_proxy_changed(GConfClient *client, guint32 cnxn_id, GConfEntry *entry, gpointer user_data) -{ - emu_set_proxy(client); -} - -/** - * em_utils_get_proxy_uri: - * - * Get the system proxy uri. - * - * Return value: Must be freed when finished with. - **/ -char * -em_utils_get_proxy_uri(void) -{ - static int init; - - if (!init) { - GConfClient *client = gconf_client_get_default(); - - gconf_client_add_dir(client, "/system/http_proxy", GCONF_CLIENT_PRELOAD_ONELEVEL, NULL); - gconf_client_notify_add(client, "/system/http_proxy", emu_proxy_changed, NULL, NULL, NULL); - emu_set_proxy(client); - g_object_unref(client); - init = TRUE; - } - - return g_strdup(emu_proxy_uri); -} - -/** - * em_utils_part_to_html: - * @part: - * - * Converts a mime part's contents into html text. If @credits is given, - * then it will be used as an attribution string, and the - * content will be cited. Otherwise no citation or attribution - * will be performed. - * - * Return Value: The part in displayable html format. - **/ -char * -em_utils_part_to_html(CamelMimePart *part) -{ - EMFormatQuote *emfq; - CamelStreamMem *mem; - GByteArray *buf; - char *text; - - buf = g_byte_array_new (); - mem = (CamelStreamMem *) camel_stream_mem_new (); - camel_stream_mem_set_byte_array (mem, buf); - - emfq = em_format_quote_new(NULL, (CamelStream *)mem, 0); - em_format_part((EMFormat *) emfq, (CamelStream *) mem, part); - g_object_unref (emfq); - - camel_stream_write ((CamelStream *) mem, "", 1); - camel_object_unref (mem); - - text = buf->data; - g_byte_array_free (buf, FALSE); - - return text; -} - -/** - * em_utils_message_to_html: - * @message: - * @credits: - * @flags: EMFormatQuote flags - * - * Convert a message to html, quoting if the @credits attribution - * string is given. - * - * Return value: The html version. - **/ -char * -em_utils_message_to_html(CamelMimeMessage *message, const char *credits, guint32 flags) -{ - EMFormatQuote *emfq; - CamelStreamMem *mem; - GByteArray *buf; - char *text; - - buf = g_byte_array_new (); - mem = (CamelStreamMem *) camel_stream_mem_new (); - camel_stream_mem_set_byte_array (mem, buf); - - emfq = em_format_quote_new(credits, (CamelStream *)mem, flags); - em_format_format((EMFormat *)emfq, (CamelMedium *)message); - g_object_unref (emfq); - - camel_stream_write ((CamelStream *) mem, "", 1); - camel_object_unref (mem); - - text = buf->data; - g_byte_array_free (buf, FALSE); - - return text; -} - -/* ********************************************************************** */ - -/** - * em_utils_expunge_folder: - * @parent: parent window - * @folder: folder to expunge - * - * Expunges @folder. - **/ -void -em_utils_expunge_folder (GtkWidget *parent, CamelFolder *folder) -{ - char *name; - - camel_object_get(folder, NULL, CAMEL_OBJECT_DESCRIPTION, &name, 0); - - if (!em_utils_prompt_user(parent, GTK_RESPONSE_NO, "/apps/evolution/mail/prompts/expunge", - _("This operation will permanently remove all deleted messages " - "in the folder `%s'. If you continue, you " - "will not be able to recover these messages.\n" - "\nReally erase these messages?"), name)) - return; - - mail_expunge_folder(folder, NULL, NULL); -} - -/** - * em_utils_empty_trash: - * @parent: parent window - * - * Empties all Trash folders. - **/ -void -em_utils_empty_trash (GtkWidget *parent) -{ - extern CamelSession *session; - CamelProvider *provider; - EAccountList *accounts; - EAccount *account; - EIterator *iter; - CamelException ex; - - if (!em_utils_prompt_user(parent, GTK_RESPONSE_NO, "/apps/evolution/mail/prompts/empty_trash", - _("This operation will permanently remove all deleted messages " - "in all folders. If you continue, you will not be able to " - "recover these messages.\n" - "\nReally erase these messages?"))) - return; - - camel_exception_init (&ex); - - /* expunge all remote stores */ - accounts = mail_config_get_accounts (); - iter = e_list_get_iterator ((EList *) accounts); - while (e_iterator_is_valid (iter)) { - account = (EAccount *) e_iterator_get (iter); - - /* make sure this is a valid source */ - if (account->enabled && account->source->url) { - provider = camel_session_get_provider (session, account->source->url, &ex); - if (provider) { - /* make sure this store is a remote store */ - if (provider->flags & CAMEL_PROVIDER_IS_STORAGE && - provider->flags & CAMEL_PROVIDER_IS_REMOTE) { - mail_empty_trash (account, NULL, NULL); - } - } - - /* clear the exception for the next round */ - camel_exception_clear (&ex); - } - - e_iterator_next (iter); - } - - g_object_unref (iter); - - /* Now empty the local trash folder */ - mail_empty_trash (NULL, NULL, NULL); -} |