/*
* 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>
*
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
*/
#include <config.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <gdk/gdkkeysyms.h>
#include <libgnome/gnome-util.h>
#ifdef G_OS_WIN32
/* Work around 'DATADIR' and 'interface' lossage in <windows.h> */
#define DATADIR crap_DATADIR
#include <windows.h>
#undef DATADIR
#undef interface
#endif
#include <libgnome/gnome-url.h>
#include <gconf/gconf-client.h>
#include <camel/camel-mime-message.h>
#include <camel/camel-stream.h>
#include <camel/camel-stream-filter.h>
#include <camel/camel-mime-filter.h>
#include <camel/camel-mime-filter-tohtml.h>
#include <camel/camel-mime-filter-enriched.h>
#include <camel/camel-multipart.h>
#include <camel/camel-stream-mem.h>
#include <camel/camel-url.h>
#include <camel/camel-vee-folder.h>
#include <camel/camel-disco-store.h>
#include <camel/camel-offline-store.h>
#include <camel/camel-vee-store.h>
#include <gtkhtml/gtkhtml.h>
#include <gtkhtml/gtkhtml-embedded.h>
#include <gtkhtml/gtkhtml-stream.h>
#include <libedataserver/e-data-server-util.h>
#include <libedataserver/e-msgport.h>
#include "menus/gal-view-etable.h"
#include "menus/gal-view-factory-etable.h"
#include "menus/gal-view-instance.h"
#include "misc/e-charset-picker.h"
#include <misc/e-spinner.h>
#include "e-util/e-error.h"
#include "e-util/e-dialog-utils.h"
#include "e-util/e-icon-factory.h"
#include "e-util/e-print.h"
#include "e-util/e-profile-event.h"
#include "e-util/e-util-private.h"
#include "e-util/e-util-labels.h"
#include "shell/e-shell.h"
#include "filter/filter-rule.h"
#include "em-format-html-display.h"
#include "em-format-html-print.h"
#include "em-folder-selection.h"
#include "em-folder-view.h"
#include "em-folder-browser.h"
#include "em-mailer-prefs.h"
#include "em-folder-browser.h"
#include "em-message-browser.h"
#include "message-list.h"
#include "em-utils.h"
#include "em-composer-utils.h"
#include "em-menu.h"
#include "em-event.h"
#include "e-mail-shell-module.h"
#include "mail-mt.h"
#include "mail-ops.h"
#include "mail-config.h"
#include "mail-autofilter.h"
#include "mail-vfolder.h"
#include "mail-tools.h"
#ifdef HAVE_XFREE
#include <X11/XF86keysym.h>
#endif
static void emfv_list_message_selected(MessageList *ml, const char *uid, EMFolderView *emfv);
static void emfv_list_built(MessageList *ml, EMFolderView *emfv);
static int emfv_list_right_click(ETree *tree, gint row, ETreePath path, gint col, GdkEvent *event, EMFolderView *emfv);
static void emfv_list_selection_change(ETree *tree, EMFolderView *emfv);
static void emfv_format_link_clicked(EMFormatHTMLDisplay *efhd, const char *uri, EMFolderView *);
static int emfv_format_popup_event(EMFormatHTMLDisplay *efhd, GdkEventButton *event, const char *uri, CamelMimePart *part, EMFolderView *);
static void emfv_enable_menus(EMFolderView *emfv);
static void emfv_set_folder(EMFolderView *emfv, CamelFolder *folder, const char *uri);
static void emfv_set_folder_uri(EMFolderView *emfv, const char *uri);
static void emfv_set_message(EMFolderView *emfv, const char *uid, int nomarkseen);
static void emfv_activate(EMFolderView *emfv, BonoboUIComponent *uic, int state);
static void emfv_setting_setup(EMFolderView *emfv);
static void emfv_on_url_cb(GObject *emitter, const char *url, EMFolderView *emfv);
static void emfv_on_url(EMFolderView *emfv, const char *uri, const char *nice_uri);
static void emfv_set_seen (EMFolderView *emfv, const char *uid);
static gboolean emfv_on_html_button_released_cb (GtkHTML *html, GdkEventButton *button, EMFolderView *emfv);
static gboolean emfv_popup_menu (GtkWidget *widget);
/* this is added to emfv->enable_map in :init() */
static const EMFolderViewEnable emfv_enable_map[] = {
{ "EditCut", EM_POPUP_SELECT_MANY },
{ "EditCopy", EM_FOLDER_VIEW_SELECT_SELECTION },
{ "EditPaste", EM_POPUP_SELECT_FOLDER },
{ "SelectAllText", EM_POPUP_SELECT_ONE },
/* FIXME: should these be single-selection? */
{ "MailNext", EM_POPUP_SELECT_MANY|EM_FOLDER_VIEW_SELECT_NEXT_MSG },
{ "MailNextFlagged", EM_POPUP_SELECT_MANY },
{ "MailNextUnread", EM_POPUP_SELECT_MANY },
{ "MailNextThread", EM_POPUP_SELECT_MANY },
{ "MailPrevious", EM_POPUP_SELECT_MANY|EM_FOLDER_VIEW_SELECT_PREV_MSG },
{ "MailPreviousFlagged", EM_POPUP_SELECT_MANY },
{ "MailPreviousUnread", EM_POPUP_SELECT_MANY },
{ "AddSenderToAddressbook", EM_POPUP_SELECT_ADD_SENDER },
{ "MessageApplyFilters", EM_POPUP_SELECT_MANY },
{ "MessageFilterJunk", EM_POPUP_SELECT_MANY },
{ "MessageCopy", EM_POPUP_SELECT_MANY },
{ "MessageDelete", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_DELETE },
{ "MessageDeleteKey", EM_POPUP_SELECT_MANY},
{ "MessageForward", EM_POPUP_SELECT_MANY },
{ "MessageForwardAttached", EM_POPUP_SELECT_MANY },
{ "MessageForwardInline", EM_POPUP_SELECT_ONE },
{ "MessageForwardQuoted", EM_POPUP_SELECT_ONE },
{ "MessageRedirect", EM_POPUP_SELECT_ONE },
{ "MessageMarkAsRead", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_MARK_READ },
{ "MessageMarkAsUnRead", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_MARK_UNREAD },
{ "MessageMarkAsImportant", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_MARK_IMPORTANT },
{ "MessageMarkAsUnimportant", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_MARK_UNIMPORTANT },
{ "MessageMarkAsJunk", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_JUNK },
{ "MessageMarkAsNotJunk", EM_POPUP_SELECT_MANY},
{ "MessageFollowUpFlag", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_FLAG_FOLLOWUP },
{ "MessageFollowUpComplete", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_FLAG_COMPLETED },
{ "MessageFollowUpClear", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_FLAG_CLEAR },
{ "MessageMove", EM_POPUP_SELECT_MANY },
{ "MessageOpen", EM_POPUP_SELECT_MANY },
{ "MessagePostReply", EM_POPUP_SELECT_ONE },
{ "MessageReplyAll", EM_POPUP_SELECT_ONE },
{ "MessageReplyList", EM_POPUP_SELECT_ONE|EM_POPUP_SELECT_MAILING_LIST },
{ "MessageReplySender", EM_POPUP_SELECT_ONE },
{ "MessageEdit", EM_POPUP_SELECT_ONE },
{ "MessageSaveAs", EM_POPUP_SELECT_MANY },
{ "MessageSearch", EM_POPUP_SELECT_ONE| EM_FOLDER_VIEW_PREVIEW_PRESENT },
{ "MessageUndelete", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_UNDELETE },
{ "PrintMessage", EM_POPUP_SELECT_ONE },
{ "PrintPreviewMessage", EM_POPUP_SELECT_ONE },
{ "TextZoomIn", EM_POPUP_SELECT_ONE },
{ "TextZoomOut", EM_POPUP_SELECT_ONE },
{ "TextZoomReset", EM_POPUP_SELECT_ONE },
{ "ToolsFilterMailingList", EM_POPUP_SELECT_ONE|EM_POPUP_SELECT_MAILING_LIST},
{ "ToolsFilterRecipient", EM_POPUP_SELECT_ONE },
{ "ToolsFilterSender", EM_POPUP_SELECT_ONE },
{ "ToolsFilterSubject", EM_POPUP_SELECT_ONE },
{ "ToolsVFolderMailingList", EM_POPUP_SELECT_ONE|EM_POPUP_SELECT_MAILING_LIST},
{ "ToolsVFolderRecipient", EM_POPUP_SELECT_ONE },
{ "ToolsVFolderSender", EM_POPUP_SELECT_ONE },
{ "ToolsVFolderSubject", EM_POPUP_SELECT_ONE },
{ "ViewLoadImages", EM_POPUP_SELECT_ONE },
{ "ViewSource", EM_POPUP_SELECT_ONE },
/* always enabled */
{ "MailStop", 0 },
{ NULL },
};
struct _EMFolderViewPrivate {
guint setting_notify_id;
guint selected_id;
guint nomarkseen:1;
guint destroyed:1;
GtkWidget *invisible;
char *selection_uri;
char *selected_uid;
};
static GtkVBoxClass *emfv_parent;
enum {
EMFV_ON_URL,
EMFV_LOADED,
EMFV_CHANGED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL];
static void emfv_selection_get(GtkWidget *widget, GtkSelectionData *data, guint info, guint time_stamp, EMFolderView *emfv);
static void emfv_selection_clear_event(GtkWidget *widget, GdkEventSelection *event, EMFolderView *emfv);
#ifdef ENABLE_PROFILING
static void
emfv_format_complete(EMFormat *emf, EMFolderView *emfv)
{
e_profile_event_emit("goto.done", emf->uid?emf->uid:"", 0);
}
#endif
static void
emfv_init(GObject *o)
{
EMFolderView *emfv = (EMFolderView *)o;
struct _EMFolderViewPrivate *p;
extern CamelSession *session;
gtk_box_set_homogeneous (GTK_BOX (emfv), FALSE);
p = emfv->priv = g_malloc0(sizeof(struct _EMFolderViewPrivate));
emfv->statusbar_active = TRUE;
emfv->list_active = FALSE;
emfv->ui_files = g_slist_append(NULL,
g_build_filename (EVOLUTION_UIDIR,
"evolution-mail-message.xml",
NULL));
emfv->ui_app_name = "evolution-mail";
emfv->enable_map = g_slist_prepend(NULL, (void *)emfv_enable_map);
emfv->list = (MessageList *)message_list_new();
g_signal_connect(emfv->list, "message_selected", G_CALLBACK(emfv_list_message_selected), emfv);
g_signal_connect(emfv->list, "message_list_built", G_CALLBACK(emfv_list_built), emfv);
/* FIXME: should this hang off message-list instead? */
g_signal_connect(emfv->list->tree, "right_click", G_CALLBACK(emfv_list_right_click), emfv);
// g_signal_connect(emfv->list->tree, "double_click", G_CALLBACK(emfv_list_double_click), emfv);
// g_signal_connect(emfv->list->tree, "key_press", G_CALLBACK(emfv_list_key_press), emfv);
g_signal_connect(emfv->list->tree, "selection_change", G_CALLBACK(emfv_list_selection_change), emfv);
emfv->preview = (EMFormatHTMLDisplay *)em_format_html_display_new();
/* FIXME: set_session should NOT be called here. Should it be a constructor attribute? */
em_format_set_session ((EMFormat *) emfv->preview, session);
g_signal_connect(emfv->preview, "link_clicked", G_CALLBACK(emfv_format_link_clicked), emfv);
g_signal_connect(emfv->preview, "popup_event", G_CALLBACK(emfv_format_popup_event), emfv);
g_signal_connect (emfv->preview, "on_url", G_CALLBACK (emfv_on_url_cb), emfv);
g_signal_connect (((EMFormatHTML *)emfv->preview)->html, "button-release-event", G_CALLBACK (emfv_on_html_button_released_cb), emfv);
#ifdef ENABLE_PROFILING
g_signal_connect(emfv->preview, "complete", G_CALLBACK (emfv_format_complete), emfv);
#endif
p->invisible = gtk_invisible_new();
g_signal_connect(p->invisible, "selection_get", G_CALLBACK(emfv_selection_get), emfv);
g_signal_connect(p->invisible, "selection_clear_event", G_CALLBACK(emfv_selection_clear_event), emfv);
gtk_selection_add_target(p->invisible, GDK_SELECTION_PRIMARY, GDK_SELECTION_TYPE_STRING, 0);
gtk_selection_add_target(p->invisible, GDK_SELECTION_CLIPBOARD, GDK_SELECTION_TYPE_STRING, 1);
emfv->async = mail_async_event_new();
emfv_setting_setup(emfv);
}
static void
free_one_ui_file (gpointer data,
gpointer user_data)
{
g_free (data);
}
static void
emfv_finalise(GObject *o)
{
EMFolderView *emfv = (EMFolderView *)o;
struct _EMFolderViewPrivate *p = emfv->priv;
g_slist_foreach (emfv->ui_files, free_one_ui_file, NULL);
g_slist_free(emfv->ui_files);
g_slist_free(emfv->enable_map);
g_free(p);
((GObjectClass *)emfv_parent)->finalize(o);
}
static void
emfv_destroy (GtkObject *o)
{
EMFolderView *emfv = (EMFolderView *) o;
struct _EMFolderViewPrivate *p = emfv->priv;
p->destroyed = TRUE;
if (emfv->list && emfv->list->seen_id) {
g_source_remove(emfv->list->seen_id);
emfv->list->seen_id = 0;
}
if (p->setting_notify_id) {
GConfClient *gconf = gconf_client_get_default();
gconf_client_notify_remove(gconf, p->setting_notify_id);
p->setting_notify_id = 0;
g_object_unref(gconf);
}
if (emfv->folder) {
camel_object_unref(emfv->folder);
g_free(emfv->folder_uri);
emfv->folder = NULL;
emfv->folder_uri = NULL;
}
if (emfv->async) {
mail_async_event_destroy(emfv->async);
emfv->async = NULL;
}
if (p->invisible) {
gtk_object_destroy((GtkObject *)p->invisible);
p->invisible = NULL;
}
if (p->selected_id != 0) {
g_source_remove(p->selected_id);
p->selected_id = 0;
}
g_free(p->selected_uid);
p->selected_uid = NULL;
g_free (emfv->displayed_uid);
emfv->displayed_uid = NULL;
emfv->preview = NULL;
emfv->list = NULL;
emfv->preview_active = FALSE;
emfv->uic = NULL;
((GtkObjectClass *) emfv_parent)->destroy (o);
}
static void
emfv_class_init(GObjectClass *klass)
{
klass->finalize = emfv_finalise;
((GtkObjectClass *) klass)->destroy = emfv_destroy;
((GtkWidgetClass *) klass)->popup_menu = emfv_popup_menu;
((EMFolderViewClass *) klass)->update_message_style = TRUE;
((EMFolderViewClass *)klass)->set_folder = emfv_set_folder;
((EMFolderViewClass *)klass)->set_folder_uri = emfv_set_folder_uri;
((EMFolderViewClass *)klass)->set_message = emfv_set_message;
((EMFolderViewClass *)klass)->activate = emfv_activate;
((EMFolderViewClass *)klass)->on_url = emfv_on_url;
signals[EMFV_ON_URL] = g_signal_new ("on-url",
G_OBJECT_CLASS_TYPE (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (EMFolderViewClass, on_url),
NULL, NULL,
e_marshal_VOID__STRING_STRING,
G_TYPE_NONE,
2, G_TYPE_STRING, G_TYPE_STRING);
signals[EMFV_LOADED] = g_signal_new("loaded",
G_OBJECT_CLASS_TYPE(klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(EMFolderViewClass, loaded),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
signals[EMFV_CHANGED] = g_signal_new("changed",
G_OBJECT_CLASS_TYPE(klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(EMFolderViewClass, changed),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
}
GType
em_folder_view_get_type(void)
{
static GType type = 0;
if (type == 0) {
static const GTypeInfo info = {
sizeof(EMFolderViewClass),
NULL, NULL,
(GClassInitFunc)emfv_class_init,
NULL, NULL,
sizeof(EMFolderView), 0,
(GInstanceInitFunc)emfv_init
};
emfv_parent = g_type_class_ref(gtk_vbox_get_type());
type = g_type_register_static(gtk_vbox_get_type(), "EMFolderView", &info, 0);
}
return type;
}
GtkWidget *em_folder_view_new(void)
{
EMFolderView *emfv = g_object_new(em_folder_view_get_type(), NULL);
return (GtkWidget *)emfv;
}
/* flag all selected messages. Return number flagged */
/* FIXME: Should this be part of message-list instead? */
int
em_folder_view_mark_selected(EMFolderView *emfv, guint32 mask, guint32 set)
{
GPtrArray *uids;
int i;
if (emfv->folder == NULL)
return 0;
uids = message_list_get_selected(emfv->list);
camel_folder_freeze(emfv->folder);
for (i=0; i<uids->len; i++)
camel_folder_set_message_flags(emfv->folder, uids->pdata[i], mask, set);
message_list_free_uids(emfv->list, uids);
camel_folder_thaw(emfv->folder);
return i;
}
/* should this be elsewhere/take a uid list? */
int
em_folder_view_open_selected(EMFolderView *emfv)
{
GPtrArray *uids, *views;
int i = 0;
uids = message_list_get_selected(emfv->list);
if (uids->len >= 10) {
char *num = g_strdup_printf("%d", uids->len);
int doit;
doit = em_utils_prompt_user((GtkWindow *)gtk_widget_get_toplevel((GtkWidget *)emfv),
"/apps/evolution/mail/prompts/open_many",
"mail:ask-open-many", num, NULL);
g_free(num);
if (!doit) {
message_list_free_uids(emfv->list, uids);
return 0;
}
}
if (em_utils_folder_is_drafts(emfv->folder, emfv->folder_uri)
|| em_utils_folder_is_templates(emfv->folder, emfv->folder_uri)
|| em_utils_folder_is_outbox(emfv->folder, emfv->folder_uri)) {
em_utils_edit_messages(emfv->folder, uids, TRUE);
return uids->len;
}
/* for vfolders we need to edit the *original*, not the vfolder copy */
views = g_ptr_array_new();
for (i=0;i<uids->len;i++) {
if (camel_object_is((CamelObject *)emfv->folder, camel_vee_folder_get_type())) {
CamelVeeMessageInfo *vinfo = (CamelVeeMessageInfo *)camel_folder_get_message_info(emfv->folder, uids->pdata[i]);
if (vinfo) {
char *uid;
/* TODO: get_location shouldn't strdup the uid */
CamelFolder *f = camel_vee_folder_get_location((CamelVeeFolder *)emfv->folder, vinfo, &uid);
char *uri = mail_tools_folder_to_url(f);
if (em_utils_folder_is_drafts(f, uri) || em_utils_folder_is_outbox(f, uri)) {
GPtrArray *edits = g_ptr_array_new();
g_ptr_array_add(edits, uid);
em_utils_edit_messages(f, edits, TRUE);
} else {
g_free(uid);
g_ptr_array_add(views, g_strdup(uids->pdata[i]));
}
g_free(uri);
}
} else {
g_ptr_array_add(views, g_strdup(uids->pdata[i]));
}
}
/* TODO: have an em_utils_open_messages call? */
for (i=0; i<views->len; i++) {
EMMessageBrowser *emmb;
emmb = (EMMessageBrowser *)em_message_browser_window_new();
message_list_set_threaded(((EMFolderView *)emmb)->list, emfv->list->threaded);
/* always keep actual message in a list view, even it doesn't belong to the filter anymore */
message_list_ensure_message (((EMFolderView *)emmb)->list, views->pdata[i]);
message_list_set_search (((EMFolderView *)emmb)->list, emfv->list->search);
em_folder_view_set_hide_deleted((EMFolderView *)emmb, emfv->hide_deleted);
/* FIXME: session needs to be passed easier than this */
em_format_set_session((EMFormat *)((EMFolderView *)emmb)->preview, ((EMFormat *)emfv->preview)->session);
em_folder_view_set_folder((EMFolderView *)emmb, emfv->folder, emfv->folder_uri);
em_folder_view_set_message((EMFolderView *)emmb, views->pdata[i], FALSE);
gtk_widget_show(emmb->window);
/* TODO: this loads the message twice (!) */
em_utils_handle_receipt (emfv->folder, uids->pdata[i], NULL);
g_free(views->pdata[i]);
}
g_ptr_array_free(views, TRUE);
message_list_free_uids(emfv->list, uids);
return i;
}
/* ********************************************************************** */
static void
emfv_set_folder(EMFolderView *emfv, CamelFolder *folder, const char *uri)
{
int isout = (folder && uri
&& (em_utils_folder_is_drafts(folder, uri)
|| em_utils_folder_is_sent(folder, uri)
|| em_utils_folder_is_outbox(folder, uri)));
if (folder == emfv->folder)
return;
if (emfv->priv->selected_id)
g_source_remove(emfv->priv->selected_id);
if (emfv->preview)
em_format_format ((EMFormat *) emfv->preview, NULL, NULL, NULL);
message_list_set_folder(emfv->list, folder, uri, isout);
g_free(emfv->folder_uri);
emfv->folder_uri = uri ? g_strdup(uri):NULL;
if (emfv->folder) {
emfv->hide_deleted = emfv->list->hidedeleted; /* <- a bit nasty but makes it track the display better */
mail_sync_folder (emfv->folder, NULL, NULL);
camel_object_unref(emfv->folder);
}
emfv->folder = folder;
if (folder) {
/* We need to set this up to get the right view options for the message-list,
* even if we're not showing it */
#if 0 /* KILL-BONOBO */
emfv_setup_view_instance(emfv);
#endif
camel_object_ref(folder);
}
emfv_enable_menus(emfv);
/* TODO: should probably be called after all processing, not just this class's impl */
g_signal_emit(emfv, signals[EMFV_LOADED], 0);
}
static void
emfv_got_folder(char *uri, CamelFolder *folder, void *data)
{
EMFolderView *emfv = data;
em_folder_view_set_folder(emfv, folder, uri);
}
static void
emfv_set_folder_uri(EMFolderView *emfv, const char *uri)
{
mail_get_folder(uri, 0, emfv_got_folder, emfv, mail_msg_fast_ordered_push);
}
static void
emfv_set_message(EMFolderView *emfv, const char *uid, int nomarkseen)
{
e_profile_event_emit("goto.uid", uid?uid:"<none>", 0);
/* This could possible race with other set messages, but likelyhood is small */
emfv->priv->nomarkseen = nomarkseen;
message_list_select_uid(emfv->list, uid);
/* force an update, since we may not get an updated event if we select the same uid */
emfv_list_message_selected(emfv->list, uid, emfv);
}
/* ********************************************************************** */
static void
emfv_selection_get(GtkWidget *widget, GtkSelectionData *data, guint info, guint time_stamp, EMFolderView *emfv)
{
struct _EMFolderViewPrivate *p = emfv->priv;
if (p->selection_uri == NULL)
return;
gtk_selection_data_set(data, data->target, 8, (unsigned char *)p->selection_uri, strlen(p->selection_uri));
}
static void
emfv_selection_clear_event(GtkWidget *widget, GdkEventSelection *event, EMFolderView *emfv)
{
#if 0 /* do i care? */
struct _EMFolderViewPrivate *p = emfv->priv;
g_free(p->selection_uri);
p->selection_uri = NULL;
#endif
}
/* ********************************************************************** */
/* Popup menu
In many cases these are the functions called by the bonobo callbacks too */
static void
emfv_popup_open(EPopup *ep, EPopupItem *pitem, void *data)
{
EMFolderView *emfv = data;
em_folder_view_open_selected(emfv);
}
static void
emfv_popup_source(EPopup *ep, EPopupItem *pitem, void *data)
{
EMFolderView *emfv = data;
EMMessageBrowser *emmb;
GPtrArray *uids;
uids = message_list_get_selected(emfv->list);
emmb = (EMMessageBrowser *)em_message_browser_window_new();
em_format_set_session((EMFormat *)((EMFolderView *)emmb)->preview, ((EMFormat *)emfv->preview)->session);
em_folder_view_set_folder((EMFolderView *)emmb, emfv->folder, emfv->folder_uri);
em_format_set_mode((EMFormat *)((EMFolderView *)emmb)->preview, EM_FORMAT_SOURCE);
em_folder_view_set_message((EMFolderView *)emmb, uids->pdata[0], FALSE);
gtk_widget_show(emmb->window);
message_list_free_uids(emfv->list, uids);
}
//#define DelInVFolderCheckName "DelInVFolderCheck"
//#define DelInVFolderKey "/apps/evolution/mail/prompts/delete_in_vfolder"
//static void
//emfv_delete_msg_response (GtkWidget *dialog, int response, gpointer data)
//{
// if (response == GTK_RESPONSE_OK) {
// EMFolderView *emfv = data;
// int count;
// GPtrArray *uids;
//
// if (dialog) {
// GList *children, *l;
// GtkWidget *check = NULL;
//
// children = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox));
// for (l = children; l; l = l->next) {
// if (GTK_IS_ALIGNMENT (l->data)) {
// check = gtk_bin_get_child (GTK_BIN (l->data));
//
// if (check && GTK_IS_CHECK_BUTTON (check) &&
// !strcmp (gtk_widget_get_name (check), DelInVFolderCheckName))
// break;
//
// check = NULL;
// }
// }
//
// if (check) {
// GConfClient *gconf = gconf_client_get_default ();
// gconf_client_set_bool (gconf, DelInVFolderKey, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check)), NULL);
// g_object_unref (gconf);
// }
//
// g_list_free (children);
// }
//
// uids = message_list_get_selected(emfv->list);
// camel_folder_freeze(emfv->folder);
//
// for (count=0; count < uids->len; count++) {
// if (camel_folder_get_message_flags (emfv->folder, uids->pdata[count]) & CAMEL_MESSAGE_USER_NOT_DELETABLE) {
// if (emfv->preview_active) {
// GtkHTMLStream *hstream = gtk_html_begin(((EMFormatHTML *)emfv->preview)->html);
//
// gtk_html_stream_printf(hstream, "<h2>%s</h2><p>%s</p>",
// _("Mail Deletion Failed"),
// _("You do not have sufficient permissions to delete this mail."));
// gtk_html_stream_close(hstream, GTK_HTML_STREAM_OK);
// } else {
// GtkWidget *w = e_error_new (NULL, "mail:no-delete-permission", "", NULL);
// em_utils_show_error_silent (w);
// }
//
// count = -1;
// break;
// } else
// camel_folder_set_message_flags(emfv->folder, uids->pdata[count], CAMEL_MESSAGE_SEEN|CAMEL_MESSAGE_DELETED, CAMEL_MESSAGE_SEEN|CAMEL_MESSAGE_DELETED );
// }
//
// message_list_free_uids(emfv->list, uids);
// camel_folder_thaw(emfv->folder);
//
// em_folder_view_select_next_message (emfv, count, FALSE);
// }
//
// if (dialog)
// gtk_widget_destroy (dialog);
//}
//static void
//emfv_popup_delete (EPopup *ep, EPopupItem *pitem, void *data)
//{
// EMFolderView *emfv = data;
// GConfClient *gconf = gconf_client_get_default ();
//
// if (emfv->folder && emfv->folder->parent_store && CAMEL_IS_VEE_STORE (emfv->folder->parent_store)
// && !gconf_client_get_bool (gconf, DelInVFolderKey, NULL)) {
// GtkWidget *dialog, *checkbox, *align;
//
// dialog = e_error_new (NULL, "mail:ask-delete-vfolder-msg", emfv->folder->full_name, NULL);
// g_signal_connect (dialog, "response", G_CALLBACK (emfv_delete_msg_response), emfv);
// checkbox = gtk_check_button_new_with_label (_("Do not ask me again."));
// gtk_widget_set_name (checkbox, DelInVFolderCheckName);
// align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
// gtk_container_add (GTK_CONTAINER (align), checkbox);
// gtk_widget_show (checkbox);
// gtk_box_pack_end (GTK_BOX (GTK_DIALOG (dialog)->vbox), align, TRUE, TRUE, 6);
// gtk_widget_show (align);
// gtk_widget_show (dialog);
// } else {
// emfv_delete_msg_response (NULL, GTK_RESPONSE_OK, emfv);
// }
//
// g_object_unref (gconf);
//}
//#undef DelInVFolderCheckName
//#undef DelInVFolderKey
static void
emfv_set_label (EMFolderView *emfv, const char *label)
{
GPtrArray *uids = message_list_get_selected (emfv->list);
int i;
for (i = 0; i < uids->len; i++)
camel_folder_set_message_user_flag (emfv->folder, uids->pdata[i], label, TRUE);
message_list_free_uids (emfv->list, uids);
}
static void
emfv_unset_label (EMFolderView *emfv, const char *label)
{
GPtrArray *uids = message_list_get_selected (emfv->list);
int i;
for (i = 0; i < uids->len; i++) {
camel_folder_set_message_user_flag (emfv->folder, uids->pdata[i], label, FALSE);
camel_folder_set_message_user_tag (emfv->folder, uids->pdata[i], "label", NULL);
}
message_list_free_uids (emfv->list, uids);
}
static void
emfv_popup_label_clear(EPopup *ep, EPopupItem *pitem, void *data)
{
EMFolderView *emfv = data;
GSList *l;
EUtilLabel *label;
for (l = mail_config_get_labels (); l; l = l->next) {
label = l->data;
emfv_unset_label(emfv, label->tag);
}
}
static void
emfv_popup_label_set(EPopup *ep, EPopupItem *pitem, void *data)
{
EMFolderView *emfv = data;
if (pitem->type & E_POPUP_ACTIVE)
emfv_set_label (emfv, pitem->user_data);
else
emfv_unset_label (emfv, pitem->user_data);
}
static void
emfv_popup_label_new (EPopup *ep, EPopupItem *pitem, void *data)
{
EMFolderView *emfv = data;
char *tag = e_util_labels_add_with_dlg (NULL, NULL);
if (tag) {
emfv_set_label (emfv, tag);
g_free (tag);
}
}
static EPopupItem emfv_popup_items[] = {
{ E_POPUP_BAR, "10.emfv", NULL, NULL, NULL, NULL },
{ E_POPUP_BAR, "20.emfv", NULL, NULL, NULL, NULL },
{ E_POPUP_BAR, "40.emfv", NULL, NULL, NULL, NULL },
// { E_POPUP_ITEM, "40.emfv.00", N_("_Delete"), emfv_popup_delete, NULL, "edit-delete", EM_POPUP_SELECT_DELETE|EM_FOLDER_VIEW_SELECT_LISTONLY },
{ E_POPUP_BAR, "50.emfv", NULL, NULL, NULL, NULL },
{ E_POPUP_SUBMENU, "60.label.00", N_("_Label"), NULL, NULL, NULL, EM_POPUP_SELECT_MANY|EM_FOLDER_VIEW_SELECT_LISTONLY },
{ E_POPUP_ITEM, "60.label.00/00.label", N_("_None"), emfv_popup_label_clear, NULL, NULL, EM_POPUP_SELECT_MANY|EM_FOLDER_VIEW_SELECT_LISTONLY },
{ E_POPUP_BAR, "60.label.00/00.label.00", NULL, NULL, NULL, NULL },
{ E_POPUP_BAR, "60.label.00/01.label", NULL, NULL, NULL, NULL },
{ E_POPUP_ITEM, "60.label.00/01.label.00", N_("_New Label"), emfv_popup_label_new, NULL, NULL, EM_POPUP_SELECT_MANY|EM_FOLDER_VIEW_SELECT_LISTONLY },
{ E_POPUP_BAR, "70.emfv.06", NULL, NULL, NULL, NULL },
{ E_POPUP_BAR, "90.filter", NULL, NULL, NULL, NULL },
{ E_POPUP_BAR, "90.filter.00/10", NULL, NULL, NULL, NULL },
};
static enum _e_popup_t
emfv_popup_labels_get_state_for_tag (EMFolderView *emfv, GPtrArray *uids, const char *label_tag)
{
enum _e_popup_t state = 0;
int i;
gboolean exists = FALSE, not_exists = FALSE;
g_return_val_if_fail (emfv != 0, state);
g_return_val_if_fail (label_tag != NULL, state);
for (i = 0; i < uids->len && (!exists || !not_exists); i++) {
if (camel_folder_get_message_user_flag (emfv->folder, uids->pdata[i], label_tag))
exists = TRUE;
else {
const char *label = e_util_labels_get_new_tag (camel_folder_get_message_user_tag (emfv->folder, uids->pdata[i], "label"));
/* backward compatibility... */
if (label && !strcmp (label, label_tag))
exists = TRUE;
else
not_exists = TRUE;
}
}
if (exists && not_exists)
state = E_POPUP_INCONSISTENT;
else if (exists)
state = E_POPUP_ACTIVE;
return state;
}
static void
emfv_popup_labels_free(EPopup *ep, GSList *l, void *data)
{
while (l) {
GSList *n = l->next;
EPopupItem *item = l->data;
g_free(item->path);
g_free(item);
g_slist_free_1(l);
l = n;
}
}
static void
emfv_popup_items_free(EPopup *ep, GSList *items, void *data)
{
g_slist_free(items);
}
static void
emfv_popup(EMFolderView *emfv, GdkEvent *event, int on_display)
{
GSList *menus = NULL, *l, *label_list = NULL;
GtkMenu *menu;
EMPopup *emp;
EMPopupTargetSelect *target;
int i;
/** @HookPoint-EMPopup: Message List Context Menu
* @Id: org.gnome.evolution.mail.folderview.popup.select
* @Type: EMPopup
* @Target: EMPopupTargetSelect
*
* This is the context menu shown on the message list or over a message.
*/
emp = em_popup_new("org.gnome.evolution.mail.folderview.popup");
target = em_folder_view_get_popup_target(emfv, emp, on_display);
for (i=0;i<sizeof(emfv_popup_items)/sizeof(emfv_popup_items[0]);i++)
menus = g_slist_prepend(menus, &emfv_popup_items[i]);
e_popup_add_items((EPopup *)emp, menus, NULL, emfv_popup_items_free, emfv);
i = 1;
if (!on_display) {
GPtrArray *uids = message_list_get_selected (emfv->list);
for (l = mail_config_get_labels (); l; l = l->next) {
EPopupItem *item;
EUtilLabel *label = l->data;
GdkPixmap *pixmap;
GdkColor colour;
GdkGC *gc;
item = g_malloc0(sizeof(*item));
item->type = E_POPUP_TOGGLE | emfv_popup_labels_get_state_for_tag (emfv, uids, label->tag);
item->path = g_strdup_printf("60.label.00/00.label.%02d", i++);
item->label = label->name;
item->activate = emfv_popup_label_set;
item->user_data = label->tag;
item->visible = EM_POPUP_SELECT_MANY|EM_FOLDER_VIEW_SELECT_LISTONLY;
gdk_color_parse (label->colour, &colour);
gdk_colormap_alloc_color(gdk_colormap_get_system(), &colour, FALSE, TRUE);
pixmap = gdk_pixmap_new(((GtkWidget *)emfv)->window, 16, 16, -1);
gc = gdk_gc_new(((GtkWidget *)emfv)->window);
gdk_gc_set_foreground(gc, &colour);
gdk_draw_rectangle(pixmap, gc, TRUE, 0, 0, 16, 16);
g_object_unref(gc);
item->image = gtk_image_new_from_pixmap(pixmap, NULL);
gtk_widget_show(item->image);
label_list = g_slist_prepend(label_list, item);
}
message_list_free_uids (emfv->list, uids);
}
e_popup_add_items((EPopup *)emp, label_list, NULL, emfv_popup_labels_free, emfv);
menu = e_popup_create_menu_once((EPopup *)emp, (EPopupTarget *)target, 0);
if (event == NULL || event->type == GDK_KEY_PRESS) {
/* FIXME: menu pos function */
gtk_menu_popup(menu, NULL, NULL, NULL, NULL, 0, event ? event->key.time : gtk_get_current_event_time());
} else {
gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event->button.button, event->button.time);
}
}
/* ********************************************************************** */
/* Bonobo menu's */
/* a lot of stuff maps directly to the popup menu equivalent */
#define EMFV_MAP_CALLBACK(from, to) \
static void \
from(BonoboUIComponent *uid, void *data, const char *path) \
{ \
to(NULL, NULL, data); \
}
//EMFV_MAP_CALLBACK(emfv_message_delete, emfv_popup_delete)
EMFV_MAP_CALLBACK(emfv_message_open, emfv_popup_open)
EMFV_MAP_CALLBACK(emfv_message_source, emfv_popup_source)
static void
prepare_offline(void *key, void *value, void *data)
{
CamelService *service = key;
if (CAMEL_IS_DISCO_STORE(service)
|| CAMEL_IS_OFFLINE_STORE(service)) {
mail_store_prepare_offline((CamelStore *)service);
}
}
static void
emfv_prepare_offline(BonoboUIComponent *uid, void *data, const char *path)
{
e_mail_shell_module_stores_foreach (
mail_shell_module, prepare_offline, NULL);
}
static void
emfv_edit_cut(BonoboUIComponent *uid, void *data, const char *path)
{
EMFolderView *emfv = data;
if (GTK_WIDGET_HAS_FOCUS(emfv->preview->formathtml.html))
em_format_html_display_cut(emfv->preview);
else
message_list_copy(emfv->list, TRUE);
}
static void
emfv_edit_copy(BonoboUIComponent *uid, void *data, const char *path)
{
EMFolderView *emfv = data;
if (GTK_WIDGET_HAS_FOCUS(emfv->preview->formathtml.html))
em_format_html_display_copy(emfv->preview);
else
message_list_copy(emfv->list, FALSE);
}
static void
emfv_edit_paste(BonoboUIComponent *uid, void *data, const char *path)
{
EMFolderView *emfv = data;
message_list_paste(emfv->list);
}
static void
emfv_select_all_text(BonoboUIComponent *uid, void *data, const char *path)
{
EMFolderView *emfv = data;
gboolean selected;
gtk_html_select_all (((EMFormatHTML *)emfv->preview)->html);
selected = gtk_html_command (((EMFormatHTML *)emfv->preview)->html, "is-selection-active");
bonobo_ui_component_set_prop(emfv->uic, "/commands/EditCopy", "sensitive", selected?"1":"0", NULL);
}
static void
emfv_message_search(BonoboUIComponent *uic, void *data, const char *path)
{
#if 0 /* KILL-BONOBO */
EMFolderView *emfv = data;
if (!emfv->list_active) /* We are in new mail window */
em_format_html_display_search(emfv->preview);
else {
/* We are in top level. Just grab focus to Search Bar */
gtk_widget_grab_focus (((ESearchBar *)((EMFolderBrowser *) emfv)->search)->entry);
gtk_option_menu_set_history (GTK_OPTION_MENU (((ESearchBar *)((EMFolderBrowser *) emfv)->search)->scopeoption), 3);
}
#endif
}
static void
emp_uri_popup_vfolder_sender(EPopup *ep, EPopupItem *pitem, void *data)
{
EMFolderView *emfv = data;
EMPopupTargetURI *t = (EMPopupTargetURI *)ep->target;
CamelURL *url;
CamelInternetAddress *addr;
url = camel_url_new(t->uri, NULL);
if (url == NULL) {
g_warning("cannot parse url '%s'", t->uri);
return;
}
if (url->path && url->path[0]) {
/* ensures vfolder is running */
vfolder_load_storage ();
addr = camel_internet_address_new ();
camel_address_decode (CAMEL_ADDRESS (addr), url->path);
vfolder_gui_add_from_address (addr, AUTO_FROM, emfv->folder_uri);
camel_object_unref (addr);
}
camel_url_free(url);
}
static void
emp_uri_popup_vfolder_recipient(EPopup *ep, EPopupItem *pitem, void *data)
{
EMFolderView *emfv = data;
EMPopupTargetURI *t = (EMPopupTargetURI *)ep->target;
CamelURL *url;
CamelInternetAddress *addr;
url = camel_url_new(t->uri, NULL);
if (url == NULL) {
g_warning("cannot parse url '%s'", t->uri);
return;
}
if (url->path && url->path[0]) {
/* ensures vfolder is running */
vfolder_load_storage ();
addr = camel_internet_address_new ();
camel_address_decode (CAMEL_ADDRESS (addr), url->path);
vfolder_gui_add_from_address (addr, AUTO_TO, emfv->folder_uri);
camel_object_unref (addr);
}
camel_url_free(url);
}
/* ********************************************************************** */
static BonoboUIVerb emfv_message_verbs[] = {
BONOBO_UI_UNSAFE_VERB ("PrepareForOffline", emfv_prepare_offline),
BONOBO_UI_UNSAFE_VERB ("EditCut", emfv_edit_cut),
BONOBO_UI_UNSAFE_VERB ("EditCopy", emfv_edit_copy),
BONOBO_UI_UNSAFE_VERB ("EditPaste", emfv_edit_paste),
BONOBO_UI_UNSAFE_VERB ("SelectAllText", emfv_select_all_text),
// BONOBO_UI_UNSAFE_VERB ("MessageDelete", emfv_message_delete),
// BONOBO_UI_UNSAFE_VERB ("MessageDeleteKey", emfv_message_delete),
BONOBO_UI_UNSAFE_VERB ("MessageOpen", emfv_message_open),
BONOBO_UI_UNSAFE_VERB ("MessageSearch", emfv_message_search),
BONOBO_UI_UNSAFE_VERB ("ViewSource", emfv_message_source),
BONOBO_UI_VERB_END
};
static void
emfv_enable_menus(EMFolderView *emfv)
{
guint32 disable_mask;
GString *name;
GSList *l;
if (emfv->uic == NULL)
return;
{
if (emfv->menu) {
EMMenuTargetSelect *t;
t = em_menu_target_new_select(emfv->menu, emfv->folder, emfv->folder_uri, message_list_get_selected(emfv->list));
t->target.widget = GTK_WIDGET (emfv);
e_menu_update_target((EMenu *)emfv->menu, t);
}
}
if (emfv->folder) {
EMPopup *emp = em_popup_new("dummy");
EMPopupTargetSelect *t;
t = em_folder_view_get_popup_target(emfv, emp, FALSE);
disable_mask = t->target.mask;
e_popup_target_free((EPopup *)emp, t);
g_object_unref(emp);
} else {
disable_mask = ~0;
}
name = g_string_new("");
for (l = emfv->enable_map; l; l = l->next) {
EMFolderViewEnable *map = l->data;
int i;
for (i=0;map[i].name;i++) {
int state = (map[i].mask & disable_mask) == 0;
g_string_printf(name, "/commands/%s", map[i].name);
bonobo_ui_component_set_prop(emfv->uic, name->str, "sensitive", state?"1":"0", NULL);
}
}
g_string_free(name, TRUE);
}
//static void
//emfv_view_mode(BonoboUIComponent *uic, const char *path, Bonobo_UIComponent_EventType type, const char *state, void *data)
//{
// EMFolderView *emfv = data;
// int i;
//
// if (type != Bonobo_UIComponent_STATE_CHANGED)
// return;
//
// /* TODO: I don't like this stuff much, is there any way we can move listening for such events
// elsehwere? Probably not I guess, unless there's a EMFolderViewContainer for bonobo usage
// of a folder view */
//
// i = state[0] != '0';
//
// em_format_set_mode((EMFormat *)emfv->preview, i);
//
// if (EM_FOLDER_VIEW_GET_CLASS (emfv)->update_message_style) {
// GConfClient *gconf = mail_config_get_gconf_client ();
//
// gconf_client_set_int (gconf, "/apps/evolution/mail/display/message_style", i, NULL);
// }
//}
//static void
//emfv_caret_mode(BonoboUIComponent *uic, const char *path, Bonobo_UIComponent_EventType type, const char *state, void *data)
//{
// EMFolderView *emfv = data;
//
// if (type != Bonobo_UIComponent_STATE_CHANGED)
// return;
//
// em_format_html_display_set_caret_mode(emfv->preview, state[0] != '0');
//
// gconf_client_set_bool(mail_config_get_gconf_client(), "/apps/evolution/mail/display/caret_mode", state[0] != '0', NULL);
//}
//static void
//emfv_charset_changed(BonoboUIComponent *uic, const char *path, Bonobo_UIComponent_EventType type, const char *state, void *data)
//{
// EMFolderView *emfv = data;
//
// if (type != Bonobo_UIComponent_STATE_CHANGED)
// return;
//
// /* menu items begin with "Charset-" = 8 characters */
// if (state[0] != '0' && strlen(path) > 8) {
// path += 8;
// /* default charset used in mail view */
// if (!strcmp(path, _("Default")))
// path = NULL;
//
// em_format_set_charset((EMFormat *)emfv->preview, path);
// }
//}
static void
emfv_activate(EMFolderView *emfv, BonoboUIComponent *uic, int act)
{
if (act) {
em_format_mode_t style;
gboolean state;
GSList *l;
emfv->uic = uic;
for (l = emfv->ui_files;l;l = l->next)
bonobo_ui_util_set_ui(uic, PREFIX, (char *)l->data, emfv->ui_app_name, NULL);
bonobo_ui_component_add_verb_list_with_data(uic, emfv_message_verbs, emfv);
/* must do plugin menu's after main ones because of bonobo bustedness */
if (emfv->menu)
e_menu_activate((EMenu *)emfv->menu, uic, act);
// state = emfv->preview->caret_mode;
// bonobo_ui_component_set_prop(uic, "/commands/CaretMode", "state", state?"1":"0", NULL);
// bonobo_ui_component_add_listener(uic, "CaretMode", emfv_caret_mode, emfv);
// style = ((EMFormat *)emfv->preview)->mode?EM_FORMAT_ALLHEADERS:EM_FORMAT_NORMAL;
// if (style)
// bonobo_ui_component_set_prop(uic, "/commands/ViewFullHeaders", "state", "1", NULL);
// bonobo_ui_component_add_listener(uic, "ViewFullHeaders", emfv_view_mode, emfv);
// em_format_set_mode((EMFormat *)emfv->preview, style);
if (emfv->folder)
bonobo_ui_component_set_prop(uic, "/commands/MessageEdit", "sensitive", "0", NULL);
// /* default charset used in mail view */
// e_charset_picker_bonobo_ui_populate (uic, "/menu/View", _("Default"), emfv_charset_changed, emfv);
emfv_enable_menus(emfv);
if (emfv->statusbar_active)
bonobo_ui_component_set_translate (uic, "/", "<status><item name=\"main\"/></status>", NULL);
/* We need to set this up to get the right view options for the message-list, even if we're not showing it */
#if 0 /* KILL-BONOBO */
if (emfv->folder)
emfv_setup_view_instance(emfv);
#endif
} else {
const BonoboUIVerb *v;
if (emfv->menu)
e_menu_activate((EMenu *)emfv->menu, uic, act);
/* TODO: Should this just rm /? */
for (v = &emfv_message_verbs[0]; v->cname; v++)
bonobo_ui_component_remove_verb(uic, v->cname);
if (emfv->folder)
mail_sync_folder(emfv->folder, NULL, NULL);
emfv->uic = NULL;
}
}
EMPopupTargetSelect *
em_folder_view_get_popup_target(EMFolderView *emfv, EMPopup *emp, int on_display)
{
EMPopupTargetSelect *t;
t = em_popup_target_new_select(emp, emfv->folder, emfv->folder_uri, message_list_get_selected(emfv->list));
t->target.widget = (GtkWidget *)emfv;
if (emfv->list->threaded)
t->target.mask &= ~EM_FOLDER_VIEW_SELECT_THREADED;
if (message_list_hidden(emfv->list) != 0)
t->target.mask &= ~EM_FOLDER_VIEW_SELECT_HIDDEN;
if (message_list_can_select(emfv->list, MESSAGE_LIST_SELECT_NEXT, 0, 0))
t->target.mask &= ~EM_FOLDER_VIEW_SELECT_NEXT_MSG;
if (message_list_can_select(emfv->list, MESSAGE_LIST_SELECT_PREVIOUS, 0, 0))
t->target.mask &= ~EM_FOLDER_VIEW_SELECT_PREV_MSG;
if (on_display)
t->target.mask &= ~EM_FOLDER_VIEW_SELECT_DISPLAY;
else
t->target.mask &= ~EM_FOLDER_VIEW_SELECT_LISTONLY;
if (gtk_html_command (((EMFormatHTML *)emfv->preview)->html, "is-selection-active"))
t->target.mask &= ~EM_FOLDER_VIEW_SELECT_SELECTION;
else
t->target.mask &= ~EM_FOLDER_VIEW_SELECT_NOSELECTION;
if (emfv->preview_active)
t->target.mask &= ~EM_FOLDER_VIEW_PREVIEW_PRESENT;
/* See bug 352980 */
/* See bug #54770 */
/* if (!emfv->hide_deleted)
t->target.mask &= ~EM_POPUP_SELECT_DELETE;*/
return t;
}
void
em_folder_view_set_statusbar (EMFolderView *emfv, gboolean statusbar)
{
g_return_if_fail (emfv);
emfv->statusbar_active = statusbar;
if (statusbar && emfv->uic)
bonobo_ui_component_set_translate (emfv->uic, "/",
"<status><item name=\"main\"/></status>", NULL);
}
void
em_folder_view_set_hide_deleted(EMFolderView *emfv, gboolean status)
{
if (emfv->folder && (emfv->folder->folder_flags & CAMEL_FOLDER_IS_TRASH))
status = FALSE;
emfv->hide_deleted = status;
if (emfv->folder) {
message_list_set_hidedeleted(emfv->list, status);
g_signal_emit(emfv, signals[EMFV_CHANGED], 0);
}
}
/* ********************************************************************** */
struct mst_t {
EMFolderView *emfv;
char *uid;
};
static void
mst_free (struct mst_t *mst)
{
mst->emfv->list->seen_id = 0;
g_free (mst->uid);
g_free (mst);
}
static int
do_mark_seen (gpointer user_data)
{
struct mst_t *mst = user_data;
EMFolderView *emfv = mst->emfv;
MessageList *list = emfv->list;
if (mst->uid && list->cursor_uid && !strcmp (mst->uid, list->cursor_uid))
emfv_set_seen (emfv, mst->uid);
return FALSE;
}
static void
emfv_list_done_message_selected(CamelFolder *folder, const char *uid, CamelMimeMessage *msg, void *data, CamelException *ex)
{
EMFolderView *emfv = data;
EMEvent *eme;
EMEventTargetMessage *target;
EShell *shell;
if (emfv->preview == NULL) {
emfv->priv->nomarkseen = FALSE;
emfv_enable_menus(emfv);
g_object_unref (emfv);
return;
}
e_profile_event_emit("goto.loaded", emfv->displayed_uid, 0);
shell = e_shell_module_get_shell (mail_shell_module);
e_shell_event (shell, "mail-icon", "evolution-mail");
/** @Event: message.reading
* @Title: Viewing a message
* @Target: EMEventTargetMessage
*
* message.reading is emitted whenever a user views a message.
*/
/* TODO: do we emit a message.reading with no message when we're looking at nothing or don't care? */
eme = em_event_peek();
target = em_event_target_new_message(eme, folder, msg, uid, 0);
e_event_emit((EEvent *)eme, "message.reading", (EEventTarget *)target);
em_format_format((EMFormat *)emfv->preview, folder, uid, msg);
if (emfv->list->seen_id)
g_source_remove(emfv->list->seen_id);
if (msg && emfv->mark_seen && !emfv->priv->nomarkseen) {
if (emfv->mark_seen_timeout > 0) {
struct mst_t *mst;
mst = g_new (struct mst_t, 1);
mst->emfv = emfv;
mst->uid = g_strdup (uid);
emfv->list->seen_id = g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, emfv->mark_seen_timeout,
(GSourceFunc)do_mark_seen, mst, (GDestroyNotify)mst_free);
} else {
emfv_set_seen (emfv, uid);
}
} else if (camel_exception_is_set(ex)) {
GtkHTMLStream *hstream = gtk_html_begin(((EMFormatHTML *)emfv->preview)->html);
/* Display the error inline rather than popping up an annoying box.
We also clear the exception, this stops the box popping up */
gtk_html_stream_printf(hstream, "<h2>%s</h2><p>%s</p>",
_("Unable to retrieve message"),
ex->desc);
gtk_html_stream_close(hstream, GTK_HTML_STREAM_OK);
camel_exception_clear(ex);
}
emfv->priv->nomarkseen = FALSE;
emfv_enable_menus(emfv);
g_object_unref (emfv);
}
static gboolean
emfv_spin(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject)
{
GtkWidget *ep;
if (!strcmp(eb->classid, "spinner")) {
GtkWidget *box, *label;
gchar *msg = g_strdup_printf("<b>%s</b>", _("Retrieving Message..."));
label = gtk_label_new (NULL);
gtk_label_set_markup ((GtkLabel *)label, msg);
box = gtk_hbox_new (FALSE, 0);
g_free (msg);
ep = e_spinner_new_spinning_small_shown ();
gtk_box_pack_start ((GtkBox *)box, ep, FALSE, FALSE, 0);
gtk_box_pack_start ((GtkBox *)box, label, FALSE, FALSE, 0);
gtk_container_add ((GtkContainer *)eb, box);
gtk_widget_show_all ((GtkWidget *)eb);
g_signal_handlers_disconnect_by_func(efh, emfv_spin, NULL);
}
return TRUE;
}
static gboolean
emfv_message_selected_timeout(void *data)
{
EMFolderView *emfv = data;
if (emfv->priv->selected_uid) {
if (emfv->displayed_uid == NULL || strcmp(emfv->displayed_uid, emfv->priv->selected_uid) != 0) {
/*GtkHTMLStream *hstream;*/
g_free(emfv->displayed_uid);
emfv->displayed_uid = emfv->priv->selected_uid;
emfv->priv->selected_uid = NULL;
g_object_ref (emfv);
/* TODO: we should manage our own thread stuff, would make cancelling outstanding stuff easier */
e_profile_event_emit("goto.load", emfv->displayed_uid, 0);
/* hstream = gtk_html_begin(((EMFormatHTML *)emfv->preview)->html);
g_signal_connect(((EMFormatHTML *)emfv->preview)->html, "object_requested", G_CALLBACK(emfv_spin), NULL);
gtk_html_stream_printf(hstream, "<object classid=\"spinner\"><h2>%s</h2><p>%s</p></object>",
_("Retrieving Message"),
emfv->displayed_uid);
gtk_html_stream_close(hstream, GTK_HTML_STREAM_OK);
*/
mail_get_messagex(emfv->folder, emfv->displayed_uid, emfv_list_done_message_selected, emfv, mail_msg_fast_ordered_push);
} else {
e_profile_event_emit("goto.empty", "", 0);
g_free(emfv->priv->selected_uid);
emfv->priv->selected_uid = NULL;
}
} else {
e_profile_event_emit("goto.empty", "", 0);
g_free(emfv->displayed_uid);
emfv->displayed_uid = NULL;
em_format_format((EMFormat *)emfv->preview, NULL, NULL, NULL);
emfv->priv->nomarkseen = FALSE;
}
emfv->priv->selected_id = 0;
return FALSE;
}
static void
emfv_list_message_selected(MessageList *ml, const char *uid, EMFolderView *emfv)
{
e_profile_event_emit("goto.listuid", uid, 0);
if (emfv->preview_active) {
if (emfv->priv->selected_id != 0)
g_source_remove(emfv->priv->selected_id);
emfv->priv->selected_id = g_timeout_add(100, emfv_message_selected_timeout, emfv);
g_free(emfv->priv->selected_uid);
emfv->priv->selected_uid = g_strdup(uid);
}
emfv_enable_menus(emfv);
g_signal_emit(emfv, signals[EMFV_CHANGED], 0);
}
static void
emfv_list_built(MessageList *ml, EMFolderView *emfv)
{
if (!emfv->priv->destroyed) {
emfv_enable_menus(emfv);
g_signal_emit(emfv, signals[EMFV_LOADED], 0);
}
}
//static void
//emfv_list_double_click(ETree *tree, gint row, ETreePath path, gint col, GdkEvent *event, EMFolderView *emfv)
//{
// /* Ignore double-clicks on columns that handle thier own state */
// if (MESSAGE_LIST_COLUMN_IS_ACTIVE (col))
// return;
//
// em_folder_view_open_selected(emfv);
//}
static int
emfv_list_right_click(ETree *tree, gint row, ETreePath path, gint col, GdkEvent *event, EMFolderView *emfv)
{
emfv_popup(emfv, event, FALSE);
return TRUE;
}
//static int
//emfv_list_key_press(ETree *tree, int row, ETreePath path, int col, GdkEvent *ev, EMFolderView *emfv)
//{
// GPtrArray *uids;
// int i;
// guint32 flags;
//
// if ((ev->key.state & GDK_CONTROL_MASK) != 0)
// return FALSE;
//
// switch (ev->key.keyval) {
// case GDK_Return:
// case GDK_KP_Enter:
// case GDK_ISO_Enter:
// em_folder_view_open_selected(emfv);
// break;
//#ifdef HAVE_XFREE
// case XF86XK_Reply:
// em_folder_view_message_reply(emfv, REPLY_MODE_ALL);
// break;
// case XF86XK_MailForward:
// uids = message_list_get_selected(emfv->list);
// em_utils_forward_messages (emfv->folder, uids, emfv->folder_uri);
// break;
//#endif /* HAVE_XFREE */
// case '!':
// uids = message_list_get_selected(emfv->list);
//
// camel_folder_freeze(emfv->folder);
// for (i = 0; i < uids->len; i++) {
// flags = camel_folder_get_message_flags(emfv->folder, uids->pdata[i]) ^ CAMEL_MESSAGE_FLAGGED;
// if (flags & CAMEL_MESSAGE_FLAGGED)
// flags &= ~CAMEL_MESSAGE_DELETED;
// camel_folder_set_message_flags(emfv->folder, uids->pdata[i],
// CAMEL_MESSAGE_FLAGGED|CAMEL_MESSAGE_DELETED, flags);
// }
// camel_folder_thaw(emfv->folder);
//
// message_list_free_uids(emfv->list, uids);
// break;
// default:
// return FALSE;
// }
//
// return TRUE;
//}
static gboolean
emfv_popup_menu (GtkWidget *widget)
{
gboolean ret = FALSE;
EMFolderView *emfv = (EMFolderView *)widget;
/* Try to bring up menu for preview html object.
Currently we cannot directly connect to html's "popup_menu" signal
since it doesn't work.
*/
if (GTK_WIDGET_HAS_FOCUS (emfv->preview->formathtml.html))
ret = em_format_html_display_popup_menu (emfv->preview);
if (!ret)
emfv_popup (emfv, NULL, FALSE);
return TRUE;
}
static void
emfv_list_selection_change(ETree *tree, EMFolderView *emfv)
{
/* we can't just listen to the message-list message selected thing, since we dont get them
in all cases. blah */
g_signal_emit(emfv, signals[EMFV_CHANGED], 0);
}
static void
emfv_format_link_clicked(EMFormatHTMLDisplay *efhd, const char *uri, EMFolderView *emfv)
{
if (!strncmp (uri, "##", 2))
return;
if (!g_ascii_strncasecmp (uri, "mailto:", 7)) {
em_utils_compose_new_message_with_mailto (uri, emfv->folder_uri);
} else if (*uri == '#') {
gtk_html_jump_to_anchor (((EMFormatHTML *) efhd)->html, uri + 1);
} else if (!g_ascii_strncasecmp (uri, "thismessage:", 12)) {
/* ignore */
} else if (!g_ascii_strncasecmp (uri, "cid:", 4)) {
/* ignore */
} else {
GError *err = NULL;
gnome_url_show (uri, &err);
if (err) {
g_warning ("gnome_url_show: %s", err->message);
g_error_free (err);
}
}
}
static gchar *
url_unescape_amp (const gchar *url)
{
gchar *buff;
int i, j, amps;
if (!url)
return NULL;
amps = 0;
for (i = 0; url [i]; i++) {
if (url [i] == '&' && strncmp (url + i, "&", 5) == 0)
amps++;
}
buff = g_strdup (url);
if (!amps)
return buff;
for (i = 0, j = 0; url [i]; i++, j++) {
buff [j] = url [i];
if (url [i] == '&' && strncmp (url + i, "&", 5) == 0)
i += 4;
}
buff [j] = 0;
return buff;
}
static void
emp_uri_popup_link_copy(EPopup *ep, EPopupItem *pitem, void *data)
{
EMFolderView *emfv = data;
struct _EMFolderViewPrivate *p = emfv->priv;
g_free(p->selection_uri);
p->selection_uri = url_unescape_amp(pitem->user_data);
gtk_selection_owner_set(p->invisible, GDK_SELECTION_PRIMARY, gtk_get_current_event_time());
gtk_selection_owner_set(p->invisible, GDK_SELECTION_CLIPBOARD, gtk_get_current_event_time());
}
static EPopupItem emfv_uri_popups[] = {
{ E_POPUP_ITEM, "00.uri.11", N_("C_all To..."), emp_uri_popup_link_copy, NULL, NULL, EM_POPUP_URI_CALLTO },
{ E_POPUP_ITEM, "00.uri.15", N_("_Copy Link Location"), emp_uri_popup_link_copy, NULL, "edit-copy", EM_POPUP_URI_NOT_MAILTO },
{ E_POPUP_SUBMENU, "99.uri.00", N_("Create _Search Folder"), NULL, NULL, NULL, EM_POPUP_URI_MAILTO },
{ E_POPUP_ITEM, "99.uri.00/00.10", N_("_From this Address"), emp_uri_popup_vfolder_sender, NULL, NULL, EM_POPUP_URI_MAILTO },
{ E_POPUP_ITEM, "99.uri.00/00.00", N_("_To this Address"), emp_uri_popup_vfolder_recipient, NULL, NULL, EM_POPUP_URI_MAILTO },
};
static void
emfv_uri_popup_free(EPopup *ep, GSList *list, void *data)
{
while (list) {
GSList *n = list->next;
struct _EPopupItem *item = list->data;
g_free(item->user_data);
item->user_data = NULL;
g_free (item);
g_slist_free_1(list);
list = n;
}
}
static void
emfv_free_em_popup (gpointer emp)
{
EPopup *ep = (EPopup *)emp;
if (!ep)
return;
if (ep->target) {
/* without this the next unref on ep does nothing */
e_popup_target_free (ep, ep->target);
ep->target = NULL;
}
g_object_unref (ep);
}
static GtkMenu *
emfv_append_menu (EMPopup *des_emp, GtkMenu *des_menu, EMPopup *src_emp, GtkMenu *src_menu)
{
GtkWidget *separator;
GList *children, *p;
char *name;
if (!src_menu)
return des_menu;
if (!des_menu)
return src_menu;
separator = gtk_separator_menu_item_new ();
gtk_widget_show (separator);
gtk_menu_shell_append (GTK_MENU_SHELL (des_menu), separator);
children = gtk_container_get_children (GTK_CONTAINER (src_menu));
for (p = children; p; p = p->next) {
g_object_ref (p->data);
gtk_container_remove (GTK_CONTAINER (src_menu), p->data);
gtk_menu_shell_append (GTK_MENU_SHELL (des_menu), p->data);
g_object_unref (p->data);
}
g_list_free (children);
gtk_widget_destroy (GTK_WIDGET (src_menu));
/* free src_emp together with des_emp; name contains unique identifier */
name = g_strdup_printf ("emp_%p", src_emp);
g_object_set_data_full (G_OBJECT (des_emp), name, src_emp, emfv_free_em_popup);
g_free (name);
return des_menu;
}
static int
emfv_format_popup_event(EMFormatHTMLDisplay *efhd, GdkEventButton *event, const char *uri, CamelMimePart *part, EMFolderView *emfv)
{
GtkMenu *menu = NULL;
EMPopup *main_emp = NULL;
if (uri == NULL && part == NULL) {
/* So we don't try and popup with nothing selected - rather odd result! */
GPtrArray *uids = message_list_get_selected(emfv->list);
int doit = uids->len > 0;
message_list_free_uids(emfv->list, uids);
if (doit)
emfv_popup(emfv, (GdkEvent *)event, TRUE);
return doit;
}
/* FIXME: this maybe should just fit on em-html-display, it has access to the
snooped part type */
/** @HookPoint-EMPopup: Inline URI Context Menu
* @Id: org.gnome.evolution.mail.folderview.popup
* @Class: org.gnome.evolution.mail.popup:1.0
* @Target: EMPopupTargetURI
*
* This is the context menu shown when clicking on inline URIs,
* including addresses or normal HTML links that are displayed inside
* the message view.
*/
/** @HookPoint-EMPopup: Inline Object Context Menu
* @Id: org.gnome.evolution.mail.folderview.popup
* @Class: org.gnome.evolution.mail.popup:1.0
* @Target: EMPopupTargetPart
*
* This is the context menu shown when clicking on inline
* content such as a picture.
*/
if (uri) {
gboolean have_more_uris = strchr (uri, '\n') != NULL;
const char *act, *next;
for (act = uri; act; act = next) {
char *u;
next = strchr (act, '\n');
if (next) {
u = g_strndup (act, next - act);
next++;
} else
u = g_strdup (act);
if (u && *u) {
GSList *menus = NULL;
int i;
EMPopupTargetURI *t;
EMPopup *emp;
EPopupTarget *target;
GtkMenu *mymenu;
emp = em_popup_new ("org.gnome.evolution.mail.folderview.popup");
t = em_popup_target_new_uri(emp, u);
target = (EPopupTarget *)t;
for (i = 0; i < sizeof (emfv_uri_popups)/sizeof (emfv_uri_popups[0]); i++) {
EPopupItem *itm = g_malloc0 (sizeof (EPopupItem));
memcpy (itm, &emfv_uri_popups[i], sizeof (EPopupItem));
itm->user_data = g_strdup (t->uri);
menus = g_slist_prepend (menus, itm);
}
e_popup_add_items ((EPopup *)emp, menus, NULL, emfv_uri_popup_free, emfv);
mymenu = e_popup_create_menu_once ((EPopup *)emp, target, 0);
if (have_more_uris) {
GtkWidget *item;
if (strlen (u) > 100) {
GString *str;
char *c;
/* the url should be in the form of http://a.b.c/... and we want to
see where the image comes from, so skip first 10 characters and
find the first '/' there */
c = strchr (u + 10, '/');
if (!c)
str = g_string_new_len (u, 40);
else
str = g_string_new_len (u, MAX (c - u + 1, 40));
g_string_append (str, "...");
g_string_append (str, u + strlen (u) - 40);
item = gtk_menu_item_new_with_label (str->str);
g_string_free (str, TRUE);
} else
item = gtk_menu_item_new_with_label (u);
gtk_widget_set_sensitive (item, FALSE);
gtk_widget_show (item);
gtk_menu_shell_insert (GTK_MENU_SHELL (mymenu), item, 0);
}
menu = emfv_append_menu (main_emp, menu, emp, mymenu);
if (!main_emp)
main_emp = emp;
}
g_free (u);
}
}
if (part) {
EMPopup *emp;
EPopupTarget *target;
emp = em_popup_new ("org.gnome.evolution.mail.folderview.popup");
target = (EPopupTarget *)em_popup_target_new_part(emp, part, NULL);
menu = emfv_append_menu (main_emp, menu, emp, e_popup_create_menu_once ((EPopup *)emp, target, 0));
if (!main_emp)
main_emp = emp;
}
if (event == NULL)
gtk_menu_popup (menu, NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
else
gtk_menu_popup (menu, NULL, NULL, NULL, NULL, event->button, event->time);
return TRUE;
}
static void
emfv_set_seen(EMFolderView *emfv, const char *uid)
{
guint32 old_flags = camel_folder_get_message_flags(emfv->folder, uid);
/* If we're setting the SEEN flag on a message, handle receipt requests */
if (!(old_flags & CAMEL_MESSAGE_SEEN))
em_utils_handle_receipt(emfv->folder, uid, (CamelMimeMessage *)((EMFormat *)emfv->preview)->message);
camel_folder_set_message_flags(emfv->folder, uid, CAMEL_MESSAGE_SEEN, CAMEL_MESSAGE_SEEN);
}
/* keep these two tables in sync */
enum {
EMFV_ANIMATE_IMAGES = 1,
EMFV_CHARSET,
EMFV_CITATION_COLOUR,
EMFV_CITATION_MARK,
EMFV_CARET_MODE,
EMFV_MESSAGE_STYLE,
EMFV_MARK_SEEN,
EMFV_MARK_SEEN_TIMEOUT,
EMFV_LOAD_HTTP,
EMFV_HEADERS,
EMFV_SHOW_PREVIEW,
EMFV_SHOW_DELETED,
EMFV_THREAD_LIST,
EMFV_PANED_SIZE,
EMFV_SENDER_PHOTO,
EMFV_PHOTO_LOCAL,
EMFV_SETTINGS /* last, for loop count */
};
/* IF these get too long, update key field */
static const char * const emfv_display_keys[] = {
"animate_images",
"charset",
"citation_colour",
"mark_citations",
"caret_mode",
"message_style",
"mark_seen",
"mark_seen_timeout",
"load_http_images",
"headers",
"show_preview",
"show_deleted",
"thread_list",
"paned_size",
"sender_photo",
"photo_local",
};
static GHashTable *emfv_setting_key;
static void
emfv_setting_notify(GConfClient *gconf, guint cnxn_id, GConfEntry *entry, EMFolderView *emfv)
{
#if 0 /* KILL-BONOBO */
GConfValue *value;
char *tkey;
g_return_if_fail (gconf_entry_get_key (entry) != NULL);
if (!(value = gconf_entry_get_value (entry)))
return;
tkey = strrchr(entry->key, '/');
g_return_if_fail (tkey != NULL);
switch(GPOINTER_TO_INT(g_hash_table_lookup(emfv_setting_key, tkey+1))) {
case EMFV_ANIMATE_IMAGES:
em_format_html_display_set_animate(emfv->preview, gconf_value_get_bool (value));
break;
case EMFV_CHARSET:
em_format_set_default_charset((EMFormat *)emfv->preview, gconf_value_get_string (value));
break;
case EMFV_CITATION_COLOUR: {
const char *s;
GdkColor colour;
guint32 rgb;
s = gconf_value_get_string (value);
gdk_color_parse(s?s:"#737373", &colour);
rgb = ((colour.red & 0xff00) << 8) | (colour.green & 0xff00) | ((colour.blue & 0xff00) >> 8);
em_format_html_set_mark_citations((EMFormatHTML *)emfv->preview,
((EMFormatHTML *)emfv->preview)->mark_citations, rgb);
break; }
case EMFV_CITATION_MARK:
em_format_html_set_mark_citations((EMFormatHTML *)emfv->preview,
gconf_value_get_bool (value),
((EMFormatHTML *)emfv->preview)->citation_colour);
break;
case EMFV_CARET_MODE:
em_format_html_display_set_caret_mode(emfv->preview, gconf_value_get_bool (value));
break;
case EMFV_MESSAGE_STYLE:
if (EM_FOLDER_VIEW_GET_CLASS (emfv)->update_message_style) {
int style = gconf_value_get_int (value);
if (style < EM_FORMAT_NORMAL || style > EM_FORMAT_SOURCE)
style = EM_FORMAT_NORMAL;
em_format_set_mode((EMFormat *)emfv->preview, style);
}
break;
case EMFV_MARK_SEEN:
emfv->mark_seen = gconf_value_get_bool (value);
break;
case EMFV_MARK_SEEN_TIMEOUT:
emfv->mark_seen_timeout = gconf_value_get_int (value);
break;
case EMFV_LOAD_HTTP:
em_format_html_set_load_http((EMFormatHTML *)emfv->preview, gconf_value_get_int(value));
break;
case EMFV_HEADERS: {
GSList *header_config_list, *p;
EMFormat *emf = (EMFormat *)emfv->preview;
header_config_list = gconf_client_get_list(gconf, "/apps/evolution/mail/display/headers", GCONF_VALUE_STRING, NULL);
em_format_clear_headers((EMFormat *)emfv->preview);
p = header_config_list;
while (p) {
EMMailerPrefsHeader *h;
char *xml = (char *)p->data;
h = em_mailer_prefs_header_from_xml(xml);
if (h && h->enabled) {
em_format_add_header(emf, h->name, EM_FORMAT_HEADER_BOLD);
}
em_mailer_prefs_header_free(h);
p = g_slist_next(p);
}
g_slist_foreach(header_config_list, (GFunc) g_free, NULL);
g_slist_free(header_config_list);
/* force a redraw */
if (emf->message)
em_format_redraw(emf);
break; }
case EMFV_SENDER_PHOTO: {
EMFormat *emf = (EMFormat *)emfv->preview;
emf->show_photo = gconf_value_get_bool (value);
if (emf->message)
em_format_redraw(emf);
break; }
case EMFV_PHOTO_LOCAL: {
EMFormat *emf = (EMFormat *)emfv->preview;
emf->photo_local = gconf_value_get_bool (value);
break; }
case EMFV_SHOW_PREVIEW: {
gboolean state_gconf, state_camel;
char *ret;
/* If emfv->folder hasn't been initialized, do nothing */
if (!emfv->folder)
return;
state_gconf = gconf_value_get_bool (value);
if (state_gconf == FALSE)
emfv_enable_menus (emfv);
if ((ret = camel_object_meta_get (emfv->folder, "evolution:show_preview"))) {
state_camel = (ret[0] != '0');
g_free (ret);
if (state_gconf == state_camel)
return;
}
if (camel_object_meta_set (emfv->folder, "evolution:show_preview", state_gconf ? "1" : "0"))
camel_object_state_write (emfv->folder);
if (emfv->list_active)
em_folder_browser_show_preview ((EMFolderBrowser *)emfv, state_gconf);
bonobo_ui_component_set_prop (emfv->uic, "/commands/ViewPreview", "state", state_gconf ? "1" : "0", NULL);
break; }
case EMFV_SHOW_DELETED: {
gboolean state;
state = gconf_value_get_bool (value);
em_folder_view_set_hide_deleted (emfv, !state);
/* Set the prop only if the component has already been
* activated. */
if (emfv->uic)
bonobo_ui_component_set_prop (emfv->uic, "/commands/HideDeleted", "state", state ? "0" : "1", NULL);
break; }
case EMFV_THREAD_LIST: {
gboolean state_gconf, state_camel;
char *ret;
/* If emfv->folder or emfv->list hasn't been initialized, do nothing */
if (!emfv->folder || !emfv->list)
return;
state_gconf = gconf_value_get_bool (value);
if ((ret = camel_object_meta_get (emfv->folder, "evolution:thread_list"))) {
state_camel = (ret[0] != '0');
g_free (ret);
if (state_gconf == state_camel)
return;
}
if (camel_object_meta_set (emfv->folder, "evolution:thread_list", state_gconf ? "1" : "0"))
camel_object_state_write (emfv->folder);
message_list_set_threaded (emfv->list, state_gconf);
bonobo_ui_component_set_prop (emfv->uic, "/commands/ViewThreaded", "state", state_gconf ? "1" : "0", NULL);
break; }
case EMFV_PANED_SIZE: {
EMFolderBrowser *emfb = (EMFolderBrowser *)emfv;
int paned_size;
if (!emfv->list_active || !emfb->vpane || !emfv->preview_active)
return;
paned_size = gconf_value_get_int (value);
if (paned_size == gtk_paned_get_position (GTK_PANED (emfb->vpane)))
return;
gtk_paned_set_position (GTK_PANED (emfb->vpane), paned_size);
break; }
}
#endif
}
static void
emfv_setting_setup(EMFolderView *emfv)
{
GConfClient *gconf = gconf_client_get_default();
GConfEntry *entry;
GError *err = NULL;
int i;
char key[64];
if (emfv_setting_key == NULL) {
emfv_setting_key = g_hash_table_new(g_str_hash, g_str_equal);
for (i=1;i<EMFV_SETTINGS;i++)
g_hash_table_insert(emfv_setting_key, (void *)emfv_display_keys[i-1], GINT_TO_POINTER(i));
}
gconf_client_add_dir(gconf, "/apps/evolution/mail/display", GCONF_CLIENT_PRELOAD_NONE, NULL);
for (i=1;err == NULL && i<EMFV_SETTINGS;i++) {
sprintf(key, "/apps/evolution/mail/display/%s", emfv_display_keys[i-1]);
entry = gconf_client_get_entry(gconf, key, NULL, TRUE, &err);
if (entry) {
emfv_setting_notify(gconf, 0, entry, emfv);
gconf_entry_free(entry);
}
}
if (err) {
g_warning("Could not load display settings: %s", err->message);
g_error_free(err);
}
emfv->priv->setting_notify_id = gconf_client_notify_add(gconf, "/apps/evolution/mail/display",
(GConfClientNotifyFunc)emfv_setting_notify,
emfv, NULL, NULL);
g_object_unref(gconf);
}
static void
emfv_on_url (EMFolderView *emfv, const char *uri, const char *nice_uri)
{
if (emfv->statusbar_active) {
if (emfv->uic) {
bonobo_ui_component_set_status (emfv->uic, nice_uri, NULL);
/* Make sure the node keeps existing if nice_url == NULL */
if (!nice_uri)
bonobo_ui_component_set_translate (
emfv->uic, "/", "<status><item name=\"main\"/></status>", NULL);
}
}
}
static void
emfv_on_url_cb (GObject *emitter, const char *url, EMFolderView *emfv)
{
char *nice_url = NULL;
if (url) {
if (strncmp (url, "mailto:", 7) == 0) {
CamelInternetAddress *cia = camel_internet_address_new();
CamelURL *curl;
char *addr;
curl = camel_url_new(url, NULL);
camel_address_decode((CamelAddress *)cia, curl->path);
addr = camel_address_format((CamelAddress *)cia);
nice_url = g_strdup_printf (_("Click to mail %s"), addr&&addr[0]?addr:(url + 7));
g_free(addr);
camel_url_free(curl);
camel_object_unref(cia);
} else if (strncmp (url, "callto:", 7) == 0 || strncmp (url, "h323:", 5) == 0 || strncmp (url, "sip:", 4) == 0) {
CamelInternetAddress *cia = camel_internet_address_new();
CamelURL *curl;
char *addr;
curl = camel_url_new(url, NULL);
camel_address_decode((CamelAddress *)cia, curl->path);
addr = camel_address_format((CamelAddress *)cia);
nice_url = g_strdup_printf (_("Click to call %s"), addr&&addr[0]?addr:(url + 7));
g_free(addr);
camel_url_free(curl);
camel_object_unref(cia);
} else if (!strncmp (url, "##", 2)) {
nice_url = g_strdup (_("Click to hide/unhide addresses"));
} else
nice_url = g_strdup_printf (_("Click to open %s"), url);
}
g_signal_emit (emfv, signals[EMFV_ON_URL], 0, url, nice_url);
g_free (nice_url);
}
static gboolean
emfv_on_html_button_released_cb (GtkHTML *html, GdkEventButton *button, EMFolderView *emfv)
{
gboolean selected;
selected = gtk_html_command (html, "is-selection-active");
bonobo_ui_component_set_prop(emfv->uic, "/commands/EditCopy", "sensitive", selected?"1":"0", NULL);
return FALSE;
}