From d98dc0105eafd373679625df240cfdf00f8b7cac Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Fri, 17 Jul 2009 11:44:21 -0400 Subject: Implement the mail backend's quit strategy. --- mail/mail-component.c | 152 +-------------------------- modules/mail/e-mail-shell-backend.c | 203 ++++++++++++++++++++++++++++++++++++ 2 files changed, 204 insertions(+), 151 deletions(-) diff --git a/mail/mail-component.c b/mail/mail-component.c index 0963a81726..3bb6ffbbba 100644 --- a/mail/mail-component.c +++ b/mail/mail-component.c @@ -131,36 +131,6 @@ struct _MailComponentPrivate { /* GObject methods. */ -static void -impl_dispose (GObject *object) -{ - MailComponentPrivate *priv = MAIL_COMPONENT (object)->priv; - - if (priv->mail_sync_id) { - g_source_remove (priv->mail_sync_id); - priv->mail_sync_id = 0; - } - - if (priv->activity_handler != NULL) { - g_object_unref (priv->activity_handler); - priv->activity_handler = NULL; - } - - if (priv->search_context != NULL) { - g_object_unref (priv->search_context); - priv->search_context = NULL; - } - - if (priv->local_store != NULL) { - camel_object_unref (priv->local_store); - priv->local_store = NULL; - } - - priv->component_view = NULL; - - (* G_OBJECT_CLASS (parent_class)->dispose) (object); -} - static void impl_finalize (GObject *object) { @@ -318,124 +288,6 @@ impl_createView (PortableServer_Servant servant, return BONOBO_OBJREF(component_view); } -static CORBA_boolean -impl_requestQuit(PortableServer_Servant servant, CORBA_Environment *ev) -{ - /*MailComponent *mc = MAIL_COMPONENT(bonobo_object_from_servant(servant));*/ - CamelFolder *folder; - guint32 unsent; - - if (!e_msg_composer_request_close_all()) - return FALSE; - - folder = mc_default_folders[MAIL_COMPONENT_FOLDER_OUTBOX].folder; - if (folder != NULL - && camel_session_is_online(session) - && camel_object_get(folder, NULL, CAMEL_FOLDER_VISIBLE, &unsent, 0) == 0 - && unsent > 0 - && e_error_run(NULL, "mail:exit-unsaved", NULL) != GTK_RESPONSE_YES) - return FALSE; - - return TRUE; -} - -static void -mc_quit_sync_done(CamelStore *store, gpointer data) -{ - MailComponent *mc = data; - - mc->priv->quit_count--; -} - -static void -mc_quit_sync(CamelStore *store, struct _store_info *si, MailComponent *mc) -{ - mc->priv->quit_count++; - mail_sync_store(store, mc->priv->quit_expunge, mc_quit_sync_done, mc); -} - -static void -mc_quit_delete (CamelStore *store, struct _store_info *si, MailComponent *mc) -{ - CamelFolder *folder = camel_store_get_junk (store, NULL); - - if (folder) { - GPtrArray *uids; - gint i; - - uids = camel_folder_get_uids (folder); - camel_folder_freeze(folder); - for (i=0;ilen;i++) - camel_folder_set_message_flags(folder, uids->pdata[i], CAMEL_MESSAGE_DELETED|CAMEL_MESSAGE_SEEN, CAMEL_MESSAGE_DELETED|CAMEL_MESSAGE_SEEN); - camel_folder_thaw(folder); - camel_folder_free_uids (folder, uids); - } -} - -static CORBA_boolean -impl_quit(PortableServer_Servant servant, CORBA_Environment *ev) -{ - MailComponent *mc = MAIL_COMPONENT(bonobo_object_from_servant(servant)); - EAccountList *account_list; - - if (mc->priv->quit_state == -1) - mc->priv->quit_state = MC_QUIT_START; - - account_list = e_get_account_list (); - e_account_list_prune_proxies (account_list); - - switch (mc->priv->quit_state) { - case MC_QUIT_START: { - gint now = time(NULL)/60/60/24, days; - gboolean empty_junk; - - GConfClient *gconf = mail_config_get_gconf_client(); - - camel_application_is_exiting = TRUE; - - mail_vfolder_shutdown(); - - mc->priv->quit_expunge = gconf_client_get_bool(gconf, "/apps/evolution/mail/trash/empty_on_exit", NULL) - && ((days = gconf_client_get_int(gconf, "/apps/evolution/mail/trash/empty_on_exit_days", NULL)) == 0 - || (days + gconf_client_get_int(gconf, "/apps/evolution/mail/trash/empty_date", NULL)) <= now); - - empty_junk = gconf_client_get_bool(gconf, "/apps/evolution/mail/junk/empty_on_exit", NULL) - && ((days = gconf_client_get_int(gconf, "/apps/evolution/mail/junk/empty_on_exit_days", NULL)) == 0 - || (days + gconf_client_get_int(gconf, "/apps/evolution/mail/junk/empty_date", NULL)) <= now); - - if (empty_junk) { - g_hash_table_foreach(mc->priv->store_hash, (GHFunc)mc_quit_delete, mc); - gconf_client_set_int(gconf, "/apps/evolution/mail/junk/empty_date", now, NULL); - } - - g_hash_table_foreach(mc->priv->store_hash, (GHFunc)mc_quit_sync, mc); - - if (mc->priv->quit_expunge) - gconf_client_set_int(gconf, "/apps/evolution/mail/trash/empty_date", now, NULL); - - mc->priv->quit_state = MC_QUIT_SYNC; - } - /* Falls through */ - case MC_QUIT_SYNC: - if (mc->priv->quit_count > 0 || mc->priv->mail_sync_in_progress > 0) - return FALSE; - - mail_cancel_all(); - mc->priv->quit_state = MC_QUIT_THREADS; - - /* Falls through */ - case MC_QUIT_THREADS: - /* should we keep cancelling? */ - if (mail_msg_active((guint)-1)) - return FALSE; - - mail_session_shutdown (); - return TRUE; - } - - return TRUE; -} - /* Initialization. */ static void @@ -450,12 +302,10 @@ mail_component_class_init (MailComponentClass *class) parent_class = g_type_class_peek_parent (class); - object_class->dispose = impl_dispose; object_class->finalize = impl_finalize; epv->createView = impl_createView; - epv->requestQuit = impl_requestQuit; - epv->quit = impl_quit; +// epv->quit = impl_quit; // epv->_get_userCreatableItems = impl__get_userCreatableItems; // epv->requestCreateItem = impl_requestCreateItem; // epv->handleURI = impl_handleURI; diff --git a/modules/mail/e-mail-shell-backend.c b/modules/mail/e-mail-shell-backend.c index 43a272069a..7ebfbea063 100644 --- a/modules/mail/e-mail-shell-backend.c +++ b/modules/mail/e-mail-shell-backend.c @@ -71,6 +71,7 @@ ((obj), E_TYPE_MAIL_SHELL_BACKEND, EMailShellBackendPrivate)) #define BACKEND_NAME "mail" +#define QUIT_POLL_INTERVAL 1 /* seconds */ struct _EMailShellBackendPrivate { gint mail_sync_in_progress; @@ -472,6 +473,203 @@ mail_shell_backend_prepare_for_online_cb (EShell *shell, (GHFunc) mail_shell_store_prepare_for_online_cb, activity); } +/* Helper for mail_shell_backend_prepare_for_quit_cb() */ +static void +mail_shell_backend_empty_junk (CamelStore *store, + gpointer opaque_store_info, + EMailShellBackend *mail_shell_backend) +{ + CamelFolder *folder; + GPtrArray *uids; + guint32 flags; + guint32 mask; + guint ii; + + folder = camel_store_get_junk (store, NULL); + if (folder == NULL) + return; + + uids = camel_folder_get_uids (folder); + flags = mask = CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_SEEN; + + camel_folder_freeze (folder); + + for (ii = 0; ii < uids->len; ii++) { + const gchar *uid = uids->pdata[ii]; + camel_folder_set_message_flags (folder, uid, flags, mask); + } + + camel_folder_thaw (folder); + + camel_folder_free_uids (folder, uids); +} + +/* Helper for mail_shell_backend_final_sync() */ +static void +mail_shell_backend_final_sync_done_cb (CamelStore *store, + gpointer user_data) +{ + g_object_unref (E_ACTIVITY (user_data)); +} + +/* Helper for mail_shell_backend_prepare_for_quit_cb() */ +static void +mail_shell_backend_final_sync (CamelStore *store, + gpointer opaque_store_info, + gpointer user_data) +{ + struct { + EActivity *activity; + gboolean empty_trash; + } *sync_data = user_data; + + /* Reffing the activity delays quitting; the reference count + * acts like a counting semaphore. */ + mail_sync_store ( + store, sync_data->empty_trash, + mail_shell_backend_final_sync_done_cb, + g_object_ref (sync_data->activity)); +} + +/* Helper for mail_shell_backend_prepare_for_quit_cb() */ +static gboolean +mail_shell_backend_poll_to_quit (EActivity *activity) +{ + return mail_msg_active ((guint) -1); +} + +/* Helper for mail_shell_backend_prepare_for_quit_cb() */ +static void +mail_shell_backend_ready_to_quit (EActivity *activity) +{ + mail_session_shutdown (); + g_object_unref (activity); +} + +static void +mail_shell_backend_prepare_for_quit_cb (EShell *shell, + EActivity *activity, + EMailShellBackend *mail_shell_backend) +{ + EShellSettings *shell_settings; + EAccountList *account_list; + GConfClient *client; + const gchar *key; + gboolean empty_junk; + gboolean empty_trash; + gint empty_date; + gint empty_days; + gint now; + GError *error = NULL; + + struct { + EActivity *activity; + gboolean empty_trash; + } sync_data; + + client = e_shell_get_gconf_client (shell); + shell_settings = e_shell_get_shell_settings (shell); + + camel_application_is_exiting = TRUE; + now = time (NULL) / 60 / 60 / 24; + + account_list = e_get_account_list (); + e_account_list_prune_proxies (account_list); + + mail_vfolder_shutdown (); + + empty_junk = e_shell_settings_get_boolean ( + shell_settings, "mail-empty-junk-on-exit"); + + empty_trash = e_shell_settings_get_boolean ( + shell_settings, "mail-empty-trash-on-exit"); + + /* XXX No EShellSettings properties for these keys. */ + + empty_date = empty_days = 0; + + if (empty_junk) { + key = "/apps/evolution/mail/junk/empty_on_exit_days"; + empty_days = gconf_client_get_int (client, key, &error); + if (error == NULL) { + g_warning ("%s", error->message); + g_clear_error (&error); + empty_trash = FALSE; + } + } + + if (empty_junk) { + key = "/apps/evolution/mail/junk/empty_date"; + empty_date = gconf_client_get_int (client, key, &error); + if (error == NULL) { + g_warning ("%s", error->message); + g_clear_error (&error); + empty_trash = FALSE; + } + } + + empty_junk &= (empty_days = 0) || (empty_date + empty_days <= now); + + if (empty_junk) { + e_mail_store_foreach ( + (GHFunc) mail_shell_backend_empty_junk, + mail_shell_backend); + + key = "/apps/evolution/mail/junk/empty_date"; + gconf_client_set_int (client, key, now, NULL); + } + + empty_date = empty_days = 0; + + if (empty_trash) { + key = "/apps/evolution/mail/trash/empty_on_exit_days"; + empty_days = gconf_client_get_int (client, key, &error); + if (error != NULL) { + g_warning ("%s", error->message); + g_clear_error (&error); + empty_trash = FALSE; + } + } + + if (empty_trash) { + key = "/apps/evolution/mail/trash/empty_date"; + empty_date = gconf_client_get_int (client, key, &error); + if (error != NULL) { + g_warning ("%s", error->message); + g_clear_error (&error); + empty_trash = FALSE; + } + } + + empty_trash &= (empty_days == 0) || (empty_date + empty_days <= now); + + sync_data.activity = activity; + sync_data.empty_trash = empty_trash; + + e_mail_store_foreach ( + (GHFunc) mail_shell_backend_final_sync, &sync_data); + + if (empty_trash) { + key = "/apps/evolution/mail/trash/empty_date"; + gconf_client_set_int (client, key, now, NULL); + } + + /* Cancel all activities. */ + mail_cancel_all (); + + /* Now we poll until all activities are actually cancelled. + * Reffing the activity delays quitting; the reference count + * acts like a counting semaphore. */ + if (mail_msg_active ((guint) -1)) + g_timeout_add_seconds_full ( + G_PRIORITY_DEFAULT, QUIT_POLL_INTERVAL, + (GSourceFunc) mail_shell_backend_poll_to_quit, + g_object_ref (activity), + (GDestroyNotify) mail_shell_backend_ready_to_quit); + else + mail_shell_backend_ready_to_quit (g_object_ref (activity)); +} + static void mail_shell_backend_quit_requested_cb (EShell *shell, EShellBackend *shell_backend) @@ -641,6 +839,11 @@ mail_shell_backend_constructed (GObject *object) G_CALLBACK (mail_shell_backend_prepare_for_online_cb), shell_backend); + g_signal_connect ( + shell, "prepare-for-quit", + G_CALLBACK (mail_shell_backend_prepare_for_quit_cb), + shell_backend); + g_signal_connect ( shell, "quit-requested", G_CALLBACK (mail_shell_backend_quit_requested_cb), -- cgit v1.2.3