From 61ae36351b24cc676f60483d576706bf827f2987 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Tue, 17 Jan 2012 11:07:19 -0500 Subject: Introduce libemail-engine and libemail-utils. These libraries are bound for E-D-S so they live at the lowest layer of Evolution for now -- even libeutil can link to them (but please don't). This is the first step toward moving mail handing to a D-Bus service. --- Makefile.am | 2 + calendar/gui/dialogs/event-page.c | 36 +- calendar/gui/dialogs/memo-page.c | 19 +- calendar/gui/dialogs/task-page.c | 24 +- calendar/gui/e-cal-model.c | 10 +- calendar/gui/e-meeting-store.c | 6 +- calendar/gui/itip-utils.c | 19 +- capplet/anjal-settings-main.c | 2 +- capplet/settings/Makefile.am | 2 + capplet/settings/anjal-mail-view.c | 2 +- capplet/settings/mail-capplet-shell.c | 4 +- capplet/settings/mail-settings-view.c | 6 +- capplet/settings/mail-view.c | 2 +- composer/Makefile.am | 1 + composer/e-composer-header-table.h | 4 +- composer/e-msg-composer.c | 14 +- configure.ac | 4 + e-util/Makefile.am | 8 - e-util/e-account-utils.c | 252 -- e-util/e-account-utils.h | 37 - e-util/e-marshal.list | 3 - e-util/e-signature-list.c | 498 ---- e-util/e-signature-list.h | 91 - e-util/e-signature-utils.c | 336 --- e-util/e-signature-utils.h | 40 - e-util/e-signature.c | 746 ------ e-util/e-signature.h | 90 - evolution-mail.pc.in | 2 +- libemail-engine/Makefile.am | 71 + libemail-engine/e-mail-enums.h | 74 + libemail-engine/e-mail-folder-utils.c | 1666 ++++++++++++++ libemail-engine/e-mail-folder-utils.h | 164 ++ libemail-engine/e-mail-junk-filter.c | 82 + libemail-engine/e-mail-junk-filter.h | 74 + libemail-engine/e-mail-session-utils.c | 931 ++++++++ libemail-engine/e-mail-session-utils.h | 97 + libemail-engine/e-mail-session.c | 1969 ++++++++++++++++ libemail-engine/e-mail-session.h | 135 ++ libemail-engine/e-mail-store-utils.c | 385 ++++ libemail-engine/e-mail-store-utils.h | 74 + libemail-engine/e-mail-utils.c | 1062 +++++++++ libemail-engine/e-mail-utils.h | 56 + libemail-engine/libemail-engine.pc.in | 15 + libemail-engine/mail-config.c | 294 +++ libemail-engine/mail-config.h | 49 + libemail-engine/mail-folder-cache.c | 1841 +++++++++++++++ libemail-engine/mail-folder-cache.h | 156 ++ libemail-engine/mail-ops.c | 1691 ++++++++++++++ libemail-engine/mail-ops.h | 98 + libemail-engine/mail-tools.c | 244 ++ libemail-engine/mail-tools.h | 41 + libemail-utils/Makefile.am | 44 + libemail-utils/e-account-utils.c | 252 ++ libemail-utils/e-account-utils.h | 37 + libemail-utils/e-signature-list.c | 498 ++++ libemail-utils/e-signature-list.h | 91 + libemail-utils/e-signature-utils.c | 336 +++ libemail-utils/e-signature-utils.h | 40 + libemail-utils/e-signature.c | 746 ++++++ libemail-utils/e-signature.h | 90 + libemail-utils/libemail-utils.pc.in | 15 + libemail-utils/mail-mt.c | 639 ++++++ libemail-utils/mail-mt.h | 116 + mail/Makefile.am | 37 +- mail/e-mail-account-manager.c | 2 +- mail/e-mail-account-manager.h | 2 +- mail/e-mail-account-store.c | 39 +- mail/e-mail-backend.c | 193 +- mail/e-mail-backend.h | 2 +- mail/e-mail-enums.h | 74 - mail/e-mail-folder-pane.c | 6 +- mail/e-mail-folder-utils.c | 1666 -------------- mail/e-mail-folder-utils.h | 164 -- mail/e-mail-junk-filter.c | 82 - mail/e-mail-junk-filter.h | 74 - mail/e-mail-junk-options.c | 2 +- mail/e-mail-junk-options.h | 2 +- mail/e-mail-migrate.c | 21 +- mail/e-mail-notebook-view.c | 2 +- mail/e-mail-paned-view.c | 8 +- mail/e-mail-reader-utils.c | 8 +- mail/e-mail-reader.c | 11 +- mail/e-mail-session-utils.c | 930 -------- mail/e-mail-session-utils.h | 97 - mail/e-mail-session.c | 2413 -------------------- mail/e-mail-session.h | 150 -- mail/e-mail-sidebar.h | 2 +- mail/e-mail-store-utils.c | 385 ---- mail/e-mail-store-utils.h | 74 - mail/e-mail-ui-session.c | 904 ++++++++ mail/e-mail-ui-session.h | 93 + mail/e-mail.h | 4 - mail/em-account-editor.c | 42 +- mail/em-composer-utils.c | 33 +- mail/em-composer-utils.h | 2 +- mail/em-filter-context.h | 2 +- mail/em-filter-folder-element.h | 2 +- mail/em-filter-source-element.c | 2 +- mail/em-filter-source-element.h | 2 +- mail/em-folder-properties.c | 16 +- mail/em-folder-properties.h | 3 +- mail/em-folder-selection-button.c | 3 +- mail/em-folder-selection-button.h | 2 +- mail/em-folder-selector.c | 3 +- mail/em-folder-tree-model.c | 28 +- mail/em-folder-tree-model.h | 2 +- mail/em-folder-tree.c | 20 +- mail/em-folder-tree.h | 3 +- mail/em-folder-utils.c | 23 +- mail/em-folder-utils.h | 2 +- mail/em-format-html-print.c | 8 +- mail/em-format-html.c | 9 +- mail/em-format-html.h | 2 +- mail/em-subscription-editor.c | 8 +- mail/em-subscription-editor.h | 2 +- mail/em-sync-stream.c | 2 +- mail/em-utils.c | 1020 +-------- mail/em-utils.h | 29 +- mail/em-vfolder-context.h | 2 +- mail/em-vfolder-rule.c | 20 +- mail/em-vfolder-rule.h | 2 +- mail/importers/Makefile.am | 2 + mail/importers/elm-importer.c | 2 +- mail/importers/evolution-mbox-importer.c | 2 +- mail/importers/mail-importer.c | 10 +- mail/importers/mail-importer.h | 2 +- mail/importers/pine-importer.c | 2 +- mail/mail-autofilter.c | 5 +- mail/mail-autofilter.h | 2 +- mail/mail-config.c | 295 --- mail/mail-config.h | 49 - mail/mail-folder-cache.c | 1875 --------------- mail/mail-folder-cache.h | 144 -- mail/mail-mt.c | 646 ------ mail/mail-mt.h | 103 - mail/mail-ops.c | 1690 -------------- mail/mail-ops.h | 99 - mail/mail-send-recv.c | 26 +- mail/mail-send-recv.h | 2 +- mail/mail-tools.c | 245 -- mail/mail-tools.h | 41 - mail/mail-vfolder.c | 17 +- mail/message-list.c | 27 +- mail/message-list.h | 2 +- modules/bogofilter/Makefile.am | 2 + modules/bogofilter/evolution-bogofilter.c | 2 +- modules/calendar/Makefile.am | 1 + modules/calendar/e-cal-shell-view-private.h | 54 +- modules/calendar/e-memo-shell-migrate.c | 7 +- modules/mail/Makefile.am | 3 +- modules/mail/e-mail-shell-backend.c | 56 +- modules/mail/e-mail-shell-content.c | 32 +- modules/mail/e-mail-shell-view-actions.c | 14 +- modules/mail/e-mail-shell-view-private.c | 3 +- modules/mail/e-mail-shell-view-private.h | 69 +- modules/mail/e-mail-shell-view.c | 2 +- modules/mail/em-account-prefs.c | 25 +- modules/mail/em-composer-prefs.c | 21 +- modules/mail/em-network-prefs.c | 17 +- modules/mdn/evolution-mdn.c | 6 +- modules/online-accounts/Makefile.am | 1 + modules/online-accounts/camel-sasl-xoauth.c | 6 +- modules/online-accounts/e-online-accounts-google.c | 2 +- .../online-accounts/evolution-online-accounts.c | 3 +- modules/spamassassin/Makefile.am | 2 + modules/spamassassin/evolution-spamassassin.c | 2 +- modules/startup-wizard/Makefile.am | 2 + modules/startup-wizard/evolution-startup-wizard.c | 6 +- plugins/caldav/Makefile.am | 1 + plugins/caldav/caldav-browse-server.c | 3 +- plugins/dbx-import/Makefile.am | 2 + plugins/dbx-import/dbx-importer.c | 7 +- plugins/imap-features/imap-headers.c | 9 +- plugins/itip-formatter/Makefile.am | 2 + plugins/itip-formatter/itip-formatter.c | 29 +- plugins/mail-notification/Makefile.am | 1 + plugins/mail-notification/mail-notification.c | 2 +- plugins/mail-to-task/Makefile.am | 1 + plugins/mail-to-task/mail-to-task.c | 23 +- plugins/mailing-list-actions/Makefile.am | 2 + .../mailing-list-actions/mailing-list-actions.c | 39 +- plugins/mark-all-read/mark-all-read.c | 3 +- plugins/pst-import/pst-importer.c | 5 +- plugins/templates/Makefile.am | 1 + plugins/templates/templates.c | 16 +- po/POTFILES.in | 21 +- shell/Makefile.am | 2 + smime/lib/Makefile.am | 1 + widgets/misc/Makefile.am | 1 + widgets/misc/e-signature-combo-box.h | 4 +- widgets/misc/e-signature-editor.c | 2 +- widgets/misc/e-signature-editor.h | 2 +- widgets/misc/e-signature-manager.h | 2 +- widgets/misc/e-signature-preview.c | 3 +- widgets/misc/e-signature-preview.h | 2 +- widgets/misc/e-signature-tree-view.h | 4 +- widgets/table/Makefile.am | 1 + widgets/text/Makefile.am | 1 + 198 files changed, 16043 insertions(+), 14949 deletions(-) delete mode 100644 e-util/e-account-utils.c delete mode 100644 e-util/e-account-utils.h delete mode 100644 e-util/e-signature-list.c delete mode 100644 e-util/e-signature-list.h delete mode 100644 e-util/e-signature-utils.c delete mode 100644 e-util/e-signature-utils.h delete mode 100644 e-util/e-signature.c delete mode 100644 e-util/e-signature.h create mode 100644 libemail-engine/Makefile.am create mode 100644 libemail-engine/e-mail-enums.h create mode 100644 libemail-engine/e-mail-folder-utils.c create mode 100644 libemail-engine/e-mail-folder-utils.h create mode 100644 libemail-engine/e-mail-junk-filter.c create mode 100644 libemail-engine/e-mail-junk-filter.h create mode 100644 libemail-engine/e-mail-session-utils.c create mode 100644 libemail-engine/e-mail-session-utils.h create mode 100644 libemail-engine/e-mail-session.c create mode 100644 libemail-engine/e-mail-session.h create mode 100644 libemail-engine/e-mail-store-utils.c create mode 100644 libemail-engine/e-mail-store-utils.h create mode 100644 libemail-engine/e-mail-utils.c create mode 100644 libemail-engine/e-mail-utils.h create mode 100644 libemail-engine/libemail-engine.pc.in create mode 100644 libemail-engine/mail-config.c create mode 100644 libemail-engine/mail-config.h create mode 100644 libemail-engine/mail-folder-cache.c create mode 100644 libemail-engine/mail-folder-cache.h create mode 100644 libemail-engine/mail-ops.c create mode 100644 libemail-engine/mail-ops.h create mode 100644 libemail-engine/mail-tools.c create mode 100644 libemail-engine/mail-tools.h create mode 100644 libemail-utils/Makefile.am create mode 100644 libemail-utils/e-account-utils.c create mode 100644 libemail-utils/e-account-utils.h create mode 100644 libemail-utils/e-signature-list.c create mode 100644 libemail-utils/e-signature-list.h create mode 100644 libemail-utils/e-signature-utils.c create mode 100644 libemail-utils/e-signature-utils.h create mode 100644 libemail-utils/e-signature.c create mode 100644 libemail-utils/e-signature.h create mode 100644 libemail-utils/libemail-utils.pc.in create mode 100644 libemail-utils/mail-mt.c create mode 100644 libemail-utils/mail-mt.h delete mode 100644 mail/e-mail-enums.h delete mode 100644 mail/e-mail-folder-utils.c delete mode 100644 mail/e-mail-folder-utils.h delete mode 100644 mail/e-mail-junk-filter.c delete mode 100644 mail/e-mail-junk-filter.h delete mode 100644 mail/e-mail-session-utils.c delete mode 100644 mail/e-mail-session-utils.h delete mode 100644 mail/e-mail-session.c delete mode 100644 mail/e-mail-session.h delete mode 100644 mail/e-mail-store-utils.c delete mode 100644 mail/e-mail-store-utils.h create mode 100644 mail/e-mail-ui-session.c create mode 100644 mail/e-mail-ui-session.h delete mode 100644 mail/mail-config.c delete mode 100644 mail/mail-config.h delete mode 100644 mail/mail-folder-cache.c delete mode 100644 mail/mail-folder-cache.h delete mode 100644 mail/mail-mt.c delete mode 100644 mail/mail-mt.h delete mode 100644 mail/mail-ops.c delete mode 100644 mail/mail-ops.h delete mode 100644 mail/mail-tools.c delete mode 100644 mail/mail-tools.h diff --git a/Makefile.am b/Makefile.am index a5e0d9f767..d1f0d19a46 100644 --- a/Makefile.am +++ b/Makefile.am @@ -53,6 +53,8 @@ SUBDIRS = \ data \ smclient \ libgnomecanvas \ + libemail-utils \ + libemail-engine \ e-util \ a11y \ filter \ diff --git a/calendar/gui/dialogs/event-page.c b/calendar/gui/dialogs/event-page.c index c8c208e1b3..a5c0ac6355 100644 --- a/calendar/gui/dialogs/event-page.c +++ b/calendar/gui/dialogs/event-page.c @@ -34,31 +34,35 @@ #include #include #include + +#include #include #include #include -#include "misc/e-dateedit.h" -#include "misc/e-send-options.h" -#include "misc/e-buffer-tagger.h" -#include -#include "../e-timezone-entry.h" -#include "e-util/e-util.h" -#include "e-util/e-account-utils.h" -#include "e-util/e-categories-config.h" -#include "e-util/e-dialog-utils.h" -#include "e-util/e-dialog-widgets.h" -#include "e-util/e-util-private.h" +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "../e-alarm-list.h" #include "../e-meeting-attendee.h" -#include "../e-meeting-store.h" #include "../e-meeting-list-view.h" -#include "comp-editor.h" -#include "comp-editor-util.h" -#include "../e-alarm-list.h" +#include "../e-meeting-store.h" +#include "../e-timezone-entry.h" + #include "alarm-list-dialog.h" -#include "event-page.h" +#include "comp-editor-util.h" +#include "comp-editor.h" #include "e-send-options-utils.h" +#include "event-page.h" #define EVENT_PAGE_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE \ diff --git a/calendar/gui/dialogs/memo-page.c b/calendar/gui/dialogs/memo-page.c index 9bee45c062..bf60445001 100644 --- a/calendar/gui/dialogs/memo-page.c +++ b/calendar/gui/dialogs/memo-page.c @@ -33,20 +33,23 @@ #include #include #include + #include #include #include #include #include #include -#include -#include "misc/e-buffer-tagger.h" - -#include "e-util/e-util.h" -#include "e-util/e-account-utils.h" -#include "e-util/e-categories-config.h" -#include "e-util/e-dialog-utils.h" -#include "e-util/e-util-private.h" + +#include +#include +#include +#include + +#include +#include + +#include #include "../calendar-config.h" #include "comp-editor.h" diff --git a/calendar/gui/dialogs/task-page.c b/calendar/gui/dialogs/task-page.c index 08cb6f45ea..2033a46ff2 100644 --- a/calendar/gui/dialogs/task-page.c +++ b/calendar/gui/dialogs/task-page.c @@ -33,27 +33,31 @@ #include #include #include + #include #include #include + #include -#include "misc/e-buffer-tagger.h" +#include + +#include #include +#include +#include + +#include + +#include "../e-meeting-attendee.h" +#include "../e-meeting-list-view.h" +#include "../e-meeting-store.h" #include "../e-timezone-entry.h" + #include "comp-editor.h" #include "comp-editor-util.h" #include "e-send-options-utils.h" #include "task-page.h" -#include "e-util/e-util.h" -#include "e-util/e-account-utils.h" -#include "e-util/e-categories-config.h" -#include "e-util/e-util-private.h" - -#include "../e-meeting-attendee.h" -#include "../e-meeting-store.h" -#include "../e-meeting-list-view.h" - #define TASK_PAGE_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE \ ((obj), TYPE_TASK_PAGE, TaskPagePrivate)) diff --git a/calendar/gui/e-cal-model.c b/calendar/gui/e-cal-model.c index c1ff096208..7344e87916 100644 --- a/calendar/gui/e-cal-model.c +++ b/calendar/gui/e-cal-model.c @@ -28,18 +28,22 @@ #include #include + #include #include #include #include #include + +#include +#include + +#include + #include "comp-util.h" #include "e-cal-model.h" #include "itip-utils.h" #include "misc.h" -#include "e-util/e-util.h" -#include "e-util/e-account-utils.h" -#include "e-util/e-util-enumtypes.h" struct _ECalModelComponentPrivate { GString *categories_str; diff --git a/calendar/gui/e-meeting-store.c b/calendar/gui/e-meeting-store.c index 833c6a821e..e11d90e7bb 100644 --- a/calendar/gui/e-meeting-store.c +++ b/calendar/gui/e-meeting-store.c @@ -28,6 +28,7 @@ #include #include #include + #include #include #include @@ -35,8 +36,11 @@ #include #include #include -#include + #include + +#include + #include "itip-utils.h" #include "e-meeting-utils.h" #include "e-meeting-attendee.h" diff --git a/calendar/gui/itip-utils.c b/calendar/gui/itip-utils.c index 4b2a8d262d..e58f2f9c7e 100644 --- a/calendar/gui/itip-utils.c +++ b/calendar/gui/itip-utils.c @@ -24,21 +24,24 @@ #include #endif +#include #include -#include -#include #include -#include -#include +#include + #include #include -#include -#include "itip-utils.h" -#include -#include "dialogs/comp-editor-util.h" +#include + +#include + +#include #include +#include "itip-utils.h" +#include "dialogs/comp-editor-util.h" + #define d(x) static const gchar *itip_methods[] = { diff --git a/capplet/anjal-settings-main.c b/capplet/anjal-settings-main.c index 7efddcffbf..c04722e42f 100644 --- a/capplet/anjal-settings-main.c +++ b/capplet/anjal-settings-main.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include "settings/mail-capplet-shell.h" #include diff --git a/capplet/settings/Makefile.am b/capplet/settings/Makefile.am index 1367fd5a75..db899e0f6c 100644 --- a/capplet/settings/Makefile.am +++ b/capplet/settings/Makefile.am @@ -59,6 +59,8 @@ libevolution_mail_settings_la_LIBADD = \ $(top_builddir)/filter/libfilter.la \ $(top_builddir)/mail/libevolution-mail.la \ $(top_builddir)/shell/libeshell.la \ + $(top_builddir)/libemail-utils/libemail-utils.la \ + $(top_builddir)/libemail-engine/libemail-engine.la \ $(top_builddir)/e-util/libeutil.la libevolution_mail_settings_la_LDFLAGS = $(NO_UNDEFINED) diff --git a/capplet/settings/anjal-mail-view.c b/capplet/settings/anjal-mail-view.c index c0926536cb..232b8ff118 100644 --- a/capplet/settings/anjal-mail-view.c +++ b/capplet/settings/anjal-mail-view.c @@ -28,7 +28,7 @@ #include #include "mail/em-utils.h" #include "mail/mail-send-recv.h" -#include "mail/mail-ops.h" +#include "libemail-engine/mail-ops.h" #include "mail/em-folder-tree.h" struct _AnjalMailViewPrivate { diff --git a/capplet/settings/mail-capplet-shell.c b/capplet/settings/mail-capplet-shell.c index 707efe3f35..3d3e015e94 100644 --- a/capplet/settings/mail-capplet-shell.c +++ b/capplet/settings/mail-capplet-shell.c @@ -38,8 +38,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/capplet/settings/mail-settings-view.c b/capplet/settings/mail-settings-view.c index a699dca9ea..992f705826 100644 --- a/capplet/settings/mail-settings-view.c +++ b/capplet/settings/mail-settings-view.c @@ -25,10 +25,12 @@ #endif #include -#include "mail-settings-view.h" #include + +#include + +#include "mail-settings-view.h" #include "mail-view.h" -#include struct _MailSettingsViewPrivate { GtkWidget *tab_str; diff --git a/capplet/settings/mail-view.c b/capplet/settings/mail-view.c index 53daf3fd08..4477be517a 100644 --- a/capplet/settings/mail-view.c +++ b/capplet/settings/mail-view.c @@ -27,7 +27,7 @@ #include #include "mail/em-utils.h" #include "mail/mail-send-recv.h" -#include "mail/mail-ops.h" +#include "libemail-engine/mail-ops.h" #include "mail-view.h" #ifndef ANJAL_SETTINGS #include "mail-folder-view.h" diff --git a/composer/Makefile.am b/composer/Makefile.am index 013d04c8bd..cee00a002b 100644 --- a/composer/Makefile.am +++ b/composer/Makefile.am @@ -63,6 +63,7 @@ libcomposer_la_LIBADD = \ $(top_builddir)/em-format/libemformat.la \ $(top_builddir)/addressbook/gui/contact-editor/libecontacteditor.la \ $(top_builddir)/addressbook/gui/contact-list-editor/libecontactlisteditor.la \ + $(top_builddir)/libemail-utils/libemail-utils.la \ $(EVOLUTION_DATA_SERVER_LIBS) \ $(GNOME_PLATFORM_LIBS) \ $(GTKHTML_LIBS) diff --git a/composer/e-composer-header-table.h b/composer/e-composer-header-table.h index f7edec0b14..9d6a83fb9a 100644 --- a/composer/e-composer-header-table.h +++ b/composer/e-composer-header-table.h @@ -23,9 +23,9 @@ #include #include -#include -#include #include +#include +#include /* Standard GObject macros */ #define E_TYPE_COMPOSER_HEADER_TABLE \ diff --git a/composer/e-msg-composer.c b/composer/e-msg-composer.c index a7250a7d7d..6a48950912 100644 --- a/composer/e-msg-composer.c +++ b/composer/e-msg-composer.c @@ -37,13 +37,13 @@ #include #include -#include "e-util/e-account-utils.h" -#include "e-util/e-alert-dialog.h" -#include "e-util/e-dialog-utils.h" -#include "e-util/e-signature-utils.h" -#include "e-util/e-util-private.h" -#include "em-format/em-format.h" -#include "em-format/em-format-quote.h" +#include +#include +#include +#include +#include +#include +#include #include "e-composer-private.h" diff --git a/configure.ac b/configure.ac index 8d5fbb4417..102244810a 100644 --- a/configure.ac +++ b/configure.ac @@ -1618,6 +1618,10 @@ help/quickref/pl/Makefile help/quickref/pt/Makefile help/quickref/sv/Makefile help/quickref/sq/Makefile +libemail-utils/Makefile +libemail-utils/libemail-utils.pc +libemail-engine/Makefile +libemail-engine/libemail-engine.pc libgnomecanvas/Makefile shell/Makefile shell/evolution-nognome diff --git a/e-util/Makefile.am b/e-util/Makefile.am index 8ef95f1841..41a99316ef 100644 --- a/e-util/Makefile.am +++ b/e-util/Makefile.am @@ -18,7 +18,6 @@ endif privsolib_LTLIBRARIES = libeutil.la eutilinclude_HEADERS = \ - e-account-utils.h \ e-activity.h \ e-alert.h \ e-alert-dialog.h \ @@ -43,9 +42,6 @@ eutilinclude_HEADERS = \ e-plugin-ui.h \ e-plugin-util.h \ e-selection.h \ - e-signature.h \ - e-signature-list.h \ - e-signature-utils.h \ e-sorter.h \ e-sorter-array.h \ e-text-event-processor-emacs-like.h \ @@ -89,7 +85,6 @@ libeutil_la_CPPFLAGS = \ libeutil_la_SOURCES = \ $(eutilinclude_HEADERS) \ - e-account-utils.c \ e-activity.c \ e-alert.c \ e-alert-dialog.c \ @@ -114,9 +109,6 @@ libeutil_la_SOURCES = \ e-plugin-util.c \ e-print.c \ e-selection.c \ - e-signature.c \ - e-signature-list.c \ - e-signature-utils.c \ e-sorter.c \ e-sorter-array.c \ e-text-event-processor-emacs-like.c \ diff --git a/e-util/e-account-utils.c b/e-util/e-account-utils.c deleted file mode 100644 index 6e64d45747..0000000000 --- a/e-util/e-account-utils.c +++ /dev/null @@ -1,252 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - */ - -/** - * SECTION: e-account-utils - * @include: e-util/e-account-utils.h - **/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "e-account-utils.h" - -#include -#include - -static EAccountList *global_account_list; - -static gboolean -account_has_transport_url (EAccount *account) -{ - return (account != NULL) && - (account->enabled) && - (account->transport != NULL) && - (account->transport->url != NULL) && - (account->transport->url[0] != '\0'); -} - -/** - * e_get_account_list: - * - * Returns the global #EAccountList. - * - * Returns: the global #EAccountList - **/ -EAccountList * -e_get_account_list (void) -{ - if (G_UNLIKELY (global_account_list == NULL)) { - GConfClient *client; - - client = gconf_client_get_default (); - global_account_list = e_account_list_new (client); - g_object_unref (client); - } - - g_return_val_if_fail (global_account_list != NULL, NULL); - - return global_account_list; -} - -/** - * e_get_default_account: - * - * Returns the #EAccount marked as the default mail account. - * - * Returns: the default #EAccount - **/ -EAccount * -e_get_default_account (void) -{ - EAccountList *account_list; - const EAccount *account; - - account_list = e_get_account_list (); - account = e_account_list_get_default (account_list); - - /* XXX EAccountList misuses const. */ - return (EAccount *) account; -} - -/** - * e_set_default_account: - * @account: an #EAccount - * - * Marks @account as the default mail account. - **/ -void -e_set_default_account (EAccount *account) -{ - EAccountList *account_list; - - g_return_if_fail (E_IS_ACCOUNT (account)); - - account_list = e_get_account_list (); - e_account_list_set_default (account_list, account); -} - -/** - * e_get_account_by_name: - * @name: a mail account name - * - * Returns the #EAccount with the given name, or %NULL if no such - * account exists. - * - * Returns: an #EAccount having the given account name, or %NULL - **/ -EAccount * -e_get_account_by_name (const gchar *name) -{ - EAccountList *account_list; - const EAccount *account; - e_account_find_t find; - - g_return_val_if_fail (name != NULL, NULL); - - find = E_ACCOUNT_FIND_NAME; - account_list = e_get_account_list (); - account = e_account_list_find (account_list, find, name); - - /* XXX EAccountList misuses const. */ - return (EAccount *) account; -} - -/** - * e_get_account_by_uid: - * @uid: a mail account UID - * - * Returns the #EAccount corresponding to the given unique identity (UID), - * or %NULL if no such account exists. The @uid can refer to an #EAccount - * UID, a #CamelStore UID, or even a #CamelTransport UID. - * - * Returns: the corresponding #EAccount, or %NULL - **/ -EAccount * -e_get_account_by_uid (const gchar *uid) -{ - EAccountList *account_list; - const EAccount *account; - e_account_find_t find; - gchar *account_uid; - - g_return_val_if_fail (uid != NULL, NULL); - - /* EAccounts have the following invariant: - * - * CamelStore UID == EAccount UID - * CamelTransport UID == EAccount UID + "-transport" - * - * Therefore we can detect CamelTransport UIDs and convert them. - */ - if (g_str_has_suffix (uid, "-transport")) - account_uid = g_strndup (uid, strlen (uid) - 10); - else - account_uid = g_strdup (uid); - - find = E_ACCOUNT_FIND_UID; - account_list = e_get_account_list (); - account = e_account_list_find (account_list, find, account_uid); - - g_free (account_uid); - - /* XXX EAccountList misuses const. */ - return (EAccount *) account; -} - -/** - * e_get_any_enabled_account: - * - * Returns the default mail account if it's enabled, otherwise the first - * enabled mail account in the global #EAccountList, or finally %NULL if - * all mail accounts are disabled or none exist. - * - * Returns: an enabled #EAccount, or %NULL if there are none - **/ -EAccount * -e_get_any_enabled_account (void) -{ - EAccount *account; - EAccountList *account_list; - EIterator *iter; - - account = e_get_default_account (); - if (account != NULL && account->enabled) - return account; - - account = NULL; - - account_list = e_get_account_list (); - iter = e_list_get_iterator (E_LIST (account_list)); - - while (e_iterator_is_valid (iter) && account == NULL) { - EAccount *candidate; - - /* XXX EIterator misuses const. */ - candidate = (EAccount *) e_iterator_get (iter); - - if (candidate->enabled) - account = candidate; - else - e_iterator_next (iter); - } - - g_object_unref (iter); - - return account; -} - -/** - * e_get_default_transport: - * - * Returns transport information for the default account if it's enabled and - * has transport information, or else from the first enabled mail account in - * the global #EAccountList that has transport information, or finally %NULL - * if no transport information could be found. - * - * Returns: an #EAccount with transport info, or %NULL - **/ -EAccount * -e_get_default_transport (void) -{ - EAccountList *account_list; - EAccount *account; - EIterator *iterator; - - account = e_get_default_account (); - if (account_has_transport_url (account)) - return account; - - account_list = e_get_account_list (); - iterator = e_list_get_iterator (E_LIST (account_list)); - - while (e_iterator_is_valid (iterator)) { - /* XXX EIterator misuses const. */ - account = (EAccount *) e_iterator_get (iterator); - if (account_has_transport_url (account)) { - g_object_unref (iterator); - return account; - } - e_iterator_next (iterator); - } - - g_object_unref (iterator); - - return NULL; -} - diff --git a/e-util/e-account-utils.h b/e-util/e-account-utils.h deleted file mode 100644 index d7dbd283fd..0000000000 --- a/e-util/e-account-utils.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - */ - -#ifndef E_ACCOUNT_UTILS_H -#define E_ACCOUNT_UTILS_H - -#include -#include -#include - -G_BEGIN_DECLS - -EAccountList * e_get_account_list (void); -EAccount * e_get_default_account (void); -void e_set_default_account (EAccount *account); -EAccount * e_get_account_by_name (const gchar *name); -EAccount * e_get_account_by_uid (const gchar *uid); -EAccount * e_get_any_enabled_account (void); -EAccount * e_get_default_transport (void); - -G_END_DECLS - -#endif /* E_ACCOUNT_UTILS_H */ diff --git a/e-util/e-marshal.list b/e-util/e-marshal.list index 6d3c1fcdb0..bf15633ab8 100644 --- a/e-util/e-marshal.list +++ b/e-util/e-marshal.list @@ -42,9 +42,6 @@ NONE:OBJECT,BOOLEAN NONE:OBJECT,DOUBLE,DOUBLE,BOOLEAN NONE:OBJECT,OBJECT NONE:OBJECT,STRING -NONE:OBJECT,STRING,INT -NONE:OBJECT,STRING,INT,STRING,STRING,STRING -NONE:OBJECT,STRING,STRING NONE:OBJECT,STRING,UINT NONE:POINTER,INT NONE:POINTER,INT,INT,INT,INT diff --git a/e-util/e-signature-list.c b/e-util/e-signature-list.c deleted file mode 100644 index afc1d9eefd..0000000000 --- a/e-util/e-signature-list.c +++ /dev/null @@ -1,498 +0,0 @@ -/* - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see - * - * - * Authors: - * Jeffrey Stedfast - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "e-signature-list.h" - -#include - -#include - -struct _ESignatureListPrivate { - GConfClient *gconf; - guint notify_id; - gboolean resave; -}; - -enum { - SIGNATURE_ADDED, - SIGNATURE_CHANGED, - SIGNATURE_REMOVED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -G_DEFINE_TYPE ( - ESignatureList, - e_signature_list, - E_TYPE_LIST) - -static void -e_signature_list_dispose (GObject *object) -{ - ESignatureList *list = (ESignatureList *) object; - - if (list->priv->gconf) { - if (list->priv->notify_id != 0) - gconf_client_notify_remove ( - list->priv->gconf, list->priv->notify_id); - g_object_unref (list->priv->gconf); - list->priv->gconf = NULL; - } - - /* Chain up to parent's dispose() method. */ - G_OBJECT_CLASS (e_signature_list_parent_class)->dispose (object); -} - -static void -e_signature_list_class_init (ESignatureListClass *class) -{ - GObjectClass *object_class; - - g_type_class_add_private (class, sizeof (ESignatureListPrivate)); - - object_class = G_OBJECT_CLASS (class); - object_class->dispose = e_signature_list_dispose; - - signals[SIGNATURE_ADDED] = g_signal_new ( - "signature-added", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (ESignatureListClass, signature_added), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, - E_TYPE_SIGNATURE); - - signals[SIGNATURE_CHANGED] = g_signal_new ( - "signature-changed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (ESignatureListClass, signature_changed), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, - E_TYPE_SIGNATURE); - - signals[SIGNATURE_REMOVED] = g_signal_new ( - "signature-removed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (ESignatureListClass, signature_removed), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, - E_TYPE_SIGNATURE); -} - -static void -e_signature_list_init (ESignatureList *signature_list) -{ - signature_list->priv = G_TYPE_INSTANCE_GET_PRIVATE ( - signature_list, E_TYPE_SIGNATURE_LIST, ESignatureListPrivate); -} - -static GSList * -add_autogen (ESignatureList *list, - GSList *new_sigs) -{ - ESignature *autogen; - - autogen = e_signature_new (); - e_signature_set_autogenerated (autogen, TRUE); - - e_list_append (E_LIST (list), autogen); - - return g_slist_prepend (new_sigs, autogen); -} - -static void -gconf_signatures_changed (GConfClient *client, - guint cnxn_id, - GConfEntry *entry, - gpointer user_data) -{ - ESignatureList *signature_list = user_data; - GSList *list, *l, *n, *new_sigs = NULL; - gboolean have_autogen = FALSE; - gboolean resave = FALSE; - ESignature *signature; - EList *old_sigs; - EIterator *iter; - gboolean found; - gchar *uid; - - old_sigs = e_list_duplicate (E_LIST (signature_list)); - - list = gconf_client_get_list ( - client, "/apps/evolution/mail/signatures", - GCONF_VALUE_STRING, NULL); - for (l = list; l; l = l->next) { - found = FALSE; - if ((uid = e_signature_uid_from_xml (l->data))) { - /* See if this is an existing signature */ - iter = e_list_get_iterator (old_sigs); - while (e_iterator_is_valid (iter)) { - const gchar *signature_uid; - - signature = (ESignature *) e_iterator_get (iter); - signature_uid = e_signature_get_uid (signature); - if (!strcmp (signature_uid, uid)) { - /* The signature still exists, so remove - * it from "old_sigs" and update it. */ - found = TRUE; - e_iterator_delete (iter); - if (e_signature_set_from_xml ( - signature, l->data)) - g_signal_emit ( - signature_list, - signals[SIGNATURE_CHANGED], - 0, signature); - - have_autogen |= - e_signature_get_autogenerated ( - signature); - - break; - } - - e_iterator_next (iter); - } - - g_object_unref (iter); - } - - if (!found) { - resave = TRUE; - - /* Must be a new signature */ - signature = e_signature_new_from_xml (l->data); - if (signature) { - have_autogen |= - e_signature_get_autogenerated (signature); - - e_list_append (E_LIST (signature_list), signature); - new_sigs = g_slist_prepend (new_sigs, signature); - } - } - - g_free (uid); - } - - g_slist_foreach (list, (GFunc) g_free, NULL); - g_slist_free (list); - - if (!have_autogen) { - new_sigs = add_autogen (signature_list, new_sigs); - resave = TRUE; - } - - if (new_sigs != NULL) { - /* Now emit signals for each added signature. */ - l = g_slist_reverse (new_sigs); - while (l != NULL) { - n = l->next; - signature = l->data; - g_signal_emit ( - signature_list, - signals[SIGNATURE_ADDED], 0, - signature); - g_object_unref (signature); - g_slist_free_1 (l); - l = n; - } - } - - /* Anything left in old_sigs must have been deleted */ - iter = e_list_get_iterator (old_sigs); - while (e_iterator_is_valid (iter)) { - signature = (ESignature *) e_iterator_get (iter); - e_list_remove (E_LIST (signature_list), signature); - g_signal_emit ( - signature_list, signals[SIGNATURE_REMOVED], 0, - signature); - e_iterator_next (iter); - } - - g_object_unref (iter); - g_object_unref (old_sigs); - - signature_list->priv->resave = resave; -} - -static gpointer -copy_func (gconstpointer data, - gpointer closure) -{ - GObject *object = (GObject *) data; - - g_object_ref (object); - - return object; -} - -static void -free_func (gpointer data, - gpointer closure) -{ - g_object_unref (data); -} - -/** - * e_signature_list_new: - * - * Reads the list of signaturess from @gconf and listens for changes. - * Will emit #signature_added, #signature_changed, and #signature_removed - * signals according to notifications from GConf. - * - * You can modify the list using e_list_append(), e_list_remove(), and - * e_iterator_delete(). After adding, removing, or changing accounts, - * you must call e_signature_list_save() to push the changes back to - * GConf. - * - * Return value: the list of signatures - **/ -ESignatureList * -e_signature_list_new (void) -{ - ESignatureList *signature_list; - GConfClient *client; - - signature_list = g_object_new (E_TYPE_SIGNATURE_LIST, NULL); - - client = gconf_client_get_default (); - e_signature_list_construct (signature_list, client); - g_object_unref (client); - - return signature_list; -} - -void -e_signature_list_construct (ESignatureList *signature_list, - GConfClient *gconf) -{ - g_return_if_fail (GCONF_IS_CLIENT (gconf)); - - e_list_construct (E_LIST (signature_list), copy_func, free_func, NULL); - signature_list->priv->gconf = gconf; - g_object_ref (gconf); - - gconf_client_add_dir (signature_list->priv->gconf, - "/apps/evolution/mail/signatures", - GCONF_CLIENT_PRELOAD_ONELEVEL, NULL); - - signature_list->priv->notify_id = - gconf_client_notify_add (signature_list->priv->gconf, - "/apps/evolution/mail/signatures", - gconf_signatures_changed, signature_list, - NULL, NULL); - - gconf_signatures_changed (signature_list->priv->gconf, - signature_list->priv->notify_id, - NULL, signature_list); - - if (signature_list->priv->resave) { - e_signature_list_save (signature_list); - signature_list->priv->resave = FALSE; - } -} - -/** - * e_signature_list_save: - * @signature_list: an #ESignatureList - * - * Saves @signature_list to GConf. Signals will be emitted for changes. - **/ -void -e_signature_list_save (ESignatureList *signature_list) -{ - GSList *list = NULL; - ESignature *signature; - EIterator *iter; - gchar *xmlbuf; - - for (iter = e_list_get_iterator (E_LIST (signature_list)); - e_iterator_is_valid (iter); - e_iterator_next (iter)) { - signature = (ESignature *) e_iterator_get (iter); - - if ((xmlbuf = e_signature_to_xml (signature))) - list = g_slist_append (list, xmlbuf); - } - - g_object_unref (iter); - - gconf_client_set_list (signature_list->priv->gconf, - "/apps/evolution/mail/signatures", - GCONF_VALUE_STRING, list, NULL); - - while (list) { - g_free (list->data); - list = g_slist_remove (list, list->data); - } - - gconf_client_suggest_sync (signature_list->priv->gconf, NULL); -} - -/** - * e_signature_list_add: - * @signature_list: signature list - * @signature: signature to add - * - * Add an signature to the signature list. Will emit the signature-changed - * event. - **/ -void -e_signature_list_add (ESignatureList *signature_list, - ESignature *signature) -{ - e_list_append ((EList *) signature_list, signature); - g_signal_emit (signature_list, signals[SIGNATURE_ADDED], 0, signature); -} - -/** - * e_signature_list_change: - * @signature_list: signature list - * @signature: signature to change - * - * Signal that the details of an signature have changed. - **/ -void -e_signature_list_change (ESignatureList *signature_list, - ESignature *signature) -{ - /* maybe the signature should do this itself ... */ - g_signal_emit (signature_list, signals[SIGNATURE_CHANGED], 0, signature); -} - -/** - * e_signature_list_remove: - * @signature_list: signature list - * @signature: signature - * - * Remove an signature from the signature list, and emit the - * signature-removed signal. If the signature was the default signature, - * then reset the default to the first signature. - **/ -void -e_signature_list_remove (ESignatureList *signature_list, - ESignature *signature) -{ - /* not sure if need to ref but no harm */ - g_object_ref (signature); - e_list_remove ((EList *) signature_list, signature); - g_signal_emit (signature_list, signals[SIGNATURE_REMOVED], 0, signature); - g_object_unref (signature); -} - -/** - * e_signature_list_find_by_name: - * @signature_list: an #ESignatureList - * @name: the signature name to find - * - * Searches @signature_list for the given signature name. - * - * Returns: the matching signature or %NULL if it doesn't exist - **/ -ESignature * -e_signature_list_find_by_name (ESignatureList *signature_list, - const gchar *signature_name) -{ - ESignature *signature = NULL; - EIterator *it; - - g_return_val_if_fail (E_IS_SIGNATURE_LIST (signature_list), NULL); - - /* this could use a callback for more flexibility ... - * ... but this makes the common cases easier */ - - if (signature_name == NULL) - return NULL; - - for (it = e_list_get_iterator (E_LIST (signature_list)); - e_iterator_is_valid (it); - e_iterator_next (it)) { - const gchar *value; - - /* XXX EIterator misuses const. */ - signature = (ESignature *) e_iterator_get (it); - value = e_signature_get_name (signature); - - if (g_strcmp0 (value, signature_name) == 0) - break; - - signature = NULL; - } - - g_object_unref (it); - - return signature; -} - -/** - * e_signature_list_find_by_uid: - * @signature_list: an #ESignatureList - * @name: the signature UID to find - * - * Searches @signature_list for the given signature UID. - * - * Returns: the matching signature or %NULL if it doesn't exist - **/ -ESignature * -e_signature_list_find_by_uid (ESignatureList *signature_list, - const gchar *signature_uid) -{ - ESignature *signature = NULL; - EIterator *it; - - g_return_val_if_fail (E_IS_SIGNATURE_LIST (signature_list), NULL); - - /* this could use a callback for more flexibility ... - * ... but this makes the common cases easier */ - - if (signature_uid == NULL) - return NULL; - - for (it = e_list_get_iterator (E_LIST (signature_list)); - e_iterator_is_valid (it); - e_iterator_next (it)) { - const gchar *value = NULL; - - /* XXX EIterator misuses const. */ - signature = (ESignature *) e_iterator_get (it); - value = e_signature_get_uid (signature); - - if (g_strcmp0 (value, signature_uid) == 0) - break; - - signature = NULL; - } - - g_object_unref (it); - - return signature; -} diff --git a/e-util/e-signature-list.h b/e-util/e-signature-list.h deleted file mode 100644 index 866bc73b65..0000000000 --- a/e-util/e-signature-list.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see - * - * - * Authors: - * Jeffrey Stedfast - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef E_SIGNATURE_LIST_H -#define E_SIGNATURE_LIST_H - -#include -#include -#include - -/* Standard GObject macros */ -#define E_TYPE_SIGNATURE_LIST \ - (e_signature_list_get_type ()) -#define E_SIGNATURE_LIST(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST \ - ((obj), E_TYPE_SIGNATURE_LIST, ESignatureList)) -#define E_SIGNATURE_LIST_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_CAST \ - ((cls), E_TYPE_SIGNATURE_LIST, ESignatureListClass)) -#define E_IS_SIGNATURE_LIST(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE \ - ((obj), E_TYPE_SIGNATURE_LIST)) -#define E_IS_SIGNATURE_LIST_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_TYPE \ - ((cls), E_TYPE_SIGNATURE_LIST)) -#define E_SIGNATURE_LIST_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS \ - ((obj), E_TYPE_SIGNATURE_LIST, ESignatureListClass)) - -G_BEGIN_DECLS - -typedef struct _ESignatureList ESignatureList; -typedef struct _ESignatureListClass ESignatureListClass; -typedef struct _ESignatureListPrivate ESignatureListPrivate; - -struct _ESignatureList { - EList parent; - ESignatureListPrivate *priv; -}; - -struct _ESignatureListClass { - EListClass parent_class; - - /* Signals */ - void (*signature_added) (ESignatureList *signature_list, - ESignature *signature); - void (*signature_changed) (ESignatureList *signature_list, - ESignature *signature); - void (*signature_removed) (ESignatureList *signature_list, - ESignature *signature); -}; - -GType e_signature_list_get_type (void); -ESignatureList *e_signature_list_new (void); -void e_signature_list_construct (ESignatureList *signature_list, - GConfClient *client); -void e_signature_list_save (ESignatureList *signature_list); -void e_signature_list_add (ESignatureList *signature_list, - ESignature *signature); -void e_signature_list_change (ESignatureList *signature_list, - ESignature *signature); -void e_signature_list_remove (ESignatureList *signature_list, - ESignature *signature); -ESignature * e_signature_list_find_by_name (ESignatureList *signature_list, - const gchar *signature_name); -ESignature * e_signature_list_find_by_uid (ESignatureList *signature_list, - const gchar *signature_uid); - -G_END_DECLS - -#endif /* E_SIGNATURE_LIST_H */ diff --git a/e-util/e-signature-utils.c b/e-util/e-signature-utils.c deleted file mode 100644 index 7a5a7829ac..0000000000 --- a/e-util/e-signature-utils.c +++ /dev/null @@ -1,336 +0,0 @@ -/* - * e-signature-utils.c - * - * 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 - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "e-signature-utils.h" - -#include -#include -#include - -#ifndef G_OS_WIN32 -#include -#endif - -#include "e-util/e-util.h" - -static ESignatureList *global_signature_list; - -ESignatureList * -e_get_signature_list (void) -{ - if (G_UNLIKELY (global_signature_list == NULL)) - global_signature_list = e_signature_list_new (); - - g_return_val_if_fail (global_signature_list != NULL, NULL); - - return global_signature_list; -} - -ESignature * -e_get_signature_by_name (const gchar *name) -{ - ESignatureList *signature_list; - - g_return_val_if_fail (name != NULL, NULL); - - signature_list = e_get_signature_list (); - - return e_signature_list_find_by_name (signature_list, name); -} - -ESignature * -e_get_signature_by_uid (const gchar *uid) -{ - ESignatureList *signature_list; - - g_return_val_if_fail (uid != NULL, NULL); - - signature_list = e_get_signature_list (); - - return e_signature_list_find_by_uid (signature_list, uid); -} - -gchar * -e_create_signature_file (GError **error) -{ - const gchar *data_dir; - gchar basename[32]; - gchar *filename; - gchar *pathname; - gint32 ii; - - data_dir = e_get_user_data_dir (); - pathname = g_build_filename (data_dir, "signatures", NULL); - filename = NULL; - - if (g_mkdir_with_parents (pathname, 0700) < 0) { - g_set_error ( - error, G_FILE_ERROR, - g_file_error_from_errno (errno), - "%s: %s", pathname, g_strerror (errno)); - g_free (pathname); - return NULL; - } - - for (ii = 0; ii < G_MAXINT32; ii++) { - - g_snprintf ( - basename, sizeof (basename), - "signature-%" G_GINT32_FORMAT, ii); - - g_free (filename); - filename = g_build_filename (pathname, basename, NULL); - - if (!g_file_test (filename, G_FILE_TEST_EXISTS)) { - gint fd; - - fd = g_creat (filename, 0600); - if (fd >= 0) { - close (fd); - break; - } - - /* If we failed once we're probably going - * to continue failing, so just give up. */ - g_set_error ( - error, G_FILE_ERROR, - g_file_error_from_errno (errno), - "%s: %s", filename, g_strerror (errno)); - g_free (filename); - filename = NULL; - break; - } - } - - /* If there are actually G_MAXINT32 signature files, the - * most recent signature file we be overwritten. Sorry. */ - - return filename; -} - -gchar * -e_read_signature_file (ESignature *signature, - gboolean convert_to_html, - GError **error) -{ - CamelStream *input_stream; - CamelStream *output_stream; - GByteArray *buffer; - const gchar *filename; - gboolean is_html; - gchar *content; - gsize length; - gint fd; - - g_return_val_if_fail (E_IS_SIGNATURE (signature), NULL); - - filename = e_signature_get_filename (signature); - is_html = e_signature_get_is_html (signature); - - fd = g_open (filename, O_RDONLY, 0); - if (fd < 0) { - g_set_error ( - error, G_FILE_ERROR, - g_file_error_from_errno (errno), - "%s: %s", filename, g_strerror (errno)); - return NULL; - } - - input_stream = camel_stream_fs_new_with_fd (fd); - - if (!is_html && convert_to_html) { - CamelStream *filtered_stream; - CamelMimeFilter *filter; - gint32 flags; - - filtered_stream = - camel_stream_filter_new (input_stream); - g_object_unref (input_stream); - - flags = - CAMEL_MIME_FILTER_TOHTML_PRESERVE_8BIT | - CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS | - CAMEL_MIME_FILTER_TOHTML_CONVERT_ADDRESSES | - CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES; - filter = camel_mime_filter_tohtml_new (flags, 0); - camel_stream_filter_add ( - CAMEL_STREAM_FILTER (filtered_stream), filter); - g_object_unref (filter); - - input_stream = filtered_stream; - } - - buffer = g_byte_array_new (); - output_stream = camel_stream_mem_new (); - camel_stream_mem_set_byte_array ( - CAMEL_STREAM_MEM (output_stream), buffer); - camel_stream_write_to_stream (input_stream, output_stream, NULL, NULL); - g_object_unref (output_stream); - g_object_unref (input_stream); - - /* Make sure the buffer is nul-terminated. */ - length = (gsize) buffer->len; - g_byte_array_append (buffer, (guint8 *) "", 1); - content = (gchar *) g_byte_array_free (buffer, FALSE); - - /* Signatures are saved as UTF-8, but we still need to check that - * the signature is valid UTF-8 because the user may be opening - * a signature file that is in his/her locale character set. If - * it's not in UTF-8 then try converting from the current locale. */ - if (!g_utf8_validate (content, length, NULL)) { - gchar *utf8; - - utf8 = g_locale_to_utf8 (content, length, NULL, NULL, error); - g_free (content); - content = utf8; - } - - return content; -} - -gchar * -e_run_signature_script (const gchar *filename) -{ - /* FIXME Make this cross-platform, prefer GLib functions over - * POSIX, and report errors via GError instead of dumping - * messages to the terminal where users won't see them. */ - -#ifndef G_OS_WIN32 - gint in_fds[2]; - pid_t pid; - - g_return_val_if_fail (filename != NULL, NULL); - - if (pipe (in_fds) == -1) { - g_warning ( - "Failed to create pipe to '%s': %s", - filename, g_strerror (errno)); - return NULL; - } - - pid = fork (); - - /* Child Process */ - if (pid == 0) { - gint maxfd, ii; - - close (in_fds[0]); - if (dup2 (in_fds[1], STDOUT_FILENO) < 0) - _exit (255); - close (in_fds[1]); - - setsid (); - - maxfd = sysconf (_SC_OPEN_MAX); - for (ii = 3; ii < maxfd; ii++) { - if (ii == STDIN_FILENO) - continue; - if (ii == STDOUT_FILENO) - continue; - if (ii == STDERR_FILENO) - continue; - fcntl (ii, F_SETFD, FD_CLOEXEC); - } - - execlp ("/bin/sh", "/bin/sh", "-c", filename, NULL); - - g_warning ( - "Could not execute '%s': %s", - filename, g_strerror (errno)); - - _exit (255); - - /* Parent Process */ - } else if (pid > 0) { - CamelStream *output_stream; - CamelStream *input_stream; - GByteArray *buffer; - gchar *content; - gsize length; - gint result; - gint status; - - close (in_fds[1]); - - buffer = g_byte_array_new (); - output_stream = camel_stream_mem_new (); - camel_stream_mem_set_byte_array ( - CAMEL_STREAM_MEM (output_stream), buffer); - - input_stream = camel_stream_fs_new_with_fd (in_fds[0]); - camel_stream_write_to_stream ( - input_stream, output_stream, NULL, NULL); - g_object_unref (input_stream); - - g_object_unref (output_stream); - - /* Make sure the buffer is nul-terminated. */ - length = (gsize) buffer->len; - g_byte_array_append (buffer, (guchar *) "", 1); - content = (gchar *) g_byte_array_free (buffer, FALSE); - - /* Signature scripts are supposed to generate UTF-8 content, - * but because users are known to never read the manual, we - * try to do our best if the content isn't valid UTF-8 by - * assuming that the content is in the user's locale - * character set. */ - if (!g_utf8_validate (content, length, NULL)) { - gchar *utf8; - - /* XXX Should pass a GError here. */ - utf8 = g_locale_to_utf8 ( - content, length, NULL, NULL, NULL); - g_free (content); - content = utf8; - } - - /* Wait for the script process to terminate. */ - result = waitpid (pid, &status, 0); - - if (result == -1 && errno == EINTR) { - /* Child process is hanging... */ - kill (pid, SIGTERM); - sleep (1); - result = waitpid (pid, &status, WNOHANG); - if (result == 0) { - /* ...still hanging, set phasers to KILL. */ - kill (pid, SIGKILL); - sleep (1); - waitpid (pid, &status, WNOHANG); - } - } - - return content; - - /* Forking Failed */ - } else { - g_warning ( - "Failed to create child process '%s': %s", - filename, g_strerror (errno)); - close (in_fds[0]); - close (in_fds[1]); - } -#endif - - return NULL; -} diff --git a/e-util/e-signature-utils.h b/e-util/e-signature-utils.h deleted file mode 100644 index 56f8564131..0000000000 --- a/e-util/e-signature-utils.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * e-signature-utils.h - * - * 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 - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - */ - -#ifndef E_SIGNATURE_UTILS_H -#define E_SIGNATURE_UTILS_H - -#include -#include -#include - -G_BEGIN_DECLS - -ESignatureList *e_get_signature_list (void); -ESignature * e_get_signature_by_name (const gchar *name); -ESignature * e_get_signature_by_uid (const gchar *uid); -gchar * e_create_signature_file (GError **error); -gchar * e_read_signature_file (ESignature *signature, - gboolean convert_to_html, - GError **error); -gchar * e_run_signature_script (const gchar *filename); - -G_END_DECLS - -#endif /* E_SIGNATURE_UTILS_H */ diff --git a/e-util/e-signature.c b/e-util/e-signature.c deleted file mode 100644 index 1b49389a82..0000000000 --- a/e-util/e-signature.c +++ /dev/null @@ -1,746 +0,0 @@ -/* - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see - * - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include -#include -#include - -#include - -#include -#include - -#include "e-signature.h" - -struct _ESignaturePrivate { - gchar *filename; - gchar *name; - gchar *uid; - - gboolean autogenerated; - gboolean is_html; - gboolean is_script; -}; - -enum { - PROP_0, - PROP_AUTOGENERATED, - PROP_FILENAME, - PROP_IS_HTML, - PROP_IS_SCRIPT, - PROP_NAME, - PROP_UID -}; - -G_DEFINE_TYPE ( - ESignature, - e_signature, - G_TYPE_OBJECT) - -static gboolean -xml_set_bool (xmlNodePtr node, - const gchar *name, - gboolean *val) -{ - gboolean v_boolean; - gchar *buf; - - if ((buf = (gchar *) xmlGetProp (node, (xmlChar *) name))) { - v_boolean = (!strcmp (buf, "true") || !strcmp (buf, "yes")); - xmlFree (buf); - - if (v_boolean != *val) { - *val = v_boolean; - return TRUE; - } - } - - return FALSE; -} - -static gboolean -xml_set_prop (xmlNodePtr node, - const gchar *name, - gchar **val) -{ - gchar *buf, *new_val; - - buf = (gchar *) xmlGetProp (node, (xmlChar *) name); - new_val = g_strdup (buf); - xmlFree (buf); - - /* We can use strcmp here whether the value is UTF8 or - * not, since we only care if the bytes changed. - */ - if (!*val || strcmp (*val, new_val)) { - g_free (*val); - *val = new_val; - return TRUE; - } else { - g_free (new_val); - return FALSE; - } -} - -static gboolean -xml_set_content (xmlNodePtr node, - gchar **val) -{ - gchar *buf, *new_val; - - buf = (gchar *) xmlNodeGetContent (node); - new_val = g_strdup (buf); - xmlFree (buf); - - /* We can use strcmp here whether the value is UTF8 or - * not, since we only care if the bytes changed. */ - if (!*val || strcmp (*val, new_val)) { - g_free (*val); - *val = new_val; - return TRUE; - } else { - g_free (new_val); - return FALSE; - } -} - -static void -signature_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_AUTOGENERATED: - e_signature_set_autogenerated ( - E_SIGNATURE (object), - g_value_get_boolean (value)); - return; - - case PROP_FILENAME: - e_signature_set_filename ( - E_SIGNATURE (object), - g_value_get_string (value)); - return; - - case PROP_IS_HTML: - e_signature_set_is_html ( - E_SIGNATURE (object), - g_value_get_boolean (value)); - return; - - case PROP_IS_SCRIPT: - e_signature_set_is_script ( - E_SIGNATURE (object), - g_value_get_boolean (value)); - return; - - case PROP_NAME: - e_signature_set_name ( - E_SIGNATURE (object), - g_value_get_string (value)); - return; - - case PROP_UID: - e_signature_set_uid ( - E_SIGNATURE (object), - g_value_get_string (value)); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -signature_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_AUTOGENERATED: - g_value_set_boolean ( - value, e_signature_get_autogenerated ( - E_SIGNATURE (object))); - return; - - case PROP_FILENAME: - g_value_set_string ( - value, e_signature_get_filename ( - E_SIGNATURE (object))); - return; - - case PROP_IS_HTML: - g_value_set_boolean ( - value, e_signature_get_is_html ( - E_SIGNATURE (object))); - return; - - case PROP_IS_SCRIPT: - g_value_set_boolean ( - value, e_signature_get_is_script ( - E_SIGNATURE (object))); - return; - - case PROP_NAME: - g_value_set_string ( - value, e_signature_get_name ( - E_SIGNATURE (object))); - return; - - case PROP_UID: - g_value_set_string ( - value, e_signature_get_uid ( - E_SIGNATURE (object))); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -signature_finalize (GObject *object) -{ - ESignaturePrivate *priv; - - priv = E_SIGNATURE (object)->priv; - - g_free (priv->filename); - g_free (priv->name); - g_free (priv->uid); - - /* Chain up to parent's finalize() method. */ - G_OBJECT_CLASS (e_signature_parent_class)->finalize (object); -} - -static void -e_signature_class_init (ESignatureClass *class) -{ - GObjectClass *object_class; - - g_type_class_add_private (class, sizeof (ESignaturePrivate)); - - object_class = G_OBJECT_CLASS (class); - object_class->set_property = signature_set_property; - object_class->get_property = signature_get_property; - object_class->finalize = signature_finalize; - - g_object_class_install_property ( - object_class, - PROP_AUTOGENERATED, - g_param_spec_boolean ( - "autogenerated", - "Autogenerated", - NULL, - FALSE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); - - g_object_class_install_property ( - object_class, - PROP_FILENAME, - g_param_spec_string ( - "filename", - "Filename", - NULL, - NULL, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); - - g_object_class_install_property ( - object_class, - PROP_IS_HTML, - g_param_spec_boolean ( - "is-html", - "Is HTML", - NULL, - FALSE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); - - g_object_class_install_property ( - object_class, - PROP_IS_SCRIPT, - g_param_spec_boolean ( - "is-script", - "Is Script", - NULL, - FALSE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); - - g_object_class_install_property ( - object_class, - PROP_NAME, - g_param_spec_string ( - "name", - "Name", - NULL, - NULL, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); - - g_object_class_install_property ( - object_class, - PROP_UID, - g_param_spec_string ( - "uid", - "UID", - NULL, - NULL, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); -} - -static void -e_signature_init (ESignature *signature) -{ - signature->priv = G_TYPE_INSTANCE_GET_PRIVATE ( - signature, E_TYPE_SIGNATURE, ESignaturePrivate); -} - -/** - * e_signature_new: - * - * Returns a new signature which can be filled in and - * added to an #ESignatureList. - * - * Returns: a new #ESignature - **/ -ESignature * -e_signature_new (void) -{ - ESignature *signature; - - signature = g_object_new (E_TYPE_SIGNATURE, NULL); - signature->priv->uid = e_uid_new (); - - return signature; -} - -/** - * e_signature_new_from_xml: - * @xml: an XML signature description - * - * Return value: a new #ESignature based on the data in @xml, or %NULL - * if @xml could not be parsed as valid signature data. - **/ -ESignature * -e_signature_new_from_xml (const gchar *xml) -{ - ESignature *signature; - - signature = g_object_new (E_TYPE_SIGNATURE, NULL); - - if (!e_signature_set_from_xml (signature, xml)) { - g_object_unref (signature); - return NULL; - } - - return signature; -} - -/** - * e_signature_uid_from_xml: - * @xml: an XML signature description - * - * Return value: the permanent UID of the signature described by @xml - * (or %NULL if @xml could not be parsed or did not contain a uid). - * The caller must free this string. - **/ -gchar * -e_signature_uid_from_xml (const gchar *xml) -{ - xmlNodePtr node; - xmlDocPtr doc; - gchar *uid = NULL; - - if (!(doc = xmlParseDoc ((xmlChar *) xml))) - return NULL; - - node = doc->children; - if (strcmp ((gchar *)node->name, "signature") != 0) { - xmlFreeDoc (doc); - return NULL; - } - - xml_set_prop (node, "uid", &uid); - xmlFreeDoc (doc); - - return uid; -} - -/** - * e_signature_set_from_xml: - * @signature: an #ESignature - * @xml: an XML signature description. - * - * Changes @signature to match @xml. - * - * Returns: %TRUE if the signature was loaded or %FALSE otherwise - **/ -gboolean -e_signature_set_from_xml (ESignature *signature, - const gchar *xml) -{ - gboolean changed = FALSE; - xmlNodePtr node, cur; - xmlDocPtr doc; - gboolean bool; - gchar *buf; - - if (!(doc = xmlParseDoc ((xmlChar *) xml))) - return FALSE; - - node = doc->children; - if (strcmp ((gchar *)node->name, "signature") != 0) { - xmlFreeDoc (doc); - return FALSE; - } - - buf = NULL; - xml_set_prop (node, "uid", &buf); - - if (buf && *buf) { - g_free (signature->priv->uid); - signature->priv->uid = buf; - } - - changed |= xml_set_prop (node, "name", &signature->priv->name); - changed |= xml_set_bool (node, "auto", &signature->priv->autogenerated); - - if (e_signature_get_autogenerated (signature)) { - xmlFreeDoc (doc); - - return changed; - } - - buf = NULL; - xml_set_prop (node, "format", &buf); - if (buf && !strcmp (buf, "text/html")) - bool = TRUE; - else - bool = FALSE; - g_free (buf); - - if (e_signature_get_is_html (signature) != bool) { - e_signature_set_is_html (signature, bool); - changed = TRUE; - } - - cur = node->children; - while (cur) { - if (!strcmp ((gchar *)cur->name, "filename")) { - changed |= xml_set_content ( - cur, &signature->priv->filename); - changed |= xml_set_bool ( - cur, "script", &signature->priv->is_script); - break; - } else if (!strcmp ((gchar *)cur->name, "script")) { - /* this is for handling 1.4 signature script definitions */ - changed |= xml_set_content ( - cur, &signature->priv->filename); - if (!e_signature_get_is_script (signature)) { - e_signature_set_is_script (signature, TRUE); - changed = TRUE; - } - break; - } - cur = cur->next; - } - - /* If the signature is not a script, replace the directory - * part with the current signatures directory. This makes - * moving the signatures directory transparent. */ - if (!e_signature_get_is_script (signature)) { - const gchar *user_data_dir; - gchar *basename; - gchar *filename; - - user_data_dir = e_get_user_data_dir (); - - filename = signature->priv->filename; - basename = g_path_get_basename (filename); - signature->priv->filename = g_build_filename ( - user_data_dir, "signatures", basename, NULL); - g_free (basename); - g_free (filename); - } - - xmlFreeDoc (doc); - - return changed; -} - -/** - * e_signature_to_xml: - * @signature: an #ESignature - * - * Return value: an XML representation of @signature, which the caller - * must free. - **/ -gchar * -e_signature_to_xml (ESignature *signature) -{ - xmlChar *xmlbuf; - gchar *tmp; - xmlNodePtr root, node; - xmlDocPtr doc; - const gchar *string; - gint n; - - doc = xmlNewDoc ((xmlChar *) "1.0"); - - root = xmlNewDocNode (doc, NULL, (xmlChar *) "signature", NULL); - xmlDocSetRootElement (doc, root); - - string = e_signature_get_name (signature); - xmlSetProp (root, (xmlChar *) "name", (xmlChar *) string); - - string = e_signature_get_uid (signature); - xmlSetProp (root, (xmlChar *) "uid", (xmlChar *) string); - - if (e_signature_get_autogenerated (signature)) - string = "true"; - else - string = "false"; - xmlSetProp (root, (xmlChar *) "auto", (xmlChar *) string); - - if (!e_signature_get_autogenerated (signature)) { - if (e_signature_get_is_html (signature)) - string = "text/html"; - else - string = "text/plain"; - xmlSetProp (root, (xmlChar *) "format", (xmlChar *) string); - - string = e_signature_get_filename (signature); - if (string != NULL) { - - /* For scripts we save the full filename, - * for normal signatures just the basename. */ - if (e_signature_get_is_script (signature)) { - node = xmlNewTextChild ( - root, NULL, (xmlChar *) "filename", - (xmlChar *) string); - xmlSetProp ( - node, (xmlChar *) "script", - (xmlChar *) "true"); - } else { - gchar *basename; - - basename = g_path_get_basename (string); - node = xmlNewTextChild ( - root, NULL, (xmlChar *) "filename", - (xmlChar *) basename); - g_free (basename); - } - } - } else { - /* this is to make Evolution-1.4 and older 1.5 versions happy */ - xmlSetProp (root, (xmlChar *) "format", (xmlChar *) "text/html"); - } - - xmlDocDumpMemory (doc, &xmlbuf, &n); - xmlFreeDoc (doc); - - /* remap to glib memory */ - tmp = g_malloc (n + 1); - memcpy (tmp, xmlbuf, n); - tmp[n] = '\0'; - xmlFree (xmlbuf); - - return tmp; -} - -gboolean -e_signature_is_equal (ESignature *signature1, - ESignature *signature2) -{ - const gchar *uid1; - const gchar *uid2; - - g_return_val_if_fail (E_IS_SIGNATURE (signature1), FALSE); - g_return_val_if_fail (E_IS_SIGNATURE (signature2), FALSE); - - /* XXX Simply compares the UIDs. Not fool-proof. */ - uid1 = e_signature_get_uid (signature1); - uid2 = e_signature_get_uid (signature2); - - return (g_strcmp0 (uid1, uid2) == 0); -} - -gboolean -e_signature_get_autogenerated (ESignature *signature) -{ - g_return_val_if_fail (E_IS_SIGNATURE (signature), FALSE); - - return signature->priv->autogenerated; -} - -void -e_signature_set_autogenerated (ESignature *signature, - gboolean autogenerated) -{ - g_return_if_fail (E_IS_SIGNATURE (signature)); - - if (signature->priv->autogenerated == autogenerated) - return; - - signature->priv->autogenerated = autogenerated; - - /* Autogenerated flags overrides several properties. */ - g_object_freeze_notify (G_OBJECT (signature)); - g_object_notify (G_OBJECT (signature), "autogenerated"); - g_object_notify (G_OBJECT (signature), "filename"); - g_object_notify (G_OBJECT (signature), "is-html"); - g_object_notify (G_OBJECT (signature), "is-script"); - g_object_notify (G_OBJECT (signature), "name"); - g_object_thaw_notify (G_OBJECT (signature)); -} - -const gchar * -e_signature_get_filename (ESignature *signature) -{ - g_return_val_if_fail (E_IS_SIGNATURE (signature), NULL); - - /* Autogenerated flags overrides the filename property. */ - if (e_signature_get_autogenerated (signature)) - return NULL; - - return signature->priv->filename; -} - -void -e_signature_set_filename (ESignature *signature, - const gchar *filename) -{ - g_return_if_fail (E_IS_SIGNATURE (signature)); - - g_free (signature->priv->filename); - signature->priv->filename = g_strdup (filename); - - g_object_notify (G_OBJECT (signature), "filename"); -} - -gboolean -e_signature_get_is_html (ESignature *signature) -{ - g_return_val_if_fail (E_IS_SIGNATURE (signature), FALSE); - - /* Autogenerated flag overrides the is-html property. */ - if (e_signature_get_autogenerated (signature)) - return FALSE; - - return signature->priv->is_html; -} - -void -e_signature_set_is_html (ESignature *signature, - gboolean is_html) -{ - g_return_if_fail (E_IS_SIGNATURE (signature)); - - if (signature->priv->is_html == is_html) - return; - - signature->priv->is_html = is_html; - - g_object_notify (G_OBJECT (signature), "is-html"); -} - -gboolean -e_signature_get_is_script (ESignature *signature) -{ - g_return_val_if_fail (E_IS_SIGNATURE (signature), FALSE); - - /* Autogenerated flags overrides the is-script property. */ - if (e_signature_get_autogenerated (signature)) - return FALSE; - - return signature->priv->is_script; -} - -void -e_signature_set_is_script (ESignature *signature, - gboolean is_script) -{ - g_return_if_fail (E_IS_SIGNATURE (signature)); - - if (signature->priv->is_script == is_script) - return; - - signature->priv->is_script = is_script; - - g_object_notify (G_OBJECT (signature), "is-script"); -} - -const gchar * -e_signature_get_name (ESignature *signature) -{ - g_return_val_if_fail (E_IS_SIGNATURE (signature), NULL); - - /* Autogenerated flag overrides the name property. */ - if (e_signature_get_autogenerated (signature)) - return _("Autogenerated"); - - return signature->priv->name; -} - -void -e_signature_set_name (ESignature *signature, - const gchar *name) -{ - g_return_if_fail (E_IS_SIGNATURE (signature)); - - g_free (signature->priv->name); - signature->priv->name = g_strdup (name); - - g_object_notify (G_OBJECT (signature), "name"); -} - -const gchar * -e_signature_get_uid (ESignature *signature) -{ - g_return_val_if_fail (E_IS_SIGNATURE (signature), NULL); - - return signature->priv->uid; -} - -void -e_signature_set_uid (ESignature *signature, - const gchar *uid) -{ - g_return_if_fail (E_IS_SIGNATURE (signature)); - - g_free (signature->priv->uid); - - if (uid == NULL) - signature->priv->uid = e_uid_new (); - else - signature->priv->uid = g_strdup (uid); - - g_object_notify (G_OBJECT (signature), "uid"); -} diff --git a/e-util/e-signature.h b/e-util/e-signature.h deleted file mode 100644 index fad1faffa3..0000000000 --- a/e-util/e-signature.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see - * - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef E_SIGNATURE_H -#define E_SIGNATURE_H - -#include - -/* Standard GObject macros */ -#define E_TYPE_SIGNATURE \ - (e_signature_get_type ()) -#define E_SIGNATURE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST \ - ((obj), E_TYPE_SIGNATURE, ESignature)) -#define E_SIGNATURE_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_CAST \ - ((cls), E_TYPE_SIGNATURE, ESignatureClass)) -#define E_IS_SIGNATURE(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE \ - ((obj), E_TYPE_SIGNATURE)) -#define E_IS_SIGNATURE_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_TYPE \ - ((cls), E_TYPE_SIGNATURE)) -#define E_SIGNATURE_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS \ - ((obj), E_TYPE_SIGNATURE, ESignatureClass)) - -G_BEGIN_DECLS - -typedef struct _ESignature ESignature; -typedef struct _ESignatureClass ESignatureClass; -typedef struct _ESignaturePrivate ESignaturePrivate; - -struct _ESignature { - GObject parent; - ESignaturePrivate *priv; -}; - -struct _ESignatureClass { - GObjectClass parent_class; -}; - -GType e_signature_get_type (void); -ESignature * e_signature_new (void); -ESignature * e_signature_new_from_xml (const gchar *xml); -gchar * e_signature_uid_from_xml (const gchar *xml); -gboolean e_signature_set_from_xml (ESignature *signature, - const gchar *xml); -gchar * e_signature_to_xml (ESignature *signature); -gboolean e_signature_is_equal (ESignature *signature1, - ESignature *signature2); -gboolean e_signature_get_autogenerated (ESignature *signature); -void e_signature_set_autogenerated (ESignature *signature, - gboolean autogenerated); -const gchar * e_signature_get_filename (ESignature *signature); -void e_signature_set_filename (ESignature *signature, - const gchar *filename); -gboolean e_signature_get_is_html (ESignature *signature); -void e_signature_set_is_html (ESignature *signature, - gboolean is_html); -gboolean e_signature_get_is_script (ESignature *signature); -void e_signature_set_is_script (ESignature *signature, - gboolean is_script); -const gchar * e_signature_get_name (ESignature *signature); -void e_signature_set_name (ESignature *signature, - const gchar *name); -const gchar * e_signature_get_uid (ESignature *signature); -void e_signature_set_uid (ESignature *signature, - const gchar *uid); - -G_END_DECLS - -#endif /* E_SIGNATURE_H */ diff --git a/evolution-mail.pc.in b/evolution-mail.pc.in index 782177052f..e2bdf78139 100644 --- a/evolution-mail.pc.in +++ b/evolution-mail.pc.in @@ -12,6 +12,6 @@ privincludedir=@privincludedir@ Name: Evolution Mail Description: Mail utilities for Evolution Version: @VERSION@ -Requires: evolution-shell-3.0 camel-1.2 +Requires: evolution-shell-3.0 camel-1.2 libemail-engine Libs: -L${privlibdir} -levolution-mail -lcomposer Cflags: -I${privincludedir} diff --git a/libemail-engine/Makefile.am b/libemail-engine/Makefile.am new file mode 100644 index 0000000000..88a0227aab --- /dev/null +++ b/libemail-engine/Makefile.am @@ -0,0 +1,71 @@ +NULL = + +lib_LTLIBRARIES = libemail-engine.la + +include $(top_srcdir)/glib-gen.mak +glib_enum_headers=e-mail-enums.h +glib_enum_output=e-mail-enumtypes +glib_enum_define=E_MAIL +glib_enum_prefix=e_mail + +ENUM_GENERATED = e-mail-enumtypes.h e-mail-enumtypes.c + +libemail_engine_la_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -I$(top_srcdir) \ + -I$(top_builddir) \ + $(EVOLUTION_DATA_SERVER_CFLAGS) \ + $(GNOME_PLATFORM_CFLAGS) \ + $(NULL) + +libmailengineincludedir = $(privincludedir)/libemail-engine +libmailengineinclude_HEADERS = \ + e-mail-enums.h \ + e-mail-enumtypes.h \ + e-mail-folder-utils.h \ + e-mail-junk-filter.h \ + e-mail-session-utils.h \ + e-mail-session.h \ + e-mail-store-utils.h \ + e-mail-utils.h \ + mail-config.h \ + mail-folder-cache.h \ + mail-ops.h \ + mail-tools.h \ + $(NULL) + +libemail_engine_la_SOURCES = \ + $(libmailengineinclude_HEADERS) \ + e-mail-enumtypes.c \ + e-mail-folder-utils.c \ + e-mail-junk-filter.c \ + e-mail-session-utils.c \ + e-mail-session.c \ + e-mail-store-utils.c \ + e-mail-utils.c \ + mail-config.c \ + mail-folder-cache.c \ + mail-ops.c \ + mail-tools.c \ + $(NULL) + +libemail_engine_la_LIBADD = \ + $(top_builddir)/libemail-utils/libemail-utils.la \ + $(EVOLUTION_DATA_SERVER_LIBS) \ + $(GNOME_PLATFORM_LIBS) \ + $(NULL) + +libemail_engine_la_LDFLAGS = $(NO_UNDEFINED) + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libemail-engine.pc + +BUILT_SOURCES = $(ENUM_GENERATED) + +CLEANFILES = $(BUILT_SOURCES) +DISTCLEANFILES = $(pkgconfig_DATA) + +dist-hook: + cd $(distdir); rm -f $(BUILT_SOURCES) + +-include $(top_srcdir)/git.mk diff --git a/libemail-engine/e-mail-enums.h b/libemail-engine/e-mail-enums.h new file mode 100644 index 0000000000..e0ad3ad86f --- /dev/null +++ b/libemail-engine/e-mail-enums.h @@ -0,0 +1,74 @@ +/* + * e-mail-enums.h + * + * 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 + * + */ + +#ifndef E_MAIL_ENUMS_H +#define E_MAIL_ENUMS_H + +#include + +G_BEGIN_DECLS + +typedef enum { + E_MAIL_DISPLAY_STYLE_NORMAL, + E_MAIL_DISPLAY_STYLE_FULL_HEADERS, + E_MAIL_DISPLAY_STYLE_SOURCE +} EMailDisplayStyle; + +typedef enum { + E_MAIL_FORWARD_STYLE_ATTACHED, + E_MAIL_FORWARD_STYLE_INLINE, + E_MAIL_FORWARD_STYLE_QUOTED +} EMailForwardStyle; + +typedef enum { + E_MAIL_IMAGE_LOADING_POLICY_NEVER, + E_MAIL_IMAGE_LOADING_POLICY_SOMETIMES, + E_MAIL_IMAGE_LOADING_POLICY_ALWAYS +} EMailImageLoadingPolicy; + +/* XXX E_MAIL_FOLDER_TEMPLATES is a prime example of why templates + * should be a core feature: the mailer now has to know about + * this specific plugin, which defeats the purpose of plugins. */ +typedef enum { + E_MAIL_LOCAL_FOLDER_INBOX, + E_MAIL_LOCAL_FOLDER_DRAFTS, + E_MAIL_LOCAL_FOLDER_OUTBOX, + E_MAIL_LOCAL_FOLDER_SENT, + E_MAIL_LOCAL_FOLDER_TEMPLATES, + E_MAIL_LOCAL_FOLDER_LOCAL_INBOX, + E_MAIL_NUM_LOCAL_FOLDERS +} EMailLocalFolder; + +typedef enum { + E_MAIL_REPLY_STYLE_QUOTED, + E_MAIL_REPLY_STYLE_DO_NOT_QUOTE, + E_MAIL_REPLY_STYLE_ATTACH, + E_MAIL_REPLY_STYLE_OUTLOOK +} EMailReplyStyle; + +typedef enum { + E_MAIL_REPLY_TO_SENDER, + E_MAIL_REPLY_TO_RECIPIENT, + E_MAIL_REPLY_TO_FROM, + E_MAIL_REPLY_TO_ALL, + E_MAIL_REPLY_TO_LIST +} EMailReplyType; + +G_END_DECLS + +#endif /* E_MAIL_ENUMS_H */ diff --git a/libemail-engine/e-mail-folder-utils.c b/libemail-engine/e-mail-folder-utils.c new file mode 100644 index 0000000000..25754f4f96 --- /dev/null +++ b/libemail-engine/e-mail-folder-utils.c @@ -0,0 +1,1666 @@ +/* + * e-mail-folder-utils.c + * + * 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 + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "e-mail-folder-utils.h" + +#include + +#include + +/* X-Mailer header value */ +#define X_MAILER ("Evolution " VERSION SUB_VERSION " " VERSION_COMMENT) + +typedef struct _AsyncContext AsyncContext; + +struct _AsyncContext { + CamelMimeMessage *message; + CamelMessageInfo *info; + CamelMimePart *part; + GHashTable *hash_table; + GPtrArray *ptr_array; + GFile *destination; + gchar *fwd_subject; + gchar *message_uid; +}; + +static void +async_context_free (AsyncContext *context) +{ + if (context->message != NULL) + g_object_unref (context->message); + + if (context->info != NULL) + camel_message_info_free (context->info); + + if (context->part != NULL) + g_object_unref (context->part); + + if (context->hash_table != NULL) + g_hash_table_unref (context->hash_table); + + if (context->ptr_array != NULL) + g_ptr_array_unref (context->ptr_array); + + if (context->destination != NULL) + g_object_unref (context->destination); + + g_free (context->fwd_subject); + g_free (context->message_uid); + + g_slice_free (AsyncContext, context); +} + +static void +mail_folder_append_message_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + AsyncContext *context; + GError *error = NULL; + + context = g_simple_async_result_get_op_res_gpointer (simple); + + e_mail_folder_append_message_sync ( + CAMEL_FOLDER (object), context->message, + context->info, &context->message_uid, + cancellable, &error); + + if (error != NULL) + g_simple_async_result_take_error (simple, error); +} + +gboolean +e_mail_folder_append_message_sync (CamelFolder *folder, + CamelMimeMessage *message, + CamelMessageInfo *info, + gchar **appended_uid, + GCancellable *cancellable, + GError **error) +{ + CamelMedium *medium; + gboolean success; + + g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); + g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), FALSE); + + medium = CAMEL_MEDIUM (message); + + camel_operation_push_message ( + cancellable, + _("Saving message to folder '%s'"), + camel_folder_get_full_name (folder)); + + if (camel_medium_get_header (medium, "X-Mailer") == NULL) + camel_medium_set_header (medium, "X-Mailer", X_MAILER); + + camel_mime_message_set_date (message, CAMEL_MESSAGE_DATE_CURRENT, 0); + + success = camel_folder_append_message_sync ( + folder, message, info, appended_uid, cancellable, error); + + camel_operation_pop_message (cancellable); + + return success; +} + +void +e_mail_folder_append_message (CamelFolder *folder, + CamelMimeMessage *message, + CamelMessageInfo *info, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *context; + + g_return_if_fail (CAMEL_IS_FOLDER (folder)); + g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message)); + + context = g_slice_new0 (AsyncContext); + context->message = g_object_ref (message); + + if (info != NULL) + context->info = camel_message_info_ref (info); + + simple = g_simple_async_result_new ( + G_OBJECT (folder), callback, user_data, + e_mail_folder_append_message); + + g_simple_async_result_set_op_res_gpointer ( + simple, context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, mail_folder_append_message_thread, + io_priority, cancellable); + + g_object_unref (simple); +} + +gboolean +e_mail_folder_append_message_finish (CamelFolder *folder, + GAsyncResult *result, + gchar **appended_uid, + GError **error) +{ + GSimpleAsyncResult *simple; + AsyncContext *context; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (folder), + e_mail_folder_append_message), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + context = g_simple_async_result_get_op_res_gpointer (simple); + + if (appended_uid != NULL) { + *appended_uid = context->message_uid; + context->message_uid = NULL; + } + + /* Assume success unless a GError is set. */ + return !g_simple_async_result_propagate_error (simple, error); +} + +static void +mail_folder_build_attachment_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + AsyncContext *context; + GError *error = NULL; + + context = g_simple_async_result_get_op_res_gpointer (simple); + + context->part = e_mail_folder_build_attachment_sync ( + CAMEL_FOLDER (object), context->ptr_array, + &context->fwd_subject, cancellable, &error); + + if (error != NULL) + g_simple_async_result_take_error (simple, error); +} + +CamelMimePart * +e_mail_folder_build_attachment_sync (CamelFolder *folder, + GPtrArray *message_uids, + gchar **fwd_subject, + GCancellable *cancellable, + GError **error) +{ + GHashTable *hash_table; + CamelMimeMessage *message; + CamelMimePart *part; + const gchar *uid; + + g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL); + g_return_val_if_fail (message_uids != NULL, NULL); + + /* Need at least one message UID to make an attachment. */ + g_return_val_if_fail (message_uids->len > 0, NULL); + + hash_table = e_mail_folder_get_multiple_messages_sync ( + folder, message_uids, cancellable, error); + + if (hash_table == NULL) + return NULL; + + /* Create the forward subject from the first message. */ + + uid = g_ptr_array_index (message_uids, 0); + g_return_val_if_fail (uid != NULL, NULL); + + message = g_hash_table_lookup (hash_table, uid); + g_return_val_if_fail (message != NULL, NULL); + + if (fwd_subject != NULL) + *fwd_subject = mail_tool_generate_forward_subject (message); + + if (message_uids->len == 1) { + part = mail_tool_make_message_attachment (message); + + } else { + CamelMultipart *multipart; + guint ii; + + multipart = camel_multipart_new (); + camel_data_wrapper_set_mime_type ( + CAMEL_DATA_WRAPPER (multipart), "multipart/digest"); + camel_multipart_set_boundary (multipart, NULL); + + for (ii = 0; ii < message_uids->len; ii++) { + uid = g_ptr_array_index (message_uids, ii); + g_return_val_if_fail (uid != NULL, NULL); + + message = g_hash_table_lookup (hash_table, uid); + g_return_val_if_fail (message != NULL, NULL); + + part = mail_tool_make_message_attachment (message); + camel_multipart_add_part (multipart, part); + g_object_unref (part); + } + + part = camel_mime_part_new (); + + camel_medium_set_content ( + CAMEL_MEDIUM (part), + CAMEL_DATA_WRAPPER (multipart)); + + camel_mime_part_set_description ( + part, _("Forwarded messages")); + + g_object_unref (multipart); + } + + g_hash_table_unref (hash_table); + + return part; +} + +void +e_mail_folder_build_attachment (CamelFolder *folder, + GPtrArray *message_uids, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *context; + + g_return_if_fail (CAMEL_IS_FOLDER (folder)); + g_return_if_fail (message_uids != NULL); + + /* Need at least one message UID to make an attachment. */ + g_return_if_fail (message_uids->len > 0); + + context = g_slice_new0 (AsyncContext); + context->ptr_array = g_ptr_array_ref (message_uids); + + simple = g_simple_async_result_new ( + G_OBJECT (folder), callback, user_data, + e_mail_folder_build_attachment); + + g_simple_async_result_set_op_res_gpointer ( + simple, context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, mail_folder_build_attachment_thread, + io_priority, cancellable); + + g_object_unref (simple); +} + +CamelMimePart * +e_mail_folder_build_attachment_finish (CamelFolder *folder, + GAsyncResult *result, + gchar **fwd_subject, + GError **error) +{ + GSimpleAsyncResult *simple; + AsyncContext *context; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (folder), + e_mail_folder_build_attachment), NULL); + + simple = G_SIMPLE_ASYNC_RESULT (result); + context = g_simple_async_result_get_op_res_gpointer (simple); + + if (g_simple_async_result_propagate_error (simple, error)) + return NULL; + + if (fwd_subject != NULL) { + *fwd_subject = context->fwd_subject; + context->fwd_subject = NULL; + } + + g_return_val_if_fail (CAMEL_IS_MIME_PART (context->part), NULL); + + return g_object_ref (context->part); +} + +static void +mail_folder_find_duplicate_messages_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + AsyncContext *context; + GError *error = NULL; + + context = g_simple_async_result_get_op_res_gpointer (simple); + + context->hash_table = e_mail_folder_find_duplicate_messages_sync ( + CAMEL_FOLDER (object), context->ptr_array, + cancellable, &error); + + if (error != NULL) + g_simple_async_result_take_error (simple, error); +} + +GHashTable * +e_mail_folder_find_duplicate_messages_sync (CamelFolder *folder, + GPtrArray *message_uids, + GCancellable *cancellable, + GError **error) +{ + GQueue trash = G_QUEUE_INIT; + GHashTable *hash_table; + GHashTable *unique_ids; + GHashTableIter iter; + gpointer key, value; + + g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL); + g_return_val_if_fail (message_uids != NULL, NULL); + + /* hash_table = { MessageUID : CamelMessage } */ + hash_table = e_mail_folder_get_multiple_messages_sync ( + folder, message_uids, cancellable, error); + + if (hash_table == NULL) + return NULL; + + camel_operation_push_message ( + cancellable, _("Scanning messages for duplicates")); + + unique_ids = g_hash_table_new_full ( + (GHashFunc) g_int64_hash, + (GEqualFunc) g_int64_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) g_free); + + g_hash_table_iter_init (&iter, hash_table); + + while (g_hash_table_iter_next (&iter, &key, &value)) { + const CamelSummaryMessageID *message_id; + CamelDataWrapper *content; + CamelMessageFlags flags; + CamelMessageInfo *info; + CamelStream *stream; + GByteArray *buffer; + gboolean duplicate; + gssize n_bytes; + gchar *digest; + + info = camel_folder_get_message_info (folder, key); + message_id = camel_message_info_message_id (info); + flags = camel_message_info_flags (info); + + /* Skip messages marked for deletion. */ + if (flags & CAMEL_MESSAGE_DELETED) { + g_queue_push_tail (&trash, key); + camel_message_info_free (info); + continue; + } + + /* Generate a digest string from the message's content. */ + + content = camel_medium_get_content (CAMEL_MEDIUM (value)); + + if (content == NULL) { + g_queue_push_tail (&trash, key); + camel_message_info_free (info); + continue; + } + + stream = camel_stream_mem_new (); + + n_bytes = camel_data_wrapper_decode_to_stream_sync ( + content, stream, cancellable, error); + + if (n_bytes < 0) { + camel_message_info_free (info); + g_object_unref (stream); + goto fail; + } + + /* The CamelStreamMem owns the buffer. */ + buffer = camel_stream_mem_get_byte_array ( + CAMEL_STREAM_MEM (stream)); + g_return_val_if_fail (buffer != NULL, NULL); + + digest = g_compute_checksum_for_data ( + G_CHECKSUM_SHA256, buffer->data, buffer->len); + + g_object_unref (stream); + + /* Determine if the message a duplicate. */ + + value = g_hash_table_lookup (unique_ids, &message_id->id.id); + duplicate = (value != NULL) && g_str_equal (digest, value); + + if (duplicate) + g_free (digest); + else { + gint64 *v_int64; + + /* XXX Might be better to create a GArray + * of 64-bit integers and have the hash + * table keys point to array elements. */ + v_int64 = g_new0 (gint64, 1); + *v_int64 = (gint64) message_id->id.id; + + g_hash_table_insert (unique_ids, v_int64, digest); + g_queue_push_tail (&trash, key); + } + + camel_message_info_free (info); + } + + /* Delete all non-duplicate messages from the hash table. */ + while ((key = g_queue_pop_head (&trash)) != NULL) + g_hash_table_remove (hash_table, key); + + goto exit; + +fail: + g_hash_table_destroy (hash_table); + hash_table = NULL; + +exit: + camel_operation_pop_message (cancellable); + + g_hash_table_destroy (unique_ids); + + return hash_table; +} + +void +e_mail_folder_find_duplicate_messages (CamelFolder *folder, + GPtrArray *message_uids, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *context; + + g_return_if_fail (CAMEL_IS_FOLDER (folder)); + g_return_if_fail (message_uids != NULL); + + context = g_slice_new0 (AsyncContext); + context->ptr_array = g_ptr_array_ref (message_uids); + + simple = g_simple_async_result_new ( + G_OBJECT (folder), callback, user_data, + e_mail_folder_find_duplicate_messages); + + g_simple_async_result_set_op_res_gpointer ( + simple, context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, mail_folder_find_duplicate_messages_thread, + io_priority, cancellable); + + g_object_unref (simple); +} + +GHashTable * +e_mail_folder_find_duplicate_messages_finish (CamelFolder *folder, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + AsyncContext *context; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (folder), + e_mail_folder_find_duplicate_messages), NULL); + + simple = G_SIMPLE_ASYNC_RESULT (result); + context = g_simple_async_result_get_op_res_gpointer (simple); + + if (g_simple_async_result_propagate_error (simple, error)) + return NULL; + + return g_hash_table_ref (context->hash_table); +} + +static void +mail_folder_get_multiple_messages_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + AsyncContext *context; + GError *error = NULL; + + context = g_simple_async_result_get_op_res_gpointer (simple); + + context->hash_table = e_mail_folder_get_multiple_messages_sync ( + CAMEL_FOLDER (object), context->ptr_array, + cancellable, &error); + + if (error != NULL) + g_simple_async_result_take_error (simple, error); +} + +GHashTable * +e_mail_folder_get_multiple_messages_sync (CamelFolder *folder, + GPtrArray *message_uids, + GCancellable *cancellable, + GError **error) +{ + GHashTable *hash_table; + CamelMimeMessage *message; + guint ii; + + g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL); + g_return_val_if_fail (message_uids != NULL, NULL); + + camel_operation_push_message ( + cancellable, + ngettext ( + "Retrieving %d message", + "Retrieving %d messages", + message_uids->len), + message_uids->len); + + hash_table = g_hash_table_new_full ( + (GHashFunc) g_str_hash, + (GEqualFunc) g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) g_object_unref); + + /* This is an all or nothing operation. Destroy the + * hash table if we fail to retrieve any message. */ + + for (ii = 0; ii < message_uids->len; ii++) { + const gchar *uid; + gint percent; + + uid = g_ptr_array_index (message_uids, ii); + percent = ((ii + 1) * 100) / message_uids->len; + + message = camel_folder_get_message_sync ( + folder, uid, cancellable, error); + + camel_operation_progress (cancellable, percent); + + if (CAMEL_IS_MIME_MESSAGE (message)) { + g_hash_table_insert ( + hash_table, g_strdup (uid), message); + } else { + g_hash_table_destroy (hash_table); + hash_table = NULL; + break; + } + } + + camel_operation_pop_message (cancellable); + + return hash_table; +} + +void +e_mail_folder_get_multiple_messages (CamelFolder *folder, + GPtrArray *message_uids, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *context; + + g_return_if_fail (CAMEL_IS_FOLDER (folder)); + g_return_if_fail (message_uids != NULL); + + context = g_slice_new0 (AsyncContext); + context->ptr_array = g_ptr_array_ref (message_uids); + + simple = g_simple_async_result_new ( + G_OBJECT (folder), callback, user_data, + e_mail_folder_get_multiple_messages); + + g_simple_async_result_set_op_res_gpointer ( + simple, context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, mail_folder_get_multiple_messages_thread, + io_priority, cancellable); + + g_object_unref (simple); +} + +GHashTable * +e_mail_folder_get_multiple_messages_finish (CamelFolder *folder, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + AsyncContext *context; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (folder), + e_mail_folder_get_multiple_messages), NULL); + + simple = G_SIMPLE_ASYNC_RESULT (result); + context = g_simple_async_result_get_op_res_gpointer (simple); + + if (g_simple_async_result_propagate_error (simple, error)) + return NULL; + + return g_hash_table_ref (context->hash_table); +} + +static void +mail_folder_remove_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + GError *error = NULL; + + e_mail_folder_remove_sync ( + CAMEL_FOLDER (object), cancellable, &error); + + if (error != NULL) + g_simple_async_result_take_error (simple, error); +} + +static gboolean +mail_folder_remove_recursive (CamelStore *store, + CamelFolderInfo *folder_info, + GCancellable *cancellable, + GError **error) +{ + gboolean success = TRUE; + + while (folder_info != NULL) { + CamelFolder *folder; + + if (folder_info->child != NULL) { + success = mail_folder_remove_recursive ( + store, folder_info->child, cancellable, error); + if (!success) + break; + } + + folder = camel_store_get_folder_sync ( + store, folder_info->full_name, 0, cancellable, error); + if (folder == NULL) { + success = FALSE; + break; + } + + if (!CAMEL_IS_VEE_FOLDER (folder)) { + GPtrArray *uids; + guint ii; + + /* Delete every message in this folder, + * then expunge it. */ + + camel_folder_freeze (folder); + + uids = camel_folder_get_uids (folder); + + for (ii = 0; ii < uids->len; ii++) + camel_folder_delete_message ( + folder, uids->pdata[ii]); + + camel_folder_free_uids (folder, uids); + + success = camel_folder_synchronize_sync ( + folder, TRUE, cancellable, error); + + camel_folder_thaw (folder); + } + + g_object_unref (folder); + + if (!success) + break; + + /* If the store supports subscriptions, + * then unsubscribe from this folder. */ + if (CAMEL_IS_SUBSCRIBABLE (store)) { + success = camel_subscribable_unsubscribe_folder_sync ( + CAMEL_SUBSCRIBABLE (store), + folder_info->full_name, + cancellable, error); + if (!success) + break; + } + + success = camel_store_delete_folder_sync ( + store, folder_info->full_name, cancellable, error); + if (!success) + break; + + folder_info = folder_info->next; + } + + return success; +} + +static void +follow_cancel_cb (GCancellable *cancellable, + GCancellable *transparent_cancellable) +{ + g_cancellable_cancel (transparent_cancellable); +} + +gboolean +e_mail_folder_remove_sync (CamelFolder *folder, + GCancellable *cancellable, + GError **error) +{ + CamelFolderInfo *folder_info; + CamelFolderInfo *to_remove; + CamelFolderInfo *next = NULL; + CamelStore *parent_store; + const gchar *full_name; + gboolean success = TRUE; + GCancellable *transparent_cancellable = NULL; + gulong cbid = 0; + + g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); + + full_name = camel_folder_get_full_name (folder); + parent_store = camel_folder_get_parent_store (folder); + + folder_info = camel_store_get_folder_info_sync ( + parent_store, full_name, + CAMEL_STORE_FOLDER_INFO_FAST | + CAMEL_STORE_FOLDER_INFO_RECURSIVE | + CAMEL_STORE_FOLDER_INFO_SUBSCRIBED, + cancellable, error); + + if (folder_info == NULL) + return FALSE; + + to_remove = folder_info; + + /* For cases when the top-level folder_info contains siblings, + * such as when full_name contains a wildcard letter, compare + * the folder name against folder_info->full_name to avoid + * removing more folders than requested. */ + if (folder_info->next != NULL) { + while (to_remove != NULL) { + if (g_strcmp0 (to_remove->full_name, full_name) == 0) + break; + to_remove = to_remove->next; + } + + /* XXX Should we set a GError and return FALSE here? */ + if (to_remove == NULL) { + g_warning ( + "%s: Failed to find folder '%s'", + G_STRFUNC, full_name); + camel_store_free_folder_info ( + parent_store, folder_info); + return TRUE; + } + + /* Prevent iterating over siblings. */ + next = to_remove->next; + to_remove->next = NULL; + } + + camel_operation_push_message ( + cancellable, _("Removing folder '%s'"), + camel_folder_get_full_name (folder)); + + if (cancellable) { + transparent_cancellable = g_cancellable_new (); + cbid = g_cancellable_connect (cancellable, G_CALLBACK (follow_cancel_cb), transparent_cancellable, NULL); + } + + success = mail_folder_remove_recursive ( + parent_store, to_remove, transparent_cancellable, error); + + if (transparent_cancellable) { + g_cancellable_disconnect (cancellable, cbid); + g_object_unref (transparent_cancellable); + } + + camel_operation_pop_message (cancellable); + + /* Restore the folder_info tree to its original + * state so we don't leak folder_info nodes. */ + to_remove->next = next; + + camel_store_free_folder_info (parent_store, folder_info); + + return success; +} + +void +e_mail_folder_remove (CamelFolder *folder, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + + g_return_if_fail (CAMEL_IS_FOLDER (folder)); + + simple = g_simple_async_result_new ( + G_OBJECT (folder), callback, + user_data, e_mail_folder_remove); + + g_simple_async_result_run_in_thread ( + simple, mail_folder_remove_thread, + io_priority, cancellable); + + g_object_unref (simple); +} + +gboolean +e_mail_folder_remove_finish (CamelFolder *folder, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (folder), + e_mail_folder_remove), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + + /* Assume success unless a GError is set. */ + return !g_simple_async_result_propagate_error (simple, error); +} + +static void +mail_folder_remove_attachments_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + AsyncContext *context; + GError *error = NULL; + + context = g_simple_async_result_get_op_res_gpointer (simple); + + e_mail_folder_remove_attachments_sync ( + CAMEL_FOLDER (object), context->ptr_array, + cancellable, &error); + + if (error != NULL) + g_simple_async_result_take_error (simple, error); +} + +/* Helper for e_mail_folder_remove_attachments_sync() */ +static gboolean +mail_folder_strip_message (CamelFolder *folder, + CamelMimeMessage *message, + const gchar *message_uid, + GCancellable *cancellable, + GError **error) +{ + CamelDataWrapper *content; + CamelMultipart *multipart; + gboolean modified = FALSE; + gboolean success = TRUE; + guint ii, n_parts; + + content = camel_medium_get_content (CAMEL_MEDIUM (message)); + + if (!CAMEL_IS_MULTIPART (content)) + return TRUE; + + multipart = CAMEL_MULTIPART (content); + n_parts = camel_multipart_get_number (multipart); + + /* Replace MIME parts with "attachment" or "inline" dispositions + * with a small "text/plain" part saying the file was removed. */ + for (ii = 0; ii < n_parts; ii++) { + CamelMimePart *mime_part; + const gchar *disposition; + gboolean is_attachment; + + mime_part = camel_multipart_get_part (multipart, ii); + disposition = camel_mime_part_get_disposition (mime_part); + + is_attachment = + (g_strcmp0 (disposition, "attachment") == 0) || + (g_strcmp0 (disposition, "inline") == 0); + + if (is_attachment) { + const gchar *filename; + const gchar *content_type; + gchar *content; + + disposition = "inline"; + content_type = "text/plain"; + filename = camel_mime_part_get_filename (mime_part); + + if (filename != NULL && *filename != '\0') + content = g_strdup_printf ( + _("File \"%s\" has been removed."), + filename); + else + content = g_strdup ( + _("File has been removed.")); + + camel_mime_part_set_content ( + mime_part, content, + strlen (content), content_type); + camel_mime_part_set_content_type ( + mime_part, content_type); + camel_mime_part_set_disposition ( + mime_part, disposition); + + modified = TRUE; + } + } + + /* Append the modified message with removed attachments to + * the folder and mark the original message for deletion. */ + if (modified) { + CamelMessageInfo *orig_info; + CamelMessageInfo *copy_info; + CamelMessageFlags flags; + + orig_info = + camel_folder_get_message_info (folder, message_uid); + copy_info = + camel_message_info_new_from_header ( + NULL, CAMEL_MIME_PART (message)->headers); + + flags = camel_folder_get_message_flags (folder, message_uid); + camel_message_info_set_flags (copy_info, flags, flags); + + success = camel_folder_append_message_sync ( + folder, message, copy_info, NULL, cancellable, error); + if (success) + camel_message_info_set_flags ( + orig_info, + CAMEL_MESSAGE_DELETED, + CAMEL_MESSAGE_DELETED); + + camel_folder_free_message_info (folder, orig_info); + camel_message_info_free (copy_info); + } + + return success; +} + +gboolean +e_mail_folder_remove_attachments_sync (CamelFolder *folder, + GPtrArray *message_uids, + GCancellable *cancellable, + GError **error) +{ + gboolean success = TRUE; + guint ii; + + g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); + g_return_val_if_fail (message_uids != NULL, FALSE); + + camel_folder_freeze (folder); + + camel_operation_push_message (cancellable, _("Removing attachments")); + + for (ii = 0; success && ii < message_uids->len; ii++) { + CamelMimeMessage *message; + const gchar *uid; + gint percent; + + uid = g_ptr_array_index (message_uids, ii); + + message = camel_folder_get_message_sync ( + folder, uid, cancellable, error); + + if (message == NULL) { + success = FALSE; + break; + } + + success = mail_folder_strip_message ( + folder, message, uid, cancellable, error); + + percent = ((ii + 1) * 100) / message_uids->len; + camel_operation_progress (cancellable, percent); + + g_object_unref (message); + } + + camel_operation_pop_message (cancellable); + + if (success) + camel_folder_synchronize_sync ( + folder, FALSE, cancellable, error); + + camel_folder_thaw (folder); + + return success; +} + +void +e_mail_folder_remove_attachments (CamelFolder *folder, + GPtrArray *message_uids, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *context; + + g_return_if_fail (CAMEL_IS_FOLDER (folder)); + g_return_if_fail (message_uids != NULL); + + context = g_slice_new0 (AsyncContext); + context->ptr_array = g_ptr_array_ref (message_uids); + + simple = g_simple_async_result_new ( + G_OBJECT (folder), callback, user_data, + e_mail_folder_remove_attachments); + + g_simple_async_result_set_op_res_gpointer ( + simple, context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, mail_folder_remove_attachments_thread, + io_priority, cancellable); + + g_object_unref (simple); +} + +gboolean +e_mail_folder_remove_attachments_finish (CamelFolder *folder, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (folder), + e_mail_folder_remove_attachments), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + + /* Assume success unless a GError is set. */ + return !g_simple_async_result_propagate_error (simple, error); +} + +static void +mail_folder_save_messages_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + AsyncContext *context; + GError *error = NULL; + + context = g_simple_async_result_get_op_res_gpointer (simple); + + e_mail_folder_save_messages_sync ( + CAMEL_FOLDER (object), context->ptr_array, + context->destination, cancellable, &error); + + if (error != NULL) + g_simple_async_result_take_error (simple, error); +} + +/* Helper for e_mail_folder_save_messages_sync() */ +static void +mail_folder_save_prepare_part (CamelMimePart *mime_part) +{ + CamelDataWrapper *content; + + content = camel_medium_get_content (CAMEL_MEDIUM (mime_part)); + + if (content == NULL) + return; + + if (CAMEL_IS_MULTIPART (content)) { + guint n_parts, ii; + + n_parts = camel_multipart_get_number ( + CAMEL_MULTIPART (content)); + for (ii = 0; ii < n_parts; ii++) { + mime_part = camel_multipart_get_part ( + CAMEL_MULTIPART (content), ii); + mail_folder_save_prepare_part (mime_part); + } + + } else if (CAMEL_IS_MIME_MESSAGE (content)) { + mail_folder_save_prepare_part (CAMEL_MIME_PART (content)); + + } else { + CamelContentType *type; + + /* Save textual parts as 8-bit, not encoded. */ + type = camel_data_wrapper_get_mime_type_field (content); + if (camel_content_type_is (type, "text", "*")) + camel_mime_part_set_encoding ( + mime_part, CAMEL_TRANSFER_ENCODING_8BIT); + } +} + +gboolean +e_mail_folder_save_messages_sync (CamelFolder *folder, + GPtrArray *message_uids, + GFile *destination, + GCancellable *cancellable, + GError **error) +{ + GFileOutputStream *file_output_stream; + GByteArray *byte_array; + CamelStream *base_stream; + gboolean success = TRUE; + guint ii; + + g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); + g_return_val_if_fail (message_uids != NULL, FALSE); + g_return_val_if_fail (G_IS_FILE (destination), FALSE); + + /* Need at least one message UID to save. */ + g_return_val_if_fail (message_uids->len > 0, FALSE); + + camel_operation_push_message ( + cancellable, ngettext ( + "Saving %d message", + "Saving %d messages", + message_uids->len), + message_uids->len); + + file_output_stream = g_file_replace ( + destination, NULL, FALSE, + G_FILE_CREATE_PRIVATE | + G_FILE_CREATE_REPLACE_DESTINATION, + cancellable, error); + + if (file_output_stream == NULL) { + camel_operation_pop_message (cancellable); + return FALSE; + } + + /* CamelStreamMem takes ownership of the GByteArray. */ + byte_array = g_byte_array_new (); + base_stream = camel_stream_mem_new_with_byte_array (byte_array); + + for (ii = 0; ii < message_uids->len; ii++) { + CamelMimeMessage *message; + CamelMimeFilter *filter; + CamelStream *stream; + const gchar *uid; + gchar *from_line; + gint percent; + gint retval; + + uid = g_ptr_array_index (message_uids, ii); + + message = camel_folder_get_message_sync ( + folder, uid, cancellable, error); + if (message == NULL) { + success = FALSE; + goto exit; + } + + mail_folder_save_prepare_part (CAMEL_MIME_PART (message)); + + from_line = camel_mime_message_build_mbox_from (message); + g_return_val_if_fail (from_line != NULL, FALSE); + + success = g_output_stream_write_all ( + G_OUTPUT_STREAM (file_output_stream), + from_line, strlen (from_line), NULL, + cancellable, error); + + g_free (from_line); + + if (!success) { + g_object_unref (message); + goto exit; + } + + filter = camel_mime_filter_from_new (); + stream = camel_stream_filter_new (base_stream); + camel_stream_filter_add (CAMEL_STREAM_FILTER (stream), filter); + + retval = camel_data_wrapper_write_to_stream_sync ( + CAMEL_DATA_WRAPPER (message), + stream, cancellable, error); + + g_object_unref (filter); + g_object_unref (stream); + + if (retval == -1) { + g_object_unref (message); + goto exit; + } + + g_byte_array_append (byte_array, (guint8 *) "\n", 1); + + success = g_output_stream_write_all ( + G_OUTPUT_STREAM (file_output_stream), + byte_array->data, byte_array->len, + NULL, cancellable, error); + + if (!success) { + g_object_unref (message); + goto exit; + } + + percent = ((ii + 1) * 100) / message_uids->len; + camel_operation_progress (cancellable, percent); + + /* Flush the buffer for the next message. + * For memory streams this never fails. */ + g_seekable_seek ( + G_SEEKABLE (base_stream), + 0, G_SEEK_SET, NULL, NULL); + + g_object_unref (message); + } + +exit: + g_object_unref (file_output_stream); + g_object_unref (base_stream); + + camel_operation_pop_message (cancellable); + + if (!success) { + /* Try deleting the destination file. */ + g_file_delete (destination, NULL, NULL); + } + + return success; +} + +void +e_mail_folder_save_messages (CamelFolder *folder, + GPtrArray *message_uids, + GFile *destination, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *context; + + g_return_if_fail (CAMEL_IS_FOLDER (folder)); + g_return_if_fail (message_uids != NULL); + g_return_if_fail (G_IS_FILE (destination)); + + /* Need at least one message UID to save. */ + g_return_if_fail (message_uids->len > 0); + + context = g_slice_new0 (AsyncContext); + context->ptr_array = g_ptr_array_ref (message_uids); + context->destination = g_object_ref (destination); + + simple = g_simple_async_result_new ( + G_OBJECT (folder), callback, user_data, + e_mail_folder_save_messages); + + g_simple_async_result_set_op_res_gpointer ( + simple, context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, mail_folder_save_messages_thread, + io_priority, cancellable); + + g_object_unref (simple); +} + +gboolean +e_mail_folder_save_messages_finish (CamelFolder *folder, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (folder), + e_mail_folder_save_messages), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + + /* Assume success unless a GError is set. */ + return !g_simple_async_result_propagate_error (simple, error); +} + +/** + * e_mail_folder_uri_build: + * @store: a #CamelStore + * @folder_name: a folder name + * + * Builds a folder URI string from @store and @folder_name. + * + * Returns: a newly-allocated folder URI string + **/ +gchar * +e_mail_folder_uri_build (CamelStore *store, + const gchar *folder_name) +{ + const gchar *uid; + gchar *encoded_name; + gchar *encoded_uid; + gchar *uri; + + g_return_val_if_fail (CAMEL_IS_STORE (store), NULL); + g_return_val_if_fail (folder_name != NULL, NULL); + + /* Skip the leading slash, if present. */ + if (*folder_name == '/') + folder_name++; + + uid = camel_service_get_uid (CAMEL_SERVICE (store)); + + encoded_uid = camel_url_encode (uid, ":;@/"); + encoded_name = camel_url_encode (folder_name, "#"); + + uri = g_strdup_printf ("folder://%s/%s", encoded_uid, encoded_name); + + g_free (encoded_uid); + g_free (encoded_name); + + return uri; +} + +/** + * e_mail_folder_uri_parse: + * @session: a #CamelSession + * @folder_uri: a folder URI + * @out_store: return location for a #CamelStore, or %NULL + * @out_folder_name: return location for a folder name, or %NULL + * @error: return location for a #GError, or %NULL + * + * Parses a folder URI generated by e_mail_folder_uri_build() and + * returns the corresponding #CamelStore instance in @out_store and + * folder name string in @out_folder_name. If the URI is malformed + * or no corresponding store exists, the function sets @error and + * returns %FALSE. + * + * If the function is able to parse the URI, the #CamelStore instance + * set in @out_store should be unreferenced with g_object_unref() when + * done with it, and the folder name string set in @out_folder_name + * should be freed with g_free(). + * + * The function also handles older style URIs, such as ones where the + * #CamelStore's #CamelStore::uri string was embedded directly in the + * folder URI, and account-based URIs that used an "email://" prefix. + * + * Returns: %TRUE if @folder_uri could be parsed, %FALSE otherwise + **/ +gboolean +e_mail_folder_uri_parse (CamelSession *session, + const gchar *folder_uri, + CamelStore **out_store, + gchar **out_folder_name, + GError **error) +{ + CamelURL *url; + CamelService *service = NULL; + gchar *folder_name = NULL; + gboolean success = FALSE; + + g_return_val_if_fail (CAMEL_IS_SESSION (session), FALSE); + g_return_val_if_fail (folder_uri != NULL, FALSE); + + url = camel_url_new (folder_uri, error); + if (url == NULL) + return FALSE; + + /* Current URI Format: 'folder://' STORE_UID '/' FOLDER_PATH */ + if (g_strcmp0 (url->protocol, "folder") == 0) { + + if (url->host != NULL) { + gchar *uid; + + if (url->user == NULL || *url->user == '\0') + uid = g_strdup (url->host); + else + uid = g_strconcat ( + url->user, "@", url->host, NULL); + + service = camel_session_get_service (session, uid); + g_free (uid); + } + + if (url->path != NULL && *url->path == '/') + folder_name = camel_url_decode_path (url->path + 1); + + /* This style was used to reference accounts by UID before + * CamelServices themselves had UIDs. Some examples are: + * + * Special cases: + * + * 'email://local@local/' FOLDER_PATH + * 'email://vfolder@local/' FOLDER_PATH + * + * General case: + * + * 'email://' ACCOUNT_UID '/' FOLDER_PATH + * + * Note: ACCOUNT_UID is now equivalent to STORE_UID, and + * the STORE_UIDs for the special cases are 'local' + * and 'vfolder'. + */ + } else if (g_strcmp0 (url->protocol, "email") == 0) { + gchar *uid = NULL; + + /* Handle the special cases. */ + if (g_strcmp0 (url->host, "local") == 0) { + if (g_strcmp0 (url->user, "local") == 0) + uid = g_strdup ("local"); + if (g_strcmp0 (url->user, "vfolder") == 0) + uid = g_strdup ("vfolder"); + } + + /* Handle the general case. */ + if (uid == NULL && url->host != NULL) { + if (url->user == NULL) + uid = g_strdup (url->host); + else + uid = g_strdup_printf ( + "%s@%s", url->user, url->host); + } + + if (uid != NULL) { + service = camel_session_get_service (session, uid); + g_free (uid); + } + + if (url->path != NULL && *url->path == '/') + folder_name = camel_url_decode_path (url->path + 1); + + /* CamelFolderInfo URIs used to embed the store's URI, so the + * folder name is appended as either a path part or a fragment + * part, depending whether the store's URI used the path part. + * To determine which it is, you have to check the provider + * flags for CAMEL_URL_FRAGMENT_IS_PATH. */ + } else { + service = camel_session_get_service_by_url ( + session, url, CAMEL_PROVIDER_STORE); + + if (CAMEL_IS_STORE (service)) { + CamelProvider *provider; + + provider = camel_service_get_provider (service); + + if (provider->url_flags & CAMEL_URL_FRAGMENT_IS_PATH) + folder_name = g_strdup (url->fragment); + else if (url->path != NULL && *url->path == '/') + folder_name = g_strdup (url->path + 1); + } + } + + if (CAMEL_IS_STORE (service) && folder_name != NULL) { + if (out_store != NULL) + *out_store = g_object_ref (service); + + if (out_folder_name != NULL) { + *out_folder_name = folder_name; + folder_name = NULL; + } + + success = TRUE; + } else { + g_set_error ( + error, CAMEL_FOLDER_ERROR, + CAMEL_FOLDER_ERROR_INVALID, + _("Invalid folder URI '%s'"), + folder_uri); + } + + g_free (folder_name); + + camel_url_free (url); + + return success; +} + +/** + * e_mail_folder_uri_equal: + * @session: a #CamelSession + * @folder_uri_a: a folder URI + * @folder_uri_b: another folder URI + * + * Compares two folder URIs for equality. If either URI is invalid, + * the function returns %FALSE. + * + * Returns: %TRUE if the URIs are equal, %FALSE if not + **/ +gboolean +e_mail_folder_uri_equal (CamelSession *session, + const gchar *folder_uri_a, + const gchar *folder_uri_b) +{ + CamelStore *store_a; + CamelStore *store_b; + CamelStoreClass *class; + gchar *folder_name_a; + gchar *folder_name_b; + gboolean success_a; + gboolean success_b; + gboolean equal = FALSE; + + g_return_val_if_fail (CAMEL_IS_SESSION (session), FALSE); + g_return_val_if_fail (folder_uri_a != NULL, FALSE); + g_return_val_if_fail (folder_uri_b != NULL, FALSE); + + success_a = e_mail_folder_uri_parse ( + session, folder_uri_a, &store_a, &folder_name_a, NULL); + + success_b = e_mail_folder_uri_parse ( + session, folder_uri_b, &store_b, &folder_name_b, NULL); + + if (!success_a || !success_b) + goto exit; + + if (store_a != store_b) + goto exit; + + /* Doesn't matter which store we use since they're the same. */ + class = CAMEL_STORE_GET_CLASS (store_a); + g_return_val_if_fail (class->compare_folder_name != NULL, FALSE); + + equal = class->compare_folder_name (folder_name_a, folder_name_b); + +exit: + if (success_a) { + g_object_unref (store_a); + g_free (folder_name_a); + } + + if (success_b) { + g_object_unref (store_b); + g_free (folder_name_b); + } + + return equal; +} + +/** + * e_mail_folder_uri_from_folder: + * @folder: a #CamelFolder + * + * Convenience function for building a folder URI from a #CamelFolder. + * Free the returned URI string with g_free(). + * + * Returns: a newly-allocated folder URI string + **/ +gchar * +e_mail_folder_uri_from_folder (CamelFolder *folder) +{ + CamelStore *store; + const gchar *folder_name; + + g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL); + + store = camel_folder_get_parent_store (folder); + folder_name = camel_folder_get_full_name (folder); + + return e_mail_folder_uri_build (store, folder_name); +} + +/** + * e_mail_folder_uri_to_markup: + * @session: a #CamelSession + * @folder_uri: a folder URI + * @error: return location for a #GError, or %NULL + * + * Converts @folder_uri to a markup string suitable for displaying to users. + * The string consists of the #CamelStore display name (in bold), followed + * by the folder path. If the URI is malformed or no corresponding store + * exists, the function sets @error and returns %NULL. Free the returned + * string with g_free(). + * + * Returns: a newly-allocated markup string, or %NULL + **/ +gchar * +e_mail_folder_uri_to_markup (CamelSession *session, + const gchar *folder_uri, + GError **error) +{ + CamelStore *store = NULL; + const gchar *display_name; + gchar *folder_name = NULL; + gchar *markup; + gboolean success; + + g_return_val_if_fail (CAMEL_IS_SESSION (session), NULL); + g_return_val_if_fail (folder_uri != NULL, NULL); + + success = e_mail_folder_uri_parse ( + session, folder_uri, &store, &folder_name, error); + + if (!success) + return NULL; + + g_return_val_if_fail (CAMEL_IS_STORE (store), NULL); + g_return_val_if_fail (folder_name != NULL, NULL); + + display_name = camel_service_get_display_name (CAMEL_SERVICE (store)); + + markup = g_markup_printf_escaped ( + "%s : %s", display_name, folder_name); + + g_object_unref (store); + g_free (folder_name); + + return markup; +} diff --git a/libemail-engine/e-mail-folder-utils.h b/libemail-engine/e-mail-folder-utils.h new file mode 100644 index 0000000000..9e8dd0f050 --- /dev/null +++ b/libemail-engine/e-mail-folder-utils.h @@ -0,0 +1,164 @@ +/* + * e-mail-folder-utils.h + * + * 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 + * + */ + +#ifndef E_MAIL_FOLDER_UTILS_H +#define E_MAIL_FOLDER_UTILS_H + +/* CamelFolder wrappers with Evolution-specific policies. */ + +#include + +G_BEGIN_DECLS + +gboolean e_mail_folder_append_message_sync + (CamelFolder *folder, + CamelMimeMessage *message, + CamelMessageInfo *info, + gchar **appended_uid, + GCancellable *cancellable, + GError **error); +void e_mail_folder_append_message (CamelFolder *folder, + CamelMimeMessage *message, + CamelMessageInfo *info, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean e_mail_folder_append_message_finish + (CamelFolder *folder, + GAsyncResult *result, + gchar **appended_uid, + GError **error); + +CamelMimePart * e_mail_folder_build_attachment_sync + (CamelFolder *folder, + GPtrArray *message_uids, + gchar **fwd_subject, + GCancellable *cancellable, + GError **error); +void e_mail_folder_build_attachment (CamelFolder *folder, + GPtrArray *message_uids, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +CamelMimePart * e_mail_folder_build_attachment_finish + (CamelFolder *folder, + GAsyncResult *result, + gchar **fwd_subject, + GError **error); + +GHashTable * e_mail_folder_find_duplicate_messages_sync + (CamelFolder *folder, + GPtrArray *message_uids, + GCancellable *cancellable, + GError **error); +void e_mail_folder_find_duplicate_messages + (CamelFolder *folder, + GPtrArray *message_uids, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +GHashTable * e_mail_folder_find_duplicate_messages_finish + (CamelFolder *folder, + GAsyncResult *result, + GError **error); + +GHashTable * e_mail_folder_get_multiple_messages_sync + (CamelFolder *folder, + GPtrArray *message_uids, + GCancellable *cancellable, + GError **error); +void e_mail_folder_get_multiple_messages + (CamelFolder *folder, + GPtrArray *message_uids, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +GHashTable * e_mail_folder_get_multiple_messages_finish + (CamelFolder *folder, + GAsyncResult *result, + GError **error); + +gboolean e_mail_folder_remove_sync (CamelFolder *folder, + GCancellable *cancellable, + GError **error); +void e_mail_folder_remove (CamelFolder *folder, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean e_mail_folder_remove_finish (CamelFolder *folder, + GAsyncResult *result, + GError **error); + +gboolean e_mail_folder_remove_attachments_sync + (CamelFolder *folder, + GPtrArray *message_uids, + GCancellable *cancellable, + GError **error); +void e_mail_folder_remove_attachments + (CamelFolder *folder, + GPtrArray *message_uids, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean e_mail_folder_remove_attachments_finish + (CamelFolder *folder, + GAsyncResult *result, + GError **error); + +gboolean e_mail_folder_save_messages_sync + (CamelFolder *folder, + GPtrArray *message_uids, + GFile *destination, + GCancellable *cancellable, + GError **error); +void e_mail_folder_save_messages (CamelFolder *folder, + GPtrArray *message_uids, + GFile *destination, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean e_mail_folder_save_messages_finish + (CamelFolder *folder, + GAsyncResult *result, + GError **error); + +gchar * e_mail_folder_uri_build (CamelStore *store, + const gchar *folder_name); +gboolean e_mail_folder_uri_parse (CamelSession *session, + const gchar *folder_uri, + CamelStore **out_store, + gchar **out_folder_name, + GError **error); +gboolean e_mail_folder_uri_equal (CamelSession *session, + const gchar *folder_uri_a, + const gchar *folder_uri_b); +gchar * e_mail_folder_uri_from_folder (CamelFolder *folder); +gchar * e_mail_folder_uri_to_markup (CamelSession *session, + const gchar *folder_uri, + GError **error); + +G_END_DECLS + +#endif /* E_MAIL_FOLDER_UTILS_H */ diff --git a/libemail-engine/e-mail-junk-filter.c b/libemail-engine/e-mail-junk-filter.c new file mode 100644 index 0000000000..fda8efb163 --- /dev/null +++ b/libemail-engine/e-mail-junk-filter.c @@ -0,0 +1,82 @@ +/* + * e-mail-junk-filter.c + * + * 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 + * + */ + +#include "e-mail-junk-filter.h" + +#include + +G_DEFINE_ABSTRACT_TYPE ( + EMailJunkFilter, + e_mail_junk_filter, + E_TYPE_EXTENSION) + +static void +e_mail_junk_filter_class_init (EMailJunkFilterClass *class) +{ + EExtensionClass *extension_class; + + extension_class = E_EXTENSION_CLASS (class); + extension_class->extensible_type = E_TYPE_MAIL_SESSION; +} + +static void +e_mail_junk_filter_init (EMailJunkFilter *junk_filter) +{ +} + +gboolean +e_mail_junk_filter_available (EMailJunkFilter *junk_filter) +{ + EMailJunkFilterClass *class; + + g_return_val_if_fail (E_IS_MAIL_JUNK_FILTER (junk_filter), FALSE); + + class = E_MAIL_JUNK_FILTER_GET_CLASS (junk_filter); + g_return_val_if_fail (class->available != NULL, FALSE); + + return class->available (junk_filter); +} + +GtkWidget * +e_mail_junk_filter_new_config_widget (EMailJunkFilter *junk_filter) +{ + EMailJunkFilterClass *class; + GtkWidget *widget = NULL; + + g_return_val_if_fail (E_IS_MAIL_JUNK_FILTER (junk_filter), NULL); + + class = E_MAIL_JUNK_FILTER_GET_CLASS (junk_filter); + + if (class->new_config_widget != NULL) + widget = class->new_config_widget (junk_filter); + + return widget; +} + +gint +e_mail_junk_filter_compare (EMailJunkFilter *junk_filter_a, + EMailJunkFilter *junk_filter_b) +{ + EMailJunkFilterClass *class_a; + EMailJunkFilterClass *class_b; + + class_a = E_MAIL_JUNK_FILTER_GET_CLASS (junk_filter_a); + class_b = E_MAIL_JUNK_FILTER_GET_CLASS (junk_filter_b); + + return g_utf8_collate (class_a->display_name, class_b->display_name); +} diff --git a/libemail-engine/e-mail-junk-filter.h b/libemail-engine/e-mail-junk-filter.h new file mode 100644 index 0000000000..74a7840c2d --- /dev/null +++ b/libemail-engine/e-mail-junk-filter.h @@ -0,0 +1,74 @@ +/* + * e-mail-junk-filter.h + * + * 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 + * + */ + +#ifndef E_MAIL_JUNK_FILTER_H +#define E_MAIL_JUNK_FILTER_H + +#include +#include + +/* Standard GObject macros */ +#define E_TYPE_MAIL_JUNK_FILTER \ + (e_mail_junk_filter_get_type ()) +#define E_MAIL_JUNK_FILTER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_MAIL_JUNK_FILTER, EMailJunkFilter)) +#define E_MAIL_JUNK_FILTER_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_MAIL_JUNK_FILTER, EMailJunkFilterClass)) +#define E_IS_MAIL_JUNK_FILTER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_MAIL_JUNK_FILTER)) +#define E_IS_MAIL_JUNK_FILTER_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_MAIL_JUNK_FILTER)) +#define E_MAIL_JUNK_FILTER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_MAIL_JUNK_FILTER, EMailJunkFilterClass)) + +G_BEGIN_DECLS + +typedef struct _EMailJunkFilter EMailJunkFilter; +typedef struct _EMailJunkFilterClass EMailJunkFilterClass; +typedef struct _EMailJunkFilterPrivate EMailJunkFilterPrivate; + +struct _EMailJunkFilter { + EExtension parent; + EMailJunkFilterPrivate *priv; +}; + +struct _EMailJunkFilterClass { + EExtensionClass parent_class; + + const gchar *filter_name; + const gchar *display_name; + + gboolean (*available) (EMailJunkFilter *junk_filter); + GtkWidget * (*new_config_widget) (EMailJunkFilter *junk_filter); +}; + +GType e_mail_junk_filter_get_type (void) G_GNUC_CONST; +gboolean e_mail_junk_filter_available (EMailJunkFilter *junk_filter); +GtkWidget * e_mail_junk_filter_new_config_widget + (EMailJunkFilter *junk_filter); +gint e_mail_junk_filter_compare (EMailJunkFilter *junk_filter_a, + EMailJunkFilter *junk_filter_b); + +G_END_DECLS + +#endif /* E_MAIL_JUNK_FILTER_H */ diff --git a/libemail-engine/e-mail-session-utils.c b/libemail-engine/e-mail-session-utils.c new file mode 100644 index 0000000000..979d15388e --- /dev/null +++ b/libemail-engine/e-mail-session-utils.c @@ -0,0 +1,931 @@ +/* + * e-mail-session-utils.c + * + * 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 + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "e-mail-session-utils.h" + +#include + +#include +#include +#include +#include + +/* X-Mailer header value */ +#define X_MAILER ("Evolution " VERSION SUB_VERSION " " VERSION_COMMENT) + +/* FIXME: Temporary - remove this after we move filter/ to eds */ +#define E_FILTER_SOURCE_OUTGOING "outgoing" + +typedef struct _AsyncContext AsyncContext; + +struct _AsyncContext { + CamelFolder *sent_folder; + + CamelMimeMessage *message; + CamelMessageInfo *info; + + CamelAddress *from; + CamelAddress *recipients; + + CamelFilterDriver *driver; + + GCancellable *cancellable; + gint io_priority; + + /* X-Evolution headers */ + struct _camel_header_raw *xev; + + GPtrArray *post_to_uris; + + gchar *folder_uri; + gchar *message_uid; + gchar *transport_uid; + gchar *sent_folder_uri; +}; + +static void +async_context_free (AsyncContext *context) +{ + if (context->sent_folder != NULL) + g_object_unref (context->sent_folder); + + if (context->message != NULL) + g_object_unref (context->message); + + if (context->info != NULL) + camel_message_info_free (context->info); + + if (context->from != NULL) + g_object_unref (context->from); + + if (context->recipients != NULL) + g_object_unref (context->recipients); + + if (context->driver != NULL) + g_object_unref (context->driver); + + if (context->cancellable != NULL) { + camel_operation_pop_message (context->cancellable); + g_object_unref (context->cancellable); + } + + if (context->xev != NULL) + camel_header_raw_clear (&context->xev); + + if (context->post_to_uris != NULL) { + g_ptr_array_foreach ( + context->post_to_uris, (GFunc) g_free, NULL); + g_ptr_array_free (context->post_to_uris, TRUE); + } + + g_free (context->folder_uri); + g_free (context->message_uid); + g_free (context->transport_uid); + g_free (context->sent_folder_uri); + + g_slice_free (AsyncContext, context); +} + +GQuark +e_mail_error_quark (void) +{ + static GQuark quark = 0; + + if (G_UNLIKELY (quark == 0)) { + const gchar *string = "e-mail-error-quark"; + quark = g_quark_from_static_string (string); + } + + return quark; +} + +static void +mail_session_handle_draft_headers_thread (GSimpleAsyncResult *simple, + EMailSession *session, + GCancellable *cancellable) +{ + AsyncContext *context; + GError *error = NULL; + + context = g_simple_async_result_get_op_res_gpointer (simple); + + e_mail_session_handle_draft_headers_sync ( + session, context->message, cancellable, &error); + + if (error != NULL) + g_simple_async_result_take_error (simple, error); +} + +gboolean +e_mail_session_handle_draft_headers_sync (EMailSession *session, + CamelMimeMessage *message, + GCancellable *cancellable, + GError **error) +{ + CamelFolder *folder; + CamelMedium *medium; + const gchar *folder_uri; + const gchar *message_uid; + const gchar *header_name; + gboolean success; + + g_return_val_if_fail (E_IS_MAIL_SESSION (session), FALSE); + g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), FALSE); + + medium = CAMEL_MEDIUM (message); + + header_name = "X-Evolution-Draft-Folder"; + folder_uri = camel_medium_get_header (medium, header_name); + + header_name = "X-Evolution-Draft-Message"; + message_uid = camel_medium_get_header (medium, header_name); + + /* Don't report errors about missing X-Evolution-Draft + * headers. These headers are optional, so their absence + * is handled by doing nothing. */ + if (folder_uri == NULL || message_uid == NULL) + return TRUE; + + folder = e_mail_session_uri_to_folder_sync ( + session, folder_uri, 0, cancellable, error); + + if (folder == NULL) + return FALSE; + + camel_folder_set_message_flags ( + folder, message_uid, + CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_SEEN, + CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_SEEN); + + success = camel_folder_synchronize_message_sync ( + folder, message_uid, cancellable, error); + + g_object_unref (folder); + + return success; +} + +void +e_mail_session_handle_draft_headers (EMailSession *session, + CamelMimeMessage *message, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *context; + + g_return_if_fail (E_IS_MAIL_SESSION (session)); + g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message)); + + context = g_slice_new0 (AsyncContext); + context->message = g_object_ref (message); + + simple = g_simple_async_result_new ( + G_OBJECT (session), callback, user_data, + e_mail_session_handle_draft_headers); + + g_simple_async_result_set_op_res_gpointer ( + simple, context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, (GSimpleAsyncThreadFunc) + mail_session_handle_draft_headers_thread, + io_priority, cancellable); + + g_object_unref (simple); +} + +gboolean +e_mail_session_handle_draft_headers_finish (EMailSession *session, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (session), + e_mail_session_handle_draft_headers), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + + /* Assume success unless a GError is set. */ + return !g_simple_async_result_propagate_error (simple, error); +} + +static void +mail_session_handle_source_headers_thread (GSimpleAsyncResult *simple, + EMailSession *session, + GCancellable *cancellable) +{ + AsyncContext *context; + GError *error = NULL; + + context = g_simple_async_result_get_op_res_gpointer (simple); + + e_mail_session_handle_source_headers_sync ( + session, context->message, cancellable, &error); + + if (error != NULL) + g_simple_async_result_take_error (simple, error); +} + +gboolean +e_mail_session_handle_source_headers_sync (EMailSession *session, + CamelMimeMessage *message, + GCancellable *cancellable, + GError **error) +{ + CamelFolder *folder; + CamelMedium *medium; + CamelMessageFlags flags = 0; + const gchar *folder_uri; + const gchar *message_uid; + const gchar *flag_string; + const gchar *header_name; + gboolean success; + guint length, ii; + gchar **tokens; + gchar *string; + + g_return_val_if_fail (E_IS_MAIL_SESSION (session), FALSE); + g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), FALSE); + + medium = CAMEL_MEDIUM (message); + + header_name = "X-Evolution-Source-Folder"; + folder_uri = camel_medium_get_header (medium, header_name); + + header_name = "X-Evolution-Source-Message"; + message_uid = camel_medium_get_header (medium, header_name); + + header_name = "X-Evolution-Source-Flags"; + flag_string = camel_medium_get_header (medium, header_name); + + /* Don't report errors about missing X-Evolution-Source + * headers. These headers are optional, so their absence + * is handled by doing nothing. */ + if (folder_uri == NULL || message_uid == NULL || flag_string == NULL) + return TRUE; + + /* Convert the flag string to CamelMessageFlags. */ + + string = g_strstrip (g_strdup (flag_string)); + tokens = g_strsplit (string, " ", 0); + g_free (string); + + /* If tokens is NULL, a length of 0 will skip the loop. */ + length = (tokens != NULL) ? g_strv_length (tokens) : 0; + + for (ii = 0; ii < length; ii++) { + /* Note: We're only checking for flags known to + * be used in X-Evolution-Source-Flags headers. + * Add more as needed. */ + if (g_strcmp0 (tokens[ii], "ANSWERED") == 0) + flags |= CAMEL_MESSAGE_ANSWERED; + else if (g_strcmp0 (tokens[ii], "ANSWERED_ALL") == 0) + flags |= CAMEL_MESSAGE_ANSWERED_ALL; + else if (g_strcmp0 (tokens[ii], "FORWARDED") == 0) + flags |= CAMEL_MESSAGE_FORWARDED; + else if (g_strcmp0 (tokens[ii], "SEEN") == 0) + flags |= CAMEL_MESSAGE_SEEN; + else + g_warning ( + "Unknown flag '%s' in %s", + tokens[ii], header_name); + } + + g_strfreev (tokens); + + folder = e_mail_session_uri_to_folder_sync ( + session, folder_uri, 0, cancellable, error); + + if (folder == NULL) + return FALSE; + + camel_folder_set_message_flags ( + folder, message_uid, flags, flags); + + success = camel_folder_synchronize_message_sync ( + folder, message_uid, cancellable, error); + + g_object_unref (folder); + + return success; +} + +void +e_mail_session_handle_source_headers (EMailSession *session, + CamelMimeMessage *message, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *context; + + g_return_if_fail (E_IS_MAIL_SESSION (session)); + g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message)); + + context = g_slice_new0 (AsyncContext); + context->message = g_object_ref (message); + + simple = g_simple_async_result_new ( + G_OBJECT (session), callback, user_data, + e_mail_session_handle_source_headers); + + g_simple_async_result_set_op_res_gpointer ( + simple, context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, (GSimpleAsyncThreadFunc) + mail_session_handle_source_headers_thread, + io_priority, cancellable); + + g_object_unref (simple); +} + +gboolean +e_mail_session_handle_source_headers_finish (EMailSession *session, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (session), + e_mail_session_handle_draft_headers), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + + /* Assume success unless a GError is set. */ + return !g_simple_async_result_propagate_error (simple, error); +} + +static void +mail_session_send_to_thread (GSimpleAsyncResult *simple, + EMailSession *session, + GCancellable *cancellable) +{ + AsyncContext *context; + CamelFolder *local_sent_folder; + GString *error_messages; + gboolean copy_to_sent = TRUE; + guint ii; + GError *error = NULL; + + context = g_simple_async_result_get_op_res_gpointer (simple); + + /* Send the message to all recipients. */ + if (camel_address_length (context->recipients) > 0) { + CamelProvider *provider; + CamelService *service; + gboolean did_connect = FALSE; + + service = camel_session_get_service ( + CAMEL_SESSION (session), context->transport_uid); + + if (!CAMEL_IS_TRANSPORT (service)) { + g_simple_async_result_set_error (simple, + CAMEL_SERVICE_ERROR, + CAMEL_SERVICE_ERROR_URL_INVALID, + _("Cannot get transport for account '%s'"), + context->transport_uid); + return; + } + + if (camel_service_get_connection_status (service) != CAMEL_SERVICE_CONNECTED) { + did_connect = TRUE; + + /* XXX This API does not allow for cancellation. */ + if (!em_utils_connect_service_sync (service, cancellable, &error)) { + g_simple_async_result_take_error (simple, error); + return; + } + } + + provider = camel_service_get_provider (service); + + if (provider->flags & CAMEL_PROVIDER_DISABLE_SENT_FOLDER) + copy_to_sent = FALSE; + + camel_transport_send_to_sync ( + CAMEL_TRANSPORT (service), + context->message, context->from, + context->recipients, cancellable, &error); + + if (did_connect) + em_utils_disconnect_service_sync ( + service, error == NULL, + cancellable, error ? NULL : &error); + + if (error != NULL) { + g_simple_async_result_take_error (simple, error); + return; + } + } + + /* Post the message to requested folders. */ + for (ii = 0; ii < context->post_to_uris->len; ii++) { + CamelFolder *folder; + const gchar *folder_uri; + + folder_uri = g_ptr_array_index (context->post_to_uris, ii); + + folder = e_mail_session_uri_to_folder_sync ( + session, folder_uri, 0, cancellable, &error); + + if (error != NULL) { + g_warn_if_fail (folder == NULL); + g_simple_async_result_take_error (simple, error); + return; + } + + g_return_if_fail (CAMEL_IS_FOLDER (folder)); + + camel_folder_append_message_sync ( + folder, context->message, context->info, + NULL, cancellable, &error); + + g_object_unref (folder); + + if (error != NULL) { + g_simple_async_result_take_error (simple, error); + return; + } + } + + /*** Post Processing ***/ + + /* This accumulates error messages during post-processing. */ + error_messages = g_string_sized_new (256); + + mail_tool_restore_xevolution_headers (context->message, context->xev); + + /* Run filters on the outgoing message. */ + if (context->driver != NULL) { + camel_filter_driver_filter_message ( + context->driver, context->message, context->info, + NULL, NULL, NULL, "", cancellable, &error); + + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + goto exit; + + if (error != NULL) { + g_string_append_printf ( + error_messages, + _("Failed to apply outgoing filters: %s"), + error->message); + g_clear_error (&error); + } + } + + if (!copy_to_sent) + goto cleanup; + + /* Append the sent message to a Sent folder. */ + + local_sent_folder = + e_mail_session_get_local_folder ( + session, E_MAIL_LOCAL_FOLDER_SENT); + + /* Try to extract a CamelFolder from the Sent folder URI. */ + if (context->sent_folder_uri != NULL) { + context->sent_folder = e_mail_session_uri_to_folder_sync ( + session, context->sent_folder_uri, 0, + cancellable, &error); + if (error != NULL) { + g_warn_if_fail (context->sent_folder == NULL); + if (error_messages->len > 0) + g_string_append (error_messages, "\n\n"); + g_string_append_printf ( + error_messages, + _("Failed to append to %s: %s\n" + "Appending to local 'Sent' folder instead."), + context->sent_folder_uri, error->message); + g_clear_error (&error); + } + } + + /* Fall back to the local Sent folder. */ + if (context->sent_folder == NULL) + context->sent_folder = g_object_ref (local_sent_folder); + + /* Append the message. */ + camel_folder_append_message_sync ( + context->sent_folder, context->message, + context->info, NULL, cancellable, &error); + + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + goto exit; + + if (error == NULL) + goto cleanup; + + /* If appending to a remote Sent folder failed, + * try appending to the local Sent folder. */ + if (context->sent_folder != local_sent_folder) { + const gchar *description; + + description = camel_folder_get_description ( + context->sent_folder); + + if (error_messages->len > 0) + g_string_append (error_messages, "\n\n"); + g_string_append_printf ( + error_messages, + _("Failed to append to %s: %s\n" + "Appending to local 'Sent' folder instead."), + description, error->message); + g_clear_error (&error); + + camel_folder_append_message_sync ( + local_sent_folder, context->message, + context->info, NULL, cancellable, &error); + } + + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + goto exit; + + /* We can't even append to the local Sent folder? + * In that case just leave the message in Outbox. */ + if (error != NULL) { + if (error_messages->len > 0) + g_string_append (error_messages, "\n\n"); + g_string_append_printf ( + error_messages, + _("Failed to append to local 'Sent' folder: %s"), + error->message); + g_clear_error (&error); + goto exit; + } + +cleanup: + + /* The send operation was successful; ignore cleanup errors. */ + + /* Mark the draft message for deletion, if present. */ + e_mail_session_handle_draft_headers_sync ( + session, context->message, cancellable, &error); + if (error != NULL) { + g_warning ("%s", error->message); + g_clear_error (&error); + } + + /* Set flags on the original source message, if present. + * Source message refers to the message being forwarded + * or replied to. */ + e_mail_session_handle_source_headers_sync ( + session, context->message, cancellable, &error); + if (error != NULL) { + g_warning ("%s", error->message); + g_clear_error (&error); + } + +exit: + + /* If we were cancelled, disregard any other errors. */ + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + g_simple_async_result_take_error (simple, error); + + /* Stuff the accumulated error messages in a GError. */ + } else if (error_messages->len > 0) { + g_simple_async_result_set_error ( + simple, E_MAIL_ERROR, + E_MAIL_ERROR_POST_PROCESSING, + "%s", error_messages->str); + } + + /* Synchronize the Sent folder. */ + if (context->sent_folder != NULL) + camel_folder_synchronize_sync ( + context->sent_folder, FALSE, cancellable, NULL); + + g_string_free (error_messages, TRUE); +} + +void +e_mail_session_send_to (EMailSession *session, + CamelMimeMessage *message, + gint io_priority, + GCancellable *cancellable, + CamelFilterGetFolderFunc get_folder_func, + gpointer get_folder_data, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *context; + CamelAddress *from; + CamelAddress *recipients; + CamelMedium *medium; + CamelMessageInfo *info; + EAccount *account = NULL; + GPtrArray *post_to_uris; + struct _camel_header_raw *xev; + struct _camel_header_raw *header; + const gchar *string; + const gchar *resent_from; + gchar *transport_uid = NULL; + gchar *sent_folder_uri = NULL; + GError *error = NULL; + + g_return_if_fail (E_IS_MAIL_SESSION (session)); + g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message)); + + medium = CAMEL_MEDIUM (message); + + camel_medium_set_header (medium, "X-Mailer", X_MAILER); + + xev = mail_tool_remove_xevolution_headers (message); + + /* Extract directives from X-Evolution headers. */ + + string = camel_header_raw_find (&xev, "X-Evolution-Account", NULL); + if (string != NULL) { + gchar *account_uid; + + account_uid = g_strstrip (g_strdup (string)); + account = e_get_account_by_uid (account_uid); + g_free (account_uid); + } + + if (account != NULL) { + if (account->transport != NULL) { + + /* XXX Transport UIDs are kludgy right now. We + * use the EAccount's regular UID and tack on + * "-transport". Will be better soon. */ + transport_uid = g_strconcat ( + account->uid, "-transport", NULL); + + /* to reprompt password on sending if needed */ + account->transport->get_password_canceled = FALSE; + } + sent_folder_uri = g_strdup (account->sent_folder_uri); + } + + string = camel_header_raw_find (&xev, "X-Evolution-Fcc", NULL); + if (sent_folder_uri == NULL && string != NULL) + sent_folder_uri = g_strstrip (g_strdup (string)); + + string = camel_header_raw_find (&xev, "X-Evolution-Transport", NULL); + if (transport_uid == NULL && string != NULL) + transport_uid = g_strstrip (g_strdup (string)); + + post_to_uris = g_ptr_array_new (); + for (header = xev; header != NULL; header = header->next) { + gchar *folder_uri; + + if (g_strcmp0 (header->name, "X-Evolution-PostTo") != 0) + continue; + + folder_uri = g_strstrip (g_strdup (header->value)); + g_ptr_array_add (post_to_uris, folder_uri); + } + + /* Collect sender and recipients from headers. */ + + from = (CamelAddress *) camel_internet_address_new (); + recipients = (CamelAddress *) camel_internet_address_new (); + resent_from = camel_medium_get_header (medium, "Resent-From"); + + if (resent_from != NULL) { + const CamelInternetAddress *addr; + const gchar *type; + + camel_address_decode (from, resent_from); + + type = CAMEL_RECIPIENT_TYPE_RESENT_TO; + addr = camel_mime_message_get_recipients (message, type); + camel_address_cat (recipients, CAMEL_ADDRESS (addr)); + + type = CAMEL_RECIPIENT_TYPE_RESENT_CC; + addr = camel_mime_message_get_recipients (message, type); + camel_address_cat (recipients, CAMEL_ADDRESS (addr)); + + type = CAMEL_RECIPIENT_TYPE_RESENT_BCC; + addr = camel_mime_message_get_recipients (message, type); + camel_address_cat (recipients, CAMEL_ADDRESS (addr)); + + } else { + const CamelInternetAddress *addr; + const gchar *type; + + addr = camel_mime_message_get_from (message); + camel_address_copy (from, CAMEL_ADDRESS (addr)); + + type = CAMEL_RECIPIENT_TYPE_TO; + addr = camel_mime_message_get_recipients (message, type); + camel_address_cat (recipients, CAMEL_ADDRESS (addr)); + + type = CAMEL_RECIPIENT_TYPE_CC; + addr = camel_mime_message_get_recipients (message, type); + camel_address_cat (recipients, CAMEL_ADDRESS (addr)); + + type = CAMEL_RECIPIENT_TYPE_BCC; + addr = camel_mime_message_get_recipients (message, type); + camel_address_cat (recipients, CAMEL_ADDRESS (addr)); + } + + /* Miscellaneous preparations. */ + + info = camel_message_info_new (NULL); + camel_message_info_set_flags (info, CAMEL_MESSAGE_SEEN, ~0); + + /* The rest of the processing happens in a thread. */ + + context = g_slice_new0 (AsyncContext); + context->message = g_object_ref (message); + context->io_priority = io_priority; + context->from = from; + context->recipients = recipients; + context->message = g_object_ref (message); + context->info = info; + context->xev = xev; + context->post_to_uris = post_to_uris; + context->transport_uid = transport_uid; + context->sent_folder_uri = sent_folder_uri; + + if (G_IS_CANCELLABLE (cancellable)) + context->cancellable = g_object_ref (cancellable); + + /* Failure here emits a runtime warning but is non-fatal. */ + context->driver = camel_session_get_filter_driver ( + CAMEL_SESSION (session), E_FILTER_SOURCE_OUTGOING, &error); + if (context->driver != NULL && get_folder_func) + camel_filter_driver_set_folder_func ( + context->driver, get_folder_func, get_folder_data); + if (error != NULL) { + g_warn_if_fail (context->driver == NULL); + g_warning ("%s", error->message); + g_error_free (error); + } + + /* This gets popped in async_context_free(). */ + camel_operation_push_message ( + context->cancellable, _("Sending message")); + + simple = g_simple_async_result_new ( + G_OBJECT (session), callback, + user_data, e_mail_session_send_to); + + g_simple_async_result_set_op_res_gpointer ( + simple, context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, (GSimpleAsyncThreadFunc) + mail_session_send_to_thread, + context->io_priority, + context->cancellable); + + g_object_unref (simple); +} + +gboolean +e_mail_session_send_to_finish (EMailSession *session, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (session), + e_mail_session_send_to), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + + /* Assume success unless a GError is set. */ + return !g_simple_async_result_propagate_error (simple, error); +} + +static void +mail_session_unsubscribe_folder_thread (GSimpleAsyncResult *simple, + EMailSession *session, + GCancellable *cancellable) +{ + AsyncContext *context; + GError *error = NULL; + + context = g_simple_async_result_get_op_res_gpointer (simple); + + e_mail_session_unsubscribe_folder_sync ( + session, context->folder_uri, cancellable, &error); + + if (error != NULL) + g_simple_async_result_take_error (simple, error); +} + +gboolean +e_mail_session_unsubscribe_folder_sync (EMailSession *session, + const gchar *folder_uri, + GCancellable *cancellable, + GError **error) +{ + CamelStore *store = NULL; + gchar *folder_name = NULL; + const gchar *message; + gboolean success = FALSE; + + g_return_val_if_fail (E_IS_MAIL_SESSION (session), FALSE); + g_return_val_if_fail (folder_uri != NULL, FALSE); + + success = e_mail_folder_uri_parse ( + CAMEL_SESSION (session), folder_uri, + &store, &folder_name, error); + + if (!success) + return FALSE; + + message = _("Unsubscribing from folder '%s'"); + camel_operation_push_message (cancellable, message, folder_name); + + /* FIXME This should take our GCancellable. */ + success = + em_utils_connect_service_sync ( + CAMEL_SERVICE (store), cancellable, error) && + camel_subscribable_unsubscribe_folder_sync ( + CAMEL_SUBSCRIBABLE (store), + folder_name, cancellable, error); + + camel_operation_pop_message (cancellable); + + g_object_unref (store); + g_free (folder_name); + + return success; +} + +void +e_mail_session_unsubscribe_folder (EMailSession *session, + const gchar *folder_uri, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *context; + + g_return_if_fail (E_IS_MAIL_SESSION (session)); + g_return_if_fail (folder_uri != NULL); + + context = g_slice_new0 (AsyncContext); + context->folder_uri = g_strdup (folder_uri); + + simple = g_simple_async_result_new ( + G_OBJECT (session), callback, user_data, + e_mail_session_unsubscribe_folder); + + g_simple_async_result_set_op_res_gpointer ( + simple, context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, (GSimpleAsyncThreadFunc) + mail_session_unsubscribe_folder_thread, + io_priority, cancellable); + + g_object_unref (simple); +} + +gboolean +e_mail_session_unsubscribe_folder_finish (EMailSession *session, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (session), + e_mail_session_unsubscribe_folder), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + + /* Assume success unless a GError is set. */ + return !g_simple_async_result_propagate_error (simple, error); +} diff --git a/libemail-engine/e-mail-session-utils.h b/libemail-engine/e-mail-session-utils.h new file mode 100644 index 0000000000..2c92216533 --- /dev/null +++ b/libemail-engine/e-mail-session-utils.h @@ -0,0 +1,97 @@ +/* + * e-mail-session-utils.h + * + * 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 + * + */ + +#ifndef E_MAIL_SESSION_UTILS_H +#define E_MAIL_SESSION_UTILS_H + +/* High-level operations with Evolution-specific policies. */ + +#include + +#define E_MAIL_ERROR (e_mail_error_quark ()) + +G_BEGIN_DECLS + +typedef enum { + E_MAIL_ERROR_POST_PROCESSING +} EMailError; + +GQuark e_mail_error_quark (void) G_GNUC_CONST; +gboolean e_mail_session_handle_draft_headers_sync + (EMailSession *session, + CamelMimeMessage *message, + GCancellable *cancellable, + GError **error); +void e_mail_session_handle_draft_headers + (EMailSession *session, + CamelMimeMessage *message, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean e_mail_session_handle_draft_headers_finish + (EMailSession *session, + GAsyncResult *result, + GError **error); +gboolean e_mail_session_handle_source_headers_sync + (EMailSession *session, + CamelMimeMessage *message, + GCancellable *cancellable, + GError **error); +void e_mail_session_handle_source_headers + (EMailSession *session, + CamelMimeMessage *message, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean e_mail_session_handle_source_headers_finish + (EMailSession *session, + GAsyncResult *result, + GError **error); +void e_mail_session_send_to (EMailSession *session, + CamelMimeMessage *message, + gint io_priority, + GCancellable *cancellable, + CamelFilterGetFolderFunc get_folder_func, + gpointer get_folder_data, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean e_mail_session_send_to_finish (EMailSession *session, + GAsyncResult *result, + GError **error); +gboolean e_mail_session_unsubscribe_folder_sync + (EMailSession *session, + const gchar *folder_uri, + GCancellable *cancellable, + GError **error); +void e_mail_session_unsubscribe_folder + (EMailSession *session, + const gchar *folder_uri, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean e_mail_session_unsubscribe_folder_finish + (EMailSession *session, + GAsyncResult *result, + GError **error); + +G_END_DECLS + +#endif /* E_MAIL_SESSION_UTILS_H */ diff --git a/libemail-engine/e-mail-session.c b/libemail-engine/e-mail-session.c new file mode 100644 index 0000000000..012ad9ba7d --- /dev/null +++ b/libemail-engine/e-mail-session.c @@ -0,0 +1,1969 @@ +/* + * e-mail-session.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + * + * Authors: + * Jonathon Jongsma + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * Copyright (C) 2009 Intel Corporation + * + */ + +/* mail-session.c: handles the session information and resource manipulation */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include + +#include + +#ifdef HAVE_CANBERRA +#include +#endif + +#include +#include +#include +#include +#include + +#include "libemail-utils/e-account-utils.h" +#include "libemail-utils/mail-mt.h" + +#include "e-mail-junk-filter.h" +#include "e-mail-session.h" +#include "e-mail-folder-utils.h" +#include "e-mail-utils.h" +#include "mail-config.h" +#include "mail-ops.h" +#include "mail-tools.h" + +#define E_MAIL_SESSION_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_MAIL_SESSION, EMailSessionPrivate)) + +typedef struct _AsyncContext AsyncContext; + +struct _EMailSessionPrivate { + MailFolderCache *folder_cache; + + EAccountList *account_list; + gulong account_added_handler_id; + + CamelStore *local_store; + + FILE *filter_logfile; + GHashTable *junk_filters; + EProxy *proxy; + + /* Local folder cache. */ + GPtrArray *local_folders; + GPtrArray *local_folder_uris; +}; + +struct _AsyncContext { + /* arguments */ + CamelStoreGetFolderFlags flags; + gchar *uid; + gchar *uri; + + /* results */ + CamelFolder *folder; +}; + +enum { + PROP_0, + PROP_FOLDER_CACHE, + PROP_JUNK_FILTER_NAME, + PROP_LOCAL_STORE +}; + +static const gchar *local_folder_names[E_MAIL_NUM_LOCAL_FOLDERS] = { + N_("Inbox"), /* E_MAIL_LOCAL_FOLDER_INBOX */ + N_("Drafts"), /* E_MAIL_LOCAL_FOLDER_DRAFTS */ + N_("Outbox"), /* E_MAIL_LOCAL_FOLDER_OUTBOX */ + N_("Sent"), /* E_MAIL_LOCAL_FOLDER_SENT */ + N_("Templates"), /* E_MAIL_LOCAL_FOLDER_TEMPLATES */ + "Inbox" /* E_MAIL_LOCAL_FOLDER_LOCAL_INBOX */ +}; + +enum { + FLUSH_OUTBOX, + STORE_ADDED, + STORE_REMOVED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +static gchar *mail_data_dir; +static gchar *mail_cache_dir; +static gchar *mail_config_dir; + +G_DEFINE_TYPE_WITH_CODE ( + EMailSession, + e_mail_session, + CAMEL_TYPE_SESSION, + G_IMPLEMENT_INTERFACE (E_TYPE_EXTENSIBLE, NULL)) + +/* Support for CamelSession.alert_user() *************************************/ + +static GQueue user_message_queue = { NULL, NULL, 0 }; + +struct _user_message_msg { + MailMsg base; + + CamelSessionAlertType type; + gchar *prompt; + GSList *button_captions; + EFlag *done; + + gint result; + guint ismain : 1; +}; + +static void user_message_exec (struct _user_message_msg *m, + GCancellable *cancellable, + GError **error); + +static void +user_message_response_free (struct _user_message_msg *m) +{ + + /* check for pendings */ + if (!g_queue_is_empty (&user_message_queue)) { + GCancellable *cancellable; + + m = g_queue_pop_head (&user_message_queue); + cancellable = m->base.cancellable; + user_message_exec (m, cancellable, &m->base.error); + mail_msg_unref (m); + } +} + +/* clicked, send back the reply */ +static void +user_message_response (struct _user_message_msg *m) +{ + /* if !allow_cancel, then we've already replied */ + if (m->button_captions) { + m->result = TRUE; //If Accepted + e_flag_set (m->done); + } + + user_message_response_free (m); +} + +static void +user_message_exec (struct _user_message_msg *m, + GCancellable *cancellable, + GError **error) +{ + /* XXX This is a case where we need to be able to construct + * custom EAlerts without a predefined XML definition. */ + if (m->ismain) { + /* Use DBUS to raise dialogs in clients and reply back. + * For now say accept all. */ + user_message_response (m); + } else + g_queue_push_tail (&user_message_queue, mail_msg_ref (m)); +} + +static void +user_message_free (struct _user_message_msg *m) +{ + g_free (m->prompt); + g_slist_free_full (m->button_captions, g_free); + e_flag_free (m->done); +} + +static MailMsgInfo user_message_info = { + sizeof (struct _user_message_msg), + (MailMsgDescFunc) NULL, + (MailMsgExecFunc) user_message_exec, + (MailMsgDoneFunc) NULL, + (MailMsgFreeFunc) user_message_free +}; + +/* Support for CamelSession.get_filter_driver () *****************************/ + +static CamelFolder * +get_folder (CamelFilterDriver *d, + const gchar *uri, + gpointer user_data, + GError **error) +{ + EMailSession *session = E_MAIL_SESSION (user_data); + + /* FIXME Not passing a GCancellable here. */ + /* FIXME Need a camel_filter_driver_get_session(). */ + return e_mail_session_uri_to_folder_sync ( + session, uri, 0, NULL, error); +} + +static CamelFilterDriver * +main_get_filter_driver (CamelSession *session, + const gchar *type, + GError **error) +{ + CamelFilterDriver *driver; + EMailSession *ms = (EMailSession *)session; + GSettings *settings; + + settings = g_settings_new ("org.gnome.evolution.mail"); + + driver = camel_filter_driver_new (session); + camel_filter_driver_set_folder_func (driver, get_folder, session); + + if (g_settings_get_boolean (settings, "filters-log-actions")) { + if (ms->priv->filter_logfile == NULL) { + gchar *filename; + + filename = g_settings_get_string (settings, "filters-log-file"); + if (filename) { + ms->priv->filter_logfile = g_fopen (filename, "a+"); + g_free (filename); + } + } + + if (ms->priv->filter_logfile) + camel_filter_driver_set_logfile (driver, ms->priv->filter_logfile); + } + + g_object_unref (settings); + + return driver; +} + +/* Support for CamelSession.forward_to () ************************************/ + +static guint preparing_flush = 0; + +static gboolean +forward_to_flush_outbox_cb (EMailSession *session) +{ + + preparing_flush = 0; + + /* Connect to this and call mail_send in the main email client.*/ + g_signal_emit (session, signals[FLUSH_OUTBOX], 0); + + return FALSE; +} + +static void +ms_forward_to_cb (CamelFolder *folder, + GAsyncResult *result, + EMailSession *session) +{ + GSettings *settings; + + /* FIXME Poor error handling. */ + if (!e_mail_folder_append_message_finish (folder, result, NULL, NULL)) + return; + + settings = g_settings_new ("org.gnome.evolution.mail"); + + /* do not call mail send immediately, just pile them all in the outbox */ + if (preparing_flush || g_settings_get_boolean ( + settings, "flush-outbox")) { + if (preparing_flush) + g_source_remove (preparing_flush); + + preparing_flush = g_timeout_add_seconds ( + 60, (GSourceFunc) + forward_to_flush_outbox_cb, session); + } + + g_object_unref (settings); +} + +static void +async_context_free (AsyncContext *context) +{ + if (context->folder != NULL) + g_object_unref (context->folder); + + g_free (context->uid); + g_free (context->uri); + + g_slice_free (AsyncContext, context); +} + +static gchar * +mail_session_make_key (CamelService *service, + const gchar *item) +{ + gchar *key; + + if (service != NULL) { + CamelURL *url; + + url = camel_service_new_camel_url (service); + key = camel_url_to_string (url, CAMEL_URL_HIDE_ALL); + camel_url_free (url); + } else + key = g_strdup (item); + + return key; +} + +static void +mail_session_check_junk_notify (GSettings *settings, + const gchar *key, + CamelSession *session) +{ + if (strcmp (key, "junk-check-incoming") == 0) + camel_session_set_check_junk ( + session, g_settings_get_boolean (settings, key)); +} + +static const gchar * +mail_session_get_junk_filter_name (EMailSession *session) +{ + CamelJunkFilter *junk_filter; + GHashTableIter iter; + gpointer key, value; + + /* XXX This property can be removed once Evolution moves to + * GSettings and can use transform functions when binding + * properties to settings. That's why this is private. */ + + g_hash_table_iter_init (&iter, session->priv->junk_filters); + junk_filter = camel_session_get_junk_filter (CAMEL_SESSION (session)); + + while (g_hash_table_iter_next (&iter, &key, &value)) { + if (junk_filter == CAMEL_JUNK_FILTER (value)) + return (const gchar *) key; + } + + if (junk_filter != NULL) + g_warning ( + "Camel is using a junk filter " + "unknown to Evolution of type %s", + G_OBJECT_TYPE_NAME (junk_filter)); + + return ""; +} + +static void +mail_session_set_junk_filter_name (EMailSession *session, + const gchar *junk_filter_name) +{ + CamelJunkFilter *junk_filter = NULL; + + /* XXX This property can be removed once Evolution moves to + * GSettings and can use transform functions when binding + * properties to settings. That's why this is private. */ + + /* An empty string is equivalent to a NULL string. */ + if (junk_filter_name != NULL && *junk_filter_name == '\0') + junk_filter_name = NULL; + + if (junk_filter_name != NULL) { + junk_filter = g_hash_table_lookup ( + session->priv->junk_filters, junk_filter_name); + if (junk_filter != NULL) { + if (!e_mail_junk_filter_available ( + E_MAIL_JUNK_FILTER (junk_filter))) + junk_filter = NULL; + } else { + g_warning ( + "Unrecognized junk filter name " + "'%s' in GSettings", junk_filter_name); + } + } + + camel_session_set_junk_filter (CAMEL_SESSION (session), junk_filter); + + /* XXX We emit the "notify" signal in mail_session_notify(). */ +} + +static void +mail_session_add_by_account (EMailSession *session, + EAccount *account) +{ + CamelService *service = NULL; + CamelProvider *provider; + CamelURL *url; + gboolean transport_only; + GError *error = NULL; + + /* check whether it's transport-only accounts */ + transport_only = + (account->source == NULL) || + (account->source->url == NULL) || + (*account->source->url == '\0'); + if (transport_only) + goto handle_transport; + + /* Load the service, but don't connect. Check its provider, + * and if this belongs in the folder tree model, add it. */ + + url = camel_url_new (account->source->url, NULL); + if (url != NULL) { + provider = camel_provider_get (url->protocol, NULL); + camel_url_free (url); + } else { + provider = NULL; + } + + if (provider == NULL) { + /* In case we do not have a provider here, we handle + * the special case of having multiple mail identities + * eg. a dummy account having just SMTP server defined */ + goto handle_transport; + } + + service = camel_session_add_service ( + CAMEL_SESSION (session), + account->uid, provider->protocol, + CAMEL_PROVIDER_STORE, &error); + + if (error != NULL) { + g_warning ( + "Failed to add service: %s: %s", + account->name, error->message); + g_error_free (error); + return; + } + + camel_service_set_display_name (service, account->name); + +handle_transport: + + /* While we're at it, add the account's transport (if it has one) + * to the CamelSession. The transport's UID is a kludge for now. + * We take the EAccount's UID and tack on "-transport". */ + + if (account->transport) { + GError *transport_error = NULL; + + url = camel_url_new ( + account->transport->url, + &transport_error); + + if (url != NULL) { + provider = camel_provider_get ( + url->protocol, &transport_error); + camel_url_free (url); + } else + provider = NULL; + + if (provider != NULL) { + gchar *transport_uid; + + transport_uid = g_strconcat ( + account->uid, "-transport", NULL); + + camel_session_add_service ( + CAMEL_SESSION (session), + transport_uid, provider->protocol, + CAMEL_PROVIDER_TRANSPORT, &transport_error); + + g_free (transport_uid); + } + + if (transport_error) { + g_warning ( + "%s: Failed to add transport service: %s", + G_STRFUNC, transport_error->message); + g_error_free (transport_error); + } + } +} + +static void +mail_session_account_added_cb (EAccountList *account_list, + EAccount *account, + EMailSession *session) +{ + mail_session_add_by_account (session, account); +} + +static void +mail_session_add_local_store (EMailSession *session) +{ + CamelLocalSettings *local_settings; + CamelSession *camel_session; + CamelSettings *settings; + CamelService *service; + const gchar *data_dir; + gchar *path; + gint ii; + GError *error = NULL; + + camel_session = CAMEL_SESSION (session); + + service = camel_session_add_service ( + camel_session, E_MAIL_SESSION_LOCAL_UID, + "maildir", CAMEL_PROVIDER_STORE, &error); + + /* XXX One could argue this is a fatal error + * since we depend on it in so many places. */ + if (error != NULL) { + g_critical ("%s: %s", G_STRFUNC, error->message); + g_error_free (error); + return; + } + + g_return_if_fail (CAMEL_IS_SERVICE (service)); + + camel_service_set_display_name (service, _("On This Computer")); + + settings = camel_service_get_settings (service); + local_settings = CAMEL_LOCAL_SETTINGS (settings); + data_dir = camel_session_get_user_data_dir (camel_session); + + path = g_build_filename (data_dir, E_MAIL_SESSION_LOCAL_UID, NULL); + camel_local_settings_set_path (local_settings, path); + g_free (path); + + /* Shouldn't need to worry about other mail applications + * altering files in our local mail store. */ + g_object_set (service, "need-summary-check", FALSE, NULL); + + /* Populate the local folder cache. */ + for (ii = 0; ii < E_MAIL_NUM_LOCAL_FOLDERS; ii++) { + CamelFolder *folder; + gchar *folder_uri; + const gchar *display_name; + GError *error = NULL; + + display_name = local_folder_names[ii]; + + /* XXX This blocks but should be fast. */ + if (ii == E_MAIL_LOCAL_FOLDER_LOCAL_INBOX) + folder = camel_store_get_inbox_folder_sync ( + CAMEL_STORE (service), NULL, &error); + else + folder = camel_store_get_folder_sync ( + CAMEL_STORE (service), display_name, + CAMEL_STORE_FOLDER_CREATE, NULL, &error); + + folder_uri = e_mail_folder_uri_build ( + CAMEL_STORE (service), display_name); + + /* The arrays take ownership of the items added. */ + g_ptr_array_add (session->priv->local_folders, folder); + g_ptr_array_add (session->priv->local_folder_uris, folder_uri); + + if (error != NULL) { + g_critical ("%s: %s", G_STRFUNC, error->message); + g_error_free (error); + } + } + + session->priv->local_store = g_object_ref (service); +} + +static void +mail_session_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_JUNK_FILTER_NAME: + mail_session_set_junk_filter_name ( + E_MAIL_SESSION (object), + g_value_get_string (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +mail_session_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_FOLDER_CACHE: + g_value_set_object ( + value, + e_mail_session_get_folder_cache ( + E_MAIL_SESSION (object))); + return; + + case PROP_JUNK_FILTER_NAME: + g_value_set_string ( + value, + mail_session_get_junk_filter_name ( + E_MAIL_SESSION (object))); + return; + + case PROP_LOCAL_STORE: + g_value_set_object ( + value, + e_mail_session_get_local_store ( + E_MAIL_SESSION (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +mail_session_dispose (GObject *object) +{ + EMailSessionPrivate *priv; + + priv = E_MAIL_SESSION_GET_PRIVATE (object); + + if (priv->folder_cache != NULL) { + g_object_unref (priv->folder_cache); + priv->folder_cache = NULL; + } + + if (priv->account_list != NULL) { + g_signal_handler_disconnect ( + priv->account_list, + priv->account_added_handler_id); + g_object_unref (priv->account_list); + priv->account_list = NULL; + } + + if (priv->local_store != NULL) { + g_object_unref (priv->local_store); + priv->local_store = NULL; + } + + g_ptr_array_set_size (priv->local_folders, 0); + g_ptr_array_set_size (priv->local_folder_uris, 0); + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (e_mail_session_parent_class)->dispose (object); +} + +static void +mail_session_finalize (GObject *object) +{ + EMailSessionPrivate *priv; + + priv = E_MAIL_SESSION_GET_PRIVATE (object); + + g_hash_table_destroy (priv->junk_filters); + g_object_unref (priv->proxy); + + g_ptr_array_free (priv->local_folders, TRUE); + g_ptr_array_free (priv->local_folder_uris, TRUE); + + g_free (mail_data_dir); + g_free (mail_config_dir); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (e_mail_session_parent_class)->finalize (object); +} + +static void +mail_session_notify (GObject *object, + GParamSpec *pspec) +{ + /* GObject does not implement this method; do not chain up. */ + + /* XXX Delete this once Evolution moves to GSettings and + * we're able to get rid of PROP_JUNK_FILTER_NAME. */ + if (g_strcmp0 (pspec->name, "junk-filter") == 0) + g_object_notify (object, "junk-filter-name"); +} + +static gboolean +mail_session_initialize_stores_idle (gpointer user_data) +{ + EMailSession *session = user_data; + EAccountList *account_list; + EAccount *account; + EIterator *iter; + + g_return_val_if_fail (session != NULL, FALSE); + + account_list = e_get_account_list (); + iter = e_list_get_iterator (E_LIST (account_list)); + + while (e_iterator_is_valid (iter)) { + /* XXX EIterator misuses const. */ + account = (EAccount *) e_iterator_get (iter); + + mail_session_add_by_account (session, account); + + e_iterator_next (iter); + } + + g_object_unref (iter); + + return FALSE; +} + +static void +mail_session_constructed (GObject *object) +{ + EMailSession *session; + EExtensible *extensible; + GType extension_type; + GList *list, *link; + GSettings *settings; + EAccountList *account_list; + gulong handler_id; + + session = E_MAIL_SESSION (object); + + /* Chain up to parent's constructed() method. */ + G_OBJECT_CLASS (e_mail_session_parent_class)->constructed (object); + + account_list = e_get_account_list (); + session->priv->account_list = g_object_ref (account_list); + + /* This must be created after the account store. */ + session->priv->folder_cache = mail_folder_cache_new (session); + + /* Add built-in CamelStores. */ + mail_session_add_local_store (session); + + /* Give it a chance to load user settings, they are not loaded yet. + * + * XXX Is this the case where hiding such natural things like loading + * user setting into an EExtension strikes back and proves itself + * being suboptimal? + */ + g_idle_add (mail_session_initialize_stores_idle, object); + + /* Listen for account list updates. */ + + handler_id = g_signal_connect ( + account_list, "account-added", + G_CALLBACK (mail_session_account_added_cb), session); + session->priv->account_added_handler_id = handler_id; + + extensible = E_EXTENSIBLE (object); + e_extensible_load_extensions (extensible); + + /* Add junk filter extensions to an internal hash table. */ + + extension_type = E_TYPE_MAIL_JUNK_FILTER; + list = e_extensible_list_extensions (extensible, extension_type); + + for (link = list; link != NULL; link = g_list_next (link)) { + EMailJunkFilter *junk_filter; + EMailJunkFilterClass *class; + + junk_filter = E_MAIL_JUNK_FILTER (link->data); + class = E_MAIL_JUNK_FILTER_GET_CLASS (junk_filter); + + if (!CAMEL_IS_JUNK_FILTER (junk_filter)) { + g_warning ( + "Skipping %s: Does not implement " + "CamelJunkFilterInterface", + G_OBJECT_TYPE_NAME (junk_filter)); + continue; + } + + if (class->filter_name == NULL) { + g_warning ( + "Skipping %s: filter_name unset", + G_OBJECT_TYPE_NAME (junk_filter)); + continue; + } + + if (class->display_name == NULL) { + g_warning ( + "Skipping %s: display_name unset", + G_OBJECT_TYPE_NAME (junk_filter)); + continue; + } + + /* No need to reference the EMailJunkFilter since + * EMailSession owns the reference to it already. */ + g_hash_table_insert ( + session->priv->junk_filters, + (gpointer) class->filter_name, + junk_filter); + } + + g_list_free (list); + + /* Bind the "junk-default-plugin" GSettings + * key to our "junk-filter-name" property. */ + + settings = g_settings_new ("org.gnome.evolution.mail"); + g_settings_bind ( + settings, "junk-default-plugin", + object, "junk-filter-name", + G_SETTINGS_BIND_DEFAULT); + g_object_unref (settings); +} + +static CamelService * +mail_session_add_service (CamelSession *session, + const gchar *uid, + const gchar *protocol, + CamelProviderType type, + GError **error) +{ + CamelService *service; + + /* Chain up to parents add_service() method. */ + service = CAMEL_SESSION_CLASS (e_mail_session_parent_class)-> + add_service (session, uid, protocol, type, error); + + /* Initialize the CamelSettings object from CamelURL parameters. + * This is temporary; soon we'll read settings from key files. */ + + if (CAMEL_IS_SERVICE (service)) { + EAccount *account; + CamelURL *url = NULL; + + account = e_get_account_by_uid (uid); + if (account != NULL) { + const gchar *url_string = NULL; + + switch (type) { + case CAMEL_PROVIDER_STORE: + url_string = account->source->url; + break; + case CAMEL_PROVIDER_TRANSPORT: + url_string = account->transport->url; + break; + default: + break; + } + + if (url_string != NULL) { + url = camel_url_new (url_string, error); + if (url == NULL) { + g_object_unref (service); + service = NULL; + } + } + } + + if (url != NULL) { + CamelSettings *settings; + + settings = camel_service_get_settings (service); + camel_settings_load_from_url (settings, url); + camel_url_free (url); + + g_object_notify (G_OBJECT (service), "settings"); + + /* Migrate files for this service from its old + * URL-based directory to a UID-based directory + * if necessary. */ + camel_service_migrate_files (service); + } + } + + return service; +} + +static gchar * +mail_session_get_password (CamelSession *session, + CamelService *service, + const gchar *prompt, + const gchar *item, + guint32 flags, + GError **error) +{ + EAccount *account = NULL; + const gchar *display_name = NULL; + const gchar *uid = NULL; + gchar *ret = NULL; + + if (CAMEL_IS_SERVICE (service)) { + display_name = camel_service_get_display_name (service); + uid = camel_service_get_uid (service); + account = e_get_account_by_uid (uid); + } + + if (!strcmp(item, "popb4smtp_uid")) { + /* not 100% mt safe, but should be ok */ + ret = g_strdup ((account != NULL) ? account->uid : uid); + } else { + gchar *key = mail_session_make_key (service, item); + EAccountService *config_service = NULL; + + ret = e_passwords_get_password (NULL, key); + if (ret == NULL || (flags & CAMEL_SESSION_PASSWORD_REPROMPT)) { + gboolean remember; + + g_free (ret); + ret = NULL; + + if (account != NULL) { + if (CAMEL_IS_STORE (service)) + config_service = account->source; + if (CAMEL_IS_TRANSPORT (service)) + config_service = account->transport; + } + + remember = config_service ? config_service->save_passwd : FALSE; + + if (!config_service || (config_service && + !config_service->get_password_canceled)) { + guint32 eflags; + gchar *title; + + if (flags & CAMEL_SESSION_PASSPHRASE) { + if (display_name != NULL) + title = g_strdup_printf ( + _("Enter Passphrase for %s"), + display_name); + else + title = g_strdup ( + _("Enter Passphrase")); + } else { + if (display_name != NULL) + title = g_strdup_printf ( + _("Enter Password for %s"), + display_name); + else + title = g_strdup ( + _("Enter Password")); + } + if ((flags & CAMEL_SESSION_PASSWORD_STATIC) != 0) + eflags = E_PASSWORDS_REMEMBER_NEVER; + else if (config_service == NULL) + eflags = E_PASSWORDS_REMEMBER_SESSION; + else + eflags = E_PASSWORDS_REMEMBER_FOREVER; + + if (flags & CAMEL_SESSION_PASSWORD_REPROMPT) + eflags |= E_PASSWORDS_REPROMPT; + + if (flags & CAMEL_SESSION_PASSWORD_SECRET) + eflags |= E_PASSWORDS_SECRET; + + if (flags & CAMEL_SESSION_PASSPHRASE) + eflags |= E_PASSWORDS_PASSPHRASE; + + /* HACK: breaks abstraction ... + * e_account_writable() doesn't use the + * EAccount, it also uses the same writable + * key for source and transport. */ + if (!e_account_writable (NULL, E_ACCOUNT_SOURCE_SAVE_PASSWD)) + eflags |= E_PASSWORDS_DISABLE_REMEMBER; + + ret = e_passwords_ask_password ( + title, NULL, key, prompt, + eflags, &remember, NULL); + + if (!ret) + e_passwords_forget_password (NULL, key); + + g_free (title); + + if (ret && config_service) { + config_service->save_passwd = remember; + e_account_list_save (e_get_account_list ()); + } + + if (config_service) + config_service->get_password_canceled = ret == NULL; + } + } + + g_free (key); + } + + if (ret == NULL) + g_set_error ( + error, G_IO_ERROR, + G_IO_ERROR_CANCELLED, + _("User canceled operation.")); + + return ret; +} + +static gboolean +mail_session_forget_password (CamelSession *session, + CamelService *service, + const gchar *item, + GError **error) +{ + gchar *key; + + key = mail_session_make_key (service, item); + + e_passwords_forget_password (NULL, key); + + g_free (key); + + return TRUE; +} + +static gint +mail_session_alert_user (CamelSession *session, + CamelSessionAlertType type, + const gchar *prompt, + GSList *button_captions) +{ + struct _user_message_msg *m; + GCancellable *cancellable; + gint result = -1; + GSList *iter; + + m = mail_msg_new (&user_message_info); + m->ismain = mail_in_main_thread (); + m->type = type; + m->prompt = g_strdup (prompt); + m->done = e_flag_new (); + m->button_captions = g_slist_copy (button_captions); + + for (iter = m->button_captions; iter; iter = iter->next) + iter->data = g_strdup (iter->data); + + if (g_slist_length (button_captions) > 1) + mail_msg_ref (m); + + cancellable = m->base.cancellable; + + if (m->ismain) + user_message_exec (m, cancellable, &m->base.error); + else + mail_msg_main_loop_push (m); + + if (g_slist_length (button_captions) > 1) { + e_flag_wait (m->done); + result = m->result; + mail_msg_unref (m); + } else if (m->ismain) + mail_msg_unref (m); + + return result; +} + +static CamelFilterDriver * +mail_session_get_filter_driver (CamelSession *session, + const gchar *type, + GError **error) +{ + return (CamelFilterDriver *) mail_call_main ( + MAIL_CALL_p_ppp, (MailMainFunc) main_get_filter_driver, + session, type, error); +} + +static gboolean +mail_session_lookup_addressbook (CamelSession *session, + const gchar *name) +{ + CamelInternetAddress *addr; + gboolean ret; + + if (!mail_config_get_lookup_book ()) + return FALSE; + + addr = camel_internet_address_new (); + camel_address_decode ((CamelAddress *) addr, name); + ret = em_utils_in_addressbook ( + addr, mail_config_get_lookup_book_local_only ()); + g_object_unref (addr); + + return ret; +} + +static gboolean +mail_session_forward_to (CamelSession *session, + CamelFolder *folder, + CamelMimeMessage *message, + const gchar *address, + GError **error) +{ + EAccount *account; + CamelMimeMessage *forward; + CamelStream *mem; + CamelInternetAddress *addr; + CamelFolder *out_folder; + CamelMessageInfo *info; + CamelMedium *medium; + const gchar *from_address; + const gchar *from_name; + const gchar *header_name; + struct _camel_header_raw *xev; + gchar *subject; + + g_return_val_if_fail (folder != NULL, FALSE); + g_return_val_if_fail (message != NULL, FALSE); + g_return_val_if_fail (address != NULL, FALSE); + + if (!*address) { + g_set_error ( + error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, + _("No destination address provided, forward " + "of the message has been cancelled.")); + return FALSE; + } + + account = em_utils_guess_account_with_recipients (message, folder); + if (!account) { + g_set_error ( + error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, + _("No account found to use, forward of the " + "message has been cancelled.")); + return FALSE; + } + + from_address = account->id->address; + from_name = account->id->name; + + forward = camel_mime_message_new (); + + /* make copy of the message, because we are going to modify it */ + mem = camel_stream_mem_new (); + camel_data_wrapper_write_to_stream_sync ( + CAMEL_DATA_WRAPPER (message), mem, NULL, NULL); + g_seekable_seek (G_SEEKABLE (mem), 0, G_SEEK_SET, NULL, NULL); + camel_data_wrapper_construct_from_stream_sync ( + CAMEL_DATA_WRAPPER (forward), mem, NULL, NULL); + g_object_unref (mem); + + /* clear previous recipients */ + camel_mime_message_set_recipients ( + forward, CAMEL_RECIPIENT_TYPE_TO, NULL); + camel_mime_message_set_recipients ( + forward, CAMEL_RECIPIENT_TYPE_CC, NULL); + camel_mime_message_set_recipients ( + forward, CAMEL_RECIPIENT_TYPE_BCC, NULL); + camel_mime_message_set_recipients ( + forward, CAMEL_RECIPIENT_TYPE_RESENT_TO, NULL); + camel_mime_message_set_recipients ( + forward, CAMEL_RECIPIENT_TYPE_RESENT_CC, NULL); + camel_mime_message_set_recipients ( + forward, CAMEL_RECIPIENT_TYPE_RESENT_BCC, NULL); + + medium = CAMEL_MEDIUM (forward); + + /* remove all delivery and notification headers */ + header_name = "Disposition-Notification-To"; + while (camel_medium_get_header (medium, header_name)) + camel_medium_remove_header (medium, header_name); + + header_name = "Delivered-To"; + while (camel_medium_get_header (medium, header_name)) + camel_medium_remove_header (medium, header_name); + + /* remove any X-Evolution-* headers that may have been set */ + xev = mail_tool_remove_xevolution_headers (forward); + camel_header_raw_clear (&xev); + + /* from */ + addr = camel_internet_address_new (); + camel_internet_address_add (addr, from_name, from_address); + camel_mime_message_set_from (forward, addr); + g_object_unref (addr); + + /* to */ + addr = camel_internet_address_new (); + camel_address_decode (CAMEL_ADDRESS (addr), address); + camel_mime_message_set_recipients ( + forward, CAMEL_RECIPIENT_TYPE_TO, addr); + g_object_unref (addr); + + /* subject */ + subject = mail_tool_generate_forward_subject (message); + camel_mime_message_set_subject (forward, subject); + g_free (subject); + + /* and send it */ + info = camel_message_info_new (NULL); + out_folder = e_mail_session_get_local_folder ( + E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_OUTBOX); + camel_message_info_set_flags ( + info, CAMEL_MESSAGE_SEEN, CAMEL_MESSAGE_SEEN); + + /* FIXME Pass a GCancellable. */ + e_mail_folder_append_message ( + out_folder, forward, info, G_PRIORITY_DEFAULT, NULL, + (GAsyncReadyCallback) ms_forward_to_cb, session); + + camel_message_info_free (info); + + return TRUE; +} + +static void +mail_session_get_socks_proxy (CamelSession *session, + const gchar *for_host, + gchar **host_ret, + gint *port_ret) +{ + EMailSession *mail_session; + gchar *uri; + + g_return_if_fail (session != NULL); + g_return_if_fail (for_host != NULL); + g_return_if_fail (host_ret != NULL); + g_return_if_fail (port_ret != NULL); + + mail_session = E_MAIL_SESSION (session); + g_return_if_fail (mail_session != NULL); + g_return_if_fail (mail_session->priv != NULL); + + *host_ret = NULL; + *port_ret = 0; + + uri = g_strconcat ("socks://", for_host, NULL); + + if (e_proxy_require_proxy_for_uri (mail_session->priv->proxy, uri)) { + SoupURI *suri; + + suri = e_proxy_peek_uri_for (mail_session->priv->proxy, uri); + if (suri) { + *host_ret = g_strdup (suri->host); + *port_ret = suri->port; + } + } + + g_free (uri); +} + +static gboolean +mail_session_authenticate_sync (CamelSession *session, + CamelService *service, + const gchar *mechanism, + GCancellable *cancellable, + GError **error) +{ + CamelServiceAuthType *authtype = NULL; + CamelAuthenticationResult result; + CamelProvider *provider; + CamelSettings *settings; + const gchar *password; + guint32 password_flags; + GError *local_error = NULL; + + /* Do not chain up. Camel's default method is only an example for + * subclasses to follow. Instead we mimic most of its logic here. */ + + provider = camel_service_get_provider (service); + settings = camel_service_get_settings (service); + + /* APOP is one case where a non-SASL mechanism name is passed, so + * don't bail if the CamelServiceAuthType struct comes back NULL. */ + if (mechanism != NULL) + authtype = camel_sasl_authtype (mechanism); + + /* If the SASL mechanism does not involve a user + * password, then it gets one shot to authenticate. */ + if (authtype != NULL && !authtype->need_password) { + result = camel_service_authenticate_sync ( + service, mechanism, cancellable, error); + if (result == CAMEL_AUTHENTICATION_REJECTED) + g_set_error ( + error, CAMEL_SERVICE_ERROR, + CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE, + _("%s authentication failed"), mechanism); + return (result == CAMEL_AUTHENTICATION_ACCEPTED); + } + + /* Some SASL mechanisms can attempt to authenticate without a + * user password being provided (e.g. single-sign-on credentials), + * but can fall back to a user password. Handle that case next. */ + if (mechanism != NULL) { + CamelProvider *provider; + CamelSasl *sasl; + const gchar *service_name; + gboolean success = FALSE; + + provider = camel_service_get_provider (service); + service_name = provider->protocol; + + /* XXX Would be nice if camel_sasl_try_empty_password_sync() + * returned CamelAuthenticationResult so it's easier to + * detect errors. */ + sasl = camel_sasl_new (service_name, mechanism, service); + if (sasl != NULL) { + success = camel_sasl_try_empty_password_sync ( + sasl, cancellable, &local_error); + g_object_unref (sasl); + } + + if (success) + return TRUE; + } + + /* Abort authentication if we got cancelled. + * Otherwise clear any errors and press on. */ + if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return FALSE; + + g_clear_error (&local_error); + + password_flags = CAMEL_SESSION_PASSWORD_SECRET; + +retry: + password = camel_service_get_password (service); + + if (password == NULL) { + CamelNetworkSettings *network_settings; + const gchar *host; + const gchar *user; + gchar *prompt; + gchar *new_passwd; + + network_settings = CAMEL_NETWORK_SETTINGS (settings); + host = camel_network_settings_get_host (network_settings); + user = camel_network_settings_get_user (network_settings); + + prompt = camel_session_build_password_prompt ( + provider->name, user, host); + + new_passwd = camel_session_get_password ( + session, service, prompt, "password", + password_flags, &local_error); + camel_service_set_password (service, new_passwd); + password = camel_service_get_password (service); + g_free (new_passwd); + + g_free (prompt); + + if (local_error != NULL) { + g_propagate_error (error, local_error); + return FALSE; + } + + if (password == NULL) { + g_set_error ( + error, CAMEL_SERVICE_ERROR, + CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE, + _("No password was provided")); + return FALSE; + } + } + + result = camel_service_authenticate_sync ( + service, mechanism, cancellable, error); + + if (result == CAMEL_AUTHENTICATION_REJECTED) { + password_flags |= CAMEL_SESSION_PASSWORD_REPROMPT; + camel_service_set_password (service, NULL); + goto retry; + } + + return (result == CAMEL_AUTHENTICATION_ACCEPTED); +} + +static void +e_mail_session_class_init (EMailSessionClass *class) +{ + GObjectClass *object_class; + CamelSessionClass *session_class; + + g_type_class_add_private (class, sizeof (EMailSessionPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = mail_session_set_property; + object_class->get_property = mail_session_get_property; + object_class->dispose = mail_session_dispose; + object_class->finalize = mail_session_finalize; + object_class->notify = mail_session_notify; + object_class->constructed = mail_session_constructed; + + session_class = CAMEL_SESSION_CLASS (class); + session_class->add_service = mail_session_add_service; + session_class->get_password = mail_session_get_password; + session_class->forget_password = mail_session_forget_password; + session_class->alert_user = mail_session_alert_user; + session_class->get_filter_driver = mail_session_get_filter_driver; + session_class->lookup_addressbook = mail_session_lookup_addressbook; + session_class->forward_to = mail_session_forward_to; + session_class->get_socks_proxy = mail_session_get_socks_proxy; + session_class->authenticate_sync = mail_session_authenticate_sync; + + g_object_class_install_property ( + object_class, + PROP_FOLDER_CACHE, + g_param_spec_object ( + "folder-cache", + NULL, + NULL, + MAIL_TYPE_FOLDER_CACHE, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + /* XXX This property can be removed once Evolution moves to + * GSettings and can use transform functions when binding + * properties to settings. */ + g_object_class_install_property ( + object_class, + PROP_JUNK_FILTER_NAME, + g_param_spec_string ( + "junk-filter-name", + NULL, + NULL, + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property ( + object_class, + PROP_LOCAL_STORE, + g_param_spec_object ( + "local-store", + "Local Store", + "Built-in local store", + CAMEL_TYPE_STORE, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * EMailSession::flush-outbox + * @session: the email session + * + * Emitted if the send folder should be flushed. + **/ + signals[FLUSH_OUTBOX] = g_signal_new ( + "flush-outbox", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, /* struct offset */ + NULL, NULL, /* accumulator */ + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + /** + * EMailSession::store-added + * @session: the email session + * @store: the CamelStore + * + * Emitted when a store is added + **/ + signals[STORE_ADDED] = g_signal_new ( + "store-added", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, /* struct offset */ + NULL, NULL, /* accumulator */ + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + CAMEL_TYPE_STORE); + + + /** + * EMailSession::store-removed + * @session: the email session + * @store: the CamelStore + * + * Emitted when a store is removed + **/ + signals[STORE_REMOVED] = g_signal_new ( + "store-removed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, /* struct offset */ + NULL, NULL, /* accumulator */ + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + CAMEL_TYPE_STORE); + + +} + +static void +e_mail_session_init (EMailSession *session) +{ + GSettings *settings; + GHashTable *junk_filters; + + junk_filters = g_hash_table_new ( + (GHashFunc) g_str_hash, + (GEqualFunc) g_str_equal); + + session->priv = E_MAIL_SESSION_GET_PRIVATE (session); + session->priv->junk_filters = junk_filters; + session->priv->proxy = e_proxy_new (); + + session->priv->local_folders = + g_ptr_array_new_with_free_func ( + (GDestroyNotify) g_object_unref); + session->priv->local_folder_uris = + g_ptr_array_new_with_free_func ( + (GDestroyNotify) g_free); + + /* Initialize the EAccount setup. */ + e_account_writable (NULL, E_ACCOUNT_SOURCE_SAVE_PASSWD); + + settings = g_settings_new ("org.gnome.evolution.mail"); + + camel_session_set_check_junk ( + CAMEL_SESSION (session), g_settings_get_boolean ( + settings, "junk-check-incoming")); + g_signal_connect ( + settings, "changed", + G_CALLBACK (mail_session_check_junk_notify), session); + + mail_config_reload_junk_headers (session); + + e_proxy_setup_proxy (session->priv->proxy); + + g_object_unref (settings); +} + +EMailSession * +e_mail_session_new (void) +{ + const gchar *user_data_dir; + const gchar *user_cache_dir; + + user_data_dir = mail_session_get_data_dir (); + user_cache_dir = mail_session_get_cache_dir (); + + return g_object_new ( + E_TYPE_MAIL_SESSION, + "user-data-dir", user_data_dir, + "user-cache-dir", user_cache_dir, + NULL); +} + +MailFolderCache * +e_mail_session_get_folder_cache (EMailSession *session) +{ + g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); + + return session->priv->folder_cache; +} + +CamelStore * +e_mail_session_get_local_store (EMailSession *session) +{ + g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); + + return session->priv->local_store; +} + +CamelFolder * +e_mail_session_get_local_folder (EMailSession *session, + EMailLocalFolder type) +{ + GPtrArray *local_folders; + CamelFolder *folder; + + g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); + + local_folders = session->priv->local_folders; + g_return_val_if_fail (type < local_folders->len, NULL); + + folder = g_ptr_array_index (local_folders, type); + g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL); + + return folder; +} + +const gchar * +e_mail_session_get_local_folder_uri (EMailSession *session, + EMailLocalFolder type) +{ + GPtrArray *local_folder_uris; + const gchar *folder_uri; + + g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); + + local_folder_uris = session->priv->local_folder_uris; + g_return_val_if_fail (type < local_folder_uris->len, NULL); + + folder_uri = g_ptr_array_index (local_folder_uris, type); + g_return_val_if_fail (folder_uri != NULL, NULL); + + return folder_uri; +} + +GList * +e_mail_session_get_available_junk_filters (EMailSession *session) +{ + GList *list, *link; + GQueue trash = G_QUEUE_INIT; + + g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); + + list = g_hash_table_get_values (session->priv->junk_filters); + + /* Discard unavailable junk filters. (e.g. Junk filter + * requires Bogofilter but Bogofilter is not installed, + * hence the junk filter is unavailable.) */ + + for (link = list; link != NULL; link = g_list_next (link)) { + EMailJunkFilter *junk_filter; + + junk_filter = E_MAIL_JUNK_FILTER (link->data); + if (!e_mail_junk_filter_available (junk_filter)) + g_queue_push_tail (&trash, link); + } + + while ((link = g_queue_pop_head (&trash)) != NULL) + list = g_list_delete_link (list, link); + + /* Sort the remaining junk filters by display name. */ + + return g_list_sort (list, (GCompareFunc) e_mail_junk_filter_compare); +} + +static void +mail_session_get_inbox_thread (GSimpleAsyncResult *simple, + EMailSession *session, + GCancellable *cancellable) +{ + AsyncContext *context; + GError *error = NULL; + + context = g_simple_async_result_get_op_res_gpointer (simple); + + context->folder = e_mail_session_get_inbox_sync ( + session, context->uid, cancellable, &error); + + if (error != NULL) + g_simple_async_result_take_error (simple, error); +} + +CamelFolder * +e_mail_session_get_inbox_sync (EMailSession *session, + const gchar *service_uid, + GCancellable *cancellable, + GError **error) +{ + CamelService *service; + + g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); + g_return_val_if_fail (service_uid != NULL, NULL); + + service = camel_session_get_service ( + CAMEL_SESSION (session), service_uid); + + if (!CAMEL_IS_STORE (service)) + return NULL; + + if (!em_utils_connect_service_sync (service, cancellable, error)) + return NULL; + + return camel_store_get_inbox_folder_sync ( + CAMEL_STORE (service), cancellable, error); +} + +void +e_mail_session_get_inbox (EMailSession *session, + const gchar *service_uid, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *context; + + g_return_if_fail (E_IS_MAIL_SESSION (session)); + g_return_if_fail (service_uid != NULL); + + context = g_slice_new0 (AsyncContext); + context->uid = g_strdup (service_uid); + + simple = g_simple_async_result_new ( + G_OBJECT (session), callback, + user_data, e_mail_session_get_inbox); + + g_simple_async_result_set_op_res_gpointer ( + simple, context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, (GSimpleAsyncThreadFunc) + mail_session_get_inbox_thread, + io_priority, cancellable); + + g_object_unref (simple); +} + +CamelFolder * +e_mail_session_get_inbox_finish (EMailSession *session, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + AsyncContext *context; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (session), + e_mail_session_get_inbox), NULL); + + simple = G_SIMPLE_ASYNC_RESULT (result); + context = g_simple_async_result_get_op_res_gpointer (simple); + + if (g_simple_async_result_propagate_error (simple, error)) + return NULL; + + g_return_val_if_fail (CAMEL_IS_FOLDER (context->folder), NULL); + + return g_object_ref (context->folder); +} + +static void +mail_session_get_trash_thread (GSimpleAsyncResult *simple, + EMailSession *session, + GCancellable *cancellable) +{ + AsyncContext *context; + GError *error = NULL; + + context = g_simple_async_result_get_op_res_gpointer (simple); + + context->folder = e_mail_session_get_trash_sync ( + session, context->uid, cancellable, &error); + + if (error != NULL) + g_simple_async_result_take_error (simple, error); +} + +CamelFolder * +e_mail_session_get_trash_sync (EMailSession *session, + const gchar *service_uid, + GCancellable *cancellable, + GError **error) +{ + CamelService *service; + + g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); + g_return_val_if_fail (service_uid != NULL, NULL); + + service = camel_session_get_service ( + CAMEL_SESSION (session), service_uid); + + if (!CAMEL_IS_STORE (service)) + return NULL; + + if (!em_utils_connect_service_sync (service, cancellable, error)) + return NULL; + + return camel_store_get_trash_folder_sync ( + CAMEL_STORE (service), cancellable, error); +} + +void +e_mail_session_get_trash (EMailSession *session, + const gchar *service_uid, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *context; + + g_return_if_fail (E_IS_MAIL_SESSION (session)); + g_return_if_fail (service_uid != NULL); + + context = g_slice_new0 (AsyncContext); + context->uid = g_strdup (service_uid); + + simple = g_simple_async_result_new ( + G_OBJECT (session), callback, + user_data, e_mail_session_get_trash); + + g_simple_async_result_set_op_res_gpointer ( + simple, context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, (GSimpleAsyncThreadFunc) + mail_session_get_trash_thread, + io_priority, cancellable); + + g_object_unref (simple); +} + +CamelFolder * +e_mail_session_get_trash_finish (EMailSession *session, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + AsyncContext *context; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (session), + e_mail_session_get_trash), NULL); + + simple = G_SIMPLE_ASYNC_RESULT (result); + context = g_simple_async_result_get_op_res_gpointer (simple); + + if (g_simple_async_result_propagate_error (simple, error)) + return NULL; + + g_return_val_if_fail (CAMEL_IS_FOLDER (context->folder), NULL); + + return g_object_ref (context->folder); +} + +static void +mail_session_uri_to_folder_thread (GSimpleAsyncResult *simple, + EMailSession *session, + GCancellable *cancellable) +{ + AsyncContext *context; + GError *error = NULL; + + context = g_simple_async_result_get_op_res_gpointer (simple); + + context->folder = e_mail_session_uri_to_folder_sync ( + session, context->uri, context->flags, + cancellable, &error); + + if (error != NULL) + g_simple_async_result_take_error (simple, error); +} + +CamelFolder * +e_mail_session_uri_to_folder_sync (EMailSession *session, + const gchar *folder_uri, + CamelStoreGetFolderFlags flags, + GCancellable *cancellable, + GError **error) +{ + CamelStore *store; + CamelFolder *folder; + gchar *folder_name; + gboolean success; + + g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); + g_return_val_if_fail (folder_uri != NULL, NULL); + + success = e_mail_folder_uri_parse ( + CAMEL_SESSION (session), folder_uri, + &store, &folder_name, error); + + if (!success) + return NULL; + + folder = camel_store_get_folder_sync ( + store, folder_name, flags, cancellable, error); + + if (folder != NULL) { + MailFolderCache *folder_cache; + folder_cache = e_mail_session_get_folder_cache (session); + mail_folder_cache_note_folder (folder_cache, folder); + } + + g_free (folder_name); + g_object_unref (store); + + return folder; +} + +void +e_mail_session_uri_to_folder (EMailSession *session, + const gchar *folder_uri, + CamelStoreGetFolderFlags flags, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *context; + + g_return_if_fail (E_IS_MAIL_SESSION (session)); + g_return_if_fail (folder_uri != NULL); + + context = g_slice_new0 (AsyncContext); + context->uri = g_strdup (folder_uri); + context->flags = flags; + + simple = g_simple_async_result_new ( + G_OBJECT (session), callback, + user_data, e_mail_session_uri_to_folder); + + g_simple_async_result_set_op_res_gpointer ( + simple, context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, (GSimpleAsyncThreadFunc) + mail_session_uri_to_folder_thread, + io_priority, cancellable); + + g_object_unref (simple); +} + +CamelFolder * +e_mail_session_uri_to_folder_finish (EMailSession *session, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + AsyncContext *context; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (session), + e_mail_session_uri_to_folder), NULL); + + simple = G_SIMPLE_ASYNC_RESULT (result); + context = g_simple_async_result_get_op_res_gpointer (simple); + + if (g_simple_async_result_propagate_error (simple, error)) + return NULL; + + g_return_val_if_fail (CAMEL_IS_FOLDER (context->folder), NULL); + + return g_object_ref (context->folder); +} + +/******************************** Legacy API *********************************/ + +void +mail_session_flush_filter_log (EMailSession *session) +{ + g_return_if_fail (E_IS_MAIL_SESSION (session)); + + if (session->priv->filter_logfile) + fflush (session->priv->filter_logfile); +} + +const gchar * +mail_session_get_data_dir (void) +{ + if (G_UNLIKELY (mail_data_dir == NULL)) + mail_data_dir = g_build_filename ( + e_get_user_data_dir (), "mail", NULL); + + return mail_data_dir; +} + +const gchar * +mail_session_get_cache_dir (void) +{ + if (G_UNLIKELY (mail_cache_dir == NULL)) + mail_cache_dir = g_build_filename ( + e_get_user_cache_dir (), "mail", NULL); + + return mail_cache_dir; +} + +const gchar * +mail_session_get_config_dir (void) +{ + if (G_UNLIKELY (mail_config_dir == NULL)) + mail_config_dir = g_build_filename ( + e_get_user_config_dir (), "mail", NULL); + + return mail_config_dir; +} + diff --git a/libemail-engine/e-mail-session.h b/libemail-engine/e-mail-session.h new file mode 100644 index 0000000000..af7892dc22 --- /dev/null +++ b/libemail-engine/e-mail-session.h @@ -0,0 +1,135 @@ +/* + * e-mail-session.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + * + * Authors: + * Jeffrey Stedfast + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef E_MAIL_SESSION_H +#define E_MAIL_SESSION_H + +#include +#include +#include + +/* Standard GObject macros */ +#define E_TYPE_MAIL_SESSION \ + (e_mail_session_get_type ()) +#define E_MAIL_SESSION(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_MAIL_SESSION, EMailSession)) +#define E_MAIL_SESSION_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_MAIL_SESSION, EMailSessionClass)) +#define E_IS_MAIL_SESSION(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_MAIL_SESSION)) +#define E_IS_MAIL_SESSION_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_MAIL_SESSION)) +#define E_MAIL_SESSION_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_MAIL_SESSION, EMailSessionClass)) + +/* Built-in CamelServices */ +#define E_MAIL_SESSION_LOCAL_UID "local" /* "On This Computer" */ +#define E_MAIL_SESSION_VFOLDER_UID "vfolder" /* "Search Folders" */ + +G_BEGIN_DECLS + +typedef struct _EMailSession EMailSession; +typedef struct _EMailSessionClass EMailSessionClass; +typedef struct _EMailSessionPrivate EMailSessionPrivate; + +struct _EMailSession { + CamelSession parent; + EMailSessionPrivate *priv; +}; + +struct _EMailSessionClass { + CamelSessionClass parent_class; +}; + +GType e_mail_session_get_type (void); +EMailSession * e_mail_session_new (void); +MailFolderCache * + e_mail_session_get_folder_cache (EMailSession *session); +CamelStore * e_mail_session_get_local_store (EMailSession *session); +CamelFolder * e_mail_session_get_local_folder (EMailSession *session, + EMailLocalFolder type); +const gchar * e_mail_session_get_local_folder_uri + (EMailSession *session, + EMailLocalFolder type); +GList * e_mail_session_get_available_junk_filters + (EMailSession *session); +CamelFolder * e_mail_session_get_inbox_sync (EMailSession *session, + const gchar *service_uid, + GCancellable *cancellable, + GError **error); +void e_mail_session_get_inbox (EMailSession *session, + const gchar *service_uid, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +CamelFolder * e_mail_session_get_inbox_finish (EMailSession *session, + GAsyncResult *result, + GError **error); +CamelFolder * e_mail_session_get_trash_sync (EMailSession *session, + const gchar *service_uid, + GCancellable *cancellable, + GError **error); +void e_mail_session_get_trash (EMailSession *session, + const gchar *service_uid, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +CamelFolder * e_mail_session_get_trash_finish (EMailSession *session, + GAsyncResult *result, + GError **error); +CamelFolder * e_mail_session_uri_to_folder_sync + (EMailSession *session, + const gchar *folder_uri, + CamelStoreGetFolderFlags flags, + GCancellable *cancellable, + GError **error); +void e_mail_session_uri_to_folder (EMailSession *session, + const gchar *folder_uri, + CamelStoreGetFolderFlags flags, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +CamelFolder * e_mail_session_uri_to_folder_finish + (EMailSession *session, + GAsyncResult *result, + GError **error); + +/*** Legacy API ***/ + +void mail_session_flush_filter_log (EMailSession *session); +const gchar * mail_session_get_data_dir (void); +const gchar * mail_session_get_cache_dir (void); +const gchar * mail_session_get_config_dir (void); + +G_END_DECLS + +#endif /* E_MAIL_SESSION_H */ diff --git a/libemail-engine/e-mail-store-utils.c b/libemail-engine/e-mail-store-utils.c new file mode 100644 index 0000000000..757f86dfd5 --- /dev/null +++ b/libemail-engine/e-mail-store-utils.c @@ -0,0 +1,385 @@ +/* + * e-mail-store-utils.c + * + * 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 + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "e-mail-utils.h" + +#include "e-mail-store-utils.h" + +#include + +typedef struct _AsyncContext AsyncContext; + +struct _AsyncContext { + gchar *full_name; +}; + +static void +async_context_free (AsyncContext *context) +{ + g_free (context->full_name); + + g_slice_free (AsyncContext, context); +} + +static void +mail_store_create_folder_thread (GSimpleAsyncResult *simple, + GObject *object, + GCancellable *cancellable) +{ + AsyncContext *context; + GError *error = NULL; + + context = g_simple_async_result_get_op_res_gpointer (simple); + + e_mail_store_create_folder_sync ( + CAMEL_STORE (object), context->full_name, + cancellable, &error); + + if (error != NULL) + g_simple_async_result_take_error (simple, error); +} + +gboolean +e_mail_store_create_folder_sync (CamelStore *store, + const gchar *full_name, + GCancellable *cancellable, + GError **error) +{ + CamelFolderInfo *folder_info; + gchar *copied_full_name; + gchar *display_name; + const gchar *parent; + gboolean success = TRUE; + + g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE); + g_return_val_if_fail (full_name != NULL, FALSE); + + copied_full_name = g_strdup (full_name); + display_name = strrchr (copied_full_name, '/'); + if (display_name == NULL) { + display_name = copied_full_name; + parent = ""; + } else { + *display_name++ = '\0'; + parent = copied_full_name; + } + + folder_info = camel_store_create_folder_sync ( + store, parent, display_name, cancellable, error); + + g_free (copied_full_name); + + if (folder_info == NULL) + return FALSE; + + if (CAMEL_IS_SUBSCRIBABLE (store)) + success = camel_subscribable_subscribe_folder_sync ( + CAMEL_SUBSCRIBABLE (store), + full_name, cancellable, error); + + camel_store_free_folder_info (store, folder_info); + + return success; +} + +void +e_mail_store_create_folder (CamelStore *store, + const gchar *full_name, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *context; + + g_return_if_fail (CAMEL_IS_STORE (store)); + g_return_if_fail (full_name != NULL); + + context = g_slice_new0 (AsyncContext); + context->full_name = g_strdup (full_name); + + simple = g_simple_async_result_new ( + G_OBJECT (store), callback, user_data, + e_mail_store_create_folder); + + g_simple_async_result_set_op_res_gpointer ( + simple, context, (GDestroyNotify) async_context_free); + + g_simple_async_result_run_in_thread ( + simple, mail_store_create_folder_thread, + io_priority, cancellable); + + g_object_unref (simple); +} + +gboolean +e_mail_store_create_folder_finish (CamelStore *store, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (store), + e_mail_store_create_folder), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + + /* Assume success unless a GError is set. */ + return !g_simple_async_result_propagate_error (simple, error); +} + +static void +mail_store_go_offline_thread (GSimpleAsyncResult *simple, + CamelStore *store, + GCancellable *cancellable) +{ + CamelService *service; + gchar *service_name; + GError *error = NULL; + + service = CAMEL_SERVICE (store); + + service_name = camel_service_get_name (service, TRUE); + camel_operation_push_message ( + cancellable, _("Disconnecting from '%s'"), service_name); + g_free (service_name); + + if (CAMEL_IS_DISCO_STORE (store)) { + CamelDiscoStore *disco_store; + + disco_store = CAMEL_DISCO_STORE (store); + + if (camel_disco_store_can_work_offline (disco_store)) + camel_disco_store_set_status ( + disco_store, CAMEL_DISCO_STORE_OFFLINE, + cancellable, &error); + else + em_utils_disconnect_service_sync (service, TRUE, cancellable, &error); + + } else if (CAMEL_IS_OFFLINE_STORE (store)) { + CamelOfflineStore *offline_store; + + offline_store = CAMEL_OFFLINE_STORE (store); + + camel_offline_store_set_online_sync ( + offline_store, FALSE, cancellable, &error); + + } else + em_utils_disconnect_service_sync (service, TRUE, cancellable, &error); + + if (error != NULL) + g_simple_async_result_take_error (simple, error); + + camel_operation_pop_message (cancellable); +} + +void +e_mail_store_go_offline (CamelStore *store, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + + g_return_if_fail (CAMEL_IS_STORE (store)); + + /* Cancel any pending connect first so the set_offline_op + * thread won't get queued behind a hung connect op. */ + camel_service_cancel_connect (CAMEL_SERVICE (store)); + + simple = g_simple_async_result_new ( + G_OBJECT (store), callback, + user_data, e_mail_store_go_offline); + + g_simple_async_result_run_in_thread ( + simple, (GSimpleAsyncThreadFunc) + mail_store_go_offline_thread, + io_priority, cancellable); + + g_object_unref (simple); +} + +gboolean +e_mail_store_go_offline_finish (CamelStore *store, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (store), e_mail_store_go_offline), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + + /* Assume success unless a GError is set. */ + return !g_simple_async_result_propagate_error (simple, error); +} + +static void +mail_store_go_online_thread (GSimpleAsyncResult *simple, + CamelStore *store, + GCancellable *cancellable) +{ + CamelService *service; + gchar *service_name; + GError *error = NULL; + + service = CAMEL_SERVICE (store); + + service_name = camel_service_get_name (service, TRUE); + camel_operation_push_message ( + cancellable, _("Reconnecting to '%s'"), service_name); + g_free (service_name); + + if (CAMEL_IS_DISCO_STORE (store)) + camel_disco_store_set_status ( + CAMEL_DISCO_STORE (store), + CAMEL_DISCO_STORE_ONLINE, + cancellable, &error); + + else if (CAMEL_IS_OFFLINE_STORE (store)) + camel_offline_store_set_online_sync ( + CAMEL_OFFLINE_STORE (store), + TRUE, cancellable, &error); + + if (error != NULL) + g_simple_async_result_take_error (simple, error); + + camel_operation_pop_message (cancellable); +} + +void +e_mail_store_go_online (CamelStore *store, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + + g_return_if_fail (CAMEL_IS_STORE (store)); + + simple = g_simple_async_result_new ( + G_OBJECT (store), callback, + user_data, e_mail_store_go_online); + + g_simple_async_result_run_in_thread ( + simple, (GSimpleAsyncThreadFunc) + mail_store_go_online_thread, + io_priority, cancellable); + + g_object_unref (simple); +} + +gboolean +e_mail_store_go_online_finish (CamelStore *store, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (store), e_mail_store_go_online), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + + /* Assume success unless a GError is set. */ + return !g_simple_async_result_propagate_error (simple, error); +} + +static void +mail_store_prepare_for_offline_thread (GSimpleAsyncResult *simple, + CamelStore *store, + GCancellable *cancellable) +{ + CamelService *service; + gchar *service_name; + GError *error = NULL; + + service = CAMEL_SERVICE (store); + + service_name = camel_service_get_name (service, TRUE); + camel_operation_push_message ( + cancellable, _("Preparing account '%s' for offline"), + service_name); + g_free (service_name); + + if (CAMEL_IS_DISCO_STORE (store)) + camel_disco_store_prepare_for_offline ( + CAMEL_DISCO_STORE (store), cancellable, &error); + + else if (CAMEL_IS_OFFLINE_STORE (store)) + camel_offline_store_prepare_for_offline_sync ( + CAMEL_OFFLINE_STORE (store), cancellable, &error); + + if (error != NULL) + g_simple_async_result_take_error (simple, error); + + camel_operation_pop_message (cancellable); +} + +void +e_mail_store_prepare_for_offline (CamelStore *store, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + + g_return_if_fail (CAMEL_IS_STORE (store)); + + simple = g_simple_async_result_new ( + G_OBJECT (store), callback, user_data, + e_mail_store_prepare_for_offline); + + g_simple_async_result_run_in_thread ( + simple, (GSimpleAsyncThreadFunc) + mail_store_prepare_for_offline_thread, + io_priority, cancellable); + + g_object_unref (simple); +} + +gboolean +e_mail_store_prepare_for_offline_finish (CamelStore *store, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (store), + e_mail_store_prepare_for_offline), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + + /* Assume success unless a GError is set. */ + return !g_simple_async_result_propagate_error (simple, error); +} diff --git a/libemail-engine/e-mail-store-utils.h b/libemail-engine/e-mail-store-utils.h new file mode 100644 index 0000000000..de4484c020 --- /dev/null +++ b/libemail-engine/e-mail-store-utils.h @@ -0,0 +1,74 @@ +/* + * e-mail-store-utils.h + * + * 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 + * + */ + +#ifndef E_MAIL_STORE_UTILS_H +#define E_MAIL_STORE_UTILS_H + +/* CamelStore wrappers with Evolution-specific policies. */ + +#include + +G_BEGIN_DECLS + +gboolean e_mail_store_create_folder_sync (CamelStore *store, + const gchar *full_name, + GCancellable *cancellable, + GError **error); +void e_mail_store_create_folder (CamelStore *store, + const gchar *full_name, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean e_mail_store_create_folder_finish + (CamelStore *store, + GAsyncResult *result, + GError **error); + +void e_mail_store_go_offline (CamelStore *store, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean e_mail_store_go_offline_finish (CamelStore *store, + GAsyncResult *result, + GError **error); + +void e_mail_store_go_online (CamelStore *store, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean e_mail_store_go_online_finish (CamelStore *store, + GAsyncResult *result, + GError **error); + +void e_mail_store_prepare_for_offline + (CamelStore *store, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean e_mail_store_prepare_for_offline_finish + (CamelStore *store, + GAsyncResult *result, + GError **error); + +G_END_DECLS + +#endif /* E_MAIL_STORE_UTILS_H */ diff --git a/libemail-engine/e-mail-utils.c b/libemail-engine/e-mail-utils.c new file mode 100644 index 0000000000..05f5381147 --- /dev/null +++ b/libemail-engine/e-mail-utils.c @@ -0,0 +1,1062 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + * + * Authors: + * Srinivasa Ragavan + * + * + */ + +#include +#include +#include +#include +#include +#include + +#include + +#ifdef G_OS_WIN32 +/* Work around namespace clobbage in */ +#define DATADIR windows_DATADIR +#include +#undef DATADIR +#undef interface +#endif + +#include +#include + + +#include + +#include + +#include +#include +#include + +#include "libemail-utils/e-account-utils.h" +#include "libemail-utils/mail-mt.h" + +#include "e-mail-folder-utils.h" +#include "e-mail-session.h" +#include "e-mail-utils.h" +#include "mail-tools.h" + +#define d(x) + +/** + * em_utils_folder_is_templates: + * @folder: a #CamelFolder + * + * Decides if @folder is a Templates folder. + * + * Returns %TRUE if this is a Templates folder or %FALSE otherwise. + **/ + +gboolean +em_utils_folder_is_templates (CamelFolder *folder) +{ + CamelFolder *local_templates_folder; + CamelSession *session; + CamelStore *store; + EAccountList *account_list; + EIterator *iterator; + gchar *folder_uri; + gboolean is_templates = FALSE; + + g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); + + store = camel_folder_get_parent_store (folder); + session = camel_service_get_session (CAMEL_SERVICE (store)); + + local_templates_folder = + e_mail_session_get_local_folder ( + E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_TEMPLATES); + + if (folder == local_templates_folder) + return TRUE; + + folder_uri = e_mail_folder_uri_from_folder (folder); + + account_list = e_get_account_list (); + iterator = e_list_get_iterator (E_LIST (account_list)); + + while (!is_templates && e_iterator_is_valid (iterator)) { + EAccount *account; + + /* XXX EIterator misuses const. */ + account = (EAccount *) e_iterator_get (iterator); + + if (account->templates_folder_uri != NULL) + is_templates = e_mail_folder_uri_equal ( + session, folder_uri, + account->templates_folder_uri); + + e_iterator_next (iterator); + } + + g_object_unref (iterator); + g_free (folder_uri); + + return is_templates; +} + +/** + * em_utils_folder_is_drafts: + * @folder: a #CamelFolder + * + * 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) +{ + CamelFolder *local_drafts_folder; + CamelSession *session; + CamelStore *store; + EAccountList *account_list; + EIterator *iterator; + gchar *folder_uri; + gboolean is_drafts = FALSE; + + g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); + + store = camel_folder_get_parent_store (folder); + session = camel_service_get_session (CAMEL_SERVICE (store)); + + local_drafts_folder = + e_mail_session_get_local_folder ( + E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_DRAFTS); + + if (folder == local_drafts_folder) + return TRUE; + + folder_uri = e_mail_folder_uri_from_folder (folder); + + account_list = e_get_account_list (); + iterator = e_list_get_iterator (E_LIST (account_list)); + + while (!is_drafts && e_iterator_is_valid (iterator)) { + EAccount *account; + + /* XXX EIterator misuses const. */ + account = (EAccount *) e_iterator_get (iterator); + + if (account->drafts_folder_uri != NULL) + is_drafts = e_mail_folder_uri_equal ( + session, folder_uri, + account->drafts_folder_uri); + + e_iterator_next (iterator); + } + + g_object_unref (iterator); + g_free (folder_uri); + + return is_drafts; +} + +/** + * em_utils_folder_is_sent: + * @folder: a #CamelFolder + * + * 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) +{ + CamelFolder *local_sent_folder; + CamelSession *session; + CamelStore *store; + EAccountList *account_list; + EIterator *iterator; + gchar *folder_uri; + gboolean is_sent = FALSE; + + g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); + + store = camel_folder_get_parent_store (folder); + session = camel_service_get_session (CAMEL_SERVICE (store)); + + local_sent_folder = + e_mail_session_get_local_folder ( + E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_SENT); + + if (folder == local_sent_folder) + return TRUE; + + folder_uri = e_mail_folder_uri_from_folder (folder); + + account_list = e_get_account_list (); + iterator = e_list_get_iterator (E_LIST (account_list)); + + while (!is_sent && e_iterator_is_valid (iterator)) { + EAccount *account; + + /* XXX EIterator misuses const. */ + account = (EAccount *) e_iterator_get (iterator); + + if (account->sent_folder_uri != NULL) + is_sent = e_mail_folder_uri_equal ( + session, folder_uri, + account->sent_folder_uri); + + e_iterator_next (iterator); + } + + g_object_unref (iterator); + g_free (folder_uri); + + return is_sent; +} + +/** + * em_utils_folder_is_outbox: + * @folder: a #CamelFolder + * + * 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) +{ + CamelStore *store; + CamelSession *session; + CamelFolder *local_outbox_folder; + + g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); + + store = camel_folder_get_parent_store (folder); + session = camel_service_get_session (CAMEL_SERVICE (store)); + + local_outbox_folder = + e_mail_session_get_local_folder ( + E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_OUTBOX); + + return (folder == local_outbox_folder); +} + +/* ********************************************************************** */ + + +/* runs sync, in main thread */ +static gpointer +emu_addr_setup (gpointer user_data) +{ + GError *err = NULL; + ESourceList **psource_list = user_data; + + if (!e_book_client_get_sources (psource_list, &err)) + g_error_free (err); + + return NULL; +} + +static void +emu_addr_cancel_stop (gpointer data) +{ + gboolean *stop = data; + + g_return_if_fail (stop != NULL); + + *stop = TRUE; +} + +static void +emu_addr_cancel_cancellable (gpointer data) +{ + GCancellable *cancellable = data; + + g_return_if_fail (cancellable != NULL); + + g_cancellable_cancel (cancellable); +} + +struct TryOpenEBookStruct { + GError **error; + EFlag *flag; + gboolean result; +}; + +static void +try_open_book_client_cb (GObject *source_object, + GAsyncResult *result, + gpointer closure) +{ + EBookClient *book_client = E_BOOK_CLIENT (source_object); + struct TryOpenEBookStruct *data = (struct TryOpenEBookStruct *) closure; + GError *error = NULL; + + if (!data) + return; + + e_client_open_finish (E_CLIENT (book_client), result, &error); + + data->result = error == NULL; + + if (!data->result) { + g_clear_error (data->error); + g_propagate_error (data->error, error); + } + + e_flag_set (data->flag); +} + +/* + * try_open_book_client: + * Tries to open address book asynchronously, but acts as synchronous. + * The advantage is it checks periodically whether the camel_operation + * has been canceled or not, and if so, then stops immediately, with + * result FALSE. Otherwise returns same as e_client_open() + */ +static gboolean +try_open_book_client (EBookClient *book_client, + gboolean only_if_exists, + GCancellable *cancellable, + GError **error) +{ + struct TryOpenEBookStruct data; + gboolean canceled = FALSE; + EFlag *flag = e_flag_new (); + + data.error = error; + data.flag = flag; + data.result = FALSE; + + e_client_open ( + E_CLIENT (book_client), only_if_exists, + cancellable, try_open_book_client_cb, &data); + + while (canceled = g_cancellable_is_cancelled (cancellable), + !canceled && !e_flag_is_set (flag)) { + GTimeVal wait; + + g_get_current_time (&wait); + g_time_val_add (&wait, 250000); /* waits 250ms */ + + e_flag_timed_wait (flag, &wait); + } + + if (canceled) { + g_cancellable_cancel (cancellable); + + g_clear_error (error); + g_propagate_error ( + error, e_client_error_create ( + E_CLIENT_ERROR_CANCELLED, NULL)); + } + + e_flag_wait (flag); + e_flag_free (flag); + + return data.result && (!error || !*error); +} + + +#define NOT_FOUND_BOOK (GINT_TO_POINTER (1)) + +G_LOCK_DEFINE_STATIC (contact_cache); + +/* key is lowercased contact email; value is EBook pointer + * (just for comparison) where it comes from */ +static GHashTable *contact_cache = NULL; + +/* key is source ID; value is pointer to EBook */ +static GHashTable *emu_books_hash = NULL; + +/* key is source ID; value is same pointer as key; this is hash of + * broken books, which failed to open for some reason */ +static GHashTable *emu_broken_books_hash = NULL; + +static ESourceList *emu_books_source_list = NULL; + +static gboolean +search_address_in_addressbooks (const gchar *address, + gboolean local_only, + gboolean (*check_contact) (EContact *contact, + gpointer user_data), + gpointer user_data) +{ + gboolean found = FALSE, stop = FALSE, found_any = FALSE; + gchar *lowercase_addr; + gpointer ptr; + EBookQuery *book_query; + gchar *query; + GSList *s, *g, *addr_sources = NULL; + GHook *hook_cancellable; + GCancellable *cancellable; + + if (!address || !*address) + return FALSE; + + G_LOCK (contact_cache); + + if (!emu_books_source_list) { + mail_call_main ( + MAIL_CALL_p_p, (MailMainFunc) + emu_addr_setup, &emu_books_source_list); + emu_books_hash = g_hash_table_new_full ( + g_str_hash, g_str_equal, g_free, g_object_unref); + emu_broken_books_hash = g_hash_table_new_full ( + g_str_hash, g_str_equal, g_free, NULL); + contact_cache = g_hash_table_new_full ( + g_str_hash, g_str_equal, g_free, NULL); + } + + if (!emu_books_source_list) { + G_UNLOCK (contact_cache); + return FALSE; + } + + lowercase_addr = g_utf8_strdown (address, -1); + ptr = g_hash_table_lookup (contact_cache, lowercase_addr); + if (ptr != NULL && (check_contact == NULL || ptr == NOT_FOUND_BOOK)) { + g_free (lowercase_addr); + G_UNLOCK (contact_cache); + return ptr != NOT_FOUND_BOOK; + } + + book_query = e_book_query_field_test (E_CONTACT_EMAIL, E_BOOK_QUERY_IS, address); + query = e_book_query_to_string (book_query); + e_book_query_unref (book_query); + + for (g = e_source_list_peek_groups (emu_books_source_list); + g; g = g_slist_next (g)) { + ESourceGroup *group = g->data; + + if (!group) + continue; + + if (local_only && !(e_source_group_peek_base_uri (group) && + g_str_has_prefix ( + e_source_group_peek_base_uri (group), "local:"))) + continue; + + for (s = e_source_group_peek_sources (group); s; s = g_slist_next (s)) { + ESource *source = s->data; + const gchar *completion = e_source_get_property (source, "completion"); + + if (completion && g_ascii_strcasecmp (completion, "true") == 0) { + addr_sources = g_slist_prepend (addr_sources, g_object_ref (source)); + } + } + } + + cancellable = g_cancellable_new (); + hook_cancellable = mail_cancel_hook_add (emu_addr_cancel_cancellable, cancellable); + + for (s = addr_sources; !stop && !found && s; s = g_slist_next (s)) { + ESource *source = s->data; + GSList *contacts; + EBookClient *book_client = NULL; + GHook *hook_stop; + gboolean cached_book = FALSE; + const gchar *display_name; + const gchar *uid; + GError *err = NULL; + + uid = e_source_peek_uid (source); + display_name = e_source_peek_name (source); + + /* failed to load this book last time, skip it now */ + if (g_hash_table_lookup (emu_broken_books_hash, uid) != NULL) { + d(printf ("%s: skipping broken book '%s'\n", + G_STRFUNC, display_name)); + continue; + } + + d(printf(" checking '%s'\n", e_source_get_uri(source))); + + hook_stop = mail_cancel_hook_add (emu_addr_cancel_stop, &stop); + + book_client = g_hash_table_lookup (emu_books_hash, uid); + if (!book_client) { + book_client = e_book_client_new (source, &err); + + if (book_client == NULL) { + if (err && (g_error_matches (err, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) || + g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED))) { + stop = TRUE; + } else if (err) { + gchar *source_uid; + + source_uid = g_strdup (uid); + + g_hash_table_insert ( + emu_broken_books_hash, + source_uid, source_uid); + + g_warning ( + "%s: Unable to create addressbook '%s': %s", + G_STRFUNC, + display_name, + err->message); + } + g_clear_error (&err); + } else if (!stop && !try_open_book_client (book_client, TRUE, cancellable, &err)) { + g_object_unref (book_client); + book_client = NULL; + + if (err && (g_error_matches (err, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) || + g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED))) { + stop = TRUE; + } else if (err) { + gchar *source_uid; + + source_uid = g_strdup (uid); + + g_hash_table_insert ( + emu_broken_books_hash, + source_uid, source_uid); + + g_warning ( + "%s: Unable to open addressbook '%s': %s", + G_STRFUNC, + display_name, + err->message); + } + g_clear_error (&err); + } + } else { + cached_book = TRUE; + } + + if (book_client && !stop && e_book_client_get_contacts_sync (book_client, query, &contacts, cancellable, &err)) { + if (contacts != NULL) { + if (!found_any) { + g_hash_table_insert (contact_cache, g_strdup (lowercase_addr), book_client); + } + found_any = TRUE; + + if (check_contact) { + GSList *l; + + for (l = contacts; l && !found; l = l->next) { + EContact *contact = l->data; + + found = check_contact (contact, user_data); + } + } else { + found = TRUE; + } + + g_slist_foreach (contacts, (GFunc) g_object_unref, NULL); + g_slist_free (contacts); + } + } else if (book_client) { + stop = stop || (err && + (g_error_matches (err, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) || + g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED))); + if (err && !stop) { + gchar *source_uid = g_strdup (uid); + + g_hash_table_insert (emu_broken_books_hash, source_uid, source_uid); + + g_warning ( + "%s: Can't get contacts from '%s': %s", + G_STRFUNC, + display_name, + err->message); + } + g_clear_error (&err); + } + + mail_cancel_hook_remove (hook_stop); + + if (stop && !cached_book && book_client) { + g_object_unref (book_client); + } else if (!stop && book_client && !cached_book) { + g_hash_table_insert ( + emu_books_hash, g_strdup (uid), book_client); + } + } + + mail_cancel_hook_remove (hook_cancellable); + g_object_unref (cancellable); + + g_slist_free_full (addr_sources, (GDestroyNotify) g_object_unref); + + g_free (query); + + if (!found_any) { + g_hash_table_insert (contact_cache, lowercase_addr, NOT_FOUND_BOOK); + lowercase_addr = NULL; + } + + G_UNLOCK (contact_cache); + + g_free (lowercase_addr); + + return found_any; +} + +gboolean +em_utils_in_addressbook (CamelInternetAddress *iaddr, + gboolean local_only) +{ + const gchar *addr; + + /* TODO: check all addresses? */ + if (iaddr == NULL || !camel_internet_address_get (iaddr, 0, NULL, &addr)) + return FALSE; + + return search_address_in_addressbooks (addr, local_only, NULL, NULL); +} + +static gboolean +extract_photo_data (EContact *contact, + gpointer user_data) +{ + EContactPhoto **photo = user_data; + + g_return_val_if_fail (contact != NULL, FALSE); + g_return_val_if_fail (user_data != NULL, FALSE); + + *photo = e_contact_get (contact, E_CONTACT_PHOTO); + if (!*photo) + *photo = e_contact_get (contact, E_CONTACT_LOGO); + + return *photo != NULL; +} + +typedef struct _PhotoInfo { + gchar *address; + EContactPhoto *photo; +} PhotoInfo; + +static void +emu_free_photo_info (PhotoInfo *pi) +{ + if (!pi) + return; + + if (pi->address) + g_free (pi->address); + if (pi->photo) + e_contact_photo_free (pi->photo); + g_free (pi); +} + +G_LOCK_DEFINE_STATIC (photos_cache); +static GSList *photos_cache = NULL; /* list of PhotoInfo-s */ + +CamelMimePart * +em_utils_contact_photo (CamelInternetAddress *cia, + gboolean local_only) +{ + const gchar *addr = NULL; + CamelMimePart *part = NULL; + EContactPhoto *photo = NULL; + GSList *p, *first_not_null = NULL; + gint count_not_null = 0; + + if (cia == NULL || !camel_internet_address_get (cia, 0, NULL, &addr) || !addr) { + return NULL; + } + + G_LOCK (photos_cache); + + /* search a cache first */ + for (p = photos_cache; p; p = p->next) { + PhotoInfo *pi = p->data; + + if (!pi) + continue; + + if (pi->photo) { + if (!first_not_null) + first_not_null = p; + count_not_null++; + } + + if (g_ascii_strcasecmp (addr, pi->address) == 0) { + photo = pi->photo; + break; + } + } + + /* !p means the address had not been found in the cache */ + if (!p && search_address_in_addressbooks ( + addr, local_only, extract_photo_data, &photo)) { + PhotoInfo *pi; + + if (photo && photo->type != E_CONTACT_PHOTO_TYPE_INLINED) { + e_contact_photo_free (photo); + photo = NULL; + } + + /* keep only up to 10 photos in memory */ + if (photo && count_not_null >= 10 && first_not_null) { + pi = first_not_null->data; + + photos_cache = g_slist_remove (photos_cache, pi); + + emu_free_photo_info (pi); + } + + pi = g_new0 (PhotoInfo, 1); + pi->address = g_strdup (addr); + pi->photo = photo; + + photos_cache = g_slist_append (photos_cache, pi); + } + + /* some photo found, use it */ + if (photo) { + /* Form a mime part out of the photo */ + part = camel_mime_part_new (); + camel_mime_part_set_content (part, + (const gchar *) photo->data.inlined.data, + photo->data.inlined.length, "image/jpeg"); + } + + G_UNLOCK (photos_cache); + + return part; +} + +/* list of email addresses (strings) to remove from local cache of photos and + * contacts, but only if the photo doesn't exist or is an not-found contact */ +void +emu_remove_from_mail_cache (const GSList *addresses) +{ + const GSList *a; + GSList *p; + CamelInternetAddress *cia; + + cia = camel_internet_address_new (); + + for (a = addresses; a; a = a->next) { + const gchar *addr = NULL; + + if (!a->data) + continue; + + if (camel_address_decode ((CamelAddress *) cia, a->data) != -1 && + camel_internet_address_get (cia, 0, NULL, &addr) && addr) { + gchar *lowercase_addr = g_utf8_strdown (addr, -1); + + G_LOCK (contact_cache); + if (g_hash_table_lookup (contact_cache, lowercase_addr) == NOT_FOUND_BOOK) + g_hash_table_remove (contact_cache, lowercase_addr); + G_UNLOCK (contact_cache); + + g_free (lowercase_addr); + + G_LOCK (photos_cache); + for (p = photos_cache; p; p = p->next) { + PhotoInfo *pi = p->data; + + if (pi && !pi->photo && g_ascii_strcasecmp (pi->address, addr) == 0) { + photos_cache = g_slist_remove (photos_cache, pi); + emu_free_photo_info (pi); + break; + } + } + G_UNLOCK (photos_cache); + } + } + + g_object_unref (cia); +} + + +void +emu_remove_from_mail_cache_1 (const gchar *address) +{ + GSList *l; + + g_return_if_fail (address != NULL); + + l = g_slist_append (NULL, (gpointer) address); + + emu_remove_from_mail_cache (l); + + g_slist_free (l); +} + +/* frees all data created by call of em_utils_in_addressbook() or + * em_utils_contact_photo() */ +void +emu_free_mail_cache (void) +{ + G_LOCK (contact_cache); + + if (emu_books_hash) { + g_hash_table_destroy (emu_books_hash); + emu_books_hash = NULL; + } + + if (emu_broken_books_hash) { + g_hash_table_destroy (emu_broken_books_hash); + emu_broken_books_hash = NULL; + } + + if (emu_books_source_list) { + g_object_unref (emu_books_source_list); + emu_books_source_list = NULL; + } + + if (contact_cache) { + g_hash_table_destroy (contact_cache); + contact_cache = NULL; + } + + G_UNLOCK (contact_cache); + + G_LOCK (photos_cache); + + g_slist_foreach (photos_cache, (GFunc) emu_free_photo_info, NULL); + g_slist_free (photos_cache); + photos_cache = NULL; + + G_UNLOCK (photos_cache); +} + +static EAccount * +guess_account_from_folder (CamelFolder *folder) +{ + CamelStore *store; + const gchar *uid; + + store = camel_folder_get_parent_store (folder); + uid = camel_service_get_uid (CAMEL_SERVICE (store)); + + return e_get_account_by_uid (uid); +} + +static EAccount * +guess_account_from_message (CamelMimeMessage *message) +{ + const gchar *uid; + + uid = camel_mime_message_get_source (message); + + return (uid != NULL) ? e_get_account_by_uid (uid) : NULL; +} + +EAccount * +em_utils_guess_account (CamelMimeMessage *message, + CamelFolder *folder) +{ + EAccount *account = NULL; + + g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL); + + if (folder != NULL) + g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL); + + /* check for newsgroup header */ + if (folder != NULL + && camel_medium_get_header (CAMEL_MEDIUM (message), "Newsgroups")) + account = guess_account_from_folder (folder); + + /* check for source folder */ + if (account == NULL && folder != NULL) + account = guess_account_from_folder (folder); + + /* then message source */ + if (account == NULL) + account = guess_account_from_message (message); + + return account; +} + +EAccount * +em_utils_guess_account_with_recipients (CamelMimeMessage *message, + CamelFolder *folder) +{ + EAccount *account = NULL; + EAccountList *account_list; + GHashTable *recipients; + EIterator *iterator; + CamelInternetAddress *addr; + const gchar *type; + const gchar *key; + + /* This policy is subject to debate and tweaking, + * but please also document the rational here. */ + + g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL); + + /* Build a set of email addresses in which to test for membership. + * Only the keys matter here; the values just need to be non-NULL. */ + recipients = g_hash_table_new (g_str_hash, g_str_equal); + + type = CAMEL_RECIPIENT_TYPE_TO; + addr = camel_mime_message_get_recipients (message, type); + if (addr != NULL) { + gint index = 0; + + while (camel_internet_address_get (addr, index++, NULL, &key)) + g_hash_table_insert ( + recipients, (gpointer) key, + GINT_TO_POINTER (1)); + } + + type = CAMEL_RECIPIENT_TYPE_CC; + addr = camel_mime_message_get_recipients (message, type); + if (addr != NULL) { + gint index = 0; + + while (camel_internet_address_get (addr, index++, NULL, &key)) + g_hash_table_insert ( + recipients, (gpointer) key, + GINT_TO_POINTER (1)); + } + + /* First Preference: We were given a folder that maps to an + * enabled account, and that account's email address appears + * in the list of To: or Cc: recipients. */ + + if (folder != NULL) + account = guess_account_from_folder (folder); + + if (account == NULL || !account->enabled) + goto second_preference; + + if ((key = account->id->address) == NULL) + goto second_preference; + + if (g_hash_table_lookup (recipients, key) != NULL) + goto exit; + +second_preference: + + /* Second Preference: Choose any enabled account whose email + * address appears in the list to To: or Cc: recipients. */ + + account_list = e_get_account_list (); + iterator = e_list_get_iterator (E_LIST (account_list)); + + while (e_iterator_is_valid (iterator)) { + account = (EAccount *) e_iterator_get (iterator); + e_iterator_next (iterator); + + if (account == NULL || !account->enabled) + continue; + + if ((key = account->id->address) == NULL) + continue; + + if (g_hash_table_lookup (recipients, key) != NULL) { + g_object_unref (iterator); + goto exit; + } + } + g_object_unref (iterator); + + /* Last Preference: Defer to em_utils_guess_account(). */ + account = em_utils_guess_account (message, folder); + +exit: + g_hash_table_destroy (recipients); + + return account; +} + +static void +cancel_service_connect_cb (GCancellable *cancellable, + CamelService *service) +{ + g_return_if_fail (CAMEL_IS_SERVICE (service)); + + camel_service_cancel_connect (service); +} + +gboolean +em_utils_connect_service_sync (CamelService *service, + GCancellable *cancellable, + GError **error) +{ + gboolean res; + gulong handler_id = 0; + + g_return_val_if_fail (CAMEL_IS_SERVICE (service), FALSE); + + if (cancellable != NULL) + handler_id = g_cancellable_connect ( + cancellable, + G_CALLBACK (cancel_service_connect_cb), + service, NULL); + + res = camel_service_connect_sync (service, error); + + if (handler_id) + g_cancellable_disconnect (cancellable, handler_id); + + return res; +} + +gboolean +em_utils_disconnect_service_sync (CamelService *service, + gboolean clean, + GCancellable *cancellable, + GError **error) +{ + gboolean res; + gulong handler_id = 0; + + g_return_val_if_fail (CAMEL_IS_SERVICE (service), FALSE); + + if (cancellable != NULL) + handler_id = g_cancellable_connect ( + cancellable, + G_CALLBACK (cancel_service_connect_cb), + service, NULL); + + res = camel_service_disconnect_sync (service, clean, error); + + if (handler_id) + g_cancellable_disconnect (cancellable, handler_id); + + return res; +} + +/** + * 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) +{ + gint i; + + for (i = 0; i < uids->len; i++) + g_free (uids->pdata[i]); + + g_ptr_array_free (uids, TRUE); +} + +/* Returns TRUE if CamelURL points to a local mbox file. */ +gboolean +em_utils_is_local_delivery_mbox_file (CamelURL *url) +{ + g_return_val_if_fail (url != NULL, FALSE); + + return g_str_equal (url->protocol, "mbox") && + (url->path != NULL) && + g_file_test (url->path, G_FILE_TEST_EXISTS) && + !g_file_test (url->path, G_FILE_TEST_IS_DIR); +} + diff --git a/libemail-engine/e-mail-utils.h b/libemail-engine/e-mail-utils.h new file mode 100644 index 0000000000..144f13dfdd --- /dev/null +++ b/libemail-engine/e-mail-utils.h @@ -0,0 +1,56 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + * + * Authors: + * Srinivasa Ragavan + * + * + */ + +#ifndef E_MAIL_UTILS_H +#define E_MAIL_UTILS_H + +#include +#include + +gboolean em_utils_folder_is_drafts (CamelFolder *folder); +gboolean em_utils_folder_is_templates (CamelFolder *folder); +gboolean em_utils_folder_is_sent (CamelFolder *folder); +gboolean em_utils_folder_is_outbox (CamelFolder *folder); +gboolean em_utils_in_addressbook (CamelInternetAddress *addr, + gboolean local_only); +CamelMimePart * em_utils_contact_photo (CamelInternetAddress *addr, + gboolean local); +EAccount * em_utils_guess_account (CamelMimeMessage *message, + CamelFolder *folder); +EAccount * em_utils_guess_account_with_recipients + (CamelMimeMessage *message, + CamelFolder *folder); +void emu_remove_from_mail_cache (const GSList *addresses); +void emu_remove_from_mail_cache_1 (const gchar *address); +void emu_free_mail_cache (void); +gboolean em_utils_connect_service_sync (CamelService *service, + GCancellable *cancellable, + GError **error); +gboolean em_utils_disconnect_service_sync + (CamelService *service, + gboolean clean, + GCancellable *cancellable, + GError **error); +void em_utils_uids_free (GPtrArray *uids); +gboolean em_utils_is_local_delivery_mbox_file + (CamelURL *url); + +#endif /* E_MAIL_UTILS_H */ diff --git a/libemail-engine/libemail-engine.pc.in b/libemail-engine/libemail-engine.pc.in new file mode 100644 index 0000000000..1d915bcf33 --- /dev/null +++ b/libemail-engine/libemail-engine.pc.in @@ -0,0 +1,15 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ +datarootdir=@datarootdir@ +datadir=@datadir@ + +privincludedir=@privincludedir@ + +Name: libemail-engine +Description: Client library for evolution mail +Version: @VERSION@ +Requires: libemail-utils +Libs: -L${libdir} -lemail-engine +Cflags: -I${privincludedir} diff --git a/libemail-engine/mail-config.c b/libemail-engine/mail-config.c new file mode 100644 index 0000000000..51d34a0714 --- /dev/null +++ b/libemail-engine/mail-config.c @@ -0,0 +1,294 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + * + * Authors: + * Jeffrey Stedfast + * Radek Doulik + * Jonathon Jongsma + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * Copyright (C) 2009 Intel Corporation + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include + +#include +#include + +#include "e-mail-folder-utils.h" +#include "mail-config.h" +#include "mail-tools.h" + +typedef struct { + GSList *labels; + + gboolean address_compress; + gint address_count; + + GSList *jh_header; + gboolean jh_check; + gboolean book_lookup; + gboolean book_lookup_local_only; +} MailConfig; + +extern gint camel_header_param_encode_filenames_in_rfc_2047; + +static MailConfig *config = NULL; +static GSettings *mail_settings = NULL; + +static void +settings_outlook_filenames_changed (GSettings *settings, + const gchar *key, + gpointer user_data) +{ + /* pass option to the camel */ + if (g_settings_get_boolean (settings, key)) + camel_header_param_encode_filenames_in_rfc_2047 = 1; + else + camel_header_param_encode_filenames_in_rfc_2047 = 0; +} + +static void +settings_jh_headers_changed (GSettings *settings, + const gchar *key, + EMailSession *session) +{ + GSList *node; + GPtrArray *name, *value; + gchar **strv; + gint i; + + g_slist_foreach (config->jh_header, (GFunc) g_free, NULL); + g_slist_free (config->jh_header); + config->jh_header = NULL; + + strv = g_settings_get_strv (settings, "junk-custom-header"); + for (i = 0; strv[i] != NULL; i++) + config->jh_header = g_slist_append (config->jh_header, g_strdup (strv[i])); + g_strfreev (strv); + + node = config->jh_header; + name = g_ptr_array_new (); + value = g_ptr_array_new (); + while (node && node->data) { + gchar **tok = g_strsplit (node->data, "=", 2); + g_ptr_array_add (name, g_strdup (tok[0])); + g_ptr_array_add (value, g_strdup (tok[1])); + node = node->next; + g_strfreev (tok); + } + camel_session_set_junk_headers ( + CAMEL_SESSION (session), + (const gchar **) name->pdata, + (const gchar **) value->pdata, name->len); + + g_ptr_array_foreach (name, (GFunc) g_free, NULL); + g_ptr_array_foreach (value, (GFunc) g_free, NULL); + g_ptr_array_free (name, TRUE); + g_ptr_array_free (value, TRUE); +} + +static void +settings_jh_check_changed (GSettings *settings, + const gchar *key, + EMailSession *session) +{ + config->jh_check = g_settings_get_boolean (settings, "junk-check-custom-header"); + if (!config->jh_check) { + camel_session_set_junk_headers ( + CAMEL_SESSION (session), NULL, NULL, 0); + } else { + settings_jh_headers_changed (settings, NULL, session); + } +} + +static void +settings_bool_value_changed (GSettings *settings, + const gchar *key, + gboolean *save_location) +{ + *save_location = g_settings_get_boolean (settings, key); +} + +static void +settings_int_value_changed (GSettings *settings, + const gchar *key, + gint *save_location) +{ + *save_location = g_settings_get_int (settings, key); +} + +void +mail_config_write (void) +{ + EAccountList *account_list; + ESignatureList *signature_list; + + if (!config) + return; + + account_list = e_get_account_list (); + signature_list = e_get_signature_list (); + + e_account_list_save (account_list); + e_signature_list_save (signature_list); + + g_settings_sync (); +} + +gint +mail_config_get_address_count (void) +{ + if (!config->address_compress) + return -1; + + return config->address_count; +} + +/* timeout interval, in seconds, when to call server update */ +gint +mail_config_get_sync_timeout (void) +{ + gint res = 60; + + res = g_settings_get_int (mail_settings, "sync-interval"); + + /* do not allow recheck sooner than every 30 seconds */ + if (res == 0) + res = 60; + else if (res < 30) + res = 30; + + return res; +} + +gchar * +mail_config_folder_to_cachename (CamelFolder *folder, + const gchar *prefix) +{ + gchar *folder_uri, *basename, *filename; + const gchar *config_dir; + + config_dir = mail_session_get_config_dir (); + + basename = g_build_filename (config_dir, "folders", NULL); + if (!g_file_test (basename, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) { + /* create the folder if does not exist */ + g_mkdir_with_parents (basename, 0700); + } + g_free (basename); + + folder_uri = e_mail_folder_uri_from_folder (folder); + e_filename_make_safe (folder_uri); + basename = g_strdup_printf ("%s%s", prefix, folder_uri); + filename = g_build_filename (config_dir, "folders", basename, NULL); + g_free (basename); + g_free (folder_uri); + + return filename; +} + +void +mail_config_reload_junk_headers (EMailSession *session) +{ + g_return_if_fail (E_IS_MAIL_SESSION (session)); + + /* It automatically sets in the session */ + if (config == NULL) + mail_config_init (session); + else { + settings_jh_check_changed (mail_settings, NULL, session); + } +} + +gboolean +mail_config_get_lookup_book (void) +{ + g_return_val_if_fail (config != NULL, FALSE); + + return config->book_lookup; +} + +gboolean +mail_config_get_lookup_book_local_only (void) +{ + g_return_val_if_fail (config != NULL, FALSE); + + return config->book_lookup_local_only; +} + +/* Config struct routines */ +void +mail_config_init (EMailSession *session) +{ + g_return_if_fail (E_IS_MAIL_SESSION (session)); + + if (config) + return; + + config = g_new0 (MailConfig, 1); + + mail_settings = g_settings_new ("org.gnome.evolution.mail"); + + /* Composer Configuration */ + + settings_outlook_filenames_changed ( + mail_settings, "composer-outlook-filenames", NULL); + g_signal_connect ( + mail_settings, "changed::composer-outlook-filenames", + G_CALLBACK (settings_outlook_filenames_changed), NULL); + + /* Display Configuration */ + + g_signal_connect ( + mail_settings, "changed::address-compress", + G_CALLBACK (settings_bool_value_changed), &config->address_compress); + config->address_compress = g_settings_get_boolean (mail_settings, "address-compress"); + + g_signal_connect ( + mail_settings, "changed::address-count", + G_CALLBACK (settings_int_value_changed), &config->address_count); + config->address_count = g_settings_get_int (mail_settings, "address-count"); + + /* Junk Configuration */ + + g_signal_connect ( + mail_settings, "changed::junk-check-custom-header", + G_CALLBACK (settings_jh_check_changed), session); + config->jh_check = g_settings_get_boolean (mail_settings, "junk-check-custom-header"); + + g_signal_connect ( + mail_settings, "changed::junk-custom-header", + G_CALLBACK (settings_jh_headers_changed), session); + + g_signal_connect ( + mail_settings, "changed::junk-lookup-addressbook", + G_CALLBACK (settings_bool_value_changed), &config->book_lookup); + config->book_lookup = g_settings_get_boolean (mail_settings, "junk-lookup-addressbook"); + + g_signal_connect ( + mail_settings, "changed::junk-lookup-addressbook-local-only", + G_CALLBACK (settings_bool_value_changed), &config->book_lookup_local_only); + config->book_lookup_local_only = g_settings_get_boolean (mail_settings, "junk-lookup-addressbook-local-only"); + + settings_jh_check_changed (mail_settings, NULL, session); +} diff --git a/libemail-engine/mail-config.h b/libemail-engine/mail-config.h new file mode 100644 index 0000000000..0a1c618f35 --- /dev/null +++ b/libemail-engine/mail-config.h @@ -0,0 +1,49 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + * + * Authors: + * Jeffrey Stedfast + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef MAIL_CONFIG_H +#define MAIL_CONFIG_H + +#include + +G_BEGIN_DECLS + +/* Configuration */ +void mail_config_init (EMailSession *session); +void mail_config_write (void); + +/* General Accessor functions */ + +gint mail_config_get_address_count (void); + +/* static utility functions */ +gchar * mail_config_folder_to_cachename (CamelFolder *folder, + const gchar *prefix); +gint mail_config_get_sync_timeout (void); + +void mail_config_reload_junk_headers (EMailSession *session); +gboolean mail_config_get_lookup_book (void); +gboolean mail_config_get_lookup_book_local_only (void); + +G_END_DECLS + +#endif /* MAIL_CONFIG_H */ diff --git a/libemail-engine/mail-folder-cache.c b/libemail-engine/mail-folder-cache.c new file mode 100644 index 0000000000..954c14d379 --- /dev/null +++ b/libemail-engine/mail-folder-cache.c @@ -0,0 +1,1841 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + * + * Authors: + * Peter Williams + * Michael Zucchi + * Jonathon Jongsma + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * Copyright (C) 2009 Intel Corporation + * + */ + +/** + * SECTION: mail-folder-cache + * @short_description: Stores information about open folders + **/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include + +#include + +#include + +#include "mail-folder-cache.h" +#include "mail-ops.h" +#include "mail-tools.h" +#include "e-mail-utils.h" +#include "e-mail-folder-utils.h" +#include "e-mail-session.h" +#include "e-mail-store-utils.h" +#include "mail-config.h" + +#define w(x) +#define d(x) + +#define MAIL_FOLDER_CACHE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), MAIL_TYPE_FOLDER_CACHE, MailFolderCachePrivate)) + +/* This code is a mess, there is no reason it should be so complicated. */ + +typedef struct _StoreInfo StoreInfo; + +struct _MailFolderCachePrivate { + gpointer session; /* weak pointer */ + + /* source id for the ping timeout callback */ + guint ping_id; + /* Store to storeinfo table, active stores */ + GHashTable *stores; + /* mutex to protect access to the stores hash */ + GMutex *stores_mutex; + /* List of folder changes to be executed in gui thread */ + GQueue updates; + /* idle source id for flushing all pending updates */ + guint update_id; + /* hack for people who LIKE to have unsent count */ + gint count_sent; + gint count_trash; + + GQueue local_folder_uris; + GQueue remote_folder_uris; +}; + +enum { + PROP_0, + PROP_SESSION +}; + +enum { + FOLDER_AVAILABLE, + FOLDER_UNAVAILABLE, + FOLDER_DELETED, + FOLDER_RENAMED, + FOLDER_UNREAD_UPDATED, + FOLDER_CHANGED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +struct _folder_info { + StoreInfo *store_info; /* 'parent' link */ + + gchar *full_name; /* full name of folder/folderinfo */ + + guint32 flags; + gboolean has_children; + + gpointer folder; /* if known (weak pointer) */ +}; + +/* pending list of updates */ +struct _folder_update { + guint remove:1; /* removing from vfolders */ + guint delete:1; /* deleting as well? */ + guint add:1; /* add to vfolder */ + guint unsub:1; /* unsubcribing? */ + guint new; /* new mail arrived? */ + + gchar *full_name; + gchar *oldfull; + + gint unread; + CamelStore *store; + + /* for only one new message... */ + gchar *msg_uid; /* ... its uid ... */ + gchar *msg_sender; /* ... its sender ... */ + gchar *msg_subject; /* ... and its subject. */ +}; + +struct _StoreInfo { + GHashTable *folders; /* by full_name */ + CamelStore *store; /* the store for these folders */ + gboolean first_update; /* TRUE initially, then FALSE forever */ + + /* Hold a reference to keep them alive. */ + CamelFolder *vjunk; + CamelFolder *vtrash; + + /* Outstanding folderinfo requests */ + GQueue folderinfo_updates; +}; + +struct _update_data { + NoteDoneFunc done; + gpointer data; + MailFolderCache *cache; + GCancellable *cancellable; +}; + +G_DEFINE_TYPE (MailFolderCache, mail_folder_cache, G_TYPE_OBJECT) + +static void +free_update (struct _folder_update *up) +{ + g_free (up->full_name); + if (up->store) + g_object_unref (up->store); + g_free (up->oldfull); + g_free (up->msg_uid); + g_free (up->msg_sender); + g_free (up->msg_subject); + g_free (up); +} + +static void +free_folder_info (struct _folder_info *mfi) +{ + g_free (mfi->full_name); + g_free (mfi); +} + +static StoreInfo * +store_info_new (CamelStore *store) +{ + StoreInfo *info; + GHashTable *folders; + + folders = g_hash_table_new_full ( + (GHashFunc) g_str_hash, + (GEqualFunc) g_str_equal, + (GDestroyNotify) NULL, + (GDestroyNotify) free_folder_info); + + info = g_slice_new0 (StoreInfo); + info->folders = folders; + info->store = g_object_ref (store); + info->first_update = TRUE; + + /* If these are vfolders then they need to be opened + * now, otherwise they won't keep track of all folders. */ + if (store->flags & CAMEL_STORE_VJUNK) + info->vjunk = camel_store_get_junk_folder_sync ( + store, NULL, NULL); + if (store->flags & CAMEL_STORE_VTRASH) + info->vtrash = camel_store_get_trash_folder_sync ( + store, NULL, NULL); + + g_queue_init (&info->folderinfo_updates); + + return info; +} + +static void +store_info_free (StoreInfo *info) +{ + struct _update_data *ud; + + while (!g_queue_is_empty (&info->folderinfo_updates)) { + ud = g_queue_pop_head (&info->folderinfo_updates); + g_cancellable_cancel (ud->cancellable); + } + + g_hash_table_destroy (info->folders); + g_object_unref (info->store); + + if (info->vjunk != NULL) + g_object_unref (info->vjunk); + + if (info->vtrash != NULL) + g_object_unref (info->vtrash); + + g_slice_free (StoreInfo, info); +} + +static gboolean +flush_updates_idle_cb (MailFolderCache *cache) +{ + struct _folder_update *up; + + g_mutex_lock (cache->priv->stores_mutex); + while ((up = g_queue_pop_head (&cache->priv->updates)) != NULL) { + g_mutex_unlock (cache->priv->stores_mutex); + + if (up->remove) { + if (up->delete) { + g_signal_emit ( + cache, signals[FOLDER_DELETED], 0, + up->store, up->full_name); + } else + g_signal_emit ( + cache, signals[FOLDER_UNAVAILABLE], 0, + up->store, up->full_name); + } else { + if (up->oldfull && up->add) { + g_signal_emit ( + cache, signals[FOLDER_RENAMED], 0, + up->store, up->oldfull, up->full_name); + } + + if (!up->oldfull && up->add) + g_signal_emit ( + cache, signals[FOLDER_AVAILABLE], 0, + up->store, up->full_name); + } + + /* update unread counts */ + g_signal_emit (cache, signals[FOLDER_UNREAD_UPDATED], 0, + up->store, up->full_name, up->unread); + + /* indicate that the folder has changed (new mail received, etc) */ + if (up->store != NULL && up->full_name != NULL) { + g_signal_emit ( + cache, signals[FOLDER_CHANGED], 0, up->store, + up->full_name, up->new, up->msg_uid, + up->msg_sender, up->msg_subject); + } + + if (CAMEL_IS_VEE_STORE (up->store) && !up->remove) { + /* Normally the vfolder store takes care of the + * folder_opened event itself, but we add folder to + * the noting system later, thus we do not know about + * search folders to update them in a tree, thus + * ensure their changes will be tracked correctly. */ + CamelFolder *folder; + + /* FIXME camel_store_get_folder_sync() may block. */ + folder = camel_store_get_folder_sync ( + up->store, up->full_name, 0, NULL, NULL); + + if (folder) { + mail_folder_cache_note_folder (cache, folder); + g_object_unref (folder); + } + } + + free_update (up); + + g_mutex_lock (cache->priv->stores_mutex); + } + cache->priv->update_id = 0; + g_mutex_unlock (cache->priv->stores_mutex); + + return FALSE; +} + +static void +flush_updates (MailFolderCache *cache) +{ + if (cache->priv->update_id > 0) + return; + + if (g_queue_is_empty (&cache->priv->updates)) + return; + + cache->priv->update_id = g_idle_add ( + (GSourceFunc) flush_updates_idle_cb, cache); +} + +/* This is how unread counts work (and don't work): + * + * camel_folder_unread_message_count() only gives a correct answer if + * the store is paying attention to the folder. (Some stores always + * pay attention to all folders, but IMAP can only pay attention to + * one folder at a time.) But it doesn't have any way to know when + * it's lying, so it's only safe to call it when you know for sure + * that the store is paying attention to the folder, such as when it's + * just been created, or you get a folder_changed signal on it. + * + * camel_store_get_folder_info() always gives correct answers for the + * folders it checks, but it can also return -1 for a folder, meaning + * it didn't check, and so you should stick with your previous answer. + * + * update_1folder is called from three places: with info != NULL when + * the folder is created (or get_folder_info), with info == NULL when + * a folder changed event is emitted. + * + * So if info is NULL, camel_folder_unread_message_count is correct, + * and if it's not NULL and its unread_message_count isn't -1, then + * it's correct. */ + +static void +update_1folder (MailFolderCache *cache, + struct _folder_info *mfi, + gint new, + const gchar *msg_uid, + const gchar *msg_sender, + const gchar *msg_subject, + CamelFolderInfo *info) +{ + struct _folder_update *up; + CamelFolder *folder; + gint unread = -1; + gint deleted; + + folder = mfi->folder; + if (folder) { + gboolean folder_is_sent; + gboolean folder_is_drafts; + gboolean folder_is_outbox; + gboolean folder_is_vtrash; + gboolean special_case; + + folder_is_sent = em_utils_folder_is_sent (folder); + folder_is_drafts = em_utils_folder_is_drafts (folder); + folder_is_outbox = em_utils_folder_is_outbox (folder); + folder_is_vtrash = CAMEL_IS_VTRASH_FOLDER (folder); + + special_case = + (cache->priv->count_trash && folder_is_vtrash) || + (cache->priv->count_sent && folder_is_sent) || + folder_is_drafts || folder_is_outbox; + + if (special_case) { + d(printf(" total count\n")); + unread = camel_folder_get_message_count (folder); + if (folder_is_drafts || folder_is_outbox) { + guint32 junked = 0; + + if ((deleted = camel_folder_get_deleted_message_count (folder)) > 0) + unread -= deleted; + + junked = camel_folder_summary_get_junk_count (folder->summary); + if (junked > 0) + unread -= junked; + } + } else { + d(printf(" unread count\n")); + if (info) + unread = info->unread; + else + unread = camel_folder_get_unread_message_count (folder); + } + } + + d(printf("folder updated: unread %d: '%s'\n", unread, mfi->full_name)); + + if (unread == -1) + return; + + up = g_malloc0 (sizeof (*up)); + up->full_name = g_strdup (mfi->full_name); + up->unread = unread; + up->new = new; + up->store = g_object_ref (mfi->store_info->store); + up->msg_uid = g_strdup (msg_uid); + up->msg_sender = g_strdup (msg_sender); + up->msg_subject = g_strdup (msg_subject); + g_queue_push_tail (&cache->priv->updates, up); + flush_updates (cache); +} + +static void +folder_changed_cb (CamelFolder *folder, + CamelFolderChangeInfo *changes, + MailFolderCache *cache) +{ + static GHashTable *last_newmail_per_folder = NULL; + time_t latest_received, new_latest_received; + CamelFolder *local_drafts; + CamelFolder *local_outbox; + CamelFolder *local_sent; + CamelSession *session; + CamelStore *parent_store; + CamelMessageInfo *info; + StoreInfo *si; + struct _folder_info *mfi; + const gchar *full_name; + gint new = 0; + gint i; + guint32 flags; + gchar *uid = NULL, *sender = NULL, *subject = NULL; + + full_name = camel_folder_get_full_name (folder); + parent_store = camel_folder_get_parent_store (folder); + session = camel_service_get_session (CAMEL_SERVICE (parent_store)); + + if (!last_newmail_per_folder) + last_newmail_per_folder = g_hash_table_new (g_direct_hash, g_direct_equal); + + /* it's fine to hash them by folder pointer here */ + latest_received = GPOINTER_TO_INT ( + g_hash_table_lookup (last_newmail_per_folder, folder)); + new_latest_received = latest_received; + + local_drafts = e_mail_session_get_local_folder ( + E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_DRAFTS); + local_outbox = e_mail_session_get_local_folder ( + E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_OUTBOX); + local_sent = e_mail_session_get_local_folder ( + E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_SENT); + + if (!CAMEL_IS_VEE_FOLDER (folder) + && folder != local_drafts + && folder != local_outbox + && folder != local_sent + && changes && (changes->uid_added->len > 0)) { + /* for each added message, check to see that it is + * brand new, not junk and not already deleted */ + for (i = 0; i < changes->uid_added->len; i++) { + info = camel_folder_get_message_info ( + folder, changes->uid_added->pdata[i]); + if (info) { + flags = camel_message_info_flags (info); + if (((flags & CAMEL_MESSAGE_SEEN) == 0) && + ((flags & CAMEL_MESSAGE_JUNK) == 0) && + ((flags & CAMEL_MESSAGE_DELETED) == 0) && + (camel_message_info_date_received (info) > latest_received)) { + if (camel_message_info_date_received (info) > new_latest_received) + new_latest_received = camel_message_info_date_received (info); + new++; + if (new == 1) { + uid = g_strdup (camel_message_info_uid (info)); + sender = g_strdup (camel_message_info_from (info)); + subject = g_strdup (camel_message_info_subject (info)); + } else { + g_free (uid); + g_free (sender); + g_free (subject); + + uid = NULL; + sender = NULL; + subject = NULL; + } + } + camel_folder_free_message_info (folder, info); + } + } + } + + if (new > 0) + g_hash_table_insert ( + last_newmail_per_folder, folder, + GINT_TO_POINTER (new_latest_received)); + + g_mutex_lock (cache->priv->stores_mutex); + if (cache->priv->stores != NULL + && (si = g_hash_table_lookup (cache->priv->stores, parent_store)) != NULL + && (mfi = g_hash_table_lookup (si->folders, full_name)) != NULL + && mfi->folder == folder) { + update_1folder (cache, mfi, new, uid, sender, subject, NULL); + } + g_mutex_unlock (cache->priv->stores_mutex); + + g_free (uid); + g_free (sender); + g_free (subject); +} + +static void +unset_folder_info (MailFolderCache *cache, + struct _folder_info *mfi, + gint delete, + gint unsub) +{ + struct _folder_update *up; + + d(printf("unset folderinfo '%s'\n", mfi->uri)); + + if (mfi->folder) { + CamelFolder *folder = mfi->folder; + + g_signal_handlers_disconnect_by_func ( + folder, folder_changed_cb, cache); + + g_object_remove_weak_pointer ( + G_OBJECT (mfi->folder), &mfi->folder); + } + + if ((mfi->flags & CAMEL_FOLDER_NOSELECT) == 0) { + up = g_malloc0 (sizeof (*up)); + + up->remove = TRUE; + up->delete = delete; + up->unsub = unsub; + up->store = g_object_ref (mfi->store_info->store); + up->full_name = g_strdup (mfi->full_name); + + g_queue_push_tail (&cache->priv->updates, up); + flush_updates (cache); + } +} + +static void +setup_folder (MailFolderCache *cache, + CamelFolderInfo *fi, + StoreInfo *si) +{ + struct _folder_info *mfi; + struct _folder_update *up; + + mfi = g_hash_table_lookup (si->folders, fi->full_name); + if (mfi) { + update_1folder (cache, mfi, 0, NULL, NULL, NULL, fi); + } else { + mfi = g_malloc0 (sizeof (*mfi)); + mfi->full_name = g_strdup (fi->full_name); + mfi->store_info = si; + mfi->flags = fi->flags; + mfi->has_children = fi->child != NULL; + + g_hash_table_insert (si->folders, mfi->full_name, mfi); + + up = g_malloc0 (sizeof (*up)); + up->full_name = g_strdup (mfi->full_name); + up->unread = fi->unread; + up->store = g_object_ref (si->store); + + if ((fi->flags & CAMEL_FOLDER_NOSELECT) == 0) + up->add = TRUE; + + g_queue_push_tail (&cache->priv->updates, up); + flush_updates (cache); + } +} + +static void +create_folders (MailFolderCache *cache, + CamelFolderInfo *fi, + StoreInfo *si) +{ + while (fi) { + setup_folder (cache, fi, si); + + if (fi->child) + create_folders (cache, fi->child, si); + + fi = fi->next; + } +} + +static void +store_folder_subscribed_cb (CamelStore *store, + CamelFolderInfo *info, + MailFolderCache *cache) +{ + StoreInfo *si; + + g_mutex_lock (cache->priv->stores_mutex); + si = g_hash_table_lookup (cache->priv->stores, store); + if (si) + setup_folder (cache, info, si); + g_mutex_unlock (cache->priv->stores_mutex); +} + +static void +store_folder_created_cb (CamelStore *store, + CamelFolderInfo *info, + MailFolderCache *cache) +{ + /* We only want created events to do more work + * if we dont support subscriptions. */ + if (!CAMEL_IS_SUBSCRIBABLE (store)) + store_folder_subscribed_cb (store, info, cache); +} + +static void +store_folder_opened_cb (CamelStore *store, + CamelFolder *folder, + MailFolderCache *cache) +{ + mail_folder_cache_note_folder (cache, folder); +} + +static void +store_folder_unsubscribed_cb (CamelStore *store, + CamelFolderInfo *info, + MailFolderCache *cache) +{ + StoreInfo *si; + struct _folder_info *mfi; + + g_mutex_lock (cache->priv->stores_mutex); + si = g_hash_table_lookup (cache->priv->stores, store); + if (si) { + mfi = g_hash_table_lookup (si->folders, info->full_name); + if (mfi) { + unset_folder_info (cache, mfi, TRUE, TRUE); + g_hash_table_remove (si->folders, mfi->full_name); + } + } + g_mutex_unlock (cache->priv->stores_mutex); +} + +static void +store_folder_deleted_cb (CamelStore *store, + CamelFolderInfo *info, + MailFolderCache *cache) +{ + /* We only want deleted events to do more work + * if we dont support subscriptions. */ + if (!CAMEL_IS_SUBSCRIBABLE (store)) + store_folder_unsubscribed_cb (store, info, cache); +} + +static void +rename_folders (MailFolderCache *cache, + StoreInfo *si, + const gchar *oldbase, + const gchar *newbase, + CamelFolderInfo *fi) +{ + gchar *old, *olduri, *oldfile, *newuri, *newfile; + struct _folder_info *mfi; + struct _folder_update *up; + const gchar *config_dir; + + up = g_malloc0 (sizeof (*up)); + + d(printf("oldbase '%s' newbase '%s' new '%s'\n", oldbase, newbase, fi->full_name)); + + /* Form what was the old name, and try and look it up */ + old = g_strdup_printf("%s%s", oldbase, fi->full_name + strlen(newbase)); + mfi = g_hash_table_lookup (si->folders, old); + if (mfi) { + up->oldfull = mfi->full_name; + + /* Be careful not to invoke the destroy function. */ + g_hash_table_steal (si->folders, mfi->full_name); + + /* Its a rename op */ + mfi->full_name = g_strdup (fi->full_name); + mfi->flags = fi->flags; + mfi->has_children = fi->child != NULL; + + g_hash_table_insert (si->folders, mfi->full_name, mfi); + } else { + /* Its a new op */ + mfi = g_malloc0 (sizeof (*mfi)); + mfi->full_name = g_strdup (fi->full_name); + mfi->store_info = si; + mfi->flags = fi->flags; + mfi->has_children = fi->child != NULL; + + g_hash_table_insert (si->folders, mfi->full_name, mfi); + } + + up->full_name = g_strdup (mfi->full_name); + up->unread = fi->unread==-1 ? 0 : fi->unread; + up->store = g_object_ref (si->store); + + if ((fi->flags & CAMEL_FOLDER_NOSELECT) == 0) + up->add = TRUE; + + g_queue_push_tail (&cache->priv->updates, up); + flush_updates (cache); +#if 0 + if (fi->sibling) + rename_folders (cache, si, oldbase, newbase, fi->sibling, folders); + if (fi->child) + rename_folders (cache, si, oldbase, newbase, fi->child, folders); +#endif + + /* rename the meta-data we maintain ourselves */ + config_dir = mail_session_get_config_dir (); + olduri = e_mail_folder_uri_build (si->store, old); + e_filename_make_safe (olduri); + newuri = e_mail_folder_uri_build (si->store, fi->full_name); + e_filename_make_safe (newuri); + oldfile = g_strdup_printf("%s/custom_view-%s.xml", config_dir, olduri); + newfile = g_strdup_printf("%s/custom_view-%s.xml", config_dir, newuri); + g_rename (oldfile, newfile); + g_free (oldfile); + g_free (newfile); + oldfile = g_strdup_printf("%s/current_view-%s.xml", config_dir, olduri); + newfile = g_strdup_printf("%s/current_view-%s.xml", config_dir, newuri); + g_rename (oldfile, newfile); + g_free (oldfile); + g_free (newfile); + g_free (olduri); + g_free (newuri); + + g_free (old); +} + +static void +get_folders (CamelFolderInfo *fi, + GPtrArray *folders) +{ + while (fi) { + g_ptr_array_add (folders, fi); + + if (fi->child) + get_folders (fi->child, folders); + + fi = fi->next; + } +} + +static gint +folder_cmp (gconstpointer ap, + gconstpointer bp) +{ + const CamelFolderInfo *a = ((CamelFolderInfo **) ap)[0]; + const CamelFolderInfo *b = ((CamelFolderInfo **) bp)[0]; + + return strcmp (a->full_name, b->full_name); +} + +static void +store_folder_renamed_cb (CamelStore *store, + const gchar *old_name, + CamelFolderInfo *info, + MailFolderCache *cache) +{ + StoreInfo *si; + + g_mutex_lock (cache->priv->stores_mutex); + si = g_hash_table_lookup (cache->priv->stores, store); + if (si) { + GPtrArray *folders = g_ptr_array_new (); + CamelFolderInfo *top; + gint i; + + /* Ok, so for some reason the folderinfo we have comes in all messed up from + * imap, should find out why ... this makes it workable */ + get_folders (info, folders); + qsort (folders->pdata, folders->len, sizeof (folders->pdata[0]), folder_cmp); + + top = folders->pdata[0]; + for (i = 0; i < folders->len; i++) { + rename_folders (cache, si, old_name, top->full_name, folders->pdata[i]); + } + + g_ptr_array_free (folders, TRUE); + + } + g_mutex_unlock (cache->priv->stores_mutex); +} + +static void +unset_folder_info_hash (gchar *path, + struct _folder_info *mfi, + gpointer data) +{ + MailFolderCache *cache = (MailFolderCache *) data; + unset_folder_info (cache, mfi, FALSE, FALSE); +} + +static void +mail_folder_cache_first_update (MailFolderCache *cache, + StoreInfo *info) +{ + EMailSession *session; + const gchar *uid; + + session = mail_folder_cache_get_session (cache); + uid = camel_service_get_uid (CAMEL_SERVICE (info->store)); + + if (info->vjunk != NULL) + mail_folder_cache_note_folder (cache, info->vjunk); + + if (info->vtrash != NULL) + mail_folder_cache_note_folder (cache, info->vtrash); + + /* Some extra work for the "On This Computer" store. */ + if (g_strcmp0 (uid, E_MAIL_SESSION_LOCAL_UID) == 0) { + CamelFolder *folder; + gint ii; + + for (ii = 0; ii < E_MAIL_NUM_LOCAL_FOLDERS; ii++) { + folder = e_mail_session_get_local_folder (session, ii); + mail_folder_cache_note_folder (cache, folder); + } + } +} + +static void +update_folders (CamelStore *store, + GAsyncResult *result, + struct _update_data *ud) +{ + CamelFolderInfo *fi; + StoreInfo *si; + GError *error = NULL; + + fi = camel_store_get_folder_info_finish (store, result, &error); + + if (error != NULL) { + g_warning ("%s", error->message); + g_error_free (error); + } + + g_mutex_lock (ud->cache->priv->stores_mutex); + si = g_hash_table_lookup (ud->cache->priv->stores, store); + if (si && !g_cancellable_is_cancelled (ud->cancellable)) { + /* The 'si' is still there, so we can remove ourselves from + * its list. Or else its not, and we're on our own and free + * anyway. */ + g_queue_remove (&si->folderinfo_updates, ud); + + if (fi != NULL) + create_folders (ud->cache, fi, si); + } + g_mutex_unlock (ud->cache->priv->stores_mutex); + + /* Do some extra work for the first update. */ + if (si != NULL && si->first_update) { + mail_folder_cache_first_update (ud->cache, si); + si->first_update = FALSE; + } + + if (fi != NULL) { + gboolean free_fi = TRUE; + + if (ud->done != NULL) + free_fi = ud->done (ud->cache, store, fi, ud->data); + if (free_fi) + camel_store_free_folder_info (store, fi); + } + + if (ud->cancellable != NULL) + g_object_unref (ud->cancellable); + + g_free (ud); +} + +struct _ping_store_msg { + MailMsg base; + CamelStore *store; +}; + +static gchar * +ping_store_desc (struct _ping_store_msg *m) +{ + gchar *service_name; + gchar *msg; + + service_name = camel_service_get_name (CAMEL_SERVICE (m->store), TRUE); + msg = g_strdup_printf (_("Pinging %s"), service_name); + g_free (service_name); + + return msg; +} + +static void +ping_store_exec (struct _ping_store_msg *m, + GCancellable *cancellable, + GError **error) +{ + CamelServiceConnectionStatus status; + CamelService *service; + gboolean online = FALSE; + + service = CAMEL_SERVICE (m->store); + status = camel_service_get_connection_status (service); + + if (status == CAMEL_SERVICE_CONNECTED) { + if (CAMEL_IS_DISCO_STORE (m->store) && + camel_disco_store_status ( + CAMEL_DISCO_STORE (m->store)) !=CAMEL_DISCO_STORE_OFFLINE) + online = TRUE; + else if (CAMEL_IS_OFFLINE_STORE (m->store) && + camel_offline_store_get_online ( + CAMEL_OFFLINE_STORE (m->store))) + online = TRUE; + } + if (online) + camel_store_noop_sync (m->store, cancellable, error); +} + +static void +ping_store_free (struct _ping_store_msg *m) +{ + g_object_unref (m->store); +} + +static MailMsgInfo ping_store_info = { + sizeof (struct _ping_store_msg), + (MailMsgDescFunc) ping_store_desc, + (MailMsgExecFunc) ping_store_exec, + (MailMsgDoneFunc) NULL, + (MailMsgFreeFunc) ping_store_free +}; + +static void +ping_store (CamelStore *store) +{ + CamelServiceConnectionStatus status; + CamelService *service; + struct _ping_store_msg *m; + + service = CAMEL_SERVICE (store); + status = camel_service_get_connection_status (service); + + if (status != CAMEL_SERVICE_CONNECTED) + return; + + m = mail_msg_new (&ping_store_info); + m->store = g_object_ref (store); + + mail_msg_slow_ordered_push (m); +} + +static gboolean +ping_cb (MailFolderCache *cache) +{ + g_mutex_lock (cache->priv->stores_mutex); + + g_hash_table_foreach (cache->priv->stores, (GHFunc) ping_store, NULL); + + g_mutex_unlock (cache->priv->stores_mutex); + + return TRUE; +} + +static gboolean +store_has_folder_hierarchy (CamelStore *store) +{ + CamelProvider *provider; + + g_return_val_if_fail (store != NULL, FALSE); + + provider = camel_service_get_provider (CAMEL_SERVICE (store)); + g_return_val_if_fail (provider != NULL, FALSE); + + return (provider->flags & (CAMEL_PROVIDER_IS_STORAGE | CAMEL_PROVIDER_IS_EXTERNAL)) != 0; +} + +static void +store_go_online_cb (CamelStore *store, + GAsyncResult *result, + struct _update_data *ud) +{ + /* FIXME Not checking result for error. */ + + g_mutex_lock (ud->cache->priv->stores_mutex); + + if (g_hash_table_lookup (ud->cache->priv->stores, store) != NULL && + !g_cancellable_is_cancelled (ud->cancellable)) { + /* We're already in the store update list. */ + if (store_has_folder_hierarchy (store)) + camel_store_get_folder_info ( + store, NULL, + CAMEL_STORE_FOLDER_INFO_FAST | + CAMEL_STORE_FOLDER_INFO_RECURSIVE | + CAMEL_STORE_FOLDER_INFO_SUBSCRIBED, + G_PRIORITY_DEFAULT, ud->cancellable, + (GAsyncReadyCallback) update_folders, ud); + } else { + /* The store vanished, that means we were probably cancelled, + * or at any rate, need to clean ourselves up. */ + if (ud->cancellable != NULL) + g_object_unref (ud->cancellable); + g_free (ud); + } + + g_mutex_unlock (ud->cache->priv->stores_mutex); +} + +static GList * +find_folder_uri (GQueue *queue, + CamelSession *session, + const gchar *folder_uri) +{ + GList *head, *link; + + head = g_queue_peek_head_link (queue); + + for (link = head; link != NULL; link = g_list_next (link)) + if (e_mail_folder_uri_equal (session, link->data, folder_uri)) + break; + + return link; +} + +struct _find_info { + const gchar *folder_uri; + struct _folder_info *fi; +}; + +static void +storeinfo_find_folder_info (CamelStore *store, + StoreInfo *si, + struct _find_info *fi) +{ + gchar *folder_name; + gboolean success; + + if (fi->fi != NULL) + return; + + success = e_mail_folder_uri_parse ( + camel_service_get_session (CAMEL_SERVICE (store)), + fi->folder_uri, NULL, &folder_name, NULL); + + if (success) { + fi->fi = g_hash_table_lookup (si->folders, folder_name); + g_free (folder_name); + } +} + +static void +mail_folder_cache_set_session (MailFolderCache *cache, + EMailSession *session) +{ + g_return_if_fail (E_IS_MAIL_SESSION (session)); + g_return_if_fail (cache->priv->session == NULL); + + cache->priv->session = session; + + g_object_add_weak_pointer ( + G_OBJECT (cache->priv->session), + &cache->priv->session); +} + +static void +mail_folder_cache_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_SESSION: + mail_folder_cache_set_session ( + MAIL_FOLDER_CACHE (object), + g_value_get_object (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +mail_folder_cache_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_SESSION: + g_value_set_object ( + value, + mail_folder_cache_get_session ( + MAIL_FOLDER_CACHE (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +mail_folder_cache_dispose (GObject *object) +{ + MailFolderCachePrivate *priv; + + priv = MAIL_FOLDER_CACHE_GET_PRIVATE (object); + + if (priv->session != NULL) { + g_object_remove_weak_pointer ( + G_OBJECT (priv->session), &priv->session); + priv->session = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (mail_folder_cache_parent_class)->dispose (object); +} + +static void +mail_folder_cache_finalize (GObject *object) +{ + MailFolderCachePrivate *priv; + + priv = MAIL_FOLDER_CACHE_GET_PRIVATE (object); + + g_hash_table_destroy (priv->stores); + g_mutex_free (priv->stores_mutex); + + if (priv->ping_id > 0) { + g_source_remove (priv->ping_id); + priv->ping_id = 0; + } + + if (priv->update_id > 0) { + g_source_remove (priv->update_id); + priv->update_id = 0; + } + + while (!g_queue_is_empty (&priv->local_folder_uris)) + g_free (g_queue_pop_head (&priv->local_folder_uris)); + + while (!g_queue_is_empty (&priv->remote_folder_uris)) + g_free (g_queue_pop_head (&priv->remote_folder_uris)); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (mail_folder_cache_parent_class)->finalize (object); +} + +static void +mail_folder_cache_folder_available (MailFolderCache *cache, + CamelStore *store, + const gchar *folder_name) +{ + CamelService *service; + CamelSession *session; + CamelProvider *provider; + GQueue *queue; + gchar *folder_uri; + + /* Disregard virtual stores. */ + if (CAMEL_IS_VEE_STORE (store)) + return; + + /* Disregard virtual Junk folders. */ + if (store->flags & CAMEL_STORE_VJUNK) + if (g_strcmp0 (folder_name, CAMEL_VJUNK_NAME) == 0) + return; + + /* Disregard virtual Trash folders. */ + if (store->flags & CAMEL_STORE_VTRASH) + if (g_strcmp0 (folder_name, CAMEL_VTRASH_NAME) == 0) + return; + + service = CAMEL_SERVICE (store); + session = camel_service_get_session (service); + provider = camel_service_get_provider (service); + + /* Reuse the stores mutex just because it's handy. */ + g_mutex_lock (cache->priv->stores_mutex); + + folder_uri = e_mail_folder_uri_build (store, folder_name); + + if (provider->flags & CAMEL_PROVIDER_IS_REMOTE) + queue = &cache->priv->remote_folder_uris; + else + queue = &cache->priv->local_folder_uris; + + if (find_folder_uri (queue, session, folder_uri) == NULL) + g_queue_push_tail (queue, folder_uri); + else + g_free (folder_uri); + + g_mutex_unlock (cache->priv->stores_mutex); +} + +static void +mail_folder_cache_folder_unavailable (MailFolderCache *cache, + CamelStore *store, + const gchar *folder_name) +{ + CamelService *service; + CamelSession *session; + CamelProvider *provider; + GQueue *queue; + GList *link; + gchar *folder_uri; + + /* Disregard virtual stores. */ + if (CAMEL_IS_VEE_STORE (store)) + return; + + /* Disregard virtual Junk folders. */ + if (store->flags & CAMEL_STORE_VJUNK) + if (g_strcmp0 (folder_name, CAMEL_VJUNK_NAME) == 0) + return; + + /* Disregard virtual Trash folders. */ + if (store->flags & CAMEL_STORE_VTRASH) + if (g_strcmp0 (folder_name, CAMEL_VTRASH_NAME) == 0) + return; + + service = CAMEL_SERVICE (store); + session = camel_service_get_session (service); + provider = camel_service_get_provider (service); + + /* Reuse the stores mutex just because it's handy. */ + g_mutex_lock (cache->priv->stores_mutex); + + folder_uri = e_mail_folder_uri_build (store, folder_name); + + if (provider->flags & CAMEL_PROVIDER_IS_REMOTE) + queue = &cache->priv->remote_folder_uris; + else + queue = &cache->priv->local_folder_uris; + + link = find_folder_uri (queue, session, folder_uri); + if (link != NULL) { + g_free (link->data); + g_queue_delete_link (queue, link); + } + + g_free (folder_uri); + + g_mutex_unlock (cache->priv->stores_mutex); +} + +static void +mail_folder_cache_folder_deleted (MailFolderCache *cache, + CamelStore *store, + const gchar *folder_name) +{ + CamelService *service; + CamelSession *session; + GQueue *queue; + GList *link; + gchar *folder_uri; + + /* Disregard virtual stores. */ + if (CAMEL_IS_VEE_STORE (store)) + return; + + /* Disregard virtual Junk folders. */ + if (store->flags & CAMEL_STORE_VJUNK) + if (g_strcmp0 (folder_name, CAMEL_VJUNK_NAME) == 0) + return; + + /* Disregard virtual Trash folders. */ + if (store->flags & CAMEL_STORE_VTRASH) + if (g_strcmp0 (folder_name, CAMEL_VTRASH_NAME) == 0) + return; + + service = CAMEL_SERVICE (store); + session = camel_service_get_session (service); + + /* Reuse the stores mutex just because it's handy. */ + g_mutex_lock (cache->priv->stores_mutex); + + folder_uri = e_mail_folder_uri_build (store, folder_name); + + queue = &cache->priv->local_folder_uris; + link = find_folder_uri (queue, session, folder_uri); + if (link != NULL) { + g_free (link->data); + g_queue_delete_link (queue, link); + } + + queue = &cache->priv->remote_folder_uris; + link = find_folder_uri (queue, session, folder_uri); + if (link != NULL) { + g_free (link->data); + g_queue_delete_link (queue, link); + } + + g_free (folder_uri); + + g_mutex_unlock (cache->priv->stores_mutex); +} + +static void +mail_folder_cache_class_init (MailFolderCacheClass *class) +{ + GObjectClass *object_class; + + g_type_class_add_private (class, sizeof (MailFolderCachePrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = mail_folder_cache_set_property; + object_class->get_property = mail_folder_cache_get_property; + object_class->dispose = mail_folder_cache_dispose; + object_class->finalize = mail_folder_cache_finalize; + + class->folder_available = mail_folder_cache_folder_available; + class->folder_unavailable = mail_folder_cache_folder_unavailable; + class->folder_deleted = mail_folder_cache_folder_deleted; + + g_object_class_install_property ( + object_class, + PROP_SESSION, + g_param_spec_object ( + "session", + "Session", + "Mail session", + E_TYPE_MAIL_SESSION, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + /** + * MailFolderCache::folder-available + * @store: the #CamelStore containing the folder + * @folder_name: the name of the folder + * + * Emitted when a folder becomes available + **/ + signals[FOLDER_AVAILABLE] = g_signal_new ( + "folder-available", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (MailFolderCacheClass, folder_available), + NULL, NULL, NULL, + G_TYPE_NONE, 2, + CAMEL_TYPE_STORE, + G_TYPE_STRING); + + /** + * MailFolderCache::folder-unavailable + * @store: the #CamelStore containing the folder + * @folder_name: the name of the folder + * + * Emitted when a folder becomes unavailable. This represents a + * transient condition. See MailFolderCache::folder-deleted to be + * notified when a folder is permanently removed. + **/ + signals[FOLDER_UNAVAILABLE] = g_signal_new ( + "folder-unavailable", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (MailFolderCacheClass, folder_unavailable), + NULL, NULL, NULL, + G_TYPE_NONE, 2, + CAMEL_TYPE_STORE, + G_TYPE_STRING); + + /** + * MailFolderCache::folder-deleted + * @store: the #CamelStore containing the folder + * @folder_name: the name of the folder + * + * Emitted when a folder is deleted + **/ + signals[FOLDER_DELETED] = g_signal_new ( + "folder-deleted", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (MailFolderCacheClass, folder_deleted), + NULL, NULL, /* accumulator */ + NULL, + G_TYPE_NONE, 2, + CAMEL_TYPE_STORE, + G_TYPE_STRING); + + /** + * MailFolderCache::folder-renamed + * @store: the #CamelStore containing the folder + * @old_folder_name: the old name of the folder + * @new_folder_name: the new name of the folder + * + * Emitted when a folder is renamed + **/ + signals[FOLDER_RENAMED] = g_signal_new ( + "folder-renamed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (MailFolderCacheClass, folder_renamed), + NULL, NULL, NULL, + G_TYPE_NONE, 3, + CAMEL_TYPE_STORE, + G_TYPE_STRING, + G_TYPE_STRING); + + /** + * MailFolderCache::folder-unread-updated + * @store: the #CamelStore containing the folder + * @folder_name: the name of the folder + * @unread: the number of unread mails in the folder + * + * Emitted when a we receive an update to the unread count for a folder + **/ + signals[FOLDER_UNREAD_UPDATED] = g_signal_new ( + "folder-unread-updated", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (MailFolderCacheClass, folder_unread_updated), + NULL, NULL, NULL, + G_TYPE_NONE, 3, + CAMEL_TYPE_STORE, + G_TYPE_STRING, + G_TYPE_INT); + + /** + * MailFolderCache::folder-changed + * @store: the #CamelStore containing the folder + * @folder_name: the name of the folder + * @new_messages: the number of new messages for the folder + * @msg_uid: uid of the new message, or NULL + * @msg_sender: sender of the new message, or NULL + * @msg_subject: subject of the new message, or NULL + * + * Emitted when a folder has changed. If @new_messages is not + * exactly 1, @msg_uid, @msg_sender, and @msg_subject will be NULL. + **/ + signals[FOLDER_CHANGED] = g_signal_new ( + "folder-changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (MailFolderCacheClass, folder_changed), + NULL, NULL, NULL, + G_TYPE_NONE, 6, + CAMEL_TYPE_STORE, + G_TYPE_STRING, + G_TYPE_INT, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING); +} + +static void +mail_folder_cache_init (MailFolderCache *cache) +{ + const gchar *buf; + guint timeout; + + cache->priv = MAIL_FOLDER_CACHE_GET_PRIVATE (cache); + + /* initialize values */ + cache->priv->stores = g_hash_table_new (NULL, NULL); + cache->priv->stores_mutex = g_mutex_new (); + + g_queue_init (&cache->priv->updates); + cache->priv->count_sent = getenv("EVOLUTION_COUNT_SENT") != NULL; + cache->priv->count_trash = getenv("EVOLUTION_COUNT_TRASH") != NULL; + + buf = getenv ("EVOLUTION_PING_TIMEOUT"); + timeout = buf ? strtoul (buf, NULL, 10) : 600; + cache->priv->ping_id = g_timeout_add_seconds ( + timeout, (GSourceFunc) ping_cb, cache); + + g_queue_init (&cache->priv->local_folder_uris); + g_queue_init (&cache->priv->remote_folder_uris); +} + +MailFolderCache * +mail_folder_cache_new (EMailSession *session) +{ + g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); + + return g_object_new ( + MAIL_TYPE_FOLDER_CACHE, + "session", session, NULL); +} + +EMailSession * +mail_folder_cache_get_session (MailFolderCache *cache) +{ + g_return_val_if_fail (MAIL_IS_FOLDER_CACHE (cache), NULL); + + return E_MAIL_SESSION (cache->priv->session); +} + +/** + * mail_folder_cache_note_store: + * + * Add a store whose folders should appear in the shell The folders are scanned + * from the store, and/or added at runtime via the folder_created event. The + * @done function returns if we can free folder info. + */ +void +mail_folder_cache_note_store (MailFolderCache *cache, + CamelStore *store, + GCancellable *cancellable, + NoteDoneFunc done, + gpointer data) +{ + CamelSession *session; + StoreInfo *si; + struct _update_data *ud; + gint hook = 0; + + g_return_if_fail (MAIL_IS_FOLDER_CACHE (cache)); + g_return_if_fail (CAMEL_IS_STORE (store)); + + session = camel_service_get_session (CAMEL_SERVICE (store)); + + g_mutex_lock (cache->priv->stores_mutex); + + si = g_hash_table_lookup (cache->priv->stores, store); + if (si == NULL) { + si = store_info_new (store); + g_hash_table_insert (cache->priv->stores, store, si); + hook = TRUE; + } + + ud = g_malloc0 (sizeof (*ud)); + ud->done = done; + ud->data = data; + ud->cache = cache; + + if (G_IS_CANCELLABLE (cancellable)) + ud->cancellable = g_object_ref (cancellable); + + /* We might get a race when setting up a store, such that it is + * still left in offline mode, after we've gone online. This + * catches and fixes it up when the shell opens us. */ + if (CAMEL_IS_DISCO_STORE (store)) { + if (camel_session_get_online (session) && + camel_disco_store_status (CAMEL_DISCO_STORE (store)) == + CAMEL_DISCO_STORE_OFFLINE) { + e_mail_store_go_online ( + store, G_PRIORITY_DEFAULT, cancellable, + (GAsyncReadyCallback) store_go_online_cb, ud); + } else { + goto normal_setup; + } + } else if (CAMEL_IS_OFFLINE_STORE (store)) { + if (camel_session_get_online (session) && + !camel_offline_store_get_online ( + CAMEL_OFFLINE_STORE (store))) { + e_mail_store_go_online ( + store, G_PRIORITY_DEFAULT, cancellable, + (GAsyncReadyCallback) store_go_online_cb, ud); + } else { + goto normal_setup; + } + } else { + normal_setup: + if (store_has_folder_hierarchy (store)) + camel_store_get_folder_info ( + store, NULL, + CAMEL_STORE_FOLDER_INFO_FAST | + CAMEL_STORE_FOLDER_INFO_RECURSIVE | + CAMEL_STORE_FOLDER_INFO_SUBSCRIBED, + G_PRIORITY_DEFAULT, cancellable, + (GAsyncReadyCallback) update_folders, ud); + } + + g_queue_push_tail (&si->folderinfo_updates, ud); + + g_mutex_unlock (cache->priv->stores_mutex); + + /* there is potential for race here, but it is safe as we check + * for the store anyway */ + if (hook) { + g_signal_connect ( + store, "folder-opened", + G_CALLBACK (store_folder_opened_cb), cache); + g_signal_connect ( + store, "folder-created", + G_CALLBACK (store_folder_created_cb), cache); + g_signal_connect ( + store, "folder-deleted", + G_CALLBACK (store_folder_deleted_cb), cache); + g_signal_connect ( + store, "folder-renamed", + G_CALLBACK (store_folder_renamed_cb), cache); + } + + if (hook && CAMEL_IS_SUBSCRIBABLE (store)) { + g_signal_connect ( + store, "folder-subscribed", + G_CALLBACK (store_folder_subscribed_cb), cache); + g_signal_connect ( + store, "folder-unsubscribed", + G_CALLBACK (store_folder_unsubscribed_cb), cache); + } +} + +/** + * mail_folder_cache_note_folder: + * + * When a folder has been opened, notify it for watching. The folder must have + * already been created on the store (which has already been noted) before the + * folder can be opened + */ +void +mail_folder_cache_note_folder (MailFolderCache *cache, + CamelFolder *folder) +{ + CamelStore *parent_store; + StoreInfo *si; + struct _folder_info *mfi; + const gchar *full_name; + + g_return_if_fail (MAIL_IS_FOLDER_CACHE (cache)); + g_return_if_fail (CAMEL_IS_FOLDER (folder)); + + full_name = camel_folder_get_full_name (folder); + parent_store = camel_folder_get_parent_store (folder); + + g_mutex_lock (cache->priv->stores_mutex); + if (cache->priv->stores == NULL + || (si = g_hash_table_lookup (cache->priv->stores, parent_store)) == NULL + || (mfi = g_hash_table_lookup (si->folders, full_name)) == NULL) { + w(g_warning("Noting folder before store initialised")); + g_mutex_unlock (cache->priv->stores_mutex); + return; + } + + /* dont do anything if we already have this */ + if (mfi->folder == folder) { + g_mutex_unlock (cache->priv->stores_mutex); + return; + } + + mfi->folder = folder; + + g_object_add_weak_pointer (G_OBJECT (folder), &mfi->folder); + + update_1folder (cache, mfi, 0, NULL, NULL, NULL, NULL); + + g_mutex_unlock (cache->priv->stores_mutex); + + g_signal_connect ( + folder, "changed", + G_CALLBACK (folder_changed_cb), cache); +} + +/** + * mail_folder_cache_get_folder_from_uri: + * + * Gets the #CamelFolder for the supplied @uri. + * + * Returns: %TRUE if the URI is available, folderp is set to a reffed + * folder if the folder has also already been opened + */ +gboolean +mail_folder_cache_get_folder_from_uri (MailFolderCache *cache, + const gchar *uri, + CamelFolder **folderp) +{ + struct _find_info fi = { uri, NULL }; + + if (cache->priv->stores == NULL) + return FALSE; + + g_mutex_lock (cache->priv->stores_mutex); + g_hash_table_foreach ( + cache->priv->stores, (GHFunc) + storeinfo_find_folder_info, &fi); + if (folderp) { + if (fi.fi && fi.fi->folder) + *folderp = g_object_ref (fi.fi->folder); + else + *folderp = NULL; + } + g_mutex_unlock (cache->priv->stores_mutex); + + return fi.fi != NULL; +} + +gboolean +mail_folder_cache_get_folder_info_flags (MailFolderCache *cache, + CamelFolder *folder, + CamelFolderInfoFlags *flags) +{ + struct _find_info fi = { NULL, NULL }; + gchar *folder_uri; + + if (cache->priv->stores == NULL) + return FALSE; + + folder_uri = e_mail_folder_uri_from_folder (folder); + fi.folder_uri = folder_uri; + + g_mutex_lock (cache->priv->stores_mutex); + g_hash_table_foreach ( + cache->priv->stores, (GHFunc) + storeinfo_find_folder_info, &fi); + if (flags) { + if (fi.fi) + *flags = fi.fi->flags; + else + *flags = 0; + } + g_mutex_unlock (cache->priv->stores_mutex); + + g_free (folder_uri); + + return fi.fi != NULL; +} + +/* Returns whether folder 'folder' has children based on folder_info->child property. + * If not found returns FALSE and sets 'found' to FALSE, if not NULL. */ +gboolean +mail_folder_cache_get_folder_has_children (MailFolderCache *cache, + CamelFolder *folder, + gboolean *found) +{ + struct _find_info fi = { NULL, NULL }; + gchar *folder_uri; + + g_return_val_if_fail (MAIL_IS_FOLDER_CACHE (cache), FALSE); + g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); + + if (cache->priv->stores == NULL) + return FALSE; + + folder_uri = e_mail_folder_uri_from_folder (folder); + fi.folder_uri = folder_uri; + + g_mutex_lock (cache->priv->stores_mutex); + g_hash_table_foreach ( + cache->priv->stores, (GHFunc) + storeinfo_find_folder_info, &fi); + if (found != NULL) + *found = fi.fi != NULL; + g_mutex_unlock (cache->priv->stores_mutex); + + g_free (folder_uri); + + return fi.fi != NULL && fi.fi->has_children; +} + +void +mail_folder_cache_get_local_folder_uris (MailFolderCache *self, + GQueue *out_queue) +{ + GList *head, *link; + + g_return_if_fail (MAIL_IS_FOLDER_CACHE (self)); + g_return_if_fail (out_queue != NULL); + + /* Reuse the stores mutex just because it's handy. */ + g_mutex_lock (self->priv->stores_mutex); + + head = g_queue_peek_head_link (&self->priv->local_folder_uris); + + for (link = head; link != NULL; link = g_list_next (link)) + g_queue_push_tail (out_queue, g_strdup (link->data)); + + g_mutex_unlock (self->priv->stores_mutex); +} + +void +mail_folder_cache_get_remote_folder_uris (MailFolderCache *self, + GQueue *out_queue) +{ + GList *head, *link; + + g_return_if_fail (MAIL_IS_FOLDER_CACHE (self)); + g_return_if_fail (out_queue != NULL); + + /* Reuse the stores mutex just because it's handy. */ + g_mutex_lock (self->priv->stores_mutex); + + head = g_queue_peek_head_link (&self->priv->remote_folder_uris); + + for (link = head; link != NULL; link = g_list_next (link)) + g_queue_push_tail (out_queue, g_strdup (link->data)); + + g_mutex_unlock (self->priv->stores_mutex); +} + +void +mail_folder_cache_service_added (MailFolderCache *cache, + CamelService *service) +{ + g_return_if_fail (MAIL_IS_FOLDER_CACHE (cache)); + g_return_if_fail (CAMEL_IS_SERVICE (service)); + + mail_folder_cache_note_store ( + cache, CAMEL_STORE (service), NULL, NULL, NULL); +} + +void +mail_folder_cache_service_removed (MailFolderCache *cache, + CamelService *service) +{ + StoreInfo *si; + + g_return_if_fail (MAIL_IS_FOLDER_CACHE (cache)); + g_return_if_fail (CAMEL_IS_SERVICE (service)); + + if (cache->priv->stores == NULL) + return; + + g_mutex_lock (cache->priv->stores_mutex); + + si = g_hash_table_lookup (cache->priv->stores, service); + if (si != NULL) { + g_hash_table_remove (cache->priv->stores, service); + + g_signal_handlers_disconnect_matched ( + service, G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, cache); + + g_hash_table_foreach ( + si->folders, (GHFunc) + unset_folder_info_hash, cache); + + store_info_free (si); + } + + g_mutex_unlock (cache->priv->stores_mutex); +} + +void +mail_folder_cache_service_enabled (MailFolderCache *cache, + CamelService *service) +{ + g_return_if_fail (MAIL_IS_FOLDER_CACHE (cache)); + g_return_if_fail (CAMEL_IS_SERVICE (service)); + + mail_folder_cache_note_store ( + cache, CAMEL_STORE (service), NULL, NULL, NULL); +} + +void +mail_folder_cache_service_disabled (MailFolderCache *cache, + CamelService *service) +{ + g_return_if_fail (MAIL_IS_FOLDER_CACHE (cache)); + g_return_if_fail (CAMEL_IS_SERVICE (service)); + + /* To the folder cache, disabling a service is the same as + * removing it. We keep a separate callback function only + * to use as a breakpoint target in a debugger. */ + mail_folder_cache_service_removed (cache, service); +} diff --git a/libemail-engine/mail-folder-cache.h b/libemail-engine/mail-folder-cache.h new file mode 100644 index 0000000000..b0d1d1bc49 --- /dev/null +++ b/libemail-engine/mail-folder-cache.h @@ -0,0 +1,156 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + * + * Authors: + * Peter Williams + * Michael Zucchi + * Jonathon Jongsma + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * Copyright (C) 2009 Intel Corporation + * + */ + +#ifndef MAIL_FOLDER_CACHE_H +#define MAIL_FOLDER_CACHE_H + +#include + +/* Standard GObject macros */ +#define MAIL_TYPE_FOLDER_CACHE \ + (mail_folder_cache_get_type ()) +#define MAIL_FOLDER_CACHE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), MAIL_TYPE_FOLDER_CACHE, MailFolderCache)) +#define MAIL_FOLDER_CACHE_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), MAIL_TYPE_FOLDER_CACHE, MailFolderCacheClass)) +#define MAIL_IS_FOLDER_CACHE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), MAIL_TYPE_FOLDER_CACHE)) +#define MAIL_IS_FOLDER_CACHE_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), MAIL_TYPE_FOLDER_CACHE)) +#define MAIL_FOLDER_CACHE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), MAIL_TYPE_FOLDER_CACHE, MailFolderCacheClass)) + +G_BEGIN_DECLS + +/* Avoid a circular dependency. */ +struct _EMailSession; + +typedef struct _MailFolderCache MailFolderCache; +typedef struct _MailFolderCacheClass MailFolderCacheClass; +typedef struct _MailFolderCachePrivate MailFolderCachePrivate; + +/** + * NoteDoneFunc: + * + * The signature of a function to be registered as a callback for + * mail_folder_cache_note_store() + */ +typedef gboolean (*NoteDoneFunc) (MailFolderCache *cache, + CamelStore *store, + CamelFolderInfo *info, + gpointer data); + +/** + * MailFolderCache: + * + * Contains only private data that should be read and manipulated using the + * functions below. + */ +struct _MailFolderCache { + GObject parent; + MailFolderCachePrivate *priv; +}; + +struct _MailFolderCacheClass { + GObjectClass parent_class; + + /* Signals */ + void (*folder_available) (MailFolderCache *cache, + CamelStore *store, + const gchar *folder_name); + void (*folder_unavailable) (MailFolderCache *cache, + CamelStore *store, + const gchar *folder_name); + void (*folder_deleted) (MailFolderCache *cache, + CamelStore *store, + const gchar *folder_name); + void (*folder_renamed) (MailFolderCache *cache, + CamelStore *store, + const gchar *old_folder_name, + const gchar *new_folder_name); + void (*folder_unread_updated) + (MailFolderCache *cache, + CamelStore *store, + const gchar *folder_name, + gint unread); + void (*folder_changed) (MailFolderCache *cache, + CamelStore *store, + gint new_messages, + const gchar *msg_uid, + const gchar *msg_sender, + const gchar *msg_subject); +}; + +GType mail_folder_cache_get_type (void) G_GNUC_CONST; +MailFolderCache * + mail_folder_cache_new (struct _EMailSession *session); +struct _EMailSession * + mail_folder_cache_get_session (MailFolderCache *cache); +void mail_folder_cache_note_store (MailFolderCache *cache, + CamelStore *store, + GCancellable *cancellable, + NoteDoneFunc done, + gpointer data); +void mail_folder_cache_note_folder (MailFolderCache *cache, + CamelFolder *folder); +gboolean mail_folder_cache_get_folder_from_uri + (MailFolderCache *cache, + const gchar *uri, + CamelFolder **folderp); +gboolean mail_folder_cache_get_folder_info_flags + (MailFolderCache *cache, + CamelFolder *folder, + CamelFolderInfoFlags *flags); +gboolean mail_folder_cache_get_folder_has_children + (MailFolderCache *cache, + CamelFolder *folder, + gboolean *found); +void mail_folder_cache_get_local_folder_uris + (MailFolderCache *cache, + GQueue *out_queue); +void mail_folder_cache_get_remote_folder_uris + (MailFolderCache *cache, + GQueue *out_queue); +void mail_folder_cache_service_added (MailFolderCache *cache, + CamelService *service); +void mail_folder_cache_service_removed + (MailFolderCache *cache, + CamelService *service); +void mail_folder_cache_service_enabled + (MailFolderCache *cache, + CamelService *service); +void mail_folder_cache_service_disabled + (MailFolderCache *cache, + CamelService *service); + + +G_END_DECLS + +#endif /* MAIL_FOLDER_CACHE_H */ diff --git a/libemail-engine/mail-ops.c b/libemail-engine/mail-ops.c new file mode 100644 index 0000000000..7063179e55 --- /dev/null +++ b/libemail-engine/mail-ops.c @@ -0,0 +1,1691 @@ +/* + * mail-ops.c: callbacks for the mail toolbar/menus + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + * + * Authors: + * Dan Winship + * Jeffrey Stedfast + * Peter Williams + * Michael Zucchi + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include + +#include +#include + +#include "e-mail-utils.h" +#include "mail-ops.h" +#include "mail-tools.h" + +#include "e-mail-session.h" +#include "e-mail-session-utils.h" + +#define w(x) +#define d(x) + +/* XXX Make this a preprocessor definition. */ +const gchar *x_mailer = "Evolution " VERSION SUB_VERSION " " VERSION_COMMENT; + +/* used for both just filtering a folder + uid's, and for filtering a whole folder */ +/* used both for fetching mail, and for filtering mail */ +struct _filter_mail_msg { + MailMsg base; + + EMailSession *session; + CamelFolder *source_folder; /* where they come from */ + GPtrArray *source_uids; /* uids to copy, or NULL == copy all */ + CamelUIDCache *cache; /* UID cache if we are to cache the uids, NULL otherwise */ + CamelFilterDriver *driver; + gint delete; /* delete messages after filtering them? */ + CamelFolder *destination; /* default destination for any messages, NULL for none */ +}; + +/* since fetching also filters, we subclass the data here */ +struct _fetch_mail_msg { + struct _filter_mail_msg fmsg; + + CamelStore *store; + GCancellable *cancellable; /* we have our own cancellation + * struct, the other should be empty */ + gint keep; /* keep on server? */ + + void (*done)(gpointer data); + gpointer data; +}; + +static gchar * +em_filter_folder_element_desc (struct _filter_mail_msg *m) +{ + return g_strdup (_("Filtering Selected Messages")); +} + +/* filter a folder, or a subset thereof, uses source_folder/source_uids */ +/* this is shared with fetch_mail */ +static void +em_filter_folder_element_exec (struct _filter_mail_msg *m, + GCancellable *cancellable, + GError **error) +{ + CamelFolder *folder; + GPtrArray *uids, *folder_uids = NULL; + + folder = m->source_folder; + + if (folder == NULL || camel_folder_get_message_count (folder) == 0) + return; + + if (m->destination) { + camel_folder_freeze (m->destination); + camel_filter_driver_set_default_folder (m->driver, m->destination); + } + + camel_folder_freeze (folder); + + if (m->source_uids) + uids = m->source_uids; + else + folder_uids = uids = camel_folder_get_uids (folder); + + camel_filter_driver_filter_folder ( + m->driver, folder, m->cache, uids, m->delete, + cancellable, error); + camel_filter_driver_flush (m->driver, error); + + if (folder_uids) + camel_folder_free_uids (folder, folder_uids); + + /* sync our source folder */ + if (!m->cache) + camel_folder_synchronize_sync ( + folder, FALSE, cancellable, error); + camel_folder_thaw (folder); + + if (m->destination) + camel_folder_thaw (m->destination); + + /* this may thaw/unref source folders, do it here so we dont do + * it in the main thread see also fetch_mail_fetch () below */ + g_object_unref (m->driver); + m->driver = NULL; +} + +static void +em_filter_folder_element_done (struct _filter_mail_msg *m) +{ +} + +static void +em_filter_folder_element_free (struct _filter_mail_msg *m) +{ + mail_session_flush_filter_log (m->session); + + if (m->session) + g_object_unref (m->session); + + if (m->source_folder) + g_object_unref (m->source_folder); + + if (m->source_uids) + em_utils_uids_free (m->source_uids); + + if (m->destination) + g_object_unref (m->destination); + + if (m->driver) + g_object_unref (m->driver); +} + +static MailMsgInfo em_filter_folder_element_info = { + sizeof (struct _filter_mail_msg), + (MailMsgDescFunc) em_filter_folder_element_desc, + (MailMsgExecFunc) em_filter_folder_element_exec, + (MailMsgDoneFunc) em_filter_folder_element_done, + (MailMsgFreeFunc) em_filter_folder_element_free +}; + +void +mail_filter_folder (EMailSession *session, + CamelFolder *source_folder, + GPtrArray *uids, + const gchar *type, + gboolean notify) +{ + struct _filter_mail_msg *m; + + m = mail_msg_new (&em_filter_folder_element_info); + m->session = g_object_ref (session); + m->source_folder = g_object_ref (source_folder); + m->source_uids = uids; + m->cache = NULL; + m->delete = FALSE; + + m->driver = camel_session_get_filter_driver ( + CAMEL_SESSION (session), type, NULL); + + if (!notify) { + /* FIXME: have a #define NOTIFY_FILTER_NAME macro? */ + /* the filter name has to stay in sync with mail-session::get_filter_driver */ + camel_filter_driver_remove_rule_by_name (m->driver, "new-mail-notification"); + } + + mail_msg_unordered_push (m); +} + +/* ********************************************************************** */ + +static gchar * +fetch_mail_desc (struct _fetch_mail_msg *m) +{ + return g_strdup (_("Fetching Mail")); +} + +static void +fetch_mail_exec (struct _fetch_mail_msg *m, + GCancellable *cancellable, + GError **error) +{ + struct _filter_mail_msg *fm = (struct _filter_mail_msg *) m; + CamelFolder *folder = NULL; + CamelService *service; + CamelSession *session; + CamelURL *url; + gboolean is_local_delivery; + const gchar *uid; + gint i; + + service = CAMEL_SERVICE (m->store); + session = camel_service_get_session (service); + + fm->destination = e_mail_session_get_local_folder ( + E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_LOCAL_INBOX); + if (fm->destination == NULL) + goto exit; + g_object_ref (fm->destination); + + url = camel_service_new_camel_url (service); + is_local_delivery = em_utils_is_local_delivery_mbox_file (url); + + if (is_local_delivery) { + gchar *path; + gchar *url_string; + + path = mail_tool_do_movemail (m->store, error); + url_string = camel_url_to_string (url, CAMEL_URL_HIDE_ALL); + + if (path && (!error || !*error)) { + camel_folder_freeze (fm->destination); + camel_filter_driver_set_default_folder ( + fm->driver, fm->destination); + camel_filter_driver_filter_mbox ( + fm->driver, path, url_string, + cancellable, error); + camel_folder_thaw (fm->destination); + + if (!error || !*error) + g_unlink (path); + } + + g_free (path); + g_free (url_string); + } else { + uid = camel_service_get_uid (service); + + folder = fm->source_folder = + e_mail_session_get_inbox_sync ( + fm->session, uid, cancellable, error); + } + + camel_url_free (url); + + if (folder != NULL) { + /* This handles 'keep on server' stuff, if we have any new + * uid's to copy across, we need to copy them to a new array + * 'cause of the way fetch_mail_free works. */ + CamelUIDCache *cache = NULL; + CamelStore *parent_store; + CamelService *service; + const gchar *data_dir; + gchar *cachename; + + parent_store = camel_folder_get_parent_store (folder); + + service = CAMEL_SERVICE (parent_store); + data_dir = camel_service_get_user_data_dir (service); + + cachename = g_build_filename (data_dir, "uid-cache", NULL); + cache = camel_uid_cache_new (cachename); + g_free (cachename); + + if (cache) { + GPtrArray *folder_uids, *cache_uids, *uids; + + folder_uids = camel_folder_get_uids (folder); + cache_uids = camel_uid_cache_get_new_uids (cache, folder_uids); + if (cache_uids) { + /* need to copy this, sigh */ + fm->source_uids = uids = g_ptr_array_new (); + g_ptr_array_set_size (uids, cache_uids->len); + for (i = 0; i < cache_uids->len; i++) + uids->pdata[i] = g_strdup (cache_uids->pdata[i]); + camel_uid_cache_free_uids (cache_uids); + + fm->cache = cache; + em_filter_folder_element_exec (fm, cancellable, error); + + /* need to uncancel so writes/etc. don't fail */ + if (g_cancellable_is_cancelled (m->cancellable)) + g_cancellable_reset (m->cancellable); + + /* save the cache of uids that we've just downloaded */ + camel_uid_cache_save (cache); + } + + if (fm->delete && (!error || !*error)) { + /* not keep on server - just delete all + * the actual messages on the server */ + for (i = 0; i < folder_uids->len; i++) { + camel_folder_delete_message ( + folder, folder_uids->pdata[i]); + } + } + + if ((fm->delete || cache_uids) && (!error || !*error)) { + /* expunge messages (downloaded so far) */ + /* FIXME Not passing a GCancellable or GError here. */ + camel_folder_synchronize_sync ( + folder, fm->delete, NULL, NULL); + } + + camel_uid_cache_destroy (cache); + camel_folder_free_uids (folder, folder_uids); + } else { + em_filter_folder_element_exec (fm, cancellable, error); + } + + /* we unref the source folder here since we + * may now block in finalize (we try to + * disconnect cleanly) */ + g_object_unref (fm->source_folder); + fm->source_folder = NULL; + } + +exit: + /* we unref this here as it may have more work to do (syncing + * folders and whatnot) before we are really done */ + /* should this be cancellable too? (i.e. above unregister above) */ + if (fm->driver) { + g_object_unref (fm->driver); + fm->driver = NULL; + } + + /* also disconnect if not a local delivery mbox; + * there is no need to keep the connection alive forever */ + if (!is_local_delivery) + em_utils_disconnect_service_sync ( + service, TRUE, cancellable, NULL); +} + +static void +fetch_mail_done (struct _fetch_mail_msg *m) +{ + if (m->done) + m->done (m->data); +} + +static void +fetch_mail_free (struct _fetch_mail_msg *m) +{ + if (m->store != NULL) + g_object_unref (m->store); + + if (m->cancellable != NULL) + g_object_unref (m->cancellable); + + em_filter_folder_element_free ((struct _filter_mail_msg *) m); +} + +static MailMsgInfo fetch_mail_info = { + sizeof (struct _fetch_mail_msg), + (MailMsgDescFunc) fetch_mail_desc, + (MailMsgExecFunc) fetch_mail_exec, + (MailMsgDoneFunc) fetch_mail_done, + (MailMsgFreeFunc) fetch_mail_free +}; + +/* ouch, a 'do everything' interface ... */ +void +mail_fetch_mail (CamelStore *store, + gint keep, + const gchar *type, + GCancellable *cancellable, + CamelFilterGetFolderFunc get_folder, + gpointer get_data, + CamelFilterStatusFunc *status, + gpointer status_data, + void (*done)(gpointer data), + gpointer data) +{ + struct _fetch_mail_msg *m; + struct _filter_mail_msg *fm; + CamelSession *session; + + g_return_if_fail (CAMEL_IS_STORE (store)); + + session = camel_service_get_session (CAMEL_SERVICE (store)); + + m = mail_msg_new (&fetch_mail_info); + fm = (struct _filter_mail_msg *) m; + fm->session = g_object_ref (session); + m->store = g_object_ref (store); + fm->delete = !keep; + fm->cache = NULL; + if (cancellable) + m->cancellable = g_object_ref (cancellable); + m->done = done; + m->data = data; + + fm->driver = camel_session_get_filter_driver (session, type, NULL); + camel_filter_driver_set_folder_func (fm->driver, get_folder, get_data); + if (status) + camel_filter_driver_set_status_func (fm->driver, status, status_data); + + mail_msg_unordered_push (m); +} + +/* ********************************************************************** */ +/* sending stuff */ +/* ** SEND MAIL *********************************************************** */ + +static const gchar *normal_recipients[] = { + CAMEL_RECIPIENT_TYPE_TO, + CAMEL_RECIPIENT_TYPE_CC, + CAMEL_RECIPIENT_TYPE_BCC +}; + +static const gchar *resent_recipients[] = { + CAMEL_RECIPIENT_TYPE_RESENT_TO, + CAMEL_RECIPIENT_TYPE_RESENT_CC, + CAMEL_RECIPIENT_TYPE_RESENT_BCC +}; + +struct _send_queue_msg { + MailMsg base; + + EMailSession *session; + CamelFolder *queue; + CamelTransport *transport; + + CamelFilterDriver *driver; + + /* we use camelfilterstatusfunc, even though its not the filter doing it */ + CamelFilterStatusFunc *status; + gpointer status_data; + + void (*done)(gpointer data); + gpointer data; +}; + +static void report_status (struct _send_queue_msg *m, + enum camel_filter_status_t status, + gint pc, + const gchar *desc, + ...); + +/* send 1 message to a specific transport */ +static void +mail_send_message (struct _send_queue_msg *m, + CamelFolder *queue, + const gchar *uid, + CamelTransport *transport, + CamelFilterDriver *driver, + GCancellable *cancellable, + GError **error) +{ + EAccount *account = NULL; + const CamelInternetAddress *iaddr; + CamelAddress *from, *recipients; + CamelMessageInfo *info = NULL; + CamelProvider *provider; + gchar *transport_uid = NULL; + gchar *sent_folder_uri = NULL; + const gchar *resent_from, *tmp; + CamelFolder *folder = NULL; + GString *err = NULL; + struct _camel_header_raw *xev, *header; + CamelMimeMessage *message; + gint i; + GError *local_error = NULL; + + message = camel_folder_get_message_sync ( + queue, uid, cancellable, error); + if (!message) + return; + + camel_medium_set_header (CAMEL_MEDIUM (message), "X-Mailer", x_mailer); + + err = g_string_new (""); + xev = mail_tool_remove_xevolution_headers (message); + + tmp = camel_header_raw_find (&xev, "X-Evolution-Account", NULL); + if (tmp != NULL) { + gchar *name; + + name = g_strstrip (g_strdup (tmp)); + if ((account = e_get_account_by_uid (name)) + /* 'old' x-evolution-account stored the name, how silly */ + || (account = e_get_account_by_name (name))) { + if (account->transport) { + CamelService *service; + gchar *transport_uid; + + transport_uid = g_strconcat ( + account->uid, "-transport", NULL); + service = camel_session_get_service ( + CAMEL_SESSION (m->session), + transport_uid); + g_free (transport_uid); + + if (CAMEL_IS_TRANSPORT (service)) + transport = CAMEL_TRANSPORT (service); + } + + sent_folder_uri = g_strdup (account->sent_folder_uri); + } + g_free (name); + } + + if (!account) { + /* default back to these headers */ + tmp = camel_header_raw_find(&xev, "X-Evolution-Transport", NULL); + if (tmp) + transport_uid = g_strstrip (g_strdup (tmp)); + + tmp = camel_header_raw_find(&xev, "X-Evolution-Fcc", NULL); + if (tmp) + sent_folder_uri = g_strstrip (g_strdup (tmp)); + } + + if (transport != NULL) { + const gchar *uid; + + /* Let the dialog know the right account it is using. */ + uid = camel_service_get_uid (CAMEL_SERVICE (transport)); + report_status (m, CAMEL_FILTER_STATUS_ACTION, 0, uid); + } + + /* Check for email sending */ + from = (CamelAddress *) camel_internet_address_new (); + resent_from = camel_medium_get_header (CAMEL_MEDIUM (message), "Resent-From"); + if (resent_from) { + camel_address_decode (from, resent_from); + } else { + iaddr = camel_mime_message_get_from (message); + camel_address_copy (from, CAMEL_ADDRESS (iaddr)); + } + + recipients = (CamelAddress *) camel_internet_address_new (); + for (i = 0; i < 3; i++) { + const gchar *type; + + type = resent_from ? resent_recipients[i] : normal_recipients[i]; + iaddr = camel_mime_message_get_recipients (message, type); + camel_address_cat (recipients, CAMEL_ADDRESS (iaddr)); + } + + if (camel_address_length (recipients) > 0) { + if (!em_utils_connect_service_sync ( + CAMEL_SERVICE (transport), cancellable, error)) + goto exit; + + if (!camel_transport_send_to_sync ( + transport, message, from, + recipients, cancellable, error)) + goto exit; + } + + /* Now check for posting, failures are ignored */ + info = camel_message_info_new (NULL); + camel_message_info_set_flags (info, CAMEL_MESSAGE_SEEN, ~0); + + for (header = xev; header; header = header->next) { + gchar *uri; + + if (strcmp(header->name, "X-Evolution-PostTo") != 0) + continue; + + /* TODO: don't lose errors */ + + uri = g_strstrip (g_strdup (header->value)); + /* FIXME Not passing a GCancellable or GError here. */ + folder = e_mail_session_uri_to_folder_sync ( + m->session, uri, 0, NULL, NULL); + if (folder) { + /* FIXME Not passing a GCancellable or GError here. */ + camel_folder_append_message_sync ( + folder, message, info, NULL, NULL, NULL); + g_object_unref (folder); + folder = NULL; + } + g_free (uri); + } + + /* post process */ + mail_tool_restore_xevolution_headers (message, xev); + + if (driver) { + camel_filter_driver_filter_message ( + driver, message, info, NULL, NULL, + NULL, "", cancellable, &local_error); + + if (local_error != NULL) { + if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + goto exit; + + /* sending mail, filtering failed */ + g_string_append_printf ( + err, _("Failed to apply outgoing filters: %s"), + local_error->message); + + g_clear_error (&local_error); + } + } + + provider = camel_service_get_provider (CAMEL_SERVICE (transport)); + + if (provider == NULL + || !(provider->flags & CAMEL_PROVIDER_DISABLE_SENT_FOLDER)) { + GError *local_error = NULL; + + if (sent_folder_uri) { + folder = e_mail_session_uri_to_folder_sync ( + m->session, sent_folder_uri, 0, + cancellable, &local_error); + if (folder == NULL) { + g_string_append_printf ( + err, _("Failed to append to %s: %s\n" + "Appending to local 'Sent' folder instead."), + sent_folder_uri, + local_error ? + local_error->message : + _("Unknown error")); + if (local_error) + g_clear_error (&local_error); + } + } + + if (!folder) { + folder = e_mail_session_get_local_folder ( + m->session, E_MAIL_LOCAL_FOLDER_SENT); + g_object_ref (folder); + } + + if (!camel_folder_append_message_sync ( + folder, message, info, + NULL, cancellable, &local_error)) { + + CamelFolder *sent_folder; + + if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + goto exit; + + sent_folder = e_mail_session_get_local_folder ( + m->session, E_MAIL_LOCAL_FOLDER_SENT); + + if (folder != sent_folder) { + const gchar *description; + + description = camel_folder_get_description (folder); + if (err->len) + g_string_append(err, "\n\n"); + g_string_append_printf ( + err, _("Failed to append to %s: %s\n" + "Appending to local 'Sent' folder instead."), + description, local_error->message); + g_object_ref (sent_folder); + g_object_unref (folder); + folder = sent_folder; + + g_clear_error (&local_error); + camel_folder_append_message_sync ( + folder, message, info, + NULL, cancellable, &local_error); + } + + if (local_error != NULL) { + if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + goto exit; + + if (err->len) + g_string_append(err, "\n\n"); + g_string_append_printf ( + err, _("Failed to append to local 'Sent' folder: %s"), + local_error->message); + } + } + } + + if (local_error == NULL) { + /* Mark the draft message for deletion, if present. */ + e_mail_session_handle_draft_headers_sync ( + m->session, message, cancellable, &local_error); + if (local_error != NULL) { + g_warning ("%s: Failed to handle draft headers: %s", G_STRFUNC, local_error->message); + g_clear_error (&local_error); + } + + /* Set flags on the original source message, if present. + * Source message refers to the message being forwarded + * or replied to. */ + e_mail_session_handle_source_headers_sync ( + m->session, message, cancellable, &local_error); + if (local_error != NULL) { + g_warning ("%s: Failed to handle source headers: %s", G_STRFUNC, local_error->message); + g_clear_error (&local_error); + } + } + + if (local_error == NULL) { + camel_folder_set_message_flags ( + queue, uid, CAMEL_MESSAGE_DELETED | + CAMEL_MESSAGE_SEEN, ~0); + /* Sync it to disk, since if it crashes in between, + * we keep sending it again on next start. */ + /* FIXME Not passing a GCancellable or GError here. */ + camel_folder_synchronize_sync (queue, FALSE, NULL, NULL); + } + + if (err->len) { + /* set the culmulative exception report */ + g_set_error ( + &local_error, CAMEL_ERROR, + CAMEL_ERROR_GENERIC, "%s", err->str); + } + +exit: + if (local_error != NULL) + g_propagate_error (error, local_error); + + /* FIXME Not passing a GCancellable or GError here. */ + if (folder) { + camel_folder_synchronize_sync (folder, FALSE, NULL, NULL); + g_object_unref (folder); + } + if (info) + camel_message_info_free (info); + g_object_unref (recipients); + g_object_unref (from); + g_free (sent_folder_uri); + g_free (transport_uid); + camel_header_raw_clear (&xev); + g_string_free (err, TRUE); + g_object_unref (message); +} + +/* ** SEND MAIL QUEUE ***************************************************** */ + +static void +report_status (struct _send_queue_msg *m, + enum camel_filter_status_t status, + gint pc, + const gchar *desc, + ...) +{ + va_list ap; + gchar *str; + + if (m->status) { + va_start (ap, desc); + str = g_strdup_vprintf (desc, ap); + va_end (ap); + m->status (m->driver, status, pc, str, m->status_data); + g_free (str); + } +} + +static void +send_queue_exec (struct _send_queue_msg *m, + GCancellable *cancellable, + GError **error) +{ + CamelFolder *sent_folder; + GPtrArray *uids, *send_uids = NULL; + gint i, j; + GError *local_error = NULL; + + d(printf("sending queue\n")); + + sent_folder = + e_mail_session_get_local_folder ( + m->session, E_MAIL_LOCAL_FOLDER_SENT); + + if (!(uids = camel_folder_get_uids (m->queue))) + return; + + send_uids = g_ptr_array_sized_new (uids->len); + for (i = 0, j = 0; i < uids->len; i++) { + CamelMessageInfo *info; + + info = camel_folder_get_message_info (m->queue, uids->pdata[i]); + if (info) { + if ((camel_message_info_flags (info) & CAMEL_MESSAGE_DELETED) == 0) + send_uids->pdata[j++] = uids->pdata[i]; + camel_folder_free_message_info (m->queue, info); + } + } + + send_uids->len = j; + if (send_uids->len == 0) { + /* nothing to send */ + camel_folder_free_uids (m->queue, uids); + g_ptr_array_free (send_uids, TRUE); + return; + } + + camel_operation_push_message (cancellable, _("Sending message")); + + /* NB: This code somewhat abuses the 'exception' stuff. Apart from + * fatal problems, it is also used as a mechanism to accumualte + * warning messages and present them back to the user. */ + + for (i = 0, j = 0; i < send_uids->len; i++) { + gint pc = (100 * i) / send_uids->len; + + report_status ( + m, CAMEL_FILTER_STATUS_START, pc, + _("Sending message %d of %d"), i+1, + send_uids->len); + + camel_operation_progress ( + cancellable, (i + 1) * 100 / send_uids->len); + + mail_send_message ( + m, m->queue, send_uids->pdata[i], m->transport, + m->driver, cancellable, &local_error); + if (local_error != NULL) { + if (!g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + /* merge exceptions into one */ + if (m->base.error != NULL) { + gchar *old_message; + + old_message = g_strdup ( + m->base.error->message); + g_clear_error (&m->base.error); + g_set_error ( + &m->base.error, CAMEL_ERROR, + CAMEL_ERROR_GENERIC, + "%s\n\n%s", old_message, + local_error->message); + g_free (old_message); + + g_clear_error (&local_error); + } else { + g_propagate_error (&m->base.error, local_error); + local_error = NULL; + } + + /* keep track of the number of failures */ + j++; + } else { + /* transfer the USER_CANCEL error to the + * async op exception and then break */ + g_propagate_error (&m->base.error, local_error); + local_error = NULL; + break; + } + } + } + + j += (send_uids->len - i); + + if (j > 0) + report_status ( + m, CAMEL_FILTER_STATUS_END, 100, + _("Failed to send %d of %d messages"), + j, send_uids->len); + else if (g_error_matches ( + m->base.error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + report_status (m, CAMEL_FILTER_STATUS_END, 100, _("Canceled.")); + else + report_status (m, CAMEL_FILTER_STATUS_END, 100, _("Complete.")); + + if (m->driver) { + g_object_unref (m->driver); + m->driver = NULL; + } + + camel_folder_free_uids (m->queue, uids); + g_ptr_array_free (send_uids, TRUE); + + /* FIXME Not passing a GCancellable or GError here. */ + if (j <= 0 && m->base.error == NULL) + camel_folder_synchronize_sync (m->queue, TRUE, NULL, NULL); + + /* FIXME Not passing a GCancellable or GError here. */ + if (sent_folder) + camel_folder_synchronize_sync (sent_folder, FALSE, NULL, NULL); + + camel_operation_pop_message (cancellable); +} + +static void +send_queue_done (struct _send_queue_msg *m) +{ + if (m->done) + m->done (m->data); +} + +static gchar * +send_queue_desc (struct _send_queue_msg *m) +{ + return g_strdup (_("Sending message")); +} + +static void +send_queue_free (struct _send_queue_msg *m) +{ + if (m->session != NULL) + g_object_unref (m->session); + if (m->driver != NULL) + g_object_unref (m->driver); + if (m->transport != NULL) + g_object_unref (m->transport); + g_object_unref (m->queue); +} + +static MailMsgInfo send_queue_info = { + sizeof (struct _send_queue_msg), + (MailMsgDescFunc) send_queue_desc, + (MailMsgExecFunc) send_queue_exec, + (MailMsgDoneFunc) send_queue_done, + (MailMsgFreeFunc) send_queue_free +}; + +/* same interface as fetch_mail, just 'cause i'm lazy today + * (and we need to run it from the same spot?) */ +void +mail_send_queue (EMailSession *session, + CamelFolder *queue, + CamelTransport *transport, + const gchar *type, + GCancellable *cancellable, + CamelFilterGetFolderFunc get_folder, + gpointer get_data, + CamelFilterStatusFunc *status, + gpointer status_data, + void (*done)(gpointer data), + gpointer data) +{ + struct _send_queue_msg *m; + + g_return_if_fail (E_IS_MAIL_SESSION (session)); + + m = mail_msg_new (&send_queue_info); + m->session = g_object_ref (session); + m->queue = g_object_ref (queue); + m->transport = g_object_ref (transport); + if (G_IS_CANCELLABLE (cancellable)) + m->base.cancellable = cancellable; + m->status = status; + m->status_data = status_data; + m->done = done; + m->data = data; + + m->driver = camel_session_get_filter_driver ( + CAMEL_SESSION (session), type, NULL); + camel_filter_driver_set_folder_func (m->driver, get_folder, get_data); + + mail_msg_unordered_push (m); +} + +/* ** TRANSFER MESSAGES **************************************************** */ + +struct _transfer_msg { + MailMsg base; + + EMailSession *session; + CamelFolder *source; + GPtrArray *uids; + gboolean delete; + gchar *dest_uri; + guint32 dest_flags; + + void (*done)(gboolean ok, gpointer data); + gpointer data; +}; + +static gchar * +transfer_messages_desc (struct _transfer_msg *m) +{ + return g_strdup_printf ( + m->delete ? + _("Moving messages to '%s'") : + _("Copying messages to '%s'"), + m->dest_uri); + +} + +static void +transfer_messages_exec (struct _transfer_msg *m, + GCancellable *cancellable, + GError **error) +{ + CamelFolder *dest; + + dest = e_mail_session_uri_to_folder_sync ( + m->session, m->dest_uri, m->dest_flags, + cancellable, error); + if (dest == NULL) + return; + + if (dest == m->source) { + g_object_unref (dest); + /* no-op */ + return; + } + + camel_folder_freeze (m->source); + camel_folder_freeze (dest); + + camel_folder_transfer_messages_to_sync ( + m->source, m->uids, dest, m->delete, NULL, + cancellable, error); + + /* make sure all deleted messages are marked as seen */ + + if (m->delete) { + gint i; + + for (i = 0; i < m->uids->len; i++) + camel_folder_set_message_flags ( + m->source, m->uids->pdata[i], + CAMEL_MESSAGE_SEEN, CAMEL_MESSAGE_SEEN); + } + + camel_folder_thaw (m->source); + camel_folder_thaw (dest); + + /* FIXME Not passing a GCancellable or GError here. */ + camel_folder_synchronize_sync (dest, FALSE, NULL, NULL); + g_object_unref (dest); +} + +static void +transfer_messages_done (struct _transfer_msg *m) +{ + if (m->done) + m->done (m->base.error == NULL, m->data); +} + +static void +transfer_messages_free (struct _transfer_msg *m) +{ + g_object_unref (m->session); + g_object_unref (m->source); + g_free (m->dest_uri); + em_utils_uids_free (m->uids); +} + +static MailMsgInfo transfer_messages_info = { + sizeof (struct _transfer_msg), + (MailMsgDescFunc) transfer_messages_desc, + (MailMsgExecFunc) transfer_messages_exec, + (MailMsgDoneFunc) transfer_messages_done, + (MailMsgFreeFunc) transfer_messages_free +}; + +void +mail_transfer_messages (EMailSession *session, + CamelFolder *source, + GPtrArray *uids, + gboolean delete_from_source, + const gchar *dest_uri, + guint32 dest_flags, + void (*done) (gboolean ok, + gpointer data), + gpointer data) +{ + struct _transfer_msg *m; + + g_return_if_fail (CAMEL_IS_FOLDER (source)); + g_return_if_fail (uids != NULL); + g_return_if_fail (dest_uri != NULL); + + m = mail_msg_new (&transfer_messages_info); + m->session = g_object_ref (session); + m->source = g_object_ref (source); + m->uids = uids; + m->delete = delete_from_source; + m->dest_uri = g_strdup (dest_uri); + m->dest_flags = dest_flags; + m->done = done; + m->data = data; + + mail_msg_slow_ordered_push (m); +} + +/* ** SYNC FOLDER ********************************************************* */ + +struct _sync_folder_msg { + MailMsg base; + + CamelFolder *folder; + void (*done) (CamelFolder *folder, gpointer data); + gpointer data; +}; + +static gchar * +sync_folder_desc (struct _sync_folder_msg *m) +{ + return g_strdup_printf (_("Storing folder '%s'"), + camel_folder_get_full_name (m->folder)); +} + +static void +sync_folder_exec (struct _sync_folder_msg *m, + GCancellable *cancellable, + GError **error) +{ + camel_folder_synchronize_sync ( + m->folder, FALSE, cancellable, error); +} + +static void +sync_folder_done (struct _sync_folder_msg *m) +{ + if (m->done) + m->done (m->folder, m->data); +} + +static void +sync_folder_free (struct _sync_folder_msg *m) +{ + if (m->folder) + g_object_unref (m->folder); +} + +static MailMsgInfo sync_folder_info = { + sizeof (struct _sync_folder_msg), + (MailMsgDescFunc) sync_folder_desc, + (MailMsgExecFunc) sync_folder_exec, + (MailMsgDoneFunc) sync_folder_done, + (MailMsgFreeFunc) sync_folder_free +}; + +void +mail_sync_folder (CamelFolder *folder, + void (*done) (CamelFolder *folder, + gpointer data), + gpointer data) +{ + struct _sync_folder_msg *m; + + m = mail_msg_new (&sync_folder_info); + m->folder = g_object_ref (folder); + m->data = data; + m->done = done; + + mail_msg_slow_ordered_push (m); +} + +/* ** SYNC STORE ********************************************************* */ + +struct _sync_store_msg { + MailMsg base; + + CamelStore *store; + gint expunge; + void (*done) (CamelStore *store, gpointer data); + gpointer data; +}; + +static gchar * +sync_store_desc (struct _sync_store_msg *m) +{ + CamelURL *url; + gchar *uri, *res; + + url = camel_service_new_camel_url (CAMEL_SERVICE (m->store)); + uri = camel_url_to_string (url, CAMEL_URL_HIDE_ALL); + camel_url_free (url); + + res = g_strdup_printf (m->expunge + ?_("Expunging and storing account '%s'") + :_("Storing account '%s'"), + uri); + g_free (uri); + + return res; +} + +static void +sync_store_exec (struct _sync_store_msg *m, + GCancellable *cancellable, + GError **error) +{ + camel_store_synchronize_sync ( + m->store, m->expunge, + cancellable, error); +} + +static void +sync_store_done (struct _sync_store_msg *m) +{ + if (m->done) + m->done (m->store, m->data); +} + +static void +sync_store_free (struct _sync_store_msg *m) +{ + g_object_unref (m->store); +} + +static MailMsgInfo sync_store_info = { + sizeof (struct _sync_store_msg), + (MailMsgDescFunc) sync_store_desc, + (MailMsgExecFunc) sync_store_exec, + (MailMsgDoneFunc) sync_store_done, + (MailMsgFreeFunc) sync_store_free +}; + +void +mail_sync_store (CamelStore *store, + gint expunge, + void (*done) (CamelStore *store, + gpointer data), + gpointer data) +{ + struct _sync_store_msg *m; + + m = mail_msg_new (&sync_store_info); + m->store = g_object_ref (store); + m->expunge = expunge; + m->data = data; + m->done = done; + + mail_msg_slow_ordered_push (m); +} + +/* ******************************************************************************** */ + +static gchar * +refresh_folder_desc (struct _sync_folder_msg *m) +{ + return g_strdup_printf ( + _("Refreshing folder '%s'"), + camel_folder_get_full_name (m->folder)); +} + +static void +refresh_folder_exec (struct _sync_folder_msg *m, + GCancellable *cancellable, + GError **error) +{ + camel_folder_refresh_info_sync ( + m->folder, cancellable, error); +} + +/* we just use the sync stuff where we can, since it would be the same */ +static MailMsgInfo refresh_folder_info = { + sizeof (struct _sync_folder_msg), + (MailMsgDescFunc) refresh_folder_desc, + (MailMsgExecFunc) refresh_folder_exec, + (MailMsgDoneFunc) sync_folder_done, + (MailMsgFreeFunc) sync_folder_free +}; + +void +mail_refresh_folder (CamelFolder *folder, + void (*done) (CamelFolder *folder, + gpointer data), + gpointer data) +{ + struct _sync_folder_msg *m; + + m = mail_msg_new (&refresh_folder_info); + m->folder = g_object_ref (folder); + m->data = data; + m->done = done; + + mail_msg_slow_ordered_push (m); +} + +/* ******************************************************************************** */ + +static gboolean +folder_is_from_source_uid (CamelFolder *folder, + const gchar *source_uid) +{ + CamelStore *store; + const gchar *uid; + + store = camel_folder_get_parent_store (folder); + uid = camel_service_get_uid (CAMEL_SERVICE (store)); + + return (g_strcmp0 (uid, source_uid) == 0); +} + +/* This is because pop3 accounts are hidden under local Inbox, + * thus whenever an expunge is done on a local trash or Inbox, + * then also all active pop3 accounts should be expunged. */ +static gboolean +expunge_pop3_stores (CamelFolder *expunging, + GCancellable *cancellable, + GError **error) +{ + GHashTable *expunging_uids; + CamelStore *parent_store; + CamelService *service; + CamelSession *session; + GPtrArray *uids; + EAccount *account; + EIterator *iter; + gboolean success = TRUE; + guint ii; + + parent_store = camel_folder_get_parent_store (expunging); + + service = CAMEL_SERVICE (parent_store); + session = camel_service_get_session (service); + + uids = camel_folder_get_uids (expunging); + + if (uids == NULL) + return TRUE; + + expunging_uids = g_hash_table_new_full ( + (GHashFunc) g_str_hash, + (GEqualFunc) g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) g_free); + + for (ii = 0; ii < uids->len; ii++) { + CamelMessageInfo *info; + CamelMessageFlags flags = 0; + CamelMimeMessage *message; + const gchar *pop3_uid; + const gchar *source_uid; + + info = camel_folder_get_message_info ( + expunging, uids->pdata[ii]); + + if (info != NULL) { + flags = camel_message_info_flags (info); + camel_folder_free_message_info (expunging, info); + } + + /* Only interested in deleted messages. */ + if ((flags & CAMEL_MESSAGE_DELETED) == 0) + continue; + + /* because the UID in the local store doesn't + * match with the UID in the pop3 store */ + message = camel_folder_get_message_sync ( + expunging, uids->pdata[ii], cancellable, NULL); + + if (message == NULL) + continue; + + pop3_uid = camel_medium_get_header ( + CAMEL_MEDIUM (message), "X-Evolution-POP3-UID"); + source_uid = camel_mime_message_get_source (message); + + if (pop3_uid != NULL) + g_hash_table_insert ( + expunging_uids, + g_strstrip (g_strdup (pop3_uid)), + g_strstrip (g_strdup (source_uid))); + + g_object_unref (message); + } + + camel_folder_free_uids (expunging, uids); + uids = NULL; + + if (g_hash_table_size (expunging_uids) == 0) { + g_hash_table_destroy (expunging_uids); + return TRUE; + } + + for (iter = e_list_get_iterator ((EList *) e_get_account_list ()); + e_iterator_is_valid (iter); e_iterator_next (iter)) { + account = (EAccount *) e_iterator_get (iter); + + if (account->enabled && + account->source && account->source->url && + g_str_has_prefix (account->source->url, "pop://")) { + CamelFolder *folder; + CamelService *service; + CamelSettings *settings; + gboolean any_found = FALSE; + gboolean delete_expunged = FALSE; + gboolean keep_on_server = FALSE; + + service = camel_session_get_service (session, account->uid); + + if (!CAMEL_IS_STORE (service)) + continue; + + settings = camel_service_get_settings (service); + if (!settings) + continue; + + g_object_get ( + settings, + "delete-expunged", &delete_expunged, + "keep-on-server", &keep_on_server, + NULL); + + if (!keep_on_server || !delete_expunged) + continue; + + folder = e_mail_session_get_inbox_sync ( + E_MAIL_SESSION (session), + account->uid, cancellable, error); + + /* Abort the loop on error. */ + if (folder == NULL) { + success = FALSE; + break; + } + + uids = camel_folder_get_uids (folder); + if (uids) { + for (ii = 0; ii < uids->len; ii++) { + /* ensure the ID is from this account, + * as it's generated by evolution */ + const gchar *source_uid; + + source_uid = g_hash_table_lookup ( + expunging_uids, uids->pdata[ii]); + if (folder_is_from_source_uid (folder, source_uid)) { + any_found = TRUE; + camel_folder_delete_message (folder, uids->pdata[ii]); + } + } + camel_folder_free_uids (folder, uids); + } + + if (any_found) + success = camel_folder_synchronize_sync (folder, TRUE, cancellable, error); + + g_object_unref (folder); + + /* Abort the loop on error. */ + if (!success) + break; + } + } + + if (iter) + g_object_unref (iter); + + g_hash_table_destroy (expunging_uids); + + return success; +} + +static gchar * +expunge_folder_desc (struct _sync_folder_msg *m) +{ + return g_strdup_printf ( + _("Expunging folder '%s'"), + camel_folder_get_full_name (m->folder)); +} + +static void +expunge_folder_exec (struct _sync_folder_msg *m, + GCancellable *cancellable, + GError **error) +{ + CamelFolder *local_inbox; + CamelStore *parent_store; + CamelService *service; + CamelSession *session; + gboolean is_local_inbox_or_trash; + gboolean store_is_local; + gboolean success = TRUE; + const gchar *uid; + + parent_store = camel_folder_get_parent_store (m->folder); + + service = CAMEL_SERVICE (parent_store); + session = camel_service_get_session (service); + + uid = camel_service_get_uid (service); + store_is_local = (g_strcmp0 (uid, E_MAIL_SESSION_LOCAL_UID) == 0); + + local_inbox = + e_mail_session_get_local_folder ( + E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_INBOX); + is_local_inbox_or_trash = (m->folder == local_inbox); + + if (store_is_local && !is_local_inbox_or_trash) { + CamelFolder *trash; + + trash = camel_store_get_trash_folder_sync ( + parent_store, cancellable, error); + + if (trash == NULL) + return; + + is_local_inbox_or_trash = (m->folder == trash); + + g_object_unref (trash); + } + + /* do this before expunge, to know which messages will be expunged */ + if (is_local_inbox_or_trash) + success = expunge_pop3_stores (m->folder, cancellable, error); + + if (success) + camel_folder_expunge_sync (m->folder, cancellable, error); +} + +/* we just use the sync stuff where we can, since it would be the same */ +static MailMsgInfo expunge_folder_info = { + sizeof (struct _sync_folder_msg), + (MailMsgDescFunc) expunge_folder_desc, + (MailMsgExecFunc) expunge_folder_exec, + (MailMsgDoneFunc) sync_folder_done, + (MailMsgFreeFunc) sync_folder_free +}; + +void +mail_expunge_folder (CamelFolder *folder) +{ + struct _sync_folder_msg *m; + + g_return_if_fail (CAMEL_IS_FOLDER (folder)); + + m = mail_msg_new (&expunge_folder_info); + m->folder = g_object_ref (folder); + + mail_msg_slow_ordered_push (m); +} + +/* ******************************************************************************** */ + +struct _empty_trash_msg { + MailMsg base; + + CamelStore *store; +}; + +static gchar * +empty_trash_desc (struct _empty_trash_msg *m) +{ + CamelService *service; + const gchar *display_name; + + service = CAMEL_SERVICE (m->store); + display_name = camel_service_get_display_name (service); + + return g_strdup_printf ( + _("Emptying trash in '%s'"), display_name); +} + +static void +empty_trash_exec (struct _empty_trash_msg *m, + GCancellable *cancellable, + GError **error) +{ + CamelService *service; + CamelFolder *trash; + const gchar *uid; + gboolean success = TRUE; + + service = CAMEL_SERVICE (m->store); + uid = camel_service_get_uid (service); + + if (!em_utils_connect_service_sync (service, cancellable, error)) + return; + + trash = camel_store_get_trash_folder_sync ( + m->store, cancellable, error); + + if (trash == NULL) + return; + + /* do this before expunge, to know which messages will be expunged */ + if (g_strcmp0 (uid, E_MAIL_SESSION_LOCAL_UID) == 0) + success = expunge_pop3_stores (trash, cancellable, error); + + if (success) + camel_folder_expunge_sync (trash, cancellable, error); + + g_object_unref (trash); +} + +static void +empty_trash_done (struct _empty_trash_msg *m) +{ +} + +static void +empty_trash_free (struct _empty_trash_msg *m) +{ + if (m->store) + g_object_unref (m->store); +} + +static MailMsgInfo empty_trash_info = { + sizeof (struct _empty_trash_msg), + (MailMsgDescFunc) empty_trash_desc, + (MailMsgExecFunc) empty_trash_exec, + (MailMsgDoneFunc) empty_trash_done, + (MailMsgFreeFunc) empty_trash_free +}; + +void +mail_empty_trash (CamelStore *store) +{ + struct _empty_trash_msg *m; + + g_return_if_fail (CAMEL_IS_STORE (store)); + + m = mail_msg_new (&empty_trash_info); + m->store = g_object_ref (store); + + mail_msg_slow_ordered_push (m); +} + +/* ** Execute Shell Command ************************************************ */ + +void +mail_execute_shell_command (CamelFilterDriver *driver, + gint argc, + gchar **argv, + gpointer data) +{ + if (argc <= 0) + return; + + g_spawn_async (NULL, argv, NULL, 0, NULL, data, NULL, NULL); +} + +/* ------------------------------------------------------------------------- */ + +struct _disconnect_msg { + MailMsg base; + + CamelStore *store; +}; + +static gchar * +disconnect_service_desc (struct _disconnect_msg *m) +{ + gchar *name, *res; + + name = camel_service_get_name (CAMEL_SERVICE (m->store), TRUE); + res = g_strdup_printf (_("Disconnecting %s"), name ? name : ""); + g_free (name); + + return res; +} + +static void +disconnect_service_exec (struct _disconnect_msg *m, + GCancellable *cancellable, + GError **error) +{ + em_utils_disconnect_service_sync ( + CAMEL_SERVICE (m->store), TRUE, cancellable, error); +} + +static void +disconnect_service_free (struct _disconnect_msg *m) +{ + g_object_unref (m->store); +} + +static MailMsgInfo disconnect_service_info = { + sizeof (struct _disconnect_msg), + (MailMsgDescFunc) disconnect_service_desc, + (MailMsgExecFunc) disconnect_service_exec, + (MailMsgDoneFunc) NULL, + (MailMsgFreeFunc) disconnect_service_free +}; + +gint +mail_disconnect_store (CamelStore *store) +{ + struct _disconnect_msg *m; + gint id; + + g_return_val_if_fail (store != NULL, -1); + + m = mail_msg_new (&disconnect_service_info); + m->store = g_object_ref (store); + + id = m->base.seq; + mail_msg_unordered_push (m); + + return id; +} diff --git a/libemail-engine/mail-ops.h b/libemail-engine/mail-ops.h new file mode 100644 index 0000000000..236dd2325f --- /dev/null +++ b/libemail-engine/mail-ops.h @@ -0,0 +1,98 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + * + * Authors: + * Peter Williams + * Michael Zucchi + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef MAIL_OPS_H +#define MAIL_OPS_H + +G_BEGIN_DECLS + +#include +#include +#include + +void mail_transfer_messages (EMailSession *session, + CamelFolder *source, + GPtrArray *uids, + gboolean delete_from_source, + const gchar *dest_uri, + guint32 dest_flags, + void (*done) (gboolean ok, gpointer data), + gpointer data); + +void mail_sync_folder (CamelFolder *folder, + void (*done) (CamelFolder *folder, gpointer data), gpointer data); + +void mail_sync_store (CamelStore *store, gint expunge, + void (*done) (CamelStore *store, gpointer data), gpointer data); + +void mail_refresh_folder (CamelFolder *folder, + void (*done) (CamelFolder *folder, gpointer data), + gpointer data); + +void mail_expunge_folder (CamelFolder *folder); +void mail_empty_trash (CamelStore *store); + +/* transfer (copy/move) a folder */ +void mail_xfer_folder (const gchar *src_uri, const gchar *dest_uri, gboolean remove_source, + void (*done) (gchar *src_uri, gchar *dest_uri, gboolean remove_source, + CamelFolder *folder, gpointer data), + gpointer data); + +/* yeah so this is messy, but it does a lot, maybe i can consolidate all user_data's to be the one */ +void mail_send_queue (EMailSession *session, + CamelFolder *queue, + CamelTransport *transport, + const gchar *type, + GCancellable *cancellable, + CamelFilterGetFolderFunc get_folder, + gpointer get_data, + CamelFilterStatusFunc *status, + gpointer status_data, + void (*done)(gpointer data), + gpointer data); + +void mail_fetch_mail (CamelStore *store, + gint keep, + const gchar *type, + GCancellable *cancellable, + CamelFilterGetFolderFunc get_folder, + gpointer get_data, + CamelFilterStatusFunc *status, + gpointer status_data, + void (*done)(gpointer data), + gpointer data); + +void mail_filter_folder (EMailSession *session, + CamelFolder *source_folder, + GPtrArray *uids, + const gchar *type, + gboolean notify); + +/* filter driver execute shell command async callback */ +void mail_execute_shell_command (CamelFilterDriver *driver, gint argc, gchar **argv, gpointer data); + +gint mail_disconnect_store (CamelStore *store); + +G_END_DECLS + +#endif /* MAIL_OPS_H */ diff --git a/libemail-engine/mail-tools.c b/libemail-engine/mail-tools.c new file mode 100644 index 0000000000..82b2146b92 --- /dev/null +++ b/libemail-engine/mail-tools.c @@ -0,0 +1,244 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + * + * Authors: + * Dan Winship + * Peter Williams + * Jeffrey Stedfast + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "e-mail-session.h" +#include "mail-folder-cache.h" +#include "mail-tools.h" + +/* **************************************** */ + +#ifndef G_OS_WIN32 + +static gchar * +mail_tool_get_local_movemail_path (CamelStore *store, + GError **error) +{ + const gchar *uid; + guchar *safe_uid, *c; + const gchar *data_dir; + gchar *path, *full; + struct stat st; + + uid = camel_service_get_uid (CAMEL_SERVICE (store)); + safe_uid = (guchar *) g_strdup ((const gchar *) uid); + for (c = safe_uid; *c; c++) + if (strchr("/:;=|%&#!*^()\\, ", *c) || !isprint((gint) *c)) + *c = '_'; + + data_dir = mail_session_get_data_dir (); + path = g_build_filename (data_dir, "spool", NULL); + + if (g_stat (path, &st) == -1 && g_mkdir_with_parents (path, 0700) == -1) { + g_set_error ( + error, G_FILE_ERROR, + g_file_error_from_errno (errno), + _("Could not create spool directory '%s': %s"), + path, g_strerror (errno)); + g_free (path); + return NULL; + } + + full = g_strdup_printf("%s/movemail.%s", path, safe_uid); + g_free (path); + g_free (safe_uid); + + return full; +} + +#endif + +gchar * +mail_tool_do_movemail (CamelStore *store, + GError **error) +{ +#ifndef G_OS_WIN32 + CamelService *service; + CamelProvider *provider; + CamelSettings *settings; + const gchar *src_path; + gchar *dest_path; + struct stat sb; + gboolean success; + + g_return_val_if_fail (CAMEL_IS_STORE (store), NULL); + + service = CAMEL_SERVICE (store); + provider = camel_service_get_provider (service); + settings = camel_service_get_settings (service); + + g_return_val_if_fail (provider != NULL, NULL); + + if (g_strcmp0 (provider->protocol, "mbox") != 0) { + /* This is really only an internal error anyway */ + g_set_error ( + error, CAMEL_SERVICE_ERROR, + CAMEL_SERVICE_ERROR_URL_INVALID, + _("Trying to movemail a non-mbox source '%s'"), + camel_service_get_uid (CAMEL_SERVICE (store))); + return NULL; + } + + src_path = camel_local_settings_get_path ( + CAMEL_LOCAL_SETTINGS (settings)); + + /* Set up our destination. */ + dest_path = mail_tool_get_local_movemail_path (store, error); + if (dest_path == NULL) + return NULL; + + /* Movemail from source to dest_path */ + success = camel_movemail (src_path, dest_path, error) != -1; + + if (g_stat (dest_path, &sb) < 0 || sb.st_size == 0) { + g_unlink (dest_path); /* Clean up the movemail.foo file. */ + g_free (dest_path); + return NULL; + } + + if (!success) { + g_free (dest_path); + return NULL; + } + + return dest_path; +#else + /* Unclear yet whether camel-movemail etc makes any sense on + * Win32, at least it is not ported yet. + */ + g_warning("%s: Not implemented", __FUNCTION__); + return NULL; +#endif +} + +gchar * +mail_tool_generate_forward_subject (CamelMimeMessage *msg) +{ + const gchar *subject; + gchar *fwd_subj; + const gint max_subject_length = 1024; + + subject = camel_mime_message_get_subject (msg); + + if (subject && *subject) { + /* Truncate insanely long subjects */ + if (strlen (subject) < max_subject_length) { + fwd_subj = g_strdup_printf ("[Fwd: %s]", subject); + } else { + /* We can't use %.*s because it depends on the + * locale being C/POSIX or UTF-8 to work correctly + * in glibc. */ + fwd_subj = g_malloc (max_subject_length + 11); + memcpy (fwd_subj, "[Fwd: ", 6); + memcpy (fwd_subj + 6, subject, max_subject_length); + memcpy (fwd_subj + 6 + max_subject_length, "...]", 5); + } + } else { + const CamelInternetAddress *from; + gchar *fromstr; + + from = camel_mime_message_get_from (msg); + if (from) { + fromstr = camel_address_format (CAMEL_ADDRESS (from)); + fwd_subj = g_strdup_printf ("[Fwd: %s]", fromstr); + g_free (fromstr); + } else + fwd_subj = g_strdup ("[Fwd: No Subject]"); + } + + return fwd_subj; +} + +struct _camel_header_raw * +mail_tool_remove_xevolution_headers (CamelMimeMessage *message) +{ + struct _camel_header_raw *scan, *list = NULL; + + for (scan = ((CamelMimePart *) message)->headers; scan; scan = scan->next) + if (!strncmp(scan->name, "X-Evolution", 11)) + camel_header_raw_append (&list, scan->name, scan->value, scan->offset); + + for (scan = list; scan; scan = scan->next) + camel_medium_remove_header ((CamelMedium *) message, scan->name); + + return list; +} + +void +mail_tool_restore_xevolution_headers (CamelMimeMessage *message, + struct _camel_header_raw *xev) +{ + CamelMedium *medium; + + medium = CAMEL_MEDIUM (message); + + for (; xev; xev = xev->next) + camel_medium_add_header (medium, xev->name, xev->value); +} + +CamelMimePart * +mail_tool_make_message_attachment (CamelMimeMessage *message) +{ + CamelMimePart *part; + const gchar *subject; + struct _camel_header_raw *xev; + gchar *desc; + + subject = camel_mime_message_get_subject (message); + if (subject) + desc = g_strdup_printf (_("Forwarded message - %s"), subject); + else + desc = g_strdup (_("Forwarded message")); + + /* rip off the X-Evolution headers */ + xev = mail_tool_remove_xevolution_headers (message); + camel_header_raw_clear (&xev); + + /* remove Bcc headers */ + camel_medium_remove_header (CAMEL_MEDIUM (message), "Bcc"); + + part = camel_mime_part_new (); + camel_mime_part_set_disposition (part, "inline"); + camel_mime_part_set_description (part, desc); + camel_medium_set_content ( + CAMEL_MEDIUM (part), CAMEL_DATA_WRAPPER (message)); + camel_mime_part_set_content_type (part, "message/rfc822"); + g_free (desc); + + return part; +} diff --git a/libemail-engine/mail-tools.h b/libemail-engine/mail-tools.h new file mode 100644 index 0000000000..94b19c0d12 --- /dev/null +++ b/libemail-engine/mail-tools.h @@ -0,0 +1,41 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + * + * Authors: + * Peter Williams + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef MAIL_TOOLS_H +#define MAIL_TOOLS_H + +#include + +/* Does a camel_movemail into the local movemail folder + * and returns the path to the new movemail folder that was created. which shoudl be freed later */ +gchar *mail_tool_do_movemail (CamelStore *store, GError **error); + +struct _camel_header_raw *mail_tool_remove_xevolution_headers (CamelMimeMessage *message); +void mail_tool_restore_xevolution_headers (CamelMimeMessage *message, struct _camel_header_raw *); + +/* Generates the subject for a message forwarding @msg */ +gchar *mail_tool_generate_forward_subject (CamelMimeMessage *msg); + +/* Make a message into an attachment */ +CamelMimePart *mail_tool_make_message_attachment (CamelMimeMessage *message); + +#endif diff --git a/libemail-utils/Makefile.am b/libemail-utils/Makefile.am new file mode 100644 index 0000000000..a2aea9aa93 --- /dev/null +++ b/libemail-utils/Makefile.am @@ -0,0 +1,44 @@ +NULL = + +lib_LTLIBRARIES = libemail-utils.la + +libemail_utils_la_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -I$(top_srcdir) \ + -I$(top_builddir) \ + -DEVOLUTION_PRIVDATADIR=\""$(privdatadir)"\" \ + $(EVOLUTION_DATA_SERVER_CFLAGS) \ + $(GNOME_PLATFORM_CFLAGS) \ + $(NULL) + +libmailutilsincludedir = $(privincludedir)/libemail-utils +libmailutilsinclude_HEADERS = \ + e-account-utils.h \ + e-signature-list.h \ + e-signature-utils.h \ + e-signature.h \ + mail-mt.h \ + $(NULL) + +libemail_utils_la_SOURCES = \ + $(libmailutilsinclude_HEADERS) \ + e-account-utils.c \ + e-signature-list.c \ + e-signature-utils.c \ + e-signature.c \ + mail-mt.c \ + $(NULL) + +libemail_utils_la_LDFLAGS = $(NO_UNDEFINED) + +libemail_utils_la_LIBADD = \ + $(EVOLUTION_DATA_SERVER_LIBS) \ + $(GNOME_PLATFORM_LIBS) \ + $(NULL) + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libemail-utils.pc + +DISTCLEANFILES = $(pkgconfig_DATA) + +-include $(top_srcdir)/git.mk diff --git a/libemail-utils/e-account-utils.c b/libemail-utils/e-account-utils.c new file mode 100644 index 0000000000..6e64d45747 --- /dev/null +++ b/libemail-utils/e-account-utils.c @@ -0,0 +1,252 @@ +/* + * 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 + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + */ + +/** + * SECTION: e-account-utils + * @include: e-util/e-account-utils.h + **/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "e-account-utils.h" + +#include +#include + +static EAccountList *global_account_list; + +static gboolean +account_has_transport_url (EAccount *account) +{ + return (account != NULL) && + (account->enabled) && + (account->transport != NULL) && + (account->transport->url != NULL) && + (account->transport->url[0] != '\0'); +} + +/** + * e_get_account_list: + * + * Returns the global #EAccountList. + * + * Returns: the global #EAccountList + **/ +EAccountList * +e_get_account_list (void) +{ + if (G_UNLIKELY (global_account_list == NULL)) { + GConfClient *client; + + client = gconf_client_get_default (); + global_account_list = e_account_list_new (client); + g_object_unref (client); + } + + g_return_val_if_fail (global_account_list != NULL, NULL); + + return global_account_list; +} + +/** + * e_get_default_account: + * + * Returns the #EAccount marked as the default mail account. + * + * Returns: the default #EAccount + **/ +EAccount * +e_get_default_account (void) +{ + EAccountList *account_list; + const EAccount *account; + + account_list = e_get_account_list (); + account = e_account_list_get_default (account_list); + + /* XXX EAccountList misuses const. */ + return (EAccount *) account; +} + +/** + * e_set_default_account: + * @account: an #EAccount + * + * Marks @account as the default mail account. + **/ +void +e_set_default_account (EAccount *account) +{ + EAccountList *account_list; + + g_return_if_fail (E_IS_ACCOUNT (account)); + + account_list = e_get_account_list (); + e_account_list_set_default (account_list, account); +} + +/** + * e_get_account_by_name: + * @name: a mail account name + * + * Returns the #EAccount with the given name, or %NULL if no such + * account exists. + * + * Returns: an #EAccount having the given account name, or %NULL + **/ +EAccount * +e_get_account_by_name (const gchar *name) +{ + EAccountList *account_list; + const EAccount *account; + e_account_find_t find; + + g_return_val_if_fail (name != NULL, NULL); + + find = E_ACCOUNT_FIND_NAME; + account_list = e_get_account_list (); + account = e_account_list_find (account_list, find, name); + + /* XXX EAccountList misuses const. */ + return (EAccount *) account; +} + +/** + * e_get_account_by_uid: + * @uid: a mail account UID + * + * Returns the #EAccount corresponding to the given unique identity (UID), + * or %NULL if no such account exists. The @uid can refer to an #EAccount + * UID, a #CamelStore UID, or even a #CamelTransport UID. + * + * Returns: the corresponding #EAccount, or %NULL + **/ +EAccount * +e_get_account_by_uid (const gchar *uid) +{ + EAccountList *account_list; + const EAccount *account; + e_account_find_t find; + gchar *account_uid; + + g_return_val_if_fail (uid != NULL, NULL); + + /* EAccounts have the following invariant: + * + * CamelStore UID == EAccount UID + * CamelTransport UID == EAccount UID + "-transport" + * + * Therefore we can detect CamelTransport UIDs and convert them. + */ + if (g_str_has_suffix (uid, "-transport")) + account_uid = g_strndup (uid, strlen (uid) - 10); + else + account_uid = g_strdup (uid); + + find = E_ACCOUNT_FIND_UID; + account_list = e_get_account_list (); + account = e_account_list_find (account_list, find, account_uid); + + g_free (account_uid); + + /* XXX EAccountList misuses const. */ + return (EAccount *) account; +} + +/** + * e_get_any_enabled_account: + * + * Returns the default mail account if it's enabled, otherwise the first + * enabled mail account in the global #EAccountList, or finally %NULL if + * all mail accounts are disabled or none exist. + * + * Returns: an enabled #EAccount, or %NULL if there are none + **/ +EAccount * +e_get_any_enabled_account (void) +{ + EAccount *account; + EAccountList *account_list; + EIterator *iter; + + account = e_get_default_account (); + if (account != NULL && account->enabled) + return account; + + account = NULL; + + account_list = e_get_account_list (); + iter = e_list_get_iterator (E_LIST (account_list)); + + while (e_iterator_is_valid (iter) && account == NULL) { + EAccount *candidate; + + /* XXX EIterator misuses const. */ + candidate = (EAccount *) e_iterator_get (iter); + + if (candidate->enabled) + account = candidate; + else + e_iterator_next (iter); + } + + g_object_unref (iter); + + return account; +} + +/** + * e_get_default_transport: + * + * Returns transport information for the default account if it's enabled and + * has transport information, or else from the first enabled mail account in + * the global #EAccountList that has transport information, or finally %NULL + * if no transport information could be found. + * + * Returns: an #EAccount with transport info, or %NULL + **/ +EAccount * +e_get_default_transport (void) +{ + EAccountList *account_list; + EAccount *account; + EIterator *iterator; + + account = e_get_default_account (); + if (account_has_transport_url (account)) + return account; + + account_list = e_get_account_list (); + iterator = e_list_get_iterator (E_LIST (account_list)); + + while (e_iterator_is_valid (iterator)) { + /* XXX EIterator misuses const. */ + account = (EAccount *) e_iterator_get (iterator); + if (account_has_transport_url (account)) { + g_object_unref (iterator); + return account; + } + e_iterator_next (iterator); + } + + g_object_unref (iterator); + + return NULL; +} + diff --git a/libemail-utils/e-account-utils.h b/libemail-utils/e-account-utils.h new file mode 100644 index 0000000000..d7dbd283fd --- /dev/null +++ b/libemail-utils/e-account-utils.h @@ -0,0 +1,37 @@ +/* + * 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 + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + */ + +#ifndef E_ACCOUNT_UTILS_H +#define E_ACCOUNT_UTILS_H + +#include +#include +#include + +G_BEGIN_DECLS + +EAccountList * e_get_account_list (void); +EAccount * e_get_default_account (void); +void e_set_default_account (EAccount *account); +EAccount * e_get_account_by_name (const gchar *name); +EAccount * e_get_account_by_uid (const gchar *uid); +EAccount * e_get_any_enabled_account (void); +EAccount * e_get_default_transport (void); + +G_END_DECLS + +#endif /* E_ACCOUNT_UTILS_H */ diff --git a/libemail-utils/e-signature-list.c b/libemail-utils/e-signature-list.c new file mode 100644 index 0000000000..afc1d9eefd --- /dev/null +++ b/libemail-utils/e-signature-list.c @@ -0,0 +1,498 @@ +/* + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + * + * Authors: + * Jeffrey Stedfast + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "e-signature-list.h" + +#include + +#include + +struct _ESignatureListPrivate { + GConfClient *gconf; + guint notify_id; + gboolean resave; +}; + +enum { + SIGNATURE_ADDED, + SIGNATURE_CHANGED, + SIGNATURE_REMOVED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +G_DEFINE_TYPE ( + ESignatureList, + e_signature_list, + E_TYPE_LIST) + +static void +e_signature_list_dispose (GObject *object) +{ + ESignatureList *list = (ESignatureList *) object; + + if (list->priv->gconf) { + if (list->priv->notify_id != 0) + gconf_client_notify_remove ( + list->priv->gconf, list->priv->notify_id); + g_object_unref (list->priv->gconf); + list->priv->gconf = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (e_signature_list_parent_class)->dispose (object); +} + +static void +e_signature_list_class_init (ESignatureListClass *class) +{ + GObjectClass *object_class; + + g_type_class_add_private (class, sizeof (ESignatureListPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->dispose = e_signature_list_dispose; + + signals[SIGNATURE_ADDED] = g_signal_new ( + "signature-added", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ESignatureListClass, signature_added), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + E_TYPE_SIGNATURE); + + signals[SIGNATURE_CHANGED] = g_signal_new ( + "signature-changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ESignatureListClass, signature_changed), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + E_TYPE_SIGNATURE); + + signals[SIGNATURE_REMOVED] = g_signal_new ( + "signature-removed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ESignatureListClass, signature_removed), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + E_TYPE_SIGNATURE); +} + +static void +e_signature_list_init (ESignatureList *signature_list) +{ + signature_list->priv = G_TYPE_INSTANCE_GET_PRIVATE ( + signature_list, E_TYPE_SIGNATURE_LIST, ESignatureListPrivate); +} + +static GSList * +add_autogen (ESignatureList *list, + GSList *new_sigs) +{ + ESignature *autogen; + + autogen = e_signature_new (); + e_signature_set_autogenerated (autogen, TRUE); + + e_list_append (E_LIST (list), autogen); + + return g_slist_prepend (new_sigs, autogen); +} + +static void +gconf_signatures_changed (GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + gpointer user_data) +{ + ESignatureList *signature_list = user_data; + GSList *list, *l, *n, *new_sigs = NULL; + gboolean have_autogen = FALSE; + gboolean resave = FALSE; + ESignature *signature; + EList *old_sigs; + EIterator *iter; + gboolean found; + gchar *uid; + + old_sigs = e_list_duplicate (E_LIST (signature_list)); + + list = gconf_client_get_list ( + client, "/apps/evolution/mail/signatures", + GCONF_VALUE_STRING, NULL); + for (l = list; l; l = l->next) { + found = FALSE; + if ((uid = e_signature_uid_from_xml (l->data))) { + /* See if this is an existing signature */ + iter = e_list_get_iterator (old_sigs); + while (e_iterator_is_valid (iter)) { + const gchar *signature_uid; + + signature = (ESignature *) e_iterator_get (iter); + signature_uid = e_signature_get_uid (signature); + if (!strcmp (signature_uid, uid)) { + /* The signature still exists, so remove + * it from "old_sigs" and update it. */ + found = TRUE; + e_iterator_delete (iter); + if (e_signature_set_from_xml ( + signature, l->data)) + g_signal_emit ( + signature_list, + signals[SIGNATURE_CHANGED], + 0, signature); + + have_autogen |= + e_signature_get_autogenerated ( + signature); + + break; + } + + e_iterator_next (iter); + } + + g_object_unref (iter); + } + + if (!found) { + resave = TRUE; + + /* Must be a new signature */ + signature = e_signature_new_from_xml (l->data); + if (signature) { + have_autogen |= + e_signature_get_autogenerated (signature); + + e_list_append (E_LIST (signature_list), signature); + new_sigs = g_slist_prepend (new_sigs, signature); + } + } + + g_free (uid); + } + + g_slist_foreach (list, (GFunc) g_free, NULL); + g_slist_free (list); + + if (!have_autogen) { + new_sigs = add_autogen (signature_list, new_sigs); + resave = TRUE; + } + + if (new_sigs != NULL) { + /* Now emit signals for each added signature. */ + l = g_slist_reverse (new_sigs); + while (l != NULL) { + n = l->next; + signature = l->data; + g_signal_emit ( + signature_list, + signals[SIGNATURE_ADDED], 0, + signature); + g_object_unref (signature); + g_slist_free_1 (l); + l = n; + } + } + + /* Anything left in old_sigs must have been deleted */ + iter = e_list_get_iterator (old_sigs); + while (e_iterator_is_valid (iter)) { + signature = (ESignature *) e_iterator_get (iter); + e_list_remove (E_LIST (signature_list), signature); + g_signal_emit ( + signature_list, signals[SIGNATURE_REMOVED], 0, + signature); + e_iterator_next (iter); + } + + g_object_unref (iter); + g_object_unref (old_sigs); + + signature_list->priv->resave = resave; +} + +static gpointer +copy_func (gconstpointer data, + gpointer closure) +{ + GObject *object = (GObject *) data; + + g_object_ref (object); + + return object; +} + +static void +free_func (gpointer data, + gpointer closure) +{ + g_object_unref (data); +} + +/** + * e_signature_list_new: + * + * Reads the list of signaturess from @gconf and listens for changes. + * Will emit #signature_added, #signature_changed, and #signature_removed + * signals according to notifications from GConf. + * + * You can modify the list using e_list_append(), e_list_remove(), and + * e_iterator_delete(). After adding, removing, or changing accounts, + * you must call e_signature_list_save() to push the changes back to + * GConf. + * + * Return value: the list of signatures + **/ +ESignatureList * +e_signature_list_new (void) +{ + ESignatureList *signature_list; + GConfClient *client; + + signature_list = g_object_new (E_TYPE_SIGNATURE_LIST, NULL); + + client = gconf_client_get_default (); + e_signature_list_construct (signature_list, client); + g_object_unref (client); + + return signature_list; +} + +void +e_signature_list_construct (ESignatureList *signature_list, + GConfClient *gconf) +{ + g_return_if_fail (GCONF_IS_CLIENT (gconf)); + + e_list_construct (E_LIST (signature_list), copy_func, free_func, NULL); + signature_list->priv->gconf = gconf; + g_object_ref (gconf); + + gconf_client_add_dir (signature_list->priv->gconf, + "/apps/evolution/mail/signatures", + GCONF_CLIENT_PRELOAD_ONELEVEL, NULL); + + signature_list->priv->notify_id = + gconf_client_notify_add (signature_list->priv->gconf, + "/apps/evolution/mail/signatures", + gconf_signatures_changed, signature_list, + NULL, NULL); + + gconf_signatures_changed (signature_list->priv->gconf, + signature_list->priv->notify_id, + NULL, signature_list); + + if (signature_list->priv->resave) { + e_signature_list_save (signature_list); + signature_list->priv->resave = FALSE; + } +} + +/** + * e_signature_list_save: + * @signature_list: an #ESignatureList + * + * Saves @signature_list to GConf. Signals will be emitted for changes. + **/ +void +e_signature_list_save (ESignatureList *signature_list) +{ + GSList *list = NULL; + ESignature *signature; + EIterator *iter; + gchar *xmlbuf; + + for (iter = e_list_get_iterator (E_LIST (signature_list)); + e_iterator_is_valid (iter); + e_iterator_next (iter)) { + signature = (ESignature *) e_iterator_get (iter); + + if ((xmlbuf = e_signature_to_xml (signature))) + list = g_slist_append (list, xmlbuf); + } + + g_object_unref (iter); + + gconf_client_set_list (signature_list->priv->gconf, + "/apps/evolution/mail/signatures", + GCONF_VALUE_STRING, list, NULL); + + while (list) { + g_free (list->data); + list = g_slist_remove (list, list->data); + } + + gconf_client_suggest_sync (signature_list->priv->gconf, NULL); +} + +/** + * e_signature_list_add: + * @signature_list: signature list + * @signature: signature to add + * + * Add an signature to the signature list. Will emit the signature-changed + * event. + **/ +void +e_signature_list_add (ESignatureList *signature_list, + ESignature *signature) +{ + e_list_append ((EList *) signature_list, signature); + g_signal_emit (signature_list, signals[SIGNATURE_ADDED], 0, signature); +} + +/** + * e_signature_list_change: + * @signature_list: signature list + * @signature: signature to change + * + * Signal that the details of an signature have changed. + **/ +void +e_signature_list_change (ESignatureList *signature_list, + ESignature *signature) +{ + /* maybe the signature should do this itself ... */ + g_signal_emit (signature_list, signals[SIGNATURE_CHANGED], 0, signature); +} + +/** + * e_signature_list_remove: + * @signature_list: signature list + * @signature: signature + * + * Remove an signature from the signature list, and emit the + * signature-removed signal. If the signature was the default signature, + * then reset the default to the first signature. + **/ +void +e_signature_list_remove (ESignatureList *signature_list, + ESignature *signature) +{ + /* not sure if need to ref but no harm */ + g_object_ref (signature); + e_list_remove ((EList *) signature_list, signature); + g_signal_emit (signature_list, signals[SIGNATURE_REMOVED], 0, signature); + g_object_unref (signature); +} + +/** + * e_signature_list_find_by_name: + * @signature_list: an #ESignatureList + * @name: the signature name to find + * + * Searches @signature_list for the given signature name. + * + * Returns: the matching signature or %NULL if it doesn't exist + **/ +ESignature * +e_signature_list_find_by_name (ESignatureList *signature_list, + const gchar *signature_name) +{ + ESignature *signature = NULL; + EIterator *it; + + g_return_val_if_fail (E_IS_SIGNATURE_LIST (signature_list), NULL); + + /* this could use a callback for more flexibility ... + * ... but this makes the common cases easier */ + + if (signature_name == NULL) + return NULL; + + for (it = e_list_get_iterator (E_LIST (signature_list)); + e_iterator_is_valid (it); + e_iterator_next (it)) { + const gchar *value; + + /* XXX EIterator misuses const. */ + signature = (ESignature *) e_iterator_get (it); + value = e_signature_get_name (signature); + + if (g_strcmp0 (value, signature_name) == 0) + break; + + signature = NULL; + } + + g_object_unref (it); + + return signature; +} + +/** + * e_signature_list_find_by_uid: + * @signature_list: an #ESignatureList + * @name: the signature UID to find + * + * Searches @signature_list for the given signature UID. + * + * Returns: the matching signature or %NULL if it doesn't exist + **/ +ESignature * +e_signature_list_find_by_uid (ESignatureList *signature_list, + const gchar *signature_uid) +{ + ESignature *signature = NULL; + EIterator *it; + + g_return_val_if_fail (E_IS_SIGNATURE_LIST (signature_list), NULL); + + /* this could use a callback for more flexibility ... + * ... but this makes the common cases easier */ + + if (signature_uid == NULL) + return NULL; + + for (it = e_list_get_iterator (E_LIST (signature_list)); + e_iterator_is_valid (it); + e_iterator_next (it)) { + const gchar *value = NULL; + + /* XXX EIterator misuses const. */ + signature = (ESignature *) e_iterator_get (it); + value = e_signature_get_uid (signature); + + if (g_strcmp0 (value, signature_uid) == 0) + break; + + signature = NULL; + } + + g_object_unref (it); + + return signature; +} diff --git a/libemail-utils/e-signature-list.h b/libemail-utils/e-signature-list.h new file mode 100644 index 0000000000..ebcb4b28e2 --- /dev/null +++ b/libemail-utils/e-signature-list.h @@ -0,0 +1,91 @@ +/* + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + * + * Authors: + * Jeffrey Stedfast + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef E_SIGNATURE_LIST_H +#define E_SIGNATURE_LIST_H + +#include +#include +#include + +/* Standard GObject macros */ +#define E_TYPE_SIGNATURE_LIST \ + (e_signature_list_get_type ()) +#define E_SIGNATURE_LIST(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_SIGNATURE_LIST, ESignatureList)) +#define E_SIGNATURE_LIST_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_SIGNATURE_LIST, ESignatureListClass)) +#define E_IS_SIGNATURE_LIST(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_SIGNATURE_LIST)) +#define E_IS_SIGNATURE_LIST_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_SIGNATURE_LIST)) +#define E_SIGNATURE_LIST_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_SIGNATURE_LIST, ESignatureListClass)) + +G_BEGIN_DECLS + +typedef struct _ESignatureList ESignatureList; +typedef struct _ESignatureListClass ESignatureListClass; +typedef struct _ESignatureListPrivate ESignatureListPrivate; + +struct _ESignatureList { + EList parent; + ESignatureListPrivate *priv; +}; + +struct _ESignatureListClass { + EListClass parent_class; + + /* Signals */ + void (*signature_added) (ESignatureList *signature_list, + ESignature *signature); + void (*signature_changed) (ESignatureList *signature_list, + ESignature *signature); + void (*signature_removed) (ESignatureList *signature_list, + ESignature *signature); +}; + +GType e_signature_list_get_type (void); +ESignatureList *e_signature_list_new (void); +void e_signature_list_construct (ESignatureList *signature_list, + GConfClient *client); +void e_signature_list_save (ESignatureList *signature_list); +void e_signature_list_add (ESignatureList *signature_list, + ESignature *signature); +void e_signature_list_change (ESignatureList *signature_list, + ESignature *signature); +void e_signature_list_remove (ESignatureList *signature_list, + ESignature *signature); +ESignature * e_signature_list_find_by_name (ESignatureList *signature_list, + const gchar *signature_name); +ESignature * e_signature_list_find_by_uid (ESignatureList *signature_list, + const gchar *signature_uid); + +G_END_DECLS + +#endif /* E_SIGNATURE_LIST_H */ diff --git a/libemail-utils/e-signature-utils.c b/libemail-utils/e-signature-utils.c new file mode 100644 index 0000000000..ca46f053db --- /dev/null +++ b/libemail-utils/e-signature-utils.c @@ -0,0 +1,336 @@ +/* + * e-signature-utils.c + * + * 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 + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "e-signature-utils.h" + +#include +#include +#include + +#ifndef G_OS_WIN32 +#include +#endif + +#include + +static ESignatureList *global_signature_list; + +ESignatureList * +e_get_signature_list (void) +{ + if (G_UNLIKELY (global_signature_list == NULL)) + global_signature_list = e_signature_list_new (); + + g_return_val_if_fail (global_signature_list != NULL, NULL); + + return global_signature_list; +} + +ESignature * +e_get_signature_by_name (const gchar *name) +{ + ESignatureList *signature_list; + + g_return_val_if_fail (name != NULL, NULL); + + signature_list = e_get_signature_list (); + + return e_signature_list_find_by_name (signature_list, name); +} + +ESignature * +e_get_signature_by_uid (const gchar *uid) +{ + ESignatureList *signature_list; + + g_return_val_if_fail (uid != NULL, NULL); + + signature_list = e_get_signature_list (); + + return e_signature_list_find_by_uid (signature_list, uid); +} + +gchar * +e_create_signature_file (GError **error) +{ + const gchar *data_dir; + gchar basename[32]; + gchar *filename; + gchar *pathname; + gint32 ii; + + data_dir = e_get_user_data_dir (); + pathname = g_build_filename (data_dir, "signatures", NULL); + filename = NULL; + + if (g_mkdir_with_parents (pathname, 0700) < 0) { + g_set_error ( + error, G_FILE_ERROR, + g_file_error_from_errno (errno), + "%s: %s", pathname, g_strerror (errno)); + g_free (pathname); + return NULL; + } + + for (ii = 0; ii < G_MAXINT32; ii++) { + + g_snprintf ( + basename, sizeof (basename), + "signature-%" G_GINT32_FORMAT, ii); + + g_free (filename); + filename = g_build_filename (pathname, basename, NULL); + + if (!g_file_test (filename, G_FILE_TEST_EXISTS)) { + gint fd; + + fd = g_creat (filename, 0600); + if (fd >= 0) { + close (fd); + break; + } + + /* If we failed once we're probably going + * to continue failing, so just give up. */ + g_set_error ( + error, G_FILE_ERROR, + g_file_error_from_errno (errno), + "%s: %s", filename, g_strerror (errno)); + g_free (filename); + filename = NULL; + break; + } + } + + /* If there are actually G_MAXINT32 signature files, the + * most recent signature file we be overwritten. Sorry. */ + + return filename; +} + +gchar * +e_read_signature_file (ESignature *signature, + gboolean convert_to_html, + GError **error) +{ + CamelStream *input_stream; + CamelStream *output_stream; + GByteArray *buffer; + const gchar *filename; + gboolean is_html; + gchar *content; + gsize length; + gint fd; + + g_return_val_if_fail (E_IS_SIGNATURE (signature), NULL); + + filename = e_signature_get_filename (signature); + is_html = e_signature_get_is_html (signature); + + fd = g_open (filename, O_RDONLY, 0); + if (fd < 0) { + g_set_error ( + error, G_FILE_ERROR, + g_file_error_from_errno (errno), + "%s: %s", filename, g_strerror (errno)); + return NULL; + } + + input_stream = camel_stream_fs_new_with_fd (fd); + + if (!is_html && convert_to_html) { + CamelStream *filtered_stream; + CamelMimeFilter *filter; + gint32 flags; + + filtered_stream = + camel_stream_filter_new (input_stream); + g_object_unref (input_stream); + + flags = + CAMEL_MIME_FILTER_TOHTML_PRESERVE_8BIT | + CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS | + CAMEL_MIME_FILTER_TOHTML_CONVERT_ADDRESSES | + CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES; + filter = camel_mime_filter_tohtml_new (flags, 0); + camel_stream_filter_add ( + CAMEL_STREAM_FILTER (filtered_stream), filter); + g_object_unref (filter); + + input_stream = filtered_stream; + } + + buffer = g_byte_array_new (); + output_stream = camel_stream_mem_new (); + camel_stream_mem_set_byte_array ( + CAMEL_STREAM_MEM (output_stream), buffer); + camel_stream_write_to_stream (input_stream, output_stream, NULL, NULL); + g_object_unref (output_stream); + g_object_unref (input_stream); + + /* Make sure the buffer is nul-terminated. */ + length = (gsize) buffer->len; + g_byte_array_append (buffer, (guint8 *) "", 1); + content = (gchar *) g_byte_array_free (buffer, FALSE); + + /* Signatures are saved as UTF-8, but we still need to check that + * the signature is valid UTF-8 because the user may be opening + * a signature file that is in his/her locale character set. If + * it's not in UTF-8 then try converting from the current locale. */ + if (!g_utf8_validate (content, length, NULL)) { + gchar *utf8; + + utf8 = g_locale_to_utf8 (content, length, NULL, NULL, error); + g_free (content); + content = utf8; + } + + return content; +} + +gchar * +e_run_signature_script (const gchar *filename) +{ + /* FIXME Make this cross-platform, prefer GLib functions over + * POSIX, and report errors via GError instead of dumping + * messages to the terminal where users won't see them. */ + +#ifndef G_OS_WIN32 + gint in_fds[2]; + pid_t pid; + + g_return_val_if_fail (filename != NULL, NULL); + + if (pipe (in_fds) == -1) { + g_warning ( + "Failed to create pipe to '%s': %s", + filename, g_strerror (errno)); + return NULL; + } + + pid = fork (); + + /* Child Process */ + if (pid == 0) { + gint maxfd, ii; + + close (in_fds[0]); + if (dup2 (in_fds[1], STDOUT_FILENO) < 0) + _exit (255); + close (in_fds[1]); + + setsid (); + + maxfd = sysconf (_SC_OPEN_MAX); + for (ii = 3; ii < maxfd; ii++) { + if (ii == STDIN_FILENO) + continue; + if (ii == STDOUT_FILENO) + continue; + if (ii == STDERR_FILENO) + continue; + fcntl (ii, F_SETFD, FD_CLOEXEC); + } + + execlp ("/bin/sh", "/bin/sh", "-c", filename, NULL); + + g_warning ( + "Could not execute '%s': %s", + filename, g_strerror (errno)); + + _exit (255); + + /* Parent Process */ + } else if (pid > 0) { + CamelStream *output_stream; + CamelStream *input_stream; + GByteArray *buffer; + gchar *content; + gsize length; + gint result; + gint status; + + close (in_fds[1]); + + buffer = g_byte_array_new (); + output_stream = camel_stream_mem_new (); + camel_stream_mem_set_byte_array ( + CAMEL_STREAM_MEM (output_stream), buffer); + + input_stream = camel_stream_fs_new_with_fd (in_fds[0]); + camel_stream_write_to_stream ( + input_stream, output_stream, NULL, NULL); + g_object_unref (input_stream); + + g_object_unref (output_stream); + + /* Make sure the buffer is nul-terminated. */ + length = (gsize) buffer->len; + g_byte_array_append (buffer, (guchar *) "", 1); + content = (gchar *) g_byte_array_free (buffer, FALSE); + + /* Signature scripts are supposed to generate UTF-8 content, + * but because users are known to never read the manual, we + * try to do our best if the content isn't valid UTF-8 by + * assuming that the content is in the user's locale + * character set. */ + if (!g_utf8_validate (content, length, NULL)) { + gchar *utf8; + + /* XXX Should pass a GError here. */ + utf8 = g_locale_to_utf8 ( + content, length, NULL, NULL, NULL); + g_free (content); + content = utf8; + } + + /* Wait for the script process to terminate. */ + result = waitpid (pid, &status, 0); + + if (result == -1 && errno == EINTR) { + /* Child process is hanging... */ + kill (pid, SIGTERM); + sleep (1); + result = waitpid (pid, &status, WNOHANG); + if (result == 0) { + /* ...still hanging, set phasers to KILL. */ + kill (pid, SIGKILL); + sleep (1); + waitpid (pid, &status, WNOHANG); + } + } + + return content; + + /* Forking Failed */ + } else { + g_warning ( + "Failed to create child process '%s': %s", + filename, g_strerror (errno)); + close (in_fds[0]); + close (in_fds[1]); + } +#endif + + return NULL; +} diff --git a/libemail-utils/e-signature-utils.h b/libemail-utils/e-signature-utils.h new file mode 100644 index 0000000000..a642a136f1 --- /dev/null +++ b/libemail-utils/e-signature-utils.h @@ -0,0 +1,40 @@ +/* + * e-signature-utils.h + * + * 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 + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + */ + +#ifndef E_SIGNATURE_UTILS_H +#define E_SIGNATURE_UTILS_H + +#include +#include +#include + +G_BEGIN_DECLS + +ESignatureList *e_get_signature_list (void); +ESignature * e_get_signature_by_name (const gchar *name); +ESignature * e_get_signature_by_uid (const gchar *uid); +gchar * e_create_signature_file (GError **error); +gchar * e_read_signature_file (ESignature *signature, + gboolean convert_to_html, + GError **error); +gchar * e_run_signature_script (const gchar *filename); + +G_END_DECLS + +#endif /* E_SIGNATURE_UTILS_H */ diff --git a/libemail-utils/e-signature.c b/libemail-utils/e-signature.c new file mode 100644 index 0000000000..1b49389a82 --- /dev/null +++ b/libemail-utils/e-signature.c @@ -0,0 +1,746 @@ +/* + * + * 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 + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include + +#include + +#include +#include + +#include "e-signature.h" + +struct _ESignaturePrivate { + gchar *filename; + gchar *name; + gchar *uid; + + gboolean autogenerated; + gboolean is_html; + gboolean is_script; +}; + +enum { + PROP_0, + PROP_AUTOGENERATED, + PROP_FILENAME, + PROP_IS_HTML, + PROP_IS_SCRIPT, + PROP_NAME, + PROP_UID +}; + +G_DEFINE_TYPE ( + ESignature, + e_signature, + G_TYPE_OBJECT) + +static gboolean +xml_set_bool (xmlNodePtr node, + const gchar *name, + gboolean *val) +{ + gboolean v_boolean; + gchar *buf; + + if ((buf = (gchar *) xmlGetProp (node, (xmlChar *) name))) { + v_boolean = (!strcmp (buf, "true") || !strcmp (buf, "yes")); + xmlFree (buf); + + if (v_boolean != *val) { + *val = v_boolean; + return TRUE; + } + } + + return FALSE; +} + +static gboolean +xml_set_prop (xmlNodePtr node, + const gchar *name, + gchar **val) +{ + gchar *buf, *new_val; + + buf = (gchar *) xmlGetProp (node, (xmlChar *) name); + new_val = g_strdup (buf); + xmlFree (buf); + + /* We can use strcmp here whether the value is UTF8 or + * not, since we only care if the bytes changed. + */ + if (!*val || strcmp (*val, new_val)) { + g_free (*val); + *val = new_val; + return TRUE; + } else { + g_free (new_val); + return FALSE; + } +} + +static gboolean +xml_set_content (xmlNodePtr node, + gchar **val) +{ + gchar *buf, *new_val; + + buf = (gchar *) xmlNodeGetContent (node); + new_val = g_strdup (buf); + xmlFree (buf); + + /* We can use strcmp here whether the value is UTF8 or + * not, since we only care if the bytes changed. */ + if (!*val || strcmp (*val, new_val)) { + g_free (*val); + *val = new_val; + return TRUE; + } else { + g_free (new_val); + return FALSE; + } +} + +static void +signature_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_AUTOGENERATED: + e_signature_set_autogenerated ( + E_SIGNATURE (object), + g_value_get_boolean (value)); + return; + + case PROP_FILENAME: + e_signature_set_filename ( + E_SIGNATURE (object), + g_value_get_string (value)); + return; + + case PROP_IS_HTML: + e_signature_set_is_html ( + E_SIGNATURE (object), + g_value_get_boolean (value)); + return; + + case PROP_IS_SCRIPT: + e_signature_set_is_script ( + E_SIGNATURE (object), + g_value_get_boolean (value)); + return; + + case PROP_NAME: + e_signature_set_name ( + E_SIGNATURE (object), + g_value_get_string (value)); + return; + + case PROP_UID: + e_signature_set_uid ( + E_SIGNATURE (object), + g_value_get_string (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +signature_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_AUTOGENERATED: + g_value_set_boolean ( + value, e_signature_get_autogenerated ( + E_SIGNATURE (object))); + return; + + case PROP_FILENAME: + g_value_set_string ( + value, e_signature_get_filename ( + E_SIGNATURE (object))); + return; + + case PROP_IS_HTML: + g_value_set_boolean ( + value, e_signature_get_is_html ( + E_SIGNATURE (object))); + return; + + case PROP_IS_SCRIPT: + g_value_set_boolean ( + value, e_signature_get_is_script ( + E_SIGNATURE (object))); + return; + + case PROP_NAME: + g_value_set_string ( + value, e_signature_get_name ( + E_SIGNATURE (object))); + return; + + case PROP_UID: + g_value_set_string ( + value, e_signature_get_uid ( + E_SIGNATURE (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +signature_finalize (GObject *object) +{ + ESignaturePrivate *priv; + + priv = E_SIGNATURE (object)->priv; + + g_free (priv->filename); + g_free (priv->name); + g_free (priv->uid); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (e_signature_parent_class)->finalize (object); +} + +static void +e_signature_class_init (ESignatureClass *class) +{ + GObjectClass *object_class; + + g_type_class_add_private (class, sizeof (ESignaturePrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = signature_set_property; + object_class->get_property = signature_get_property; + object_class->finalize = signature_finalize; + + g_object_class_install_property ( + object_class, + PROP_AUTOGENERATED, + g_param_spec_boolean ( + "autogenerated", + "Autogenerated", + NULL, + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + object_class, + PROP_FILENAME, + g_param_spec_string ( + "filename", + "Filename", + NULL, + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + object_class, + PROP_IS_HTML, + g_param_spec_boolean ( + "is-html", + "Is HTML", + NULL, + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + object_class, + PROP_IS_SCRIPT, + g_param_spec_boolean ( + "is-script", + "Is Script", + NULL, + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + object_class, + PROP_NAME, + g_param_spec_string ( + "name", + "Name", + NULL, + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + object_class, + PROP_UID, + g_param_spec_string ( + "uid", + "UID", + NULL, + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); +} + +static void +e_signature_init (ESignature *signature) +{ + signature->priv = G_TYPE_INSTANCE_GET_PRIVATE ( + signature, E_TYPE_SIGNATURE, ESignaturePrivate); +} + +/** + * e_signature_new: + * + * Returns a new signature which can be filled in and + * added to an #ESignatureList. + * + * Returns: a new #ESignature + **/ +ESignature * +e_signature_new (void) +{ + ESignature *signature; + + signature = g_object_new (E_TYPE_SIGNATURE, NULL); + signature->priv->uid = e_uid_new (); + + return signature; +} + +/** + * e_signature_new_from_xml: + * @xml: an XML signature description + * + * Return value: a new #ESignature based on the data in @xml, or %NULL + * if @xml could not be parsed as valid signature data. + **/ +ESignature * +e_signature_new_from_xml (const gchar *xml) +{ + ESignature *signature; + + signature = g_object_new (E_TYPE_SIGNATURE, NULL); + + if (!e_signature_set_from_xml (signature, xml)) { + g_object_unref (signature); + return NULL; + } + + return signature; +} + +/** + * e_signature_uid_from_xml: + * @xml: an XML signature description + * + * Return value: the permanent UID of the signature described by @xml + * (or %NULL if @xml could not be parsed or did not contain a uid). + * The caller must free this string. + **/ +gchar * +e_signature_uid_from_xml (const gchar *xml) +{ + xmlNodePtr node; + xmlDocPtr doc; + gchar *uid = NULL; + + if (!(doc = xmlParseDoc ((xmlChar *) xml))) + return NULL; + + node = doc->children; + if (strcmp ((gchar *)node->name, "signature") != 0) { + xmlFreeDoc (doc); + return NULL; + } + + xml_set_prop (node, "uid", &uid); + xmlFreeDoc (doc); + + return uid; +} + +/** + * e_signature_set_from_xml: + * @signature: an #ESignature + * @xml: an XML signature description. + * + * Changes @signature to match @xml. + * + * Returns: %TRUE if the signature was loaded or %FALSE otherwise + **/ +gboolean +e_signature_set_from_xml (ESignature *signature, + const gchar *xml) +{ + gboolean changed = FALSE; + xmlNodePtr node, cur; + xmlDocPtr doc; + gboolean bool; + gchar *buf; + + if (!(doc = xmlParseDoc ((xmlChar *) xml))) + return FALSE; + + node = doc->children; + if (strcmp ((gchar *)node->name, "signature") != 0) { + xmlFreeDoc (doc); + return FALSE; + } + + buf = NULL; + xml_set_prop (node, "uid", &buf); + + if (buf && *buf) { + g_free (signature->priv->uid); + signature->priv->uid = buf; + } + + changed |= xml_set_prop (node, "name", &signature->priv->name); + changed |= xml_set_bool (node, "auto", &signature->priv->autogenerated); + + if (e_signature_get_autogenerated (signature)) { + xmlFreeDoc (doc); + + return changed; + } + + buf = NULL; + xml_set_prop (node, "format", &buf); + if (buf && !strcmp (buf, "text/html")) + bool = TRUE; + else + bool = FALSE; + g_free (buf); + + if (e_signature_get_is_html (signature) != bool) { + e_signature_set_is_html (signature, bool); + changed = TRUE; + } + + cur = node->children; + while (cur) { + if (!strcmp ((gchar *)cur->name, "filename")) { + changed |= xml_set_content ( + cur, &signature->priv->filename); + changed |= xml_set_bool ( + cur, "script", &signature->priv->is_script); + break; + } else if (!strcmp ((gchar *)cur->name, "script")) { + /* this is for handling 1.4 signature script definitions */ + changed |= xml_set_content ( + cur, &signature->priv->filename); + if (!e_signature_get_is_script (signature)) { + e_signature_set_is_script (signature, TRUE); + changed = TRUE; + } + break; + } + cur = cur->next; + } + + /* If the signature is not a script, replace the directory + * part with the current signatures directory. This makes + * moving the signatures directory transparent. */ + if (!e_signature_get_is_script (signature)) { + const gchar *user_data_dir; + gchar *basename; + gchar *filename; + + user_data_dir = e_get_user_data_dir (); + + filename = signature->priv->filename; + basename = g_path_get_basename (filename); + signature->priv->filename = g_build_filename ( + user_data_dir, "signatures", basename, NULL); + g_free (basename); + g_free (filename); + } + + xmlFreeDoc (doc); + + return changed; +} + +/** + * e_signature_to_xml: + * @signature: an #ESignature + * + * Return value: an XML representation of @signature, which the caller + * must free. + **/ +gchar * +e_signature_to_xml (ESignature *signature) +{ + xmlChar *xmlbuf; + gchar *tmp; + xmlNodePtr root, node; + xmlDocPtr doc; + const gchar *string; + gint n; + + doc = xmlNewDoc ((xmlChar *) "1.0"); + + root = xmlNewDocNode (doc, NULL, (xmlChar *) "signature", NULL); + xmlDocSetRootElement (doc, root); + + string = e_signature_get_name (signature); + xmlSetProp (root, (xmlChar *) "name", (xmlChar *) string); + + string = e_signature_get_uid (signature); + xmlSetProp (root, (xmlChar *) "uid", (xmlChar *) string); + + if (e_signature_get_autogenerated (signature)) + string = "true"; + else + string = "false"; + xmlSetProp (root, (xmlChar *) "auto", (xmlChar *) string); + + if (!e_signature_get_autogenerated (signature)) { + if (e_signature_get_is_html (signature)) + string = "text/html"; + else + string = "text/plain"; + xmlSetProp (root, (xmlChar *) "format", (xmlChar *) string); + + string = e_signature_get_filename (signature); + if (string != NULL) { + + /* For scripts we save the full filename, + * for normal signatures just the basename. */ + if (e_signature_get_is_script (signature)) { + node = xmlNewTextChild ( + root, NULL, (xmlChar *) "filename", + (xmlChar *) string); + xmlSetProp ( + node, (xmlChar *) "script", + (xmlChar *) "true"); + } else { + gchar *basename; + + basename = g_path_get_basename (string); + node = xmlNewTextChild ( + root, NULL, (xmlChar *) "filename", + (xmlChar *) basename); + g_free (basename); + } + } + } else { + /* this is to make Evolution-1.4 and older 1.5 versions happy */ + xmlSetProp (root, (xmlChar *) "format", (xmlChar *) "text/html"); + } + + xmlDocDumpMemory (doc, &xmlbuf, &n); + xmlFreeDoc (doc); + + /* remap to glib memory */ + tmp = g_malloc (n + 1); + memcpy (tmp, xmlbuf, n); + tmp[n] = '\0'; + xmlFree (xmlbuf); + + return tmp; +} + +gboolean +e_signature_is_equal (ESignature *signature1, + ESignature *signature2) +{ + const gchar *uid1; + const gchar *uid2; + + g_return_val_if_fail (E_IS_SIGNATURE (signature1), FALSE); + g_return_val_if_fail (E_IS_SIGNATURE (signature2), FALSE); + + /* XXX Simply compares the UIDs. Not fool-proof. */ + uid1 = e_signature_get_uid (signature1); + uid2 = e_signature_get_uid (signature2); + + return (g_strcmp0 (uid1, uid2) == 0); +} + +gboolean +e_signature_get_autogenerated (ESignature *signature) +{ + g_return_val_if_fail (E_IS_SIGNATURE (signature), FALSE); + + return signature->priv->autogenerated; +} + +void +e_signature_set_autogenerated (ESignature *signature, + gboolean autogenerated) +{ + g_return_if_fail (E_IS_SIGNATURE (signature)); + + if (signature->priv->autogenerated == autogenerated) + return; + + signature->priv->autogenerated = autogenerated; + + /* Autogenerated flags overrides several properties. */ + g_object_freeze_notify (G_OBJECT (signature)); + g_object_notify (G_OBJECT (signature), "autogenerated"); + g_object_notify (G_OBJECT (signature), "filename"); + g_object_notify (G_OBJECT (signature), "is-html"); + g_object_notify (G_OBJECT (signature), "is-script"); + g_object_notify (G_OBJECT (signature), "name"); + g_object_thaw_notify (G_OBJECT (signature)); +} + +const gchar * +e_signature_get_filename (ESignature *signature) +{ + g_return_val_if_fail (E_IS_SIGNATURE (signature), NULL); + + /* Autogenerated flags overrides the filename property. */ + if (e_signature_get_autogenerated (signature)) + return NULL; + + return signature->priv->filename; +} + +void +e_signature_set_filename (ESignature *signature, + const gchar *filename) +{ + g_return_if_fail (E_IS_SIGNATURE (signature)); + + g_free (signature->priv->filename); + signature->priv->filename = g_strdup (filename); + + g_object_notify (G_OBJECT (signature), "filename"); +} + +gboolean +e_signature_get_is_html (ESignature *signature) +{ + g_return_val_if_fail (E_IS_SIGNATURE (signature), FALSE); + + /* Autogenerated flag overrides the is-html property. */ + if (e_signature_get_autogenerated (signature)) + return FALSE; + + return signature->priv->is_html; +} + +void +e_signature_set_is_html (ESignature *signature, + gboolean is_html) +{ + g_return_if_fail (E_IS_SIGNATURE (signature)); + + if (signature->priv->is_html == is_html) + return; + + signature->priv->is_html = is_html; + + g_object_notify (G_OBJECT (signature), "is-html"); +} + +gboolean +e_signature_get_is_script (ESignature *signature) +{ + g_return_val_if_fail (E_IS_SIGNATURE (signature), FALSE); + + /* Autogenerated flags overrides the is-script property. */ + if (e_signature_get_autogenerated (signature)) + return FALSE; + + return signature->priv->is_script; +} + +void +e_signature_set_is_script (ESignature *signature, + gboolean is_script) +{ + g_return_if_fail (E_IS_SIGNATURE (signature)); + + if (signature->priv->is_script == is_script) + return; + + signature->priv->is_script = is_script; + + g_object_notify (G_OBJECT (signature), "is-script"); +} + +const gchar * +e_signature_get_name (ESignature *signature) +{ + g_return_val_if_fail (E_IS_SIGNATURE (signature), NULL); + + /* Autogenerated flag overrides the name property. */ + if (e_signature_get_autogenerated (signature)) + return _("Autogenerated"); + + return signature->priv->name; +} + +void +e_signature_set_name (ESignature *signature, + const gchar *name) +{ + g_return_if_fail (E_IS_SIGNATURE (signature)); + + g_free (signature->priv->name); + signature->priv->name = g_strdup (name); + + g_object_notify (G_OBJECT (signature), "name"); +} + +const gchar * +e_signature_get_uid (ESignature *signature) +{ + g_return_val_if_fail (E_IS_SIGNATURE (signature), NULL); + + return signature->priv->uid; +} + +void +e_signature_set_uid (ESignature *signature, + const gchar *uid) +{ + g_return_if_fail (E_IS_SIGNATURE (signature)); + + g_free (signature->priv->uid); + + if (uid == NULL) + signature->priv->uid = e_uid_new (); + else + signature->priv->uid = g_strdup (uid); + + g_object_notify (G_OBJECT (signature), "uid"); +} diff --git a/libemail-utils/e-signature.h b/libemail-utils/e-signature.h new file mode 100644 index 0000000000..fad1faffa3 --- /dev/null +++ b/libemail-utils/e-signature.h @@ -0,0 +1,90 @@ +/* + * + * 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 + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef E_SIGNATURE_H +#define E_SIGNATURE_H + +#include + +/* Standard GObject macros */ +#define E_TYPE_SIGNATURE \ + (e_signature_get_type ()) +#define E_SIGNATURE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_SIGNATURE, ESignature)) +#define E_SIGNATURE_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_SIGNATURE, ESignatureClass)) +#define E_IS_SIGNATURE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_SIGNATURE)) +#define E_IS_SIGNATURE_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_SIGNATURE)) +#define E_SIGNATURE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_SIGNATURE, ESignatureClass)) + +G_BEGIN_DECLS + +typedef struct _ESignature ESignature; +typedef struct _ESignatureClass ESignatureClass; +typedef struct _ESignaturePrivate ESignaturePrivate; + +struct _ESignature { + GObject parent; + ESignaturePrivate *priv; +}; + +struct _ESignatureClass { + GObjectClass parent_class; +}; + +GType e_signature_get_type (void); +ESignature * e_signature_new (void); +ESignature * e_signature_new_from_xml (const gchar *xml); +gchar * e_signature_uid_from_xml (const gchar *xml); +gboolean e_signature_set_from_xml (ESignature *signature, + const gchar *xml); +gchar * e_signature_to_xml (ESignature *signature); +gboolean e_signature_is_equal (ESignature *signature1, + ESignature *signature2); +gboolean e_signature_get_autogenerated (ESignature *signature); +void e_signature_set_autogenerated (ESignature *signature, + gboolean autogenerated); +const gchar * e_signature_get_filename (ESignature *signature); +void e_signature_set_filename (ESignature *signature, + const gchar *filename); +gboolean e_signature_get_is_html (ESignature *signature); +void e_signature_set_is_html (ESignature *signature, + gboolean is_html); +gboolean e_signature_get_is_script (ESignature *signature); +void e_signature_set_is_script (ESignature *signature, + gboolean is_script); +const gchar * e_signature_get_name (ESignature *signature); +void e_signature_set_name (ESignature *signature, + const gchar *name); +const gchar * e_signature_get_uid (ESignature *signature); +void e_signature_set_uid (ESignature *signature, + const gchar *uid); + +G_END_DECLS + +#endif /* E_SIGNATURE_H */ diff --git a/libemail-utils/libemail-utils.pc.in b/libemail-utils/libemail-utils.pc.in new file mode 100644 index 0000000000..384147b793 --- /dev/null +++ b/libemail-utils/libemail-utils.pc.in @@ -0,0 +1,15 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ +datarootdir=@datarootdir@ +datadir=@datadir@ + +privincludedir=@privincludedir@ + +Name: libemail-utils +Description: Client library for evolution mail +Version: @VERSION@ +Requires: camel-1.2 libedataserver-1.2 gio-2.0 +Libs: -L${libdir} -lemail-utils +Cflags: -I${privincludedir} diff --git a/libemail-utils/mail-mt.c b/libemail-utils/mail-mt.c new file mode 100644 index 0000000000..e932bd6e93 --- /dev/null +++ b/libemail-utils/mail-mt.c @@ -0,0 +1,639 @@ +/* + * 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 + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include + +#include + +#include "mail-mt.h" + +/*#define MALLOC_CHECK*/ +#define d(x) + +/* XXX This is a dirty hack on a dirty hack. We really need + * to rework or get rid of the functions that use this. */ +const gchar *shell_builtin_backend = "mail"; + +static guint mail_msg_seq; /* sequence number of each message */ + +/* Table of active messages. Must hold mail_msg_lock to access. */ +static GHashTable *mail_msg_active_table; +static GMutex *mail_msg_lock; +static GCond *mail_msg_cond; + +static MailMsgCreateActivityFunc create_activity = NULL; +static MailMsgSubmitActivityFunc submit_acitivity = NULL; +static MailMsgFreeActivityFunc free_activity = NULL; +static MailMsgCompleteActivityFunc complete_activity = NULL; +static MailMsgAlertErrorFunc alert_error = NULL; +static MailMsgCancelActivityFunc cancel_activity = NULL; + +void mail_msg_register_activities (MailMsgCreateActivityFunc acreate, + MailMsgSubmitActivityFunc asubmit, + MailMsgFreeActivityFunc freeact, + MailMsgCompleteActivityFunc comp_act, + MailMsgCancelActivityFunc cancel_act, + MailMsgAlertErrorFunc ealert) +{ + /* This is a utter hack to keep EActivity out of EDS and still let Evolution do EActivity */ + create_activity = acreate; + submit_acitivity = asubmit; + free_activity = freeact; + complete_activity = comp_act; + cancel_activity = cancel_act; + alert_error = ealert; +} + +static void +mail_msg_cancelled (CamelOperation *operation, + gpointer user_data) +{ + mail_msg_cancel (GPOINTER_TO_UINT (user_data)); +} + + +static gboolean +mail_msg_submit (CamelOperation *cancellable) +{ + + if (submit_acitivity) + submit_acitivity ((GCancellable *)cancellable); + return FALSE; +} + +gpointer +mail_msg_new (MailMsgInfo *info) +{ + MailMsg *msg; + + g_mutex_lock (mail_msg_lock); + + msg = g_slice_alloc0 (info->size); + msg->info = info; + msg->ref_count = 1; + msg->seq = mail_msg_seq++; + + msg->cancellable = camel_operation_new (); + + if (create_activity) + create_activity (msg->cancellable); + + g_signal_connect ( + msg->cancellable, "cancelled", + G_CALLBACK (mail_msg_cancelled), + GINT_TO_POINTER (msg->seq)); + + g_hash_table_insert ( + mail_msg_active_table, GINT_TO_POINTER (msg->seq), msg); + + d(printf("New message %p\n", msg)); + + g_mutex_unlock (mail_msg_lock); + + return msg; +} + +#ifdef MALLOC_CHECK +#include + +static void +checkmem (gpointer p) +{ + if (p) { + gint status = mprobe (p); + + switch (status) { + case MCHECK_HEAD: + printf("Memory underrun at %p\n", p); + abort (); + case MCHECK_TAIL: + printf("Memory overrun at %p\n", p); + abort (); + case MCHECK_FREE: + printf("Double free %p\n", p); + abort (); + } + } +} +#endif + +static gboolean +mail_msg_free (MailMsg *mail_msg) +{ + /* This is an idle callback. */ + + if (free_activity) + free_activity (mail_msg->cancellable); + + if (mail_msg->cancellable != NULL) + g_object_unref (mail_msg->cancellable); + + if (mail_msg->error != NULL) + g_error_free (mail_msg->error); + + g_slice_free1 (mail_msg->info->size, mail_msg); + + return FALSE; +} + +gpointer +mail_msg_ref (gpointer msg) +{ + MailMsg *mail_msg = msg; + + g_return_val_if_fail (mail_msg != NULL, msg); + g_return_val_if_fail (mail_msg->ref_count > 0, msg); + + g_atomic_int_inc (&mail_msg->ref_count); + + return msg; +} + +void +mail_msg_unref (gpointer msg) +{ + MailMsg *mail_msg = msg; + + g_return_if_fail (mail_msg != NULL); + g_return_if_fail (mail_msg->ref_count > 0); + + if (g_atomic_int_dec_and_test (&mail_msg->ref_count)) { + +#ifdef MALLOC_CHECK + checkmem (mail_msg); + checkmem (mail_msg->cancel); + checkmem (mail_msg->priv); +#endif + d(printf("Free message %p\n", msg)); + + if (mail_msg->info->free) + mail_msg->info->free (mail_msg); + + g_mutex_lock (mail_msg_lock); + + g_hash_table_remove ( + mail_msg_active_table, + GINT_TO_POINTER (mail_msg->seq)); + g_cond_broadcast (mail_msg_cond); + + g_mutex_unlock (mail_msg_lock); + + /* Destroy the message from an idle callback + * so we know we're in the main loop thread. */ + g_idle_add ((GSourceFunc) mail_msg_free, mail_msg); + } +} + +void +mail_msg_check_error (gpointer msg) +{ + MailMsg *m = msg; + +#ifdef MALLOC_CHECK + checkmem (m); + checkmem (m->cancel); + checkmem (m->priv); +#endif + + if (m->error == NULL) + return; + + if (complete_activity) + complete_activity (m->cancellable); + + if (g_error_matches (m->error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + if (cancel_activity) + cancel_activity (m->cancellable); + return; + } + + /* XXX Hmm, no explanation of why this is needed. It looks like + * a lame hack and will be removed at some point, if only to + * reintroduce whatever issue made this necessary so we can + * document it the source code this time. */ + if (g_error_matches (m->error, CAMEL_FOLDER_ERROR, CAMEL_FOLDER_ERROR_INVALID_UID)) + return; + + /* FIXME: Submit an error on the dbus */ + if (alert_error) { + char *what; + + if (m->info->desc && (what = m->info->desc (m))) { + alert_error (m->cancellable, what, m->error->message); + g_free (what); + } else + alert_error (m->cancellable, NULL, m->error->message); + } +} + +void +mail_msg_cancel (guint msgid) +{ + MailMsg *msg; + GCancellable *cancellable = NULL; + + g_mutex_lock (mail_msg_lock); + + msg = g_hash_table_lookup ( + mail_msg_active_table, GINT_TO_POINTER (msgid)); + + /* Hold a reference to the GCancellable so it doesn't finalize + * itself on us between unlocking the mutex and cancelling. */ + if (msg != NULL) { + cancellable = msg->cancellable; + if (g_cancellable_is_cancelled (cancellable)) + cancellable = NULL; + else + g_object_ref (cancellable); + } + + g_mutex_unlock (mail_msg_lock); + + if (cancellable != NULL) { + g_cancellable_cancel (cancellable); + g_object_unref (cancellable); + } +} + +gboolean +mail_msg_active (void) +{ + gboolean active; + + g_mutex_lock (mail_msg_lock); + active = g_hash_table_size (mail_msg_active_table) > 0; + g_mutex_unlock (mail_msg_lock); + + return active; +} + +/* **************************************** */ + +static GHookList cancel_hook_list; + +GHook * +mail_cancel_hook_add (GHookFunc func, + gpointer data) +{ + GHook *hook; + + g_mutex_lock (mail_msg_lock); + + if (!cancel_hook_list.is_setup) + g_hook_list_init (&cancel_hook_list, sizeof (GHook)); + + hook = g_hook_alloc (&cancel_hook_list); + hook->func = func; + hook->data = data; + + g_hook_append (&cancel_hook_list, hook); + + g_mutex_unlock (mail_msg_lock); + + return hook; +} + +void +mail_cancel_hook_remove (GHook *hook) +{ + g_mutex_lock (mail_msg_lock); + + g_return_if_fail (cancel_hook_list.is_setup); + g_hook_destroy_link (&cancel_hook_list, hook); + + g_mutex_unlock (mail_msg_lock); +} + +void +mail_cancel_all (void) +{ + camel_operation_cancel_all (); + + g_mutex_lock (mail_msg_lock); + + if (cancel_hook_list.is_setup) + g_hook_list_invoke (&cancel_hook_list, FALSE); + + g_mutex_unlock (mail_msg_lock); +} + +static guint idle_source_id = 0; +G_LOCK_DEFINE_STATIC (idle_source_id); +static GAsyncQueue *main_loop_queue = NULL; +static GAsyncQueue *msg_reply_queue = NULL; +static GThread *main_thread = NULL; + +static gboolean +mail_msg_idle_cb (void) +{ + MailMsg *msg; + + g_return_val_if_fail (main_loop_queue != NULL, FALSE); + g_return_val_if_fail (msg_reply_queue != NULL, FALSE); + + G_LOCK (idle_source_id); + idle_source_id = 0; + G_UNLOCK (idle_source_id); + /* check the main loop queue */ + while ((msg = g_async_queue_try_pop (main_loop_queue)) != NULL) { + GCancellable *cancellable; + + cancellable = msg->cancellable; + + g_idle_add_full ( + G_PRIORITY_DEFAULT, + (GSourceFunc) mail_msg_submit, + g_object_ref (msg->cancellable), + (GDestroyNotify) g_object_unref); + if (msg->info->exec != NULL) + msg->info->exec (msg, cancellable, &msg->error); + if (msg->info->done != NULL) + msg->info->done (msg); + mail_msg_unref (msg); + } + + /* check the reply queue */ + while ((msg = g_async_queue_try_pop (msg_reply_queue)) != NULL) { + if (msg->info->done != NULL) + msg->info->done (msg); + mail_msg_check_error (msg); + mail_msg_unref (msg); + } + return FALSE; +} + +static void +mail_msg_proxy (MailMsg *msg) +{ + GCancellable *cancellable; + + cancellable = msg->cancellable; + + if (msg->info->desc != NULL) { + gchar *text = msg->info->desc (msg); + camel_operation_push_message (cancellable, "%s", text); + g_free (text); + } + + g_idle_add_full ( + G_PRIORITY_DEFAULT, + (GSourceFunc) mail_msg_submit, + g_object_ref (msg->cancellable), + (GDestroyNotify) g_object_unref); + + if (msg->info->exec != NULL) + msg->info->exec (msg, cancellable, &msg->error); + + if (msg->info->desc != NULL) + camel_operation_pop_message (cancellable); + + g_async_queue_push (msg_reply_queue, msg); + + G_LOCK (idle_source_id); + if (idle_source_id == 0) + idle_source_id = g_idle_add ( + (GSourceFunc) mail_msg_idle_cb, NULL); + G_UNLOCK (idle_source_id); +} + +void +mail_msg_init (void) +{ + mail_msg_lock = g_mutex_new (); + mail_msg_cond = g_cond_new (); + + main_loop_queue = g_async_queue_new (); + msg_reply_queue = g_async_queue_new (); + + mail_msg_active_table = g_hash_table_new (NULL, NULL); + main_thread = g_thread_self (); +} + +static gint +mail_msg_compare (const MailMsg *msg1, + const MailMsg *msg2) +{ + gint priority1 = msg1->priority; + gint priority2 = msg2->priority; + + if (priority1 == priority2) + return 0; + + return (priority1 < priority2) ? 1 : -1; +} + +static gpointer +create_thread_pool (gpointer data) +{ + GThreadPool *thread_pool; + gint max_threads = GPOINTER_TO_INT (data); + + /* once created, run forever */ + thread_pool = g_thread_pool_new ( + (GFunc) mail_msg_proxy, NULL, max_threads, FALSE, NULL); + g_thread_pool_set_sort_function ( + thread_pool, (GCompareDataFunc) mail_msg_compare, NULL); + + return thread_pool; +} + +void +mail_msg_main_loop_push (gpointer msg) +{ + g_async_queue_push_sorted (main_loop_queue, msg, + (GCompareDataFunc) mail_msg_compare, NULL); + + G_LOCK (idle_source_id); + if (idle_source_id == 0) + idle_source_id = g_idle_add ( + (GSourceFunc) mail_msg_idle_cb, NULL); + G_UNLOCK (idle_source_id); +} + +void +mail_msg_unordered_push (gpointer msg) +{ + static GOnce once = G_ONCE_INIT; + + g_once (&once, (GThreadFunc) create_thread_pool, GINT_TO_POINTER (10)); + + g_thread_pool_push ((GThreadPool *) once.retval, msg, NULL); +} + +void +mail_msg_fast_ordered_push (gpointer msg) +{ + static GOnce once = G_ONCE_INIT; + + g_once (&once, (GThreadFunc) create_thread_pool, GINT_TO_POINTER (1)); + + g_thread_pool_push ((GThreadPool *) once.retval, msg, NULL); +} + +void +mail_msg_slow_ordered_push (gpointer msg) +{ + static GOnce once = G_ONCE_INIT; + + g_once (&once, (GThreadFunc) create_thread_pool, GINT_TO_POINTER (1)); + + g_thread_pool_push ((GThreadPool *) once.retval, msg, NULL); +} + +gboolean +mail_in_main_thread (void) +{ + return (g_thread_self () == main_thread); +} + +/* ********************************************************************** */ + +struct _call_msg { + MailMsg base; + + mail_call_t type; + MailMainFunc func; + gpointer ret; + va_list ap; + EFlag *done; +}; + +static void +do_call (struct _call_msg *m, + GCancellable *cancellable, + GError **error) +{ + gpointer p1, *p2, *p3, *p4, *p5; + gint i1; + va_list ap; + + G_VA_COPY (ap, m->ap); + + switch (m->type) { + case MAIL_CALL_p_p: + p1 = va_arg (ap, gpointer ); + m->ret = m->func (p1); + break; + case MAIL_CALL_p_pp: + p1 = va_arg (ap, gpointer ); + p2 = va_arg (ap, gpointer ); + m->ret = m->func (p1, p2); + break; + case MAIL_CALL_p_ppp: + p1 = va_arg (ap, gpointer ); + p2 = va_arg (ap, gpointer ); + p3 = va_arg (ap, gpointer ); + m->ret = m->func (p1, p2, p3); + break; + case MAIL_CALL_p_pppp: + p1 = va_arg (ap, gpointer ); + p2 = va_arg (ap, gpointer ); + p3 = va_arg (ap, gpointer ); + p4 = va_arg (ap, gpointer ); + m->ret = m->func (p1, p2, p3, p4); + break; + case MAIL_CALL_p_ppppp: + p1 = va_arg (ap, gpointer ); + p2 = va_arg (ap, gpointer ); + p3 = va_arg (ap, gpointer ); + p4 = va_arg (ap, gpointer ); + p5 = va_arg (ap, gpointer ); + m->ret = m->func (p1, p2, p3, p4, p5); + break; + case MAIL_CALL_p_ppippp: + p1 = va_arg (ap, gpointer ); + p2 = va_arg (ap, gpointer ); + i1 = va_arg (ap, gint); + p3 = va_arg (ap, gpointer ); + p4 = va_arg (ap, gpointer ); + p5 = va_arg (ap, gpointer ); + m->ret = m->func (p1, p2, i1, p3, p4, p5); + break; + } + + if (g_cancellable_is_cancelled (cancellable)) { + if (cancel_activity) + cancel_activity (cancellable); + } else { + if (complete_activity) + complete_activity (cancellable); + } + + if (m->done != NULL) + e_flag_set (m->done); +} + +static MailMsgInfo mail_call_info = { + sizeof (struct _call_msg), + (MailMsgDescFunc) NULL, + (MailMsgExecFunc) do_call, + (MailMsgDoneFunc) NULL, + (MailMsgFreeFunc) NULL +}; + +gpointer +mail_call_main (mail_call_t type, + MailMainFunc func, + ...) +{ + GCancellable *cancellable; + struct _call_msg *m; + gpointer ret; + va_list ap; + + va_start (ap, func); + + m = mail_msg_new (&mail_call_info); + m->type = type; + m->func = func; + G_VA_COPY (m->ap, ap); + + cancellable = m->base.cancellable; + + if (mail_in_main_thread ()) + do_call (m, cancellable, &m->base.error); + else { + mail_msg_ref (m); + m->done = e_flag_new (); + mail_msg_main_loop_push (m); + e_flag_wait (m->done); + e_flag_free (m->done); + } + + va_end (ap); + + ret = m->ret; + mail_msg_unref (m); + + return ret; +} + +void +mail_mt_set_backend (gchar *backend) +{ + shell_builtin_backend = backend; +} + diff --git a/libemail-utils/mail-mt.h b/libemail-utils/mail-mt.h new file mode 100644 index 0000000000..52da408f70 --- /dev/null +++ b/libemail-utils/mail-mt.h @@ -0,0 +1,116 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + * + * Authors: + * Michael Zucchi + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef _MAIL_MT +#define _MAIL_MT + +#include + +typedef struct _MailMsg MailMsg; +typedef struct _MailMsgInfo MailMsgInfo; + +typedef gchar * (*MailMsgDescFunc) (MailMsg *msg); +typedef void (*MailMsgExecFunc) (MailMsg *msg, + GCancellable *cancellable, + GError **error); +typedef void (*MailMsgDoneFunc) (MailMsg *msg); +typedef void (*MailMsgFreeFunc) (MailMsg *msg); +typedef void (*MailMsgDispatchFunc) (gpointer msg); + + +typedef void (*MailMsgCreateActivityFunc) (GCancellable *cancellable); +typedef void (*MailMsgSubmitActivityFunc) (GCancellable *cancellable); +typedef void (*MailMsgFreeActivityFunc) (GCancellable *cancellable); +typedef void (*MailMsgCompleteActivityFunc) (GCancellable *cancellable); +typedef void (*MailMsgCancelActivityFunc) (GCancellable *cancellable); +typedef void (*MailMsgAlertErrorFunc) (GCancellable *cancellable, const char *what, const char *message); + +struct _MailMsg { + MailMsgInfo *info; + volatile gint ref_count; + guint seq; /* seq number for synchronisation */ + gint priority; /* priority (default = 0) */ + GCancellable *cancellable; + GError *error; /* up to the caller to use this */ +}; + +struct _MailMsgInfo { + gsize size; + MailMsgDescFunc desc; + MailMsgExecFunc exec; + MailMsgDoneFunc done; + MailMsgFreeFunc free; +}; + +/* setup ports */ +void mail_msg_init (void); +void mail_msg_register_activities (MailMsgCreateActivityFunc, + MailMsgSubmitActivityFunc, + MailMsgFreeActivityFunc, + MailMsgCompleteActivityFunc, + MailMsgCancelActivityFunc, + MailMsgAlertErrorFunc); + +gboolean mail_in_main_thread (void); + +/* allocate a new message */ +gpointer mail_msg_new (MailMsgInfo *info); +gpointer mail_msg_ref (gpointer msg); +void mail_msg_unref (gpointer msg); +void mail_msg_check_error (gpointer msg); +void mail_msg_cancel (guint msgid); +gboolean mail_msg_active (void); + +/* dispatch a message */ +void mail_msg_main_loop_push (gpointer msg); +void mail_msg_unordered_push (gpointer msg); +void mail_msg_fast_ordered_push (gpointer msg); +void mail_msg_slow_ordered_push (gpointer msg); + +/* To implement the stop button */ +GHook * mail_cancel_hook_add (GHookFunc func, gpointer data); +void mail_cancel_hook_remove (GHook *hook); +void mail_cancel_all (void); + +/* request a string/password */ +gchar *mail_get_password (CamelService *service, const gchar *prompt, + gboolean secret, gboolean *cache); + +void mail_mt_set_backend (gchar *backend); + +/* Call a function in the GUI thread, wait for it to return, type is + * the marshaller to use. FIXME This thing is horrible, please put + * it out of its misery. */ +typedef enum { + MAIL_CALL_p_p, + MAIL_CALL_p_pp, + MAIL_CALL_p_ppp, + MAIL_CALL_p_pppp, + MAIL_CALL_p_ppppp, + MAIL_CALL_p_ppippp +} mail_call_t; + +typedef gpointer (*MailMainFunc)(); + +gpointer mail_call_main (mail_call_t type, MailMainFunc func, ...); + +#endif /* _MAIL_MT */ diff --git a/mail/Makefile.am b/mail/Makefile.am index 8310cff129..b80d56cb8e 100644 --- a/mail/Makefile.am +++ b/mail/Makefile.am @@ -4,14 +4,6 @@ privsolib_LTLIBRARIES = libevolution-mail.la mailincludedir = $(privincludedir)/mail -include $(top_srcdir)/glib-gen.mak -glib_enum_headers=e-mail-enums.h -glib_enum_output=e-mail-enumtypes -glib_enum_define=E_MAIL -glib_enum_prefix=e_mail - -ENUM_GENERATED = e-mail-enumtypes.h e-mail-enumtypes.c - libevolution_mail_la_CPPFLAGS = \ $(AM_CPPFLAGS) \ -I$(top_srcdir)/widgets \ @@ -53,11 +45,7 @@ mailinclude_HEADERS = \ e-mail-backend.h \ e-mail-browser.h \ e-mail-display.h \ - e-mail-enums.h \ - e-mail-enumtypes.h \ e-mail-folder-pane.h \ - e-mail-folder-utils.h \ - e-mail-junk-filter.h \ e-mail-junk-options.h \ e-mail-label-action.h \ e-mail-label-dialog.h \ @@ -70,10 +58,8 @@ mailinclude_HEADERS = \ e-mail-paned-view.h \ e-mail-reader-utils.h \ e-mail-reader.h \ - e-mail-session-utils.h \ - e-mail-session.h \ + e-mail-ui-session.h \ e-mail-sidebar.h \ - e-mail-store-utils.h \ e-mail-tag-editor.h \ e-mail-view.h \ em-account-editor.h \ @@ -104,13 +90,8 @@ mailinclude_HEADERS = \ em-vfolder-editor.h \ em-vfolder-rule.h \ mail-autofilter.h \ - mail-config.h \ - mail-folder-cache.h \ mail-guess-servers.h \ - mail-mt.h \ - mail-ops.h \ mail-send-recv.h \ - mail-tools.h \ mail-vfolder.h \ message-list.h @@ -129,10 +110,7 @@ libevolution_mail_la_SOURCES = \ e-mail-backend.c \ e-mail-browser.c \ e-mail-display.c \ - e-mail-enumtypes.c \ e-mail-folder-pane.c \ - e-mail-folder-utils.c \ - e-mail-junk-filter.c \ e-mail-junk-options.c \ e-mail-label-action.c \ e-mail-label-dialog.c \ @@ -145,10 +123,8 @@ libevolution_mail_la_SOURCES = \ e-mail-paned-view.c \ e-mail-reader-utils.c \ e-mail-reader.c \ - e-mail-session-utils.c \ - e-mail-session.c \ + e-mail-ui-session.c \ e-mail-sidebar.c \ - e-mail-store-utils.c \ e-mail-tag-editor.c \ e-mail-view.c \ em-account-editor.c \ @@ -179,13 +155,8 @@ libevolution_mail_la_SOURCES = \ em-vfolder-editor.c \ em-vfolder-rule.c \ mail-autofilter.c \ - mail-config.c \ - mail-folder-cache.c \ mail-guess-servers.c \ - mail-mt.c \ - mail-ops.c \ mail-send-recv.c \ - mail-tools.c \ mail-vfolder.c \ message-list.c @@ -202,6 +173,8 @@ SMIME_LIBS = \ endif libevolution_mail_la_LIBADD = \ + $(top_builddir)/libemail-utils/libemail-utils.la \ + $(top_builddir)/libemail-engine/libemail-engine.la \ $(top_builddir)/e-util/libeutil.la \ $(top_builddir)/shell/libeshell.la \ $(top_builddir)/composer/libcomposer.la \ @@ -307,7 +280,7 @@ endif dist-hook: cd $(distdir); rm -f $(BUILT_SOURCES) -BUILT_SOURCES = $(error_DATA) $(ENUM_GENERATED) +BUILT_SOURCES = $(error_DATA) CLEANFILES = $(BUILT_SOURCES) diff --git a/mail/e-mail-account-manager.c b/mail/e-mail-account-manager.c index 522e26e94c..86a0bf5e4b 100644 --- a/mail/e-mail-account-manager.c +++ b/mail/e-mail-account-manager.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include #define E_MAIL_ACCOUNT_MANAGER_GET_PRIVATE(obj) \ diff --git a/mail/e-mail-account-manager.h b/mail/e-mail-account-manager.h index 23f7890500..63e52b463c 100644 --- a/mail/e-mail-account-manager.h +++ b/mail/e-mail-account-manager.h @@ -20,8 +20,8 @@ #define E_MAIL_ACCOUNT_MANAGER_H #include -#include #include +#include /* Standard GObject macros */ #define E_TYPE_MAIL_ACCOUNT_MANAGER \ diff --git a/mail/e-mail-account-store.c b/mail/e-mail-account-store.c index e5a630850c..c14f75e4e5 100644 --- a/mail/e-mail-account-store.c +++ b/mail/e-mail-account-store.c @@ -25,9 +25,11 @@ #include #include -#include #include -#include + +#include +#include + #include #define E_MAIL_ACCOUNT_STORE_GET_PRIVATE(obj) \ @@ -462,9 +464,16 @@ mail_account_store_service_removed (EMailAccountStore *store, EAccountList *account_list; EAccount *account; + EMailSession *session; + MailFolderCache *cache; CamelProvider *provider; const gchar *uid; + session = e_mail_account_store_get_session (store); + cache = e_mail_session_get_folder_cache (session); + + mail_folder_cache_service_removed (cache, service); + account_list = e_get_account_list (); uid = camel_service_get_uid (service); account = e_get_account_by_uid (uid); @@ -497,9 +506,16 @@ mail_account_store_service_enabled (EMailAccountStore *store, * The 'busy_count' is bumped until changes are written back * to the D-Bus service. For now I guess we'll just block. */ + EMailSession *session; + MailFolderCache *cache; GSettings *settings; const gchar *uid; + session = e_mail_account_store_get_session (store); + cache = e_mail_session_get_folder_cache (session); + + mail_folder_cache_service_enabled (cache, service); + uid = camel_service_get_uid (service); /* Handle built-in services that don't have an EAccount. */ @@ -541,9 +557,16 @@ mail_account_store_service_disabled (EMailAccountStore *store, * The 'busy_count' is bumped until changes are written back * to the D-Bus service. For now I guess we'll just block. */ + EMailSession *session; + MailFolderCache *cache; GSettings *settings; const gchar *uid; + session = e_mail_account_store_get_session (store); + cache = e_mail_session_get_folder_cache (session); + + mail_folder_cache_service_disabled (cache, service); + uid = camel_service_get_uid (service); /* Handle built-in services that don't have an EAccount. */ @@ -1096,6 +1119,10 @@ e_mail_account_store_add_service (EMailAccountStore *store, /* This populates the rest of the columns. */ mail_account_store_update_row (store, service, &iter); + /* No need to connect to "service-added" emissions since it's + * always immediately followed by either "service-enabled" or + * "service-disabled" in MailFolderCache */ + g_signal_emit (store, signals[SERVICE_ADDED], 0, service); if (enabled) @@ -1115,7 +1142,7 @@ e_mail_account_store_remove_service (EMailAccountStore *store, CamelService *service) { GtkTreeIter iter; - gboolean proceed = TRUE; + gboolean proceed; g_return_if_fail (E_IS_MAIL_ACCOUNT_STORE (store)); g_return_if_fail (CAMEL_IS_SERVICE (service)); @@ -1148,7 +1175,7 @@ e_mail_account_store_enable_service (EMailAccountStore *store, CamelService *service) { GtkTreeIter iter; - gboolean proceed = TRUE; + gboolean proceed; g_return_if_fail (E_IS_MAIL_ACCOUNT_STORE (store)); g_return_if_fail (CAMEL_IS_SERVICE (service)); @@ -1166,7 +1193,6 @@ e_mail_account_store_enable_service (EMailAccountStore *store, gtk_list_store_set ( GTK_LIST_STORE (store), &iter, E_MAIL_ACCOUNT_STORE_COLUMN_ENABLED, TRUE, -1); - g_signal_emit (store, signals[SERVICE_ENABLED], 0, service); } } @@ -1177,7 +1203,7 @@ e_mail_account_store_disable_service (EMailAccountStore *store, CamelService *service) { GtkTreeIter iter; - gboolean proceed = TRUE; + gboolean proceed; g_return_if_fail (E_IS_MAIL_ACCOUNT_STORE (store)); g_return_if_fail (CAMEL_IS_SERVICE (service)); @@ -1195,7 +1221,6 @@ e_mail_account_store_disable_service (EMailAccountStore *store, gtk_list_store_set ( GTK_LIST_STORE (store), &iter, E_MAIL_ACCOUNT_STORE_COLUMN_ENABLED, FALSE, -1); - g_signal_emit (store, signals[SERVICE_DISABLED], 0, service); } } diff --git a/mail/e-mail-backend.c b/mail/e-mail-backend.c index 2f769e9c42..921b2d0efc 100644 --- a/mail/e-mail-backend.c +++ b/mail/e-mail-backend.c @@ -32,26 +32,29 @@ #include #include -#include "e-util/e-account-utils.h" -#include "e-util/e-alert-dialog.h" -#include "e-util/e-alert-sink.h" - -#include "misc/e-account-combo-box.h" - -#include "shell/e-shell.h" - -#include "mail/e-mail-folder-utils.h" -#include "mail/e-mail-migrate.h" -#include "mail/e-mail-session.h" -#include "mail/e-mail-store-utils.h" -#include "mail/em-event.h" -#include "mail/em-folder-tree-model.h" -#include "mail/em-utils.h" -#include "mail/mail-autofilter.h" -#include "mail/mail-config.h" -#include "mail/mail-folder-cache.h" -#include "mail/mail-ops.h" -#include "mail/mail-vfolder.h" +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include #define E_MAIL_BACKEND_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE \ @@ -759,6 +762,132 @@ mail_backend_finalize (GObject *object) camel_shutdown (); } +static void +mail_backend_add_store (EMailSession *session, + CamelStore *store, + EMailBackend *backend) +{ + EMFolderTreeModel *model; + + model = em_folder_tree_model_get_default (); + em_folder_tree_model_add_store (model, store); +} + +static void +mail_backend_remove_store (EMailSession *session, + CamelStore *store, + EMailBackend *backend) +{ + EMFolderTreeModel *model; + + model = em_folder_tree_model_get_default (); + em_folder_tree_model_remove_store (model, store); +} + +#define SET_ACITIVITY(cancellable, activity) \ + g_object_set_data (G_OBJECT (cancellable), "e-activity", activity) +#define GET_ACITIVITY(cancellable) \ + g_object_get_data (G_OBJECT (cancellable), "e-activity") + +static void +mail_mt_create_activity (GCancellable *cancellable) +{ + EActivity *activity; + + activity = e_activity_new (); + e_activity_set_percent (activity, 0.0); + e_activity_set_cancellable (activity, cancellable); + SET_ACITIVITY (cancellable, activity); +} + +static void +mail_mt_submit_activity (GCancellable *cancellable) +{ + EShell *shell; + EShellBackend *shell_backend; + EActivity *activity; + + shell = e_shell_get_default (); + shell_backend = e_shell_get_backend_by_name ( + shell, "mail"); + + activity = GET_ACITIVITY (cancellable); + if (activity) + e_shell_backend_add_activity (shell_backend, activity); + +} + +static void +mail_mt_free_activity (GCancellable *cancellable) +{ + EActivity *activity = GET_ACITIVITY (cancellable); + + if (activity) + g_object_unref (activity); +} + +static void +mail_mt_complete_acitivity (GCancellable *cancellable) +{ + EActivity *activity = GET_ACITIVITY (cancellable); + + if (activity) + e_activity_set_state (activity, E_ACTIVITY_COMPLETED); +} + +static void +mail_mt_cancel_activity (GCancellable *cancellable) +{ + EActivity *activity = GET_ACITIVITY (cancellable); + + if (activity) + e_activity_set_state (activity, E_ACTIVITY_CANCELLED); +} + +static void +mail_mt_alert_error (GCancellable *cancellable, + const char *what, + const char *message) +{ + EShell *shell; + EShellView *shell_view; + EShellWindow *shell_window = NULL; + EShellContent *shell_content; + GList *list, *iter; + GtkApplication *application; + + shell = e_shell_get_default (); + application = GTK_APPLICATION (shell); + list = gtk_application_get_windows (application); + + /* Find the most recently used EShellWindow. */ + for (iter = list; iter != NULL; iter = g_list_next (iter)) { + if (E_IS_SHELL_WINDOW (iter->data)) { + shell_window = E_SHELL_WINDOW (iter->data); + break; + } + } + + /* If we can't find an EShellWindow then... well, screw it. */ + if (shell_window == NULL) + return; + + shell_view = e_shell_window_get_shell_view ( + shell_window, "mail"); + shell_content = e_shell_view_get_shell_content (shell_view); + + if (what) { + e_alert_submit ( + E_ALERT_SINK (shell_content), + "mail:async-error", what, + message, NULL); + } else + e_alert_submit ( + E_ALERT_SINK (shell_content), + "mail:async-error-nodescribe", + message, NULL); +} + static void mail_backend_constructed (GObject *object) { @@ -777,7 +906,11 @@ mail_backend_constructed (GObject *object) camel_provider_init (); - priv->session = e_mail_session_new (); + priv->session = e_mail_ui_session_new (); + + g_signal_connect ( + priv->session, "flush-outbox", + G_CALLBACK (mail_send), priv->session); g_object_bind_property ( shell, "online", @@ -805,6 +938,16 @@ mail_backend_constructed (GObject *object) * Give EAccountComboBox a CamelSession property. */ e_account_combo_box_set_session (CAMEL_SESSION (priv->session)); + g_signal_connect ( + priv->session, "store-added", + G_CALLBACK (mail_backend_add_store), + shell_backend); + + g_signal_connect ( + priv->session, "store-removed", + G_CALLBACK (mail_backend_remove_store), + shell_backend); + g_signal_connect ( shell, "prepare-for-offline", G_CALLBACK (mail_backend_prepare_for_offline_cb), @@ -844,6 +987,14 @@ mail_backend_constructed (GObject *object) mail_config_init (priv->session); mail_msg_init (); + mail_msg_register_activities ( + mail_mt_create_activity, + mail_mt_submit_activity, + mail_mt_free_activity, + mail_mt_complete_acitivity, + mail_mt_cancel_activity, + mail_mt_alert_error); + /* Chain up to parent's constructed() method. */ G_OBJECT_CLASS (e_mail_backend_parent_class)->constructed (object); } diff --git a/mail/e-mail-backend.h b/mail/e-mail-backend.h index 6279d3fb5e..b44b330a9f 100644 --- a/mail/e-mail-backend.h +++ b/mail/e-mail-backend.h @@ -26,8 +26,8 @@ #ifndef E_MAIL_BACKEND_H #define E_MAIL_BACKEND_H -#include #include +#include /* Standard GObject macros */ #define E_TYPE_MAIL_BACKEND \ diff --git a/mail/e-mail-enums.h b/mail/e-mail-enums.h deleted file mode 100644 index e0ad3ad86f..0000000000 --- a/mail/e-mail-enums.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * e-mail-enums.h - * - * 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 - * - */ - -#ifndef E_MAIL_ENUMS_H -#define E_MAIL_ENUMS_H - -#include - -G_BEGIN_DECLS - -typedef enum { - E_MAIL_DISPLAY_STYLE_NORMAL, - E_MAIL_DISPLAY_STYLE_FULL_HEADERS, - E_MAIL_DISPLAY_STYLE_SOURCE -} EMailDisplayStyle; - -typedef enum { - E_MAIL_FORWARD_STYLE_ATTACHED, - E_MAIL_FORWARD_STYLE_INLINE, - E_MAIL_FORWARD_STYLE_QUOTED -} EMailForwardStyle; - -typedef enum { - E_MAIL_IMAGE_LOADING_POLICY_NEVER, - E_MAIL_IMAGE_LOADING_POLICY_SOMETIMES, - E_MAIL_IMAGE_LOADING_POLICY_ALWAYS -} EMailImageLoadingPolicy; - -/* XXX E_MAIL_FOLDER_TEMPLATES is a prime example of why templates - * should be a core feature: the mailer now has to know about - * this specific plugin, which defeats the purpose of plugins. */ -typedef enum { - E_MAIL_LOCAL_FOLDER_INBOX, - E_MAIL_LOCAL_FOLDER_DRAFTS, - E_MAIL_LOCAL_FOLDER_OUTBOX, - E_MAIL_LOCAL_FOLDER_SENT, - E_MAIL_LOCAL_FOLDER_TEMPLATES, - E_MAIL_LOCAL_FOLDER_LOCAL_INBOX, - E_MAIL_NUM_LOCAL_FOLDERS -} EMailLocalFolder; - -typedef enum { - E_MAIL_REPLY_STYLE_QUOTED, - E_MAIL_REPLY_STYLE_DO_NOT_QUOTE, - E_MAIL_REPLY_STYLE_ATTACH, - E_MAIL_REPLY_STYLE_OUTLOOK -} EMailReplyStyle; - -typedef enum { - E_MAIL_REPLY_TO_SENDER, - E_MAIL_REPLY_TO_RECIPIENT, - E_MAIL_REPLY_TO_FROM, - E_MAIL_REPLY_TO_ALL, - E_MAIL_REPLY_TO_LIST -} EMailReplyType; - -G_END_DECLS - -#endif /* E_MAIL_ENUMS_H */ diff --git a/mail/e-mail-folder-pane.c b/mail/e-mail-folder-pane.c index 277228071e..7e0457e3bd 100644 --- a/mail/e-mail-folder-pane.c +++ b/mail/e-mail-folder-pane.c @@ -30,18 +30,22 @@ #include "e-util/e-util.h" #include "e-util/e-plugin-ui.h" + #include "shell/e-shell.h" #include "shell/e-shell-utils.h" + #include "widgets/misc/e-popup-action.h" #include "widgets/misc/e-preview-pane.h" +#include "libemail-engine/e-mail-utils.h" +#include "libemail-engine/mail-tools.h" + #include "mail/e-mail-reader.h" #include "mail/e-mail-reader-utils.h" #include "mail/em-folder-tree-model.h" #include "mail/em-format-html-display.h" #include "mail/em-composer-utils.h" #include "mail/em-utils.h" -#include "mail/mail-tools.h" #include "mail/message-list.h" #define E_MAIL_FOLDER_PANE_GET_PRIVATE(obj) \ diff --git a/mail/e-mail-folder-utils.c b/mail/e-mail-folder-utils.c deleted file mode 100644 index fe093adb21..0000000000 --- a/mail/e-mail-folder-utils.c +++ /dev/null @@ -1,1666 +0,0 @@ -/* - * e-mail-folder-utils.c - * - * 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 - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "e-mail-folder-utils.h" - -#include - -#include "mail/mail-tools.h" - -/* X-Mailer header value */ -#define X_MAILER ("Evolution " VERSION SUB_VERSION " " VERSION_COMMENT) - -typedef struct _AsyncContext AsyncContext; - -struct _AsyncContext { - CamelMimeMessage *message; - CamelMessageInfo *info; - CamelMimePart *part; - GHashTable *hash_table; - GPtrArray *ptr_array; - GFile *destination; - gchar *fwd_subject; - gchar *message_uid; -}; - -static void -async_context_free (AsyncContext *context) -{ - if (context->message != NULL) - g_object_unref (context->message); - - if (context->info != NULL) - camel_message_info_free (context->info); - - if (context->part != NULL) - g_object_unref (context->part); - - if (context->hash_table != NULL) - g_hash_table_unref (context->hash_table); - - if (context->ptr_array != NULL) - g_ptr_array_unref (context->ptr_array); - - if (context->destination != NULL) - g_object_unref (context->destination); - - g_free (context->fwd_subject); - g_free (context->message_uid); - - g_slice_free (AsyncContext, context); -} - -static void -mail_folder_append_message_thread (GSimpleAsyncResult *simple, - GObject *object, - GCancellable *cancellable) -{ - AsyncContext *context; - GError *error = NULL; - - context = g_simple_async_result_get_op_res_gpointer (simple); - - e_mail_folder_append_message_sync ( - CAMEL_FOLDER (object), context->message, - context->info, &context->message_uid, - cancellable, &error); - - if (error != NULL) - g_simple_async_result_take_error (simple, error); -} - -gboolean -e_mail_folder_append_message_sync (CamelFolder *folder, - CamelMimeMessage *message, - CamelMessageInfo *info, - gchar **appended_uid, - GCancellable *cancellable, - GError **error) -{ - CamelMedium *medium; - gboolean success; - - g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); - g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), FALSE); - - medium = CAMEL_MEDIUM (message); - - camel_operation_push_message ( - cancellable, - _("Saving message to folder '%s'"), - camel_folder_get_full_name (folder)); - - if (camel_medium_get_header (medium, "X-Mailer") == NULL) - camel_medium_set_header (medium, "X-Mailer", X_MAILER); - - camel_mime_message_set_date (message, CAMEL_MESSAGE_DATE_CURRENT, 0); - - success = camel_folder_append_message_sync ( - folder, message, info, appended_uid, cancellable, error); - - camel_operation_pop_message (cancellable); - - return success; -} - -void -e_mail_folder_append_message (CamelFolder *folder, - CamelMimeMessage *message, - CamelMessageInfo *info, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *simple; - AsyncContext *context; - - g_return_if_fail (CAMEL_IS_FOLDER (folder)); - g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message)); - - context = g_slice_new0 (AsyncContext); - context->message = g_object_ref (message); - - if (info != NULL) - context->info = camel_message_info_ref (info); - - simple = g_simple_async_result_new ( - G_OBJECT (folder), callback, user_data, - e_mail_folder_append_message); - - g_simple_async_result_set_op_res_gpointer ( - simple, context, (GDestroyNotify) async_context_free); - - g_simple_async_result_run_in_thread ( - simple, mail_folder_append_message_thread, - io_priority, cancellable); - - g_object_unref (simple); -} - -gboolean -e_mail_folder_append_message_finish (CamelFolder *folder, - GAsyncResult *result, - gchar **appended_uid, - GError **error) -{ - GSimpleAsyncResult *simple; - AsyncContext *context; - - g_return_val_if_fail ( - g_simple_async_result_is_valid ( - result, G_OBJECT (folder), - e_mail_folder_append_message), FALSE); - - simple = G_SIMPLE_ASYNC_RESULT (result); - context = g_simple_async_result_get_op_res_gpointer (simple); - - if (appended_uid != NULL) { - *appended_uid = context->message_uid; - context->message_uid = NULL; - } - - /* Assume success unless a GError is set. */ - return !g_simple_async_result_propagate_error (simple, error); -} - -static void -mail_folder_build_attachment_thread (GSimpleAsyncResult *simple, - GObject *object, - GCancellable *cancellable) -{ - AsyncContext *context; - GError *error = NULL; - - context = g_simple_async_result_get_op_res_gpointer (simple); - - context->part = e_mail_folder_build_attachment_sync ( - CAMEL_FOLDER (object), context->ptr_array, - &context->fwd_subject, cancellable, &error); - - if (error != NULL) - g_simple_async_result_take_error (simple, error); -} - -CamelMimePart * -e_mail_folder_build_attachment_sync (CamelFolder *folder, - GPtrArray *message_uids, - gchar **fwd_subject, - GCancellable *cancellable, - GError **error) -{ - GHashTable *hash_table; - CamelMimeMessage *message; - CamelMimePart *part; - const gchar *uid; - - g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL); - g_return_val_if_fail (message_uids != NULL, NULL); - - /* Need at least one message UID to make an attachment. */ - g_return_val_if_fail (message_uids->len > 0, NULL); - - hash_table = e_mail_folder_get_multiple_messages_sync ( - folder, message_uids, cancellable, error); - - if (hash_table == NULL) - return NULL; - - /* Create the forward subject from the first message. */ - - uid = g_ptr_array_index (message_uids, 0); - g_return_val_if_fail (uid != NULL, NULL); - - message = g_hash_table_lookup (hash_table, uid); - g_return_val_if_fail (message != NULL, NULL); - - if (fwd_subject != NULL) - *fwd_subject = mail_tool_generate_forward_subject (message); - - if (message_uids->len == 1) { - part = mail_tool_make_message_attachment (message); - - } else { - CamelMultipart *multipart; - guint ii; - - multipart = camel_multipart_new (); - camel_data_wrapper_set_mime_type ( - CAMEL_DATA_WRAPPER (multipart), "multipart/digest"); - camel_multipart_set_boundary (multipart, NULL); - - for (ii = 0; ii < message_uids->len; ii++) { - uid = g_ptr_array_index (message_uids, ii); - g_return_val_if_fail (uid != NULL, NULL); - - message = g_hash_table_lookup (hash_table, uid); - g_return_val_if_fail (message != NULL, NULL); - - part = mail_tool_make_message_attachment (message); - camel_multipart_add_part (multipart, part); - g_object_unref (part); - } - - part = camel_mime_part_new (); - - camel_medium_set_content ( - CAMEL_MEDIUM (part), - CAMEL_DATA_WRAPPER (multipart)); - - camel_mime_part_set_description ( - part, _("Forwarded messages")); - - g_object_unref (multipart); - } - - g_hash_table_unref (hash_table); - - return part; -} - -void -e_mail_folder_build_attachment (CamelFolder *folder, - GPtrArray *message_uids, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *simple; - AsyncContext *context; - - g_return_if_fail (CAMEL_IS_FOLDER (folder)); - g_return_if_fail (message_uids != NULL); - - /* Need at least one message UID to make an attachment. */ - g_return_if_fail (message_uids->len > 0); - - context = g_slice_new0 (AsyncContext); - context->ptr_array = g_ptr_array_ref (message_uids); - - simple = g_simple_async_result_new ( - G_OBJECT (folder), callback, user_data, - e_mail_folder_build_attachment); - - g_simple_async_result_set_op_res_gpointer ( - simple, context, (GDestroyNotify) async_context_free); - - g_simple_async_result_run_in_thread ( - simple, mail_folder_build_attachment_thread, - io_priority, cancellable); - - g_object_unref (simple); -} - -CamelMimePart * -e_mail_folder_build_attachment_finish (CamelFolder *folder, - GAsyncResult *result, - gchar **fwd_subject, - GError **error) -{ - GSimpleAsyncResult *simple; - AsyncContext *context; - - g_return_val_if_fail ( - g_simple_async_result_is_valid ( - result, G_OBJECT (folder), - e_mail_folder_build_attachment), NULL); - - simple = G_SIMPLE_ASYNC_RESULT (result); - context = g_simple_async_result_get_op_res_gpointer (simple); - - if (g_simple_async_result_propagate_error (simple, error)) - return NULL; - - if (fwd_subject != NULL) { - *fwd_subject = context->fwd_subject; - context->fwd_subject = NULL; - } - - g_return_val_if_fail (CAMEL_IS_MIME_PART (context->part), NULL); - - return g_object_ref (context->part); -} - -static void -mail_folder_find_duplicate_messages_thread (GSimpleAsyncResult *simple, - GObject *object, - GCancellable *cancellable) -{ - AsyncContext *context; - GError *error = NULL; - - context = g_simple_async_result_get_op_res_gpointer (simple); - - context->hash_table = e_mail_folder_find_duplicate_messages_sync ( - CAMEL_FOLDER (object), context->ptr_array, - cancellable, &error); - - if (error != NULL) - g_simple_async_result_take_error (simple, error); -} - -GHashTable * -e_mail_folder_find_duplicate_messages_sync (CamelFolder *folder, - GPtrArray *message_uids, - GCancellable *cancellable, - GError **error) -{ - GQueue trash = G_QUEUE_INIT; - GHashTable *hash_table; - GHashTable *unique_ids; - GHashTableIter iter; - gpointer key, value; - - g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL); - g_return_val_if_fail (message_uids != NULL, NULL); - - /* hash_table = { MessageUID : CamelMessage } */ - hash_table = e_mail_folder_get_multiple_messages_sync ( - folder, message_uids, cancellable, error); - - if (hash_table == NULL) - return NULL; - - camel_operation_push_message ( - cancellable, _("Scanning messages for duplicates")); - - unique_ids = g_hash_table_new_full ( - (GHashFunc) g_int64_hash, - (GEqualFunc) g_int64_equal, - (GDestroyNotify) g_free, - (GDestroyNotify) g_free); - - g_hash_table_iter_init (&iter, hash_table); - - while (g_hash_table_iter_next (&iter, &key, &value)) { - const CamelSummaryMessageID *message_id; - CamelDataWrapper *content; - CamelMessageFlags flags; - CamelMessageInfo *info; - CamelStream *stream; - GByteArray *buffer; - gboolean duplicate; - gssize n_bytes; - gchar *digest; - - info = camel_folder_get_message_info (folder, key); - message_id = camel_message_info_message_id (info); - flags = camel_message_info_flags (info); - - /* Skip messages marked for deletion. */ - if (flags & CAMEL_MESSAGE_DELETED) { - g_queue_push_tail (&trash, key); - camel_message_info_free (info); - continue; - } - - /* Generate a digest string from the message's content. */ - - content = camel_medium_get_content (CAMEL_MEDIUM (value)); - - if (content == NULL) { - g_queue_push_tail (&trash, key); - camel_message_info_free (info); - continue; - } - - stream = camel_stream_mem_new (); - - n_bytes = camel_data_wrapper_decode_to_stream_sync ( - content, stream, cancellable, error); - - if (n_bytes < 0) { - camel_message_info_free (info); - g_object_unref (stream); - goto fail; - } - - /* The CamelStreamMem owns the buffer. */ - buffer = camel_stream_mem_get_byte_array ( - CAMEL_STREAM_MEM (stream)); - g_return_val_if_fail (buffer != NULL, NULL); - - digest = g_compute_checksum_for_data ( - G_CHECKSUM_SHA256, buffer->data, buffer->len); - - g_object_unref (stream); - - /* Determine if the message a duplicate. */ - - value = g_hash_table_lookup (unique_ids, &message_id->id.id); - duplicate = (value != NULL) && g_str_equal (digest, value); - - if (duplicate) - g_free (digest); - else { - gint64 *v_int64; - - /* XXX Might be better to create a GArray - * of 64-bit integers and have the hash - * table keys point to array elements. */ - v_int64 = g_new0 (gint64, 1); - *v_int64 = (gint64) message_id->id.id; - - g_hash_table_insert (unique_ids, v_int64, digest); - g_queue_push_tail (&trash, key); - } - - camel_message_info_free (info); - } - - /* Delete all non-duplicate messages from the hash table. */ - while ((key = g_queue_pop_head (&trash)) != NULL) - g_hash_table_remove (hash_table, key); - - goto exit; - -fail: - g_hash_table_destroy (hash_table); - hash_table = NULL; - -exit: - camel_operation_pop_message (cancellable); - - g_hash_table_destroy (unique_ids); - - return hash_table; -} - -void -e_mail_folder_find_duplicate_messages (CamelFolder *folder, - GPtrArray *message_uids, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *simple; - AsyncContext *context; - - g_return_if_fail (CAMEL_IS_FOLDER (folder)); - g_return_if_fail (message_uids != NULL); - - context = g_slice_new0 (AsyncContext); - context->ptr_array = g_ptr_array_ref (message_uids); - - simple = g_simple_async_result_new ( - G_OBJECT (folder), callback, user_data, - e_mail_folder_find_duplicate_messages); - - g_simple_async_result_set_op_res_gpointer ( - simple, context, (GDestroyNotify) async_context_free); - - g_simple_async_result_run_in_thread ( - simple, mail_folder_find_duplicate_messages_thread, - io_priority, cancellable); - - g_object_unref (simple); -} - -GHashTable * -e_mail_folder_find_duplicate_messages_finish (CamelFolder *folder, - GAsyncResult *result, - GError **error) -{ - GSimpleAsyncResult *simple; - AsyncContext *context; - - g_return_val_if_fail ( - g_simple_async_result_is_valid ( - result, G_OBJECT (folder), - e_mail_folder_find_duplicate_messages), NULL); - - simple = G_SIMPLE_ASYNC_RESULT (result); - context = g_simple_async_result_get_op_res_gpointer (simple); - - if (g_simple_async_result_propagate_error (simple, error)) - return NULL; - - return g_hash_table_ref (context->hash_table); -} - -static void -mail_folder_get_multiple_messages_thread (GSimpleAsyncResult *simple, - GObject *object, - GCancellable *cancellable) -{ - AsyncContext *context; - GError *error = NULL; - - context = g_simple_async_result_get_op_res_gpointer (simple); - - context->hash_table = e_mail_folder_get_multiple_messages_sync ( - CAMEL_FOLDER (object), context->ptr_array, - cancellable, &error); - - if (error != NULL) - g_simple_async_result_take_error (simple, error); -} - -GHashTable * -e_mail_folder_get_multiple_messages_sync (CamelFolder *folder, - GPtrArray *message_uids, - GCancellable *cancellable, - GError **error) -{ - GHashTable *hash_table; - CamelMimeMessage *message; - guint ii; - - g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL); - g_return_val_if_fail (message_uids != NULL, NULL); - - camel_operation_push_message ( - cancellable, - ngettext ( - "Retrieving %d message", - "Retrieving %d messages", - message_uids->len), - message_uids->len); - - hash_table = g_hash_table_new_full ( - (GHashFunc) g_str_hash, - (GEqualFunc) g_str_equal, - (GDestroyNotify) g_free, - (GDestroyNotify) g_object_unref); - - /* This is an all or nothing operation. Destroy the - * hash table if we fail to retrieve any message. */ - - for (ii = 0; ii < message_uids->len; ii++) { - const gchar *uid; - gint percent; - - uid = g_ptr_array_index (message_uids, ii); - percent = ((ii + 1) * 100) / message_uids->len; - - message = camel_folder_get_message_sync ( - folder, uid, cancellable, error); - - camel_operation_progress (cancellable, percent); - - if (CAMEL_IS_MIME_MESSAGE (message)) { - g_hash_table_insert ( - hash_table, g_strdup (uid), message); - } else { - g_hash_table_destroy (hash_table); - hash_table = NULL; - break; - } - } - - camel_operation_pop_message (cancellable); - - return hash_table; -} - -void -e_mail_folder_get_multiple_messages (CamelFolder *folder, - GPtrArray *message_uids, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *simple; - AsyncContext *context; - - g_return_if_fail (CAMEL_IS_FOLDER (folder)); - g_return_if_fail (message_uids != NULL); - - context = g_slice_new0 (AsyncContext); - context->ptr_array = g_ptr_array_ref (message_uids); - - simple = g_simple_async_result_new ( - G_OBJECT (folder), callback, user_data, - e_mail_folder_get_multiple_messages); - - g_simple_async_result_set_op_res_gpointer ( - simple, context, (GDestroyNotify) async_context_free); - - g_simple_async_result_run_in_thread ( - simple, mail_folder_get_multiple_messages_thread, - io_priority, cancellable); - - g_object_unref (simple); -} - -GHashTable * -e_mail_folder_get_multiple_messages_finish (CamelFolder *folder, - GAsyncResult *result, - GError **error) -{ - GSimpleAsyncResult *simple; - AsyncContext *context; - - g_return_val_if_fail ( - g_simple_async_result_is_valid ( - result, G_OBJECT (folder), - e_mail_folder_get_multiple_messages), NULL); - - simple = G_SIMPLE_ASYNC_RESULT (result); - context = g_simple_async_result_get_op_res_gpointer (simple); - - if (g_simple_async_result_propagate_error (simple, error)) - return NULL; - - return g_hash_table_ref (context->hash_table); -} - -static void -mail_folder_remove_thread (GSimpleAsyncResult *simple, - GObject *object, - GCancellable *cancellable) -{ - GError *error = NULL; - - e_mail_folder_remove_sync ( - CAMEL_FOLDER (object), cancellable, &error); - - if (error != NULL) - g_simple_async_result_take_error (simple, error); -} - -static gboolean -mail_folder_remove_recursive (CamelStore *store, - CamelFolderInfo *folder_info, - GCancellable *cancellable, - GError **error) -{ - gboolean success = TRUE; - - while (folder_info != NULL) { - CamelFolder *folder; - - if (folder_info->child != NULL) { - success = mail_folder_remove_recursive ( - store, folder_info->child, cancellable, error); - if (!success) - break; - } - - folder = camel_store_get_folder_sync ( - store, folder_info->full_name, 0, cancellable, error); - if (folder == NULL) { - success = FALSE; - break; - } - - if (!CAMEL_IS_VEE_FOLDER (folder)) { - GPtrArray *uids; - guint ii; - - /* Delete every message in this folder, - * then expunge it. */ - - camel_folder_freeze (folder); - - uids = camel_folder_get_uids (folder); - - for (ii = 0; ii < uids->len; ii++) - camel_folder_delete_message ( - folder, uids->pdata[ii]); - - camel_folder_free_uids (folder, uids); - - success = camel_folder_synchronize_sync ( - folder, TRUE, cancellable, error); - - camel_folder_thaw (folder); - } - - g_object_unref (folder); - - if (!success) - break; - - /* If the store supports subscriptions, - * then unsubscribe from this folder. */ - if (CAMEL_IS_SUBSCRIBABLE (store)) { - success = camel_subscribable_unsubscribe_folder_sync ( - CAMEL_SUBSCRIBABLE (store), - folder_info->full_name, - cancellable, error); - if (!success) - break; - } - - success = camel_store_delete_folder_sync ( - store, folder_info->full_name, cancellable, error); - if (!success) - break; - - folder_info = folder_info->next; - } - - return success; -} - -static void -follow_cancel_cb (GCancellable *cancellable, - GCancellable *transparent_cancellable) -{ - g_cancellable_cancel (transparent_cancellable); -} - -gboolean -e_mail_folder_remove_sync (CamelFolder *folder, - GCancellable *cancellable, - GError **error) -{ - CamelFolderInfo *folder_info; - CamelFolderInfo *to_remove; - CamelFolderInfo *next = NULL; - CamelStore *parent_store; - const gchar *full_name; - gboolean success = TRUE; - GCancellable *transparent_cancellable = NULL; - gulong cbid = 0; - - g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); - - full_name = camel_folder_get_full_name (folder); - parent_store = camel_folder_get_parent_store (folder); - - folder_info = camel_store_get_folder_info_sync ( - parent_store, full_name, - CAMEL_STORE_FOLDER_INFO_FAST | - CAMEL_STORE_FOLDER_INFO_RECURSIVE | - CAMEL_STORE_FOLDER_INFO_SUBSCRIBED, - cancellable, error); - - if (folder_info == NULL) - return FALSE; - - to_remove = folder_info; - - /* For cases when the top-level folder_info contains siblings, - * such as when full_name contains a wildcard letter, compare - * the folder name against folder_info->full_name to avoid - * removing more folders than requested. */ - if (folder_info->next != NULL) { - while (to_remove != NULL) { - if (g_strcmp0 (to_remove->full_name, full_name) == 0) - break; - to_remove = to_remove->next; - } - - /* XXX Should we set a GError and return FALSE here? */ - if (to_remove == NULL) { - g_warning ( - "%s: Failed to find folder '%s'", - G_STRFUNC, full_name); - camel_store_free_folder_info ( - parent_store, folder_info); - return TRUE; - } - - /* Prevent iterating over siblings. */ - next = to_remove->next; - to_remove->next = NULL; - } - - camel_operation_push_message ( - cancellable, _("Removing folder '%s'"), - camel_folder_get_full_name (folder)); - - if (cancellable) { - transparent_cancellable = g_cancellable_new (); - cbid = g_cancellable_connect (cancellable, G_CALLBACK (follow_cancel_cb), transparent_cancellable, NULL); - } - - success = mail_folder_remove_recursive ( - parent_store, to_remove, transparent_cancellable, error); - - if (transparent_cancellable) { - g_cancellable_disconnect (cancellable, cbid); - g_object_unref (transparent_cancellable); - } - - camel_operation_pop_message (cancellable); - - /* Restore the folder_info tree to its original - * state so we don't leak folder_info nodes. */ - to_remove->next = next; - - camel_store_free_folder_info (parent_store, folder_info); - - return success; -} - -void -e_mail_folder_remove (CamelFolder *folder, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *simple; - - g_return_if_fail (CAMEL_IS_FOLDER (folder)); - - simple = g_simple_async_result_new ( - G_OBJECT (folder), callback, - user_data, e_mail_folder_remove); - - g_simple_async_result_run_in_thread ( - simple, mail_folder_remove_thread, - io_priority, cancellable); - - g_object_unref (simple); -} - -gboolean -e_mail_folder_remove_finish (CamelFolder *folder, - GAsyncResult *result, - GError **error) -{ - GSimpleAsyncResult *simple; - - g_return_val_if_fail ( - g_simple_async_result_is_valid ( - result, G_OBJECT (folder), - e_mail_folder_remove), FALSE); - - simple = G_SIMPLE_ASYNC_RESULT (result); - - /* Assume success unless a GError is set. */ - return !g_simple_async_result_propagate_error (simple, error); -} - -static void -mail_folder_remove_attachments_thread (GSimpleAsyncResult *simple, - GObject *object, - GCancellable *cancellable) -{ - AsyncContext *context; - GError *error = NULL; - - context = g_simple_async_result_get_op_res_gpointer (simple); - - e_mail_folder_remove_attachments_sync ( - CAMEL_FOLDER (object), context->ptr_array, - cancellable, &error); - - if (error != NULL) - g_simple_async_result_take_error (simple, error); -} - -/* Helper for e_mail_folder_remove_attachments_sync() */ -static gboolean -mail_folder_strip_message (CamelFolder *folder, - CamelMimeMessage *message, - const gchar *message_uid, - GCancellable *cancellable, - GError **error) -{ - CamelDataWrapper *content; - CamelMultipart *multipart; - gboolean modified = FALSE; - gboolean success = TRUE; - guint ii, n_parts; - - content = camel_medium_get_content (CAMEL_MEDIUM (message)); - - if (!CAMEL_IS_MULTIPART (content)) - return TRUE; - - multipart = CAMEL_MULTIPART (content); - n_parts = camel_multipart_get_number (multipart); - - /* Replace MIME parts with "attachment" or "inline" dispositions - * with a small "text/plain" part saying the file was removed. */ - for (ii = 0; ii < n_parts; ii++) { - CamelMimePart *mime_part; - const gchar *disposition; - gboolean is_attachment; - - mime_part = camel_multipart_get_part (multipart, ii); - disposition = camel_mime_part_get_disposition (mime_part); - - is_attachment = - (g_strcmp0 (disposition, "attachment") == 0) || - (g_strcmp0 (disposition, "inline") == 0); - - if (is_attachment) { - const gchar *filename; - const gchar *content_type; - gchar *content; - - disposition = "inline"; - content_type = "text/plain"; - filename = camel_mime_part_get_filename (mime_part); - - if (filename != NULL && *filename != '\0') - content = g_strdup_printf ( - _("File \"%s\" has been removed."), - filename); - else - content = g_strdup ( - _("File has been removed.")); - - camel_mime_part_set_content ( - mime_part, content, - strlen (content), content_type); - camel_mime_part_set_content_type ( - mime_part, content_type); - camel_mime_part_set_disposition ( - mime_part, disposition); - - modified = TRUE; - } - } - - /* Append the modified message with removed attachments to - * the folder and mark the original message for deletion. */ - if (modified) { - CamelMessageInfo *orig_info; - CamelMessageInfo *copy_info; - CamelMessageFlags flags; - - orig_info = - camel_folder_get_message_info (folder, message_uid); - copy_info = - camel_message_info_new_from_header ( - NULL, CAMEL_MIME_PART (message)->headers); - - flags = camel_folder_get_message_flags (folder, message_uid); - camel_message_info_set_flags (copy_info, flags, flags); - - success = camel_folder_append_message_sync ( - folder, message, copy_info, NULL, cancellable, error); - if (success) - camel_message_info_set_flags ( - orig_info, - CAMEL_MESSAGE_DELETED, - CAMEL_MESSAGE_DELETED); - - camel_folder_free_message_info (folder, orig_info); - camel_message_info_free (copy_info); - } - - return success; -} - -gboolean -e_mail_folder_remove_attachments_sync (CamelFolder *folder, - GPtrArray *message_uids, - GCancellable *cancellable, - GError **error) -{ - gboolean success = TRUE; - guint ii; - - g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); - g_return_val_if_fail (message_uids != NULL, FALSE); - - camel_folder_freeze (folder); - - camel_operation_push_message (cancellable, _("Removing attachments")); - - for (ii = 0; success && ii < message_uids->len; ii++) { - CamelMimeMessage *message; - const gchar *uid; - gint percent; - - uid = g_ptr_array_index (message_uids, ii); - - message = camel_folder_get_message_sync ( - folder, uid, cancellable, error); - - if (message == NULL) { - success = FALSE; - break; - } - - success = mail_folder_strip_message ( - folder, message, uid, cancellable, error); - - percent = ((ii + 1) * 100) / message_uids->len; - camel_operation_progress (cancellable, percent); - - g_object_unref (message); - } - - camel_operation_pop_message (cancellable); - - if (success) - camel_folder_synchronize_sync ( - folder, FALSE, cancellable, error); - - camel_folder_thaw (folder); - - return success; -} - -void -e_mail_folder_remove_attachments (CamelFolder *folder, - GPtrArray *message_uids, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *simple; - AsyncContext *context; - - g_return_if_fail (CAMEL_IS_FOLDER (folder)); - g_return_if_fail (message_uids != NULL); - - context = g_slice_new0 (AsyncContext); - context->ptr_array = g_ptr_array_ref (message_uids); - - simple = g_simple_async_result_new ( - G_OBJECT (folder), callback, user_data, - e_mail_folder_remove_attachments); - - g_simple_async_result_set_op_res_gpointer ( - simple, context, (GDestroyNotify) async_context_free); - - g_simple_async_result_run_in_thread ( - simple, mail_folder_remove_attachments_thread, - io_priority, cancellable); - - g_object_unref (simple); -} - -gboolean -e_mail_folder_remove_attachments_finish (CamelFolder *folder, - GAsyncResult *result, - GError **error) -{ - GSimpleAsyncResult *simple; - - g_return_val_if_fail ( - g_simple_async_result_is_valid ( - result, G_OBJECT (folder), - e_mail_folder_remove_attachments), FALSE); - - simple = G_SIMPLE_ASYNC_RESULT (result); - - /* Assume success unless a GError is set. */ - return !g_simple_async_result_propagate_error (simple, error); -} - -static void -mail_folder_save_messages_thread (GSimpleAsyncResult *simple, - GObject *object, - GCancellable *cancellable) -{ - AsyncContext *context; - GError *error = NULL; - - context = g_simple_async_result_get_op_res_gpointer (simple); - - e_mail_folder_save_messages_sync ( - CAMEL_FOLDER (object), context->ptr_array, - context->destination, cancellable, &error); - - if (error != NULL) - g_simple_async_result_take_error (simple, error); -} - -/* Helper for e_mail_folder_save_messages_sync() */ -static void -mail_folder_save_prepare_part (CamelMimePart *mime_part) -{ - CamelDataWrapper *content; - - content = camel_medium_get_content (CAMEL_MEDIUM (mime_part)); - - if (content == NULL) - return; - - if (CAMEL_IS_MULTIPART (content)) { - guint n_parts, ii; - - n_parts = camel_multipart_get_number ( - CAMEL_MULTIPART (content)); - for (ii = 0; ii < n_parts; ii++) { - mime_part = camel_multipart_get_part ( - CAMEL_MULTIPART (content), ii); - mail_folder_save_prepare_part (mime_part); - } - - } else if (CAMEL_IS_MIME_MESSAGE (content)) { - mail_folder_save_prepare_part (CAMEL_MIME_PART (content)); - - } else { - CamelContentType *type; - - /* Save textual parts as 8-bit, not encoded. */ - type = camel_data_wrapper_get_mime_type_field (content); - if (camel_content_type_is (type, "text", "*")) - camel_mime_part_set_encoding ( - mime_part, CAMEL_TRANSFER_ENCODING_8BIT); - } -} - -gboolean -e_mail_folder_save_messages_sync (CamelFolder *folder, - GPtrArray *message_uids, - GFile *destination, - GCancellable *cancellable, - GError **error) -{ - GFileOutputStream *file_output_stream; - GByteArray *byte_array; - CamelStream *base_stream; - gboolean success = TRUE; - guint ii; - - g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); - g_return_val_if_fail (message_uids != NULL, FALSE); - g_return_val_if_fail (G_IS_FILE (destination), FALSE); - - /* Need at least one message UID to save. */ - g_return_val_if_fail (message_uids->len > 0, FALSE); - - camel_operation_push_message ( - cancellable, ngettext ( - "Saving %d message", - "Saving %d messages", - message_uids->len), - message_uids->len); - - file_output_stream = g_file_replace ( - destination, NULL, FALSE, - G_FILE_CREATE_PRIVATE | - G_FILE_CREATE_REPLACE_DESTINATION, - cancellable, error); - - if (file_output_stream == NULL) { - camel_operation_pop_message (cancellable); - return FALSE; - } - - /* CamelStreamMem takes ownership of the GByteArray. */ - byte_array = g_byte_array_new (); - base_stream = camel_stream_mem_new_with_byte_array (byte_array); - - for (ii = 0; ii < message_uids->len; ii++) { - CamelMimeMessage *message; - CamelMimeFilter *filter; - CamelStream *stream; - const gchar *uid; - gchar *from_line; - gint percent; - gint retval; - - uid = g_ptr_array_index (message_uids, ii); - - message = camel_folder_get_message_sync ( - folder, uid, cancellable, error); - if (message == NULL) { - success = FALSE; - goto exit; - } - - mail_folder_save_prepare_part (CAMEL_MIME_PART (message)); - - from_line = camel_mime_message_build_mbox_from (message); - g_return_val_if_fail (from_line != NULL, FALSE); - - success = g_output_stream_write_all ( - G_OUTPUT_STREAM (file_output_stream), - from_line, strlen (from_line), NULL, - cancellable, error); - - g_free (from_line); - - if (!success) { - g_object_unref (message); - goto exit; - } - - filter = camel_mime_filter_from_new (); - stream = camel_stream_filter_new (base_stream); - camel_stream_filter_add (CAMEL_STREAM_FILTER (stream), filter); - - retval = camel_data_wrapper_write_to_stream_sync ( - CAMEL_DATA_WRAPPER (message), - stream, cancellable, error); - - g_object_unref (filter); - g_object_unref (stream); - - if (retval == -1) { - g_object_unref (message); - goto exit; - } - - g_byte_array_append (byte_array, (guint8 *) "\n", 1); - - success = g_output_stream_write_all ( - G_OUTPUT_STREAM (file_output_stream), - byte_array->data, byte_array->len, - NULL, cancellable, error); - - if (!success) { - g_object_unref (message); - goto exit; - } - - percent = ((ii + 1) * 100) / message_uids->len; - camel_operation_progress (cancellable, percent); - - /* Flush the buffer for the next message. - * For memory streams this never fails. */ - g_seekable_seek ( - G_SEEKABLE (base_stream), - 0, G_SEEK_SET, NULL, NULL); - - g_object_unref (message); - } - -exit: - g_object_unref (file_output_stream); - g_object_unref (base_stream); - - camel_operation_pop_message (cancellable); - - if (!success) { - /* Try deleting the destination file. */ - g_file_delete (destination, NULL, NULL); - } - - return success; -} - -void -e_mail_folder_save_messages (CamelFolder *folder, - GPtrArray *message_uids, - GFile *destination, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *simple; - AsyncContext *context; - - g_return_if_fail (CAMEL_IS_FOLDER (folder)); - g_return_if_fail (message_uids != NULL); - g_return_if_fail (G_IS_FILE (destination)); - - /* Need at least one message UID to save. */ - g_return_if_fail (message_uids->len > 0); - - context = g_slice_new0 (AsyncContext); - context->ptr_array = g_ptr_array_ref (message_uids); - context->destination = g_object_ref (destination); - - simple = g_simple_async_result_new ( - G_OBJECT (folder), callback, user_data, - e_mail_folder_save_messages); - - g_simple_async_result_set_op_res_gpointer ( - simple, context, (GDestroyNotify) async_context_free); - - g_simple_async_result_run_in_thread ( - simple, mail_folder_save_messages_thread, - io_priority, cancellable); - - g_object_unref (simple); -} - -gboolean -e_mail_folder_save_messages_finish (CamelFolder *folder, - GAsyncResult *result, - GError **error) -{ - GSimpleAsyncResult *simple; - - g_return_val_if_fail ( - g_simple_async_result_is_valid ( - result, G_OBJECT (folder), - e_mail_folder_save_messages), FALSE); - - simple = G_SIMPLE_ASYNC_RESULT (result); - - /* Assume success unless a GError is set. */ - return !g_simple_async_result_propagate_error (simple, error); -} - -/** - * e_mail_folder_uri_build: - * @store: a #CamelStore - * @folder_name: a folder name - * - * Builds a folder URI string from @store and @folder_name. - * - * Returns: a newly-allocated folder URI string - **/ -gchar * -e_mail_folder_uri_build (CamelStore *store, - const gchar *folder_name) -{ - const gchar *uid; - gchar *encoded_name; - gchar *encoded_uid; - gchar *uri; - - g_return_val_if_fail (CAMEL_IS_STORE (store), NULL); - g_return_val_if_fail (folder_name != NULL, NULL); - - /* Skip the leading slash, if present. */ - if (*folder_name == '/') - folder_name++; - - uid = camel_service_get_uid (CAMEL_SERVICE (store)); - - encoded_uid = camel_url_encode (uid, ":;@/"); - encoded_name = camel_url_encode (folder_name, "#"); - - uri = g_strdup_printf ("folder://%s/%s", encoded_uid, encoded_name); - - g_free (encoded_uid); - g_free (encoded_name); - - return uri; -} - -/** - * e_mail_folder_uri_parse: - * @session: a #CamelSession - * @folder_uri: a folder URI - * @out_store: return location for a #CamelStore, or %NULL - * @out_folder_name: return location for a folder name, or %NULL - * @error: return location for a #GError, or %NULL - * - * Parses a folder URI generated by e_mail_folder_uri_build() and - * returns the corresponding #CamelStore instance in @out_store and - * folder name string in @out_folder_name. If the URI is malformed - * or no corresponding store exists, the function sets @error and - * returns %FALSE. - * - * If the function is able to parse the URI, the #CamelStore instance - * set in @out_store should be unreferenced with g_object_unref() when - * done with it, and the folder name string set in @out_folder_name - * should be freed with g_free(). - * - * The function also handles older style URIs, such as ones where the - * #CamelStore's #CamelStore::uri string was embedded directly in the - * folder URI, and account-based URIs that used an "email://" prefix. - * - * Returns: %TRUE if @folder_uri could be parsed, %FALSE otherwise - **/ -gboolean -e_mail_folder_uri_parse (CamelSession *session, - const gchar *folder_uri, - CamelStore **out_store, - gchar **out_folder_name, - GError **error) -{ - CamelURL *url; - CamelService *service = NULL; - gchar *folder_name = NULL; - gboolean success = FALSE; - - g_return_val_if_fail (CAMEL_IS_SESSION (session), FALSE); - g_return_val_if_fail (folder_uri != NULL, FALSE); - - url = camel_url_new (folder_uri, error); - if (url == NULL) - return FALSE; - - /* Current URI Format: 'folder://' STORE_UID '/' FOLDER_PATH */ - if (g_strcmp0 (url->protocol, "folder") == 0) { - - if (url->host != NULL) { - gchar *uid; - - if (url->user == NULL || *url->user == '\0') - uid = g_strdup (url->host); - else - uid = g_strconcat ( - url->user, "@", url->host, NULL); - - service = camel_session_get_service (session, uid); - g_free (uid); - } - - if (url->path != NULL && *url->path == '/') - folder_name = camel_url_decode_path (url->path + 1); - - /* This style was used to reference accounts by UID before - * CamelServices themselves had UIDs. Some examples are: - * - * Special cases: - * - * 'email://local@local/' FOLDER_PATH - * 'email://vfolder@local/' FOLDER_PATH - * - * General case: - * - * 'email://' ACCOUNT_UID '/' FOLDER_PATH - * - * Note: ACCOUNT_UID is now equivalent to STORE_UID, and - * the STORE_UIDs for the special cases are 'local' - * and 'vfolder'. - */ - } else if (g_strcmp0 (url->protocol, "email") == 0) { - gchar *uid = NULL; - - /* Handle the special cases. */ - if (g_strcmp0 (url->host, "local") == 0) { - if (g_strcmp0 (url->user, "local") == 0) - uid = g_strdup ("local"); - if (g_strcmp0 (url->user, "vfolder") == 0) - uid = g_strdup ("vfolder"); - } - - /* Handle the general case. */ - if (uid == NULL && url->host != NULL) { - if (url->user == NULL) - uid = g_strdup (url->host); - else - uid = g_strdup_printf ( - "%s@%s", url->user, url->host); - } - - if (uid != NULL) { - service = camel_session_get_service (session, uid); - g_free (uid); - } - - if (url->path != NULL && *url->path == '/') - folder_name = camel_url_decode_path (url->path + 1); - - /* CamelFolderInfo URIs used to embed the store's URI, so the - * folder name is appended as either a path part or a fragment - * part, depending whether the store's URI used the path part. - * To determine which it is, you have to check the provider - * flags for CAMEL_URL_FRAGMENT_IS_PATH. */ - } else { - service = camel_session_get_service_by_url ( - session, url, CAMEL_PROVIDER_STORE); - - if (CAMEL_IS_STORE (service)) { - CamelProvider *provider; - - provider = camel_service_get_provider (service); - - if (provider->url_flags & CAMEL_URL_FRAGMENT_IS_PATH) - folder_name = g_strdup (url->fragment); - else if (url->path != NULL && *url->path == '/') - folder_name = g_strdup (url->path + 1); - } - } - - if (CAMEL_IS_STORE (service) && folder_name != NULL) { - if (out_store != NULL) - *out_store = g_object_ref (service); - - if (out_folder_name != NULL) { - *out_folder_name = folder_name; - folder_name = NULL; - } - - success = TRUE; - } else { - g_set_error ( - error, CAMEL_FOLDER_ERROR, - CAMEL_FOLDER_ERROR_INVALID, - _("Invalid folder URI '%s'"), - folder_uri); - } - - g_free (folder_name); - - camel_url_free (url); - - return success; -} - -/** - * e_mail_folder_uri_equal: - * @session: a #CamelSession - * @folder_uri_a: a folder URI - * @folder_uri_b: another folder URI - * - * Compares two folder URIs for equality. If either URI is invalid, - * the function returns %FALSE. - * - * Returns: %TRUE if the URIs are equal, %FALSE if not - **/ -gboolean -e_mail_folder_uri_equal (CamelSession *session, - const gchar *folder_uri_a, - const gchar *folder_uri_b) -{ - CamelStore *store_a; - CamelStore *store_b; - CamelStoreClass *class; - gchar *folder_name_a; - gchar *folder_name_b; - gboolean success_a; - gboolean success_b; - gboolean equal = FALSE; - - g_return_val_if_fail (CAMEL_IS_SESSION (session), FALSE); - g_return_val_if_fail (folder_uri_a != NULL, FALSE); - g_return_val_if_fail (folder_uri_b != NULL, FALSE); - - success_a = e_mail_folder_uri_parse ( - session, folder_uri_a, &store_a, &folder_name_a, NULL); - - success_b = e_mail_folder_uri_parse ( - session, folder_uri_b, &store_b, &folder_name_b, NULL); - - if (!success_a || !success_b) - goto exit; - - if (store_a != store_b) - goto exit; - - /* Doesn't matter which store we use since they're the same. */ - class = CAMEL_STORE_GET_CLASS (store_a); - g_return_val_if_fail (class->compare_folder_name != NULL, FALSE); - - equal = class->compare_folder_name (folder_name_a, folder_name_b); - -exit: - if (success_a) { - g_object_unref (store_a); - g_free (folder_name_a); - } - - if (success_b) { - g_object_unref (store_b); - g_free (folder_name_b); - } - - return equal; -} - -/** - * e_mail_folder_uri_from_folder: - * @folder: a #CamelFolder - * - * Convenience function for building a folder URI from a #CamelFolder. - * Free the returned URI string with g_free(). - * - * Returns: a newly-allocated folder URI string - **/ -gchar * -e_mail_folder_uri_from_folder (CamelFolder *folder) -{ - CamelStore *store; - const gchar *folder_name; - - g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL); - - store = camel_folder_get_parent_store (folder); - folder_name = camel_folder_get_full_name (folder); - - return e_mail_folder_uri_build (store, folder_name); -} - -/** - * e_mail_folder_uri_to_markup: - * @session: a #CamelSession - * @folder_uri: a folder URI - * @error: return location for a #GError, or %NULL - * - * Converts @folder_uri to a markup string suitable for displaying to users. - * The string consists of the #CamelStore display name (in bold), followed - * by the folder path. If the URI is malformed or no corresponding store - * exists, the function sets @error and returns %NULL. Free the returned - * string with g_free(). - * - * Returns: a newly-allocated markup string, or %NULL - **/ -gchar * -e_mail_folder_uri_to_markup (CamelSession *session, - const gchar *folder_uri, - GError **error) -{ - CamelStore *store = NULL; - const gchar *display_name; - gchar *folder_name = NULL; - gchar *markup; - gboolean success; - - g_return_val_if_fail (CAMEL_IS_SESSION (session), NULL); - g_return_val_if_fail (folder_uri != NULL, NULL); - - success = e_mail_folder_uri_parse ( - session, folder_uri, &store, &folder_name, error); - - if (!success) - return NULL; - - g_return_val_if_fail (CAMEL_IS_STORE (store), NULL); - g_return_val_if_fail (folder_name != NULL, NULL); - - display_name = camel_service_get_display_name (CAMEL_SERVICE (store)); - - markup = g_markup_printf_escaped ( - "%s : %s", display_name, folder_name); - - g_object_unref (store); - g_free (folder_name); - - return markup; -} diff --git a/mail/e-mail-folder-utils.h b/mail/e-mail-folder-utils.h deleted file mode 100644 index 9e8dd0f050..0000000000 --- a/mail/e-mail-folder-utils.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * e-mail-folder-utils.h - * - * 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 - * - */ - -#ifndef E_MAIL_FOLDER_UTILS_H -#define E_MAIL_FOLDER_UTILS_H - -/* CamelFolder wrappers with Evolution-specific policies. */ - -#include - -G_BEGIN_DECLS - -gboolean e_mail_folder_append_message_sync - (CamelFolder *folder, - CamelMimeMessage *message, - CamelMessageInfo *info, - gchar **appended_uid, - GCancellable *cancellable, - GError **error); -void e_mail_folder_append_message (CamelFolder *folder, - CamelMimeMessage *message, - CamelMessageInfo *info, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean e_mail_folder_append_message_finish - (CamelFolder *folder, - GAsyncResult *result, - gchar **appended_uid, - GError **error); - -CamelMimePart * e_mail_folder_build_attachment_sync - (CamelFolder *folder, - GPtrArray *message_uids, - gchar **fwd_subject, - GCancellable *cancellable, - GError **error); -void e_mail_folder_build_attachment (CamelFolder *folder, - GPtrArray *message_uids, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -CamelMimePart * e_mail_folder_build_attachment_finish - (CamelFolder *folder, - GAsyncResult *result, - gchar **fwd_subject, - GError **error); - -GHashTable * e_mail_folder_find_duplicate_messages_sync - (CamelFolder *folder, - GPtrArray *message_uids, - GCancellable *cancellable, - GError **error); -void e_mail_folder_find_duplicate_messages - (CamelFolder *folder, - GPtrArray *message_uids, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -GHashTable * e_mail_folder_find_duplicate_messages_finish - (CamelFolder *folder, - GAsyncResult *result, - GError **error); - -GHashTable * e_mail_folder_get_multiple_messages_sync - (CamelFolder *folder, - GPtrArray *message_uids, - GCancellable *cancellable, - GError **error); -void e_mail_folder_get_multiple_messages - (CamelFolder *folder, - GPtrArray *message_uids, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -GHashTable * e_mail_folder_get_multiple_messages_finish - (CamelFolder *folder, - GAsyncResult *result, - GError **error); - -gboolean e_mail_folder_remove_sync (CamelFolder *folder, - GCancellable *cancellable, - GError **error); -void e_mail_folder_remove (CamelFolder *folder, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean e_mail_folder_remove_finish (CamelFolder *folder, - GAsyncResult *result, - GError **error); - -gboolean e_mail_folder_remove_attachments_sync - (CamelFolder *folder, - GPtrArray *message_uids, - GCancellable *cancellable, - GError **error); -void e_mail_folder_remove_attachments - (CamelFolder *folder, - GPtrArray *message_uids, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean e_mail_folder_remove_attachments_finish - (CamelFolder *folder, - GAsyncResult *result, - GError **error); - -gboolean e_mail_folder_save_messages_sync - (CamelFolder *folder, - GPtrArray *message_uids, - GFile *destination, - GCancellable *cancellable, - GError **error); -void e_mail_folder_save_messages (CamelFolder *folder, - GPtrArray *message_uids, - GFile *destination, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean e_mail_folder_save_messages_finish - (CamelFolder *folder, - GAsyncResult *result, - GError **error); - -gchar * e_mail_folder_uri_build (CamelStore *store, - const gchar *folder_name); -gboolean e_mail_folder_uri_parse (CamelSession *session, - const gchar *folder_uri, - CamelStore **out_store, - gchar **out_folder_name, - GError **error); -gboolean e_mail_folder_uri_equal (CamelSession *session, - const gchar *folder_uri_a, - const gchar *folder_uri_b); -gchar * e_mail_folder_uri_from_folder (CamelFolder *folder); -gchar * e_mail_folder_uri_to_markup (CamelSession *session, - const gchar *folder_uri, - GError **error); - -G_END_DECLS - -#endif /* E_MAIL_FOLDER_UTILS_H */ diff --git a/mail/e-mail-junk-filter.c b/mail/e-mail-junk-filter.c deleted file mode 100644 index 71128013ad..0000000000 --- a/mail/e-mail-junk-filter.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * e-mail-junk-filter.c - * - * 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 - * - */ - -#include "e-mail-junk-filter.h" - -#include - -G_DEFINE_ABSTRACT_TYPE ( - EMailJunkFilter, - e_mail_junk_filter, - E_TYPE_EXTENSION) - -static void -e_mail_junk_filter_class_init (EMailJunkFilterClass *class) -{ - EExtensionClass *extension_class; - - extension_class = E_EXTENSION_CLASS (class); - extension_class->extensible_type = E_TYPE_MAIL_SESSION; -} - -static void -e_mail_junk_filter_init (EMailJunkFilter *junk_filter) -{ -} - -gboolean -e_mail_junk_filter_available (EMailJunkFilter *junk_filter) -{ - EMailJunkFilterClass *class; - - g_return_val_if_fail (E_IS_MAIL_JUNK_FILTER (junk_filter), FALSE); - - class = E_MAIL_JUNK_FILTER_GET_CLASS (junk_filter); - g_return_val_if_fail (class->available != NULL, FALSE); - - return class->available (junk_filter); -} - -GtkWidget * -e_mail_junk_filter_new_config_widget (EMailJunkFilter *junk_filter) -{ - EMailJunkFilterClass *class; - GtkWidget *widget = NULL; - - g_return_val_if_fail (E_IS_MAIL_JUNK_FILTER (junk_filter), NULL); - - class = E_MAIL_JUNK_FILTER_GET_CLASS (junk_filter); - - if (class->new_config_widget != NULL) - widget = class->new_config_widget (junk_filter); - - return widget; -} - -gint -e_mail_junk_filter_compare (EMailJunkFilter *junk_filter_a, - EMailJunkFilter *junk_filter_b) -{ - EMailJunkFilterClass *class_a; - EMailJunkFilterClass *class_b; - - class_a = E_MAIL_JUNK_FILTER_GET_CLASS (junk_filter_a); - class_b = E_MAIL_JUNK_FILTER_GET_CLASS (junk_filter_b); - - return g_utf8_collate (class_a->display_name, class_b->display_name); -} diff --git a/mail/e-mail-junk-filter.h b/mail/e-mail-junk-filter.h deleted file mode 100644 index 74a7840c2d..0000000000 --- a/mail/e-mail-junk-filter.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * e-mail-junk-filter.h - * - * 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 - * - */ - -#ifndef E_MAIL_JUNK_FILTER_H -#define E_MAIL_JUNK_FILTER_H - -#include -#include - -/* Standard GObject macros */ -#define E_TYPE_MAIL_JUNK_FILTER \ - (e_mail_junk_filter_get_type ()) -#define E_MAIL_JUNK_FILTER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST \ - ((obj), E_TYPE_MAIL_JUNK_FILTER, EMailJunkFilter)) -#define E_MAIL_JUNK_FILTER_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_CAST \ - ((cls), E_TYPE_MAIL_JUNK_FILTER, EMailJunkFilterClass)) -#define E_IS_MAIL_JUNK_FILTER(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE \ - ((obj), E_TYPE_MAIL_JUNK_FILTER)) -#define E_IS_MAIL_JUNK_FILTER_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_TYPE \ - ((cls), E_TYPE_MAIL_JUNK_FILTER)) -#define E_MAIL_JUNK_FILTER_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS \ - ((obj), E_TYPE_MAIL_JUNK_FILTER, EMailJunkFilterClass)) - -G_BEGIN_DECLS - -typedef struct _EMailJunkFilter EMailJunkFilter; -typedef struct _EMailJunkFilterClass EMailJunkFilterClass; -typedef struct _EMailJunkFilterPrivate EMailJunkFilterPrivate; - -struct _EMailJunkFilter { - EExtension parent; - EMailJunkFilterPrivate *priv; -}; - -struct _EMailJunkFilterClass { - EExtensionClass parent_class; - - const gchar *filter_name; - const gchar *display_name; - - gboolean (*available) (EMailJunkFilter *junk_filter); - GtkWidget * (*new_config_widget) (EMailJunkFilter *junk_filter); -}; - -GType e_mail_junk_filter_get_type (void) G_GNUC_CONST; -gboolean e_mail_junk_filter_available (EMailJunkFilter *junk_filter); -GtkWidget * e_mail_junk_filter_new_config_widget - (EMailJunkFilter *junk_filter); -gint e_mail_junk_filter_compare (EMailJunkFilter *junk_filter_a, - EMailJunkFilter *junk_filter_b); - -G_END_DECLS - -#endif /* E_MAIL_JUNK_FILTER_H */ diff --git a/mail/e-mail-junk-options.c b/mail/e-mail-junk-options.c index d57e1d6dc6..e2c670c688 100644 --- a/mail/e-mail-junk-options.c +++ b/mail/e-mail-junk-options.c @@ -21,7 +21,7 @@ #include #include -#include +#include #define E_MAIL_JUNK_OPTIONS_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE \ diff --git a/mail/e-mail-junk-options.h b/mail/e-mail-junk-options.h index 5e2c99faf7..7e9108e7b7 100644 --- a/mail/e-mail-junk-options.h +++ b/mail/e-mail-junk-options.h @@ -20,7 +20,7 @@ #define E_MAIL_JUNK_OPTIONS_H #include -#include +#include /* Standard GObject macros */ #define E_TYPE_MAIL_JUNK_OPTIONS \ diff --git a/mail/e-mail-migrate.c b/mail/e-mail-migrate.c index fdf5684e0a..3b7de4c387 100644 --- a/mail/e-mail-migrate.c +++ b/mail/e-mail-migrate.c @@ -48,22 +48,25 @@ #include #include -#include #include #include + +#include +#include + +#include #include -#include "e-util/e-account-utils.h" -#include "e-util/e-alert-dialog.h" -#include "e-util/e-util-private.h" -#include "e-util/e-plugin.h" -#include "e-util/e-signature-utils.h" +#include +#include +#include + +#include +#include -#include "shell/e-shell.h" -#include "shell/e-shell-migrate.h" +#include #include "e-mail-backend.h" -#include "e-mail-folder-utils.h" #include "em-utils.h" #define d(x) x diff --git a/mail/e-mail-notebook-view.c b/mail/e-mail-notebook-view.c index 0232b92423..5d100cfc21 100644 --- a/mail/e-mail-notebook-view.c +++ b/mail/e-mail-notebook-view.c @@ -31,7 +31,7 @@ #include "mail/em-folder-tree.h" #include "e-mail-notebook-view.h" #include "e-mail-folder-pane.h" -#include "e-mail-folder-utils.h" +#include "libemail-engine/e-mail-folder-utils.h" #include "e-mail-message-pane.h" #include diff --git a/mail/e-mail-paned-view.c b/mail/e-mail-paned-view.c index 0098462de1..7a510e3ebd 100644 --- a/mail/e-mail-paned-view.c +++ b/mail/e-mail-paned-view.c @@ -38,11 +38,13 @@ #include +#include +#include +#include +#include + #include "em-utils.h" -#include "mail-config.h" -#include "mail-ops.h" #include "message-list.h" -#include "e-mail-folder-utils.h" #include "e-mail-reader-utils.h" #define E_MAIL_PANED_VIEW_GET_PRIVATE(obj) \ diff --git a/mail/e-mail-reader-utils.c b/mail/e-mail-reader-utils.c index bd51c97e1f..c814435119 100644 --- a/mail/e-mail-reader-utils.c +++ b/mail/e-mail-reader-utils.c @@ -37,15 +37,17 @@ #include "misc/e-web-view.h" #include "shell/e-shell-utils.h" +#include +#include +#include +#include + #include "mail/e-mail-backend.h" #include "mail/e-mail-browser.h" -#include "mail/e-mail-folder-utils.h" #include "mail/em-composer-utils.h" #include "mail/em-format-html-print.h" #include "mail/em-utils.h" #include "mail/mail-autofilter.h" -#include "mail/mail-ops.h" -#include "mail/mail-tools.h" #include "mail/mail-vfolder.h" #include "mail/message-list.h" diff --git a/mail/e-mail-reader.c b/mail/e-mail-reader.c index 5c67c62d02..37c92fbf78 100644 --- a/mail/e-mail-reader.c +++ b/mail/e-mail-reader.c @@ -32,7 +32,6 @@ #include #endif -#include "e-util/e-account-utils.h" #include "e-util/e-charset.h" #include "e-util/e-util.h" #include "e-util/e-alert-dialog.h" @@ -40,10 +39,16 @@ #include "widgets/misc/e-popup-action.h" #include "widgets/misc/e-menu-tool-action.h" +#include "libemail-utils/e-account-utils.h" +#include "libemail-utils/mail-mt.h" + +#include "libemail-engine/mail-ops.h" +#include "libemail-engine/e-mail-utils.h" +#include "libemail-engine/e-mail-enumtypes.h" + #include "mail/e-mail-backend.h" #include "mail/e-mail-browser.h" #include "mail/e-mail-display.h" -#include "mail/e-mail-enumtypes.h" #include "mail/e-mail-reader-utils.h" #include "mail/e-mail-view.h" #include "mail/em-composer-utils.h" @@ -52,8 +57,6 @@ #include "mail/em-folder-tree.h" #include "mail/em-utils.h" #include "mail/mail-autofilter.h" -#include "mail/mail-ops.h" -#include "mail/mail-mt.h" #include "mail/mail-vfolder.h" #include "mail/message-list.h" diff --git a/mail/e-mail-session-utils.c b/mail/e-mail-session-utils.c deleted file mode 100644 index f1c27a3425..0000000000 --- a/mail/e-mail-session-utils.c +++ /dev/null @@ -1,930 +0,0 @@ -/* - * e-mail-session-utils.c - * - * 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 - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "e-mail-session-utils.h" - -#include "em-utils.h" - -#include - -#include -#include -#include -#include - -/* X-Mailer header value */ -#define X_MAILER ("Evolution " VERSION SUB_VERSION " " VERSION_COMMENT) - -typedef struct _AsyncContext AsyncContext; - -struct _AsyncContext { - CamelFolder *sent_folder; - - CamelMimeMessage *message; - CamelMessageInfo *info; - - CamelAddress *from; - CamelAddress *recipients; - - CamelFilterDriver *driver; - - GCancellable *cancellable; - gint io_priority; - - /* X-Evolution headers */ - struct _camel_header_raw *xev; - - GPtrArray *post_to_uris; - - gchar *folder_uri; - gchar *message_uid; - gchar *transport_uid; - gchar *sent_folder_uri; -}; - -static void -async_context_free (AsyncContext *context) -{ - if (context->sent_folder != NULL) - g_object_unref (context->sent_folder); - - if (context->message != NULL) - g_object_unref (context->message); - - if (context->info != NULL) - camel_message_info_free (context->info); - - if (context->from != NULL) - g_object_unref (context->from); - - if (context->recipients != NULL) - g_object_unref (context->recipients); - - if (context->driver != NULL) - g_object_unref (context->driver); - - if (context->cancellable != NULL) { - camel_operation_pop_message (context->cancellable); - g_object_unref (context->cancellable); - } - - if (context->xev != NULL) - camel_header_raw_clear (&context->xev); - - if (context->post_to_uris != NULL) { - g_ptr_array_foreach ( - context->post_to_uris, (GFunc) g_free, NULL); - g_ptr_array_free (context->post_to_uris, TRUE); - } - - g_free (context->folder_uri); - g_free (context->message_uid); - g_free (context->transport_uid); - g_free (context->sent_folder_uri); - - g_slice_free (AsyncContext, context); -} - -GQuark -e_mail_error_quark (void) -{ - static GQuark quark = 0; - - if (G_UNLIKELY (quark == 0)) { - const gchar *string = "e-mail-error-quark"; - quark = g_quark_from_static_string (string); - } - - return quark; -} - -static void -mail_session_handle_draft_headers_thread (GSimpleAsyncResult *simple, - EMailSession *session, - GCancellable *cancellable) -{ - AsyncContext *context; - GError *error = NULL; - - context = g_simple_async_result_get_op_res_gpointer (simple); - - e_mail_session_handle_draft_headers_sync ( - session, context->message, cancellable, &error); - - if (error != NULL) - g_simple_async_result_take_error (simple, error); -} - -gboolean -e_mail_session_handle_draft_headers_sync (EMailSession *session, - CamelMimeMessage *message, - GCancellable *cancellable, - GError **error) -{ - CamelFolder *folder; - CamelMedium *medium; - const gchar *folder_uri; - const gchar *message_uid; - const gchar *header_name; - gboolean success; - - g_return_val_if_fail (E_IS_MAIL_SESSION (session), FALSE); - g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), FALSE); - - medium = CAMEL_MEDIUM (message); - - header_name = "X-Evolution-Draft-Folder"; - folder_uri = camel_medium_get_header (medium, header_name); - - header_name = "X-Evolution-Draft-Message"; - message_uid = camel_medium_get_header (medium, header_name); - - /* Don't report errors about missing X-Evolution-Draft - * headers. These headers are optional, so their absence - * is handled by doing nothing. */ - if (folder_uri == NULL || message_uid == NULL) - return TRUE; - - folder = e_mail_session_uri_to_folder_sync ( - session, folder_uri, 0, cancellable, error); - - if (folder == NULL) - return FALSE; - - camel_folder_set_message_flags ( - folder, message_uid, - CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_SEEN, - CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_SEEN); - - success = camel_folder_synchronize_message_sync ( - folder, message_uid, cancellable, error); - - g_object_unref (folder); - - return success; -} - -void -e_mail_session_handle_draft_headers (EMailSession *session, - CamelMimeMessage *message, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *simple; - AsyncContext *context; - - g_return_if_fail (E_IS_MAIL_SESSION (session)); - g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message)); - - context = g_slice_new0 (AsyncContext); - context->message = g_object_ref (message); - - simple = g_simple_async_result_new ( - G_OBJECT (session), callback, user_data, - e_mail_session_handle_draft_headers); - - g_simple_async_result_set_op_res_gpointer ( - simple, context, (GDestroyNotify) async_context_free); - - g_simple_async_result_run_in_thread ( - simple, (GSimpleAsyncThreadFunc) - mail_session_handle_draft_headers_thread, - io_priority, cancellable); - - g_object_unref (simple); -} - -gboolean -e_mail_session_handle_draft_headers_finish (EMailSession *session, - GAsyncResult *result, - GError **error) -{ - GSimpleAsyncResult *simple; - - g_return_val_if_fail ( - g_simple_async_result_is_valid ( - result, G_OBJECT (session), - e_mail_session_handle_draft_headers), FALSE); - - simple = G_SIMPLE_ASYNC_RESULT (result); - - /* Assume success unless a GError is set. */ - return !g_simple_async_result_propagate_error (simple, error); -} - -static void -mail_session_handle_source_headers_thread (GSimpleAsyncResult *simple, - EMailSession *session, - GCancellable *cancellable) -{ - AsyncContext *context; - GError *error = NULL; - - context = g_simple_async_result_get_op_res_gpointer (simple); - - e_mail_session_handle_source_headers_sync ( - session, context->message, cancellable, &error); - - if (error != NULL) - g_simple_async_result_take_error (simple, error); -} - -gboolean -e_mail_session_handle_source_headers_sync (EMailSession *session, - CamelMimeMessage *message, - GCancellable *cancellable, - GError **error) -{ - CamelFolder *folder; - CamelMedium *medium; - CamelMessageFlags flags = 0; - const gchar *folder_uri; - const gchar *message_uid; - const gchar *flag_string; - const gchar *header_name; - gboolean success; - guint length, ii; - gchar **tokens; - gchar *string; - - g_return_val_if_fail (E_IS_MAIL_SESSION (session), FALSE); - g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), FALSE); - - medium = CAMEL_MEDIUM (message); - - header_name = "X-Evolution-Source-Folder"; - folder_uri = camel_medium_get_header (medium, header_name); - - header_name = "X-Evolution-Source-Message"; - message_uid = camel_medium_get_header (medium, header_name); - - header_name = "X-Evolution-Source-Flags"; - flag_string = camel_medium_get_header (medium, header_name); - - /* Don't report errors about missing X-Evolution-Source - * headers. These headers are optional, so their absence - * is handled by doing nothing. */ - if (folder_uri == NULL || message_uid == NULL || flag_string == NULL) - return TRUE; - - /* Convert the flag string to CamelMessageFlags. */ - - string = g_strstrip (g_strdup (flag_string)); - tokens = g_strsplit (string, " ", 0); - g_free (string); - - /* If tokens is NULL, a length of 0 will skip the loop. */ - length = (tokens != NULL) ? g_strv_length (tokens) : 0; - - for (ii = 0; ii < length; ii++) { - /* Note: We're only checking for flags known to - * be used in X-Evolution-Source-Flags headers. - * Add more as needed. */ - if (g_strcmp0 (tokens[ii], "ANSWERED") == 0) - flags |= CAMEL_MESSAGE_ANSWERED; - else if (g_strcmp0 (tokens[ii], "ANSWERED_ALL") == 0) - flags |= CAMEL_MESSAGE_ANSWERED_ALL; - else if (g_strcmp0 (tokens[ii], "FORWARDED") == 0) - flags |= CAMEL_MESSAGE_FORWARDED; - else if (g_strcmp0 (tokens[ii], "SEEN") == 0) - flags |= CAMEL_MESSAGE_SEEN; - else - g_warning ( - "Unknown flag '%s' in %s", - tokens[ii], header_name); - } - - g_strfreev (tokens); - - folder = e_mail_session_uri_to_folder_sync ( - session, folder_uri, 0, cancellable, error); - - if (folder == NULL) - return FALSE; - - camel_folder_set_message_flags ( - folder, message_uid, flags, flags); - - success = camel_folder_synchronize_message_sync ( - folder, message_uid, cancellable, error); - - g_object_unref (folder); - - return success; -} - -void -e_mail_session_handle_source_headers (EMailSession *session, - CamelMimeMessage *message, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *simple; - AsyncContext *context; - - g_return_if_fail (E_IS_MAIL_SESSION (session)); - g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message)); - - context = g_slice_new0 (AsyncContext); - context->message = g_object_ref (message); - - simple = g_simple_async_result_new ( - G_OBJECT (session), callback, user_data, - e_mail_session_handle_source_headers); - - g_simple_async_result_set_op_res_gpointer ( - simple, context, (GDestroyNotify) async_context_free); - - g_simple_async_result_run_in_thread ( - simple, (GSimpleAsyncThreadFunc) - mail_session_handle_source_headers_thread, - io_priority, cancellable); - - g_object_unref (simple); -} - -gboolean -e_mail_session_handle_source_headers_finish (EMailSession *session, - GAsyncResult *result, - GError **error) -{ - GSimpleAsyncResult *simple; - - g_return_val_if_fail ( - g_simple_async_result_is_valid ( - result, G_OBJECT (session), - e_mail_session_handle_draft_headers), FALSE); - - simple = G_SIMPLE_ASYNC_RESULT (result); - - /* Assume success unless a GError is set. */ - return !g_simple_async_result_propagate_error (simple, error); -} - -static void -mail_session_send_to_thread (GSimpleAsyncResult *simple, - EMailSession *session, - GCancellable *cancellable) -{ - AsyncContext *context; - CamelFolder *local_sent_folder; - GString *error_messages; - gboolean copy_to_sent = TRUE; - guint ii; - GError *error = NULL; - - context = g_simple_async_result_get_op_res_gpointer (simple); - - /* Send the message to all recipients. */ - if (camel_address_length (context->recipients) > 0) { - CamelProvider *provider; - CamelService *service; - gboolean did_connect = FALSE; - - service = camel_session_get_service ( - CAMEL_SESSION (session), context->transport_uid); - - if (!CAMEL_IS_TRANSPORT (service)) { - g_simple_async_result_set_error (simple, - CAMEL_SERVICE_ERROR, - CAMEL_SERVICE_ERROR_URL_INVALID, - _("Cannot get transport for account '%s'"), - context->transport_uid); - return; - } - - if (camel_service_get_connection_status (service) != CAMEL_SERVICE_CONNECTED) { - did_connect = TRUE; - - /* XXX This API does not allow for cancellation. */ - if (!em_utils_connect_service_sync (service, cancellable, &error)) { - g_simple_async_result_take_error (simple, error); - return; - } - } - - provider = camel_service_get_provider (service); - - if (provider->flags & CAMEL_PROVIDER_DISABLE_SENT_FOLDER) - copy_to_sent = FALSE; - - camel_transport_send_to_sync ( - CAMEL_TRANSPORT (service), - context->message, context->from, - context->recipients, cancellable, &error); - - if (did_connect) - em_utils_disconnect_service_sync ( - service, error == NULL, - cancellable, error ? NULL : &error); - - if (error != NULL) { - g_simple_async_result_take_error (simple, error); - return; - } - } - - /* Post the message to requested folders. */ - for (ii = 0; ii < context->post_to_uris->len; ii++) { - CamelFolder *folder; - const gchar *folder_uri; - - folder_uri = g_ptr_array_index (context->post_to_uris, ii); - - folder = e_mail_session_uri_to_folder_sync ( - session, folder_uri, 0, cancellable, &error); - - if (error != NULL) { - g_warn_if_fail (folder == NULL); - g_simple_async_result_take_error (simple, error); - return; - } - - g_return_if_fail (CAMEL_IS_FOLDER (folder)); - - camel_folder_append_message_sync ( - folder, context->message, context->info, - NULL, cancellable, &error); - - g_object_unref (folder); - - if (error != NULL) { - g_simple_async_result_take_error (simple, error); - return; - } - } - - /*** Post Processing ***/ - - /* This accumulates error messages during post-processing. */ - error_messages = g_string_sized_new (256); - - mail_tool_restore_xevolution_headers (context->message, context->xev); - - /* Run filters on the outgoing message. */ - if (context->driver != NULL) { - camel_filter_driver_filter_message ( - context->driver, context->message, context->info, - NULL, NULL, NULL, "", cancellable, &error); - - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - goto exit; - - if (error != NULL) { - g_string_append_printf ( - error_messages, - _("Failed to apply outgoing filters: %s"), - error->message); - g_clear_error (&error); - } - } - - if (!copy_to_sent) - goto cleanup; - - /* Append the sent message to a Sent folder. */ - - local_sent_folder = - e_mail_session_get_local_folder ( - session, E_MAIL_LOCAL_FOLDER_SENT); - - /* Try to extract a CamelFolder from the Sent folder URI. */ - if (context->sent_folder_uri != NULL) { - context->sent_folder = e_mail_session_uri_to_folder_sync ( - session, context->sent_folder_uri, 0, - cancellable, &error); - if (error != NULL) { - g_warn_if_fail (context->sent_folder == NULL); - if (error_messages->len > 0) - g_string_append (error_messages, "\n\n"); - g_string_append_printf ( - error_messages, - _("Failed to append to %s: %s\n" - "Appending to local 'Sent' folder instead."), - context->sent_folder_uri, error->message); - g_clear_error (&error); - } - } - - /* Fall back to the local Sent folder. */ - if (context->sent_folder == NULL) - context->sent_folder = g_object_ref (local_sent_folder); - - /* Append the message. */ - camel_folder_append_message_sync ( - context->sent_folder, context->message, - context->info, NULL, cancellable, &error); - - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - goto exit; - - if (error == NULL) - goto cleanup; - - /* If appending to a remote Sent folder failed, - * try appending to the local Sent folder. */ - if (context->sent_folder != local_sent_folder) { - const gchar *description; - - description = camel_folder_get_description ( - context->sent_folder); - - if (error_messages->len > 0) - g_string_append (error_messages, "\n\n"); - g_string_append_printf ( - error_messages, - _("Failed to append to %s: %s\n" - "Appending to local 'Sent' folder instead."), - description, error->message); - g_clear_error (&error); - - camel_folder_append_message_sync ( - local_sent_folder, context->message, - context->info, NULL, cancellable, &error); - } - - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - goto exit; - - /* We can't even append to the local Sent folder? - * In that case just leave the message in Outbox. */ - if (error != NULL) { - if (error_messages->len > 0) - g_string_append (error_messages, "\n\n"); - g_string_append_printf ( - error_messages, - _("Failed to append to local 'Sent' folder: %s"), - error->message); - g_clear_error (&error); - goto exit; - } - -cleanup: - - /* The send operation was successful; ignore cleanup errors. */ - - /* Mark the draft message for deletion, if present. */ - e_mail_session_handle_draft_headers_sync ( - session, context->message, cancellable, &error); - if (error != NULL) { - g_warning ("%s", error->message); - g_clear_error (&error); - } - - /* Set flags on the original source message, if present. - * Source message refers to the message being forwarded - * or replied to. */ - e_mail_session_handle_source_headers_sync ( - session, context->message, cancellable, &error); - if (error != NULL) { - g_warning ("%s", error->message); - g_clear_error (&error); - } - -exit: - - /* If we were cancelled, disregard any other errors. */ - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - g_simple_async_result_take_error (simple, error); - - /* Stuff the accumulated error messages in a GError. */ - } else if (error_messages->len > 0) { - g_simple_async_result_set_error ( - simple, E_MAIL_ERROR, - E_MAIL_ERROR_POST_PROCESSING, - "%s", error_messages->str); - } - - /* Synchronize the Sent folder. */ - if (context->sent_folder != NULL) - camel_folder_synchronize_sync ( - context->sent_folder, FALSE, cancellable, NULL); - - g_string_free (error_messages, TRUE); -} - -void -e_mail_session_send_to (EMailSession *session, - CamelMimeMessage *message, - gint io_priority, - GCancellable *cancellable, - CamelFilterGetFolderFunc get_folder_func, - gpointer get_folder_data, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *simple; - AsyncContext *context; - CamelAddress *from; - CamelAddress *recipients; - CamelMedium *medium; - CamelMessageInfo *info; - EAccount *account = NULL; - GPtrArray *post_to_uris; - struct _camel_header_raw *xev; - struct _camel_header_raw *header; - const gchar *string; - const gchar *resent_from; - gchar *transport_uid = NULL; - gchar *sent_folder_uri = NULL; - GError *error = NULL; - - g_return_if_fail (E_IS_MAIL_SESSION (session)); - g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message)); - - medium = CAMEL_MEDIUM (message); - - camel_medium_set_header (medium, "X-Mailer", X_MAILER); - - xev = mail_tool_remove_xevolution_headers (message); - - /* Extract directives from X-Evolution headers. */ - - string = camel_header_raw_find (&xev, "X-Evolution-Account", NULL); - if (string != NULL) { - gchar *account_uid; - - account_uid = g_strstrip (g_strdup (string)); - account = e_get_account_by_uid (account_uid); - g_free (account_uid); - } - - if (account != NULL) { - if (account->transport != NULL) { - - /* XXX Transport UIDs are kludgy right now. We - * use the EAccount's regular UID and tack on - * "-transport". Will be better soon. */ - transport_uid = g_strconcat ( - account->uid, "-transport", NULL); - - /* to reprompt password on sending if needed */ - account->transport->get_password_canceled = FALSE; - } - sent_folder_uri = g_strdup (account->sent_folder_uri); - } - - string = camel_header_raw_find (&xev, "X-Evolution-Fcc", NULL); - if (sent_folder_uri == NULL && string != NULL) - sent_folder_uri = g_strstrip (g_strdup (string)); - - string = camel_header_raw_find (&xev, "X-Evolution-Transport", NULL); - if (transport_uid == NULL && string != NULL) - transport_uid = g_strstrip (g_strdup (string)); - - post_to_uris = g_ptr_array_new (); - for (header = xev; header != NULL; header = header->next) { - gchar *folder_uri; - - if (g_strcmp0 (header->name, "X-Evolution-PostTo") != 0) - continue; - - folder_uri = g_strstrip (g_strdup (header->value)); - g_ptr_array_add (post_to_uris, folder_uri); - } - - /* Collect sender and recipients from headers. */ - - from = (CamelAddress *) camel_internet_address_new (); - recipients = (CamelAddress *) camel_internet_address_new (); - resent_from = camel_medium_get_header (medium, "Resent-From"); - - if (resent_from != NULL) { - const CamelInternetAddress *addr; - const gchar *type; - - camel_address_decode (from, resent_from); - - type = CAMEL_RECIPIENT_TYPE_RESENT_TO; - addr = camel_mime_message_get_recipients (message, type); - camel_address_cat (recipients, CAMEL_ADDRESS (addr)); - - type = CAMEL_RECIPIENT_TYPE_RESENT_CC; - addr = camel_mime_message_get_recipients (message, type); - camel_address_cat (recipients, CAMEL_ADDRESS (addr)); - - type = CAMEL_RECIPIENT_TYPE_RESENT_BCC; - addr = camel_mime_message_get_recipients (message, type); - camel_address_cat (recipients, CAMEL_ADDRESS (addr)); - - } else { - const CamelInternetAddress *addr; - const gchar *type; - - addr = camel_mime_message_get_from (message); - camel_address_copy (from, CAMEL_ADDRESS (addr)); - - type = CAMEL_RECIPIENT_TYPE_TO; - addr = camel_mime_message_get_recipients (message, type); - camel_address_cat (recipients, CAMEL_ADDRESS (addr)); - - type = CAMEL_RECIPIENT_TYPE_CC; - addr = camel_mime_message_get_recipients (message, type); - camel_address_cat (recipients, CAMEL_ADDRESS (addr)); - - type = CAMEL_RECIPIENT_TYPE_BCC; - addr = camel_mime_message_get_recipients (message, type); - camel_address_cat (recipients, CAMEL_ADDRESS (addr)); - } - - /* Miscellaneous preparations. */ - - info = camel_message_info_new (NULL); - camel_message_info_set_flags (info, CAMEL_MESSAGE_SEEN, ~0); - - /* The rest of the processing happens in a thread. */ - - context = g_slice_new0 (AsyncContext); - context->message = g_object_ref (message); - context->io_priority = io_priority; - context->from = from; - context->recipients = recipients; - context->message = g_object_ref (message); - context->info = info; - context->xev = xev; - context->post_to_uris = post_to_uris; - context->transport_uid = transport_uid; - context->sent_folder_uri = sent_folder_uri; - - if (G_IS_CANCELLABLE (cancellable)) - context->cancellable = g_object_ref (cancellable); - - /* Failure here emits a runtime warning but is non-fatal. */ - context->driver = camel_session_get_filter_driver ( - CAMEL_SESSION (session), E_FILTER_SOURCE_OUTGOING, &error); - if (context->driver != NULL && get_folder_func) - camel_filter_driver_set_folder_func ( - context->driver, get_folder_func, get_folder_data); - if (error != NULL) { - g_warn_if_fail (context->driver == NULL); - g_warning ("%s", error->message); - g_error_free (error); - } - - /* This gets popped in async_context_free(). */ - camel_operation_push_message ( - context->cancellable, _("Sending message")); - - simple = g_simple_async_result_new ( - G_OBJECT (session), callback, - user_data, e_mail_session_send_to); - - g_simple_async_result_set_op_res_gpointer ( - simple, context, (GDestroyNotify) async_context_free); - - g_simple_async_result_run_in_thread ( - simple, (GSimpleAsyncThreadFunc) - mail_session_send_to_thread, - context->io_priority, - context->cancellable); - - g_object_unref (simple); -} - -gboolean -e_mail_session_send_to_finish (EMailSession *session, - GAsyncResult *result, - GError **error) -{ - GSimpleAsyncResult *simple; - - g_return_val_if_fail ( - g_simple_async_result_is_valid ( - result, G_OBJECT (session), - e_mail_session_send_to), FALSE); - - simple = G_SIMPLE_ASYNC_RESULT (result); - - /* Assume success unless a GError is set. */ - return !g_simple_async_result_propagate_error (simple, error); -} - -static void -mail_session_unsubscribe_folder_thread (GSimpleAsyncResult *simple, - EMailSession *session, - GCancellable *cancellable) -{ - AsyncContext *context; - GError *error = NULL; - - context = g_simple_async_result_get_op_res_gpointer (simple); - - e_mail_session_unsubscribe_folder_sync ( - session, context->folder_uri, cancellable, &error); - - if (error != NULL) - g_simple_async_result_take_error (simple, error); -} - -gboolean -e_mail_session_unsubscribe_folder_sync (EMailSession *session, - const gchar *folder_uri, - GCancellable *cancellable, - GError **error) -{ - CamelStore *store = NULL; - gchar *folder_name = NULL; - const gchar *message; - gboolean success = FALSE; - - g_return_val_if_fail (E_IS_MAIL_SESSION (session), FALSE); - g_return_val_if_fail (folder_uri != NULL, FALSE); - - success = e_mail_folder_uri_parse ( - CAMEL_SESSION (session), folder_uri, - &store, &folder_name, error); - - if (!success) - return FALSE; - - message = _("Unsubscribing from folder '%s'"); - camel_operation_push_message (cancellable, message, folder_name); - - /* FIXME This should take our GCancellable. */ - success = - em_utils_connect_service_sync ( - CAMEL_SERVICE (store), cancellable, error) && - camel_subscribable_unsubscribe_folder_sync ( - CAMEL_SUBSCRIBABLE (store), - folder_name, cancellable, error); - - camel_operation_pop_message (cancellable); - - g_object_unref (store); - g_free (folder_name); - - return success; -} - -void -e_mail_session_unsubscribe_folder (EMailSession *session, - const gchar *folder_uri, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *simple; - AsyncContext *context; - - g_return_if_fail (E_IS_MAIL_SESSION (session)); - g_return_if_fail (folder_uri != NULL); - - context = g_slice_new0 (AsyncContext); - context->folder_uri = g_strdup (folder_uri); - - simple = g_simple_async_result_new ( - G_OBJECT (session), callback, user_data, - e_mail_session_unsubscribe_folder); - - g_simple_async_result_set_op_res_gpointer ( - simple, context, (GDestroyNotify) async_context_free); - - g_simple_async_result_run_in_thread ( - simple, (GSimpleAsyncThreadFunc) - mail_session_unsubscribe_folder_thread, - io_priority, cancellable); - - g_object_unref (simple); -} - -gboolean -e_mail_session_unsubscribe_folder_finish (EMailSession *session, - GAsyncResult *result, - GError **error) -{ - GSimpleAsyncResult *simple; - - g_return_val_if_fail ( - g_simple_async_result_is_valid ( - result, G_OBJECT (session), - e_mail_session_unsubscribe_folder), FALSE); - - simple = G_SIMPLE_ASYNC_RESULT (result); - - /* Assume success unless a GError is set. */ - return !g_simple_async_result_propagate_error (simple, error); -} diff --git a/mail/e-mail-session-utils.h b/mail/e-mail-session-utils.h deleted file mode 100644 index b398be5f84..0000000000 --- a/mail/e-mail-session-utils.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * e-mail-session-utils.h - * - * 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 - * - */ - -#ifndef E_MAIL_SESSION_UTILS_H -#define E_MAIL_SESSION_UTILS_H - -/* High-level operations with Evolution-specific policies. */ - -#include - -#define E_MAIL_ERROR (e_mail_error_quark ()) - -G_BEGIN_DECLS - -typedef enum { - E_MAIL_ERROR_POST_PROCESSING -} EMailError; - -GQuark e_mail_error_quark (void) G_GNUC_CONST; -gboolean e_mail_session_handle_draft_headers_sync - (EMailSession *session, - CamelMimeMessage *message, - GCancellable *cancellable, - GError **error); -void e_mail_session_handle_draft_headers - (EMailSession *session, - CamelMimeMessage *message, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean e_mail_session_handle_draft_headers_finish - (EMailSession *session, - GAsyncResult *result, - GError **error); -gboolean e_mail_session_handle_source_headers_sync - (EMailSession *session, - CamelMimeMessage *message, - GCancellable *cancellable, - GError **error); -void e_mail_session_handle_source_headers - (EMailSession *session, - CamelMimeMessage *message, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean e_mail_session_handle_source_headers_finish - (EMailSession *session, - GAsyncResult *result, - GError **error); -void e_mail_session_send_to (EMailSession *session, - CamelMimeMessage *message, - gint io_priority, - GCancellable *cancellable, - CamelFilterGetFolderFunc get_folder_func, - gpointer get_folder_data, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean e_mail_session_send_to_finish (EMailSession *session, - GAsyncResult *result, - GError **error); -gboolean e_mail_session_unsubscribe_folder_sync - (EMailSession *session, - const gchar *folder_uri, - GCancellable *cancellable, - GError **error); -void e_mail_session_unsubscribe_folder - (EMailSession *session, - const gchar *folder_uri, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean e_mail_session_unsubscribe_folder_finish - (EMailSession *session, - GAsyncResult *result, - GError **error); - -G_END_DECLS - -#endif /* E_MAIL_SESSION_UTILS_H */ diff --git a/mail/e-mail-session.c b/mail/e-mail-session.c deleted file mode 100644 index 57c800cb91..0000000000 --- a/mail/e-mail-session.c +++ /dev/null @@ -1,2413 +0,0 @@ -/* - * e-mail-session.c - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see - * - * - * Authors: - * Jonathon Jongsma - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * Copyright (C) 2009 Intel Corporation - * - */ - -/* mail-session.c: handles the session information and resource manipulation */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include -#include - -#include - -#ifdef HAVE_CANBERRA -#include -#endif - -#include -#include -#include -#include - -#include "e-util/e-util.h" -#include "e-util/e-account-utils.h" -#include "e-util/e-alert-dialog.h" -#include "e-util/e-util-private.h" - -#include "shell/e-shell.h" -#include "shell/e-shell-view.h" -#include "shell/e-shell-content.h" -#include "shell/e-shell-window.h" - -#include "e-mail-account-store.h" -#include "e-mail-folder-utils.h" -#include "e-mail-junk-filter.h" -#include "e-mail-session.h" -#include "em-composer-utils.h" -#include "em-filter-context.h" -#include "em-filter-rule.h" -#include "em-utils.h" -#include "mail-config.h" -#include "mail-mt.h" -#include "mail-ops.h" -#include "mail-send-recv.h" -#include "mail-tools.h" - -#define E_MAIL_SESSION_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE \ - ((obj), E_TYPE_MAIL_SESSION, EMailSessionPrivate)) - -typedef struct _AsyncContext AsyncContext; -typedef struct _SourceContext SourceContext; - -struct _EMailSessionPrivate { - EMailAccountStore *account_store; - MailFolderCache *folder_cache; - EMailLabelListStore *label_store; - - EAccountList *account_list; - gulong account_added_handler_id; - gulong account_changed_handler_id; - - CamelStore *local_store; - CamelStore *vfolder_store; - - FILE *filter_logfile; - GHashTable *junk_filters; - EProxy *proxy; - - /* Local folder cache. */ - GPtrArray *local_folders; - GPtrArray *local_folder_uris; -}; - -struct _AsyncContext { - /* arguments */ - CamelStoreGetFolderFlags flags; - gchar *uid; - gchar *uri; - - /* results */ - CamelFolder *folder; -}; - -struct _SourceContext { - EMailSession *session; - CamelService *service; -}; - -enum { - PROP_0, - PROP_ACCOUNT_STORE, - PROP_FOLDER_CACHE, - PROP_JUNK_FILTER_NAME, - PROP_LABEL_STORE, - PROP_LOCAL_STORE, - PROP_VFOLDER_STORE -}; - -enum { - ACTIVITY_ADDED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL]; - -static const gchar *local_folder_names[E_MAIL_NUM_LOCAL_FOLDERS] = { - N_("Inbox"), /* E_MAIL_LOCAL_FOLDER_INBOX */ - N_("Drafts"), /* E_MAIL_LOCAL_FOLDER_DRAFTS */ - N_("Outbox"), /* E_MAIL_LOCAL_FOLDER_OUTBOX */ - N_("Sent"), /* E_MAIL_LOCAL_FOLDER_SENT */ - N_("Templates"), /* E_MAIL_LOCAL_FOLDER_TEMPLATES */ - "Inbox" /* E_MAIL_LOCAL_FOLDER_LOCAL_INBOX */ -}; - -static gchar *mail_data_dir; -static gchar *mail_cache_dir; -static gchar *mail_config_dir; - -#if 0 -static MailMsgInfo ms_thread_info_dummy = { sizeof (MailMsg) }; -#endif - -G_DEFINE_TYPE_WITH_CODE ( - EMailSession, - e_mail_session, - CAMEL_TYPE_SESSION, - G_IMPLEMENT_INTERFACE (E_TYPE_EXTENSIBLE, NULL)) - -/* Support for CamelSession.alert_user() *************************************/ - -static gpointer user_message_dialog; -static GQueue user_message_queue = { NULL, NULL, 0 }; - -struct _user_message_msg { - MailMsg base; - - CamelSessionAlertType type; - gchar *prompt; - GSList *button_captions; - EFlag *done; - - gint result; - guint ismain : 1; -}; - -static void user_message_exec (struct _user_message_msg *m, - GCancellable *cancellable, - GError **error); - -static void -user_message_response_free (GtkDialog *dialog, - gint button) -{ - struct _user_message_msg *m = NULL; - - gtk_widget_destroy ((GtkWidget *) dialog); - - user_message_dialog = NULL; - - /* check for pendings */ - if (!g_queue_is_empty (&user_message_queue)) { - GCancellable *cancellable; - - m = g_queue_pop_head (&user_message_queue); - cancellable = e_activity_get_cancellable (m->base.activity); - user_message_exec (m, cancellable, &m->base.error); - mail_msg_unref (m); - } -} - -/* clicked, send back the reply */ -static void -user_message_response (GtkDialog *dialog, - gint button, - struct _user_message_msg *m) -{ - /* if !m or !button_captions, then we've already replied */ - if (m && m->button_captions) { - m->result = button; - e_flag_set (m->done); - } - - user_message_response_free (dialog, button); -} - -static void -user_message_exec (struct _user_message_msg *m, - GCancellable *cancellable, - GError **error) -{ - gboolean info_only; - GtkWindow *parent; - EShell *shell; - const gchar *error_type; - gint index; - GSList *iter; - - info_only = g_slist_length (m->button_captions) <= 1; - - if (!m->ismain && user_message_dialog != NULL && !info_only) { - g_queue_push_tail (&user_message_queue, mail_msg_ref (m)); - return; - } - - switch (m->type) { - case CAMEL_SESSION_ALERT_INFO: - error_type = "mail:session-message-info"; - break; - case CAMEL_SESSION_ALERT_WARNING: - error_type = "mail:session-message-warning"; - break; - case CAMEL_SESSION_ALERT_ERROR: - error_type = "mail:session-message-error"; - break; - default: - error_type = NULL; - g_return_if_reached (); - } - - shell = e_shell_get_default (); - - /* try to find "mail" view to place the informational alert to */ - if (info_only) { - GtkWindow *active_window; - EShellWindow *shell_window; - EShellView *shell_view; - EShellContent *shell_content = NULL; - - /* check currently active window first, ... */ - active_window = e_shell_get_active_window (shell); - if (active_window && E_IS_SHELL_WINDOW (active_window)) { - if (E_IS_SHELL_WINDOW (active_window)) { - shell_window = E_SHELL_WINDOW (active_window); - shell_view = e_shell_window_peek_shell_view (shell_window, "mail"); - if (shell_view) - shell_content = e_shell_view_get_shell_content (shell_view); - } - } - - if (!shell_content) { - GList *list, *iter; - - list = gtk_application_get_windows (GTK_APPLICATION (shell)); - - /* ...then iterate through all opened windows and pick one which has it */ - for (iter = list; iter != NULL && !shell_content; iter = g_list_next (iter)) { - if (E_IS_SHELL_WINDOW (iter->data)) { - shell_window = iter->data; - shell_view = e_shell_window_peek_shell_view (shell_window, "mail"); - if (shell_view) - shell_content = e_shell_view_get_shell_content (shell_view); - } - } - } - - /* when no shell-content found, which might not happen, but just in case, - process the information alert like usual, through an EAlertDialog machinery - */ - if (shell_content) { - e_alert_submit (E_ALERT_SINK (shell_content), error_type, m->prompt, NULL); - return; - } else if (!m->ismain && user_message_dialog != NULL) { - g_queue_push_tail (&user_message_queue, mail_msg_ref (m)); - return; - } - } - - /* Pull in the active window from the shell to get a parent window */ - parent = e_shell_get_active_window (shell); - user_message_dialog = e_alert_dialog_new_for_args ( - parent, error_type, m->prompt, NULL); - g_object_set (user_message_dialog, "resizable", TRUE, NULL); - - if (m->button_captions) { - GtkWidget *action_area; - GList *children, *child; - - /* remove all default buttons and keep only those requested */ - action_area = gtk_dialog_get_action_area (GTK_DIALOG (user_message_dialog)); - - children = gtk_container_get_children (GTK_CONTAINER (action_area)); - for (child = children; child != NULL; child = child->next) { - gtk_container_remove (GTK_CONTAINER (action_area), child->data); - } - - g_list_free (children); - } - - for (index = 0, iter = m->button_captions; iter; index++, iter = iter->next) { - gtk_dialog_add_button (GTK_DIALOG (user_message_dialog), iter->data, index); - } - - /* XXX This is a case where we need to be able to construct - * custom EAlerts without a predefined XML definition. */ - if (m->ismain) { - gint response; - - response = gtk_dialog_run (user_message_dialog); - user_message_response ( - user_message_dialog, response, m); - } else { - gpointer user_data = m; - - if (g_slist_length (m->button_captions) <= 1) - user_data = NULL; - - g_signal_connect ( - user_message_dialog, "response", - G_CALLBACK (user_message_response), user_data); - gtk_widget_show (user_message_dialog); - } -} - -static void -user_message_free (struct _user_message_msg *m) -{ - g_free (m->prompt); - g_slist_free_full (m->button_captions, g_free); - e_flag_free (m->done); -} - -static MailMsgInfo user_message_info = { - sizeof (struct _user_message_msg), - (MailMsgDescFunc) NULL, - (MailMsgExecFunc) user_message_exec, - (MailMsgDoneFunc) NULL, - (MailMsgFreeFunc) user_message_free -}; - -/* Support for CamelSession.get_filter_driver () *****************************/ - -static CamelFolder * -get_folder (CamelFilterDriver *d, - const gchar *uri, - gpointer user_data, - GError **error) -{ - EMailSession *session = E_MAIL_SESSION (user_data); - - /* FIXME Not passing a GCancellable here. */ - /* FIXME Need a camel_filter_driver_get_session(). */ - return e_mail_session_uri_to_folder_sync ( - session, uri, 0, NULL, error); -} - -static gboolean -session_play_sound_cb (const gchar *filename) -{ -#ifdef HAVE_CANBERRA - if (filename != NULL && *filename != '\0') - ca_context_play ( - ca_gtk_context_get (), 0, - CA_PROP_MEDIA_FILENAME, filename, - NULL); - else -#endif - gdk_beep (); - - return FALSE; -} - -static void -session_play_sound (CamelFilterDriver *driver, - const gchar *filename, - gpointer user_data) -{ - g_idle_add_full ( - G_PRIORITY_DEFAULT_IDLE, - (GSourceFunc) session_play_sound_cb, - g_strdup (filename), (GDestroyNotify) g_free); -} - -static void -session_system_beep (CamelFilterDriver *driver, - gpointer user_data) -{ - g_idle_add ((GSourceFunc) session_play_sound_cb, NULL); -} - -static CamelFilterDriver * -main_get_filter_driver (CamelSession *session, - const gchar *type, - GError **error) -{ - EMailSession *ms = E_MAIL_SESSION (session); - CamelFilterDriver *driver; - EFilterRule *rule = NULL; - const gchar *config_dir; - gchar *user, *system; - GSettings *settings; - ERuleContext *fc; - - settings = g_settings_new ("org.gnome.evolution.mail"); - - config_dir = mail_session_get_config_dir (); - user = g_build_filename (config_dir, "filters.xml", NULL); - system = g_build_filename (EVOLUTION_PRIVDATADIR, "filtertypes.xml", NULL); - fc = (ERuleContext *) em_filter_context_new (ms); - e_rule_context_load (fc, system, user); - g_free (system); - g_free (user); - - driver = camel_filter_driver_new (session); - camel_filter_driver_set_folder_func (driver, get_folder, session); - - if (g_settings_get_boolean (settings, "filters-log-actions")) { - if (ms->priv->filter_logfile == NULL) { - gchar *filename; - - filename = g_settings_get_string (settings, "filters-log-file"); - if (filename) { - ms->priv->filter_logfile = g_fopen (filename, "a+"); - g_free (filename); - } - } - - if (ms->priv->filter_logfile) - camel_filter_driver_set_logfile (driver, ms->priv->filter_logfile); - } - - camel_filter_driver_set_shell_func (driver, mail_execute_shell_command, NULL); - camel_filter_driver_set_play_sound_func (driver, session_play_sound, NULL); - camel_filter_driver_set_system_beep_func (driver, session_system_beep, NULL); - - if ((!strcmp (type, E_FILTER_SOURCE_INCOMING) || - !strcmp (type, E_FILTER_SOURCE_JUNKTEST)) - && camel_session_get_check_junk (session)) { - - /* implicit junk check as 1st rule */ - camel_filter_driver_add_rule ( - driver, "Junk check", "(junk-test)", - "(begin (set-system-flag \"junk\"))"); - } - - if (strcmp (type, E_FILTER_SOURCE_JUNKTEST) != 0) { - GString *fsearch, *faction; - - fsearch = g_string_new (""); - faction = g_string_new (""); - - if (!strcmp (type, E_FILTER_SOURCE_DEMAND)) - type = E_FILTER_SOURCE_INCOMING; - - /* add the user-defined rules next */ - while ((rule = e_rule_context_next_rule (fc, rule, type))) { - g_string_truncate (fsearch, 0); - g_string_truncate (faction, 0); - - /* skip disabled rules */ - if (!rule->enabled) - continue; - - e_filter_rule_build_code (rule, fsearch); - em_filter_rule_build_action ( - EM_FILTER_RULE (rule), faction); - camel_filter_driver_add_rule ( - driver, rule->name, - fsearch->str, faction->str); - } - - g_string_free (fsearch, TRUE); - g_string_free (faction, TRUE); - } - - g_object_unref (fc); - - g_object_unref (settings); - - return driver; -} - -/* Support for CamelSession.forward_to () ************************************/ - -static guint preparing_flush = 0; - -static gboolean -forward_to_flush_outbox_cb (EMailSession *session) -{ - g_return_val_if_fail (preparing_flush != 0, FALSE); - - preparing_flush = 0; - mail_send (session); - - return FALSE; -} - -static void -ms_forward_to_cb (CamelFolder *folder, - GAsyncResult *result, - EMailSession *session) -{ - GSettings *settings; - - /* FIXME Poor error handling. */ - if (!e_mail_folder_append_message_finish (folder, result, NULL, NULL)) - return; - - settings = g_settings_new ("org.gnome.evolution.mail"); - - /* do not call mail send immediately, just pile them all in the outbox */ - if (preparing_flush || g_settings_get_boolean ( - settings, "flush-outbox")) { - if (preparing_flush) - g_source_remove (preparing_flush); - - preparing_flush = g_timeout_add_seconds ( - 60, (GSourceFunc) - forward_to_flush_outbox_cb, session); - } - - g_object_unref (settings); -} - -static void -async_context_free (AsyncContext *context) -{ - if (context->folder != NULL) - g_object_unref (context->folder); - - g_free (context->uid); - g_free (context->uri); - - g_slice_free (AsyncContext, context); -} - -static void -source_context_free (SourceContext *context) -{ - if (context->session != NULL) - g_object_unref (context->session); - - if (context->service != NULL) - g_object_unref (context->service); - - g_slice_free (SourceContext, context); -} - -static gchar * -mail_session_make_key (CamelService *service, - const gchar *item) -{ - gchar *key; - - if (service != NULL) { - CamelURL *url; - - url = camel_service_new_camel_url (service); - key = camel_url_to_string (url, CAMEL_URL_HIDE_ALL); - camel_url_free (url); - } else - key = g_strdup (item); - - return key; -} - -static void -mail_session_check_junk_notify (GSettings *settings, - const gchar *key, - CamelSession *session) -{ - if (strcmp (key, "junk-check-incoming") == 0) - camel_session_set_check_junk ( - session, g_settings_get_boolean (settings, key)); -} - -static const gchar * -mail_session_get_junk_filter_name (EMailSession *session) -{ - CamelJunkFilter *junk_filter; - GHashTableIter iter; - gpointer key, value; - - /* XXX This property can be removed once Evolution moves to - * GSettings and can use transform functions when binding - * properties to settings. That's why this is private. */ - - g_hash_table_iter_init (&iter, session->priv->junk_filters); - junk_filter = camel_session_get_junk_filter (CAMEL_SESSION (session)); - - while (g_hash_table_iter_next (&iter, &key, &value)) { - if (junk_filter == CAMEL_JUNK_FILTER (value)) - return (const gchar *) key; - } - - if (junk_filter != NULL) - g_warning ( - "Camel is using a junk filter " - "unknown to Evolution of type %s", - G_OBJECT_TYPE_NAME (junk_filter)); - - return ""; -} - -static void -mail_session_set_junk_filter_name (EMailSession *session, - const gchar *junk_filter_name) -{ - CamelJunkFilter *junk_filter = NULL; - - /* XXX This property can be removed once Evolution moves to - * GSettings and can use transform functions when binding - * properties to settings. That's why this is private. */ - - /* An empty string is equivalent to a NULL string. */ - if (junk_filter_name != NULL && *junk_filter_name == '\0') - junk_filter_name = NULL; - - if (junk_filter_name != NULL) { - junk_filter = g_hash_table_lookup ( - session->priv->junk_filters, junk_filter_name); - if (junk_filter != NULL) { - if (!e_mail_junk_filter_available ( - E_MAIL_JUNK_FILTER (junk_filter))) - junk_filter = NULL; - } else { - g_warning ( - "Unrecognized junk filter name " - "'%s' in GSettings", junk_filter_name); - } - } - - camel_session_set_junk_filter (CAMEL_SESSION (session), junk_filter); - - /* XXX We emit the "notify" signal in mail_session_notify(). */ -} - -static void -mail_session_add_by_account (EMailSession *session, - EAccount *account) -{ - CamelService *service = NULL; - CamelProvider *provider; - CamelURL *url; - gboolean transport_only; - GError *error = NULL; - - /* check whether it's transport-only accounts */ - transport_only = - (account->source == NULL) || - (account->source->url == NULL) || - (*account->source->url == '\0'); - if (transport_only) - goto handle_transport; - - /* Load the service, but don't connect. Check its provider, - * and if this belongs in the folder tree model, add it. */ - - url = camel_url_new (account->source->url, NULL); - if (url != NULL) { - provider = camel_provider_get (url->protocol, NULL); - camel_url_free (url); - } else { - provider = NULL; - } - - if (provider == NULL) { - /* In case we do not have a provider here, we handle - * the special case of having multiple mail identities - * eg. a dummy account having just SMTP server defined */ - goto handle_transport; - } - - service = camel_session_add_service ( - CAMEL_SESSION (session), - account->uid, provider->protocol, - CAMEL_PROVIDER_STORE, &error); - - if (error != NULL) { - g_warning ( - "Failed to add service: %s: %s", - account->name, error->message); - g_error_free (error); - return; - } - - camel_service_set_display_name (service, account->name); - -handle_transport: - - /* While we're at it, add the account's transport (if it has one) - * to the CamelSession. The transport's UID is a kludge for now. - * We take the EAccount's UID and tack on "-transport". */ - - if (account->transport) { - GError *transport_error = NULL; - - url = camel_url_new ( - account->transport->url, - &transport_error); - - if (url != NULL) { - provider = camel_provider_get ( - url->protocol, &transport_error); - camel_url_free (url); - } else - provider = NULL; - - if (provider != NULL) { - gchar *transport_uid; - - transport_uid = g_strconcat ( - account->uid, "-transport", NULL); - - camel_session_add_service ( - CAMEL_SESSION (session), - transport_uid, provider->protocol, - CAMEL_PROVIDER_TRANSPORT, &transport_error); - - g_free (transport_uid); - } - - if (transport_error) { - g_warning ( - "%s: Failed to add transport service: %s", - G_STRFUNC, transport_error->message); - g_error_free (transport_error); - } - } -} - -static void -mail_session_account_added_cb (EAccountList *account_list, - EAccount *account, - EMailSession *session) -{ - mail_session_add_by_account (session, account); -} - -static void -mail_session_account_changed_cb (EAccountList *account_list, - EAccount *account, - EMailSession *session) -{ - EMFolderTreeModel *folder_tree_model; - CamelService *service; - - service = camel_session_get_service ( - CAMEL_SESSION (session), account->uid); - - if (!CAMEL_IS_STORE (service)) - return; - - /* Update the display name of the corresponding CamelStore. - * EMailAccountStore listens for "notify" signals from each - * service so it will detect this and update the model. - * - * XXX If EAccount defined GObject properties we could just - * bind EAccount:name to CamelService:display-name and - * be done with it. Oh well. - */ - - camel_service_set_display_name (service, account->name); - - /* Remove the store from the folder tree model and, if the - * account is still enabled, re-add it. Easier than trying - * to update the model with the store in place. - * - * em_folder_tree_model_add_store() already knows which types - * of stores to disregard, so we don't have to deal with that - * here. */ - - folder_tree_model = em_folder_tree_model_get_default (); - - em_folder_tree_model_remove_store ( - folder_tree_model, CAMEL_STORE (service)); - - if (account->enabled) - em_folder_tree_model_add_store ( - folder_tree_model, CAMEL_STORE (service)); -} - -static gboolean -mail_session_add_service_cb (SourceContext *context) -{ - EMailAccountStore *store; - - store = e_mail_session_get_account_store (context->session); - e_mail_account_store_add_service (store, context->service); - - return FALSE; -} - -static void -mail_session_add_local_store (EMailSession *session) -{ - CamelLocalSettings *local_settings; - CamelSession *camel_session; - CamelSettings *settings; - CamelService *service; - const gchar *data_dir; - gchar *path; - gint ii; - GError *error = NULL; - - camel_session = CAMEL_SESSION (session); - - service = camel_session_add_service ( - camel_session, E_MAIL_SESSION_LOCAL_UID, - "maildir", CAMEL_PROVIDER_STORE, &error); - - /* XXX One could argue this is a fatal error - * since we depend on it in so many places. */ - if (error != NULL) { - g_critical ("%s: %s", G_STRFUNC, error->message); - g_error_free (error); - return; - } - - g_return_if_fail (CAMEL_IS_SERVICE (service)); - - camel_service_set_display_name (service, _("On This Computer")); - - settings = camel_service_get_settings (service); - local_settings = CAMEL_LOCAL_SETTINGS (settings); - data_dir = camel_session_get_user_data_dir (camel_session); - - path = g_build_filename (data_dir, E_MAIL_SESSION_LOCAL_UID, NULL); - camel_local_settings_set_path (local_settings, path); - g_free (path); - - /* Shouldn't need to worry about other mail applications - * altering files in our local mail store. */ - g_object_set (service, "need-summary-check", FALSE, NULL); - - /* Populate the local folder cache. */ - for (ii = 0; ii < E_MAIL_NUM_LOCAL_FOLDERS; ii++) { - CamelFolder *folder; - gchar *folder_uri; - const gchar *display_name; - GError *error = NULL; - - display_name = local_folder_names[ii]; - - /* XXX This blocks but should be fast. */ - if (ii == E_MAIL_LOCAL_FOLDER_LOCAL_INBOX) - folder = camel_store_get_inbox_folder_sync ( - CAMEL_STORE (service), NULL, &error); - else - folder = camel_store_get_folder_sync ( - CAMEL_STORE (service), display_name, - CAMEL_STORE_FOLDER_CREATE, NULL, &error); - - folder_uri = e_mail_folder_uri_build ( - CAMEL_STORE (service), display_name); - - /* The arrays take ownership of the items added. */ - g_ptr_array_add (session->priv->local_folders, folder); - g_ptr_array_add (session->priv->local_folder_uris, folder_uri); - - if (error != NULL) { - g_critical ("%s: %s", G_STRFUNC, error->message); - g_error_free (error); - } - } - - session->priv->local_store = g_object_ref (service); -} - -static void -mail_session_add_vfolder_store (EMailSession *session) -{ - CamelSession *camel_session; - CamelService *service; - GError *error = NULL; - - camel_session = CAMEL_SESSION (session); - - service = camel_session_add_service ( - camel_session, E_MAIL_SESSION_VFOLDER_UID, - "vfolder", CAMEL_PROVIDER_STORE, &error); - - if (error != NULL) { - g_critical ("%s: %s", G_STRFUNC, error->message); - g_error_free (error); - return; - } - - g_return_if_fail (CAMEL_IS_SERVICE (service)); - - camel_service_set_display_name (service, _("Search Folders")); - em_utils_connect_service_sync (service, NULL, NULL); - - /* XXX There's more configuration to do in vfolder_load_storage() - * but it requires an EMailBackend, which we don't have access - * to from here, so it has to be called from elsewhere. Kinda - * thinking about reworking that... */ - - session->priv->vfolder_store = g_object_ref (service); -} - -static void -mail_session_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_JUNK_FILTER_NAME: - mail_session_set_junk_filter_name ( - E_MAIL_SESSION (object), - g_value_get_string (value)); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -mail_session_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_ACCOUNT_STORE: - g_value_set_object ( - value, - e_mail_session_get_account_store ( - E_MAIL_SESSION (object))); - return; - - case PROP_FOLDER_CACHE: - g_value_set_object ( - value, - e_mail_session_get_folder_cache ( - E_MAIL_SESSION (object))); - return; - - case PROP_JUNK_FILTER_NAME: - g_value_set_string ( - value, - mail_session_get_junk_filter_name ( - E_MAIL_SESSION (object))); - return; - - case PROP_LABEL_STORE: - g_value_set_object ( - value, - e_mail_session_get_label_store ( - E_MAIL_SESSION (object))); - return; - - case PROP_LOCAL_STORE: - g_value_set_object ( - value, - e_mail_session_get_local_store ( - E_MAIL_SESSION (object))); - return; - - case PROP_VFOLDER_STORE: - g_value_set_object ( - value, - e_mail_session_get_vfolder_store ( - E_MAIL_SESSION (object))); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -mail_session_dispose (GObject *object) -{ - EMailSessionPrivate *priv; - - priv = E_MAIL_SESSION_GET_PRIVATE (object); - - if (priv->account_store != NULL) { - e_mail_account_store_clear (priv->account_store); - g_object_unref (priv->account_store); - priv->account_store = NULL; - } - - if (priv->folder_cache != NULL) { - g_object_unref (priv->folder_cache); - priv->folder_cache = NULL; - } - - if (priv->label_store != NULL) { - g_object_unref (priv->label_store); - priv->label_store = NULL; - } - - if (priv->account_list != NULL) { - g_signal_handler_disconnect ( - priv->account_list, - priv->account_added_handler_id); - g_signal_handler_disconnect ( - priv->account_list, - priv->account_changed_handler_id); - g_object_unref (priv->account_list); - priv->account_list = NULL; - } - - if (priv->local_store != NULL) { - g_object_unref (priv->local_store); - priv->local_store = NULL; - } - - if (priv->vfolder_store != NULL) { - g_object_unref (priv->vfolder_store); - priv->vfolder_store = NULL; - } - - g_ptr_array_set_size (priv->local_folders, 0); - g_ptr_array_set_size (priv->local_folder_uris, 0); - - /* Chain up to parent's dispose() method. */ - G_OBJECT_CLASS (e_mail_session_parent_class)->dispose (object); -} - -static void -mail_session_finalize (GObject *object) -{ - EMailSessionPrivate *priv; - - priv = E_MAIL_SESSION_GET_PRIVATE (object); - - g_hash_table_destroy (priv->junk_filters); - g_object_unref (priv->proxy); - - g_ptr_array_free (priv->local_folders, TRUE); - g_ptr_array_free (priv->local_folder_uris, TRUE); - - g_free (mail_data_dir); - g_free (mail_config_dir); - - /* Chain up to parent's finalize() method. */ - G_OBJECT_CLASS (e_mail_session_parent_class)->finalize (object); -} - -static void -mail_session_notify (GObject *object, - GParamSpec *pspec) -{ - /* GObject does not implement this method; do not chain up. */ - - /* XXX Delete this once Evolution moves to GSettings and - * we're able to get rid of PROP_JUNK_FILTER_NAME. */ - if (g_strcmp0 (pspec->name, "junk-filter") == 0) - g_object_notify (object, "junk-filter-name"); -} - -static gboolean -mail_session_initialize_stores_idle (gpointer user_data) -{ - EMailSession *session = user_data; - EAccountList *account_list; - EAccount *account; - EIterator *iter; - - g_return_val_if_fail (session != NULL, FALSE); - - /* Load user-defined mail accounts. */ - account_list = session->priv->account_list; - iter = e_list_get_iterator (E_LIST (account_list)); - - while (e_iterator_is_valid (iter)) { - /* XXX EIterator misuses const. */ - account = (EAccount *) e_iterator_get (iter); - - mail_session_add_by_account (session, account); - - e_iterator_next (iter); - } - - g_object_unref (iter); - - /* Initialize which account is default. */ - - account = e_get_default_account (); - if (account != NULL) { - CamelService *service; - - service = camel_session_get_service ( - CAMEL_SESSION (session), account->uid); - e_mail_account_store_set_default_service ( - session->priv->account_store, service); - } - - return FALSE; -} - -static void -mail_session_constructed (GObject *object) -{ - EMFolderTreeModel *folder_tree_model; - EMailSession *session; - EExtensible *extensible; - GType extension_type; - GList *list, *link; - GSettings *settings; - EAccountList *account_list; - gulong handler_id; - - session = E_MAIL_SESSION (object); - - /* Chain up to parent's constructed() method. */ - G_OBJECT_CLASS (e_mail_session_parent_class)->constructed (object); - - account_list = e_get_account_list (); - session->priv->account_list = g_object_ref (account_list); - - session->priv->account_store = e_mail_account_store_new (session); - - /* This must be created after the account store. */ - session->priv->folder_cache = mail_folder_cache_new (session); - - /* XXX Make sure the folder tree model is created before we - * add built-in CamelStores so it gets signals from the - * EMailAccountStore. - * - * XXX This is creating a circular reference. Perhaps the - * model should only hold a weak pointer to EMailSession? - * - * FIXME EMailSession should just own the default instance. - */ - folder_tree_model = em_folder_tree_model_get_default (); - em_folder_tree_model_set_session (folder_tree_model, session); - - /* Add built-in CamelStores. */ - - mail_session_add_local_store (session); - mail_session_add_vfolder_store (session); - - /* Give it a chance to load user settings, they are not loaded yet. - * - * XXX Is this the case where hiding such natural things like loading - * user setting into an EExtension strikes back and proves itself - * being suboptimal? - */ - g_idle_add (mail_session_initialize_stores_idle, object); - - /* Listen for account list updates. */ - - handler_id = g_signal_connect ( - account_list, "account-added", - G_CALLBACK (mail_session_account_added_cb), session); - session->priv->account_added_handler_id = handler_id; - - handler_id = g_signal_connect ( - account_list, "account-changed", - G_CALLBACK (mail_session_account_changed_cb), session); - session->priv->account_changed_handler_id = handler_id; - - extensible = E_EXTENSIBLE (object); - e_extensible_load_extensions (extensible); - - /* Add junk filter extensions to an internal hash table. */ - - extension_type = E_TYPE_MAIL_JUNK_FILTER; - list = e_extensible_list_extensions (extensible, extension_type); - - for (link = list; link != NULL; link = g_list_next (link)) { - EMailJunkFilter *junk_filter; - EMailJunkFilterClass *class; - - junk_filter = E_MAIL_JUNK_FILTER (link->data); - class = E_MAIL_JUNK_FILTER_GET_CLASS (junk_filter); - - if (!CAMEL_IS_JUNK_FILTER (junk_filter)) { - g_warning ( - "Skipping %s: Does not implement " - "CamelJunkFilterInterface", - G_OBJECT_TYPE_NAME (junk_filter)); - continue; - } - - if (class->filter_name == NULL) { - g_warning ( - "Skipping %s: filter_name unset", - G_OBJECT_TYPE_NAME (junk_filter)); - continue; - } - - if (class->display_name == NULL) { - g_warning ( - "Skipping %s: display_name unset", - G_OBJECT_TYPE_NAME (junk_filter)); - continue; - } - - /* No need to reference the EMailJunkFilter since - * EMailSession owns the reference to it already. */ - g_hash_table_insert ( - session->priv->junk_filters, - (gpointer) class->filter_name, - junk_filter); - } - - g_list_free (list); - - /* Bind the "junk-default-plugin" GSettings - * key to our "junk-filter-name" property. */ - - settings = g_settings_new ("org.gnome.evolution.mail"); - g_settings_bind ( - settings, "junk-default-plugin", - object, "junk-filter-name", - G_SETTINGS_BIND_DEFAULT); - g_object_unref (settings); -} - -static CamelService * -mail_session_add_service (CamelSession *session, - const gchar *uid, - const gchar *protocol, - CamelProviderType type, - GError **error) -{ - CamelService *service; - - /* Chain up to parents add_service() method. */ - service = CAMEL_SESSION_CLASS (e_mail_session_parent_class)-> - add_service (session, uid, protocol, type, error); - - /* Initialize the CamelSettings object from CamelURL parameters. - * This is temporary; soon we'll read settings from key files. */ - - if (CAMEL_IS_SERVICE (service)) { - EAccount *account; - CamelURL *url = NULL; - - account = e_get_account_by_uid (uid); - if (account != NULL) { - const gchar *url_string = NULL; - - switch (type) { - case CAMEL_PROVIDER_STORE: - url_string = account->source->url; - break; - case CAMEL_PROVIDER_TRANSPORT: - url_string = account->transport->url; - break; - default: - break; - } - - if (url_string != NULL) { - url = camel_url_new (url_string, error); - if (url == NULL) { - g_object_unref (service); - service = NULL; - } - } - } - - if (url != NULL) { - CamelSettings *settings; - - settings = camel_service_get_settings (service); - camel_settings_load_from_url (settings, url); - camel_url_free (url); - - g_object_notify (G_OBJECT (service), "settings"); - - /* Migrate files for this service from its old - * URL-based directory to a UID-based directory - * if necessary. */ - camel_service_migrate_files (service); - } - } - - /* Inform the EMailAccountStore of the new CamelService - * from an idle callback so the service has a chance to - * fully initialize first. */ - if (CAMEL_IS_STORE (service)) { - SourceContext *context; - - context = g_slice_new0 (SourceContext); - context->session = g_object_ref (session); - context->service = g_object_ref (service); - - g_idle_add_full ( - G_PRIORITY_DEFAULT_IDLE, - (GSourceFunc) mail_session_add_service_cb, - context, (GDestroyNotify) source_context_free); - } - - return service; -} - -static gchar * -mail_session_get_password (CamelSession *session, - CamelService *service, - const gchar *prompt, - const gchar *item, - guint32 flags, - GError **error) -{ - EAccount *account = NULL; - const gchar *display_name = NULL; - const gchar *uid = NULL; - gchar *ret = NULL; - - if (CAMEL_IS_SERVICE (service)) { - display_name = camel_service_get_display_name (service); - uid = camel_service_get_uid (service); - account = e_get_account_by_uid (uid); - } - - if (!strcmp(item, "popb4smtp_uid")) { - /* not 100% mt safe, but should be ok */ - ret = g_strdup ((account != NULL) ? account->uid : uid); - } else { - gchar *key = mail_session_make_key (service, item); - EAccountService *config_service = NULL; - - ret = e_passwords_get_password (NULL, key); - if (ret == NULL || (flags & CAMEL_SESSION_PASSWORD_REPROMPT)) { - gboolean remember; - - g_free (ret); - ret = NULL; - - if (account != NULL) { - if (CAMEL_IS_STORE (service)) - config_service = account->source; - if (CAMEL_IS_TRANSPORT (service)) - config_service = account->transport; - } - - remember = config_service ? config_service->save_passwd : FALSE; - - if (!config_service || (config_service && - !config_service->get_password_canceled)) { - guint32 eflags; - gchar *title; - - if (flags & CAMEL_SESSION_PASSPHRASE) { - if (display_name != NULL) - title = g_strdup_printf ( - _("Enter Passphrase for %s"), - display_name); - else - title = g_strdup ( - _("Enter Passphrase")); - } else { - if (display_name != NULL) - title = g_strdup_printf ( - _("Enter Password for %s"), - display_name); - else - title = g_strdup ( - _("Enter Password")); - } - if ((flags & CAMEL_SESSION_PASSWORD_STATIC) != 0) - eflags = E_PASSWORDS_REMEMBER_NEVER; - else if (config_service == NULL) - eflags = E_PASSWORDS_REMEMBER_SESSION; - else - eflags = E_PASSWORDS_REMEMBER_FOREVER; - - if (flags & CAMEL_SESSION_PASSWORD_REPROMPT) - eflags |= E_PASSWORDS_REPROMPT; - - if (flags & CAMEL_SESSION_PASSWORD_SECRET) - eflags |= E_PASSWORDS_SECRET; - - if (flags & CAMEL_SESSION_PASSPHRASE) - eflags |= E_PASSWORDS_PASSPHRASE; - - /* HACK: breaks abstraction ... - * e_account_writable() doesn't use the - * EAccount, it also uses the same writable - * key for source and transport. */ - if (!e_account_writable (NULL, E_ACCOUNT_SOURCE_SAVE_PASSWD)) - eflags |= E_PASSWORDS_DISABLE_REMEMBER; - - ret = e_passwords_ask_password ( - title, NULL, key, prompt, - eflags, &remember, NULL); - - if (!ret) - e_passwords_forget_password (NULL, key); - - g_free (title); - - if (ret && config_service) { - config_service->save_passwd = remember; - e_account_list_save (e_get_account_list ()); - } - - if (config_service) - config_service->get_password_canceled = ret == NULL; - } - } - - g_free (key); - } - - if (ret == NULL) - g_set_error ( - error, G_IO_ERROR, - G_IO_ERROR_CANCELLED, - _("User canceled operation.")); - - return ret; -} - -static gboolean -mail_session_forget_password (CamelSession *session, - CamelService *service, - const gchar *item, - GError **error) -{ - gchar *key; - - key = mail_session_make_key (service, item); - - e_passwords_forget_password (NULL, key); - - g_free (key); - - return TRUE; -} - -static gint -mail_session_alert_user (CamelSession *session, - CamelSessionAlertType type, - const gchar *prompt, - GSList *button_captions) -{ - struct _user_message_msg *m; - GCancellable *cancellable; - gint result = -1; - GSList *iter; - - m = mail_msg_new (&user_message_info); - m->ismain = mail_in_main_thread (); - m->type = type; - m->prompt = g_strdup (prompt); - m->done = e_flag_new (); - m->button_captions = g_slist_copy (button_captions); - - for (iter = m->button_captions; iter; iter = iter->next) - iter->data = g_strdup (iter->data); - - if (g_slist_length (button_captions) > 1) - mail_msg_ref (m); - - cancellable = e_activity_get_cancellable (m->base.activity); - - if (m->ismain) - user_message_exec (m, cancellable, &m->base.error); - else - mail_msg_main_loop_push (m); - - if (g_slist_length (button_captions) > 1) { - e_flag_wait (m->done); - result = m->result; - mail_msg_unref (m); - } else if (m->ismain) - mail_msg_unref (m); - - return result; -} - -static CamelFilterDriver * -mail_session_get_filter_driver (CamelSession *session, - const gchar *type, - GError **error) -{ - return (CamelFilterDriver *) mail_call_main ( - MAIL_CALL_p_ppp, (MailMainFunc) main_get_filter_driver, - session, type, error); -} - -static gboolean -mail_session_lookup_addressbook (CamelSession *session, - const gchar *name) -{ - CamelInternetAddress *addr; - gboolean ret; - - if (!mail_config_get_lookup_book ()) - return FALSE; - - addr = camel_internet_address_new (); - camel_address_decode ((CamelAddress *) addr, name); - ret = em_utils_in_addressbook ( - addr, mail_config_get_lookup_book_local_only ()); - g_object_unref (addr); - - return ret; -} - -static gboolean -mail_session_forward_to (CamelSession *session, - CamelFolder *folder, - CamelMimeMessage *message, - const gchar *address, - GError **error) -{ - EAccount *account; - CamelMimeMessage *forward; - CamelStream *mem; - CamelInternetAddress *addr; - CamelFolder *out_folder; - CamelMessageInfo *info; - CamelMedium *medium; - const gchar *from_address; - const gchar *from_name; - const gchar *header_name; - struct _camel_header_raw *xev; - gchar *subject; - - g_return_val_if_fail (folder != NULL, FALSE); - g_return_val_if_fail (message != NULL, FALSE); - g_return_val_if_fail (address != NULL, FALSE); - - if (!*address) { - g_set_error ( - error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, - _("No destination address provided, forward " - "of the message has been cancelled.")); - return FALSE; - } - - account = em_utils_guess_account_with_recipients (message, folder); - if (!account) { - g_set_error ( - error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, - _("No account found to use, forward of the " - "message has been cancelled.")); - return FALSE; - } - - from_address = account->id->address; - from_name = account->id->name; - - forward = camel_mime_message_new (); - - /* make copy of the message, because we are going to modify it */ - mem = camel_stream_mem_new (); - camel_data_wrapper_write_to_stream_sync ( - CAMEL_DATA_WRAPPER (message), mem, NULL, NULL); - g_seekable_seek (G_SEEKABLE (mem), 0, G_SEEK_SET, NULL, NULL); - camel_data_wrapper_construct_from_stream_sync ( - CAMEL_DATA_WRAPPER (forward), mem, NULL, NULL); - g_object_unref (mem); - - /* clear previous recipients */ - camel_mime_message_set_recipients ( - forward, CAMEL_RECIPIENT_TYPE_TO, NULL); - camel_mime_message_set_recipients ( - forward, CAMEL_RECIPIENT_TYPE_CC, NULL); - camel_mime_message_set_recipients ( - forward, CAMEL_RECIPIENT_TYPE_BCC, NULL); - camel_mime_message_set_recipients ( - forward, CAMEL_RECIPIENT_TYPE_RESENT_TO, NULL); - camel_mime_message_set_recipients ( - forward, CAMEL_RECIPIENT_TYPE_RESENT_CC, NULL); - camel_mime_message_set_recipients ( - forward, CAMEL_RECIPIENT_TYPE_RESENT_BCC, NULL); - - medium = CAMEL_MEDIUM (forward); - - /* remove all delivery and notification headers */ - header_name = "Disposition-Notification-To"; - while (camel_medium_get_header (medium, header_name)) - camel_medium_remove_header (medium, header_name); - - header_name = "Delivered-To"; - while (camel_medium_get_header (medium, header_name)) - camel_medium_remove_header (medium, header_name); - - /* remove any X-Evolution-* headers that may have been set */ - xev = mail_tool_remove_xevolution_headers (forward); - camel_header_raw_clear (&xev); - - /* from */ - addr = camel_internet_address_new (); - camel_internet_address_add (addr, from_name, from_address); - camel_mime_message_set_from (forward, addr); - g_object_unref (addr); - - /* to */ - addr = camel_internet_address_new (); - camel_address_decode (CAMEL_ADDRESS (addr), address); - camel_mime_message_set_recipients ( - forward, CAMEL_RECIPIENT_TYPE_TO, addr); - g_object_unref (addr); - - /* subject */ - subject = mail_tool_generate_forward_subject (message); - camel_mime_message_set_subject (forward, subject); - g_free (subject); - - /* and send it */ - info = camel_message_info_new (NULL); - out_folder = e_mail_session_get_local_folder ( - E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_OUTBOX); - camel_message_info_set_flags ( - info, CAMEL_MESSAGE_SEEN, CAMEL_MESSAGE_SEEN); - - /* FIXME Pass a GCancellable. */ - e_mail_folder_append_message ( - out_folder, forward, info, G_PRIORITY_DEFAULT, NULL, - (GAsyncReadyCallback) ms_forward_to_cb, session); - - camel_message_info_free (info); - - return TRUE; -} - -static void -mail_session_get_socks_proxy (CamelSession *session, - const gchar *for_host, - gchar **host_ret, - gint *port_ret) -{ - EMailSession *mail_session; - gchar *uri; - - g_return_if_fail (session != NULL); - g_return_if_fail (for_host != NULL); - g_return_if_fail (host_ret != NULL); - g_return_if_fail (port_ret != NULL); - - mail_session = E_MAIL_SESSION (session); - g_return_if_fail (mail_session != NULL); - g_return_if_fail (mail_session->priv != NULL); - - *host_ret = NULL; - *port_ret = 0; - - uri = g_strconcat ("socks://", for_host, NULL); - - if (e_proxy_require_proxy_for_uri (mail_session->priv->proxy, uri)) { - SoupURI *suri; - - suri = e_proxy_peek_uri_for (mail_session->priv->proxy, uri); - if (suri) { - *host_ret = g_strdup (suri->host); - *port_ret = suri->port; - } - } - - g_free (uri); -} - -static gboolean -mail_session_authenticate_sync (CamelSession *session, - CamelService *service, - const gchar *mechanism, - GCancellable *cancellable, - GError **error) -{ - CamelServiceAuthType *authtype = NULL; - CamelAuthenticationResult result; - CamelProvider *provider; - CamelSettings *settings; - const gchar *password; - guint32 password_flags; - GError *local_error = NULL; - - /* Do not chain up. Camel's default method is only an example for - * subclasses to follow. Instead we mimic most of its logic here. */ - - provider = camel_service_get_provider (service); - settings = camel_service_get_settings (service); - - /* APOP is one case where a non-SASL mechanism name is passed, so - * don't bail if the CamelServiceAuthType struct comes back NULL. */ - if (mechanism != NULL) - authtype = camel_sasl_authtype (mechanism); - - /* If the SASL mechanism does not involve a user - * password, then it gets one shot to authenticate. */ - if (authtype != NULL && !authtype->need_password) { - result = camel_service_authenticate_sync ( - service, mechanism, cancellable, error); - if (result == CAMEL_AUTHENTICATION_REJECTED) - g_set_error ( - error, CAMEL_SERVICE_ERROR, - CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE, - _("%s authentication failed"), mechanism); - return (result == CAMEL_AUTHENTICATION_ACCEPTED); - } - - /* Some SASL mechanisms can attempt to authenticate without a - * user password being provided (e.g. single-sign-on credentials), - * but can fall back to a user password. Handle that case next. */ - if (mechanism != NULL) { - CamelProvider *provider; - CamelSasl *sasl; - const gchar *service_name; - gboolean success = FALSE; - - provider = camel_service_get_provider (service); - service_name = provider->protocol; - - /* XXX Would be nice if camel_sasl_try_empty_password_sync() - * returned CamelAuthenticationResult so it's easier to - * detect errors. */ - sasl = camel_sasl_new (service_name, mechanism, service); - if (sasl != NULL) { - success = camel_sasl_try_empty_password_sync ( - sasl, cancellable, &local_error); - g_object_unref (sasl); - } - - if (success) - return TRUE; - } - - /* Abort authentication if we got cancelled. - * Otherwise clear any errors and press on. */ - if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return FALSE; - - g_clear_error (&local_error); - - password_flags = CAMEL_SESSION_PASSWORD_SECRET; - -retry: - password = camel_service_get_password (service); - - if (password == NULL) { - CamelNetworkSettings *network_settings; - const gchar *host; - const gchar *user; - gchar *prompt; - gchar *new_passwd; - - network_settings = CAMEL_NETWORK_SETTINGS (settings); - host = camel_network_settings_get_host (network_settings); - user = camel_network_settings_get_user (network_settings); - - prompt = camel_session_build_password_prompt ( - provider->name, user, host); - - new_passwd = camel_session_get_password ( - session, service, prompt, "password", - password_flags, &local_error); - camel_service_set_password (service, new_passwd); - password = camel_service_get_password (service); - g_free (new_passwd); - - g_free (prompt); - - if (local_error != NULL) { - g_propagate_error (error, local_error); - return FALSE; - } - - if (password == NULL) { - g_set_error ( - error, CAMEL_SERVICE_ERROR, - CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE, - _("No password was provided")); - return FALSE; - } - } - - result = camel_service_authenticate_sync ( - service, mechanism, cancellable, error); - - if (result == CAMEL_AUTHENTICATION_REJECTED) { - password_flags |= CAMEL_SESSION_PASSWORD_REPROMPT; - camel_service_set_password (service, NULL); - goto retry; - } - - return (result == CAMEL_AUTHENTICATION_ACCEPTED); -} - -static void -e_mail_session_class_init (EMailSessionClass *class) -{ - GObjectClass *object_class; - CamelSessionClass *session_class; - - g_type_class_add_private (class, sizeof (EMailSessionPrivate)); - - object_class = G_OBJECT_CLASS (class); - object_class->set_property = mail_session_set_property; - object_class->get_property = mail_session_get_property; - object_class->dispose = mail_session_dispose; - object_class->finalize = mail_session_finalize; - object_class->notify = mail_session_notify; - object_class->constructed = mail_session_constructed; - - session_class = CAMEL_SESSION_CLASS (class); - session_class->add_service = mail_session_add_service; - session_class->get_password = mail_session_get_password; - session_class->forget_password = mail_session_forget_password; - session_class->alert_user = mail_session_alert_user; - session_class->get_filter_driver = mail_session_get_filter_driver; - session_class->lookup_addressbook = mail_session_lookup_addressbook; - session_class->forward_to = mail_session_forward_to; - session_class->get_socks_proxy = mail_session_get_socks_proxy; - session_class->authenticate_sync = mail_session_authenticate_sync; - - g_object_class_install_property ( - object_class, - PROP_FOLDER_CACHE, - g_param_spec_object ( - "folder-cache", - NULL, - NULL, - MAIL_TYPE_FOLDER_CACHE, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - /* XXX This property can be removed once Evolution moves to - * GSettings and can use transform functions when binding - * properties to settings. */ - g_object_class_install_property ( - object_class, - PROP_JUNK_FILTER_NAME, - g_param_spec_string ( - "junk-filter-name", - NULL, - NULL, - NULL, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property ( - object_class, - PROP_LABEL_STORE, - g_param_spec_object ( - "label-store", - "Label Store", - "Mail label store", - E_TYPE_MAIL_LABEL_LIST_STORE, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property ( - object_class, - PROP_LOCAL_STORE, - g_param_spec_object ( - "local-store", - "Local Store", - "Built-in local store", - CAMEL_TYPE_STORE, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property ( - object_class, - PROP_VFOLDER_STORE, - g_param_spec_object ( - "vfolder-store", - "Search Folder Store", - "Built-in search folder store", - CAMEL_TYPE_STORE, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - signals[ACTIVITY_ADDED] = g_signal_new ( - "activity-added", - G_OBJECT_CLASS_TYPE (class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EMailSessionClass, activity_added), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, - E_TYPE_ACTIVITY); -} - -static void -e_mail_session_init (EMailSession *session) -{ - GSettings *settings; - GHashTable *junk_filters; - - junk_filters = g_hash_table_new ( - (GHashFunc) g_str_hash, - (GEqualFunc) g_str_equal); - - session->priv = E_MAIL_SESSION_GET_PRIVATE (session); - session->priv->label_store = e_mail_label_list_store_new (); - session->priv->junk_filters = junk_filters; - session->priv->proxy = e_proxy_new (); - - session->priv->local_folders = - g_ptr_array_new_with_free_func ( - (GDestroyNotify) g_object_unref); - session->priv->local_folder_uris = - g_ptr_array_new_with_free_func ( - (GDestroyNotify) g_free); - - /* Initialize the EAccount setup. */ - e_account_writable (NULL, E_ACCOUNT_SOURCE_SAVE_PASSWD); - - settings = g_settings_new ("org.gnome.evolution.mail"); - - camel_session_set_check_junk ( - CAMEL_SESSION (session), g_settings_get_boolean ( - settings, "junk-check-incoming")); - g_signal_connect ( - settings, "changed", - G_CALLBACK (mail_session_check_junk_notify), session); - - mail_config_reload_junk_headers (session); - - e_proxy_setup_proxy (session->priv->proxy); - - g_object_unref (settings); -} - -EMailSession * -e_mail_session_new (void) -{ - const gchar *user_data_dir; - const gchar *user_cache_dir; - - user_data_dir = mail_session_get_data_dir (); - user_cache_dir = mail_session_get_cache_dir (); - - return g_object_new ( - E_TYPE_MAIL_SESSION, - "user-data-dir", user_data_dir, - "user-cache-dir", user_cache_dir, - NULL); -} - -void -e_mail_session_add_activity (EMailSession *session, - EActivity *activity) -{ - g_return_if_fail (E_IS_MAIL_SESSION (session)); - g_return_if_fail (E_IS_ACTIVITY (activity)); - - g_signal_emit (session, signals[ACTIVITY_ADDED], 0, activity); -} - -EMailAccountStore * -e_mail_session_get_account_store (EMailSession *session) -{ - g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); - - return session->priv->account_store; -} - -MailFolderCache * -e_mail_session_get_folder_cache (EMailSession *session) -{ - g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); - - return session->priv->folder_cache; -} - -EMailLabelListStore * -e_mail_session_get_label_store (EMailSession *session) -{ - g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); - - return session->priv->label_store; -} - -CamelStore * -e_mail_session_get_local_store (EMailSession *session) -{ - g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); - - return session->priv->local_store; -} - -CamelStore * -e_mail_session_get_vfolder_store (EMailSession *session) -{ - g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); - - return session->priv->vfolder_store; -} - -CamelFolder * -e_mail_session_get_local_folder (EMailSession *session, - EMailLocalFolder type) -{ - GPtrArray *local_folders; - CamelFolder *folder; - - g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); - - local_folders = session->priv->local_folders; - g_return_val_if_fail (type < local_folders->len, NULL); - - folder = g_ptr_array_index (local_folders, type); - g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL); - - return folder; -} - -const gchar * -e_mail_session_get_local_folder_uri (EMailSession *session, - EMailLocalFolder type) -{ - GPtrArray *local_folder_uris; - const gchar *folder_uri; - - g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); - - local_folder_uris = session->priv->local_folder_uris; - g_return_val_if_fail (type < local_folder_uris->len, NULL); - - folder_uri = g_ptr_array_index (local_folder_uris, type); - g_return_val_if_fail (folder_uri != NULL, NULL); - - return folder_uri; -} - -GList * -e_mail_session_get_available_junk_filters (EMailSession *session) -{ - GList *list, *link; - GQueue trash = G_QUEUE_INIT; - - g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); - - list = g_hash_table_get_values (session->priv->junk_filters); - - /* Discard unavailable junk filters. (e.g. Junk filter - * requires Bogofilter but Bogofilter is not installed, - * hence the junk filter is unavailable.) */ - - for (link = list; link != NULL; link = g_list_next (link)) { - EMailJunkFilter *junk_filter; - - junk_filter = E_MAIL_JUNK_FILTER (link->data); - if (!e_mail_junk_filter_available (junk_filter)) - g_queue_push_tail (&trash, link); - } - - while ((link = g_queue_pop_head (&trash)) != NULL) - list = g_list_delete_link (list, link); - - /* Sort the remaining junk filters by display name. */ - - return g_list_sort (list, (GCompareFunc) e_mail_junk_filter_compare); -} - -static void -mail_session_get_inbox_thread (GSimpleAsyncResult *simple, - EMailSession *session, - GCancellable *cancellable) -{ - AsyncContext *context; - GError *error = NULL; - - context = g_simple_async_result_get_op_res_gpointer (simple); - - context->folder = e_mail_session_get_inbox_sync ( - session, context->uid, cancellable, &error); - - if (error != NULL) - g_simple_async_result_take_error (simple, error); -} - -CamelFolder * -e_mail_session_get_inbox_sync (EMailSession *session, - const gchar *service_uid, - GCancellable *cancellable, - GError **error) -{ - CamelService *service; - - g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); - g_return_val_if_fail (service_uid != NULL, NULL); - - service = camel_session_get_service ( - CAMEL_SESSION (session), service_uid); - - if (!CAMEL_IS_STORE (service)) - return NULL; - - if (!em_utils_connect_service_sync (service, cancellable, error)) - return NULL; - - return camel_store_get_inbox_folder_sync ( - CAMEL_STORE (service), cancellable, error); -} - -void -e_mail_session_get_inbox (EMailSession *session, - const gchar *service_uid, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *simple; - AsyncContext *context; - - g_return_if_fail (E_IS_MAIL_SESSION (session)); - g_return_if_fail (service_uid != NULL); - - context = g_slice_new0 (AsyncContext); - context->uid = g_strdup (service_uid); - - simple = g_simple_async_result_new ( - G_OBJECT (session), callback, - user_data, e_mail_session_get_inbox); - - g_simple_async_result_set_op_res_gpointer ( - simple, context, (GDestroyNotify) async_context_free); - - g_simple_async_result_run_in_thread ( - simple, (GSimpleAsyncThreadFunc) - mail_session_get_inbox_thread, - io_priority, cancellable); - - g_object_unref (simple); -} - -CamelFolder * -e_mail_session_get_inbox_finish (EMailSession *session, - GAsyncResult *result, - GError **error) -{ - GSimpleAsyncResult *simple; - AsyncContext *context; - - g_return_val_if_fail ( - g_simple_async_result_is_valid ( - result, G_OBJECT (session), - e_mail_session_get_inbox), NULL); - - simple = G_SIMPLE_ASYNC_RESULT (result); - context = g_simple_async_result_get_op_res_gpointer (simple); - - if (g_simple_async_result_propagate_error (simple, error)) - return NULL; - - g_return_val_if_fail (CAMEL_IS_FOLDER (context->folder), NULL); - - return g_object_ref (context->folder); -} - -static void -mail_session_get_trash_thread (GSimpleAsyncResult *simple, - EMailSession *session, - GCancellable *cancellable) -{ - AsyncContext *context; - GError *error = NULL; - - context = g_simple_async_result_get_op_res_gpointer (simple); - - context->folder = e_mail_session_get_trash_sync ( - session, context->uid, cancellable, &error); - - if (error != NULL) - g_simple_async_result_take_error (simple, error); -} - -CamelFolder * -e_mail_session_get_trash_sync (EMailSession *session, - const gchar *service_uid, - GCancellable *cancellable, - GError **error) -{ - CamelService *service; - - g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); - g_return_val_if_fail (service_uid != NULL, NULL); - - service = camel_session_get_service ( - CAMEL_SESSION (session), service_uid); - - if (!CAMEL_IS_STORE (service)) - return NULL; - - if (!em_utils_connect_service_sync (service, cancellable, error)) - return NULL; - - return camel_store_get_trash_folder_sync ( - CAMEL_STORE (service), cancellable, error); -} - -void -e_mail_session_get_trash (EMailSession *session, - const gchar *service_uid, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *simple; - AsyncContext *context; - - g_return_if_fail (E_IS_MAIL_SESSION (session)); - g_return_if_fail (service_uid != NULL); - - context = g_slice_new0 (AsyncContext); - context->uid = g_strdup (service_uid); - - simple = g_simple_async_result_new ( - G_OBJECT (session), callback, - user_data, e_mail_session_get_trash); - - g_simple_async_result_set_op_res_gpointer ( - simple, context, (GDestroyNotify) async_context_free); - - g_simple_async_result_run_in_thread ( - simple, (GSimpleAsyncThreadFunc) - mail_session_get_trash_thread, - io_priority, cancellable); - - g_object_unref (simple); -} - -CamelFolder * -e_mail_session_get_trash_finish (EMailSession *session, - GAsyncResult *result, - GError **error) -{ - GSimpleAsyncResult *simple; - AsyncContext *context; - - g_return_val_if_fail ( - g_simple_async_result_is_valid ( - result, G_OBJECT (session), - e_mail_session_get_trash), NULL); - - simple = G_SIMPLE_ASYNC_RESULT (result); - context = g_simple_async_result_get_op_res_gpointer (simple); - - if (g_simple_async_result_propagate_error (simple, error)) - return NULL; - - g_return_val_if_fail (CAMEL_IS_FOLDER (context->folder), NULL); - - return g_object_ref (context->folder); -} - -static void -mail_session_uri_to_folder_thread (GSimpleAsyncResult *simple, - EMailSession *session, - GCancellable *cancellable) -{ - AsyncContext *context; - GError *error = NULL; - - context = g_simple_async_result_get_op_res_gpointer (simple); - - context->folder = e_mail_session_uri_to_folder_sync ( - session, context->uri, context->flags, - cancellable, &error); - - if (error != NULL) - g_simple_async_result_take_error (simple, error); -} - -CamelFolder * -e_mail_session_uri_to_folder_sync (EMailSession *session, - const gchar *folder_uri, - CamelStoreGetFolderFlags flags, - GCancellable *cancellable, - GError **error) -{ - CamelStore *store; - CamelFolder *folder; - gchar *folder_name; - gboolean success; - - g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); - g_return_val_if_fail (folder_uri != NULL, NULL); - - success = e_mail_folder_uri_parse ( - CAMEL_SESSION (session), folder_uri, - &store, &folder_name, error); - - if (!success) - return NULL; - - folder = camel_store_get_folder_sync ( - store, folder_name, flags, cancellable, error); - - if (folder != NULL) { - MailFolderCache *folder_cache; - folder_cache = e_mail_session_get_folder_cache (session); - mail_folder_cache_note_folder (folder_cache, folder); - } - - g_free (folder_name); - g_object_unref (store); - - return folder; -} - -void -e_mail_session_uri_to_folder (EMailSession *session, - const gchar *folder_uri, - CamelStoreGetFolderFlags flags, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *simple; - AsyncContext *context; - - g_return_if_fail (E_IS_MAIL_SESSION (session)); - g_return_if_fail (folder_uri != NULL); - - context = g_slice_new0 (AsyncContext); - context->uri = g_strdup (folder_uri); - context->flags = flags; - - simple = g_simple_async_result_new ( - G_OBJECT (session), callback, - user_data, e_mail_session_uri_to_folder); - - g_simple_async_result_set_op_res_gpointer ( - simple, context, (GDestroyNotify) async_context_free); - - g_simple_async_result_run_in_thread ( - simple, (GSimpleAsyncThreadFunc) - mail_session_uri_to_folder_thread, - io_priority, cancellable); - - g_object_unref (simple); -} - -CamelFolder * -e_mail_session_uri_to_folder_finish (EMailSession *session, - GAsyncResult *result, - GError **error) -{ - GSimpleAsyncResult *simple; - AsyncContext *context; - - g_return_val_if_fail ( - g_simple_async_result_is_valid ( - result, G_OBJECT (session), - e_mail_session_uri_to_folder), NULL); - - simple = G_SIMPLE_ASYNC_RESULT (result); - context = g_simple_async_result_get_op_res_gpointer (simple); - - if (g_simple_async_result_propagate_error (simple, error)) - return NULL; - - g_return_val_if_fail (CAMEL_IS_FOLDER (context->folder), NULL); - - return g_object_ref (context->folder); -} - -/******************************** Legacy API *********************************/ - -void -mail_session_flush_filter_log (EMailSession *session) -{ - g_return_if_fail (E_IS_MAIL_SESSION (session)); - - if (session->priv->filter_logfile) - fflush (session->priv->filter_logfile); -} - -const gchar * -mail_session_get_data_dir (void) -{ - if (G_UNLIKELY (mail_data_dir == NULL)) - mail_data_dir = g_build_filename ( - e_get_user_data_dir (), "mail", NULL); - - return mail_data_dir; -} - -const gchar * -mail_session_get_cache_dir (void) -{ - if (G_UNLIKELY (mail_cache_dir == NULL)) - mail_cache_dir = g_build_filename ( - e_get_user_cache_dir (), "mail", NULL); - - return mail_cache_dir; -} - -const gchar * -mail_session_get_config_dir (void) -{ - if (G_UNLIKELY (mail_config_dir == NULL)) - mail_config_dir = g_build_filename ( - e_get_user_config_dir (), "mail", NULL); - - return mail_config_dir; -} - diff --git a/mail/e-mail-session.h b/mail/e-mail-session.h deleted file mode 100644 index 7f5f22de27..0000000000 --- a/mail/e-mail-session.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * e-mail-session.h - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see - * - * - * Authors: - * Jeffrey Stedfast - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef E_MAIL_SESSION_H -#define E_MAIL_SESSION_H - -#include -#include -#include -#include -#include -#include - -/* Standard GObject macros */ -#define E_TYPE_MAIL_SESSION \ - (e_mail_session_get_type ()) -#define E_MAIL_SESSION(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST \ - ((obj), E_TYPE_MAIL_SESSION, EMailSession)) -#define E_MAIL_SESSION_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_CAST \ - ((cls), E_TYPE_MAIL_SESSION, EMailSessionClass)) -#define E_IS_MAIL_SESSION(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE \ - ((obj), E_TYPE_MAIL_SESSION)) -#define E_IS_MAIL_SESSION_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_TYPE \ - ((cls), E_TYPE_MAIL_SESSION)) -#define E_MAIL_SESSION_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS \ - ((obj), E_TYPE_MAIL_SESSION, EMailSessionClass)) - -/* Built-in CamelServices */ -#define E_MAIL_SESSION_LOCAL_UID "local" /* "On This Computer" */ -#define E_MAIL_SESSION_VFOLDER_UID "vfolder" /* "Search Folders" */ - -G_BEGIN_DECLS - -typedef struct _EMailSession EMailSession; -typedef struct _EMailSessionClass EMailSessionClass; -typedef struct _EMailSessionPrivate EMailSessionPrivate; - -struct _EMailSession { - CamelSession parent; - EMailSessionPrivate *priv; -}; - -struct _EMailSessionClass { - CamelSessionClass parent_class; - - void (*activity_added) (EMailSession *session, - EActivity *activity); -}; - -GType e_mail_session_get_type (void); -EMailSession * e_mail_session_new (void); -void e_mail_session_add_activity (EMailSession *session, - EActivity *activity); -EMailAccountStore * - e_mail_session_get_account_store - (EMailSession *session); -MailFolderCache * - e_mail_session_get_folder_cache (EMailSession *session); -EMailLabelListStore * - e_mail_session_get_label_store (EMailSession *session); -CamelStore * e_mail_session_get_local_store (EMailSession *session); -CamelStore * e_mail_session_get_vfolder_store - (EMailSession *session); -CamelFolder * e_mail_session_get_local_folder (EMailSession *session, - EMailLocalFolder type); -const gchar * e_mail_session_get_local_folder_uri - (EMailSession *session, - EMailLocalFolder type); -GList * e_mail_session_get_available_junk_filters - (EMailSession *session); -CamelFolder * e_mail_session_get_inbox_sync (EMailSession *session, - const gchar *service_uid, - GCancellable *cancellable, - GError **error); -void e_mail_session_get_inbox (EMailSession *session, - const gchar *service_uid, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -CamelFolder * e_mail_session_get_inbox_finish (EMailSession *session, - GAsyncResult *result, - GError **error); -CamelFolder * e_mail_session_get_trash_sync (EMailSession *session, - const gchar *service_uid, - GCancellable *cancellable, - GError **error); -void e_mail_session_get_trash (EMailSession *session, - const gchar *service_uid, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -CamelFolder * e_mail_session_get_trash_finish (EMailSession *session, - GAsyncResult *result, - GError **error); -CamelFolder * e_mail_session_uri_to_folder_sync - (EMailSession *session, - const gchar *folder_uri, - CamelStoreGetFolderFlags flags, - GCancellable *cancellable, - GError **error); -void e_mail_session_uri_to_folder (EMailSession *session, - const gchar *folder_uri, - CamelStoreGetFolderFlags flags, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -CamelFolder * e_mail_session_uri_to_folder_finish - (EMailSession *session, - GAsyncResult *result, - GError **error); - -/*** Legacy API ***/ - -void mail_session_flush_filter_log (EMailSession *session); -const gchar * mail_session_get_data_dir (void); -const gchar * mail_session_get_cache_dir (void); -const gchar * mail_session_get_config_dir (void); - -G_END_DECLS - -#endif /* E_MAIL_SESSION_H */ diff --git a/mail/e-mail-sidebar.h b/mail/e-mail-sidebar.h index a88c3ccc15..bdde4c1090 100644 --- a/mail/e-mail-sidebar.h +++ b/mail/e-mail-sidebar.h @@ -22,8 +22,8 @@ #ifndef E_MAIL_SIDEBAR_H #define E_MAIL_SIDEBAR_H -#include #include +#include /* Standard GObject macros */ #define E_TYPE_MAIL_SIDEBAR \ diff --git a/mail/e-mail-store-utils.c b/mail/e-mail-store-utils.c deleted file mode 100644 index 7f978c8b7f..0000000000 --- a/mail/e-mail-store-utils.c +++ /dev/null @@ -1,385 +0,0 @@ -/* - * e-mail-store-utils.c - * - * 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 - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "em-utils.h" - -#include "e-mail-store-utils.h" - -#include - -typedef struct _AsyncContext AsyncContext; - -struct _AsyncContext { - gchar *full_name; -}; - -static void -async_context_free (AsyncContext *context) -{ - g_free (context->full_name); - - g_slice_free (AsyncContext, context); -} - -static void -mail_store_create_folder_thread (GSimpleAsyncResult *simple, - GObject *object, - GCancellable *cancellable) -{ - AsyncContext *context; - GError *error = NULL; - - context = g_simple_async_result_get_op_res_gpointer (simple); - - e_mail_store_create_folder_sync ( - CAMEL_STORE (object), context->full_name, - cancellable, &error); - - if (error != NULL) - g_simple_async_result_take_error (simple, error); -} - -gboolean -e_mail_store_create_folder_sync (CamelStore *store, - const gchar *full_name, - GCancellable *cancellable, - GError **error) -{ - CamelFolderInfo *folder_info; - gchar *copied_full_name; - gchar *display_name; - const gchar *parent; - gboolean success = TRUE; - - g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE); - g_return_val_if_fail (full_name != NULL, FALSE); - - copied_full_name = g_strdup (full_name); - display_name = strrchr (copied_full_name, '/'); - if (display_name == NULL) { - display_name = copied_full_name; - parent = ""; - } else { - *display_name++ = '\0'; - parent = copied_full_name; - } - - folder_info = camel_store_create_folder_sync ( - store, parent, display_name, cancellable, error); - - g_free (copied_full_name); - - if (folder_info == NULL) - return FALSE; - - if (CAMEL_IS_SUBSCRIBABLE (store)) - success = camel_subscribable_subscribe_folder_sync ( - CAMEL_SUBSCRIBABLE (store), - full_name, cancellable, error); - - camel_store_free_folder_info (store, folder_info); - - return success; -} - -void -e_mail_store_create_folder (CamelStore *store, - const gchar *full_name, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *simple; - AsyncContext *context; - - g_return_if_fail (CAMEL_IS_STORE (store)); - g_return_if_fail (full_name != NULL); - - context = g_slice_new0 (AsyncContext); - context->full_name = g_strdup (full_name); - - simple = g_simple_async_result_new ( - G_OBJECT (store), callback, user_data, - e_mail_store_create_folder); - - g_simple_async_result_set_op_res_gpointer ( - simple, context, (GDestroyNotify) async_context_free); - - g_simple_async_result_run_in_thread ( - simple, mail_store_create_folder_thread, - io_priority, cancellable); - - g_object_unref (simple); -} - -gboolean -e_mail_store_create_folder_finish (CamelStore *store, - GAsyncResult *result, - GError **error) -{ - GSimpleAsyncResult *simple; - - g_return_val_if_fail ( - g_simple_async_result_is_valid ( - result, G_OBJECT (store), - e_mail_store_create_folder), FALSE); - - simple = G_SIMPLE_ASYNC_RESULT (result); - - /* Assume success unless a GError is set. */ - return !g_simple_async_result_propagate_error (simple, error); -} - -static void -mail_store_go_offline_thread (GSimpleAsyncResult *simple, - CamelStore *store, - GCancellable *cancellable) -{ - CamelService *service; - gchar *service_name; - GError *error = NULL; - - service = CAMEL_SERVICE (store); - - service_name = camel_service_get_name (service, TRUE); - camel_operation_push_message ( - cancellable, _("Disconnecting from '%s'"), service_name); - g_free (service_name); - - if (CAMEL_IS_DISCO_STORE (store)) { - CamelDiscoStore *disco_store; - - disco_store = CAMEL_DISCO_STORE (store); - - if (camel_disco_store_can_work_offline (disco_store)) - camel_disco_store_set_status ( - disco_store, CAMEL_DISCO_STORE_OFFLINE, - cancellable, &error); - else - em_utils_disconnect_service_sync (service, TRUE, cancellable, &error); - - } else if (CAMEL_IS_OFFLINE_STORE (store)) { - CamelOfflineStore *offline_store; - - offline_store = CAMEL_OFFLINE_STORE (store); - - camel_offline_store_set_online_sync ( - offline_store, FALSE, cancellable, &error); - - } else - em_utils_disconnect_service_sync (service, TRUE, cancellable, &error); - - if (error != NULL) - g_simple_async_result_take_error (simple, error); - - camel_operation_pop_message (cancellable); -} - -void -e_mail_store_go_offline (CamelStore *store, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *simple; - - g_return_if_fail (CAMEL_IS_STORE (store)); - - /* Cancel any pending connect first so the set_offline_op - * thread won't get queued behind a hung connect op. */ - camel_service_cancel_connect (CAMEL_SERVICE (store)); - - simple = g_simple_async_result_new ( - G_OBJECT (store), callback, - user_data, e_mail_store_go_offline); - - g_simple_async_result_run_in_thread ( - simple, (GSimpleAsyncThreadFunc) - mail_store_go_offline_thread, - io_priority, cancellable); - - g_object_unref (simple); -} - -gboolean -e_mail_store_go_offline_finish (CamelStore *store, - GAsyncResult *result, - GError **error) -{ - GSimpleAsyncResult *simple; - - g_return_val_if_fail ( - g_simple_async_result_is_valid ( - result, G_OBJECT (store), e_mail_store_go_offline), FALSE); - - simple = G_SIMPLE_ASYNC_RESULT (result); - - /* Assume success unless a GError is set. */ - return !g_simple_async_result_propagate_error (simple, error); -} - -static void -mail_store_go_online_thread (GSimpleAsyncResult *simple, - CamelStore *store, - GCancellable *cancellable) -{ - CamelService *service; - gchar *service_name; - GError *error = NULL; - - service = CAMEL_SERVICE (store); - - service_name = camel_service_get_name (service, TRUE); - camel_operation_push_message ( - cancellable, _("Reconnecting to '%s'"), service_name); - g_free (service_name); - - if (CAMEL_IS_DISCO_STORE (store)) - camel_disco_store_set_status ( - CAMEL_DISCO_STORE (store), - CAMEL_DISCO_STORE_ONLINE, - cancellable, &error); - - else if (CAMEL_IS_OFFLINE_STORE (store)) - camel_offline_store_set_online_sync ( - CAMEL_OFFLINE_STORE (store), - TRUE, cancellable, &error); - - if (error != NULL) - g_simple_async_result_take_error (simple, error); - - camel_operation_pop_message (cancellable); -} - -void -e_mail_store_go_online (CamelStore *store, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *simple; - - g_return_if_fail (CAMEL_IS_STORE (store)); - - simple = g_simple_async_result_new ( - G_OBJECT (store), callback, - user_data, e_mail_store_go_online); - - g_simple_async_result_run_in_thread ( - simple, (GSimpleAsyncThreadFunc) - mail_store_go_online_thread, - io_priority, cancellable); - - g_object_unref (simple); -} - -gboolean -e_mail_store_go_online_finish (CamelStore *store, - GAsyncResult *result, - GError **error) -{ - GSimpleAsyncResult *simple; - - g_return_val_if_fail ( - g_simple_async_result_is_valid ( - result, G_OBJECT (store), e_mail_store_go_online), FALSE); - - simple = G_SIMPLE_ASYNC_RESULT (result); - - /* Assume success unless a GError is set. */ - return !g_simple_async_result_propagate_error (simple, error); -} - -static void -mail_store_prepare_for_offline_thread (GSimpleAsyncResult *simple, - CamelStore *store, - GCancellable *cancellable) -{ - CamelService *service; - gchar *service_name; - GError *error = NULL; - - service = CAMEL_SERVICE (store); - - service_name = camel_service_get_name (service, TRUE); - camel_operation_push_message ( - cancellable, _("Preparing account '%s' for offline"), - service_name); - g_free (service_name); - - if (CAMEL_IS_DISCO_STORE (store)) - camel_disco_store_prepare_for_offline ( - CAMEL_DISCO_STORE (store), cancellable, &error); - - else if (CAMEL_IS_OFFLINE_STORE (store)) - camel_offline_store_prepare_for_offline_sync ( - CAMEL_OFFLINE_STORE (store), cancellable, &error); - - if (error != NULL) - g_simple_async_result_take_error (simple, error); - - camel_operation_pop_message (cancellable); -} - -void -e_mail_store_prepare_for_offline (CamelStore *store, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *simple; - - g_return_if_fail (CAMEL_IS_STORE (store)); - - simple = g_simple_async_result_new ( - G_OBJECT (store), callback, user_data, - e_mail_store_prepare_for_offline); - - g_simple_async_result_run_in_thread ( - simple, (GSimpleAsyncThreadFunc) - mail_store_prepare_for_offline_thread, - io_priority, cancellable); - - g_object_unref (simple); -} - -gboolean -e_mail_store_prepare_for_offline_finish (CamelStore *store, - GAsyncResult *result, - GError **error) -{ - GSimpleAsyncResult *simple; - - g_return_val_if_fail ( - g_simple_async_result_is_valid ( - result, G_OBJECT (store), - e_mail_store_prepare_for_offline), FALSE); - - simple = G_SIMPLE_ASYNC_RESULT (result); - - /* Assume success unless a GError is set. */ - return !g_simple_async_result_propagate_error (simple, error); -} diff --git a/mail/e-mail-store-utils.h b/mail/e-mail-store-utils.h deleted file mode 100644 index de4484c020..0000000000 --- a/mail/e-mail-store-utils.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * e-mail-store-utils.h - * - * 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 - * - */ - -#ifndef E_MAIL_STORE_UTILS_H -#define E_MAIL_STORE_UTILS_H - -/* CamelStore wrappers with Evolution-specific policies. */ - -#include - -G_BEGIN_DECLS - -gboolean e_mail_store_create_folder_sync (CamelStore *store, - const gchar *full_name, - GCancellable *cancellable, - GError **error); -void e_mail_store_create_folder (CamelStore *store, - const gchar *full_name, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean e_mail_store_create_folder_finish - (CamelStore *store, - GAsyncResult *result, - GError **error); - -void e_mail_store_go_offline (CamelStore *store, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean e_mail_store_go_offline_finish (CamelStore *store, - GAsyncResult *result, - GError **error); - -void e_mail_store_go_online (CamelStore *store, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean e_mail_store_go_online_finish (CamelStore *store, - GAsyncResult *result, - GError **error); - -void e_mail_store_prepare_for_offline - (CamelStore *store, - gint io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean e_mail_store_prepare_for_offline_finish - (CamelStore *store, - GAsyncResult *result, - GError **error); - -G_END_DECLS - -#endif /* E_MAIL_STORE_UTILS_H */ diff --git a/mail/e-mail-ui-session.c b/mail/e-mail-ui-session.c new file mode 100644 index 0000000000..dcb2e25573 --- /dev/null +++ b/mail/e-mail-ui-session.c @@ -0,0 +1,904 @@ +/* + * e-mail-ui-session.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + * + * Authors: + * Jonathon Jongsma + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * Copyright (C) 2009 Intel Corporation + * + */ + +/* mail-session.c: handles the session information and resource manipulation */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include + +#include + + +#ifdef HAVE_CANBERRA +#include +#endif + +#include +#include +#include +#include + +#include "e-mail-account-store.h" + +#include "e-util/e-util.h" +#include "libemail-utils/e-account-utils.h" +#include "e-util/e-alert-dialog.h" +#include "e-util/e-util-private.h" + +#include "shell/e-shell.h" +#include "shell/e-shell-view.h" +#include "shell/e-shell-content.h" +#include "shell/e-shell-window.h" + +#include "libemail-engine/e-mail-folder-utils.h" +#include "libemail-engine/e-mail-junk-filter.h" +#include "libemail-engine/e-mail-session.h" +#include "e-mail-ui-session.h" +#include "em-composer-utils.h" +#include "em-filter-context.h" +#include "em-filter-rule.h" +#include "em-utils.h" +#include "libemail-engine/mail-config.h" +#include "libemail-utils/mail-mt.h" +#include "libemail-engine/mail-ops.h" +#include "mail-send-recv.h" +#include "libemail-engine/mail-tools.h" + +#define E_MAIL_UI_SESSION_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_MAIL_UI_SESSION, EMailUISessionPrivate)) + +typedef struct _SourceContext SourceContext; + +struct _EMailUISessionPrivate { + FILE *filter_logfile; + CamelStore *vfolder_store; + EMailAccountStore *account_store; + EMailLabelListStore *label_store; + + EAccountList *account_list; + gulong account_changed_handler_id; +}; + +enum { + PROP_0, + PROP_ACCOUNT_STORE, + PROP_LABEL_STORE, + PROP_VFOLDER_STORE +}; + +enum { + ACTIVITY_ADDED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +G_DEFINE_TYPE_WITH_CODE ( + EMailUISession, + e_mail_ui_session, + E_TYPE_MAIL_SESSION, + G_IMPLEMENT_INTERFACE (E_TYPE_EXTENSIBLE, NULL)) + +struct _SourceContext { + EMailUISession *session; + CamelService *service; +}; + +/* Support for CamelSession.alert_user() *************************************/ + +static gpointer user_message_dialog; +static GQueue user_message_queue = { NULL, NULL, 0 }; + +struct _user_message_msg { + MailMsg base; + + CamelSessionAlertType type; + gchar *prompt; + GSList *button_captions; + EFlag *done; + + gint result; + guint ismain : 1; +}; + +static void user_message_exec (struct _user_message_msg *m, + GCancellable *cancellable, + GError **error); + +static void +user_message_response_free (GtkDialog *dialog, + gint button) +{ + struct _user_message_msg *m = NULL; + + gtk_widget_destroy ((GtkWidget *) dialog); + + user_message_dialog = NULL; + + /* check for pendings */ + if (!g_queue_is_empty (&user_message_queue)) { + GCancellable *cancellable; + + m = g_queue_pop_head (&user_message_queue); + cancellable = m->base.cancellable; + user_message_exec (m, cancellable, &m->base.error); + mail_msg_unref (m); + } +} + +/* clicked, send back the reply */ +static void +user_message_response (GtkDialog *dialog, + gint button, + struct _user_message_msg *m) +{ + /* if !m or !button_captions, then we've already replied */ + if (m && m->button_captions) { + m->result = button; + e_flag_set (m->done); + } + + user_message_response_free (dialog, button); +} + +static void +user_message_exec (struct _user_message_msg *m, + GCancellable *cancellable, + GError **error) +{ + gboolean info_only; + GtkWindow *parent; + EShell *shell; + const gchar *error_type; + gint index; + GSList *iter; + + info_only = g_slist_length (m->button_captions) <= 1; + + if (!m->ismain && user_message_dialog != NULL && !info_only) { + g_queue_push_tail (&user_message_queue, mail_msg_ref (m)); + return; + } + + switch (m->type) { + case CAMEL_SESSION_ALERT_INFO: + error_type = "mail:session-message-info"; + break; + case CAMEL_SESSION_ALERT_WARNING: + error_type = "mail:session-message-warning"; + break; + case CAMEL_SESSION_ALERT_ERROR: + error_type = "mail:session-message-error"; + break; + default: + error_type = NULL; + g_return_if_reached (); + } + + shell = e_shell_get_default (); + + /* try to find "mail" view to place the informational alert to */ + if (info_only) { + GtkWindow *active_window; + EShellWindow *shell_window; + EShellView *shell_view; + EShellContent *shell_content = NULL; + + /* check currently active window first, ... */ + active_window = e_shell_get_active_window (shell); + if (active_window && E_IS_SHELL_WINDOW (active_window)) { + if (E_IS_SHELL_WINDOW (active_window)) { + shell_window = E_SHELL_WINDOW (active_window); + shell_view = e_shell_window_peek_shell_view (shell_window, "mail"); + if (shell_view) + shell_content = e_shell_view_get_shell_content (shell_view); + } + } + + if (!shell_content) { + GList *list, *iter; + + list = gtk_application_get_windows (GTK_APPLICATION (shell)); + + /* ...then iterate through all opened windows and pick one which has it */ + for (iter = list; iter != NULL && !shell_content; iter = g_list_next (iter)) { + if (E_IS_SHELL_WINDOW (iter->data)) { + shell_window = iter->data; + shell_view = e_shell_window_peek_shell_view (shell_window, "mail"); + if (shell_view) + shell_content = e_shell_view_get_shell_content (shell_view); + } + } + } + + /* when no shell-content found, which might not happen, but just in case, + process the information alert like usual, through an EAlertDialog machinery + */ + if (shell_content) { + e_alert_submit (E_ALERT_SINK (shell_content), error_type, m->prompt, NULL); + return; + } else if (!m->ismain && user_message_dialog != NULL) { + g_queue_push_tail (&user_message_queue, mail_msg_ref (m)); + return; + } + } + + /* Pull in the active window from the shell to get a parent window */ + parent = e_shell_get_active_window (shell); + user_message_dialog = e_alert_dialog_new_for_args ( + parent, error_type, m->prompt, NULL); + g_object_set (user_message_dialog, "resizable", TRUE, NULL); + + if (m->button_captions) { + GtkWidget *action_area; + GList *children, *child; + + /* remove all default buttons and keep only those requested */ + action_area = gtk_dialog_get_action_area (GTK_DIALOG (user_message_dialog)); + + children = gtk_container_get_children (GTK_CONTAINER (action_area)); + for (child = children; child != NULL; child = child->next) { + gtk_container_remove (GTK_CONTAINER (action_area), child->data); + } + + g_list_free (children); + } + + for (index = 0, iter = m->button_captions; iter; index++, iter = iter->next) { + gtk_dialog_add_button (GTK_DIALOG (user_message_dialog), iter->data, index); + } + + + /* XXX This is a case where we need to be able to construct + * custom EAlerts without a predefined XML definition. */ + if (m->ismain) { + gint response; + + response = gtk_dialog_run (user_message_dialog); + user_message_response ( + user_message_dialog, response, m); + } else { + gpointer user_data = m; + + if (g_slist_length (m->button_captions) <= 1) + user_data = NULL; + + g_signal_connect ( + user_message_dialog, "response", + G_CALLBACK (user_message_response), user_data); + gtk_widget_show (user_message_dialog); + } +} + +static void +user_message_free (struct _user_message_msg *m) +{ + g_free (m->prompt); + g_slist_free_full (m->button_captions, g_free); + e_flag_free (m->done); +} + +static MailMsgInfo user_message_info = { + sizeof (struct _user_message_msg), + (MailMsgDescFunc) NULL, + (MailMsgExecFunc) user_message_exec, + (MailMsgDoneFunc) NULL, + (MailMsgFreeFunc) user_message_free +}; + +/* Support for CamelSession.get_filter_driver () *****************************/ + +static CamelFolder * +get_folder (CamelFilterDriver *d, + const gchar *uri, + gpointer user_data, + GError **error) +{ + EMailSession *session = E_MAIL_SESSION (user_data); + + /* FIXME Not passing a GCancellable here. */ + /* FIXME Need a camel_filter_driver_get_session(). */ + return e_mail_session_uri_to_folder_sync ( + session, uri, 0, NULL, error); +} + +static gboolean +session_play_sound_cb (const gchar *filename) +{ +#ifdef HAVE_CANBERRA + if (filename != NULL && *filename != '\0') + ca_context_play ( + ca_gtk_context_get (), 0, + CA_PROP_MEDIA_FILENAME, filename, + NULL); + else +#endif + gdk_beep (); + + return FALSE; +} + +static void +session_play_sound (CamelFilterDriver *driver, + const gchar *filename, + gpointer user_data) +{ + g_idle_add_full ( + G_PRIORITY_DEFAULT_IDLE, + (GSourceFunc) session_play_sound_cb, + g_strdup (filename), (GDestroyNotify) g_free); +} + +static void +session_system_beep (CamelFilterDriver *driver, + gpointer user_data) +{ + g_idle_add ((GSourceFunc) session_play_sound_cb, NULL); +} + +static CamelFilterDriver * +main_get_filter_driver (CamelSession *session, + const gchar *type, + GError **error) +{ + EMailSession *ms = E_MAIL_SESSION (session); + CamelFilterDriver *driver; + EFilterRule *rule = NULL; + const gchar *config_dir; + gchar *user, *system; + GSettings *settings; + ERuleContext *fc; + EMailUISessionPrivate *priv; + + priv = E_MAIL_UI_SESSION_GET_PRIVATE (session); + + settings = g_settings_new ("org.gnome.evolution.mail"); + + config_dir = mail_session_get_config_dir (); + user = g_build_filename (config_dir, "filters.xml", NULL); + system = g_build_filename (EVOLUTION_PRIVDATADIR, "filtertypes.xml", NULL); + fc = (ERuleContext *) em_filter_context_new (ms); + e_rule_context_load (fc, system, user); + g_free (system); + g_free (user); + + driver = camel_filter_driver_new (session); + camel_filter_driver_set_folder_func (driver, get_folder, session); + + if (g_settings_get_boolean (settings, "filters-log-actions")) { + if (priv->filter_logfile == NULL) { + gchar *filename; + + filename = g_settings_get_string (settings, "filters-log-file"); + if (filename) { + priv->filter_logfile = g_fopen (filename, "a+"); + g_free (filename); + } + } + + if (priv->filter_logfile) + camel_filter_driver_set_logfile (driver, priv->filter_logfile); + } + + camel_filter_driver_set_shell_func (driver, mail_execute_shell_command, NULL); + camel_filter_driver_set_play_sound_func (driver, session_play_sound, NULL); + camel_filter_driver_set_system_beep_func (driver, session_system_beep, NULL); + + if ((!strcmp (type, E_FILTER_SOURCE_INCOMING) || + !strcmp (type, E_FILTER_SOURCE_JUNKTEST)) + && camel_session_get_check_junk (session)) { + + /* implicit junk check as 1st rule */ + camel_filter_driver_add_rule ( + driver, "Junk check", "(junk-test)", + "(begin (set-system-flag \"junk\"))"); + } + + if (strcmp (type, E_FILTER_SOURCE_JUNKTEST) != 0) { + GString *fsearch, *faction; + + fsearch = g_string_new (""); + faction = g_string_new (""); + + if (!strcmp (type, E_FILTER_SOURCE_DEMAND)) + type = E_FILTER_SOURCE_INCOMING; + + /* add the user-defined rules next */ + while ((rule = e_rule_context_next_rule (fc, rule, type))) { + g_string_truncate (fsearch, 0); + g_string_truncate (faction, 0); + + /* skip disabled rules */ + if (!rule->enabled) + continue; + + e_filter_rule_build_code (rule, fsearch); + em_filter_rule_build_action ( + EM_FILTER_RULE (rule), faction); + camel_filter_driver_add_rule ( + driver, rule->name, + fsearch->str, faction->str); + } + + g_string_free (fsearch, TRUE); + g_string_free (faction, TRUE); + } + + g_object_unref (fc); + + g_object_unref (settings); + + return driver; +} + +static void +source_context_free (SourceContext *context) +{ + if (context->session != NULL) + g_object_unref (context->session); + + if (context->service != NULL) + g_object_unref (context->service); + + g_slice_free (SourceContext, context); +} + +static void +mail_ui_session_dispose (GObject *object) +{ + EMailUISessionPrivate *priv; + + priv = E_MAIL_UI_SESSION_GET_PRIVATE (object); + + if (priv->account_store != NULL) { + e_mail_account_store_clear (priv->account_store); + g_object_unref (priv->account_store); + priv->account_store = NULL; + } + + if (priv->label_store != NULL) { + g_object_unref (priv->label_store); + priv->label_store = NULL; + } + + + if (priv->vfolder_store != NULL) { + g_object_unref (priv->vfolder_store); + priv->vfolder_store = NULL; + } + + if (priv->account_list != NULL) { + g_signal_handler_disconnect ( + priv->account_list, + priv->account_changed_handler_id); + g_object_unref (priv->account_list); + priv->account_list = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (e_mail_ui_session_parent_class)->dispose (object); +} + +static void +mail_ui_session_add_vfolder_store (EMailUISession *uisession) +{ + CamelSession *camel_session; + CamelService *service; + GError *error = NULL; + + camel_session = CAMEL_SESSION (uisession); + + service = camel_session_add_service ( + camel_session, E_MAIL_SESSION_VFOLDER_UID, + "vfolder", CAMEL_PROVIDER_STORE, &error); + + if (error != NULL) { + g_critical ("%s: %s", G_STRFUNC, error->message); + g_error_free (error); + return; + } + + g_return_if_fail (CAMEL_IS_SERVICE (service)); + + camel_service_set_display_name (service, _("Search Folders")); + em_utils_connect_service_sync (service, NULL, NULL); + + /* XXX There's more configuration to do in vfolder_load_storage() + * but it requires an EMailBackend, which we don't have access + * to from here, so it has to be called from elsewhere. Kinda + * thinking about reworking that... */ + + uisession->priv->vfolder_store = g_object_ref (service); +} + +static void +mail_ui_session_account_changed_cb (EAccountList *account_list, + EAccount *account, + EMailSession *session) +{ + EMFolderTreeModel *folder_tree_model; + CamelService *service; + + service = camel_session_get_service ( + CAMEL_SESSION (session), account->uid); + + if (!CAMEL_IS_STORE (service)) + return; + + /* Update the display name of the corresponding CamelStore. + * EMailAccountStore listens for "notify" signals from each + * service so it will detect this and update the model. + * + * XXX If EAccount defined GObject properties we could just + * bind EAccount:name to CamelService:display-name and + * be done with it. Oh well. + */ + + camel_service_set_display_name (service, account->name); + + /* Remove the store from the folder tree model and, if the + * account is still enabled, re-add it. Easier than trying + * to update the model with the store in place. + * + * em_folder_tree_model_add_store() already knows which types + * of stores to disregard, so we don't have to deal with that + * here. */ + + folder_tree_model = em_folder_tree_model_get_default (); + + em_folder_tree_model_remove_store ( + folder_tree_model, CAMEL_STORE (service)); + + if (account->enabled) + em_folder_tree_model_add_store ( + folder_tree_model, CAMEL_STORE (service)); +} + +static gboolean +mail_ui_session_initialize_stores_idle (gpointer user_data) +{ + EMailUISession *session = user_data; + EMailAccountStore *account_store; + EAccount *account; + + g_return_val_if_fail (session != NULL, FALSE); + + account_store = e_mail_ui_session_get_account_store (session); + + /* Initialize which account is default. */ + account = e_get_default_account (); + if (account != NULL) { + CamelService *service; + + service = camel_session_get_service ( + CAMEL_SESSION (session), account->uid); + e_mail_account_store_set_default_service ( + account_store, service); + } + + return FALSE; +} + +static void +mail_ui_session_constructed (GObject *object) +{ + EMailUISessionPrivate *priv; + EMFolderTreeModel *folder_tree_model; + EMailSession *session; + EMailUISession *uisession; + EAccountList *account_list; + gulong handler_id; + + session = E_MAIL_SESSION (object); + uisession = E_MAIL_UI_SESSION(object); + uisession->priv = priv = E_MAIL_UI_SESSION_GET_PRIVATE (object); + + priv->account_store = e_mail_account_store_new (session); + + account_list = e_get_account_list (); + uisession->priv->account_list = g_object_ref (account_list); + + /* XXX Make sure the folder tree model is created before we + * add built-in CamelStores so it gets signals from the + * EMailAccountStore. + * + * XXX This is creating a circular reference. Perhaps the + * model should only hold a weak pointer to EMailSession? + * + * FIXME EMailSession should just own the default instance. + */ + folder_tree_model = em_folder_tree_model_get_default (); + + /* Chain up to parent's constructed() method. */ + G_OBJECT_CLASS (e_mail_ui_session_parent_class)->constructed (object); + + em_folder_tree_model_set_session (folder_tree_model, session); + + mail_ui_session_add_vfolder_store (uisession); + + g_idle_add (mail_ui_session_initialize_stores_idle, object); + + handler_id = g_signal_connect ( + account_list, "account-changed", + G_CALLBACK (mail_ui_session_account_changed_cb), session); + priv->account_changed_handler_id = handler_id; + +} + +static gint +mail_ui_session_alert_user (CamelSession *session, + CamelSessionAlertType type, + const gchar *prompt, + GSList *button_captions) +{ + struct _user_message_msg *m; + GCancellable *cancellable; + gint result = -1; + GSList *iter; + + m = mail_msg_new (&user_message_info); + m->ismain = mail_in_main_thread (); + m->type = type; + m->prompt = g_strdup (prompt); + m->done = e_flag_new (); + m->button_captions = g_slist_copy (button_captions); + + for (iter = m->button_captions; iter; iter = iter->next) + iter->data = g_strdup (iter->data); + + if (g_slist_length (button_captions) > 1) + mail_msg_ref (m); + + cancellable = m->base.cancellable; + + if (m->ismain) + user_message_exec (m, cancellable, &m->base.error); + else + mail_msg_main_loop_push (m); + + if (g_slist_length (button_captions) > 1) { + e_flag_wait (m->done); + result = m->result; + mail_msg_unref (m); + } else if (m->ismain) + mail_msg_unref (m); + + return result; +} + +static CamelFilterDriver * +mail_ui_session_get_filter_driver (CamelSession *session, + const gchar *type, + GError **error) +{ + return (CamelFilterDriver *) mail_call_main ( + MAIL_CALL_p_ppp, (MailMainFunc) main_get_filter_driver, + session, type, error); +} + +static void +mail_ui_session_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +mail_ui_session_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_ACCOUNT_STORE: + g_value_set_object ( + value, + e_mail_ui_session_get_account_store ( + E_MAIL_UI_SESSION (object))); + return; + + case PROP_LABEL_STORE: + g_value_set_object ( + value, + e_mail_ui_session_get_label_store ( + E_MAIL_UI_SESSION (object))); + return; + + + case PROP_VFOLDER_STORE: + g_value_set_object ( + value, + e_mail_ui_session_get_vfolder_store ( + E_MAIL_UI_SESSION (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static gboolean +mail_ui_session_add_service_cb (SourceContext *context) +{ + EMailAccountStore *store; + + store = e_mail_ui_session_get_account_store (context->session); + e_mail_account_store_add_service (store, context->service); + + return FALSE; +} + +static CamelService * +mail_ui_session_add_service (CamelSession *session, + const gchar *uid, + const gchar *protocol, + CamelProviderType type, + GError **error) +{ + CamelService *service; + + /* Chain up to parent's constructed() method. */ + service = CAMEL_SESSION_CLASS (e_mail_ui_session_parent_class)-> + add_service (session, uid, protocol, type, error); + + /* Inform the EMailAccountStore of the new CamelService + * from an idle callback so the service has a chance to + * fully initialize first. */ + if (CAMEL_IS_STORE (service)) { + SourceContext *context; + + context = g_slice_new0 (SourceContext); + context->session = g_object_ref (session); + context->service = g_object_ref (service); + + g_idle_add_full ( + G_PRIORITY_DEFAULT_IDLE, + (GSourceFunc) mail_ui_session_add_service_cb, + context, (GDestroyNotify) source_context_free); + } + + return service; +} + +static void +e_mail_ui_session_class_init (EMailUISessionClass *class) +{ + GObjectClass *object_class; + CamelSessionClass *session_class; + + g_type_class_add_private (class, sizeof (EMailUISessionPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = mail_ui_session_set_property; + object_class->get_property = mail_ui_session_get_property; + object_class->dispose = mail_ui_session_dispose; + object_class->constructed = mail_ui_session_constructed; + + session_class = CAMEL_SESSION_CLASS (class); + session_class->alert_user = mail_ui_session_alert_user; + session_class->get_filter_driver = mail_ui_session_get_filter_driver; + session_class->add_service = mail_ui_session_add_service; + + g_object_class_install_property ( + object_class, + PROP_VFOLDER_STORE, + g_param_spec_object ( + "vfolder-store", + "Search Folder Store", + "Built-in search folder store", + CAMEL_TYPE_STORE, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property ( + object_class, + PROP_LABEL_STORE, + g_param_spec_object ( + "label-store", + "Label Store", + "Mail label store", + E_TYPE_MAIL_LABEL_LIST_STORE, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + signals[ACTIVITY_ADDED] = g_signal_new ( + "activity-added", + G_OBJECT_CLASS_TYPE (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EMailUISessionClass, activity_added), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + E_TYPE_ACTIVITY); +} + +static void +e_mail_ui_session_init (EMailUISession *session) +{ + session->priv = E_MAIL_UI_SESSION_GET_PRIVATE (session); + session->priv->label_store = e_mail_label_list_store_new (); +} + +EMailSession * +e_mail_ui_session_new (void) +{ + const gchar *user_data_dir; + const gchar *user_cache_dir; + + user_data_dir = mail_session_get_data_dir (); + user_cache_dir = mail_session_get_cache_dir (); + + return g_object_new ( + E_TYPE_MAIL_UI_SESSION, + "user-data-dir", user_data_dir, + "user-cache-dir", user_cache_dir, + NULL); +} + + +EMailAccountStore * +e_mail_ui_session_get_account_store (EMailUISession *session) +{ + g_return_val_if_fail (E_IS_MAIL_UI_SESSION (session), NULL); + + return session->priv->account_store; +} + +CamelStore * +e_mail_ui_session_get_vfolder_store (EMailUISession *session) +{ + g_return_val_if_fail (E_IS_MAIL_UI_SESSION (session), NULL); + + return session->priv->vfolder_store; +} + +void +e_mail_ui_session_add_activity (EMailUISession *session, + EActivity *activity) +{ + g_return_if_fail (E_IS_MAIL_UI_SESSION (session)); + g_return_if_fail (E_IS_ACTIVITY (activity)); + + g_signal_emit (session, signals[ACTIVITY_ADDED], 0, activity); +} + +EMailLabelListStore * +e_mail_ui_session_get_label_store (EMailUISession *session) +{ + g_return_val_if_fail (E_IS_MAIL_UI_SESSION (session), NULL); + + return session->priv->label_store; +} + diff --git a/mail/e-mail-ui-session.h b/mail/e-mail-ui-session.h new file mode 100644 index 0000000000..1a36487757 --- /dev/null +++ b/mail/e-mail-ui-session.h @@ -0,0 +1,93 @@ +/* + * e-mail-session.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + * + * Authors: + * Jeffrey Stedfast + * Srinivasa Ragavan + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef E_MAIL_UI_SESSION_H +#define E_MAIL_UI_SESSION_H + +#include +#include +#include +#include +#include +#include + +#include +#include + +/* Standard GObject macros */ +#define E_TYPE_MAIL_UI_SESSION \ + (e_mail_ui_session_get_type ()) +#define E_MAIL_UI_SESSION(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_MAIL_UI_SESSION, EMailUISession)) +#define E_MAIL_UI_SESSION_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_MAIL_UI_SESSION, EMailUISessionClass)) +#define E_IS_MAIL_UI_SESSION(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_MAIL_UI_SESSION)) +#define E_IS_MAIL_UI_SESSION_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_MAIL_UI_SESSION)) +#define E_MAIL_UI_SESSION_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_MAIL_UI_SESSION, EMailUISessionClass)) + +G_BEGIN_DECLS + +typedef struct _EMailUISession EMailUISession; +typedef struct _EMailUISessionClass EMailUISessionClass; +typedef struct _EMailUISessionPrivate EMailUISessionPrivate; + +struct _EMailUISession { + EMailSession parent; + EMailUISessionPrivate *priv; +}; + +struct _EMailUISessionClass { + EMailSessionClass parent_class; + + void (*activity_added) (EMailUISession *session, + EActivity *activity); + +}; + +GType e_mail_ui_session_get_type (void); +EMailSession * e_mail_ui_session_new (void); +CamelStore * e_mail_ui_session_get_vfolder_store + (EMailUISession *session); +EMailAccountStore * + e_mail_ui_session_get_account_store + (EMailUISession *session); +void e_mail_ui_session_add_activity (EMailUISession *session, + EActivity *activity); +EMailLabelListStore * + e_mail_ui_session_get_label_store + (EMailUISession *session); + +G_END_DECLS + +#endif /* E_MAIL_UI_SESSION_H */ diff --git a/mail/e-mail.h b/mail/e-mail.h index 02c169cd10..3b34765784 100644 --- a/mail/e-mail.h +++ b/mail/e-mail.h @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -38,10 +37,7 @@ #include #include #include -#include -#include #include -#include #include #include diff --git a/mail/em-account-editor.c b/mail/em-account-editor.c index 1fc17abc5e..8b7f1600d6 100644 --- a/mail/em-account-editor.c +++ b/mail/em-account-editor.c @@ -45,32 +45,38 @@ #include -#include "shell/e-shell.h" -#include "e-util/e-util.h" -#include "e-util/e-alert-dialog.h" -#include "e-util/e-account-utils.h" -#include "e-util/e-dialog-utils.h" -#include "e-util/e-signature-list.h" -#include "e-util/e-signature-utils.h" -#include "e-util/e-util-private.h" -#include "widgets/misc/e-auth-combo-box.h" -#include "widgets/misc/e-signature-editor.h" -#include "widgets/misc/e-port-entry.h" +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "e-mail-account-store.h" #include "e-mail-backend.h" -#include "e-mail-folder-utils.h" #include "e-mail-junk-options.h" +#include "e-mail-ui-session.h" +#include "em-account-editor.h" #include "em-config.h" #include "em-folder-selection-button.h" -#include "em-account-editor.h" -#include "mail-send-recv.h" #include "em-utils.h" -#include "mail-ops.h" -#include "mail-mt.h" #include "mail-guess-servers.h" +#include "mail-send-recv.h" #if defined (HAVE_NSS) && defined (ENABLE_SMIME) -#include "smime/gui/e-cert-selector.h" +#include #endif #define EM_ACCOUNT_EDITOR_GET_PRIVATE(obj) \ @@ -5501,7 +5507,7 @@ emae_commit (EConfig *ec, service = camel_session_get_service ( CAMEL_SESSION (session), account->uid); - store = e_mail_session_get_account_store (session); + store = e_mail_ui_session_get_account_store (E_MAIL_UI_SESSION(session)); e_mail_account_store_set_default_service (store, service); } diff --git a/mail/em-composer-utils.c b/mail/em-composer-utils.c index dc8d89725a..4d8e37d9a4 100644 --- a/mail/em-composer-utils.c +++ b/mail/em-composer-utils.c @@ -32,32 +32,35 @@ #include -#include "mail-mt.h" -#include "mail-ops.h" -#include "mail-tools.h" -#include "mail-send-recv.h" +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include -#include "e-util/e-account-utils.h" -#include "e-util/e-alert-dialog.h" -#include "e-util/e-alert-sink.h" -#include "e-util/e-util.h" +#include -#include "shell/e-shell.h" +#include +#include +#include -#include "e-mail-folder-utils.h" -#include "e-mail-session.h" -#include "e-mail-session-utils.h" #include "em-utils.h" #include "em-composer-utils.h" -#include "composer/e-msg-composer.h" -#include "composer/e-composer-actions.h" -#include "composer/e-composer-post-header.h" #include "em-folder-selector.h" #include "em-folder-tree.h" #include "em-format-html.h" #include "em-format-html-print.h" #include "em-format-quote.h" #include "em-event.h" +#include "mail-send-recv.h" + #ifdef G_OS_WIN32 #ifdef gmtime_r diff --git a/mail/em-composer-utils.h b/mail/em-composer-utils.h index 093001dfd0..5b3d3a469a 100644 --- a/mail/em-composer-utils.h +++ b/mail/em-composer-utils.h @@ -26,9 +26,9 @@ #include #include -#include #include #include +#include G_BEGIN_DECLS diff --git a/mail/em-filter-context.h b/mail/em-filter-context.h index 3545bf16eb..1f8889d94c 100644 --- a/mail/em-filter-context.h +++ b/mail/em-filter-context.h @@ -25,8 +25,8 @@ #ifndef EM_FILTER_CONTEXT_H #define EM_FILTER_CONTEXT_H -#include #include +#include /* Standard GObject macros */ #define EM_TYPE_FILTER_CONTEXT \ diff --git a/mail/em-filter-folder-element.h b/mail/em-filter-folder-element.h index f71b4c128b..f5a1741795 100644 --- a/mail/em-filter-folder-element.h +++ b/mail/em-filter-folder-element.h @@ -25,8 +25,8 @@ #ifndef EM_FILTER_FOLDER_ELEMENT_H #define EM_FILTER_FOLDER_ELEMENT_H -#include #include +#include /* Standard GObject macros */ #define EM_TYPE_FILTER_FOLDER_ELEMENT \ diff --git a/mail/em-filter-source-element.c b/mail/em-filter-source-element.c index a8e51e2827..5848f938db 100644 --- a/mail/em-filter-source-element.c +++ b/mail/em-filter-source-element.c @@ -32,8 +32,8 @@ #include #include -#include #include +#include #define EM_FILTER_SOURCE_ELEMENT_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE \ diff --git a/mail/em-filter-source-element.h b/mail/em-filter-source-element.h index 41c3f3f8fc..061a487fc8 100644 --- a/mail/em-filter-source-element.h +++ b/mail/em-filter-source-element.h @@ -24,8 +24,8 @@ #ifndef EM_FILTER_SOURCE_ELEMENT_H #define EM_FILTER_SOURCE_ELEMENT_H -#include #include +#include /* Standard GObject macros */ #define EM_TYPE_FILTER_SOURCE_ELEMENT \ diff --git a/mail/em-folder-properties.c b/mail/em-folder-properties.c index 75ccf5304b..2abb1f366d 100644 --- a/mail/em-folder-properties.c +++ b/mail/em-folder-properties.c @@ -24,18 +24,20 @@ #include #endif +#include "em-folder-properties.h" + #include #include #include -#include "em-folder-properties.h" -#include "em-config.h" +#include +#include +#include #include "e-mail-backend.h" -#include "e-mail-folder-utils.h" -#include "mail-ops.h" -#include "mail-mt.h" +#include "e-mail-ui-session.h" +#include "em-config.h" #include "mail-vfolder.h" typedef struct _AsyncContext AsyncContext; @@ -498,8 +500,8 @@ em_folder_properties_show (CamelStore *store, cancellable = camel_operation_new (); e_activity_set_cancellable (context->activity, cancellable); - e_mail_session_add_activity ( - E_MAIL_SESSION (session), context->activity); + e_mail_ui_session_add_activity ( + E_MAIL_UI_SESSION (session), context->activity); camel_store_get_folder ( store, folder_name, 0, G_PRIORITY_DEFAULT, cancellable, diff --git a/mail/em-folder-properties.h b/mail/em-folder-properties.h index 704e43b6d3..2d829af17f 100644 --- a/mail/em-folder-properties.h +++ b/mail/em-folder-properties.h @@ -25,7 +25,8 @@ #define __EM_FOLDER_PROPERTIES_H__ #include -#include +#include +#include G_BEGIN_DECLS diff --git a/mail/em-folder-selection-button.c b/mail/em-folder-selection-button.c index 6e40234444..fb4e27d83b 100644 --- a/mail/em-folder-selection-button.c +++ b/mail/em-folder-selection-button.c @@ -28,7 +28,8 @@ #include #include -#include "e-mail-folder-utils.h" +#include + #include "em-folder-tree.h" #include "em-folder-selector.h" #include "em-utils.h" diff --git a/mail/em-folder-selection-button.h b/mail/em-folder-selection-button.h index 6e646e3af0..945f1dab0b 100644 --- a/mail/em-folder-selection-button.h +++ b/mail/em-folder-selection-button.h @@ -25,7 +25,7 @@ #define EM_FOLDER_SELECTION_BUTTON_H #include -#include +#include /* Standard GObject macros */ #define EM_TYPE_FOLDER_SELECTION_BUTTON \ diff --git a/mail/em-folder-selector.c b/mail/em-folder-selector.c index 2f5b58274f..18172cb7a5 100644 --- a/mail/em-folder-selector.c +++ b/mail/em-folder-selector.c @@ -29,7 +29,8 @@ #include #include -#include "e-mail-session.h" +#include + #include "em-folder-tree.h" #include "em-folder-selector.h" #include "em-folder-utils.h" diff --git a/mail/em-folder-tree-model.c b/mail/em-folder-tree-model.c index c346435f80..7ee385c892 100644 --- a/mail/em-folder-tree-model.c +++ b/mail/em-folder-tree-model.c @@ -36,22 +36,22 @@ #include -#include "e-util/e-util.h" -#include "e-util/e-account-utils.h" +#include +#include -#include "mail-tools.h" -#include "mail-mt.h" -#include "mail-ops.h" +#include +#include -/* sigh, these 2 only needed for outbox total count checking - a mess */ -#include "mail-folder-cache.h" +#include +#include +#include +#include -#include "em-utils.h" -#include "em-folder-utils.h" -#include "em-event.h" - -#include "e-mail-folder-utils.h" -#include "shell/e-shell.h" +#include +#include +#include +#include +#include #define EM_FOLDER_TREE_MODEL_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE \ @@ -573,7 +573,7 @@ em_folder_tree_model_set_session (EMFolderTreeModel *model, MailFolderCache *folder_cache; folder_cache = e_mail_session_get_folder_cache (session); - account_store = e_mail_session_get_account_store (session); + account_store = e_mail_ui_session_get_account_store (E_MAIL_UI_SESSION (session)); /* Keep our own reference since we connect to its signals. */ g_warn_if_fail (model->priv->account_store == NULL); diff --git a/mail/em-folder-tree-model.h b/mail/em-folder-tree-model.h index 1bf5483367..b4acb3dce6 100644 --- a/mail/em-folder-tree-model.h +++ b/mail/em-folder-tree-model.h @@ -26,7 +26,7 @@ #include #include -#include +#include /* Standard GObject macros */ #define EM_TYPE_FOLDER_TREE_MODEL \ diff --git a/mail/em-folder-tree.c b/mail/em-folder-tree.c index a1e4142cf6..46a8c108e8 100644 --- a/mail/em-folder-tree.c +++ b/mail/em-folder-tree.c @@ -48,11 +48,11 @@ #include "em-vfolder-rule.h" -#include "mail-mt.h" -#include "mail-ops.h" -#include "mail-tools.h" -#include "mail-send-recv.h" -#include "mail-vfolder.h" +#include "libemail-utils/mail-mt.h" +#include "libemail-engine/e-mail-folder-utils.h" +#include "libemail-engine/e-mail-session.h" +#include "libemail-engine/mail-ops.h" +#include "libemail-engine/mail-tools.h" #include "em-utils.h" #include "em-folder-tree.h" @@ -60,9 +60,10 @@ #include "em-folder-selector.h" #include "em-folder-properties.h" #include "em-event.h" +#include "mail-send-recv.h" +#include "mail-vfolder.h" -#include "e-mail-folder-utils.h" -#include "e-mail-session.h" +#include "e-mail-ui-session.h" #define d(x) @@ -1822,7 +1823,8 @@ em_folder_tree_new_activity (EMFolderTree *folder_tree) g_object_unref (cancellable); session = em_folder_tree_get_session (folder_tree); - e_mail_session_add_activity (session, activity); + e_mail_ui_session_add_activity ( + E_MAIL_UI_SESSION (session), activity); return activity; } @@ -2036,7 +2038,7 @@ folder_tree_drop_folder (struct _DragDataReceivedAsync *m) d(printf(" * Drop folder '%s' onto '%s'\n", data, m->full_name)); - cancellable = e_activity_get_cancellable (m->base.activity); + cancellable = m->base.cancellable; folder = e_mail_session_uri_to_folder_sync ( m->session, (gchar *) data, 0, diff --git a/mail/em-folder-tree.h b/mail/em-folder-tree.h index 6a60f2bc31..1e39ebab18 100644 --- a/mail/em-folder-tree.h +++ b/mail/em-folder-tree.h @@ -25,9 +25,10 @@ #define EM_FOLDER_TREE_H #include +#include #include -#include #include +#include /* Standard GObject macros */ #define EM_TYPE_FOLDER_TREE \ diff --git a/mail/em-folder-utils.c b/mail/em-folder-utils.c index 825e6af7ca..1350df7c7b 100644 --- a/mail/em-folder-utils.c +++ b/mail/em-folder-utils.c @@ -45,22 +45,23 @@ #include "em-vfolder-rule.h" -#include "mail-mt.h" -#include "mail-ops.h" -#include "mail-tools.h" -#include "mail-vfolder.h" -#include "mail-folder-cache.h" - +#include "libemail-utils/mail-mt.h" +#include "libemail-engine/e-mail-folder-utils.h" +#include "libemail-engine/e-mail-session.h" +#include "libemail-engine/e-mail-store-utils.h" +#include "libemail-engine/e-mail-utils.h" +#include "libemail-engine/mail-ops.h" +#include "libemail-engine/mail-tools.h" +#include "libemail-engine/mail-folder-cache.h" + +#include "e-mail-ui-session.h" #include "em-utils.h" #include "em-folder-tree.h" #include "em-folder-tree-model.h" #include "em-folder-utils.h" #include "em-folder-selector.h" #include "em-folder-properties.h" - -#include "e-mail-folder-utils.h" -#include "e-mail-session.h" -#include "e-mail-store-utils.h" +#include "mail-vfolder.h" #define d(x) @@ -567,7 +568,7 @@ em_folder_utils_create_folder (GtkWindow *parent, model = em_folder_tree_model_new (); em_folder_tree_model_set_session (model, session); - account_store = e_mail_session_get_account_store (session); + account_store = e_mail_ui_session_get_account_store (E_MAIL_UI_SESSION (session)); e_mail_account_store_queue_enabled_services (account_store, &queue); while (!g_queue_is_empty (&queue)) { diff --git a/mail/em-folder-utils.h b/mail/em-folder-utils.h index 9211cacd90..db3853042c 100644 --- a/mail/em-folder-utils.h +++ b/mail/em-folder-utils.h @@ -26,7 +26,7 @@ #include #include -#include +#include #include G_BEGIN_DECLS diff --git a/mail/em-format-html-print.c b/mail/em-format-html-print.c index a600c5a48a..04216900bc 100644 --- a/mail/em-format-html-print.c +++ b/mail/em-format-html-print.c @@ -30,11 +30,13 @@ #include #include -#include "mail-ops.h" -#include "mail-mt.h" -#include "em-format-html-print.h" #include +#include +#include + +#include "em-format-html-print.h" + G_DEFINE_TYPE ( EMFormatHTMLPrint, em_format_html_print, diff --git a/mail/em-format-html.c b/mail/em-format-html.c index 706de09248..a720d2cc9f 100644 --- a/mail/em-format-html.c +++ b/mail/em-format-html.c @@ -57,12 +57,15 @@ #include -#include "e-mail-enumtypes.h" +#include + +#include +#include +#include + #include "em-format-html.h" #include "em-html-stream.h" #include "em-utils.h" -#include "mail-config.h" -#include "mail-mt.h" #define EM_FORMAT_HTML_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE \ diff --git a/mail/em-format-html.h b/mail/em-format-html.h index 7ded2e82f9..954a54ea0c 100644 --- a/mail/em-format-html.h +++ b/mail/em-format-html.h @@ -29,9 +29,9 @@ #define EM_FORMAT_HTML_H #include -#include #include #include +#include /* Standard GObject macros */ #define EM_TYPE_FORMAT_HTML \ diff --git a/mail/em-subscription-editor.c b/mail/em-subscription-editor.c index 15f7a3be32..ceefe7ca49 100644 --- a/mail/em-subscription-editor.c +++ b/mail/em-subscription-editor.c @@ -25,12 +25,12 @@ #include #include -#include "mail-tools.h" -#include "mail-ops.h" -#include "mail-mt.h" +#include +#include +#include +#include #include -#include #include #include "em-folder-utils.h" diff --git a/mail/em-subscription-editor.h b/mail/em-subscription-editor.h index c6f6c258f0..b9abedb166 100644 --- a/mail/em-subscription-editor.h +++ b/mail/em-subscription-editor.h @@ -21,7 +21,7 @@ #include #include -#include +#include /* Standard GObject macros */ #define EM_TYPE_SUBSCRIPTION_EDITOR \ diff --git a/mail/em-sync-stream.c b/mail/em-sync-stream.c index 06f96ecd83..841d890e41 100644 --- a/mail/em-sync-stream.c +++ b/mail/em-sync-stream.c @@ -32,7 +32,7 @@ #include #include -#include "mail-mt.h" +#include enum _write_msg_t { EMSS_WRITE, diff --git a/mail/em-utils.c b/mail/em-utils.c index 416588cfbb..247b47d967 100644 --- a/mail/em-utils.c +++ b/mail/em-utils.c @@ -41,38 +41,40 @@ #undef interface #endif -#include -#include - #include "em-filter-editor.h" #include #include -#include "mail-mt.h" -#include "mail-ops.h" -#include "mail-tools.h" -#include "e-mail-tag-editor.h" - +#include +#include #include #include #include -#include "e-util/e-util.h" -#include "e-util/e-util-private.h" -#include "e-util/e-mktemp.h" -#include "e-util/e-account-utils.h" -#include "e-util/e-dialog-utils.h" -#include "e-util/e-alert-dialog.h" -#include "shell/e-shell.h" -#include "widgets/misc/e-attachment.h" -#include "em-utils.h" +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "e-mail-tag-editor.h" #include "em-composer-utils.h" #include "em-format-quote.h" #include "em-format-html-print.h" -#include "e-mail-folder-utils.h" -#include "e-mail-session.h" +#include "em-utils.h" /* XXX This is a dirty hack on a dirty hack. We really need * to rework or get rid of the functions that use this. */ @@ -1107,202 +1109,6 @@ em_utils_selection_get_urilist (GtkSelectionData *selection_data, g_strfreev (uris); } -/** - * em_utils_folder_is_templates: - * @folder: a #CamelFolder - * - * Decides if @folder is a Templates folder. - * - * Returns %TRUE if this is a Templates folder or %FALSE otherwise. - **/ - -gboolean -em_utils_folder_is_templates (CamelFolder *folder) -{ - CamelFolder *local_templates_folder; - CamelSession *session; - CamelStore *store; - EAccountList *account_list; - EIterator *iterator; - gchar *folder_uri; - gboolean is_templates = FALSE; - - g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); - - store = camel_folder_get_parent_store (folder); - session = camel_service_get_session (CAMEL_SERVICE (store)); - - local_templates_folder = - e_mail_session_get_local_folder ( - E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_TEMPLATES); - - if (folder == local_templates_folder) - return TRUE; - - folder_uri = e_mail_folder_uri_from_folder (folder); - - account_list = e_get_account_list (); - iterator = e_list_get_iterator (E_LIST (account_list)); - - while (!is_templates && e_iterator_is_valid (iterator)) { - EAccount *account; - - /* XXX EIterator misuses const. */ - account = (EAccount *) e_iterator_get (iterator); - - if (account->templates_folder_uri != NULL) - is_templates = e_mail_folder_uri_equal ( - session, folder_uri, - account->templates_folder_uri); - - e_iterator_next (iterator); - } - - g_object_unref (iterator); - g_free (folder_uri); - - return is_templates; -} - -/** - * em_utils_folder_is_drafts: - * @folder: a #CamelFolder - * - * 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) -{ - CamelFolder *local_drafts_folder; - CamelSession *session; - CamelStore *store; - EAccountList *account_list; - EIterator *iterator; - gchar *folder_uri; - gboolean is_drafts = FALSE; - - g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); - - store = camel_folder_get_parent_store (folder); - session = camel_service_get_session (CAMEL_SERVICE (store)); - - local_drafts_folder = - e_mail_session_get_local_folder ( - E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_DRAFTS); - - if (folder == local_drafts_folder) - return TRUE; - - folder_uri = e_mail_folder_uri_from_folder (folder); - - account_list = e_get_account_list (); - iterator = e_list_get_iterator (E_LIST (account_list)); - - while (!is_drafts && e_iterator_is_valid (iterator)) { - EAccount *account; - - /* XXX EIterator misuses const. */ - account = (EAccount *) e_iterator_get (iterator); - - if (account->drafts_folder_uri != NULL) - is_drafts = e_mail_folder_uri_equal ( - session, folder_uri, - account->drafts_folder_uri); - - e_iterator_next (iterator); - } - - g_object_unref (iterator); - g_free (folder_uri); - - return is_drafts; -} - -/** - * em_utils_folder_is_sent: - * @folder: a #CamelFolder - * - * 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) -{ - CamelFolder *local_sent_folder; - CamelSession *session; - CamelStore *store; - EAccountList *account_list; - EIterator *iterator; - gchar *folder_uri; - gboolean is_sent = FALSE; - - g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); - - store = camel_folder_get_parent_store (folder); - session = camel_service_get_session (CAMEL_SERVICE (store)); - - local_sent_folder = - e_mail_session_get_local_folder ( - E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_SENT); - - if (folder == local_sent_folder) - return TRUE; - - folder_uri = e_mail_folder_uri_from_folder (folder); - - account_list = e_get_account_list (); - iterator = e_list_get_iterator (E_LIST (account_list)); - - while (!is_sent && e_iterator_is_valid (iterator)) { - EAccount *account; - - /* XXX EIterator misuses const. */ - account = (EAccount *) e_iterator_get (iterator); - - if (account->sent_folder_uri != NULL) - is_sent = e_mail_folder_uri_equal ( - session, folder_uri, - account->sent_folder_uri); - - e_iterator_next (iterator); - } - - g_object_unref (iterator); - g_free (folder_uri); - - return is_sent; -} - -/** - * em_utils_folder_is_outbox: - * @folder: a #CamelFolder - * - * 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) -{ - CamelStore *store; - CamelSession *session; - CamelFolder *local_outbox_folder; - - g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); - - store = camel_folder_get_parent_store (folder); - session = camel_service_get_session (CAMEL_SERVICE (store)); - - local_outbox_folder = - e_mail_session_get_local_folder ( - E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_OUTBOX); - - return (folder == local_outbox_folder); -} - /* ********************************************************************** */ static EProxy *emu_proxy = NULL; static GStaticMutex emu_proxy_lock = G_STATIC_MUTEX_INIT; @@ -1454,578 +1260,6 @@ em_utils_empty_trash (GtkWidget *parent, /* ********************************************************************** */ -/* runs sync, in main thread */ -static gpointer -emu_addr_setup (gpointer user_data) -{ - GError *err = NULL; - ESourceList **psource_list = user_data; - - if (!e_book_client_get_sources (psource_list, &err)) - g_error_free (err); - - return NULL; -} - -static void -emu_addr_cancel_stop (gpointer data) -{ - gboolean *stop = data; - - g_return_if_fail (stop != NULL); - - *stop = TRUE; -} - -static void -emu_addr_cancel_cancellable (gpointer data) -{ - GCancellable *cancellable = data; - - g_return_if_fail (cancellable != NULL); - - g_cancellable_cancel (cancellable); -} - -struct TryOpenEBookStruct { - GError **error; - EFlag *flag; - gboolean result; -}; - -static void -try_open_book_client_cb (GObject *source_object, - GAsyncResult *result, - gpointer closure) -{ - EBookClient *book_client = E_BOOK_CLIENT (source_object); - struct TryOpenEBookStruct *data = (struct TryOpenEBookStruct *) closure; - GError *error = NULL; - - if (!data) - return; - - e_client_open_finish (E_CLIENT (book_client), result, &error); - - data->result = error == NULL; - - if (!data->result) { - g_clear_error (data->error); - g_propagate_error (data->error, error); - } - - e_flag_set (data->flag); -} - -/* - * try_open_book_client: - * Tries to open address book asynchronously, but acts as synchronous. - * The advantage is it checks periodically whether the camel_operation - * has been canceled or not, and if so, then stops immediately, with - * result FALSE. Otherwise returns same as e_client_open() - */ -static gboolean -try_open_book_client (EBookClient *book_client, - gboolean only_if_exists, - GCancellable *cancellable, - GError **error) -{ - struct TryOpenEBookStruct data; - gboolean canceled = FALSE; - EFlag *flag = e_flag_new (); - - data.error = error; - data.flag = flag; - data.result = FALSE; - - e_client_open ( - E_CLIENT (book_client), only_if_exists, - cancellable, try_open_book_client_cb, &data); - - while (canceled = g_cancellable_is_cancelled (cancellable), - !canceled && !e_flag_is_set (flag)) { - GTimeVal wait; - - g_get_current_time (&wait); - g_time_val_add (&wait, 250000); /* waits 250ms */ - - e_flag_timed_wait (flag, &wait); - } - - if (canceled) { - g_cancellable_cancel (cancellable); - - g_clear_error (error); - g_propagate_error ( - error, e_client_error_create ( - E_CLIENT_ERROR_CANCELLED, NULL)); - } - - e_flag_wait (flag); - e_flag_free (flag); - - return data.result && (!error || !*error); -} - -#define NOT_FOUND_BOOK (GINT_TO_POINTER (1)) - -G_LOCK_DEFINE_STATIC (contact_cache); - -/* key is lowercased contact email; value is EBook pointer - * (just for comparison) where it comes from */ -static GHashTable *contact_cache = NULL; - -/* key is source ID; value is pointer to EBook */ -static GHashTable *emu_books_hash = NULL; - -/* key is source ID; value is same pointer as key; this is hash of - * broken books, which failed to open for some reason */ -static GHashTable *emu_broken_books_hash = NULL; - -static ESourceList *emu_books_source_list = NULL; - -static gboolean -search_address_in_addressbooks (const gchar *address, - gboolean local_only, - gboolean (*check_contact) (EContact *contact, - gpointer user_data), - gpointer user_data) -{ - gboolean found = FALSE, stop = FALSE, found_any = FALSE; - gchar *lowercase_addr; - gpointer ptr; - EBookQuery *book_query; - gchar *query; - GSList *s, *g, *addr_sources = NULL; - GHook *hook_cancellable; - GCancellable *cancellable; - - if (!address || !*address) - return FALSE; - - G_LOCK (contact_cache); - - if (!emu_books_source_list) { - mail_call_main ( - MAIL_CALL_p_p, (MailMainFunc) - emu_addr_setup, &emu_books_source_list); - emu_books_hash = g_hash_table_new_full ( - g_str_hash, g_str_equal, g_free, g_object_unref); - emu_broken_books_hash = g_hash_table_new_full ( - g_str_hash, g_str_equal, g_free, NULL); - contact_cache = g_hash_table_new_full ( - g_str_hash, g_str_equal, g_free, NULL); - } - - if (!emu_books_source_list) { - G_UNLOCK (contact_cache); - return FALSE; - } - - lowercase_addr = g_utf8_strdown (address, -1); - ptr = g_hash_table_lookup (contact_cache, lowercase_addr); - if (ptr != NULL && (check_contact == NULL || ptr == NOT_FOUND_BOOK)) { - g_free (lowercase_addr); - G_UNLOCK (contact_cache); - return ptr != NOT_FOUND_BOOK; - } - - book_query = e_book_query_field_test (E_CONTACT_EMAIL, E_BOOK_QUERY_IS, address); - query = e_book_query_to_string (book_query); - e_book_query_unref (book_query); - - for (g = e_source_list_peek_groups (emu_books_source_list); - g; g = g_slist_next (g)) { - ESourceGroup *group = g->data; - - if (!group) - continue; - - if (local_only && !(e_source_group_peek_base_uri (group) && - g_str_has_prefix ( - e_source_group_peek_base_uri (group), "local:"))) - continue; - - for (s = e_source_group_peek_sources (group); s; s = g_slist_next (s)) { - ESource *source = s->data; - const gchar *completion = e_source_get_property (source, "completion"); - - if (completion && g_ascii_strcasecmp (completion, "true") == 0) { - addr_sources = g_slist_prepend (addr_sources, g_object_ref (source)); - } - } - } - - cancellable = g_cancellable_new (); - hook_cancellable = mail_cancel_hook_add (emu_addr_cancel_cancellable, cancellable); - - for (s = addr_sources; !stop && !found && s; s = g_slist_next (s)) { - ESource *source = s->data; - GSList *contacts; - EBookClient *book_client = NULL; - GHook *hook_stop; - gboolean cached_book = FALSE; - const gchar *display_name; - const gchar *uid; - GError *err = NULL; - - uid = e_source_peek_uid (source); - display_name = e_source_peek_name (source); - - /* failed to load this book last time, skip it now */ - if (g_hash_table_lookup (emu_broken_books_hash, uid) != NULL) { - d(printf ("%s: skipping broken book '%s'\n", - G_STRFUNC, display_name)); - continue; - } - - d(printf(" checking '%s'\n", e_source_get_uri(source))); - - hook_stop = mail_cancel_hook_add (emu_addr_cancel_stop, &stop); - - book_client = g_hash_table_lookup (emu_books_hash, uid); - if (!book_client) { - book_client = e_book_client_new (source, &err); - - if (book_client == NULL) { - if (err && (g_error_matches (err, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) || - g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED))) { - stop = TRUE; - } else if (err) { - gchar *source_uid; - - source_uid = g_strdup (uid); - - g_hash_table_insert ( - emu_broken_books_hash, - source_uid, source_uid); - - g_warning ( - "%s: Unable to create addressbook '%s': %s", - G_STRFUNC, - display_name, - err->message); - } - g_clear_error (&err); - } else if (!stop && !try_open_book_client (book_client, TRUE, cancellable, &err)) { - g_object_unref (book_client); - book_client = NULL; - - if (err && (g_error_matches (err, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) || - g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED))) { - stop = TRUE; - } else if (err) { - gchar *source_uid; - - source_uid = g_strdup (uid); - - g_hash_table_insert ( - emu_broken_books_hash, - source_uid, source_uid); - - g_warning ( - "%s: Unable to open addressbook '%s': %s", - G_STRFUNC, - display_name, - err->message); - } - g_clear_error (&err); - } - } else { - cached_book = TRUE; - } - - if (book_client && !stop && e_book_client_get_contacts_sync (book_client, query, &contacts, cancellable, &err)) { - if (contacts != NULL) { - if (!found_any) { - g_hash_table_insert (contact_cache, g_strdup (lowercase_addr), book_client); - } - found_any = TRUE; - - if (check_contact) { - GSList *l; - - for (l = contacts; l && !found; l = l->next) { - EContact *contact = l->data; - - found = check_contact (contact, user_data); - } - } else { - found = TRUE; - } - - g_slist_foreach (contacts, (GFunc) g_object_unref, NULL); - g_slist_free (contacts); - } - } else if (book_client) { - stop = stop || (err && - (g_error_matches (err, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) || - g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED))); - if (err && !stop) { - gchar *source_uid = g_strdup (uid); - - g_hash_table_insert (emu_broken_books_hash, source_uid, source_uid); - - g_warning ( - "%s: Can't get contacts from '%s': %s", - G_STRFUNC, - display_name, - err->message); - } - g_clear_error (&err); - } - - mail_cancel_hook_remove (hook_stop); - - if (stop && !cached_book && book_client) { - g_object_unref (book_client); - } else if (!stop && book_client && !cached_book) { - g_hash_table_insert ( - emu_books_hash, g_strdup (uid), book_client); - } - } - - mail_cancel_hook_remove (hook_cancellable); - g_object_unref (cancellable); - - g_slist_free_full (addr_sources, (GDestroyNotify) g_object_unref); - - g_free (query); - - if (!found_any) { - g_hash_table_insert (contact_cache, lowercase_addr, NOT_FOUND_BOOK); - lowercase_addr = NULL; - } - - G_UNLOCK (contact_cache); - - g_free (lowercase_addr); - - return found_any; -} - -gboolean -em_utils_in_addressbook (CamelInternetAddress *iaddr, - gboolean local_only) -{ - const gchar *addr; - - /* TODO: check all addresses? */ - if (iaddr == NULL || !camel_internet_address_get (iaddr, 0, NULL, &addr)) - return FALSE; - - return search_address_in_addressbooks (addr, local_only, NULL, NULL); -} - -static gboolean -extract_photo_data (EContact *contact, - gpointer user_data) -{ - EContactPhoto **photo = user_data; - - g_return_val_if_fail (contact != NULL, FALSE); - g_return_val_if_fail (user_data != NULL, FALSE); - - *photo = e_contact_get (contact, E_CONTACT_PHOTO); - if (!*photo) - *photo = e_contact_get (contact, E_CONTACT_LOGO); - - return *photo != NULL; -} - -typedef struct _PhotoInfo { - gchar *address; - EContactPhoto *photo; -} PhotoInfo; - -static void -emu_free_photo_info (PhotoInfo *pi) -{ - if (!pi) - return; - - if (pi->address) - g_free (pi->address); - if (pi->photo) - e_contact_photo_free (pi->photo); - g_free (pi); -} - -G_LOCK_DEFINE_STATIC (photos_cache); -static GSList *photos_cache = NULL; /* list of PhotoInfo-s */ - -CamelMimePart * -em_utils_contact_photo (CamelInternetAddress *cia, - gboolean local_only) -{ - const gchar *addr = NULL; - CamelMimePart *part = NULL; - EContactPhoto *photo = NULL; - GSList *p, *first_not_null = NULL; - gint count_not_null = 0; - - if (cia == NULL || !camel_internet_address_get (cia, 0, NULL, &addr) || !addr) { - return NULL; - } - - G_LOCK (photos_cache); - - /* search a cache first */ - for (p = photos_cache; p; p = p->next) { - PhotoInfo *pi = p->data; - - if (!pi) - continue; - - if (pi->photo) { - if (!first_not_null) - first_not_null = p; - count_not_null++; - } - - if (g_ascii_strcasecmp (addr, pi->address) == 0) { - photo = pi->photo; - break; - } - } - - /* !p means the address had not been found in the cache */ - if (!p && search_address_in_addressbooks ( - addr, local_only, extract_photo_data, &photo)) { - PhotoInfo *pi; - - if (photo && photo->type != E_CONTACT_PHOTO_TYPE_INLINED) { - e_contact_photo_free (photo); - photo = NULL; - } - - /* keep only up to 10 photos in memory */ - if (photo && count_not_null >= 10 && first_not_null) { - pi = first_not_null->data; - - photos_cache = g_slist_remove (photos_cache, pi); - - emu_free_photo_info (pi); - } - - pi = g_new0 (PhotoInfo, 1); - pi->address = g_strdup (addr); - pi->photo = photo; - - photos_cache = g_slist_append (photos_cache, pi); - } - - /* some photo found, use it */ - if (photo) { - /* Form a mime part out of the photo */ - part = camel_mime_part_new (); - camel_mime_part_set_content (part, - (const gchar *) photo->data.inlined.data, - photo->data.inlined.length, "image/jpeg"); - } - - G_UNLOCK (photos_cache); - - return part; -} - -/* list of email addresses (strings) to remove from local cache of photos and - * contacts, but only if the photo doesn't exist or is an not-found contact */ -void -emu_remove_from_mail_cache (const GSList *addresses) -{ - const GSList *a; - GSList *p; - CamelInternetAddress *cia; - - cia = camel_internet_address_new (); - - for (a = addresses; a; a = a->next) { - const gchar *addr = NULL; - - if (!a->data) - continue; - - if (camel_address_decode ((CamelAddress *) cia, a->data) != -1 && - camel_internet_address_get (cia, 0, NULL, &addr) && addr) { - gchar *lowercase_addr = g_utf8_strdown (addr, -1); - - G_LOCK (contact_cache); - if (g_hash_table_lookup (contact_cache, lowercase_addr) == NOT_FOUND_BOOK) - g_hash_table_remove (contact_cache, lowercase_addr); - G_UNLOCK (contact_cache); - - g_free (lowercase_addr); - - G_LOCK (photos_cache); - for (p = photos_cache; p; p = p->next) { - PhotoInfo *pi = p->data; - - if (pi && !pi->photo && g_ascii_strcasecmp (pi->address, addr) == 0) { - photos_cache = g_slist_remove (photos_cache, pi); - emu_free_photo_info (pi); - break; - } - } - G_UNLOCK (photos_cache); - } - } - - g_object_unref (cia); -} - -void -emu_remove_from_mail_cache_1 (const gchar *address) -{ - GSList *l; - - g_return_if_fail (address != NULL); - - l = g_slist_append (NULL, (gpointer) address); - - emu_remove_from_mail_cache (l); - - g_slist_free (l); -} - -/* frees all data created by call of em_utils_in_addressbook() or - * em_utils_contact_photo() */ -void -emu_free_mail_cache (void) -{ - G_LOCK (contact_cache); - - if (emu_books_hash) { - g_hash_table_destroy (emu_books_hash); - emu_books_hash = NULL; - } - - if (emu_broken_books_hash) { - g_hash_table_destroy (emu_broken_books_hash); - emu_broken_books_hash = NULL; - } - - if (emu_books_source_list) { - g_object_unref (emu_books_source_list); - emu_books_source_list = NULL; - } - - if (contact_cache) { - g_hash_table_destroy (contact_cache); - contact_cache = NULL; - } - - G_UNLOCK (contact_cache); - - G_LOCK (photos_cache); - - g_slist_foreach (photos_cache, (GFunc) emu_free_photo_info, NULL); - g_slist_free (photos_cache); - photos_cache = NULL; - - G_UNLOCK (photos_cache); -} - void em_utils_clear_get_password_canceled_accounts_flag (void) { @@ -2080,148 +1314,6 @@ em_utils_url_unescape_amp (const gchar *url) return buff; } -static EAccount * -guess_account_from_folder (CamelFolder *folder) -{ - CamelStore *store; - const gchar *uid; - - store = camel_folder_get_parent_store (folder); - uid = camel_service_get_uid (CAMEL_SERVICE (store)); - - return e_get_account_by_uid (uid); -} - -static EAccount * -guess_account_from_message (CamelMimeMessage *message) -{ - const gchar *uid; - - uid = camel_mime_message_get_source (message); - - return (uid != NULL) ? e_get_account_by_uid (uid) : NULL; -} - -EAccount * -em_utils_guess_account (CamelMimeMessage *message, - CamelFolder *folder) -{ - EAccount *account = NULL; - - g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL); - - if (folder != NULL) - g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL); - - /* check for newsgroup header */ - if (folder != NULL - && camel_medium_get_header (CAMEL_MEDIUM (message), "Newsgroups")) - account = guess_account_from_folder (folder); - - /* check for source folder */ - if (account == NULL && folder != NULL) - account = guess_account_from_folder (folder); - - /* then message source */ - if (account == NULL) - account = guess_account_from_message (message); - - return account; -} - -EAccount * -em_utils_guess_account_with_recipients (CamelMimeMessage *message, - CamelFolder *folder) -{ - EAccount *account = NULL; - EAccountList *account_list; - GHashTable *recipients; - EIterator *iterator; - CamelInternetAddress *addr; - const gchar *type; - const gchar *key; - - /* This policy is subject to debate and tweaking, - * but please also document the rational here. */ - - g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL); - - /* Build a set of email addresses in which to test for membership. - * Only the keys matter here; the values just need to be non-NULL. */ - recipients = g_hash_table_new (g_str_hash, g_str_equal); - - type = CAMEL_RECIPIENT_TYPE_TO; - addr = camel_mime_message_get_recipients (message, type); - if (addr != NULL) { - gint index = 0; - - while (camel_internet_address_get (addr, index++, NULL, &key)) - g_hash_table_insert ( - recipients, (gpointer) key, - GINT_TO_POINTER (1)); - } - - type = CAMEL_RECIPIENT_TYPE_CC; - addr = camel_mime_message_get_recipients (message, type); - if (addr != NULL) { - gint index = 0; - - while (camel_internet_address_get (addr, index++, NULL, &key)) - g_hash_table_insert ( - recipients, (gpointer) key, - GINT_TO_POINTER (1)); - } - - /* First Preference: We were given a folder that maps to an - * enabled account, and that account's email address appears - * in the list of To: or Cc: recipients. */ - - if (folder != NULL) - account = guess_account_from_folder (folder); - - if (account == NULL || !account->enabled) - goto second_preference; - - if ((key = account->id->address) == NULL) - goto second_preference; - - if (g_hash_table_lookup (recipients, key) != NULL) - goto exit; - -second_preference: - - /* Second Preference: Choose any enabled account whose email - * address appears in the list to To: or Cc: recipients. */ - - account_list = e_get_account_list (); - iterator = e_list_get_iterator (E_LIST (account_list)); - - while (e_iterator_is_valid (iterator)) { - account = (EAccount *) e_iterator_get (iterator); - e_iterator_next (iterator); - - if (account == NULL || !account->enabled) - continue; - - if ((key = account->id->address) == NULL) - continue; - - if (g_hash_table_lookup (recipients, key) != NULL) { - g_object_unref (iterator); - goto exit; - } - } - g_object_unref (iterator); - - /* Last Preference: Defer to em_utils_guess_account(). */ - account = em_utils_guess_account (message, folder); - -exit: - g_hash_table_destroy (recipients); - - return account; -} - void emu_restore_folder_tree_state (EMFolderTree *folder_tree) { @@ -2252,76 +1344,6 @@ emu_restore_folder_tree_state (EMFolderTree *folder_tree) g_key_file_free (key_file); } -/* Returns TRUE if CamelURL points to a local mbox file. */ -gboolean -em_utils_is_local_delivery_mbox_file (CamelURL *url) -{ - g_return_val_if_fail (url != NULL, FALSE); - - return g_str_equal (url->protocol, "mbox") && - (url->path != NULL) && - g_file_test (url->path, G_FILE_TEST_EXISTS) && - !g_file_test (url->path, G_FILE_TEST_IS_DIR); -} - -static void -cancel_service_connect_cb (GCancellable *cancellable, - CamelService *service) -{ - g_return_if_fail (CAMEL_IS_SERVICE (service)); - - camel_service_cancel_connect (service); -} - -gboolean -em_utils_connect_service_sync (CamelService *service, - GCancellable *cancellable, - GError **error) -{ - gboolean res; - gulong handler_id = 0; - - g_return_val_if_fail (CAMEL_IS_SERVICE (service), FALSE); - - if (cancellable != NULL) - handler_id = g_cancellable_connect ( - cancellable, - G_CALLBACK (cancel_service_connect_cb), - service, NULL); - - res = camel_service_connect_sync (service, error); - - if (handler_id) - g_cancellable_disconnect (cancellable, handler_id); - - return res; -} - -gboolean -em_utils_disconnect_service_sync (CamelService *service, - gboolean clean, - GCancellable *cancellable, - GError **error) -{ - gboolean res; - gulong handler_id = 0; - - g_return_val_if_fail (CAMEL_IS_SERVICE (service), FALSE); - - if (cancellable != NULL) - handler_id = g_cancellable_connect ( - cancellable, - G_CALLBACK (cancel_service_connect_cb), - service, NULL); - - res = camel_service_disconnect_sync (service, clean, error); - - if (handler_id) - g_cancellable_disconnect (cancellable, handler_id); - - return res; -} - static gboolean check_prefix (const gchar *subject, const gchar *prefix, diff --git a/mail/em-utils.h b/mail/em-utils.h index bf02419526..09ae4a56eb 100644 --- a/mail/em-utils.h +++ b/mail/em-utils.h @@ -29,8 +29,10 @@ #include #include +#include +#include + #include -#include #include G_BEGIN_DECLS @@ -42,7 +44,6 @@ gboolean em_utils_ask_open_many (GtkWindow *parent, gint how_many); gboolean em_utils_prompt_user (GtkWindow *parent, const gchar *promptkey, const gchar *tag, ...); GPtrArray *em_utils_uids_copy (GPtrArray *uids); -void em_utils_uids_free (GPtrArray *uids); void em_utils_edit_filters (EMailSession *session, EAlertSink *alert_sink, @@ -64,11 +65,6 @@ void em_utils_selection_get_uidlist (GtkSelectionData *data, EMailSession *sessi void em_utils_selection_set_urilist (GtkSelectionData *data, CamelFolder *folder, GPtrArray *uids); void em_utils_selection_get_urilist (GtkSelectionData *data, CamelFolder *folder); -gboolean em_utils_folder_is_drafts (CamelFolder *folder); -gboolean em_utils_folder_is_templates (CamelFolder *folder); -gboolean em_utils_folder_is_sent (CamelFolder *folder); -gboolean em_utils_folder_is_outbox (CamelFolder *folder); - EProxy * em_utils_get_proxy (void); /* FIXME: should this have an override charset? */ @@ -77,33 +73,16 @@ gchar *em_utils_message_to_html (CamelMimeMessage *msg, const gchar *credits, gu void em_utils_empty_trash (GtkWidget *parent, EMailSession *session); -/* is this address in the addressbook? caches results */ -gboolean em_utils_in_addressbook (CamelInternetAddress *addr, gboolean local_only); -CamelMimePart *em_utils_contact_photo (CamelInternetAddress *addr, gboolean local); - /* clears flag 'get_password_canceled' at every known accounts, so if needed, get_password will show dialog */ void em_utils_clear_get_password_canceled_accounts_flag (void); /* Unescapes & back to a real & in URIs */ gchar *em_utils_url_unescape_amp (const gchar *url); -EAccount * em_utils_guess_account (CamelMimeMessage *message, - CamelFolder *folder); -EAccount * em_utils_guess_account_with_recipients - (CamelMimeMessage *message, - CamelFolder *folder); - -void emu_remove_from_mail_cache (const GSList *addresses); -void emu_remove_from_mail_cache_1 (const gchar *address); -void emu_free_mail_cache (void); +void emu_free_mail_account_sort_order_cache (void); void emu_restore_folder_tree_state (EMFolderTree *folder_tree); -gboolean em_utils_is_local_delivery_mbox_file (CamelURL *url); - -gboolean em_utils_connect_service_sync (CamelService *service, GCancellable *cancellable, GError **error); -gboolean em_utils_disconnect_service_sync (CamelService *service, gboolean clean, GCancellable *cancellable, GError **error); - gboolean em_utils_is_re_in_subject (struct _EShell *shell, const gchar *subject, gint *skip_len); diff --git a/mail/em-vfolder-context.h b/mail/em-vfolder-context.h index c0fd041abc..2d1c6ef0fc 100644 --- a/mail/em-vfolder-context.h +++ b/mail/em-vfolder-context.h @@ -25,8 +25,8 @@ #ifndef EM_VFOLDER_CONTEXT_H #define EM_VFOLDER_CONTEXT_H -#include #include +#include /* Standard GObject macros */ #define EM_TYPE_VFOLDER_CONTEXT \ diff --git a/mail/em-vfolder-rule.c b/mail/em-vfolder-rule.c index a22816070a..91bf46128e 100644 --- a/mail/em-vfolder-rule.c +++ b/mail/em-vfolder-rule.c @@ -30,17 +30,19 @@ #include #include +#include + +#include +#include +#include + +#include + +#include "em-folder-selector.h" +#include "em-folder-tree.h" +#include "em-utils.h" #include "em-vfolder-context.h" #include "em-vfolder-rule.h" -#include "mail/e-mail-folder-utils.h" -#include "mail/em-utils.h" -#include "mail/em-folder-tree.h" -#include "mail/em-folder-selector.h" -#include "shell/e-shell.h" - -#include "e-util/e-util.h" -#include "e-util/e-alert.h" -#include "e-util/e-util-private.h" #define EM_VFOLDER_RULE_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE \ diff --git a/mail/em-vfolder-rule.h b/mail/em-vfolder-rule.h index 7fc8daaee9..1b3a4432ca 100644 --- a/mail/em-vfolder-rule.h +++ b/mail/em-vfolder-rule.h @@ -24,8 +24,8 @@ #ifndef EM_VFOLDER_RULE_H #define EM_VFOLDER_RULE_H -#include #include +#include /* Standard GObject macros */ #define EM_TYPE_VFOLDER_RULE \ diff --git a/mail/importers/Makefile.am b/mail/importers/Makefile.am index fa1a400f03..6a7e9a8b6e 100644 --- a/mail/importers/Makefile.am +++ b/mail/importers/Makefile.am @@ -28,6 +28,8 @@ libevolution_mail_importers_la_LIBADD = \ $(top_builddir)/mail/libevolution-mail.la \ $(top_builddir)/shell/libeshell.la \ $(top_builddir)/widgets/misc/libemiscwidgets.la \ + $(top_builddir)/libemail-engine/libemail-engine.la \ + $(top_builddir)/libemail-utils/libemail-utils.la \ $(EVOLUTION_DATA_SERVER_LIBS) \ $(GNOME_PLATFORM_LIBS) \ $(GTKHTML_LIBS) diff --git a/mail/importers/elm-importer.c b/mail/importers/elm-importer.c index 832bf749ea..288d9fb736 100644 --- a/mail/importers/elm-importer.c +++ b/mail/importers/elm-importer.c @@ -40,7 +40,7 @@ #include "mail-importer.h" -#include "mail/mail-mt.h" +#include "libemail-utils/mail-mt.h" #include "mail/e-mail-backend.h" #include "e-util/e-import.h" #include "shell/e-shell.h" diff --git a/mail/importers/evolution-mbox-importer.c b/mail/importers/evolution-mbox-importer.c index c3d5f2f1b7..f6e5c63613 100644 --- a/mail/importers/evolution-mbox-importer.c +++ b/mail/importers/evolution-mbox-importer.c @@ -48,7 +48,7 @@ #include "mail/em-folder-selection-button.h" #include "mail/em-folder-tree-model.h" #include "mail/em-folder-tree.h" -#include "mail/mail-mt.h" +#include "libemail-utils/mail-mt.h" #include "mail-importer.h" diff --git a/mail/importers/mail-importer.c b/mail/importers/mail-importer.c index 558359c636..716d99c991 100644 --- a/mail/importers/mail-importer.c +++ b/mail/importers/mail-importer.c @@ -39,9 +39,9 @@ #include "e-util/e-util-private.h" #include "shell/e-shell-backend.h" -#include "mail-mt.h" -#include "mail-tools.h" -#include "e-mail-session.h" +#include "libemail-utils/mail-mt.h" +#include "libemail-engine/mail-tools.h" +#include "libemail-engine/e-mail-session.h" #include "mail-importer.h" @@ -277,9 +277,9 @@ mail_importer_import_mbox_sync (EMailSession *session, m->path = g_strdup (path); m->uri = g_strdup (folderuri); if (cancellable) - e_activity_set_cancellable (m->base.activity, cancellable); + m->base.cancellable = cancellable; - cancellable = e_activity_get_cancellable (m->base.activity); + cancellable = m->base.cancellable; import_mbox_exec (m, cancellable, &m->base.error); import_mbox_done (m); diff --git a/mail/importers/mail-importer.h b/mail/importers/mail-importer.h index d66ed464ec..bd0335c299 100644 --- a/mail/importers/mail-importer.h +++ b/mail/importers/mail-importer.h @@ -26,7 +26,7 @@ #include #include -#include +#include EImportImporter *mbox_importer_peek (void); diff --git a/mail/importers/pine-importer.c b/mail/importers/pine-importer.c index 1ba44583ab..3ecfbbc5df 100644 --- a/mail/importers/pine-importer.c +++ b/mail/importers/pine-importer.c @@ -43,7 +43,7 @@ #include "mail-importer.h" -#include "mail/mail-mt.h" +#include "libemail-utils/mail-mt.h" #include "mail/e-mail-backend.h" #include "e-util/e-import.h" #include "shell/e-shell.h" diff --git a/mail/mail-autofilter.c b/mail/mail-autofilter.c index 6d08c78a40..08e3a3d937 100644 --- a/mail/mail-autofilter.c +++ b/mail/mail-autofilter.c @@ -29,8 +29,9 @@ #include -#include "e-mail-folder-utils.h" -#include "e-mail-session.h" +#include +#include + #include "mail-vfolder.h" #include "mail-autofilter.h" #include "em-utils.h" diff --git a/mail/mail-autofilter.h b/mail/mail-autofilter.h index 47f68c3be5..34593b0f95 100644 --- a/mail/mail-autofilter.h +++ b/mail/mail-autofilter.h @@ -27,9 +27,9 @@ #include #include -#include #include #include +#include enum { AUTO_SUBJECT = 1, diff --git a/mail/mail-config.c b/mail/mail-config.c deleted file mode 100644 index fc003acbde..0000000000 --- a/mail/mail-config.c +++ /dev/null @@ -1,295 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see - * - * - * Authors: - * Jeffrey Stedfast - * Radek Doulik - * Jonathon Jongsma - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * Copyright (C) 2009 Intel Corporation - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include - -#include -#include "e-util/e-account-utils.h" -#include "e-util/e-signature-utils.h" - -#include "e-mail-folder-utils.h" -#include "mail-config.h" -#include "mail-tools.h" - -typedef struct { - GSList *labels; - - gboolean address_compress; - gint address_count; - - GSList *jh_header; - gboolean jh_check; - gboolean book_lookup; - gboolean book_lookup_local_only; -} MailConfig; - -extern gint camel_header_param_encode_filenames_in_rfc_2047; - -static MailConfig *config = NULL; -static GSettings *mail_settings = NULL; - -static void -settings_outlook_filenames_changed (GSettings *settings, - const gchar *key, - gpointer user_data) -{ - /* pass option to the camel */ - if (g_settings_get_boolean (settings, key)) - camel_header_param_encode_filenames_in_rfc_2047 = 1; - else - camel_header_param_encode_filenames_in_rfc_2047 = 0; -} - -static void -settings_jh_headers_changed (GSettings *settings, - const gchar *key, - EMailSession *session) -{ - GSList *node; - GPtrArray *name, *value; - gchar **strv; - gint i; - - g_slist_foreach (config->jh_header, (GFunc) g_free, NULL); - g_slist_free (config->jh_header); - config->jh_header = NULL; - - strv = g_settings_get_strv (settings, "junk-custom-header"); - for (i = 0; strv[i] != NULL; i++) - config->jh_header = g_slist_append (config->jh_header, g_strdup (strv[i])); - g_strfreev (strv); - - node = config->jh_header; - name = g_ptr_array_new (); - value = g_ptr_array_new (); - while (node && node->data) { - gchar **tok = g_strsplit (node->data, "=", 2); - g_ptr_array_add (name, g_strdup (tok[0])); - g_ptr_array_add (value, g_strdup (tok[1])); - node = node->next; - g_strfreev (tok); - } - camel_session_set_junk_headers ( - CAMEL_SESSION (session), - (const gchar **) name->pdata, - (const gchar **) value->pdata, name->len); - - g_ptr_array_foreach (name, (GFunc) g_free, NULL); - g_ptr_array_foreach (value, (GFunc) g_free, NULL); - g_ptr_array_free (name, TRUE); - g_ptr_array_free (value, TRUE); -} - -static void -settings_jh_check_changed (GSettings *settings, - const gchar *key, - EMailSession *session) -{ - config->jh_check = g_settings_get_boolean (settings, "junk-check-custom-header"); - if (!config->jh_check) { - camel_session_set_junk_headers ( - CAMEL_SESSION (session), NULL, NULL, 0); - } else { - settings_jh_headers_changed (settings, NULL, session); - } -} - -static void -settings_bool_value_changed (GSettings *settings, - const gchar *key, - gboolean *save_location) -{ - *save_location = g_settings_get_boolean (settings, key); -} - -static void -settings_int_value_changed (GSettings *settings, - const gchar *key, - gint *save_location) -{ - *save_location = g_settings_get_int (settings, key); -} - -void -mail_config_write (void) -{ - EAccountList *account_list; - ESignatureList *signature_list; - - if (!config) - return; - - account_list = e_get_account_list (); - signature_list = e_get_signature_list (); - - e_account_list_save (account_list); - e_signature_list_save (signature_list); - - g_settings_sync (); -} - -gint -mail_config_get_address_count (void) -{ - if (!config->address_compress) - return -1; - - return config->address_count; -} - -/* timeout interval, in seconds, when to call server update */ -gint -mail_config_get_sync_timeout (void) -{ - gint res = 60; - - res = g_settings_get_int (mail_settings, "sync-interval"); - - /* do not allow recheck sooner than every 30 seconds */ - if (res == 0) - res = 60; - else if (res < 30) - res = 30; - - return res; -} - -gchar * -mail_config_folder_to_cachename (CamelFolder *folder, - const gchar *prefix) -{ - gchar *folder_uri, *basename, *filename; - const gchar *config_dir; - - config_dir = mail_session_get_config_dir (); - - basename = g_build_filename (config_dir, "folders", NULL); - if (!g_file_test (basename, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) { - /* create the folder if does not exist */ - g_mkdir_with_parents (basename, 0700); - } - g_free (basename); - - folder_uri = e_mail_folder_uri_from_folder (folder); - e_filename_make_safe (folder_uri); - basename = g_strdup_printf ("%s%s", prefix, folder_uri); - filename = g_build_filename (config_dir, "folders", basename, NULL); - g_free (basename); - g_free (folder_uri); - - return filename; -} - -void -mail_config_reload_junk_headers (EMailSession *session) -{ - g_return_if_fail (E_IS_MAIL_SESSION (session)); - - /* It automatically sets in the session */ - if (config == NULL) - mail_config_init (session); - else { - settings_jh_check_changed (mail_settings, NULL, session); - } -} - -gboolean -mail_config_get_lookup_book (void) -{ - g_return_val_if_fail (config != NULL, FALSE); - - return config->book_lookup; -} - -gboolean -mail_config_get_lookup_book_local_only (void) -{ - g_return_val_if_fail (config != NULL, FALSE); - - return config->book_lookup_local_only; -} - -/* Config struct routines */ -void -mail_config_init (EMailSession *session) -{ - g_return_if_fail (E_IS_MAIL_SESSION (session)); - - if (config) - return; - - config = g_new0 (MailConfig, 1); - - mail_settings = g_settings_new ("org.gnome.evolution.mail"); - - /* Composer Configuration */ - - settings_outlook_filenames_changed ( - mail_settings, "composer-outlook-filenames", NULL); - g_signal_connect ( - mail_settings, "changed::composer-outlook-filenames", - G_CALLBACK (settings_outlook_filenames_changed), NULL); - - /* Display Configuration */ - - g_signal_connect ( - mail_settings, "changed::address-compress", - G_CALLBACK (settings_bool_value_changed), &config->address_compress); - config->address_compress = g_settings_get_boolean (mail_settings, "address-compress"); - - g_signal_connect ( - mail_settings, "changed::address-count", - G_CALLBACK (settings_int_value_changed), &config->address_count); - config->address_count = g_settings_get_int (mail_settings, "address-count"); - - /* Junk Configuration */ - - g_signal_connect ( - mail_settings, "changed::junk-check-custom-header", - G_CALLBACK (settings_jh_check_changed), session); - config->jh_check = g_settings_get_boolean (mail_settings, "junk-check-custom-header"); - - g_signal_connect ( - mail_settings, "changed::junk-custom-header", - G_CALLBACK (settings_jh_headers_changed), session); - - g_signal_connect ( - mail_settings, "changed::junk-lookup-addressbook", - G_CALLBACK (settings_bool_value_changed), &config->book_lookup); - config->book_lookup = g_settings_get_boolean (mail_settings, "junk-lookup-addressbook"); - - g_signal_connect ( - mail_settings, "changed::junk-lookup-addressbook-local-only", - G_CALLBACK (settings_bool_value_changed), &config->book_lookup_local_only); - config->book_lookup_local_only = g_settings_get_boolean (mail_settings, "junk-lookup-addressbook-local-only"); - - settings_jh_check_changed (mail_settings, NULL, session); -} diff --git a/mail/mail-config.h b/mail/mail-config.h deleted file mode 100644 index 29038093cb..0000000000 --- a/mail/mail-config.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see - * - * - * Authors: - * Jeffrey Stedfast - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef MAIL_CONFIG_H -#define MAIL_CONFIG_H - -#include - -G_BEGIN_DECLS - -/* Configuration */ -void mail_config_init (EMailSession *session); -void mail_config_write (void); - -/* General Accessor functions */ - -gint mail_config_get_address_count (void); - -/* static utility functions */ -gchar * mail_config_folder_to_cachename (CamelFolder *folder, - const gchar *prefix); -gint mail_config_get_sync_timeout (void); - -void mail_config_reload_junk_headers (EMailSession *session); -gboolean mail_config_get_lookup_book (void); -gboolean mail_config_get_lookup_book_local_only (void); - -G_END_DECLS - -#endif /* MAIL_CONFIG_H */ diff --git a/mail/mail-folder-cache.c b/mail/mail-folder-cache.c deleted file mode 100644 index 4092ee6861..0000000000 --- a/mail/mail-folder-cache.c +++ /dev/null @@ -1,1875 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see - * - * - * Authors: - * Peter Williams - * Michael Zucchi - * Jonathon Jongsma - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * Copyright (C) 2009 Intel Corporation - * - */ - -/** - * SECTION: mail-folder-cache - * @short_description: Stores information about open folders - **/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include -#include - -#include -#include -#include - -#include "mail-mt.h" -#include "mail-folder-cache.h" -#include "mail-ops.h" -#include "mail-tools.h" - -#include "em-utils.h" -#include "e-mail-folder-utils.h" -#include "e-mail-session.h" -#include "e-mail-store-utils.h" - -#define w(x) -#define d(x) - -#define MAIL_FOLDER_CACHE_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE \ - ((obj), MAIL_TYPE_FOLDER_CACHE, MailFolderCachePrivate)) - -/* This code is a mess, there is no reason it should be so complicated. */ - -typedef struct _StoreInfo StoreInfo; - -struct _MailFolderCachePrivate { - gpointer session; /* weak pointer */ - EMailAccountStore *account_store; - - /* source id for the ping timeout callback */ - guint ping_id; - /* Store to storeinfo table, active stores */ - GHashTable *stores; - /* mutex to protect access to the stores hash */ - GMutex *stores_mutex; - /* List of folder changes to be executed in gui thread */ - GQueue updates; - /* idle source id for flushing all pending updates */ - guint update_id; - /* hack for people who LIKE to have unsent count */ - gint count_sent; - gint count_trash; - - GQueue local_folder_uris; - GQueue remote_folder_uris; -}; - -enum { - PROP_0, - PROP_SESSION -}; - -enum { - FOLDER_AVAILABLE, - FOLDER_UNAVAILABLE, - FOLDER_DELETED, - FOLDER_RENAMED, - FOLDER_UNREAD_UPDATED, - FOLDER_CHANGED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL]; - -struct _folder_info { - StoreInfo *store_info; /* 'parent' link */ - - gchar *full_name; /* full name of folder/folderinfo */ - - guint32 flags; - gboolean has_children; - - gpointer folder; /* if known (weak pointer) */ -}; - -/* pending list of updates */ -struct _folder_update { - guint remove:1; /* removing from vfolders */ - guint delete:1; /* deleting as well? */ - guint add:1; /* add to vfolder */ - guint unsub:1; /* unsubcribing? */ - guint new; /* new mail arrived? */ - - gchar *full_name; - gchar *oldfull; - - gint unread; - CamelStore *store; - - /* for only one new message... */ - gchar *msg_uid; /* ... its uid ... */ - gchar *msg_sender; /* ... its sender ... */ - gchar *msg_subject; /* ... and its subject. */ -}; - -struct _StoreInfo { - GHashTable *folders; /* by full_name */ - CamelStore *store; /* the store for these folders */ - gboolean first_update; /* TRUE initially, then FALSE forever */ - - /* Hold a reference to keep them alive. */ - CamelFolder *vjunk; - CamelFolder *vtrash; - - /* Outstanding folderinfo requests */ - GQueue folderinfo_updates; -}; - -struct _update_data { - NoteDoneFunc done; - gpointer data; - MailFolderCache *cache; - GCancellable *cancellable; -}; - -G_DEFINE_TYPE (MailFolderCache, mail_folder_cache, G_TYPE_OBJECT) - -static void -free_update (struct _folder_update *up) -{ - g_free (up->full_name); - if (up->store) - g_object_unref (up->store); - g_free (up->oldfull); - g_free (up->msg_uid); - g_free (up->msg_sender); - g_free (up->msg_subject); - g_free (up); -} - -static void -free_folder_info (struct _folder_info *mfi) -{ - g_free (mfi->full_name); - g_free (mfi); -} - -static StoreInfo * -store_info_new (CamelStore *store) -{ - StoreInfo *info; - GHashTable *folders; - - folders = g_hash_table_new_full ( - (GHashFunc) g_str_hash, - (GEqualFunc) g_str_equal, - (GDestroyNotify) NULL, - (GDestroyNotify) free_folder_info); - - info = g_slice_new0 (StoreInfo); - info->folders = folders; - info->store = g_object_ref (store); - info->first_update = TRUE; - - /* If these are vfolders then they need to be opened - * now, otherwise they won't keep track of all folders. */ - if (store->flags & CAMEL_STORE_VJUNK) - info->vjunk = camel_store_get_junk_folder_sync ( - store, NULL, NULL); - if (store->flags & CAMEL_STORE_VTRASH) - info->vtrash = camel_store_get_trash_folder_sync ( - store, NULL, NULL); - - g_queue_init (&info->folderinfo_updates); - - return info; -} - -static void -store_info_free (StoreInfo *info) -{ - struct _update_data *ud; - - while (!g_queue_is_empty (&info->folderinfo_updates)) { - ud = g_queue_pop_head (&info->folderinfo_updates); - g_cancellable_cancel (ud->cancellable); - } - - g_hash_table_destroy (info->folders); - g_object_unref (info->store); - - if (info->vjunk != NULL) - g_object_unref (info->vjunk); - - if (info->vtrash != NULL) - g_object_unref (info->vtrash); - - g_slice_free (StoreInfo, info); -} - -static gboolean -flush_updates_idle_cb (MailFolderCache *cache) -{ - struct _folder_update *up; - - g_mutex_lock (cache->priv->stores_mutex); - while ((up = g_queue_pop_head (&cache->priv->updates)) != NULL) { - g_mutex_unlock (cache->priv->stores_mutex); - - if (up->remove) { - if (up->delete) { - g_signal_emit ( - cache, signals[FOLDER_DELETED], 0, - up->store, up->full_name); - } else - g_signal_emit ( - cache, signals[FOLDER_UNAVAILABLE], 0, - up->store, up->full_name); - } else { - if (up->oldfull && up->add) { - g_signal_emit ( - cache, signals[FOLDER_RENAMED], 0, - up->store, up->oldfull, up->full_name); - } - - if (!up->oldfull && up->add) - g_signal_emit ( - cache, signals[FOLDER_AVAILABLE], 0, - up->store, up->full_name); - } - - /* update unread counts */ - g_signal_emit (cache, signals[FOLDER_UNREAD_UPDATED], 0, - up->store, up->full_name, up->unread); - - /* indicate that the folder has changed (new mail received, etc) */ - if (up->store != NULL && up->full_name != NULL) { - g_signal_emit ( - cache, signals[FOLDER_CHANGED], 0, up->store, - up->full_name, up->new, up->msg_uid, - up->msg_sender, up->msg_subject); - } - - if (CAMEL_IS_VEE_STORE (up->store) && !up->remove) { - /* Normally the vfolder store takes care of the - * folder_opened event itcache, but we add folder to - * the noting system later, thus we do not know about - * search folders to update them in a tree, thus - * ensure their changes will be tracked correctly. */ - CamelFolder *folder; - - /* FIXME camel_store_get_folder_sync() may block. */ - folder = camel_store_get_folder_sync ( - up->store, up->full_name, 0, NULL, NULL); - - if (folder) { - mail_folder_cache_note_folder (cache, folder); - g_object_unref (folder); - } - } - - free_update (up); - - g_mutex_lock (cache->priv->stores_mutex); - } - cache->priv->update_id = 0; - g_mutex_unlock (cache->priv->stores_mutex); - - return FALSE; -} - -static void -flush_updates (MailFolderCache *cache) -{ - if (cache->priv->update_id > 0) - return; - - if (g_queue_is_empty (&cache->priv->updates)) - return; - - cache->priv->update_id = g_idle_add ( - (GSourceFunc) flush_updates_idle_cb, cache); -} - -/* This is how unread counts work (and don't work): - * - * camel_folder_unread_message_count() only gives a correct answer if - * the store is paying attention to the folder. (Some stores always - * pay attention to all folders, but IMAP can only pay attention to - * one folder at a time.) But it doesn't have any way to know when - * it's lying, so it's only safe to call it when you know for sure - * that the store is paying attention to the folder, such as when it's - * just been created, or you get a folder_changed signal on it. - * - * camel_store_get_folder_info() always gives correct answers for the - * folders it checks, but it can also return -1 for a folder, meaning - * it didn't check, and so you should stick with your previous answer. - * - * update_1folder is called from three places: with info != NULL when - * the folder is created (or get_folder_info), with info == NULL when - * a folder changed event is emitted. - * - * So if info is NULL, camel_folder_unread_message_count is correct, - * and if it's not NULL and its unread_message_count isn't -1, then - * it's correct. */ - -static void -update_1folder (MailFolderCache *cache, - struct _folder_info *mfi, - gint new, - const gchar *msg_uid, - const gchar *msg_sender, - const gchar *msg_subject, - CamelFolderInfo *info) -{ - struct _folder_update *up; - CamelFolder *folder; - gint unread = -1; - gint deleted; - - folder = mfi->folder; - if (folder) { - gboolean folder_is_sent; - gboolean folder_is_drafts; - gboolean folder_is_outbox; - gboolean folder_is_vtrash; - gboolean special_case; - - folder_is_sent = em_utils_folder_is_sent (folder); - folder_is_drafts = em_utils_folder_is_drafts (folder); - folder_is_outbox = em_utils_folder_is_outbox (folder); - folder_is_vtrash = CAMEL_IS_VTRASH_FOLDER (folder); - - special_case = - (cache->priv->count_trash && folder_is_vtrash) || - (cache->priv->count_sent && folder_is_sent) || - folder_is_drafts || folder_is_outbox; - - if (special_case) { - d(printf(" total count\n")); - unread = camel_folder_get_message_count (folder); - if (folder_is_drafts || folder_is_outbox) { - guint32 junked = 0; - - if ((deleted = camel_folder_get_deleted_message_count (folder)) > 0) - unread -= deleted; - - junked = camel_folder_summary_get_junk_count (folder->summary); - if (junked > 0) - unread -= junked; - } - } else { - d(printf(" unread count\n")); - if (info) - unread = info->unread; - else - unread = camel_folder_get_unread_message_count (folder); - } - } - - d(printf("folder updated: unread %d: '%s'\n", unread, mfi->full_name)); - - if (unread == -1) - return; - - up = g_malloc0 (sizeof (*up)); - up->full_name = g_strdup (mfi->full_name); - up->unread = unread; - up->new = new; - up->store = g_object_ref (mfi->store_info->store); - up->msg_uid = g_strdup (msg_uid); - up->msg_sender = g_strdup (msg_sender); - up->msg_subject = g_strdup (msg_subject); - g_queue_push_tail (&cache->priv->updates, up); - flush_updates (cache); -} - -static void -folder_changed_cb (CamelFolder *folder, - CamelFolderChangeInfo *changes, - MailFolderCache *cache) -{ - static GHashTable *last_newmail_per_folder = NULL; - time_t latest_received, new_latest_received; - CamelFolder *local_drafts; - CamelFolder *local_outbox; - CamelFolder *local_sent; - CamelSession *session; - CamelStore *parent_store; - CamelMessageInfo *info; - StoreInfo *si; - struct _folder_info *mfi; - const gchar *full_name; - gint new = 0; - gint i; - guint32 flags; - gchar *uid = NULL, *sender = NULL, *subject = NULL; - - full_name = camel_folder_get_full_name (folder); - parent_store = camel_folder_get_parent_store (folder); - session = camel_service_get_session (CAMEL_SERVICE (parent_store)); - - if (!last_newmail_per_folder) - last_newmail_per_folder = g_hash_table_new (g_direct_hash, g_direct_equal); - - /* it's fine to hash them by folder pointer here */ - latest_received = GPOINTER_TO_INT ( - g_hash_table_lookup (last_newmail_per_folder, folder)); - new_latest_received = latest_received; - - local_drafts = e_mail_session_get_local_folder ( - E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_DRAFTS); - local_outbox = e_mail_session_get_local_folder ( - E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_OUTBOX); - local_sent = e_mail_session_get_local_folder ( - E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_SENT); - - if (!CAMEL_IS_VEE_FOLDER (folder) - && folder != local_drafts - && folder != local_outbox - && folder != local_sent - && changes && (changes->uid_added->len > 0)) { - /* for each added message, check to see that it is - * brand new, not junk and not already deleted */ - for (i = 0; i < changes->uid_added->len; i++) { - info = camel_folder_get_message_info ( - folder, changes->uid_added->pdata[i]); - if (info) { - flags = camel_message_info_flags (info); - if (((flags & CAMEL_MESSAGE_SEEN) == 0) && - ((flags & CAMEL_MESSAGE_JUNK) == 0) && - ((flags & CAMEL_MESSAGE_DELETED) == 0) && - (camel_message_info_date_received (info) > latest_received)) { - if (camel_message_info_date_received (info) > new_latest_received) - new_latest_received = camel_message_info_date_received (info); - new++; - if (new == 1) { - uid = g_strdup (camel_message_info_uid (info)); - sender = g_strdup (camel_message_info_from (info)); - subject = g_strdup (camel_message_info_subject (info)); - } else { - g_free (uid); - g_free (sender); - g_free (subject); - - uid = NULL; - sender = NULL; - subject = NULL; - } - } - camel_folder_free_message_info (folder, info); - } - } - } - - if (new > 0) - g_hash_table_insert ( - last_newmail_per_folder, folder, - GINT_TO_POINTER (new_latest_received)); - - g_mutex_lock (cache->priv->stores_mutex); - if (cache->priv->stores != NULL - && (si = g_hash_table_lookup (cache->priv->stores, parent_store)) != NULL - && (mfi = g_hash_table_lookup (si->folders, full_name)) != NULL - && mfi->folder == folder) { - update_1folder (cache, mfi, new, uid, sender, subject, NULL); - } - g_mutex_unlock (cache->priv->stores_mutex); - - g_free (uid); - g_free (sender); - g_free (subject); -} - -static void -unset_folder_info (MailFolderCache *cache, - struct _folder_info *mfi, - gint delete, - gint unsub) -{ - struct _folder_update *up; - - d(printf("unset folderinfo '%s'\n", mfi->uri)); - - if (mfi->folder) { - CamelFolder *folder = mfi->folder; - - g_signal_handlers_disconnect_by_func ( - folder, folder_changed_cb, cache); - - g_object_remove_weak_pointer ( - G_OBJECT (mfi->folder), &mfi->folder); - } - - if ((mfi->flags & CAMEL_FOLDER_NOSELECT) == 0) { - up = g_malloc0 (sizeof (*up)); - - up->remove = TRUE; - up->delete = delete; - up->unsub = unsub; - up->store = g_object_ref (mfi->store_info->store); - up->full_name = g_strdup (mfi->full_name); - - g_queue_push_tail (&cache->priv->updates, up); - flush_updates (cache); - } -} - -static void -setup_folder (MailFolderCache *cache, - CamelFolderInfo *fi, - StoreInfo *si) -{ - struct _folder_info *mfi; - struct _folder_update *up; - - mfi = g_hash_table_lookup (si->folders, fi->full_name); - if (mfi) { - update_1folder (cache, mfi, 0, NULL, NULL, NULL, fi); - } else { - mfi = g_malloc0 (sizeof (*mfi)); - mfi->full_name = g_strdup (fi->full_name); - mfi->store_info = si; - mfi->flags = fi->flags; - mfi->has_children = fi->child != NULL; - - g_hash_table_insert (si->folders, mfi->full_name, mfi); - - up = g_malloc0 (sizeof (*up)); - up->full_name = g_strdup (mfi->full_name); - up->unread = fi->unread; - up->store = g_object_ref (si->store); - - if ((fi->flags & CAMEL_FOLDER_NOSELECT) == 0) - up->add = TRUE; - - g_queue_push_tail (&cache->priv->updates, up); - flush_updates (cache); - } -} - -static void -create_folders (MailFolderCache *cache, - CamelFolderInfo *fi, - StoreInfo *si) -{ - while (fi) { - setup_folder (cache, fi, si); - - if (fi->child) - create_folders (cache, fi->child, si); - - fi = fi->next; - } -} - -static void -store_folder_subscribed_cb (CamelStore *store, - CamelFolderInfo *info, - MailFolderCache *cache) -{ - StoreInfo *si; - - g_mutex_lock (cache->priv->stores_mutex); - si = g_hash_table_lookup (cache->priv->stores, store); - if (si) - setup_folder (cache, info, si); - g_mutex_unlock (cache->priv->stores_mutex); -} - -static void -store_folder_created_cb (CamelStore *store, - CamelFolderInfo *info, - MailFolderCache *cache) -{ - /* We only want created events to do more work - * if we dont support subscriptions. */ - if (!CAMEL_IS_SUBSCRIBABLE (store)) - store_folder_subscribed_cb (store, info, cache); -} - -static void -store_folder_opened_cb (CamelStore *store, - CamelFolder *folder, - MailFolderCache *cache) -{ - mail_folder_cache_note_folder (cache, folder); -} - -static void -store_folder_unsubscribed_cb (CamelStore *store, - CamelFolderInfo *info, - MailFolderCache *cache) -{ - StoreInfo *si; - struct _folder_info *mfi; - - g_mutex_lock (cache->priv->stores_mutex); - si = g_hash_table_lookup (cache->priv->stores, store); - if (si) { - mfi = g_hash_table_lookup (si->folders, info->full_name); - if (mfi) { - unset_folder_info (cache, mfi, TRUE, TRUE); - g_hash_table_remove (si->folders, mfi->full_name); - } - } - g_mutex_unlock (cache->priv->stores_mutex); -} - -static void -store_folder_deleted_cb (CamelStore *store, - CamelFolderInfo *info, - MailFolderCache *cache) -{ - /* We only want deleted events to do more work - * if we dont support subscriptions. */ - if (!CAMEL_IS_SUBSCRIBABLE (store)) - store_folder_unsubscribed_cb (store, info, cache); -} - -static void -rename_folders (MailFolderCache *cache, - StoreInfo *si, - const gchar *oldbase, - const gchar *newbase, - CamelFolderInfo *fi) -{ - gchar *old, *olduri, *oldfile, *newuri, *newfile; - struct _folder_info *mfi; - struct _folder_update *up; - const gchar *config_dir; - - up = g_malloc0 (sizeof (*up)); - - d(printf("oldbase '%s' newbase '%s' new '%s'\n", oldbase, newbase, fi->full_name)); - - /* Form what was the old name, and try and look it up */ - old = g_strdup_printf("%s%s", oldbase, fi->full_name + strlen(newbase)); - mfi = g_hash_table_lookup (si->folders, old); - if (mfi) { - up->oldfull = mfi->full_name; - - /* Be careful not to invoke the destroy function. */ - g_hash_table_steal (si->folders, mfi->full_name); - - /* Its a rename op */ - mfi->full_name = g_strdup (fi->full_name); - mfi->flags = fi->flags; - mfi->has_children = fi->child != NULL; - - g_hash_table_insert (si->folders, mfi->full_name, mfi); - } else { - /* Its a new op */ - mfi = g_malloc0 (sizeof (*mfi)); - mfi->full_name = g_strdup (fi->full_name); - mfi->store_info = si; - mfi->flags = fi->flags; - mfi->has_children = fi->child != NULL; - - g_hash_table_insert (si->folders, mfi->full_name, mfi); - } - - up->full_name = g_strdup (mfi->full_name); - up->unread = fi->unread==-1 ? 0 : fi->unread; - up->store = g_object_ref (si->store); - - if ((fi->flags & CAMEL_FOLDER_NOSELECT) == 0) - up->add = TRUE; - - g_queue_push_tail (&cache->priv->updates, up); - flush_updates (cache); -#if 0 - if (fi->sibling) - rename_folders (cache, si, oldbase, newbase, fi->sibling, folders); - if (fi->child) - rename_folders (cache, si, oldbase, newbase, fi->child, folders); -#endif - - /* rename the meta-data we maintain ourselves */ - config_dir = mail_session_get_config_dir (); - olduri = e_mail_folder_uri_build (si->store, old); - e_filename_make_safe (olduri); - newuri = e_mail_folder_uri_build (si->store, fi->full_name); - e_filename_make_safe (newuri); - oldfile = g_strdup_printf("%s/custom_view-%s.xml", config_dir, olduri); - newfile = g_strdup_printf("%s/custom_view-%s.xml", config_dir, newuri); - g_rename (oldfile, newfile); - g_free (oldfile); - g_free (newfile); - oldfile = g_strdup_printf("%s/current_view-%s.xml", config_dir, olduri); - newfile = g_strdup_printf("%s/current_view-%s.xml", config_dir, newuri); - g_rename (oldfile, newfile); - g_free (oldfile); - g_free (newfile); - g_free (olduri); - g_free (newuri); - - g_free (old); -} - -static void -get_folders (CamelFolderInfo *fi, - GPtrArray *folders) -{ - while (fi) { - g_ptr_array_add (folders, fi); - - if (fi->child) - get_folders (fi->child, folders); - - fi = fi->next; - } -} - -static gint -folder_cmp (gconstpointer ap, - gconstpointer bp) -{ - const CamelFolderInfo *a = ((CamelFolderInfo **) ap)[0]; - const CamelFolderInfo *b = ((CamelFolderInfo **) bp)[0]; - - return strcmp (a->full_name, b->full_name); -} - -static void -store_folder_renamed_cb (CamelStore *store, - const gchar *old_name, - CamelFolderInfo *info, - MailFolderCache *cache) -{ - StoreInfo *si; - - g_mutex_lock (cache->priv->stores_mutex); - si = g_hash_table_lookup (cache->priv->stores, store); - if (si) { - GPtrArray *folders = g_ptr_array_new (); - CamelFolderInfo *top; - gint i; - - /* Ok, so for some reason the folderinfo we have comes in all messed up from - * imap, should find out why ... this makes it workable */ - get_folders (info, folders); - qsort (folders->pdata, folders->len, sizeof (folders->pdata[0]), folder_cmp); - - top = folders->pdata[0]; - for (i = 0; i < folders->len; i++) { - rename_folders (cache, si, old_name, top->full_name, folders->pdata[i]); - } - - g_ptr_array_free (folders, TRUE); - - } - g_mutex_unlock (cache->priv->stores_mutex); -} - -static void -unset_folder_info_hash (gchar *path, - struct _folder_info *mfi, - gpointer data) -{ - MailFolderCache *cache = (MailFolderCache *) data; - unset_folder_info (cache, mfi, FALSE, FALSE); -} - -static void -mail_folder_cache_first_update (MailFolderCache *cache, - StoreInfo *info) -{ - EMailSession *session; - const gchar *uid; - - session = mail_folder_cache_get_session (cache); - uid = camel_service_get_uid (CAMEL_SERVICE (info->store)); - - if (info->vjunk != NULL) - mail_folder_cache_note_folder (cache, info->vjunk); - - if (info->vtrash != NULL) - mail_folder_cache_note_folder (cache, info->vtrash); - - /* Some extra work for the "On This Computer" store. */ - if (g_strcmp0 (uid, E_MAIL_SESSION_LOCAL_UID) == 0) { - CamelFolder *folder; - gint ii; - - for (ii = 0; ii < E_MAIL_NUM_LOCAL_FOLDERS; ii++) { - folder = e_mail_session_get_local_folder (session, ii); - mail_folder_cache_note_folder (cache, folder); - } - } -} - -static void -update_folders (CamelStore *store, - GAsyncResult *result, - struct _update_data *ud) -{ - CamelFolderInfo *fi; - StoreInfo *si; - GError *error = NULL; - - fi = camel_store_get_folder_info_finish (store, result, &error); - - if (error != NULL) { - g_warning ("%s", error->message); - g_error_free (error); - } - - g_mutex_lock (ud->cache->priv->stores_mutex); - si = g_hash_table_lookup (ud->cache->priv->stores, store); - if (si && !g_cancellable_is_cancelled (ud->cancellable)) { - /* The 'si' is still there, so we can remove ourselves from - * its list. Or else its not, and we're on our own and free - * anyway. */ - g_queue_remove (&si->folderinfo_updates, ud); - - if (fi != NULL) - create_folders (ud->cache, fi, si); - } - g_mutex_unlock (ud->cache->priv->stores_mutex); - - /* Do some extra work for the first update. */ - if (si != NULL && si->first_update) { - mail_folder_cache_first_update (ud->cache, si); - si->first_update = FALSE; - } - - if (fi != NULL) { - gboolean free_fi = TRUE; - - if (ud->done != NULL) - free_fi = ud->done (ud->cache, store, fi, ud->data); - if (free_fi) - camel_store_free_folder_info (store, fi); - } - - if (ud->cancellable != NULL) - g_object_unref (ud->cancellable); - - g_free (ud); -} - -struct _ping_store_msg { - MailMsg base; - CamelStore *store; -}; - -static gchar * -ping_store_desc (struct _ping_store_msg *m) -{ - gchar *service_name; - gchar *msg; - - service_name = camel_service_get_name (CAMEL_SERVICE (m->store), TRUE); - msg = g_strdup_printf (_("Pinging %s"), service_name); - g_free (service_name); - - return msg; -} - -static void -ping_store_exec (struct _ping_store_msg *m, - GCancellable *cancellable, - GError **error) -{ - CamelServiceConnectionStatus status; - CamelService *service; - gboolean online = FALSE; - - service = CAMEL_SERVICE (m->store); - status = camel_service_get_connection_status (service); - - if (status == CAMEL_SERVICE_CONNECTED) { - if (CAMEL_IS_DISCO_STORE (m->store) && - camel_disco_store_status ( - CAMEL_DISCO_STORE (m->store)) !=CAMEL_DISCO_STORE_OFFLINE) - online = TRUE; - else if (CAMEL_IS_OFFLINE_STORE (m->store) && - camel_offline_store_get_online ( - CAMEL_OFFLINE_STORE (m->store))) - online = TRUE; - } - if (online) - camel_store_noop_sync (m->store, cancellable, error); -} - -static void -ping_store_free (struct _ping_store_msg *m) -{ - g_object_unref (m->store); -} - -static MailMsgInfo ping_store_info = { - sizeof (struct _ping_store_msg), - (MailMsgDescFunc) ping_store_desc, - (MailMsgExecFunc) ping_store_exec, - (MailMsgDoneFunc) NULL, - (MailMsgFreeFunc) ping_store_free -}; - -static void -ping_store (CamelStore *store) -{ - CamelServiceConnectionStatus status; - CamelService *service; - struct _ping_store_msg *m; - - service = CAMEL_SERVICE (store); - status = camel_service_get_connection_status (service); - - if (status != CAMEL_SERVICE_CONNECTED) - return; - - m = mail_msg_new (&ping_store_info); - m->store = g_object_ref (store); - - mail_msg_slow_ordered_push (m); -} - -static gboolean -ping_cb (MailFolderCache *cache) -{ - g_mutex_lock (cache->priv->stores_mutex); - - g_hash_table_foreach (cache->priv->stores, (GHFunc) ping_store, NULL); - - g_mutex_unlock (cache->priv->stores_mutex); - - return TRUE; -} - -static gboolean -store_has_folder_hierarchy (CamelStore *store) -{ - CamelProvider *provider; - - g_return_val_if_fail (store != NULL, FALSE); - - provider = camel_service_get_provider (CAMEL_SERVICE (store)); - g_return_val_if_fail (provider != NULL, FALSE); - - return (provider->flags & (CAMEL_PROVIDER_IS_STORAGE | CAMEL_PROVIDER_IS_EXTERNAL)) != 0; -} - -static void -store_go_online_cb (CamelStore *store, - GAsyncResult *result, - struct _update_data *ud) -{ - /* FIXME Not checking result for error. */ - - g_mutex_lock (ud->cache->priv->stores_mutex); - - if (g_hash_table_lookup (ud->cache->priv->stores, store) != NULL && - !g_cancellable_is_cancelled (ud->cancellable)) { - /* We're already in the store update list. */ - if (store_has_folder_hierarchy (store)) - camel_store_get_folder_info ( - store, NULL, - CAMEL_STORE_FOLDER_INFO_FAST | - CAMEL_STORE_FOLDER_INFO_RECURSIVE | - CAMEL_STORE_FOLDER_INFO_SUBSCRIBED, - G_PRIORITY_DEFAULT, ud->cancellable, - (GAsyncReadyCallback) update_folders, ud); - } else { - /* The store vanished, that means we were probably cancelled, - * or at any rate, need to clean ourselves up. */ - if (ud->cancellable != NULL) - g_object_unref (ud->cancellable); - g_free (ud); - } - - g_mutex_unlock (ud->cache->priv->stores_mutex); -} - -static GList * -find_folder_uri (GQueue *queue, - CamelSession *session, - const gchar *folder_uri) -{ - GList *head, *link; - - head = g_queue_peek_head_link (queue); - - for (link = head; link != NULL; link = g_list_next (link)) - if (e_mail_folder_uri_equal (session, link->data, folder_uri)) - break; - - return link; -} - -struct _find_info { - const gchar *folder_uri; - struct _folder_info *fi; -}; - -static void -storeinfo_find_folder_info (CamelStore *store, - StoreInfo *si, - struct _find_info *fi) -{ - gchar *folder_name; - gboolean success; - - if (fi->fi != NULL) - return; - - success = e_mail_folder_uri_parse ( - camel_service_get_session (CAMEL_SERVICE (store)), - fi->folder_uri, NULL, &folder_name, NULL); - - if (success) { - fi->fi = g_hash_table_lookup (si->folders, folder_name); - g_free (folder_name); - } -} - -static void -mail_folder_cache_service_removed (EMailAccountStore *account_store, - CamelService *service, - MailFolderCache *cache) -{ - StoreInfo *si; - - if (cache->priv->stores == NULL) - return; - - g_mutex_lock (cache->priv->stores_mutex); - - si = g_hash_table_lookup (cache->priv->stores, service); - if (si != NULL) { - g_hash_table_remove (cache->priv->stores, service); - - g_signal_handlers_disconnect_matched ( - service, G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, cache); - - g_hash_table_foreach ( - si->folders, (GHFunc) - unset_folder_info_hash, cache); - - store_info_free (si); - } - - g_mutex_unlock (cache->priv->stores_mutex); -} - -static void -mail_folder_cache_service_enabled (EMailAccountStore *account_store, - CamelService *service, - MailFolderCache *cache) -{ - mail_folder_cache_note_store ( - cache, CAMEL_STORE (service), NULL, NULL, NULL); -} - -static void -mail_folder_cache_service_disabled (EMailAccountStore *account_store, - CamelService *service, - MailFolderCache *cache) -{ - /* To the folder cache, disabling a service is the same as - * removing it. We keep a separate callback function only - * to use as a breakpoint target in a debugger. */ - mail_folder_cache_service_removed (account_store, service, cache); -} - -static void -mail_folder_cache_set_session (MailFolderCache *cache, - EMailSession *session) -{ - g_return_if_fail (E_IS_MAIL_SESSION (session)); - g_return_if_fail (cache->priv->session == NULL); - - cache->priv->session = session; - - g_object_add_weak_pointer ( - G_OBJECT (cache->priv->session), - &cache->priv->session); -} - -static void -mail_folder_cache_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_SESSION: - mail_folder_cache_set_session ( - MAIL_FOLDER_CACHE (object), - g_value_get_object (value)); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -mail_folder_cache_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_SESSION: - g_value_set_object ( - value, - mail_folder_cache_get_session ( - MAIL_FOLDER_CACHE (object))); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -mail_folder_cache_dispose (GObject *object) -{ - MailFolderCachePrivate *priv; - - priv = MAIL_FOLDER_CACHE_GET_PRIVATE (object); - - if (priv->session != NULL) { - g_object_remove_weak_pointer ( - G_OBJECT (priv->session), &priv->session); - priv->session = NULL; - } - - if (priv->account_store != NULL) { - g_signal_handlers_disconnect_matched ( - priv->account_store, G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, object); - g_object_unref (priv->account_store); - priv->account_store = NULL; - } - - /* Chain up to parent's dispose() method. */ - G_OBJECT_CLASS (mail_folder_cache_parent_class)->dispose (object); -} - -static void -mail_folder_cache_finalize (GObject *object) -{ - MailFolderCachePrivate *priv; - - priv = MAIL_FOLDER_CACHE_GET_PRIVATE (object); - - g_hash_table_destroy (priv->stores); - g_mutex_free (priv->stores_mutex); - - if (priv->ping_id > 0) { - g_source_remove (priv->ping_id); - priv->ping_id = 0; - } - - if (priv->update_id > 0) { - g_source_remove (priv->update_id); - priv->update_id = 0; - } - - while (!g_queue_is_empty (&priv->local_folder_uris)) - g_free (g_queue_pop_head (&priv->local_folder_uris)); - - while (!g_queue_is_empty (&priv->remote_folder_uris)) - g_free (g_queue_pop_head (&priv->remote_folder_uris)); - - /* Chain up to parent's finalize() method. */ - G_OBJECT_CLASS (mail_folder_cache_parent_class)->finalize (object); -} - -static void -mail_folder_cache_constructed (GObject *object) -{ - MailFolderCache *cache; - EMailSession *session; - EMailAccountStore *account_store; - - cache = MAIL_FOLDER_CACHE (object); - - /* Chain up to parent's constructed() method. */ - G_OBJECT_CLASS (mail_folder_cache_parent_class)->constructed (object); - - session = mail_folder_cache_get_session (cache); - account_store = e_mail_session_get_account_store (session); - - cache->priv->account_store = g_object_ref (account_store); - - /* No need to connect to "service-added" emissions since it's - * always immediately followed by either "service-enabled" or - * "service-disabled". */ - - g_signal_connect ( - account_store, "service-removed", - G_CALLBACK (mail_folder_cache_service_removed), cache); - - g_signal_connect ( - account_store, "service-enabled", - G_CALLBACK (mail_folder_cache_service_enabled), cache); - - g_signal_connect ( - account_store, "service-disabled", - G_CALLBACK (mail_folder_cache_service_disabled), cache); - -} - -static void -mail_folder_cache_folder_available (MailFolderCache *cache, - CamelStore *store, - const gchar *folder_name) -{ - CamelService *service; - CamelSession *session; - CamelProvider *provider; - GQueue *queue; - gchar *folder_uri; - - /* Disregard virtual stores. */ - if (CAMEL_IS_VEE_STORE (store)) - return; - - /* Disregard virtual Junk folders. */ - if (store->flags & CAMEL_STORE_VJUNK) - if (g_strcmp0 (folder_name, CAMEL_VJUNK_NAME) == 0) - return; - - /* Disregard virtual Trash folders. */ - if (store->flags & CAMEL_STORE_VTRASH) - if (g_strcmp0 (folder_name, CAMEL_VTRASH_NAME) == 0) - return; - - service = CAMEL_SERVICE (store); - session = camel_service_get_session (service); - provider = camel_service_get_provider (service); - - /* Reuse the stores mutex just because it's handy. */ - g_mutex_lock (cache->priv->stores_mutex); - - folder_uri = e_mail_folder_uri_build (store, folder_name); - - if (provider->flags & CAMEL_PROVIDER_IS_REMOTE) - queue = &cache->priv->remote_folder_uris; - else - queue = &cache->priv->local_folder_uris; - - if (find_folder_uri (queue, session, folder_uri) == NULL) - g_queue_push_tail (queue, folder_uri); - else - g_free (folder_uri); - - g_mutex_unlock (cache->priv->stores_mutex); -} - -static void -mail_folder_cache_folder_unavailable (MailFolderCache *cache, - CamelStore *store, - const gchar *folder_name) -{ - CamelService *service; - CamelSession *session; - CamelProvider *provider; - GQueue *queue; - GList *link; - gchar *folder_uri; - - /* Disregard virtual stores. */ - if (CAMEL_IS_VEE_STORE (store)) - return; - - /* Disregard virtual Junk folders. */ - if (store->flags & CAMEL_STORE_VJUNK) - if (g_strcmp0 (folder_name, CAMEL_VJUNK_NAME) == 0) - return; - - /* Disregard virtual Trash folders. */ - if (store->flags & CAMEL_STORE_VTRASH) - if (g_strcmp0 (folder_name, CAMEL_VTRASH_NAME) == 0) - return; - - service = CAMEL_SERVICE (store); - session = camel_service_get_session (service); - provider = camel_service_get_provider (service); - - /* Reuse the stores mutex just because it's handy. */ - g_mutex_lock (cache->priv->stores_mutex); - - folder_uri = e_mail_folder_uri_build (store, folder_name); - - if (provider->flags & CAMEL_PROVIDER_IS_REMOTE) - queue = &cache->priv->remote_folder_uris; - else - queue = &cache->priv->local_folder_uris; - - link = find_folder_uri (queue, session, folder_uri); - if (link != NULL) { - g_free (link->data); - g_queue_delete_link (queue, link); - } - - g_free (folder_uri); - - g_mutex_unlock (cache->priv->stores_mutex); -} - -static void -mail_folder_cache_folder_deleted (MailFolderCache *cache, - CamelStore *store, - const gchar *folder_name) -{ - CamelService *service; - CamelSession *session; - GQueue *queue; - GList *link; - gchar *folder_uri; - - /* Disregard virtual stores. */ - if (CAMEL_IS_VEE_STORE (store)) - return; - - /* Disregard virtual Junk folders. */ - if (store->flags & CAMEL_STORE_VJUNK) - if (g_strcmp0 (folder_name, CAMEL_VJUNK_NAME) == 0) - return; - - /* Disregard virtual Trash folders. */ - if (store->flags & CAMEL_STORE_VTRASH) - if (g_strcmp0 (folder_name, CAMEL_VTRASH_NAME) == 0) - return; - - service = CAMEL_SERVICE (store); - session = camel_service_get_session (service); - - /* Reuse the stores mutex just because it's handy. */ - g_mutex_lock (cache->priv->stores_mutex); - - folder_uri = e_mail_folder_uri_build (store, folder_name); - - queue = &cache->priv->local_folder_uris; - link = find_folder_uri (queue, session, folder_uri); - if (link != NULL) { - g_free (link->data); - g_queue_delete_link (queue, link); - } - - queue = &cache->priv->remote_folder_uris; - link = find_folder_uri (queue, session, folder_uri); - if (link != NULL) { - g_free (link->data); - g_queue_delete_link (queue, link); - } - - g_free (folder_uri); - - g_mutex_unlock (cache->priv->stores_mutex); -} - -static void -mail_folder_cache_class_init (MailFolderCacheClass *class) -{ - GObjectClass *object_class; - - g_type_class_add_private (class, sizeof (MailFolderCachePrivate)); - - object_class = G_OBJECT_CLASS (class); - object_class->set_property = mail_folder_cache_set_property; - object_class->get_property = mail_folder_cache_get_property; - object_class->dispose = mail_folder_cache_dispose; - object_class->finalize = mail_folder_cache_finalize; - object_class->constructed = mail_folder_cache_constructed; - - class->folder_available = mail_folder_cache_folder_available; - class->folder_unavailable = mail_folder_cache_folder_unavailable; - class->folder_deleted = mail_folder_cache_folder_deleted; - - g_object_class_install_property ( - object_class, - PROP_SESSION, - g_param_spec_object ( - "session", - "Session", - "Mail session", - E_TYPE_MAIL_SESSION, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); - - /** - * MailFolderCache::folder-available - * @store: the #CamelStore containing the folder - * @folder_name: the name of the folder - * - * Emitted when a folder becomes available - **/ - signals[FOLDER_AVAILABLE] = g_signal_new ( - "folder-available", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (MailFolderCacheClass, folder_available), - NULL, NULL, /* accumulator */ - e_marshal_VOID__OBJECT_STRING, - G_TYPE_NONE, 2, - CAMEL_TYPE_STORE, - G_TYPE_STRING); - - /** - * MailFolderCache::folder-unavailable - * @store: the #CamelStore containing the folder - * @folder_name: the name of the folder - * - * Emitted when a folder becomes unavailable. This represents a - * transient condition. See MailFolderCache::folder-deleted to be - * notified when a folder is permanently removed. - **/ - signals[FOLDER_UNAVAILABLE] = g_signal_new ( - "folder-unavailable", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (MailFolderCacheClass, folder_unavailable), - NULL, NULL, /* accumulator */ - e_marshal_VOID__OBJECT_STRING, - G_TYPE_NONE, 2, - CAMEL_TYPE_STORE, - G_TYPE_STRING); - - /** - * MailFolderCache::folder-deleted - * @store: the #CamelStore containing the folder - * @folder_name: the name of the folder - * - * Emitted when a folder is deleted - **/ - signals[FOLDER_DELETED] = g_signal_new ( - "folder-deleted", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (MailFolderCacheClass, folder_deleted), - NULL, NULL, /* accumulator */ - e_marshal_VOID__OBJECT_STRING, - G_TYPE_NONE, 2, - CAMEL_TYPE_STORE, - G_TYPE_STRING); - - /** - * MailFolderCache::folder-renamed - * @store: the #CamelStore containing the folder - * @old_folder_name: the old name of the folder - * @new_folder_name: the new name of the folder - * - * Emitted when a folder is renamed - **/ - signals[FOLDER_RENAMED] = g_signal_new ( - "folder-renamed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (MailFolderCacheClass, folder_renamed), - NULL, NULL, /* accumulator */ - e_marshal_VOID__OBJECT_STRING_STRING, - G_TYPE_NONE, 3, - CAMEL_TYPE_STORE, - G_TYPE_STRING, - G_TYPE_STRING); - - /** - * MailFolderCache::folder-unread-updated - * @store: the #CamelStore containing the folder - * @folder_name: the name of the folder - * @unread: the number of unread mails in the folder - * - * Emitted when a we receive an update to the unread count for a folder - **/ - signals[FOLDER_UNREAD_UPDATED] = g_signal_new ( - "folder-unread-updated", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (MailFolderCacheClass, folder_unread_updated), - NULL, NULL, /* accumulator */ - e_marshal_VOID__OBJECT_STRING_INT, - G_TYPE_NONE, 3, - CAMEL_TYPE_STORE, - G_TYPE_STRING, - G_TYPE_INT); - - /** - * MailFolderCache::folder-changed - * @store: the #CamelStore containing the folder - * @folder_name: the name of the folder - * @new_messages: the number of new messages for the folder - * @msg_uid: uid of the new message, or NULL - * @msg_sender: sender of the new message, or NULL - * @msg_subject: subject of the new message, or NULL - * - * Emitted when a folder has changed. If @new_messages is not - * exactly 1, @msg_uid, @msg_sender, and @msg_subject will be NULL. - **/ - signals[FOLDER_CHANGED] = g_signal_new ( - "folder-changed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (MailFolderCacheClass, folder_changed), - NULL, NULL, /* accumulator */ - e_marshal_VOID__OBJECT_STRING_INT_STRING_STRING_STRING, - G_TYPE_NONE, 6, - CAMEL_TYPE_STORE, - G_TYPE_STRING, - G_TYPE_INT, - G_TYPE_STRING, - G_TYPE_STRING, - G_TYPE_STRING); -} - -static void -mail_folder_cache_init (MailFolderCache *cache) -{ - const gchar *buf; - guint timeout; - - cache->priv = MAIL_FOLDER_CACHE_GET_PRIVATE (cache); - - /* initialize values */ - cache->priv->stores = g_hash_table_new (NULL, NULL); - cache->priv->stores_mutex = g_mutex_new (); - - g_queue_init (&cache->priv->updates); - cache->priv->count_sent = getenv("EVOLUTION_COUNT_SENT") != NULL; - cache->priv->count_trash = getenv("EVOLUTION_COUNT_TRASH") != NULL; - - buf = getenv ("EVOLUTION_PING_TIMEOUT"); - timeout = buf ? strtoul (buf, NULL, 10) : 600; - cache->priv->ping_id = g_timeout_add_seconds ( - timeout, (GSourceFunc) ping_cb, cache); - - g_queue_init (&cache->priv->local_folder_uris); - g_queue_init (&cache->priv->remote_folder_uris); -} - -MailFolderCache * -mail_folder_cache_new (EMailSession *session) -{ - g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); - - return g_object_new ( - MAIL_TYPE_FOLDER_CACHE, - "session", session, NULL); -} - -EMailSession * -mail_folder_cache_get_session (MailFolderCache *cache) -{ - g_return_val_if_fail (MAIL_IS_FOLDER_CACHE (cache), NULL); - - return E_MAIL_SESSION (cache->priv->session); -} - -/** - * mail_folder_cache_note_store: - * - * Add a store whose folders should appear in the shell The folders are scanned - * from the store, and/or added at runtime via the folder_created event. The - * @done function returns if we can free folder info. - */ -void -mail_folder_cache_note_store (MailFolderCache *cache, - CamelStore *store, - GCancellable *cancellable, - NoteDoneFunc done, - gpointer data) -{ - CamelSession *session; - StoreInfo *si; - struct _update_data *ud; - gint hook = 0; - - g_return_if_fail (MAIL_IS_FOLDER_CACHE (cache)); - g_return_if_fail (CAMEL_IS_STORE (store)); - - session = camel_service_get_session (CAMEL_SERVICE (store)); - - g_mutex_lock (cache->priv->stores_mutex); - - si = g_hash_table_lookup (cache->priv->stores, store); - if (si == NULL) { - si = store_info_new (store); - g_hash_table_insert (cache->priv->stores, store, si); - hook = TRUE; - } - - ud = g_malloc0 (sizeof (*ud)); - ud->done = done; - ud->data = data; - ud->cache = cache; - - if (G_IS_CANCELLABLE (cancellable)) - ud->cancellable = g_object_ref (cancellable); - - /* We might get a race when setting up a store, such that it is - * still left in offline mode, after we've gone online. This - * catches and fixes it up when the shell opens us. */ - if (CAMEL_IS_DISCO_STORE (store)) { - if (camel_session_get_online (session) && - camel_disco_store_status (CAMEL_DISCO_STORE (store)) == - CAMEL_DISCO_STORE_OFFLINE) { - e_mail_store_go_online ( - store, G_PRIORITY_DEFAULT, cancellable, - (GAsyncReadyCallback) store_go_online_cb, ud); - } else { - goto normal_setup; - } - } else if (CAMEL_IS_OFFLINE_STORE (store)) { - if (camel_session_get_online (session) && - !camel_offline_store_get_online ( - CAMEL_OFFLINE_STORE (store))) { - e_mail_store_go_online ( - store, G_PRIORITY_DEFAULT, cancellable, - (GAsyncReadyCallback) store_go_online_cb, ud); - } else { - goto normal_setup; - } - } else { - normal_setup: - if (store_has_folder_hierarchy (store)) - camel_store_get_folder_info ( - store, NULL, - CAMEL_STORE_FOLDER_INFO_FAST | - CAMEL_STORE_FOLDER_INFO_RECURSIVE | - CAMEL_STORE_FOLDER_INFO_SUBSCRIBED, - G_PRIORITY_DEFAULT, cancellable, - (GAsyncReadyCallback) update_folders, ud); - } - - g_queue_push_tail (&si->folderinfo_updates, ud); - - g_mutex_unlock (cache->priv->stores_mutex); - - /* there is potential for race here, but it is safe as we check - * for the store anyway */ - if (hook) { - g_signal_connect ( - store, "folder-opened", - G_CALLBACK (store_folder_opened_cb), cache); - g_signal_connect ( - store, "folder-created", - G_CALLBACK (store_folder_created_cb), cache); - g_signal_connect ( - store, "folder-deleted", - G_CALLBACK (store_folder_deleted_cb), cache); - g_signal_connect ( - store, "folder-renamed", - G_CALLBACK (store_folder_renamed_cb), cache); - } - - if (hook && CAMEL_IS_SUBSCRIBABLE (store)) { - g_signal_connect ( - store, "folder-subscribed", - G_CALLBACK (store_folder_subscribed_cb), cache); - g_signal_connect ( - store, "folder-unsubscribed", - G_CALLBACK (store_folder_unsubscribed_cb), cache); - } -} - -/** - * mail_folder_cache_note_folder: - * - * When a folder has been opened, notify it for watching. The folder must have - * already been created on the store (which has already been noted) before the - * folder can be opened - */ -void -mail_folder_cache_note_folder (MailFolderCache *cache, - CamelFolder *folder) -{ - CamelStore *parent_store; - StoreInfo *si; - struct _folder_info *mfi; - const gchar *full_name; - - g_return_if_fail (MAIL_IS_FOLDER_CACHE (cache)); - g_return_if_fail (CAMEL_IS_FOLDER (folder)); - - full_name = camel_folder_get_full_name (folder); - parent_store = camel_folder_get_parent_store (folder); - - g_mutex_lock (cache->priv->stores_mutex); - if (cache->priv->stores == NULL - || (si = g_hash_table_lookup (cache->priv->stores, parent_store)) == NULL - || (mfi = g_hash_table_lookup (si->folders, full_name)) == NULL) { - w(g_warning("Noting folder before store initialised")); - g_mutex_unlock (cache->priv->stores_mutex); - return; - } - - /* dont do anything if we already have this */ - if (mfi->folder == folder) { - g_mutex_unlock (cache->priv->stores_mutex); - return; - } - - mfi->folder = folder; - - g_object_add_weak_pointer (G_OBJECT (folder), &mfi->folder); - - update_1folder (cache, mfi, 0, NULL, NULL, NULL, NULL); - - g_mutex_unlock (cache->priv->stores_mutex); - - g_signal_connect ( - folder, "changed", - G_CALLBACK (folder_changed_cb), cache); -} - -/** - * mail_folder_cache_get_folder_from_uri: - * - * Gets the #CamelFolder for the supplied @uri. - * - * Returns: %TRUE if the URI is available, folderp is set to a reffed - * folder if the folder has also already been opened - */ -gboolean -mail_folder_cache_get_folder_from_uri (MailFolderCache *cache, - const gchar *uri, - CamelFolder **folderp) -{ - struct _find_info fi = { uri, NULL }; - - if (cache->priv->stores == NULL) - return FALSE; - - g_mutex_lock (cache->priv->stores_mutex); - g_hash_table_foreach ( - cache->priv->stores, (GHFunc) - storeinfo_find_folder_info, &fi); - if (folderp) { - if (fi.fi && fi.fi->folder) - *folderp = g_object_ref (fi.fi->folder); - else - *folderp = NULL; - } - g_mutex_unlock (cache->priv->stores_mutex); - - return fi.fi != NULL; -} - -gboolean -mail_folder_cache_get_folder_info_flags (MailFolderCache *cache, - CamelFolder *folder, - CamelFolderInfoFlags *flags) -{ - struct _find_info fi = { NULL, NULL }; - gchar *folder_uri; - - if (cache->priv->stores == NULL) - return FALSE; - - folder_uri = e_mail_folder_uri_from_folder (folder); - fi.folder_uri = folder_uri; - - g_mutex_lock (cache->priv->stores_mutex); - g_hash_table_foreach ( - cache->priv->stores, (GHFunc) - storeinfo_find_folder_info, &fi); - if (flags) { - if (fi.fi) - *flags = fi.fi->flags; - else - *flags = 0; - } - g_mutex_unlock (cache->priv->stores_mutex); - - g_free (folder_uri); - - return fi.fi != NULL; -} - -/* Returns whether folder 'folder' has children based on folder_info->child property. - * If not found returns FALSE and sets 'found' to FALSE, if not NULL. */ -gboolean -mail_folder_cache_get_folder_has_children (MailFolderCache *cache, - CamelFolder *folder, - gboolean *found) -{ - struct _find_info fi = { NULL, NULL }; - gchar *folder_uri; - - g_return_val_if_fail (cache != NULL, FALSE); - g_return_val_if_fail (folder != NULL, FALSE); - - if (cache->priv->stores == NULL) - return FALSE; - - folder_uri = e_mail_folder_uri_from_folder (folder); - fi.folder_uri = folder_uri; - - g_mutex_lock (cache->priv->stores_mutex); - g_hash_table_foreach ( - cache->priv->stores, (GHFunc) - storeinfo_find_folder_info, &fi); - if (found) - *found = fi.fi != NULL; - g_mutex_unlock (cache->priv->stores_mutex); - - g_free (folder_uri); - - return fi.fi != NULL && fi.fi->has_children; -} - -void -mail_folder_cache_get_local_folder_uris (MailFolderCache *self, - GQueue *out_queue) -{ - GList *head, *link; - - g_return_if_fail (MAIL_IS_FOLDER_CACHE (self)); - g_return_if_fail (out_queue != NULL); - - /* Reuse the stores mutex just because it's handy. */ - g_mutex_lock (self->priv->stores_mutex); - - head = g_queue_peek_head_link (&self->priv->local_folder_uris); - - for (link = head; link != NULL; link = g_list_next (link)) - g_queue_push_tail (out_queue, g_strdup (link->data)); - - g_mutex_unlock (self->priv->stores_mutex); -} - -void -mail_folder_cache_get_remote_folder_uris (MailFolderCache *self, - GQueue *out_queue) -{ - GList *head, *link; - - g_return_if_fail (MAIL_IS_FOLDER_CACHE (self)); - g_return_if_fail (out_queue != NULL); - - /* Reuse the stores mutex just because it's handy. */ - g_mutex_lock (self->priv->stores_mutex); - - head = g_queue_peek_head_link (&self->priv->remote_folder_uris); - - for (link = head; link != NULL; link = g_list_next (link)) - g_queue_push_tail (out_queue, g_strdup (link->data)); - - g_mutex_unlock (self->priv->stores_mutex); -} diff --git a/mail/mail-folder-cache.h b/mail/mail-folder-cache.h deleted file mode 100644 index 8e9fa34fe5..0000000000 --- a/mail/mail-folder-cache.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see - * - * - * Authors: - * Peter Williams - * Michael Zucchi - * Jonathon Jongsma - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * Copyright (C) 2009 Intel Corporation - * - */ - -#ifndef MAIL_FOLDER_CACHE_H -#define MAIL_FOLDER_CACHE_H - -#include - -/* Standard GObject macros */ -#define MAIL_TYPE_FOLDER_CACHE \ - (mail_folder_cache_get_type ()) -#define MAIL_FOLDER_CACHE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST \ - ((obj), MAIL_TYPE_FOLDER_CACHE, MailFolderCache)) -#define MAIL_FOLDER_CACHE_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_CAST \ - ((cls), MAIL_TYPE_FOLDER_CACHE, MailFolderCacheClass)) -#define MAIL_IS_FOLDER_CACHE(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE \ - ((obj), MAIL_TYPE_FOLDER_CACHE)) -#define MAIL_IS_FOLDER_CACHE_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_TYPE \ - ((cls), MAIL_TYPE_FOLDER_CACHE)) -#define MAIL_FOLDER_CACHE_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS \ - ((obj), MAIL_TYPE_FOLDER_CACHE, MailFolderCacheClass)) - -G_BEGIN_DECLS - -/* Avoid a circular dependency. */ -struct _EMailSession; - -typedef struct _MailFolderCache MailFolderCache; -typedef struct _MailFolderCacheClass MailFolderCacheClass; -typedef struct _MailFolderCachePrivate MailFolderCachePrivate; - -/** - * NoteDoneFunc: - * - * The signature of a function to be registered as a callback for - * mail_folder_cache_note_store() - */ -typedef gboolean (*NoteDoneFunc) (MailFolderCache *cache, - CamelStore *store, - CamelFolderInfo *info, - gpointer data); - -/** - * MailFolderCache: - * - * Contains only private data that should be read and manipulated using the - * functions below. - */ -struct _MailFolderCache { - GObject parent; - MailFolderCachePrivate *priv; -}; - -struct _MailFolderCacheClass { - GObjectClass parent_class; - - /* Signals */ - void (*folder_available) (MailFolderCache *cache, - CamelStore *store, - const gchar *folder_name); - void (*folder_unavailable) (MailFolderCache *cache, - CamelStore *store, - const gchar *folder_name); - void (*folder_deleted) (MailFolderCache *cache, - CamelStore *store, - const gchar *folder_name); - void (*folder_renamed) (MailFolderCache *cache, - CamelStore *store, - const gchar *old_folder_name, - const gchar *new_folder_name); - void (*folder_unread_updated) - (MailFolderCache *cache, - CamelStore *store, - const gchar *folder_name, - gint unread); - void (*folder_changed) (MailFolderCache *cache, - CamelStore *store, - gint new_messages, - const gchar *msg_uid, - const gchar *msg_sender, - const gchar *msg_subject); -}; - -GType mail_folder_cache_get_type (void) G_GNUC_CONST; -MailFolderCache * - mail_folder_cache_new (struct _EMailSession *session); -struct _EMailSession * - mail_folder_cache_get_session (MailFolderCache *cache); -void mail_folder_cache_note_store (MailFolderCache *cache, - CamelStore *store, - GCancellable *cancellable, - NoteDoneFunc done, - gpointer data); -void mail_folder_cache_note_folder (MailFolderCache *cache, - CamelFolder *folder); -gboolean mail_folder_cache_get_folder_from_uri - (MailFolderCache *cache, - const gchar *uri, - CamelFolder **folderp); -gboolean mail_folder_cache_get_folder_info_flags - (MailFolderCache *cache, - CamelFolder *folder, - CamelFolderInfoFlags *flags); -gboolean mail_folder_cache_get_folder_has_children - (MailFolderCache *cache, - CamelFolder *folder, - gboolean *found); -void mail_folder_cache_get_local_folder_uris - (MailFolderCache *cache, - GQueue *out_queue); -void mail_folder_cache_get_remote_folder_uris - (MailFolderCache *cache, - GQueue *out_queue); - -G_END_DECLS - -#endif /* MAIL_FOLDER_CACHE_H */ diff --git a/mail/mail-mt.c b/mail/mail-mt.c deleted file mode 100644 index 526571f61f..0000000000 --- a/mail/mail-mt.c +++ /dev/null @@ -1,646 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include - -#include - -#include -#include - -#include "mail-mt.h" - -/*#define MALLOC_CHECK*/ -#define d(x) - -/* XXX This is a dirty hack on a dirty hack. We really need - * to rework or get rid of the functions that use this. */ -const gchar *shell_builtin_backend = "mail"; - -static guint mail_msg_seq; /* sequence number of each message */ - -/* Table of active messages. Must hold mail_msg_lock to access. */ -static GHashTable *mail_msg_active_table; -static GMutex *mail_msg_lock; -static GCond *mail_msg_cond; - -static void -mail_msg_cancelled (CamelOperation *operation, - gpointer user_data) -{ - mail_msg_cancel (GPOINTER_TO_UINT (user_data)); -} - -static gboolean -mail_msg_submit (EActivity *activity) -{ - EShell *shell; - EShellBackend *shell_backend; - - shell = e_shell_get_default (); - shell_backend = e_shell_get_backend_by_name ( - shell, shell_builtin_backend); - - e_shell_backend_add_activity (shell_backend, activity); - - return FALSE; -} - -gpointer -mail_msg_new (MailMsgInfo *info) -{ - MailMsg *msg; - GCancellable *cancellable; - - g_mutex_lock (mail_msg_lock); - - msg = g_slice_alloc0 (info->size); - msg->info = info; - msg->ref_count = 1; - msg->seq = mail_msg_seq++; - msg->activity = e_activity_new (); - - cancellable = camel_operation_new (); - - e_activity_set_percent (msg->activity, 0.0); - e_activity_set_cancellable (msg->activity, cancellable); - - g_signal_connect ( - cancellable, "cancelled", - G_CALLBACK (mail_msg_cancelled), - GINT_TO_POINTER (msg->seq)); - - g_object_unref (cancellable); - - g_hash_table_insert ( - mail_msg_active_table, GINT_TO_POINTER (msg->seq), msg); - - d(printf("New message %p\n", msg)); - - g_mutex_unlock (mail_msg_lock); - - return msg; -} - -#ifdef MALLOC_CHECK -#include - -static void -checkmem (gpointer p) -{ - if (p) { - gint status = mprobe (p); - - switch (status) { - case MCHECK_HEAD: - printf("Memory underrun at %p\n", p); - abort (); - case MCHECK_TAIL: - printf("Memory overrun at %p\n", p); - abort (); - case MCHECK_FREE: - printf("Double free %p\n", p); - abort (); - } - } -} -#endif - -static gboolean -mail_msg_free (MailMsg *mail_msg) -{ - /* This is an idle callback. */ - - if (mail_msg->activity != NULL) - g_object_unref (mail_msg->activity); - - if (mail_msg->error != NULL) - g_error_free (mail_msg->error); - - g_slice_free1 (mail_msg->info->size, mail_msg); - - return FALSE; -} - -gpointer -mail_msg_ref (gpointer msg) -{ - MailMsg *mail_msg = msg; - - g_return_val_if_fail (mail_msg != NULL, msg); - g_return_val_if_fail (mail_msg->ref_count > 0, msg); - - g_atomic_int_inc (&mail_msg->ref_count); - - return msg; -} - -void -mail_msg_unref (gpointer msg) -{ - MailMsg *mail_msg = msg; - - g_return_if_fail (mail_msg != NULL); - g_return_if_fail (mail_msg->ref_count > 0); - - if (g_atomic_int_dec_and_test (&mail_msg->ref_count)) { - -#ifdef MALLOC_CHECK - checkmem (mail_msg); - checkmem (mail_msg->cancel); - checkmem (mail_msg->priv); -#endif - d(printf("Free message %p\n", msg)); - - if (mail_msg->info->free) - mail_msg->info->free (mail_msg); - - g_mutex_lock (mail_msg_lock); - - g_hash_table_remove ( - mail_msg_active_table, - GINT_TO_POINTER (mail_msg->seq)); - g_cond_broadcast (mail_msg_cond); - - g_mutex_unlock (mail_msg_lock); - - /* Destroy the message from an idle callback - * so we know we're in the main loop thread. */ - g_idle_add ((GSourceFunc) mail_msg_free, mail_msg); - } -} - -void -mail_msg_check_error (gpointer msg) -{ - EShell *shell; - EShellView *shell_view; - EShellWindow *shell_window = NULL; - EShellContent *shell_content; - GtkApplication *application; - MailMsg *m = msg; - gchar *what; - GList *list, *iter; - -#ifdef MALLOC_CHECK - checkmem (m); - checkmem (m->cancel); - checkmem (m->priv); -#endif - - if (e_activity_handle_cancellation (m->activity, m->error)) - return; - - e_activity_set_state (m->activity, E_ACTIVITY_COMPLETED); - - if (m->error == NULL) - return; - - /* XXX Hmm, no explanation of why this is needed. It looks like - * a lame hack and will be removed at some point, if only to - * reintroduce whatever issue made this necessary so we can - * document it the source code this time. */ - if (g_error_matches (m->error, CAMEL_FOLDER_ERROR, CAMEL_FOLDER_ERROR_INVALID_UID)) - return; - - shell = e_shell_get_default (); - application = GTK_APPLICATION (shell); - list = gtk_application_get_windows (application); - - /* Find the most recently used EShellWindow. */ - for (iter = list; iter != NULL; iter = g_list_next (iter)) { - if (E_IS_SHELL_WINDOW (iter->data)) { - shell_window = E_SHELL_WINDOW (iter->data); - break; - } - } - - /* If we can't find an EShellWindow then... well, screw it. */ - if (shell_window == NULL) - return; - - shell_view = e_shell_window_get_shell_view ( - shell_window, shell_builtin_backend); - shell_content = e_shell_view_get_shell_content (shell_view); - - if (m->info->desc && (what = m->info->desc (m))) { - e_alert_submit ( - E_ALERT_SINK (shell_content), - "mail:async-error", what, - m->error->message, NULL); - g_free (what); - } else - e_alert_submit ( - E_ALERT_SINK (shell_content), - "mail:async-error-nodescribe", - m->error->message, NULL); -} - -void -mail_msg_cancel (guint msgid) -{ - MailMsg *msg; - GCancellable *cancellable = NULL; - - g_mutex_lock (mail_msg_lock); - - msg = g_hash_table_lookup ( - mail_msg_active_table, GINT_TO_POINTER (msgid)); - - /* Hold a reference to the GCancellable so it doesn't finalize - * itself on us between unlocking the mutex and cancelling. */ - if (msg != NULL) { - cancellable = e_activity_get_cancellable (msg->activity); - if (g_cancellable_is_cancelled (cancellable)) - cancellable = NULL; - else - g_object_ref (cancellable); - } - - g_mutex_unlock (mail_msg_lock); - - if (cancellable != NULL) { - g_cancellable_cancel (cancellable); - g_object_unref (cancellable); - } -} - -gboolean -mail_msg_active (void) -{ - gboolean active; - - g_mutex_lock (mail_msg_lock); - active = g_hash_table_size (mail_msg_active_table) > 0; - g_mutex_unlock (mail_msg_lock); - - return active; -} - -/* **************************************** */ - -static GHookList cancel_hook_list; - -GHook * -mail_cancel_hook_add (GHookFunc func, - gpointer data) -{ - GHook *hook; - - g_mutex_lock (mail_msg_lock); - - if (!cancel_hook_list.is_setup) - g_hook_list_init (&cancel_hook_list, sizeof (GHook)); - - hook = g_hook_alloc (&cancel_hook_list); - hook->func = func; - hook->data = data; - - g_hook_append (&cancel_hook_list, hook); - - g_mutex_unlock (mail_msg_lock); - - return hook; -} - -void -mail_cancel_hook_remove (GHook *hook) -{ - g_mutex_lock (mail_msg_lock); - - g_return_if_fail (cancel_hook_list.is_setup); - g_hook_destroy_link (&cancel_hook_list, hook); - - g_mutex_unlock (mail_msg_lock); -} - -void -mail_cancel_all (void) -{ - camel_operation_cancel_all (); - - g_mutex_lock (mail_msg_lock); - - if (cancel_hook_list.is_setup) - g_hook_list_invoke (&cancel_hook_list, FALSE); - - g_mutex_unlock (mail_msg_lock); -} - -static guint idle_source_id = 0; -G_LOCK_DEFINE_STATIC (idle_source_id); -static GAsyncQueue *main_loop_queue = NULL; -static GAsyncQueue *msg_reply_queue = NULL; -static GThread *main_thread = NULL; - -static gboolean -mail_msg_idle_cb (void) -{ - MailMsg *msg; - - g_return_val_if_fail (main_loop_queue != NULL, FALSE); - g_return_val_if_fail (msg_reply_queue != NULL, FALSE); - - G_LOCK (idle_source_id); - idle_source_id = 0; - G_UNLOCK (idle_source_id); - /* check the main loop queue */ - while ((msg = g_async_queue_try_pop (main_loop_queue)) != NULL) { - GCancellable *cancellable; - - cancellable = e_activity_get_cancellable (msg->activity); - - g_idle_add_full ( - G_PRIORITY_DEFAULT, - (GSourceFunc) mail_msg_submit, - g_object_ref (msg->activity), - (GDestroyNotify) g_object_unref); - if (msg->info->exec != NULL) - msg->info->exec (msg, cancellable, &msg->error); - if (msg->info->done != NULL) - msg->info->done (msg); - mail_msg_unref (msg); - } - - /* check the reply queue */ - while ((msg = g_async_queue_try_pop (msg_reply_queue)) != NULL) { - if (msg->info->done != NULL) - msg->info->done (msg); - mail_msg_check_error (msg); - mail_msg_unref (msg); - } - return FALSE; -} - -static void -mail_msg_proxy (MailMsg *msg) -{ - GCancellable *cancellable; - - cancellable = e_activity_get_cancellable (msg->activity); - - if (msg->info->desc != NULL) { - gchar *text = msg->info->desc (msg); - camel_operation_push_message (cancellable, "%s", text); - g_free (text); - } - - g_idle_add_full ( - G_PRIORITY_DEFAULT, - (GSourceFunc) mail_msg_submit, - g_object_ref (msg->activity), - (GDestroyNotify) g_object_unref); - - if (msg->info->exec != NULL) - msg->info->exec (msg, cancellable, &msg->error); - - if (msg->info->desc != NULL) - camel_operation_pop_message (cancellable); - - g_async_queue_push (msg_reply_queue, msg); - - G_LOCK (idle_source_id); - if (idle_source_id == 0) - idle_source_id = g_idle_add ( - (GSourceFunc) mail_msg_idle_cb, NULL); - G_UNLOCK (idle_source_id); -} - -void -mail_msg_init (void) -{ - mail_msg_lock = g_mutex_new (); - mail_msg_cond = g_cond_new (); - - main_loop_queue = g_async_queue_new (); - msg_reply_queue = g_async_queue_new (); - - mail_msg_active_table = g_hash_table_new (NULL, NULL); - main_thread = g_thread_self (); -} - -static gint -mail_msg_compare (const MailMsg *msg1, - const MailMsg *msg2) -{ - gint priority1 = msg1->priority; - gint priority2 = msg2->priority; - - if (priority1 == priority2) - return 0; - - return (priority1 < priority2) ? 1 : -1; -} - -static gpointer -create_thread_pool (gpointer data) -{ - GThreadPool *thread_pool; - gint max_threads = GPOINTER_TO_INT (data); - - /* once created, run forever */ - thread_pool = g_thread_pool_new ( - (GFunc) mail_msg_proxy, NULL, max_threads, FALSE, NULL); - g_thread_pool_set_sort_function ( - thread_pool, (GCompareDataFunc) mail_msg_compare, NULL); - - return thread_pool; -} - -void -mail_msg_main_loop_push (gpointer msg) -{ - g_async_queue_push_sorted (main_loop_queue, msg, - (GCompareDataFunc) mail_msg_compare, NULL); - - G_LOCK (idle_source_id); - if (idle_source_id == 0) - idle_source_id = g_idle_add ( - (GSourceFunc) mail_msg_idle_cb, NULL); - G_UNLOCK (idle_source_id); -} - -void -mail_msg_unordered_push (gpointer msg) -{ - static GOnce once = G_ONCE_INIT; - - g_once (&once, (GThreadFunc) create_thread_pool, GINT_TO_POINTER (10)); - - g_thread_pool_push ((GThreadPool *) once.retval, msg, NULL); -} - -void -mail_msg_fast_ordered_push (gpointer msg) -{ - static GOnce once = G_ONCE_INIT; - - g_once (&once, (GThreadFunc) create_thread_pool, GINT_TO_POINTER (1)); - - g_thread_pool_push ((GThreadPool *) once.retval, msg, NULL); -} - -void -mail_msg_slow_ordered_push (gpointer msg) -{ - static GOnce once = G_ONCE_INIT; - - g_once (&once, (GThreadFunc) create_thread_pool, GINT_TO_POINTER (1)); - - g_thread_pool_push ((GThreadPool *) once.retval, msg, NULL); -} - -gboolean -mail_in_main_thread (void) -{ - return (g_thread_self () == main_thread); -} - -/* ********************************************************************** */ - -struct _call_msg { - MailMsg base; - - mail_call_t type; - MailMainFunc func; - gpointer ret; - va_list ap; - EFlag *done; -}; - -static void -do_call (struct _call_msg *m, - GCancellable *cancellable, - GError **error) -{ - gpointer p1, *p2, *p3, *p4, *p5; - gint i1; - va_list ap; - - G_VA_COPY (ap, m->ap); - - switch (m->type) { - case MAIL_CALL_p_p: - p1 = va_arg (ap, gpointer ); - m->ret = m->func (p1); - break; - case MAIL_CALL_p_pp: - p1 = va_arg (ap, gpointer ); - p2 = va_arg (ap, gpointer ); - m->ret = m->func (p1, p2); - break; - case MAIL_CALL_p_ppp: - p1 = va_arg (ap, gpointer ); - p2 = va_arg (ap, gpointer ); - p3 = va_arg (ap, gpointer ); - m->ret = m->func (p1, p2, p3); - break; - case MAIL_CALL_p_pppp: - p1 = va_arg (ap, gpointer ); - p2 = va_arg (ap, gpointer ); - p3 = va_arg (ap, gpointer ); - p4 = va_arg (ap, gpointer ); - m->ret = m->func (p1, p2, p3, p4); - break; - case MAIL_CALL_p_ppppp: - p1 = va_arg (ap, gpointer ); - p2 = va_arg (ap, gpointer ); - p3 = va_arg (ap, gpointer ); - p4 = va_arg (ap, gpointer ); - p5 = va_arg (ap, gpointer ); - m->ret = m->func (p1, p2, p3, p4, p5); - break; - case MAIL_CALL_p_ppippp: - p1 = va_arg (ap, gpointer ); - p2 = va_arg (ap, gpointer ); - i1 = va_arg (ap, gint); - p3 = va_arg (ap, gpointer ); - p4 = va_arg (ap, gpointer ); - p5 = va_arg (ap, gpointer ); - m->ret = m->func (p1, p2, i1, p3, p4, p5); - break; - } - - e_activity_set_state ( - m->base.activity, - g_cancellable_is_cancelled (cancellable) ? - E_ACTIVITY_CANCELLED : E_ACTIVITY_COMPLETED); - - if (m->done != NULL) - e_flag_set (m->done); -} - -static MailMsgInfo mail_call_info = { - sizeof (struct _call_msg), - (MailMsgDescFunc) NULL, - (MailMsgExecFunc) do_call, - (MailMsgDoneFunc) NULL, - (MailMsgFreeFunc) NULL -}; - -gpointer -mail_call_main (mail_call_t type, - MailMainFunc func, - ...) -{ - GCancellable *cancellable; - struct _call_msg *m; - gpointer ret; - va_list ap; - - va_start (ap, func); - - m = mail_msg_new (&mail_call_info); - m->type = type; - m->func = func; - G_VA_COPY (m->ap, ap); - - cancellable = e_activity_get_cancellable (m->base.activity); - - if (mail_in_main_thread ()) - do_call (m, cancellable, &m->base.error); - else { - mail_msg_ref (m); - m->done = e_flag_new (); - mail_msg_main_loop_push (m); - e_flag_wait (m->done); - e_flag_free (m->done); - } - - va_end (ap); - - ret = m->ret; - mail_msg_unref (m); - - return ret; -} - -void -mail_mt_set_backend (gchar *backend) -{ - shell_builtin_backend = backend; -} - diff --git a/mail/mail-mt.h b/mail/mail-mt.h deleted file mode 100644 index 0b595072b6..0000000000 --- a/mail/mail-mt.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see - * - * - * Authors: - * Michael Zucchi - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef _MAIL_MT -#define _MAIL_MT - -#include -#include - -typedef struct _MailMsg MailMsg; -typedef struct _MailMsgInfo MailMsgInfo; - -typedef gchar * (*MailMsgDescFunc) (MailMsg *msg); -typedef void (*MailMsgExecFunc) (MailMsg *msg, - GCancellable *cancellable, - GError **error); -typedef void (*MailMsgDoneFunc) (MailMsg *msg); -typedef void (*MailMsgFreeFunc) (MailMsg *msg); -typedef void (*MailMsgDispatchFunc) (gpointer msg); - -struct _MailMsg { - MailMsgInfo *info; - volatile gint ref_count; - guint seq; /* seq number for synchronisation */ - gint priority; /* priority (default = 0) */ - EActivity *activity; - GError *error; /* up to the caller to use this */ -}; - -struct _MailMsgInfo { - gsize size; - MailMsgDescFunc desc; - MailMsgExecFunc exec; - MailMsgDoneFunc done; - MailMsgFreeFunc free; -}; - -/* setup ports */ -void mail_msg_init (void); - -gboolean mail_in_main_thread (void); - -/* allocate a new message */ -gpointer mail_msg_new (MailMsgInfo *info); -gpointer mail_msg_ref (gpointer msg); -void mail_msg_unref (gpointer msg); -void mail_msg_check_error (gpointer msg); -void mail_msg_cancel (guint msgid); -gboolean mail_msg_active (void); - -/* dispatch a message */ -void mail_msg_main_loop_push (gpointer msg); -void mail_msg_unordered_push (gpointer msg); -void mail_msg_fast_ordered_push (gpointer msg); -void mail_msg_slow_ordered_push (gpointer msg); - -/* To implement the stop button */ -GHook * mail_cancel_hook_add (GHookFunc func, gpointer data); -void mail_cancel_hook_remove (GHook *hook); -void mail_cancel_all (void); - -/* request a string/password */ -gchar *mail_get_password (CamelService *service, const gchar *prompt, - gboolean secret, gboolean *cache); - -void mail_mt_set_backend (gchar *backend); - -/* Call a function in the GUI thread, wait for it to return, type is - * the marshaller to use. FIXME This thing is horrible, please put - * it out of its misery. */ -typedef enum { - MAIL_CALL_p_p, - MAIL_CALL_p_pp, - MAIL_CALL_p_ppp, - MAIL_CALL_p_pppp, - MAIL_CALL_p_ppppp, - MAIL_CALL_p_ppippp -} mail_call_t; - -typedef gpointer (*MailMainFunc)(); - -gpointer mail_call_main (mail_call_t type, MailMainFunc func, ...); - -#endif /* _MAIL_MT */ diff --git a/mail/mail-ops.c b/mail/mail-ops.c deleted file mode 100644 index 27b48c2aa8..0000000000 --- a/mail/mail-ops.c +++ /dev/null @@ -1,1690 +0,0 @@ -/* - * mail-ops.c: callbacks for the mail toolbar/menus - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see - * - * - * Authors: - * Dan Winship - * Jeffrey Stedfast - * Peter Williams - * Michael Zucchi - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include -#include - -#include -#include "e-util/e-account-utils.h" - -#include "em-filter-rule.h" -#include "em-utils.h" -#include "mail-mt.h" -#include "mail-ops.h" -#include "mail-tools.h" - -#include "e-mail-session.h" -#include "e-mail-session-utils.h" - -#define w(x) -#define d(x) - -/* XXX Make this a preprocessor definition. */ -const gchar *x_mailer = "Evolution " VERSION SUB_VERSION " " VERSION_COMMENT; - -/* used for both just filtering a folder + uid's, and for filtering a whole folder */ -/* used both for fetching mail, and for filtering mail */ -struct _filter_mail_msg { - MailMsg base; - - EMailSession *session; - CamelFolder *source_folder; /* where they come from */ - GPtrArray *source_uids; /* uids to copy, or NULL == copy all */ - CamelUIDCache *cache; /* UID cache if we are to cache the uids, NULL otherwise */ - CamelFilterDriver *driver; - gint delete; /* delete messages after filtering them? */ - CamelFolder *destination; /* default destination for any messages, NULL for none */ -}; - -/* since fetching also filters, we subclass the data here */ -struct _fetch_mail_msg { - struct _filter_mail_msg fmsg; - - CamelStore *store; - GCancellable *cancellable; /* we have our own cancellation - * struct, the other should be empty */ - gint keep; /* keep on server? */ - - void (*done)(gpointer data); - gpointer data; -}; - -static gchar * -em_filter_folder_element_desc (struct _filter_mail_msg *m) -{ - return g_strdup (_("Filtering Selected Messages")); -} - -/* filter a folder, or a subset thereof, uses source_folder/source_uids */ -/* this is shared with fetch_mail */ -static void -em_filter_folder_element_exec (struct _filter_mail_msg *m, - GCancellable *cancellable, - GError **error) -{ - CamelFolder *folder; - GPtrArray *uids, *folder_uids = NULL; - - folder = m->source_folder; - - if (folder == NULL || camel_folder_get_message_count (folder) == 0) - return; - - if (m->destination) { - camel_folder_freeze (m->destination); - camel_filter_driver_set_default_folder (m->driver, m->destination); - } - - camel_folder_freeze (folder); - - if (m->source_uids) - uids = m->source_uids; - else - folder_uids = uids = camel_folder_get_uids (folder); - - camel_filter_driver_filter_folder ( - m->driver, folder, m->cache, uids, m->delete, - cancellable, error); - camel_filter_driver_flush (m->driver, error); - - if (folder_uids) - camel_folder_free_uids (folder, folder_uids); - - /* sync our source folder */ - if (!m->cache) - camel_folder_synchronize_sync ( - folder, FALSE, cancellable, error); - camel_folder_thaw (folder); - - if (m->destination) - camel_folder_thaw (m->destination); - - /* this may thaw/unref source folders, do it here so we dont do - * it in the main thread see also fetch_mail_fetch () below */ - g_object_unref (m->driver); - m->driver = NULL; -} - -static void -em_filter_folder_element_done (struct _filter_mail_msg *m) -{ -} - -static void -em_filter_folder_element_free (struct _filter_mail_msg *m) -{ - mail_session_flush_filter_log (m->session); - - if (m->session) - g_object_unref (m->session); - - if (m->source_folder) - g_object_unref (m->source_folder); - - if (m->source_uids) - em_utils_uids_free (m->source_uids); - - if (m->destination) - g_object_unref (m->destination); - - if (m->driver) - g_object_unref (m->driver); -} - -static MailMsgInfo em_filter_folder_element_info = { - sizeof (struct _filter_mail_msg), - (MailMsgDescFunc) em_filter_folder_element_desc, - (MailMsgExecFunc) em_filter_folder_element_exec, - (MailMsgDoneFunc) em_filter_folder_element_done, - (MailMsgFreeFunc) em_filter_folder_element_free -}; - -void -mail_filter_folder (EMailSession *session, - CamelFolder *source_folder, - GPtrArray *uids, - const gchar *type, - gboolean notify) -{ - struct _filter_mail_msg *m; - - m = mail_msg_new (&em_filter_folder_element_info); - m->session = g_object_ref (session); - m->source_folder = g_object_ref (source_folder); - m->source_uids = uids; - m->cache = NULL; - m->delete = FALSE; - - m->driver = camel_session_get_filter_driver ( - CAMEL_SESSION (session), type, NULL); - - if (!notify) { - /* FIXME: have a #define NOTIFY_FILTER_NAME macro? */ - /* the filter name has to stay in sync with mail-session::get_filter_driver */ - camel_filter_driver_remove_rule_by_name (m->driver, "new-mail-notification"); - } - - mail_msg_unordered_push (m); -} - -/* ********************************************************************** */ - -static gchar * -fetch_mail_desc (struct _fetch_mail_msg *m) -{ - return g_strdup (_("Fetching Mail")); -} - -static void -fetch_mail_exec (struct _fetch_mail_msg *m, - GCancellable *cancellable, - GError **error) -{ - struct _filter_mail_msg *fm = (struct _filter_mail_msg *) m; - CamelFolder *folder = NULL; - CamelService *service; - CamelSession *session; - CamelURL *url; - gboolean is_local_delivery; - const gchar *uid; - gint i; - - service = CAMEL_SERVICE (m->store); - session = camel_service_get_session (service); - - fm->destination = e_mail_session_get_local_folder ( - E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_LOCAL_INBOX); - if (fm->destination == NULL) - goto exit; - g_object_ref (fm->destination); - - url = camel_service_new_camel_url (service); - is_local_delivery = em_utils_is_local_delivery_mbox_file (url); - - if (is_local_delivery) { - gchar *path; - gchar *url_string; - - path = mail_tool_do_movemail (m->store, error); - url_string = camel_url_to_string (url, CAMEL_URL_HIDE_ALL); - - if (path && (!error || !*error)) { - camel_folder_freeze (fm->destination); - camel_filter_driver_set_default_folder ( - fm->driver, fm->destination); - camel_filter_driver_filter_mbox ( - fm->driver, path, url_string, - cancellable, error); - camel_folder_thaw (fm->destination); - - if (!error || !*error) - g_unlink (path); - } - - g_free (path); - g_free (url_string); - } else { - uid = camel_service_get_uid (service); - - folder = fm->source_folder = - e_mail_session_get_inbox_sync ( - fm->session, uid, cancellable, error); - } - - camel_url_free (url); - - if (folder != NULL) { - /* This handles 'keep on server' stuff, if we have any new - * uid's to copy across, we need to copy them to a new array - * 'cause of the way fetch_mail_free works. */ - CamelUIDCache *cache = NULL; - CamelStore *parent_store; - CamelService *service; - const gchar *data_dir; - gchar *cachename; - - parent_store = camel_folder_get_parent_store (folder); - - service = CAMEL_SERVICE (parent_store); - data_dir = camel_service_get_user_data_dir (service); - - cachename = g_build_filename (data_dir, "uid-cache", NULL); - cache = camel_uid_cache_new (cachename); - g_free (cachename); - - if (cache) { - GPtrArray *folder_uids, *cache_uids, *uids; - - folder_uids = camel_folder_get_uids (folder); - cache_uids = camel_uid_cache_get_new_uids (cache, folder_uids); - if (cache_uids) { - /* need to copy this, sigh */ - fm->source_uids = uids = g_ptr_array_new (); - g_ptr_array_set_size (uids, cache_uids->len); - for (i = 0; i < cache_uids->len; i++) - uids->pdata[i] = g_strdup (cache_uids->pdata[i]); - camel_uid_cache_free_uids (cache_uids); - - fm->cache = cache; - em_filter_folder_element_exec (fm, cancellable, error); - - /* need to uncancel so writes/etc. don't fail */ - if (g_cancellable_is_cancelled (m->cancellable)) - g_cancellable_reset (m->cancellable); - - /* save the cache of uids that we've just downloaded */ - camel_uid_cache_save (cache); - } - - if (fm->delete && (!error || !*error)) { - /* not keep on server - just delete all - * the actual messages on the server */ - for (i = 0; i < folder_uids->len; i++) { - camel_folder_delete_message ( - folder, folder_uids->pdata[i]); - } - } - - if ((fm->delete || cache_uids) && (!error || !*error)) { - /* expunge messages (downloaded so far) */ - /* FIXME Not passing a GCancellable or GError here. */ - camel_folder_synchronize_sync ( - folder, fm->delete, NULL, NULL); - } - - camel_uid_cache_destroy (cache); - camel_folder_free_uids (folder, folder_uids); - } else { - em_filter_folder_element_exec (fm, cancellable, error); - } - - /* we unref the source folder here since we - * may now block in finalize (we try to - * disconnect cleanly) */ - g_object_unref (fm->source_folder); - fm->source_folder = NULL; - } - -exit: - /* we unref this here as it may have more work to do (syncing - * folders and whatnot) before we are really done */ - /* should this be cancellable too? (i.e. above unregister above) */ - if (fm->driver) { - g_object_unref (fm->driver); - fm->driver = NULL; - } - - /* also disconnect if not a local delivery mbox; - * there is no need to keep the connection alive forever */ - if (!is_local_delivery) - em_utils_disconnect_service_sync ( - service, TRUE, cancellable, NULL); -} - -static void -fetch_mail_done (struct _fetch_mail_msg *m) -{ - if (m->done) - m->done (m->data); -} - -static void -fetch_mail_free (struct _fetch_mail_msg *m) -{ - if (m->store != NULL) - g_object_unref (m->store); - - if (m->cancellable != NULL) - g_object_unref (m->cancellable); - - em_filter_folder_element_free ((struct _filter_mail_msg *) m); -} - -static MailMsgInfo fetch_mail_info = { - sizeof (struct _fetch_mail_msg), - (MailMsgDescFunc) fetch_mail_desc, - (MailMsgExecFunc) fetch_mail_exec, - (MailMsgDoneFunc) fetch_mail_done, - (MailMsgFreeFunc) fetch_mail_free -}; - -/* ouch, a 'do everything' interface ... */ -void -mail_fetch_mail (CamelStore *store, - gint keep, - const gchar *type, - GCancellable *cancellable, - CamelFilterGetFolderFunc get_folder, - gpointer get_data, - CamelFilterStatusFunc *status, - gpointer status_data, - void (*done)(gpointer data), - gpointer data) -{ - struct _fetch_mail_msg *m; - struct _filter_mail_msg *fm; - CamelSession *session; - - g_return_if_fail (CAMEL_IS_STORE (store)); - - session = camel_service_get_session (CAMEL_SERVICE (store)); - - m = mail_msg_new (&fetch_mail_info); - fm = (struct _filter_mail_msg *) m; - fm->session = g_object_ref (session); - m->store = g_object_ref (store); - fm->delete = !keep; - fm->cache = NULL; - if (cancellable) - m->cancellable = g_object_ref (cancellable); - m->done = done; - m->data = data; - - fm->driver = camel_session_get_filter_driver (session, type, NULL); - camel_filter_driver_set_folder_func (fm->driver, get_folder, get_data); - if (status) - camel_filter_driver_set_status_func (fm->driver, status, status_data); - - mail_msg_unordered_push (m); -} - -/* ********************************************************************** */ -/* sending stuff */ -/* ** SEND MAIL *********************************************************** */ - -static const gchar *normal_recipients[] = { - CAMEL_RECIPIENT_TYPE_TO, - CAMEL_RECIPIENT_TYPE_CC, - CAMEL_RECIPIENT_TYPE_BCC -}; - -static const gchar *resent_recipients[] = { - CAMEL_RECIPIENT_TYPE_RESENT_TO, - CAMEL_RECIPIENT_TYPE_RESENT_CC, - CAMEL_RECIPIENT_TYPE_RESENT_BCC -}; - -struct _send_queue_msg { - MailMsg base; - - EMailSession *session; - CamelFolder *queue; - CamelTransport *transport; - - CamelFilterDriver *driver; - - /* we use camelfilterstatusfunc, even though its not the filter doing it */ - CamelFilterStatusFunc *status; - gpointer status_data; - - void (*done)(gpointer data); - gpointer data; -}; - -static void report_status (struct _send_queue_msg *m, - enum camel_filter_status_t status, - gint pc, - const gchar *desc, - ...); - -/* send 1 message to a specific transport */ -static void -mail_send_message (struct _send_queue_msg *m, - CamelFolder *queue, - const gchar *uid, - CamelTransport *transport, - CamelFilterDriver *driver, - GCancellable *cancellable, - GError **error) -{ - EAccount *account = NULL; - const CamelInternetAddress *iaddr; - CamelAddress *from, *recipients; - CamelMessageInfo *info = NULL; - CamelProvider *provider; - gchar *transport_uid = NULL; - gchar *sent_folder_uri = NULL; - const gchar *resent_from, *tmp; - CamelFolder *folder = NULL; - GString *err = NULL; - struct _camel_header_raw *xev, *header; - CamelMimeMessage *message; - gint i; - GError *local_error = NULL; - - message = camel_folder_get_message_sync ( - queue, uid, cancellable, error); - if (!message) - return; - - camel_medium_set_header (CAMEL_MEDIUM (message), "X-Mailer", x_mailer); - - err = g_string_new (""); - xev = mail_tool_remove_xevolution_headers (message); - - tmp = camel_header_raw_find (&xev, "X-Evolution-Account", NULL); - if (tmp != NULL) { - gchar *name; - - name = g_strstrip (g_strdup (tmp)); - if ((account = e_get_account_by_uid (name)) - /* 'old' x-evolution-account stored the name, how silly */ - || (account = e_get_account_by_name (name))) { - if (account->transport) { - CamelService *service; - gchar *transport_uid; - - transport_uid = g_strconcat ( - account->uid, "-transport", NULL); - service = camel_session_get_service ( - CAMEL_SESSION (m->session), - transport_uid); - g_free (transport_uid); - - if (CAMEL_IS_TRANSPORT (service)) - transport = CAMEL_TRANSPORT (service); - } - - sent_folder_uri = g_strdup (account->sent_folder_uri); - } - g_free (name); - } - - if (!account) { - /* default back to these headers */ - tmp = camel_header_raw_find(&xev, "X-Evolution-Transport", NULL); - if (tmp) - transport_uid = g_strstrip (g_strdup (tmp)); - - tmp = camel_header_raw_find(&xev, "X-Evolution-Fcc", NULL); - if (tmp) - sent_folder_uri = g_strstrip (g_strdup (tmp)); - } - - if (transport != NULL) { - const gchar *uid; - - /* Let the dialog know the right account it is using. */ - uid = camel_service_get_uid (CAMEL_SERVICE (transport)); - report_status (m, CAMEL_FILTER_STATUS_ACTION, 0, uid); - } - - /* Check for email sending */ - from = (CamelAddress *) camel_internet_address_new (); - resent_from = camel_medium_get_header (CAMEL_MEDIUM (message), "Resent-From"); - if (resent_from) { - camel_address_decode (from, resent_from); - } else { - iaddr = camel_mime_message_get_from (message); - camel_address_copy (from, CAMEL_ADDRESS (iaddr)); - } - - recipients = (CamelAddress *) camel_internet_address_new (); - for (i = 0; i < 3; i++) { - const gchar *type; - - type = resent_from ? resent_recipients[i] : normal_recipients[i]; - iaddr = camel_mime_message_get_recipients (message, type); - camel_address_cat (recipients, CAMEL_ADDRESS (iaddr)); - } - - if (camel_address_length (recipients) > 0) { - if (!em_utils_connect_service_sync ( - CAMEL_SERVICE (transport), cancellable, error)) - goto exit; - - if (!camel_transport_send_to_sync ( - transport, message, from, - recipients, cancellable, error)) - goto exit; - } - - /* Now check for posting, failures are ignored */ - info = camel_message_info_new (NULL); - camel_message_info_set_flags (info, CAMEL_MESSAGE_SEEN, ~0); - - for (header = xev; header; header = header->next) { - gchar *uri; - - if (strcmp(header->name, "X-Evolution-PostTo") != 0) - continue; - - /* TODO: don't lose errors */ - - uri = g_strstrip (g_strdup (header->value)); - /* FIXME Not passing a GCancellable or GError here. */ - folder = e_mail_session_uri_to_folder_sync ( - m->session, uri, 0, NULL, NULL); - if (folder) { - /* FIXME Not passing a GCancellable or GError here. */ - camel_folder_append_message_sync ( - folder, message, info, NULL, NULL, NULL); - g_object_unref (folder); - folder = NULL; - } - g_free (uri); - } - - /* post process */ - mail_tool_restore_xevolution_headers (message, xev); - - if (driver) { - camel_filter_driver_filter_message ( - driver, message, info, NULL, NULL, - NULL, "", cancellable, &local_error); - - if (local_error != NULL) { - if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - goto exit; - - /* sending mail, filtering failed */ - g_string_append_printf ( - err, _("Failed to apply outgoing filters: %s"), - local_error->message); - - g_clear_error (&local_error); - } - } - - provider = camel_service_get_provider (CAMEL_SERVICE (transport)); - - if (provider == NULL - || !(provider->flags & CAMEL_PROVIDER_DISABLE_SENT_FOLDER)) { - GError *local_error = NULL; - - if (sent_folder_uri) { - folder = e_mail_session_uri_to_folder_sync ( - m->session, sent_folder_uri, 0, - cancellable, &local_error); - if (folder == NULL) { - g_string_append_printf ( - err, _("Failed to append to %s: %s\n" - "Appending to local 'Sent' folder instead."), - sent_folder_uri, - local_error ? - local_error->message : - _("Unknown error")); - if (local_error) - g_clear_error (&local_error); - } - } - - if (!folder) { - folder = e_mail_session_get_local_folder ( - m->session, E_MAIL_LOCAL_FOLDER_SENT); - g_object_ref (folder); - } - - if (!camel_folder_append_message_sync ( - folder, message, info, - NULL, cancellable, &local_error)) { - - CamelFolder *sent_folder; - - if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - goto exit; - - sent_folder = e_mail_session_get_local_folder ( - m->session, E_MAIL_LOCAL_FOLDER_SENT); - - if (folder != sent_folder) { - const gchar *description; - - description = camel_folder_get_description (folder); - if (err->len) - g_string_append(err, "\n\n"); - g_string_append_printf ( - err, _("Failed to append to %s: %s\n" - "Appending to local 'Sent' folder instead."), - description, local_error->message); - g_object_ref (sent_folder); - g_object_unref (folder); - folder = sent_folder; - - g_clear_error (&local_error); - camel_folder_append_message_sync ( - folder, message, info, - NULL, cancellable, &local_error); - } - - if (local_error != NULL) { - if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - goto exit; - - if (err->len) - g_string_append(err, "\n\n"); - g_string_append_printf ( - err, _("Failed to append to local 'Sent' folder: %s"), - local_error->message); - } - } - } - - if (local_error == NULL) { - /* Mark the draft message for deletion, if present. */ - e_mail_session_handle_draft_headers_sync ( - m->session, message, cancellable, &local_error); - if (local_error != NULL) { - g_warning ("%s: Failed to handle draft headers: %s", G_STRFUNC, local_error->message); - g_clear_error (&local_error); - } - - /* Set flags on the original source message, if present. - * Source message refers to the message being forwarded - * or replied to. */ - e_mail_session_handle_source_headers_sync ( - m->session, message, cancellable, &local_error); - if (local_error != NULL) { - g_warning ("%s: Failed to handle source headers: %s", G_STRFUNC, local_error->message); - g_clear_error (&local_error); - } - } - - if (local_error == NULL) { - camel_folder_set_message_flags ( - queue, uid, CAMEL_MESSAGE_DELETED | - CAMEL_MESSAGE_SEEN, ~0); - /* Sync it to disk, since if it crashes in between, - * we keep sending it again on next start. */ - /* FIXME Not passing a GCancellable or GError here. */ - camel_folder_synchronize_sync (queue, FALSE, NULL, NULL); - } - - if (err->len) { - /* set the culmulative exception report */ - g_set_error ( - &local_error, CAMEL_ERROR, - CAMEL_ERROR_GENERIC, "%s", err->str); - } - -exit: - if (local_error != NULL) - g_propagate_error (error, local_error); - - /* FIXME Not passing a GCancellable or GError here. */ - if (folder) { - camel_folder_synchronize_sync (folder, FALSE, NULL, NULL); - g_object_unref (folder); - } - if (info) - camel_message_info_free (info); - g_object_unref (recipients); - g_object_unref (from); - g_free (sent_folder_uri); - g_free (transport_uid); - camel_header_raw_clear (&xev); - g_string_free (err, TRUE); - g_object_unref (message); -} - -/* ** SEND MAIL QUEUE ***************************************************** */ - -static void -report_status (struct _send_queue_msg *m, - enum camel_filter_status_t status, - gint pc, - const gchar *desc, - ...) -{ - va_list ap; - gchar *str; - - if (m->status) { - va_start (ap, desc); - str = g_strdup_vprintf (desc, ap); - va_end (ap); - m->status (m->driver, status, pc, str, m->status_data); - g_free (str); - } -} - -static void -send_queue_exec (struct _send_queue_msg *m, - GCancellable *cancellable, - GError **error) -{ - CamelFolder *sent_folder; - GPtrArray *uids, *send_uids = NULL; - gint i, j; - GError *local_error = NULL; - - d(printf("sending queue\n")); - - sent_folder = - e_mail_session_get_local_folder ( - m->session, E_MAIL_LOCAL_FOLDER_SENT); - - if (!(uids = camel_folder_get_uids (m->queue))) - return; - - send_uids = g_ptr_array_sized_new (uids->len); - for (i = 0, j = 0; i < uids->len; i++) { - CamelMessageInfo *info; - - info = camel_folder_get_message_info (m->queue, uids->pdata[i]); - if (info) { - if ((camel_message_info_flags (info) & CAMEL_MESSAGE_DELETED) == 0) - send_uids->pdata[j++] = uids->pdata[i]; - camel_folder_free_message_info (m->queue, info); - } - } - - send_uids->len = j; - if (send_uids->len == 0) { - /* nothing to send */ - camel_folder_free_uids (m->queue, uids); - g_ptr_array_free (send_uids, TRUE); - return; - } - - camel_operation_push_message (cancellable, _("Sending message")); - - /* NB: This code somewhat abuses the 'exception' stuff. Apart from - * fatal problems, it is also used as a mechanism to accumualte - * warning messages and present them back to the user. */ - - for (i = 0, j = 0; i < send_uids->len; i++) { - gint pc = (100 * i) / send_uids->len; - - report_status ( - m, CAMEL_FILTER_STATUS_START, pc, - _("Sending message %d of %d"), i+1, - send_uids->len); - - camel_operation_progress ( - cancellable, (i + 1) * 100 / send_uids->len); - - mail_send_message ( - m, m->queue, send_uids->pdata[i], m->transport, - m->driver, cancellable, &local_error); - if (local_error != NULL) { - if (!g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - /* merge exceptions into one */ - if (m->base.error != NULL) { - gchar *old_message; - - old_message = g_strdup ( - m->base.error->message); - g_clear_error (&m->base.error); - g_set_error ( - &m->base.error, CAMEL_ERROR, - CAMEL_ERROR_GENERIC, - "%s\n\n%s", old_message, - local_error->message); - g_free (old_message); - - g_clear_error (&local_error); - } else { - g_propagate_error (&m->base.error, local_error); - local_error = NULL; - } - - /* keep track of the number of failures */ - j++; - } else { - /* transfer the USER_CANCEL error to the - * async op exception and then break */ - g_propagate_error (&m->base.error, local_error); - local_error = NULL; - break; - } - } - } - - j += (send_uids->len - i); - - if (j > 0) - report_status ( - m, CAMEL_FILTER_STATUS_END, 100, - _("Failed to send %d of %d messages"), - j, send_uids->len); - else if (g_error_matches ( - m->base.error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - report_status (m, CAMEL_FILTER_STATUS_END, 100, _("Canceled.")); - else - report_status (m, CAMEL_FILTER_STATUS_END, 100, _("Complete.")); - - if (m->driver) { - g_object_unref (m->driver); - m->driver = NULL; - } - - camel_folder_free_uids (m->queue, uids); - g_ptr_array_free (send_uids, TRUE); - - /* FIXME Not passing a GCancellable or GError here. */ - if (j <= 0 && m->base.error == NULL) - camel_folder_synchronize_sync (m->queue, TRUE, NULL, NULL); - - /* FIXME Not passing a GCancellable or GError here. */ - if (sent_folder) - camel_folder_synchronize_sync (sent_folder, FALSE, NULL, NULL); - - camel_operation_pop_message (cancellable); -} - -static void -send_queue_done (struct _send_queue_msg *m) -{ - if (m->done) - m->done (m->data); -} - -static gchar * -send_queue_desc (struct _send_queue_msg *m) -{ - return g_strdup (_("Sending message")); -} - -static void -send_queue_free (struct _send_queue_msg *m) -{ - if (m->session != NULL) - g_object_unref (m->session); - if (m->driver != NULL) - g_object_unref (m->driver); - if (m->transport != NULL) - g_object_unref (m->transport); - g_object_unref (m->queue); -} - -static MailMsgInfo send_queue_info = { - sizeof (struct _send_queue_msg), - (MailMsgDescFunc) send_queue_desc, - (MailMsgExecFunc) send_queue_exec, - (MailMsgDoneFunc) send_queue_done, - (MailMsgFreeFunc) send_queue_free -}; - -/* same interface as fetch_mail, just 'cause i'm lazy today - * (and we need to run it from the same spot?) */ -void -mail_send_queue (EMailSession *session, - CamelFolder *queue, - CamelTransport *transport, - const gchar *type, - GCancellable *cancellable, - CamelFilterGetFolderFunc get_folder, - gpointer get_data, - CamelFilterStatusFunc *status, - gpointer status_data, - void (*done)(gpointer data), - gpointer data) -{ - struct _send_queue_msg *m; - - g_return_if_fail (E_IS_MAIL_SESSION (session)); - - m = mail_msg_new (&send_queue_info); - m->session = g_object_ref (session); - m->queue = g_object_ref (queue); - m->transport = g_object_ref (transport); - if (G_IS_CANCELLABLE (cancellable)) - e_activity_set_cancellable (m->base.activity, cancellable); - m->status = status; - m->status_data = status_data; - m->done = done; - m->data = data; - - m->driver = camel_session_get_filter_driver ( - CAMEL_SESSION (session), type, NULL); - camel_filter_driver_set_folder_func (m->driver, get_folder, get_data); - - mail_msg_unordered_push (m); -} - -/* ** TRANSFER MESSAGES **************************************************** */ - -struct _transfer_msg { - MailMsg base; - - EMailSession *session; - CamelFolder *source; - GPtrArray *uids; - gboolean delete; - gchar *dest_uri; - guint32 dest_flags; - - void (*done)(gboolean ok, gpointer data); - gpointer data; -}; - -static gchar * -transfer_messages_desc (struct _transfer_msg *m) -{ - return g_strdup_printf ( - m->delete ? - _("Moving messages to '%s'") : - _("Copying messages to '%s'"), - m->dest_uri); - -} - -static void -transfer_messages_exec (struct _transfer_msg *m, - GCancellable *cancellable, - GError **error) -{ - CamelFolder *dest; - - dest = e_mail_session_uri_to_folder_sync ( - m->session, m->dest_uri, m->dest_flags, - cancellable, error); - if (dest == NULL) - return; - - if (dest == m->source) { - g_object_unref (dest); - /* no-op */ - return; - } - - camel_folder_freeze (m->source); - camel_folder_freeze (dest); - - camel_folder_transfer_messages_to_sync ( - m->source, m->uids, dest, m->delete, NULL, - cancellable, error); - - /* make sure all deleted messages are marked as seen */ - - if (m->delete) { - gint i; - - for (i = 0; i < m->uids->len; i++) - camel_folder_set_message_flags ( - m->source, m->uids->pdata[i], - CAMEL_MESSAGE_SEEN, CAMEL_MESSAGE_SEEN); - } - - camel_folder_thaw (m->source); - camel_folder_thaw (dest); - - /* FIXME Not passing a GCancellable or GError here. */ - camel_folder_synchronize_sync (dest, FALSE, NULL, NULL); - g_object_unref (dest); -} - -static void -transfer_messages_done (struct _transfer_msg *m) -{ - if (m->done) - m->done (m->base.error == NULL, m->data); -} - -static void -transfer_messages_free (struct _transfer_msg *m) -{ - g_object_unref (m->session); - g_object_unref (m->source); - g_free (m->dest_uri); - em_utils_uids_free (m->uids); -} - -static MailMsgInfo transfer_messages_info = { - sizeof (struct _transfer_msg), - (MailMsgDescFunc) transfer_messages_desc, - (MailMsgExecFunc) transfer_messages_exec, - (MailMsgDoneFunc) transfer_messages_done, - (MailMsgFreeFunc) transfer_messages_free -}; - -void -mail_transfer_messages (EMailSession *session, - CamelFolder *source, - GPtrArray *uids, - gboolean delete_from_source, - const gchar *dest_uri, - guint32 dest_flags, - void (*done) (gboolean ok, - gpointer data), - gpointer data) -{ - struct _transfer_msg *m; - - g_return_if_fail (CAMEL_IS_FOLDER (source)); - g_return_if_fail (uids != NULL); - g_return_if_fail (dest_uri != NULL); - - m = mail_msg_new (&transfer_messages_info); - m->session = g_object_ref (session); - m->source = g_object_ref (source); - m->uids = uids; - m->delete = delete_from_source; - m->dest_uri = g_strdup (dest_uri); - m->dest_flags = dest_flags; - m->done = done; - m->data = data; - - mail_msg_slow_ordered_push (m); -} - -/* ** SYNC FOLDER ********************************************************* */ - -struct _sync_folder_msg { - MailMsg base; - - CamelFolder *folder; - void (*done) (CamelFolder *folder, gpointer data); - gpointer data; -}; - -static gchar * -sync_folder_desc (struct _sync_folder_msg *m) -{ - return g_strdup_printf (_("Storing folder '%s'"), - camel_folder_get_full_name (m->folder)); -} - -static void -sync_folder_exec (struct _sync_folder_msg *m, - GCancellable *cancellable, - GError **error) -{ - camel_folder_synchronize_sync ( - m->folder, FALSE, cancellable, error); -} - -static void -sync_folder_done (struct _sync_folder_msg *m) -{ - if (m->done) - m->done (m->folder, m->data); -} - -static void -sync_folder_free (struct _sync_folder_msg *m) -{ - if (m->folder) - g_object_unref (m->folder); -} - -static MailMsgInfo sync_folder_info = { - sizeof (struct _sync_folder_msg), - (MailMsgDescFunc) sync_folder_desc, - (MailMsgExecFunc) sync_folder_exec, - (MailMsgDoneFunc) sync_folder_done, - (MailMsgFreeFunc) sync_folder_free -}; - -void -mail_sync_folder (CamelFolder *folder, - void (*done) (CamelFolder *folder, - gpointer data), - gpointer data) -{ - struct _sync_folder_msg *m; - - m = mail_msg_new (&sync_folder_info); - m->folder = g_object_ref (folder); - m->data = data; - m->done = done; - - mail_msg_slow_ordered_push (m); -} - -/* ** SYNC STORE ********************************************************* */ - -struct _sync_store_msg { - MailMsg base; - - CamelStore *store; - gint expunge; - void (*done) (CamelStore *store, gpointer data); - gpointer data; -}; - -static gchar * -sync_store_desc (struct _sync_store_msg *m) -{ - CamelURL *url; - gchar *uri, *res; - - url = camel_service_new_camel_url (CAMEL_SERVICE (m->store)); - uri = camel_url_to_string (url, CAMEL_URL_HIDE_ALL); - camel_url_free (url); - - res = g_strdup_printf (m->expunge - ?_("Expunging and storing account '%s'") - :_("Storing account '%s'"), - uri); - g_free (uri); - - return res; -} - -static void -sync_store_exec (struct _sync_store_msg *m, - GCancellable *cancellable, - GError **error) -{ - camel_store_synchronize_sync ( - m->store, m->expunge, - cancellable, error); -} - -static void -sync_store_done (struct _sync_store_msg *m) -{ - if (m->done) - m->done (m->store, m->data); -} - -static void -sync_store_free (struct _sync_store_msg *m) -{ - g_object_unref (m->store); -} - -static MailMsgInfo sync_store_info = { - sizeof (struct _sync_store_msg), - (MailMsgDescFunc) sync_store_desc, - (MailMsgExecFunc) sync_store_exec, - (MailMsgDoneFunc) sync_store_done, - (MailMsgFreeFunc) sync_store_free -}; - -void -mail_sync_store (CamelStore *store, - gint expunge, - void (*done) (CamelStore *store, - gpointer data), - gpointer data) -{ - struct _sync_store_msg *m; - - m = mail_msg_new (&sync_store_info); - m->store = g_object_ref (store); - m->expunge = expunge; - m->data = data; - m->done = done; - - mail_msg_slow_ordered_push (m); -} - -/* ******************************************************************************** */ - -static gchar * -refresh_folder_desc (struct _sync_folder_msg *m) -{ - return g_strdup_printf ( - _("Refreshing folder '%s'"), - camel_folder_get_full_name (m->folder)); -} - -static void -refresh_folder_exec (struct _sync_folder_msg *m, - GCancellable *cancellable, - GError **error) -{ - camel_folder_refresh_info_sync ( - m->folder, cancellable, error); -} - -/* we just use the sync stuff where we can, since it would be the same */ -static MailMsgInfo refresh_folder_info = { - sizeof (struct _sync_folder_msg), - (MailMsgDescFunc) refresh_folder_desc, - (MailMsgExecFunc) refresh_folder_exec, - (MailMsgDoneFunc) sync_folder_done, - (MailMsgFreeFunc) sync_folder_free -}; - -void -mail_refresh_folder (CamelFolder *folder, - void (*done) (CamelFolder *folder, - gpointer data), - gpointer data) -{ - struct _sync_folder_msg *m; - - m = mail_msg_new (&refresh_folder_info); - m->folder = g_object_ref (folder); - m->data = data; - m->done = done; - - mail_msg_slow_ordered_push (m); -} - -/* ******************************************************************************** */ - -static gboolean -folder_is_from_source_uid (CamelFolder *folder, - const gchar *source_uid) -{ - CamelStore *store; - const gchar *uid; - - store = camel_folder_get_parent_store (folder); - uid = camel_service_get_uid (CAMEL_SERVICE (store)); - - return (g_strcmp0 (uid, source_uid) == 0); -} - -/* This is because pop3 accounts are hidden under local Inbox, - * thus whenever an expunge is done on a local trash or Inbox, - * then also all active pop3 accounts should be expunged. */ -static gboolean -expunge_pop3_stores (CamelFolder *expunging, - GCancellable *cancellable, - GError **error) -{ - GHashTable *expunging_uids; - CamelStore *parent_store; - CamelService *service; - CamelSession *session; - GPtrArray *uids; - EAccount *account; - EIterator *iter; - gboolean success = TRUE; - guint ii; - - parent_store = camel_folder_get_parent_store (expunging); - - service = CAMEL_SERVICE (parent_store); - session = camel_service_get_session (service); - - uids = camel_folder_get_uids (expunging); - - if (uids == NULL) - return TRUE; - - expunging_uids = g_hash_table_new_full ( - (GHashFunc) g_str_hash, - (GEqualFunc) g_str_equal, - (GDestroyNotify) g_free, - (GDestroyNotify) g_free); - - for (ii = 0; ii < uids->len; ii++) { - CamelMessageInfo *info; - CamelMessageFlags flags = 0; - CamelMimeMessage *message; - const gchar *pop3_uid; - const gchar *source_uid; - - info = camel_folder_get_message_info ( - expunging, uids->pdata[ii]); - - if (info != NULL) { - flags = camel_message_info_flags (info); - camel_folder_free_message_info (expunging, info); - } - - /* Only interested in deleted messages. */ - if ((flags & CAMEL_MESSAGE_DELETED) == 0) - continue; - - /* because the UID in the local store doesn't - * match with the UID in the pop3 store */ - message = camel_folder_get_message_sync ( - expunging, uids->pdata[ii], cancellable, NULL); - - if (message == NULL) - continue; - - pop3_uid = camel_medium_get_header ( - CAMEL_MEDIUM (message), "X-Evolution-POP3-UID"); - source_uid = camel_mime_message_get_source (message); - - if (pop3_uid != NULL) - g_hash_table_insert ( - expunging_uids, - g_strstrip (g_strdup (pop3_uid)), - g_strstrip (g_strdup (source_uid))); - - g_object_unref (message); - } - - camel_folder_free_uids (expunging, uids); - uids = NULL; - - if (g_hash_table_size (expunging_uids) == 0) { - g_hash_table_destroy (expunging_uids); - return TRUE; - } - - for (iter = e_list_get_iterator ((EList *) e_get_account_list ()); - e_iterator_is_valid (iter); e_iterator_next (iter)) { - account = (EAccount *) e_iterator_get (iter); - - if (account->enabled && - account->source && account->source->url && - g_str_has_prefix (account->source->url, "pop://")) { - CamelFolder *folder; - CamelService *service; - CamelSettings *settings; - gboolean any_found = FALSE, delete_expunged = FALSE, keep_on_server = FALSE; - - service = camel_session_get_service ( - session, account->uid); - - if (!CAMEL_IS_STORE (service)) - continue; - - settings = camel_service_get_settings (service); - if (!settings) - continue; - - g_object_get ( - settings, - "delete-expunged", &delete_expunged, - "keep-on-server", &keep_on_server, - NULL); - - if (!keep_on_server || !delete_expunged) - continue; - - folder = e_mail_session_get_inbox_sync ( - E_MAIL_SESSION (session), - account->uid, cancellable, error); - - /* Abort the loop on error. */ - if (folder == NULL) { - success = FALSE; - break; - } - - uids = camel_folder_get_uids (folder); - if (uids) { - for (ii = 0; ii < uids->len; ii++) { - /* ensure the ID is from this account, - * as it's generated by evolution */ - const gchar *source_uid; - - source_uid = g_hash_table_lookup ( - expunging_uids, uids->pdata[ii]); - if (folder_is_from_source_uid (folder, source_uid)) { - any_found = TRUE; - camel_folder_delete_message (folder, uids->pdata[ii]); - } - } - camel_folder_free_uids (folder, uids); - } - - if (any_found) - success = camel_folder_synchronize_sync (folder, TRUE, cancellable, error); - - g_object_unref (folder); - - /* Abort the loop on error. */ - if (!success) - break; - } - } - - if (iter) - g_object_unref (iter); - - g_hash_table_destroy (expunging_uids); - - return success; -} - -static gchar * -expunge_folder_desc (struct _sync_folder_msg *m) -{ - return g_strdup_printf ( - _("Expunging folder '%s'"), - camel_folder_get_full_name (m->folder)); -} - -static void -expunge_folder_exec (struct _sync_folder_msg *m, - GCancellable *cancellable, - GError **error) -{ - CamelFolder *local_inbox; - CamelStore *parent_store; - CamelService *service; - CamelSession *session; - gboolean is_local_inbox_or_trash; - gboolean store_is_local; - gboolean success = TRUE; - const gchar *uid; - - parent_store = camel_folder_get_parent_store (m->folder); - - service = CAMEL_SERVICE (parent_store); - session = camel_service_get_session (service); - - uid = camel_service_get_uid (service); - store_is_local = (g_strcmp0 (uid, E_MAIL_SESSION_LOCAL_UID) == 0); - - local_inbox = - e_mail_session_get_local_folder ( - E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_INBOX); - is_local_inbox_or_trash = (m->folder == local_inbox); - - if (store_is_local && !is_local_inbox_or_trash) { - CamelFolder *trash; - - trash = camel_store_get_trash_folder_sync ( - parent_store, cancellable, error); - - if (trash == NULL) - return; - - is_local_inbox_or_trash = (m->folder == trash); - - g_object_unref (trash); - } - - /* do this before expunge, to know which messages will be expunged */ - if (is_local_inbox_or_trash) - success = expunge_pop3_stores (m->folder, cancellable, error); - - if (success) - camel_folder_expunge_sync (m->folder, cancellable, error); -} - -/* we just use the sync stuff where we can, since it would be the same */ -static MailMsgInfo expunge_folder_info = { - sizeof (struct _sync_folder_msg), - (MailMsgDescFunc) expunge_folder_desc, - (MailMsgExecFunc) expunge_folder_exec, - (MailMsgDoneFunc) sync_folder_done, - (MailMsgFreeFunc) sync_folder_free -}; - -void -mail_expunge_folder (CamelFolder *folder) -{ - struct _sync_folder_msg *m; - - g_return_if_fail (CAMEL_IS_FOLDER (folder)); - - m = mail_msg_new (&expunge_folder_info); - m->folder = g_object_ref (folder); - - mail_msg_slow_ordered_push (m); -} - -/* ******************************************************************************** */ - -struct _empty_trash_msg { - MailMsg base; - - CamelStore *store; -}; - -static gchar * -empty_trash_desc (struct _empty_trash_msg *m) -{ - CamelService *service; - const gchar *display_name; - - service = CAMEL_SERVICE (m->store); - display_name = camel_service_get_display_name (service); - - return g_strdup_printf ( - _("Emptying trash in '%s'"), display_name); -} - -static void -empty_trash_exec (struct _empty_trash_msg *m, - GCancellable *cancellable, - GError **error) -{ - CamelService *service; - CamelFolder *trash; - const gchar *uid; - gboolean success = TRUE; - - service = CAMEL_SERVICE (m->store); - uid = camel_service_get_uid (service); - - if (!em_utils_connect_service_sync (service, cancellable, error)) - return; - - trash = camel_store_get_trash_folder_sync ( - m->store, cancellable, error); - - if (trash == NULL) - return; - - /* do this before expunge, to know which messages will be expunged */ - if (g_strcmp0 (uid, E_MAIL_SESSION_LOCAL_UID) == 0) - success = expunge_pop3_stores (trash, cancellable, error); - - if (success) - camel_folder_expunge_sync (trash, cancellable, error); - - g_object_unref (trash); -} - -static void -empty_trash_done (struct _empty_trash_msg *m) -{ -} - -static void -empty_trash_free (struct _empty_trash_msg *m) -{ - if (m->store) - g_object_unref (m->store); -} - -static MailMsgInfo empty_trash_info = { - sizeof (struct _empty_trash_msg), - (MailMsgDescFunc) empty_trash_desc, - (MailMsgExecFunc) empty_trash_exec, - (MailMsgDoneFunc) empty_trash_done, - (MailMsgFreeFunc) empty_trash_free -}; - -void -mail_empty_trash (CamelStore *store) -{ - struct _empty_trash_msg *m; - - g_return_if_fail (CAMEL_IS_STORE (store)); - - m = mail_msg_new (&empty_trash_info); - m->store = g_object_ref (store); - - mail_msg_slow_ordered_push (m); -} - -/* ** Execute Shell Command ************************************************ */ - -void -mail_execute_shell_command (CamelFilterDriver *driver, - gint argc, - gchar **argv, - gpointer data) -{ - if (argc <= 0) - return; - - g_spawn_async (NULL, argv, NULL, 0, NULL, data, NULL, NULL); -} - -/* ------------------------------------------------------------------------- */ - -struct _disconnect_msg { - MailMsg base; - - CamelStore *store; -}; - -static gchar * -disconnect_service_desc (struct _disconnect_msg *m) -{ - gchar *name, *res; - - name = camel_service_get_name (CAMEL_SERVICE (m->store), TRUE); - res = g_strdup_printf (_("Disconnecting %s"), name ? name : ""); - g_free (name); - - return res; -} - -static void -disconnect_service_exec (struct _disconnect_msg *m, - GCancellable *cancellable, - GError **error) -{ - em_utils_disconnect_service_sync ( - CAMEL_SERVICE (m->store), TRUE, cancellable, error); -} - -static void -disconnect_service_free (struct _disconnect_msg *m) -{ - g_object_unref (m->store); -} - -static MailMsgInfo disconnect_service_info = { - sizeof (struct _disconnect_msg), - (MailMsgDescFunc) disconnect_service_desc, - (MailMsgExecFunc) disconnect_service_exec, - (MailMsgDoneFunc) NULL, - (MailMsgFreeFunc) disconnect_service_free -}; - -gint -mail_disconnect_store (CamelStore *store) -{ - struct _disconnect_msg *m; - gint id; - - g_return_val_if_fail (store != NULL, -1); - - m = mail_msg_new (&disconnect_service_info); - m->store = g_object_ref (store); - - id = m->base.seq; - mail_msg_unordered_push (m); - - return id; -} diff --git a/mail/mail-ops.h b/mail/mail-ops.h deleted file mode 100644 index b8eb184c7e..0000000000 --- a/mail/mail-ops.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see - * - * - * Authors: - * Peter Williams - * Michael Zucchi - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef MAIL_OPS_H -#define MAIL_OPS_H - -G_BEGIN_DECLS - -#include - -#include -#include - -void mail_transfer_messages (EMailSession *session, - CamelFolder *source, - GPtrArray *uids, - gboolean delete_from_source, - const gchar *dest_uri, - guint32 dest_flags, - void (*done) (gboolean ok, gpointer data), - gpointer data); - -void mail_sync_folder (CamelFolder *folder, - void (*done) (CamelFolder *folder, gpointer data), gpointer data); - -void mail_sync_store (CamelStore *store, gint expunge, - void (*done) (CamelStore *store, gpointer data), gpointer data); - -void mail_refresh_folder (CamelFolder *folder, - void (*done) (CamelFolder *folder, gpointer data), - gpointer data); - -void mail_expunge_folder (CamelFolder *folder); -void mail_empty_trash (CamelStore *store); - -/* transfer (copy/move) a folder */ -void mail_xfer_folder (const gchar *src_uri, const gchar *dest_uri, gboolean remove_source, - void (*done) (gchar *src_uri, gchar *dest_uri, gboolean remove_source, - CamelFolder *folder, gpointer data), - gpointer data); - -/* yeah so this is messy, but it does a lot, maybe i can consolidate all user_data's to be the one */ -void mail_send_queue (EMailSession *session, - CamelFolder *queue, - CamelTransport *transport, - const gchar *type, - GCancellable *cancellable, - CamelFilterGetFolderFunc get_folder, - gpointer get_data, - CamelFilterStatusFunc *status, - gpointer status_data, - void (*done)(gpointer data), - gpointer data); - -void mail_fetch_mail (CamelStore *store, - gint keep, - const gchar *type, - GCancellable *cancellable, - CamelFilterGetFolderFunc get_folder, - gpointer get_data, - CamelFilterStatusFunc *status, - gpointer status_data, - void (*done)(gpointer data), - gpointer data); - -void mail_filter_folder (EMailSession *session, - CamelFolder *source_folder, - GPtrArray *uids, - const gchar *type, - gboolean notify); - -/* filter driver execute shell command async callback */ -void mail_execute_shell_command (CamelFilterDriver *driver, gint argc, gchar **argv, gpointer data); - -gint mail_disconnect_store (CamelStore *store); - -G_END_DECLS - -#endif /* MAIL_OPS_H */ diff --git a/mail/mail-send-recv.c b/mail/mail-send-recv.c index 4e206ea221..05a48c47ce 100644 --- a/mail/mail-send-recv.c +++ b/mail/mail-send-recv.c @@ -29,22 +29,26 @@ #include -#include "libedataserver/e-account-list.h" +#include -#include "shell/e-shell.h" -#include "e-util/e-account-utils.h" -#include "e-util/e-util.h" +#include +#include -#include "e-mail-folder-utils.h" -#include "e-mail-session.h" +#include +#include + +#include +#include +#include +#include +#include + +#include "e-mail-account-store.h" +#include "e-mail-ui-session.h" #include "em-event.h" #include "em-filter-rule.h" #include "em-utils.h" -#include "mail-folder-cache.h" -#include "mail-mt.h" -#include "mail-ops.h" #include "mail-send-recv.h" -#include "mail-tools.h" #define d(x) @@ -501,7 +505,7 @@ build_dialog (GtkWindow *parent, EMEventTargetSendReceive *target; GQueue queue = G_QUEUE_INIT; - account_store = e_mail_session_get_account_store (session); + account_store = e_mail_ui_session_get_account_store (E_MAIL_UI_SESSION (session)); /* Convert the outgoing account to a CamelTransport. */ if (outgoing_account != NULL) { diff --git a/mail/mail-send-recv.h b/mail/mail-send-recv.h index cd11a4a9bb..fb49493060 100644 --- a/mail/mail-send-recv.h +++ b/mail/mail-send-recv.h @@ -24,7 +24,7 @@ #define MAIL_SEND_RECV_H #include -#include +#include G_BEGIN_DECLS diff --git a/mail/mail-tools.c b/mail/mail-tools.c deleted file mode 100644 index 30ac175a18..0000000000 --- a/mail/mail-tools.c +++ /dev/null @@ -1,245 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see - * - * - * Authors: - * Dan Winship - * Peter Williams - * Jeffrey Stedfast - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include "e-mail-session.h" -#include "em-utils.h" -#include "mail-folder-cache.h" -#include "mail-tools.h" - -/* **************************************** */ - -#ifndef G_OS_WIN32 - -static gchar * -mail_tool_get_local_movemail_path (CamelStore *store, - GError **error) -{ - const gchar *uid; - guchar *safe_uid, *c; - const gchar *data_dir; - gchar *path, *full; - struct stat st; - - uid = camel_service_get_uid (CAMEL_SERVICE (store)); - safe_uid = (guchar *) g_strdup ((const gchar *) uid); - for (c = safe_uid; *c; c++) - if (strchr("/:;=|%&#!*^()\\, ", *c) || !isprint((gint) *c)) - *c = '_'; - - data_dir = mail_session_get_data_dir (); - path = g_build_filename (data_dir, "spool", NULL); - - if (g_stat (path, &st) == -1 && g_mkdir_with_parents (path, 0700) == -1) { - g_set_error ( - error, G_FILE_ERROR, - g_file_error_from_errno (errno), - _("Could not create spool directory '%s': %s"), - path, g_strerror (errno)); - g_free (path); - return NULL; - } - - full = g_strdup_printf("%s/movemail.%s", path, safe_uid); - g_free (path); - g_free (safe_uid); - - return full; -} - -#endif - -gchar * -mail_tool_do_movemail (CamelStore *store, - GError **error) -{ -#ifndef G_OS_WIN32 - CamelService *service; - CamelProvider *provider; - CamelSettings *settings; - const gchar *src_path; - gchar *dest_path; - struct stat sb; - gboolean success; - - g_return_val_if_fail (CAMEL_IS_STORE (store), NULL); - - service = CAMEL_SERVICE (store); - provider = camel_service_get_provider (service); - settings = camel_service_get_settings (service); - - g_return_val_if_fail (provider != NULL, NULL); - - if (g_strcmp0 (provider->protocol, "mbox") != 0) { - /* This is really only an internal error anyway */ - g_set_error ( - error, CAMEL_SERVICE_ERROR, - CAMEL_SERVICE_ERROR_URL_INVALID, - _("Trying to movemail a non-mbox source '%s'"), - camel_service_get_uid (CAMEL_SERVICE (store))); - return NULL; - } - - src_path = camel_local_settings_get_path ( - CAMEL_LOCAL_SETTINGS (settings)); - - /* Set up our destination. */ - dest_path = mail_tool_get_local_movemail_path (store, error); - if (dest_path == NULL) - return NULL; - - /* Movemail from source to dest_path */ - success = camel_movemail (src_path, dest_path, error) != -1; - - if (g_stat (dest_path, &sb) < 0 || sb.st_size == 0) { - g_unlink (dest_path); /* Clean up the movemail.foo file. */ - g_free (dest_path); - return NULL; - } - - if (!success) { - g_free (dest_path); - return NULL; - } - - return dest_path; -#else - /* Unclear yet whether camel-movemail etc makes any sense on - * Win32, at least it is not ported yet. - */ - g_warning("%s: Not implemented", __FUNCTION__); - return NULL; -#endif -} - -gchar * -mail_tool_generate_forward_subject (CamelMimeMessage *msg) -{ - const gchar *subject; - gchar *fwd_subj; - const gint max_subject_length = 1024; - - subject = camel_mime_message_get_subject (msg); - - if (subject && *subject) { - /* Truncate insanely long subjects */ - if (strlen (subject) < max_subject_length) { - fwd_subj = g_strdup_printf ("[Fwd: %s]", subject); - } else { - /* We can't use %.*s because it depends on the - * locale being C/POSIX or UTF-8 to work correctly - * in glibc. */ - fwd_subj = g_malloc (max_subject_length + 11); - memcpy (fwd_subj, "[Fwd: ", 6); - memcpy (fwd_subj + 6, subject, max_subject_length); - memcpy (fwd_subj + 6 + max_subject_length, "...]", 5); - } - } else { - const CamelInternetAddress *from; - gchar *fromstr; - - from = camel_mime_message_get_from (msg); - if (from) { - fromstr = camel_address_format (CAMEL_ADDRESS (from)); - fwd_subj = g_strdup_printf ("[Fwd: %s]", fromstr); - g_free (fromstr); - } else - fwd_subj = g_strdup ("[Fwd: No Subject]"); - } - - return fwd_subj; -} - -struct _camel_header_raw * -mail_tool_remove_xevolution_headers (CamelMimeMessage *message) -{ - struct _camel_header_raw *scan, *list = NULL; - - for (scan = ((CamelMimePart *) message)->headers; scan; scan = scan->next) - if (!strncmp(scan->name, "X-Evolution", 11)) - camel_header_raw_append (&list, scan->name, scan->value, scan->offset); - - for (scan = list; scan; scan = scan->next) - camel_medium_remove_header ((CamelMedium *) message, scan->name); - - return list; -} - -void -mail_tool_restore_xevolution_headers (CamelMimeMessage *message, - struct _camel_header_raw *xev) -{ - CamelMedium *medium; - - medium = CAMEL_MEDIUM (message); - - for (; xev; xev = xev->next) - camel_medium_add_header (medium, xev->name, xev->value); -} - -CamelMimePart * -mail_tool_make_message_attachment (CamelMimeMessage *message) -{ - CamelMimePart *part; - const gchar *subject; - struct _camel_header_raw *xev; - gchar *desc; - - subject = camel_mime_message_get_subject (message); - if (subject) - desc = g_strdup_printf (_("Forwarded message - %s"), subject); - else - desc = g_strdup (_("Forwarded message")); - - /* rip off the X-Evolution headers */ - xev = mail_tool_remove_xevolution_headers (message); - camel_header_raw_clear (&xev); - - /* remove Bcc headers */ - camel_medium_remove_header (CAMEL_MEDIUM (message), "Bcc"); - - part = camel_mime_part_new (); - camel_mime_part_set_disposition (part, "inline"); - camel_mime_part_set_description (part, desc); - camel_medium_set_content ( - CAMEL_MEDIUM (part), CAMEL_DATA_WRAPPER (message)); - camel_mime_part_set_content_type (part, "message/rfc822"); - g_free (desc); - - return part; -} diff --git a/mail/mail-tools.h b/mail/mail-tools.h deleted file mode 100644 index 94b19c0d12..0000000000 --- a/mail/mail-tools.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see - * - * - * Authors: - * Peter Williams - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef MAIL_TOOLS_H -#define MAIL_TOOLS_H - -#include - -/* Does a camel_movemail into the local movemail folder - * and returns the path to the new movemail folder that was created. which shoudl be freed later */ -gchar *mail_tool_do_movemail (CamelStore *store, GError **error); - -struct _camel_header_raw *mail_tool_remove_xevolution_headers (CamelMimeMessage *message); -void mail_tool_restore_xevolution_headers (CamelMimeMessage *message, struct _camel_header_raw *); - -/* Generates the subject for a message forwarding @msg */ -gchar *mail_tool_generate_forward_subject (CamelMimeMessage *msg); - -/* Make a message into an attachment */ -CamelMimePart *mail_tool_make_message_attachment (CamelMimeMessage *message); - -#endif diff --git a/mail/mail-vfolder.c b/mail/mail-vfolder.c index f5039d98ff..4b10e829de 100644 --- a/mail/mail-vfolder.c +++ b/mail/mail-vfolder.c @@ -31,20 +31,23 @@ #include "e-util/e-alert-dialog.h" #include "e-util/e-util-private.h" +#include "libemail-utils/mail-mt.h" +#include "libemail-engine/mail-folder-cache.h" +#include "libemail-engine/e-mail-folder-utils.h" +#include "libemail-engine/e-mail-session.h" +#include "libemail-engine/e-mail-utils.h" +#include "libemail-engine/mail-ops.h" +#include "libemail-engine/mail-tools.h" + #include "e-mail-backend.h" -#include "e-mail-session.h" -#include "e-mail-folder-utils.h" #include "em-folder-tree-model.h" #include "em-utils.h" #include "em-vfolder-context.h" #include "em-vfolder-editor.h" #include "em-vfolder-rule.h" #include "mail-autofilter.h" -#include "mail-folder-cache.h" -#include "mail-mt.h" -#include "mail-ops.h" -#include "mail-tools.h" #include "mail-vfolder.h" +#include "e-mail-ui-session.h" #define d(x) /* (printf("%s:%s: ", G_STRLOC, G_STRFUNC), (x))*/ @@ -1020,7 +1023,7 @@ vfolder_load_storage (EMailBackend *backend) config_dir = mail_session_get_config_dir (); session = e_mail_backend_get_session (backend); - vfolder_store = e_mail_session_get_vfolder_store (session); + vfolder_store = e_mail_ui_session_get_vfolder_store (E_MAIL_UI_SESSION(session)); g_signal_connect ( vfolder_store, "folder-deleted", diff --git a/mail/message-list.c b/mail/message-list.c index 98fd90babb..405e9d08cd 100644 --- a/mail/message-list.c +++ b/mail/message-list.c @@ -58,13 +58,16 @@ #include "table/e-tree-memory-callbacks.h" #include "table/e-tree-memory.h" -#include "e-mail-label-list-store.h" -#include "em-utils.h" -#include "mail-config.h" -#include "mail-mt.h" -#include "mail-ops.h" -#include "mail-tools.h" -#include "message-list.h" +#include "libemail-utils/mail-mt.h" +#include "libemail-engine/e-mail-utils.h" +#include "libemail-engine/mail-config.h" +#include "libemail-engine/mail-ops.h" +#include "libemail-engine/mail-tools.h" + +#include "mail/e-mail-label-list-store.h" +#include "mail/e-mail-ui-session.h" +#include "mail/em-utils.h" +#include "mail/message-list.h" #if HAVE_CLUTTER #include @@ -1709,7 +1712,8 @@ ml_tree_value_at_ex (ETreeModel *etm, /* Get all applicable labels. */ struct LabelsData ld; - ld.store = e_mail_session_get_label_store (session); + ld.store = e_mail_ui_session_get_label_store ( + E_MAIL_UI_SESSION (session)); ld.labels_tag2iter = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) gtk_tree_iter_free); for_node_and_subtree_if_collapsed (message_list, path, msg_info, add_all_labels_foreach, &ld); @@ -1791,7 +1795,8 @@ ml_tree_value_at_ex (ETreeModel *etm, struct LabelsData ld; GString *result = g_string_new (""); - ld.store = e_mail_session_get_label_store (session); + ld.store = e_mail_ui_session_get_label_store ( + E_MAIL_UI_SESSION (session)); ld.labels_tag2iter = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) gtk_tree_iter_free); for_node_and_subtree_if_collapsed (message_list, path, msg_info, add_all_labels_foreach, &ld); @@ -4764,7 +4769,7 @@ regen_list_done (struct _regen_list_msg *m) GCancellable *cancellable; gboolean searching; - cancellable = e_activity_get_cancellable (m->base.activity); + cancellable = m->base.cancellable; if (m->ml->priv->destroyed) return; @@ -4956,7 +4961,7 @@ mail_regen_cancel (MessageList *ml) MailMsg *mm = link->data; GCancellable *cancellable; - cancellable = e_activity_get_cancellable (mm->activity); + cancellable = mm->cancellable; g_cancellable_cancel (cancellable); } diff --git a/mail/message-list.h b/mail/message-list.h index bd2e97b6f8..44a312e667 100644 --- a/mail/message-list.h +++ b/mail/message-list.h @@ -27,7 +27,7 @@ #include #include -#include +#include /* Standard GObject macros */ #define MESSAGE_LIST_TYPE \ diff --git a/modules/bogofilter/Makefile.am b/modules/bogofilter/Makefile.am index 5fbf45e5b4..2d8f5c9fd2 100644 --- a/modules/bogofilter/Makefile.am +++ b/modules/bogofilter/Makefile.am @@ -14,6 +14,8 @@ libevolution_module_bogofilter_la_SOURCES = \ libevolution_module_bogofilter_la_LIBADD = \ $(top_builddir)/e-util/libeutil.la \ $(top_builddir)/mail/libevolution-mail.la \ + $(top_builddir)/libemail-engine/libemail-engine.la \ + $(top_builddir)/libemail-utils/libemail-utils.la \ $(EVOLUTION_DATA_SERVER_LIBS) \ $(GNOME_PLATFORM_LIBS) diff --git a/modules/bogofilter/evolution-bogofilter.c b/modules/bogofilter/evolution-bogofilter.c index 74c1d362ca..0467c0f654 100644 --- a/modules/bogofilter/evolution-bogofilter.c +++ b/modules/bogofilter/evolution-bogofilter.c @@ -23,7 +23,7 @@ #include -#include +#include /* Standard GObject macros */ #define E_TYPE_BOGOFILTER \ diff --git a/modules/calendar/Makefile.am b/modules/calendar/Makefile.am index 4f09f92692..57b697b0df 100644 --- a/modules/calendar/Makefile.am +++ b/modules/calendar/Makefile.am @@ -89,6 +89,7 @@ libevolution_module_calendar_la_LIBADD = \ $(top_builddir)/mail/libevolution-mail.la \ $(top_builddir)/addressbook/gui/contact-editor/libecontacteditor.la \ $(top_builddir)/addressbook/gui/contact-list-editor/libecontactlisteditor.la \ + $(top_builddir)/libemail-utils/libemail-utils.la \ $(top_builddir)/e-util/libeutil.la \ $(top_builddir)/filter/libfilter.la \ $(top_builddir)/widgets/menus/libmenus.la \ diff --git a/modules/calendar/e-cal-shell-view-private.h b/modules/calendar/e-cal-shell-view-private.h index 27aaca6e9e..ad4984a4ef 100644 --- a/modules/calendar/e-cal-shell-view-private.h +++ b/modules/calendar/e-cal-shell-view-private.h @@ -26,6 +26,7 @@ #include #include + #include #include #include @@ -33,31 +34,34 @@ #include #include -#include "e-util/e-account-utils.h" -#include "e-util/e-selection.h" -#include "e-util/e-dialog-utils.h" -#include "e-util/e-file-utils.h" -#include "e-util/e-util.h" -#include "shell/e-shell-utils.h" -#include "misc/e-popup-action.h" -#include "misc/e-selectable.h" - -#include "calendar/gui/calendar-config.h" -#include "calendar/gui/comp-util.h" -#include "calendar/gui/e-cal-list-view.h" -#include "calendar/gui/e-cal-model-tasks.h" -#include "calendar/gui/e-calendar-view.h" -#include "calendar/gui/e-day-view.h" -#include "calendar/gui/e-week-view.h" -#include "calendar/gui/gnome-cal.h" -#include "calendar/gui/print.h" -#include "calendar/gui/dialogs/calendar-setup.h" -#include "calendar/gui/dialogs/copy-source-dialog.h" -#include "calendar/gui/dialogs/event-editor.h" -#include "calendar/gui/dialogs/goto-dialog.h" -#include "calendar/gui/dialogs/memo-editor.h" -#include "calendar/gui/dialogs/select-source-dialog.h" -#include "calendar/gui/dialogs/task-editor.h" +#include +#include +#include +#include + +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "e-cal-shell-backend.h" #include "e-cal-shell-content.h" diff --git a/modules/calendar/e-memo-shell-migrate.c b/modules/calendar/e-memo-shell-migrate.c index 6402cf1e0a..171428f408 100644 --- a/modules/calendar/e-memo-shell-migrate.c +++ b/modules/calendar/e-memo-shell-migrate.c @@ -28,13 +28,14 @@ #include #include #include + #include #include #include -#include "e-util/e-account-utils.h" -#include "calendar/gui/calendar-config-keys.h" -#include "shell/e-shell.h" +#include +#include +#include #include "e-memo-shell-backend.h" diff --git a/modules/mail/Makefile.am b/modules/mail/Makefile.am index 90cf1aa54f..7fbb354b26 100644 --- a/modules/mail/Makefile.am +++ b/modules/mail/Makefile.am @@ -3,7 +3,6 @@ module_LTLIBRARIES = libevolution-module-mail.la libevolution_module_mail_la_CPPFLAGS = \ $(AM_CPPFLAGS) \ -I$(top_srcdir) \ - -I$(top_srcdir)/mail \ -I$(top_srcdir)/widgets \ -DEVOLUTION_ETSPECDIR=\""$(etspecdir)"\" \ -DEVOLUTION_UIDIR=\""$(uidir)"\" \ @@ -51,6 +50,8 @@ libevolution_module_mail_la_SOURCES = \ em-network-prefs.h libevolution_module_mail_la_LIBADD = \ + $(top_builddir)/libemail-utils/libemail-utils.la \ + $(top_builddir)/libemail-engine/libemail-engine.la \ $(top_builddir)/e-util/libeutil.la \ $(top_builddir)/em-format/libemformat.la \ $(top_builddir)/filter/libfilter.la \ diff --git a/modules/mail/e-mail-shell-backend.c b/modules/mail/e-mail-shell-backend.c index d15ca1ebe8..4e28d8c629 100644 --- a/modules/mail/e-mail-shell-backend.c +++ b/modules/mail/e-mail-shell-backend.c @@ -27,37 +27,42 @@ #include -#include "e-util/e-import.h" -#include "e-util/e-util.h" -#include "shell/e-shell.h" -#include "shell/e-shell-window.h" -#include "composer/e-msg-composer.h" -#include "widgets/misc/e-preferences-window.h" -#include "widgets/misc/e-web-view.h" +#include +#include + +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "e-mail-shell-settings.h" #include "e-mail-shell-sidebar.h" #include "e-mail-shell-view.h" - -#include "e-mail-browser.h" -#include "e-mail-folder-utils.h" -#include "e-mail-reader.h" -#include "e-mail-session.h" -#include "em-account-editor.h" #include "em-account-prefs.h" #include "em-composer-prefs.h" -#include "em-composer-utils.h" -#include "em-folder-utils.h" -#include "em-format-hook.h" -#include "em-format-html-display.h" #include "em-mailer-prefs.h" #include "em-network-prefs.h" -#include "em-utils.h" -#include "mail-config.h" -#include "mail-ops.h" -#include "mail-send-recv.h" -#include "mail-vfolder.h" -#include "importers/mail-importer.h" #define E_MAIL_SHELL_BACKEND_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE \ @@ -471,7 +476,7 @@ mail_shell_backend_start (EShellBackend *shell_backend) backend = E_MAIL_BACKEND (shell_backend); session = e_mail_backend_get_session (backend); - account_store = e_mail_session_get_account_store (session); + account_store = e_mail_ui_session_get_account_store (E_MAIL_UI_SESSION (session)); enable_search_folders = e_shell_settings_get_boolean ( shell_settings, "mail-enable-search-folders"); @@ -646,7 +651,8 @@ e_mail_labels_get_filter_options (void) backend = E_MAIL_BACKEND (shell_backend); session = e_mail_backend_get_session (backend); - label_store = e_mail_session_get_label_store (session); + label_store = e_mail_ui_session_get_label_store ( + E_MAIL_UI_SESSION (session)); model = GTK_TREE_MODEL (label_store); valid = gtk_tree_model_get_iter_first (model, &iter); diff --git a/modules/mail/e-mail-shell-content.c b/modules/mail/e-mail-shell-content.c index 56a0c52de6..5bb60e3784 100644 --- a/modules/mail/e-mail-shell-content.c +++ b/modules/mail/e-mail-shell-content.c @@ -28,21 +28,23 @@ #include #include -#include "e-util/e-util-private.h" -#include "widgets/menus/gal-view-etable.h" -#include "widgets/menus/gal-view-instance.h" -#include "widgets/misc/e-paned.h" -#include "widgets/misc/e-preview-pane.h" -#include "widgets/misc/e-search-bar.h" - -#include "em-utils.h" -#include "mail-ops.h" -#include "message-list.h" - -#include "e-mail-paned-view.h" -#include "e-mail-notebook-view.h" -#include "e-mail-reader.h" -#include "e-mail-reader-utils.h" +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + #include "e-mail-shell-backend.h" #include "e-mail-shell-view-actions.h" diff --git a/modules/mail/e-mail-shell-view-actions.c b/modules/mail/e-mail-shell-view-actions.c index 26bcfc4bb8..407f17ef78 100644 --- a/modules/mail/e-mail-shell-view-actions.c +++ b/modules/mail/e-mail-shell-view-actions.c @@ -99,7 +99,7 @@ action_mail_account_disable_cb (GtkAction *action, backend = E_MAIL_BACKEND (shell_backend); session = e_mail_backend_get_session (backend); - account_store = e_mail_session_get_account_store (session); + account_store = e_mail_ui_session_get_account_store (E_MAIL_UI_SESSION (session)); folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar); store = em_folder_tree_get_selected_store (folder_tree); @@ -709,7 +709,8 @@ action_mail_label_new_cb (GtkAction *action, backend = E_MAIL_BACKEND (shell_backend); session = e_mail_backend_get_session (backend); - label_store = e_mail_session_get_label_store (session); + label_store = e_mail_ui_session_get_label_store ( + E_MAIL_UI_SESSION (session)); label_dialog = E_MAIL_LABEL_DIALOG (dialog); label_name = e_mail_label_dialog_get_label_name (label_dialog); @@ -770,7 +771,8 @@ action_mail_label_none_cb (GtkAction *action, backend = E_MAIL_BACKEND (shell_backend); session = e_mail_backend_get_session (backend); - label_store = e_mail_session_get_label_store (session); + label_store = e_mail_ui_session_get_label_store ( + E_MAIL_UI_SESSION (session)); mail_shell_content = mail_shell_view->priv->mail_shell_content; mail_view = e_mail_shell_content_get_mail_view (mail_shell_content); @@ -1919,7 +1921,8 @@ e_mail_shell_view_update_popup_labels (EMailShellView *mail_shell_view) backend = E_MAIL_BACKEND (shell_backend); session = e_mail_backend_get_session (backend); - label_store = e_mail_session_get_label_store (session); + label_store = e_mail_ui_session_get_label_store ( + E_MAIL_UI_SESSION (session)); action_group = ACTION_GROUP (MAIL_LABEL); merge_id = mail_shell_view->priv->label_merge_id; @@ -2021,7 +2024,8 @@ e_mail_shell_view_update_search_filter (EMailShellView *mail_shell_view) backend = E_MAIL_BACKEND (shell_backend); session = e_mail_backend_get_session (backend); - label_store = e_mail_session_get_label_store (session); + label_store = e_mail_ui_session_get_label_store ( + E_MAIL_UI_SESSION (session)); action_group = ACTION_GROUP (MAIL_FILTER); e_action_group_remove_all_actions (action_group); diff --git a/modules/mail/e-mail-shell-view-private.c b/modules/mail/e-mail-shell-view-private.c index b7e7f9575b..f43734f175 100644 --- a/modules/mail/e-mail-shell-view-private.c +++ b/modules/mail/e-mail-shell-view-private.c @@ -665,7 +665,8 @@ e_mail_shell_view_private_constructed (EMailShellView *mail_shell_view) backend = E_MAIL_BACKEND (shell_backend); session = e_mail_backend_get_session (backend); - label_store = e_mail_session_get_label_store (session); + label_store = e_mail_ui_session_get_label_store ( + E_MAIL_UI_SESSION (session)); e_shell_window_add_action_group (shell_window, "mail"); e_shell_window_add_action_group (shell_window, "mail-filter"); diff --git a/modules/mail/e-mail-shell-view-private.h b/modules/mail/e-mail-shell-view-private.h index 24b5e531bf..c60d5c699e 100644 --- a/modules/mail/e-mail-shell-view-private.h +++ b/modules/mail/e-mail-shell-view-private.h @@ -28,38 +28,43 @@ #include #include /* for camel_search_word */ -#include "e-util/e-util.h" -#include "e-util/e-account-utils.h" -#include "e-util/e-ui-manager.h" -#include "filter/e-filter-part.h" -#include "widgets/misc/e-web-view.h" -#include "widgets/misc/e-popup-action.h" -#include "widgets/menus/gal-view-instance.h" - -#include "e-mail-folder-utils.h" -#include "e-mail-label-action.h" -#include "e-mail-label-dialog.h" -#include "e-mail-label-list-store.h" -#include "e-mail-reader.h" -#include "e-mail-reader-utils.h" -#include "e-mail-session.h" -#include "e-mail-session-utils.h" -#include "e-mail-sidebar.h" -#include "e-mail-store-utils.h" -#include "em-composer-utils.h" -#include "em-folder-properties.h" -#include "em-folder-selector.h" -#include "em-folder-utils.h" -#include "em-search-context.h" -#include "em-subscription-editor.h" -#include "em-utils.h" -#include "mail-autofilter.h" -#include "mail-folder-cache.h" -#include "mail-ops.h" -#include "mail-send-recv.h" -#include "mail-tools.h" -#include "mail-vfolder.h" -#include "message-list.h" +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "e-mail-shell-backend.h" #include "e-mail-shell-content.h" diff --git a/modules/mail/e-mail-shell-view.c b/modules/mail/e-mail-shell-view.c index 07fec7e45f..afd7501d92 100644 --- a/modules/mail/e-mail-shell-view.c +++ b/modules/mail/e-mail-shell-view.c @@ -269,7 +269,7 @@ mail_shell_view_execute_search (EShellView *shell_view) folder = e_mail_reader_get_folder (reader); message_list = e_mail_reader_get_message_list (reader); - label_store = e_mail_session_get_label_store (session); + label_store = e_mail_ui_session_get_label_store (E_MAIL_UI_SESSION (session)); action = ACTION (MAIL_SEARCH_SUBJECT_OR_ADDRESSES_CONTAIN); value = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (action)); diff --git a/modules/mail/em-account-prefs.c b/modules/mail/em-account-prefs.c index 24651d1131..c6b132ebbb 100644 --- a/modules/mail/em-account-prefs.c +++ b/modules/mail/em-account-prefs.c @@ -33,16 +33,20 @@ #include -#include "e-util/e-alert-dialog.h" -#include "e-util/e-account-utils.h" +#include -#include "e-mail-backend.h" -#include "em-config.h" -#include "em-account-editor.h" -#include "em-utils.h" -#include "mail-vfolder.h" -#include "shell/e-shell.h" -#include "capplet/settings/mail-capplet-shell.h" +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include #define EM_ACCOUNT_PREFS_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE \ @@ -321,7 +325,8 @@ em_account_prefs_new (EPreferencesWindow *window) backend = E_MAIL_BACKEND (shell_backend); session = e_mail_backend_get_session (backend); - account_store = e_mail_session_get_account_store (session); + account_store = e_mail_ui_session_get_account_store ( + E_MAIL_UI_SESSION (session)); return g_object_new ( EM_TYPE_ACCOUNT_PREFS, diff --git a/modules/mail/em-composer-prefs.c b/modules/mail/em-composer-prefs.c index 0dcd1116bb..e678152097 100644 --- a/modules/mail/em-composer-prefs.c +++ b/modules/mail/em-composer-prefs.c @@ -24,18 +24,14 @@ #include #endif +#include "em-composer-prefs.h" + #include #include #include #include #include -#include "e-util/e-signature-utils.h" - -#include "em-composer-prefs.h" -#include "composer/e-msg-composer.h" -#include "shell/e-shell-utils.h" - #include #include @@ -44,14 +40,21 @@ #include #include + +#include + +#include + +#include + #include #include #include #include -#include "em-config.h" -#include "em-folder-selection-button.h" -#include "e-mail-junk-options.h" +#include +#include +#include G_DEFINE_TYPE ( EMComposerPrefs, diff --git a/modules/mail/em-network-prefs.c b/modules/mail/em-network-prefs.c index 793925055a..93a12d202a 100644 --- a/modules/mail/em-network-prefs.c +++ b/modules/mail/em-network-prefs.c @@ -24,25 +24,24 @@ #include #endif +#include "em-network-prefs.h" + #include #include #include #include #include -#include "em-network-prefs.h" - +#include #include #include -#include - -#include "e-util/e-util.h" -#include "e-util/e-util-private.h" -#include "mail/e-mail-junk-options.h" +#include +#include -#include "em-config.h" -#include "em-folder-selection-button.h" +#include +#include +#include #define d(x) diff --git a/modules/mdn/evolution-mdn.c b/modules/mdn/evolution-mdn.c index fa3fd8171c..d0a1e6d6ee 100644 --- a/modules/mdn/evolution-mdn.c +++ b/modules/mdn/evolution-mdn.c @@ -23,13 +23,15 @@ #include #include -#include + +#include + +#include #include #include #include #include -#include #define MDN_USER_FLAG "receipt-handled" diff --git a/modules/online-accounts/Makefile.am b/modules/online-accounts/Makefile.am index ccb7ada29a..f449247ec9 100644 --- a/modules/online-accounts/Makefile.am +++ b/modules/online-accounts/Makefile.am @@ -18,6 +18,7 @@ libevolution_module_online_accounts_la_SOURCES = \ libevolution_module_online_accounts_la_LIBADD = \ $(top_builddir)/e-util/libeutil.la \ $(top_builddir)/shell/libeshell.la \ + $(top_builddir)/libemail-utils/libemail-utils.la \ $(EVOLUTION_DATA_SERVER_LIBS) \ $(GNOME_PLATFORM_LIBS) \ $(GOA_LIBS) diff --git a/modules/online-accounts/camel-sasl-xoauth.c b/modules/online-accounts/camel-sasl-xoauth.c index edf5c6eec3..7b1a59aa24 100644 --- a/modules/online-accounts/camel-sasl-xoauth.c +++ b/modules/online-accounts/camel-sasl-xoauth.c @@ -20,11 +20,11 @@ #include #endif -#include +#include -#include "camel-sasl-xoauth.h" +#include -#include +#include "camel-sasl-xoauth.h" #define GOA_API_IS_SUBJECT_TO_CHANGE #include diff --git a/modules/online-accounts/e-online-accounts-google.c b/modules/online-accounts/e-online-accounts-google.c index e71b8d16cb..709eb3bb8e 100644 --- a/modules/online-accounts/e-online-accounts-google.c +++ b/modules/online-accounts/e-online-accounts-google.c @@ -29,7 +29,7 @@ #include #include -#include +#include /* This is the property name or URL parameter under which we * embed the GoaAccount ID into an EAccount or ESource object. */ diff --git a/modules/online-accounts/evolution-online-accounts.c b/modules/online-accounts/evolution-online-accounts.c index d127f4d096..6efeaba33e 100644 --- a/modules/online-accounts/evolution-online-accounts.c +++ b/modules/online-accounts/evolution-online-accounts.c @@ -30,7 +30,8 @@ #include #include -#include + +#include #include "camel-sasl-xoauth.h" #include "e-online-accounts-google.h" diff --git a/modules/spamassassin/Makefile.am b/modules/spamassassin/Makefile.am index 8ea91303b4..fce8989566 100644 --- a/modules/spamassassin/Makefile.am +++ b/modules/spamassassin/Makefile.am @@ -14,6 +14,8 @@ libevolution_module_spamassassin_la_LIBADD = \ $(top_builddir)/e-util/libeutil.la \ $(top_builddir)/mail/libevolution-mail.la \ $(top_builddir)/shell/libeshell.la \ + $(top_builddir)/libemail-engine/libemail-engine.la \ + $(top_builddir)/libemail-utils/libemail-utils.la \ $(EVOLUTION_DATA_SERVER_LIBS) \ $(GNOME_PLATFORM_LIBS) diff --git a/modules/spamassassin/evolution-spamassassin.c b/modules/spamassassin/evolution-spamassassin.c index 1b88d0f558..7f595caf32 100644 --- a/modules/spamassassin/evolution-spamassassin.c +++ b/modules/spamassassin/evolution-spamassassin.c @@ -25,7 +25,7 @@ #include #include -#include +#include /* Standard GObject macros */ #define E_TYPE_SPAM_ASSASSIN \ diff --git a/modules/startup-wizard/Makefile.am b/modules/startup-wizard/Makefile.am index 2643387010..ebaec22531 100644 --- a/modules/startup-wizard/Makefile.am +++ b/modules/startup-wizard/Makefile.am @@ -19,6 +19,8 @@ libevolution_module_startup_wizard_la_LIBADD = \ $(top_builddir)/calendar/gui/libevolution-calendar.la \ $(top_builddir)/mail/libevolution-mail.la \ $(top_builddir)/capplet/settings/libevolution-mail-settings.la \ + $(top_builddir)/libemail-engine/libemail-engine.la \ + $(top_builddir)/libemail-utils/libemail-utils.la \ $(EVOLUTION_DATA_SERVER_LIBS) \ $(GNOME_PLATFORM_LIBS) diff --git a/modules/startup-wizard/evolution-startup-wizard.c b/modules/startup-wizard/evolution-startup-wizard.c index de15b72609..2edeb1cc78 100644 --- a/modules/startup-wizard/evolution-startup-wizard.c +++ b/modules/startup-wizard/evolution-startup-wizard.c @@ -24,13 +24,17 @@ #include #include -#include + #include #include +#include + #include #include + #include + #include /* Standard GObject macros */ diff --git a/plugins/caldav/Makefile.am b/plugins/caldav/Makefile.am index 6d89204eff..432cafd08e 100644 --- a/plugins/caldav/Makefile.am +++ b/plugins/caldav/Makefile.am @@ -19,6 +19,7 @@ liborg_gnome_evolution_caldav_la_SOURCES = \ liborg_gnome_evolution_caldav_la_LIBADD = \ $(top_builddir)/e-util/libeutil.la \ $(top_builddir)/widgets/misc/libemiscwidgets.la \ + $(top_builddir)/libemail-utils/libemail-utils.la \ $(EVOLUTION_DATA_SERVER_LIBS) \ $(GNOME_PLATFORM_LIBS) diff --git a/plugins/caldav/caldav-browse-server.c b/plugins/caldav/caldav-browse-server.c index e1384ce062..c9d09cea20 100644 --- a/plugins/caldav/caldav-browse-server.c +++ b/plugins/caldav/caldav-browse-server.c @@ -38,7 +38,8 @@ #include #include -#include + +#include #include "caldav-browse-server.h" diff --git a/plugins/dbx-import/Makefile.am b/plugins/dbx-import/Makefile.am index 67d5e0d5d3..eeaf69ff3f 100644 --- a/plugins/dbx-import/Makefile.am +++ b/plugins/dbx-import/Makefile.am @@ -27,6 +27,8 @@ liborg_gnome_dbx_import_la_LIBADD = \ $(top_builddir)/mail/libevolution-mail.la \ $(top_builddir)/e-util/libeutil.la \ $(top_builddir)/shell/libeshell.la \ + $(top_builddir)/libemail-engine/libemail-engine.la \ + $(top_builddir)/libemail-utils/libemail-utils.la \ $(EVOLUTION_DATA_SERVER_LIBS) \ $(GNOME_PLATFORM_LIBS) \ $(GTKHTML_LIBS) diff --git a/plugins/dbx-import/dbx-importer.c b/plugins/dbx-import/dbx-importer.c index 5415f4867c..f6b666516a 100644 --- a/plugins/dbx-import/dbx-importer.c +++ b/plugins/dbx-import/dbx-importer.c @@ -64,10 +64,11 @@ #include #include +#include +#include + #include #include -#include -#include #include #define d(x) @@ -603,7 +604,7 @@ dbx_import_file (DbxImporter *m) /* Destination folder, was set in our widget */ m->parent_uri = g_strdup (((EImportTargetURI *) m->target)->uri_dest); - cancellable = e_activity_get_cancellable (m->base.activity); + cancellable = m->base.cancellable; /* XXX Dig up the EMailSession from the default EShell. * Since the EImport framework doesn't allow for user diff --git a/plugins/imap-features/imap-headers.c b/plugins/imap-features/imap-headers.c index f09f880b36..60f50d7dd6 100644 --- a/plugins/imap-features/imap-headers.c +++ b/plugins/imap-features/imap-headers.c @@ -25,15 +25,14 @@ #endif #include - -#include - #include +#include #include -#include -#include +#include + +#include typedef struct _epif_data EPImapFeaturesData; struct _epif_data { diff --git a/plugins/itip-formatter/Makefile.am b/plugins/itip-formatter/Makefile.am index 793908ecad..71fced63f0 100644 --- a/plugins/itip-formatter/Makefile.am +++ b/plugins/itip-formatter/Makefile.am @@ -22,6 +22,8 @@ liborg_gnome_itip_formatter_la_LIBADD = \ $(top_builddir)/shell/libeshell.la \ $(top_builddir)/em-format/libemformat.la \ $(top_builddir)/widgets/misc/libemiscwidgets.la \ + $(top_builddir)/libemail-utils/libemail-utils.la \ + $(top_builddir)/libemail-engine/libemail-engine.la \ $(EVOLUTION_DATA_SERVER_LIBS) \ $(GNOME_PLATFORM_LIBS) \ $(GTKHTML_LIBS) diff --git a/plugins/itip-formatter/itip-formatter.c b/plugins/itip-formatter/itip-formatter.c index 687dc26a53..d450dcfb80 100644 --- a/plugins/itip-formatter/itip-formatter.c +++ b/plugins/itip-formatter/itip-formatter.c @@ -27,27 +27,36 @@ #include #include #include + #include #include +#include #include #include #include + +#include +#include + +#include +#include + +#include +#include + +#include +#include + #include #include #include #include -#include -#include -#include -#include -#include -#include -#include + +#include + #include -#include -#include + #include "itip-view.h" -#include #define CLASSID "itip://" #define CONF_KEY_DELETE "delete-processed" diff --git a/plugins/mail-notification/Makefile.am b/plugins/mail-notification/Makefile.am index bcac34a81c..07cb42ed32 100644 --- a/plugins/mail-notification/Makefile.am +++ b/plugins/mail-notification/Makefile.am @@ -29,6 +29,7 @@ liborg_gnome_mail_notification_la_LIBADD = \ $(top_builddir)/e-util/libeutil.la \ $(top_builddir)/mail/libevolution-mail.la \ $(top_builddir)/shell/libeshell.la \ + $(top_builddir)/libemail-utils/libemail-utils.la \ $(EVOLUTION_DATA_SERVER_LIBS) \ $(GNOME_PLATFORM_LIBS) \ $(LIBNOTIFY_LIBS) \ diff --git a/plugins/mail-notification/mail-notification.c b/plugins/mail-notification/mail-notification.c index 481cf24c97..0c6714d856 100644 --- a/plugins/mail-notification/mail-notification.c +++ b/plugins/mail-notification/mail-notification.c @@ -36,7 +36,7 @@ #include #include -#include +#include #include #include #include diff --git a/plugins/mail-to-task/Makefile.am b/plugins/mail-to-task/Makefile.am index 845a82c7a3..48f0724b6f 100644 --- a/plugins/mail-to-task/Makefile.am +++ b/plugins/mail-to-task/Makefile.am @@ -23,6 +23,7 @@ liborg_gnome_mail_to_task_la_LIBADD = \ $(top_builddir)/calendar/gui/libevolution-calendar.la \ $(top_builddir)/mail/libevolution-mail.la \ $(top_builddir)/widgets/misc/libemiscwidgets.la \ + $(top_builddir)/libemail-engine/libemail-engine.la \ $(EVOLUTION_DATA_SERVER_LIBS) \ $(GNOME_PLATFORM_LIBS) \ $(GTKHTML_LIBS) diff --git a/plugins/mail-to-task/mail-to-task.c b/plugins/mail-to-task/mail-to-task.c index a4713c5447..e338393a76 100644 --- a/plugins/mail-to-task/mail-to-task.c +++ b/plugins/mail-to-task/mail-to-task.c @@ -28,9 +28,9 @@ #include #endif -#include -#include #include +#include +#include #include #include @@ -41,20 +41,25 @@ #include #include -#include -#include -#include -#include -#include #include + +#include + #include +#include + #include #include + +#include +#include +#include +#include + #include #include -#include #include -#include +#include #define E_SHELL_WINDOW_ACTION_CONVERT_TO_EVENT(window) \ E_SHELL_WINDOW_ACTION ((window), "mail-convert-to-event") diff --git a/plugins/mailing-list-actions/Makefile.am b/plugins/mailing-list-actions/Makefile.am index 77f6fdce6e..a3c46efab2 100644 --- a/plugins/mailing-list-actions/Makefile.am +++ b/plugins/mailing-list-actions/Makefile.am @@ -21,6 +21,8 @@ liborg_gnome_mailing_list_actions_la_LIBADD = \ $(top_builddir)/composer/libcomposer.la \ $(top_builddir)/mail/libevolution-mail.la \ $(top_builddir)/shell/libeshell.la \ + $(top_builddir)/libemail-engine/libemail-engine.la \ + $(top_builddir)/libemail-utils/libemail-utils.la \ $(EVOLUTION_DATA_SERVER_LIBS) \ $(GNOME_PLATFORM_LIBS) \ $(GTKHTML_LIBS) diff --git a/plugins/mailing-list-actions/mailing-list-actions.c b/plugins/mailing-list-actions/mailing-list-actions.c index 8e849be972..a9bc811c1d 100644 --- a/plugins/mailing-list-actions/mailing-list-actions.c +++ b/plugins/mailing-list-actions/mailing-list-actions.c @@ -24,27 +24,32 @@ #include #endif -#include #include #include #include +#include + +#include +#include + +#include + +#include +#include +#include + +#include + +#include +#include -#include "composer/e-msg-composer.h" -#include "mail/e-mail-browser.h" -#include "mail/e-mail-reader.h" -#include "mail/em-composer-utils.h" -#include "mail/em-format-hook.h" -#include "mail/em-config.h" -#include "mail/em-utils.h" -#include "mail/mail-ops.h" -#include "mail/mail-mt.h" -#include "mail/message-list.h" -#include "e-util/e-util.h" -#include "e-util/e-account-utils.h" -#include "e-util/e-alert-dialog.h" -#include "shell/e-shell-view.h" -#include "shell/e-shell-window.h" -#include "shell/e-shell-window-actions.h" +#include +#include +#include +#include +#include +#include +#include /* EAlert Message IDs */ #define MESSAGE_PREFIX "org.gnome.mailing-list-actions:" diff --git a/plugins/mark-all-read/mark-all-read.c b/plugins/mark-all-read/mark-all-read.c index 476172d43e..beac49ae47 100644 --- a/plugins/mark-all-read/mark-all-read.c +++ b/plugins/mark-all-read/mark-all-read.c @@ -30,7 +30,8 @@ #include #include -#include +#include + #include #include diff --git a/plugins/pst-import/pst-importer.c b/plugins/pst-import/pst-importer.c index 4305827ed1..f1e61dd07c 100644 --- a/plugins/pst-import/pst-importer.c +++ b/plugins/pst-import/pst-importer.c @@ -53,10 +53,11 @@ #include #include +#include +#include + #include #include -#include -#include #include #include #include diff --git a/plugins/templates/Makefile.am b/plugins/templates/Makefile.am index a64a10e1dd..948dfea677 100644 --- a/plugins/templates/Makefile.am +++ b/plugins/templates/Makefile.am @@ -23,6 +23,7 @@ liborg_gnome_templates_la_LIBADD = \ $(top_builddir)/composer/libcomposer.la \ $(top_builddir)/shell/libeshell.la \ $(top_builddir)/mail/libevolution-mail.la \ + $(top_builddir)/libemail-engine/libemail-engine.la \ $(EVOLUTION_DATA_SERVER_LIBS) \ $(GNOME_PLATFORM_LIBS) \ $(GTKHTML_LIBS) diff --git a/plugins/templates/templates.c b/plugins/templates/templates.c index 714a6f0e0b..2b62dc922d 100644 --- a/plugins/templates/templates.c +++ b/plugins/templates/templates.c @@ -30,19 +30,21 @@ #include #include +#include #include +#include +#include + +#include + +#include +#include +#include -#include #include -#include #include #include -#include #include -#include -#include -#include -#include #include diff --git a/po/POTFILES.in b/po/POTFILES.in index 4ffe4684c9..5814851518 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -166,7 +166,6 @@ e-util/e-file-utils.c e-util/e-plugin.c e-util/e-plugin-util.c e-util/e-print.c -e-util/e-signature.c e-util/e-system.error.xml e-util/e-util.c filter/e-filter-datespec.c @@ -179,12 +178,21 @@ filter/e-rule-context.c filter/e-rule-editor.c filter/filter.error.xml [type: gettext/glade]filter/filter.ui +libemail-engine/e-mail-folder-utils.c +libemail-engine/e-mail-session.c +libemail-engine/e-mail-session-utils.c +libemail-engine/e-mail-store-utils.c +libemail-engine/mail-config.c +libemail-engine/mail-folder-cache.c +libemail-engine/mail-ops.c +libemail-engine/mail-tools.c +libemail-utils/e-signature.c +libemail-utils/mail-mt.c mail/e-mail-account-manager.c mail/e-mail-account-tree-view.c mail/e-mail-attachment-bar.c mail/e-mail-browser.c mail/e-mail-display.c -mail/e-mail-folder-utils.c mail/e-mail-junk-options.c mail/e-mail-label-dialog.c mail/e-mail-label-list-store.c @@ -194,10 +202,8 @@ mail/e-mail-migrate.c mail/e-mail-notebook-view.c mail/e-mail-reader.c mail/e-mail-reader-utils.c -mail/e-mail-session.c -mail/e-mail-session-utils.c -mail/e-mail-store-utils.c mail/e-mail-tag-editor.c +mail/e-mail-ui-session.c mail/em-account-editor.c mail/em-composer-utils.c mail/em-filter-editor.c @@ -225,15 +231,10 @@ mail/importers/evolution-mbox-importer.c mail/importers/mail-importer.c mail/importers/pine-importer.c mail/mail-autofilter.c -mail/mail-config.c [type: gettext/glade]mail/mail-config.ui [type: gettext/glade]mail/mail-dialogs.ui mail/mail.error.xml -mail/mail-folder-cache.c -mail/mail-mt.c -mail/mail-ops.c mail/mail-send-recv.c -mail/mail-tools.c mail/mail-vfolder.c mail/message-list.c mail/message-list.etspec diff --git a/shell/Makefile.am b/shell/Makefile.am index ad9a0bb308..57b9b0c75d 100644 --- a/shell/Makefile.am +++ b/shell/Makefile.am @@ -90,6 +90,7 @@ libeshell_la_SOURCES = \ libeshell_la_LDFLAGS = $(NO_UNDEFINED) libeshell_la_LIBADD = \ + $(top_builddir)/libemail-utils/libemail-utils.la \ $(top_builddir)/e-util/libeutil.la \ $(top_builddir)/filter/libfilter.la \ $(top_builddir)/smclient/libeggsmclient.la \ @@ -142,6 +143,7 @@ evolution_LDADD = \ $(top_builddir)/widgets/e-timezone-dialog/libetimezonedialog.la \ $(top_builddir)/widgets/menus/libmenus.la \ $(top_builddir)/widgets/misc/libemiscwidgets.la \ + $(top_builddir)/libemail-utils/libemail-utils.la \ $(top_builddir)/e-util/libeutil.la \ $(top_builddir)/filter/libfilter.la \ $(EVOLUTION_DATA_SERVER_LIBS) \ diff --git a/smime/lib/Makefile.am b/smime/lib/Makefile.am index df2fb96208..9ed6067c0e 100644 --- a/smime/lib/Makefile.am +++ b/smime/lib/Makefile.am @@ -29,6 +29,7 @@ libessmime_la_SOURCES = \ e-pkcs12.h libessmime_la_LIBADD = \ + $(top_builddir)/libemail-utils/libemail-utils.la \ $(top_builddir)/e-util/libeutil.la \ $(EVOLUTION_DATA_SERVER_LIBS) \ $(GNOME_PLATFORM_LIBS) \ diff --git a/widgets/misc/Makefile.am b/widgets/misc/Makefile.am index 24495ed2cb..d0bef3fa28 100644 --- a/widgets/misc/Makefile.am +++ b/widgets/misc/Makefile.am @@ -157,6 +157,7 @@ libemiscwidgets_la_LIBADD = \ $(top_builddir)/filter/libfilter.la \ $(top_builddir)/a11y/libevolution-a11y.la \ $(top_builddir)/libgnomecanvas/libgnomecanvas.la \ + $(top_builddir)/libemail-utils/libemail-utils.la \ $(EVOLUTION_DATA_SERVER_LIBS) \ $(GNOME_PLATFORM_LIBS) \ $(MATH_LIB) \ diff --git a/widgets/misc/e-signature-combo-box.h b/widgets/misc/e-signature-combo-box.h index dd81eb55c3..5a571499df 100644 --- a/widgets/misc/e-signature-combo-box.h +++ b/widgets/misc/e-signature-combo-box.h @@ -23,8 +23,8 @@ #define E_SIGNATURE_COMBO_BOX_H #include -#include -#include +#include +#include /* Standard GObject macros */ #define E_TYPE_SIGNATURE_COMBO_BOX \ diff --git a/widgets/misc/e-signature-editor.c b/widgets/misc/e-signature-editor.c index 16efaa6d34..d968debe8f 100644 --- a/widgets/misc/e-signature-editor.c +++ b/widgets/misc/e-signature-editor.c @@ -30,7 +30,7 @@ #include #include -#include +#include #include enum { diff --git a/widgets/misc/e-signature-editor.h b/widgets/misc/e-signature-editor.h index 6d9f4a9b61..0d07cb840e 100644 --- a/widgets/misc/e-signature-editor.h +++ b/widgets/misc/e-signature-editor.h @@ -23,8 +23,8 @@ #define E_SIGNATURE_EDITOR_H #include -#include #include +#include /* Standard GObject macros */ #define E_TYPE_SIGNATURE_EDITOR \ diff --git a/widgets/misc/e-signature-manager.h b/widgets/misc/e-signature-manager.h index 88ee391564..a5516214a2 100644 --- a/widgets/misc/e-signature-manager.h +++ b/widgets/misc/e-signature-manager.h @@ -23,9 +23,9 @@ #define E_SIGNATURE_MANAGER_H #include -#include #include #include +#include /* Standard GObject macros */ #define E_TYPE_SIGNATURE_MANAGER \ diff --git a/widgets/misc/e-signature-preview.c b/widgets/misc/e-signature-preview.c index a2c2352efb..6de03c0881 100644 --- a/widgets/misc/e-signature-preview.c +++ b/widgets/misc/e-signature-preview.c @@ -29,7 +29,8 @@ #include #include #include -#include "e-util/e-signature-utils.h" + +#include enum { PROP_0, diff --git a/widgets/misc/e-signature-preview.h b/widgets/misc/e-signature-preview.h index 1a884b8563..f13ecf8ec4 100644 --- a/widgets/misc/e-signature-preview.h +++ b/widgets/misc/e-signature-preview.h @@ -22,8 +22,8 @@ #ifndef E_SIGNATURE_PREVIEW_H #define E_SIGNATURE_PREVIEW_H -#include #include +#include /* Standard GObject macros */ #define E_TYPE_SIGNATURE_PREVIEW \ diff --git a/widgets/misc/e-signature-tree-view.h b/widgets/misc/e-signature-tree-view.h index 50d1e11905..6842340d8a 100644 --- a/widgets/misc/e-signature-tree-view.h +++ b/widgets/misc/e-signature-tree-view.h @@ -23,8 +23,8 @@ #define E_SIGNATURE_TREE_VIEW_H #include -#include -#include +#include +#include /* Standard GObject macros */ #define E_TYPE_SIGNATURE_TREE_VIEW \ diff --git a/widgets/table/Makefile.am b/widgets/table/Makefile.am index 36af5ec2bf..001a2fd1e7 100644 --- a/widgets/table/Makefile.am +++ b/widgets/table/Makefile.am @@ -172,6 +172,7 @@ libetable_la_LIBADD = \ $(top_builddir)/widgets/misc/libemiscwidgets.la \ $(top_builddir)/widgets/text/libetext.la \ $(top_builddir)/libgnomecanvas/libgnomecanvas.la \ + $(top_builddir)/libemail-utils/libemail-utils.la \ $(EVOLUTION_DATA_SERVER_LIBS) \ $(GNOME_PLATFORM_LIBS) \ $(MATH_LIB) diff --git a/widgets/text/Makefile.am b/widgets/text/Makefile.am index d7c62af74e..0928da099f 100644 --- a/widgets/text/Makefile.am +++ b/widgets/text/Makefile.am @@ -35,6 +35,7 @@ libetext_la_LIBADD = \ $(top_builddir)/e-util/libeutil.la \ $(top_builddir)/widgets/misc/libemiscwidgets.la \ $(top_builddir)/libgnomecanvas/libgnomecanvas.la \ + $(top_builddir)/libemail-utils/libemail-utils.la \ $(EVOLUTION_DATA_SERVER_LIBS) \ $(GNOME_PLATFORM_LIBS) \ $(REGEX_LIBS) \ -- cgit v1.2.3