diff options
-rw-r--r-- | mail/ChangeLog | 24 | ||||
-rw-r--r-- | mail/mail-offline-handler.c | 144 | ||||
-rw-r--r-- | mail/mail-ops.c | 112 | ||||
-rw-r--r-- | mail/mail-ops.h | 9 |
4 files changed, 234 insertions, 55 deletions
diff --git a/mail/ChangeLog b/mail/ChangeLog index b8b5c98d3d..87e4a1a66a 100644 --- a/mail/ChangeLog +++ b/mail/ChangeLog @@ -1,3 +1,27 @@ +2002-05-15 Not Zed <NotZed@Ximian.com> + + * mail-ops.c (prep_offline_do): + (prep_offline_done): + (prep_offline_free): + (mail_prep_offline): Implement prep_offline for an individual + folder. + (set_offline_do): Only call disco_store_set_status or disconnect + for the store, dont do any offline prep stuff. + + * mail-offline-handler.c: Applied patch from Ettore to hook in + extra offline interfaces. + (impl_destroy): Dont free listener here anymore, its removed, but + free sync table. + (mail_offline_handler_init): Same for setup. + (impl_syncFolder): Implement. + (sync_done): handles finalising synchronisation of 1 folder. + (sync_status): progress reporting, camel side. + (sync_timeout): progress reporting, gmainloop side. + (impl_cancelSyncFolder): Implement. + (impl_goOffline, storage_go_offline, went_offline): Dont copy the + listener to our struct - its an argument, not a member, so give + each thread its own copy. + 2002-05-15 Jeffrey Stedfast <fejj@ximian.com> * message-list.c (ml_tree_value_at): Instead of g_assert()ing that diff --git a/mail/mail-offline-handler.c b/mail/mail-offline-handler.c index 5217420570..a24f52a79c 100644 --- a/mail/mail-offline-handler.c +++ b/mail/mail-offline-handler.c @@ -38,7 +38,7 @@ static BonoboXObjectClass *parent_class = NULL; struct _MailOfflineHandlerPrivate { - GNOME_Evolution_OfflineProgressListener listener_interface; + GHashTable *sync_table; }; static gboolean @@ -107,37 +107,139 @@ impl_prepareForOffline (PortableServer_Servant servant, *active_connection_list = create_connection_list (); } +/* keep track of each sync in progress */ +struct _sync_info { + char *uri; /* uri of folder being synced */ + CamelOperation *cancel; /* progress report/cancellation object */ + GNOME_Evolution_SyncFolderProgressListener listener; + int pc; /* percent complete (0-100) */ + int lastpc; /* last percent reported, so we dont overreport */ + int id; /* timeout id */ +}; + static void -went_offline (CamelStore *store, void *data) +impl_cancelSyncFolder (PortableServer_Servant servant, + const GNOME_Evolution_Folder *folder, + CORBA_Environment *ev) { - MailOfflineHandler *offline_handler = data; + MailOfflineHandler *offline_handler; MailOfflineHandlerPrivate *priv; + struct _sync_info *info; + + offline_handler = MAIL_OFFLINE_HANDLER (bonobo_object_from_servant (servant)); + priv = offline_handler->priv; + + info = g_hash_table_lookup(priv->sync_table, folder->physicalUri); + if (info) + camel_operation_cancel(info->cancel); + else + g_warning("Shell tried to cancel sync of '%s': no such folder", folder->physicalUri); +} + +static int sync_timeout(struct _sync_info *info) +{ CORBA_Environment ev; - GNOME_Evolution_ConnectionList *connection_list; + if (info->pc != info->lastpc) { + CORBA_exception_init(&ev); + GNOME_Evolution_SyncFolderProgressListener_updateProgress(info->listener, info->pc/100.0, &ev); + if (ev._major != CORBA_NO_EXCEPTION) + g_warning("Error updating offline progress"); + CORBA_exception_free(&ev); + info->lastpc = info->pc; + } + + return TRUE; +} + +static void sync_status(CamelOperation *op, const char *what, int pc, void *data) +{ + struct _sync_info *info = data; + + if (pc == CAMEL_OPERATION_START) + pc = 0; + else if (pc == CAMEL_OPERATION_END) + pc = 100; + + info->pc = pc; +} + +static void +sync_done(const char *uri, void *crap) +{ + CORBA_Environment ev; + struct _sync_info *info = crap; + + g_source_remove(info->id); + + CORBA_exception_init(&ev); + GNOME_Evolution_SyncFolderProgressListener_reportSuccess(info->listener, &ev); + if (ev._major != CORBA_NO_EXCEPTION) + g_warning("Error sending offline completion: hang likely"); + CORBA_Object_release(info->listener, &ev); + CORBA_exception_free(&ev); + + g_free(info->uri); + camel_operation_unref(info->cancel); + g_free(info); +} + +static void +impl_syncFolder (PortableServer_Servant servant, + const GNOME_Evolution_Folder *folder, + const GNOME_Evolution_SyncFolderProgressListener progress_listener, + CORBA_Environment *ev) +{ + MailOfflineHandler *offline_handler; + MailOfflineHandlerPrivate *priv; + struct _sync_info *info; + + offline_handler = MAIL_OFFLINE_HANDLER(bonobo_object_from_servant (servant)); priv = offline_handler->priv; + info = g_malloc(sizeof(*info)); + info->listener = CORBA_Object_duplicate(progress_listener, ev); + info->pc = 0; + info->uri = g_strdup(folder->physicalUri); + info->id = g_timeout_add(500, (GSourceFunc)sync_timeout, info); + info->cancel = camel_operation_new(sync_status, info); + + g_hash_table_insert(priv->sync_table, info->uri, info); + + mail_prep_offline(info->uri, info->cancel, sync_done, info); +} + +static void +went_offline (CamelStore *store, void *data) +{ + CORBA_Environment ev; + GNOME_Evolution_ConnectionList *connection_list; + GNOME_Evolution_OfflineProgressListener listener = data; + connection_list = create_connection_list (); CORBA_exception_init (&ev); - - GNOME_Evolution_OfflineProgressListener_updateProgress (priv->listener_interface, connection_list, &ev); + GNOME_Evolution_OfflineProgressListener_updateProgress(listener, connection_list, &ev); if (ev._major != CORBA_NO_EXCEPTION) g_warning ("Error updating offline progress"); + CORBA_Object_release(listener, &ev); CORBA_exception_free (&ev); - - /* CORBA_free (connection_list); */ + CORBA_free (connection_list); } static void storage_go_offline (gpointer key, gpointer value, gpointer data) { CamelStore *store = key; - MailOfflineHandler *offline_handler = data; + GNOME_Evolution_OfflineProgressListener listener = data; + CORBA_Environment ev; - if (service_is_relevant (CAMEL_SERVICE (store), TRUE)) - mail_store_set_offline (store, TRUE, went_offline, offline_handler); + CORBA_exception_init(&ev); + if (service_is_relevant (CAMEL_SERVICE (store), TRUE)) { + mail_store_set_offline (store, TRUE, went_offline, CORBA_Object_duplicate(listener, &ev)); + } + CORBA_exception_free(&ev); } static void @@ -146,19 +248,15 @@ impl_goOffline (PortableServer_Servant servant, CORBA_Environment *ev) { MailOfflineHandler *offline_handler; - MailOfflineHandlerPrivate *priv; offline_handler = MAIL_OFFLINE_HANDLER (bonobo_object_from_servant (servant)); - priv = offline_handler->priv; - - priv->listener_interface = CORBA_Object_duplicate (progress_listener, ev); /* This will disable further auto-mail-check action. */ camel_session_set_online (session, FALSE); /* FIXME: If send/receive active, wait for it to finish */ - mail_storages_foreach (storage_go_offline, offline_handler); + mail_storages_foreach (storage_go_offline, progress_listener); } static void @@ -196,15 +294,7 @@ impl_destroy (GtkObject *object) offline_handler = MAIL_OFFLINE_HANDLER (object); priv = offline_handler->priv; - - if (priv->listener_interface != CORBA_OBJECT_NIL) { - CORBA_Environment ev; - - CORBA_exception_init (&ev); - CORBA_Object_release (priv->listener_interface, &ev); - CORBA_exception_free (&ev); - } - + g_hash_table_destroy(priv->sync_table); g_free (priv); if (GTK_OBJECT_CLASS (parent_class)->destroy != NULL) @@ -225,6 +315,8 @@ mail_offline_handler_class_init (MailOfflineHandlerClass *klass) epv = & klass->epv; epv->_get_isOffline = impl__get_isOffline; epv->prepareForOffline = impl_prepareForOffline; + epv->syncFolder = impl_syncFolder; + epv->cancelSyncFolder = impl_cancelSyncFolder; epv->goOffline = impl_goOffline; epv->goOnline = impl_goOnline; @@ -237,7 +329,7 @@ mail_offline_handler_init (MailOfflineHandler *offline_handler) MailOfflineHandlerPrivate *priv; priv = g_new (MailOfflineHandlerPrivate, 1); - priv->listener_interface = CORBA_OBJECT_NIL; + priv->sync_table = g_hash_table_new(g_str_hash, g_str_equal); offline_handler->priv = priv; } diff --git a/mail/mail-ops.c b/mail/mail-ops.c index c86c5f2208..ed7a876585 100644 --- a/mail/mail-ops.c +++ b/mail/mail-ops.c @@ -2085,6 +2085,85 @@ mail_save_part (CamelMimePart *part, const char *path, } +/* ** PREPARE OFFLINE ***************************************************** */ + +struct _prep_offline_msg { + struct _mail_msg msg; + + CamelOperation *cancel; + char *uri; + void (*done)(const char *uri, void *data); + void *data; +}; + +static void prep_offline_do(struct _mail_msg *mm) +{ + struct _prep_offline_msg *m = (struct _prep_offline_msg *)mm; + CamelFolder *folder; + + if (m->cancel) + camel_operation_register(m->cancel); + + folder = mail_tool_uri_to_folder(m->uri, 0, &mm->ex); + if (folder) { + if (CAMEL_IS_DISCO_FOLDER(folder)) { + camel_disco_folder_prepare_for_offline((CamelDiscoFolder *)folder, + "(match-all (not (system-flag \"Seen\")))", + &mm->ex); + } + /* prepare_for_offline should do this? */ + /* of course it should all be atomic, but ... */ + camel_folder_sync(folder, FALSE, NULL); + camel_object_unref((CamelObject *)folder); + } + + if (m->cancel) + camel_operation_unregister(m->cancel); +} + +static void prep_offline_done(struct _mail_msg *mm) +{ + struct _prep_offline_msg *m = (struct _prep_offline_msg *)mm; + + if (m->done) + m->done(m->uri, m->data); +} + +static void prep_offline_free(struct _mail_msg *mm) +{ + struct _prep_offline_msg *m = (struct _prep_offline_msg *)mm; + + if (m->cancel) + camel_operation_unref(m->cancel); + g_free(m->uri); +} + +static struct _mail_msg_op prep_offline_op = { + NULL, /* DO NOT CHANGE THIS, IT MUST BE NULL FOR CANCELLATION TO WORK */ + prep_offline_do, + prep_offline_done, + prep_offline_free, +}; + +void +mail_prep_offline(const char *uri, + CamelOperation *cancel, + void (*done)(const char *, void *data), + void *data) +{ + struct _prep_offline_msg *m; + + m = mail_msg_new(&prep_offline_op, NULL, sizeof(*m)); + m->cancel = cancel; + if (cancel) + camel_operation_ref(cancel); + m->uri = g_strdup(uri); + m->data = data; + m->done = done; + + e_thread_put(mail_thread_queued, (EMsg *)m); +} + /* ** GO OFFLINE ***************************************************** */ struct _set_offline_msg { @@ -2102,9 +2181,9 @@ static char *set_offline_desc(struct _mail_msg *mm, int done) char *service_name = camel_service_get_name (CAMEL_SERVICE (m->store), TRUE); char *msg; - msg = g_strdup_printf (m->offline ? _("Disconnecting from %s") : - _("Reconnecting to %s"), service_name); - g_free (service_name); + msg = g_strdup_printf(m->offline?_("Disconnecting from %s"):_("Reconnecting to %s"), + service_name); + g_free(service_name); return msg; } @@ -2118,29 +2197,11 @@ static void set_offline_do(struct _mail_msg *mm) camel_service_disconnect (CAMEL_SERVICE (m->store), TRUE, &mm->ex); } - return; - } - - if (m->offline && camel_disco_store_status (CAMEL_DISCO_STORE (m->store)) == CAMEL_DISCO_STORE_ONLINE) { - CamelFolder *inbox; - - /* FIXME. Something more generic here... (bug 10755) */ - inbox = camel_store_get_inbox (m->store, NULL); - if (inbox) { - camel_disco_folder_prepare_for_offline ( - CAMEL_DISCO_FOLDER (inbox), - "(match-all (not (system-flag \"Seen\")))", - &mm->ex); - camel_folder_sync (inbox, FALSE, NULL); - camel_object_unref (CAMEL_OBJECT (inbox)); - if (camel_exception_is_set (&mm->ex)) - return; - } + } else { + camel_disco_store_set_status (CAMEL_DISCO_STORE (m->store), + m->offline ? CAMEL_DISCO_STORE_OFFLINE : CAMEL_DISCO_STORE_ONLINE, + &mm->ex); } - - camel_disco_store_set_status (CAMEL_DISCO_STORE (m->store), - m->offline ? CAMEL_DISCO_STORE_OFFLINE : - CAMEL_DISCO_STORE_ONLINE, &mm->ex); } static void set_offline_done(struct _mail_msg *mm) @@ -2188,7 +2249,6 @@ mail_store_set_offline (CamelStore *store, gboolean offline, e_thread_put(mail_thread_queued, (EMsg *)m); } - /* ** Execute Shell Command ***************************************************** */ struct _execute_shell_command_msg { diff --git a/mail/mail-ops.h b/mail/mail-ops.h index 6aa5627d61..a6631d6559 100644 --- a/mail/mail-ops.h +++ b/mail/mail-ops.h @@ -147,9 +147,12 @@ void mail_filter_folder (CamelFolder *source_folder, GPtrArray *uids, void mail_filter_on_demand (CamelFolder *folder, GPtrArray *uids); /* Work Offline */ -void mail_store_set_offline (CamelStore *store, gboolean offline, - void (*done)(CamelStore *, void *data), - void *data); +void mail_prep_offline(const char *uri, CamelOperation *cancel, + void (*done)(const char *, void *data), + void *data); +void mail_store_set_offline(CamelStore *store, gboolean offline, + void (*done)(CamelStore *, void *data), + void *data); /* filter driver execute shell command async callback */ void mail_execute_shell_command (CamelFilterDriver *driver, const char *command, void *data); |