+2007-07-04 Murray Cumming <murrayc@murrayc.com>
+
+ * src/maemo/modest-msg-view-window.c:
+ (modest_msg_view_window_select_next_message):
+
+ * src/modest-platform.h:
+ * src/maemo/modest-platform.c:
+ Added modest_platform_connect_and_wait(), which calls
+ tny_maemo_conic_device_connect() always in the main thread, by calling it
+ in an idle handler and waiting for the idle handler to run. It should be
+ in the main thread because it uses GTK+ UI code. It just returns TRUE
+ if the device is already online.
+
+ There is some nasty code to ensure that subsequent calls to
+ modest_platform_connect_and_wait() just wait for the first one to finish,
+ by checking repeatedly in another idle handler. This is necessary,
+ because other threads (or even the main thread, via another idle handler)
+ can call modest_platform_connect_and_wait() while
+ modest_platform_connect_and_wait() is running.
+
+ (modest_platform_connect_and_wait_if_network_account),
+ (modest_platform_connect_and_wait_if_network_folderstore):
+ Convenience functions that calls modest_platform_connect_and_wait() if
+ the account or folder might want network access.
+
+ * src/modest-mail-operation.c:
+ (modest_mail_operation_update_account):
+ * src/modest-ui-actions.c: (download_uncached_messages),
+ (modest_ui_actions_on_rename_folder), (delete_folder),
+ (modest_ui_actions_on_main_window_move_to),
+ (modest_ui_actions_on_msg_view_window_move_to):
+ * src/widgets/modest-folder-view.c:
+ (drag_and_drop_from_folder_view):
+ Offer a connection if we are offline.
+
+ * src/modest-tny-account.c: (on_connection_status_changed):
+ Document this as only handling errors during network operations in progress,
+ and replace the idle code with a simple call to
+ modest_platform_connect_and_wait(), which does this instead.
+
2007-07-03 Murray Cumming <murrayc@murrayc.com>
* src/modest-tny-account.c:
return TRUE;
}
+gboolean modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
+{
+ /* TODO: Do something with network-manager?
+ Otherwise, maybe it is safe to assume that we would already be online if we could be. */
+ return TRUE;
+}
+
gboolean modest_platform_set_update_interval (guint minutes)
{
/* TODO. */
tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
/* Msg download completed */
- if (flags & TNY_HEADER_FLAG_CACHED)
+ if (flags & TNY_HEADER_FLAG_CACHED) {
+ /* No download is necessary, because the message is cached: */
mail_op = modest_mail_operation_new (MODEST_MAIL_OPERATION_TYPE_OPEN, G_OBJECT(window));
- else
+ } else {
+ /* Offer the connection dialog if necessary: */
+ TnyFolder *folder = tny_header_get_folder(header);
+ if (!modest_platform_connect_and_wait_if_network_folderstore (NULL, TNY_FOLDER_STORE (folder))) {
+ g_object_unref (folder);
+ return FALSE;
+ }
+ if (folder) {
+ g_object_unref (folder);
+ folder = NULL;
+ }
+
mail_op = modest_mail_operation_new (MODEST_MAIL_OPERATION_TYPE_RECEIVE, G_OBJECT(window));
+ }
/* New mail operation */
modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
#include <alarmd/alarm_event.h> /* For alarm_event_add(), etc. */
#include <tny-maemo-conic-device.h>
#include <tny-folder.h>
+#include <tny-camel-imap-store-account.h>
+#include <tny-camel-pop-store-account.h>
#include <gtk/gtkicontheme.h>
#include <gtk/gtkmenuitem.h>
#include <gtk/gtkmain.h>
gtk_widget_destroy (GTK_WIDGET (dialog));
}
-gboolean modest_platform_connect_and_wait (GtkWindow *parent_window)
+
+
+typedef struct
{
+ GMainLoop* loop;
+} UtilIdleData;
+
+static gboolean
+on_idle_connect_and_wait(gpointer user_data)
+{
+ printf ("DEBUG: %s:\n", __FUNCTION__);
TnyDevice *device = modest_runtime_get_device();
+ if (!tny_device_is_online (device)) {
+ gdk_threads_enter();
+ tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device), NULL);
+ gdk_threads_leave();
+ }
+
+ /* Allow the function that requested this idle callback to continue: */
+ UtilIdleData *data = (UtilIdleData*)user_data;
+ if (data->loop)
+ g_main_loop_quit (data->loop);
+ return FALSE; /* Don't call this again. */
+}
+
+static gboolean connect_request_in_progress = FALSE;
+
+/* This callback is used when connect_and_wait() is already queued as an idle callback.
+ * This can happen because the gtk_dialog_run() for the connection dialog
+ * (at least in the fake scratchbox version) allows idle handlers to keep running.
+ */
+static gboolean
+on_idle_wait_for_previous_connect_to_finish(gpointer user_data)
+{
+ gboolean result = FALSE;
+ TnyDevice *device = modest_runtime_get_device();
if (tny_device_is_online (device))
+ result = FALSE; /* Stop trying. */
+ else {
+ /* Keep trying until connect_request_in_progress is FALSE. */
+ if (connect_request_in_progress)
+ result = TRUE; /* Keep trying */
+ else {
+ printf ("DEBUG: %s: other idle has finished.\n", __FUNCTION__);
+
+ result = FALSE; /* Stop trying, now that a result should be available. */
+ }
+ }
+
+ if (result == FALSE) {
+ /* Allow the function that requested this idle callback to continue: */
+ UtilIdleData *data = (UtilIdleData*)user_data;
+ if (data->loop)
+ g_main_loop_quit (data->loop);
+ }
+
+ return result;
+}
+
+
+gboolean modest_platform_connect_and_wait (GtkWindow *parent_window)
+{
+ if (connect_request_in_progress)
+ return FALSE;
+
+ printf ("DEBUG: %s:\n", __FUNCTION__);
+ TnyDevice *device = modest_runtime_get_device();
+
+ if (tny_device_is_online (device)) {
+ printf ("DEBUG: %s: Already online.\n", __FUNCTION__);
return TRUE;
+ } else
+ {
+ printf ("DEBUG: %s: tny_device_is_online() returned FALSE\n", __FUNCTION__);
+ }
/* This blocks on the result: */
- return tny_maemo_conic_device_connect (TNY_MAEMO_CONIC_DEVICE (device), NULL);
+ UtilIdleData *data = g_slice_new0 (UtilIdleData);
+
+ GMainContext *context = NULL; /* g_main_context_new (); */
+ data->loop = g_main_loop_new (context, FALSE /* not running */);
+
+ /* Cause the function to be run in an idle-handler, which is always
+ * in the main thread:
+ */
+ if (!connect_request_in_progress) {
+ printf ("DEBUG: %s: First request\n", __FUNCTION__);
+ connect_request_in_progress = TRUE;
+ g_idle_add (&on_idle_connect_and_wait, data);
+ }
+ else {
+ printf ("DEBUG: %s: nth request\n", __FUNCTION__);
+ g_idle_add_full (G_PRIORITY_LOW, &on_idle_wait_for_previous_connect_to_finish, data, NULL);
+ }
+
+ /* This main loop will run until the idle handler has stopped it: */
+ printf ("DEBUG: %s: before g_main_loop_run()\n", __FUNCTION__);
+ GDK_THREADS_LEAVE();
+ g_main_loop_run (data->loop);
+ GDK_THREADS_ENTER();
+ printf ("DEBUG: %s: after g_main_loop_run()\n", __FUNCTION__);
+ connect_request_in_progress = FALSE;
+ printf ("DEBUG: %s: Finished\n", __FUNCTION__);
+ g_main_loop_unref (data->loop);
+ /* g_main_context_unref (context); */
+
+ g_slice_free (UtilIdleData, data);
+
+ return tny_device_is_online (device);
+}
+
+gboolean modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
+{
+ if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
+ if (!TNY_IS_CAMEL_POP_STORE_ACCOUNT (account) &&
+ !TNY_IS_CAMEL_IMAP_STORE_ACCOUNT (account)) {
+ /* This must be a maildir account, which does not require a connection: */
+ return TRUE;
+ }
+ }
+
+ return modest_platform_connect_and_wait (parent_window);
+}
+
+gboolean modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
+{
+ if (!folder_store)
+ return TRUE; /* Maybe it is something local. */
+
+ gboolean result = TRUE;
+ if (TNY_IS_FOLDER (folder_store)) {
+ /* Get the folder's parent account: */
+ TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
+ result = modest_platform_connect_and_wait_if_network_account (NULL, account);
+ g_object_unref (account);
+ } else if (TNY_IS_ACCOUNT (folder_store)) {
+ /* Use the folder store as an account: */
+ result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
+ }
+
+ return result;
}
void
priv->done = 0;
priv->status = MODEST_MAIL_OPERATION_STATUS_IN_PROGRESS;
+ /* Make sure that we have a connection, and request one
+ * if necessary:
+ * TODO: Is there some way to trigger this for every attempt to
+ * use the network? */
+ if (!modest_platform_connect_and_wait (NULL))
+ goto error;
+
/* Get the Modest account */
modest_account = (TnyStoreAccount *)
modest_tny_account_store_get_server_account (modest_runtime_get_account_store (),
*/
gboolean modest_platform_connect_and_wait (GtkWindow *parent_window);
+
+/*
+ * modest_platform_connect_and_wait_if_network_account:
+ * @parent_window: the parent #GtkWindow for any interactive or progress feedback UI.
+ * @account: The account that might need a connection in subsequent operations.
+ * @return value: Whether a connection was made. Also returns TRUE if no connection is necessary.
+ *
+ * Like modest_platform_connect_and_wait(), but only attempts to make a connection if the
+ * account uses the network. For instance, this just returns TRUE for local maildir accounts.
+ */
+gboolean modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account);
+
+/*
+ * modest_platform_connect_and_wait_if_network_account:
+ * @parent_window: the parent #GtkWindow for any interactive or progress feedback UI.
+ * @folder_store: The folder store (folder or account) that might need a connection in subsequent operations.
+ * @return value: Whether a connection was made. Also returns TRUE if no connection is necessary.
+ *
+ * Like modest_platform_connect_and_wait(), but only attempts to make a connection if the
+ * folder store uses the network. For instance, this just returns TRUE for local maildir folders.
+ */
+gboolean modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store);
+
/**
* modest_platform_set_update_interval:
* @minutes: The number of minutes between updates, or 0 for no updates.
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include <modest-platform.h>
#include <modest-tny-platform-factory.h>
#include <modest-tny-account.h>
#include <modest-tny-account-store.h>
#include <modest-tny-local-folders-account.h>
#include <modest-runtime.h>
-#include <modest-platform.h>
#include <tny-simple-list.h>
#include <modest-tny-folder.h>
#include <modest-tny-outbox-account.h>
return special_folder;
}
-typedef struct
-{
- GSourceFunc func;
- GMainLoop* loop;
-} UtilIdleData;
-
-static gboolean util_on_idle(gpointer user_data)
-{
- /* We are now in the main thread,
- * so we can call the function:
- */
- UtilIdleData *idle_data = (UtilIdleData*)user_data;
- if (idle_data && idle_data->func)
- (*(idle_data->func))(NULL);
-
- /* Stop the main loop so that the caller can continue: */
- if (idle_data->loop)
- g_main_loop_quit (idle_data->loop);
-
- return FALSE; /* Stop calling this callback. */
-}
-
-static void
-util_run_in_main_thread_and_wait(GSourceFunc function)
-{
- UtilIdleData *data = g_slice_new0 (UtilIdleData);
- data->func = function;
- data->loop = g_main_loop_new (NULL, FALSE /* not running */);
-
- /* Cause the function to be run in an idle-handler, which is always
- * in the main thread:
- */
- g_idle_add (util_on_idle, data);
-
- /* This main loop will run until the idle handler has stopped it: */
- g_main_loop_run (data->loop);
- g_main_loop_unref (data->loop);
-
- g_slice_free (UtilIdleData, data);
-}
-
-static gboolean
-connect_and_wait(gpointer user_data)
-{
- modest_platform_connect_and_wait(NULL);
- return TRUE; /* Ignored */
-}
-
static void
on_connection_status_changed (TnyAccount *account, TnyConnectionStatus status, gpointer user_data)
{
printf ("DEBUG: %s: status=%d\n", __FUNCTION__, status);
if (status == TNY_CONNECTION_STATUS_DISCONNECTED) {
- /* We are trying to use the network with an account,
- * but the accounts are set as offline, because our TnyDevice is offline,
+ /* A tinymail network operation failed, and tinymail then noticed that
+ * the account is offline, because our TnyDevice is offline,
* because libconic says we are offline.
- * So ask the user to go online:
+ * So ask the user to go online again.
+ *
+ * Note that this signal will not be emitted if the account was offline
+ * when the network operation was first attempted. For those cases,
+ * the application must do its own explicit checks.
*
* We make sure that this UI is shown in the main thread, to avoid races,
* because tinymail does not guarantee that this signal handler will be called
* in the main thread.
*/
- util_run_in_main_thread_and_wait (&connect_and_wait);
+ modest_platform_connect_and_wait (NULL);
} else if (status == TNY_CONNECTION_STATUS_CONNECTED_BROKEN) {
printf ("DEBUG: %s: Connection broken. Forcing TnyDevice offline.\n",
__FUNCTION__);
uncached_messages));
if (response == GTK_RESPONSE_CANCEL)
retval = FALSE;
+ else {
+ /* If a download will be necessary, make sure that we have a connection: */
+ retval = modest_platform_connect_and_wait(win);
+ }
}
return retval;
}
return;
folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW(folder_view));
+
+ /* Offer the connection dialog if necessary: */
+ if (!modest_platform_connect_and_wait_if_network_folderstore (NULL, folder)) {
+ g_object_unref (G_OBJECT (folder));
+ return;
+ }
+
if (folder && TNY_IS_FOLDER (folder)) {
gchar *folder_name;
if (!TNY_IS_FOLDER (folder)) {
modest_platform_run_information_dialog (GTK_WINDOW (main_window),
_("mail_in_ui_folder_delete_error"));
+ g_object_unref (G_OBJECT (folder));
return ;
}
+ /* Offer the connection dialog if necessary: */
+ if (!modest_platform_connect_and_wait_if_network_folderstore (NULL, folder)) {
+ g_object_unref (G_OBJECT (folder));
+ return;
+ }
+
/* Ask the user */
message = g_strdup_printf (_("mcen_nc_delete_folder_text"),
tny_folder_get_name (TNY_FOLDER (folder)));
{
GtkWidget *dialog = NULL, *folder_view = NULL, *tree_view = NULL;
GtkWidget *header_view = NULL;
- gint result;
+ gint result = 0;
TnyFolderStore *folder_store = NULL;
ModestMailOperation *mail_op = NULL;
!MODEST_IS_TNY_LOCAL_FOLDERS_ACCOUNT (folder_store))
goto end;
+ /* Offer the connection dialog if necessary: */
+ if (modest_platform_connect_and_wait_if_network_folderstore (GTK_WINDOW (win), folder_store)) {
+ goto end;
+ }
+
/* Get folder or messages to transfer */
if (gtk_widget_is_focus (folder_view)) {
TnyFolderStore *src_folder;
src_folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
- /* Clean folder on header view before moving it */
- modest_header_view_clear (MODEST_HEADER_VIEW (header_view));
+ /* Offer the connection dialog if necessary: */
+ if (modest_platform_connect_and_wait_if_network_folderstore (GTK_WINDOW (win), src_folder)) {
- if (TNY_IS_FOLDER (src_folder)) {
- mail_op =
- modest_mail_operation_new_with_error_handling (MODEST_MAIL_OPERATION_TYPE_RECEIVE,
+ /* Clean folder on header view before moving it */
+ modest_header_view_clear (MODEST_HEADER_VIEW (header_view));
+
+ if (TNY_IS_FOLDER (src_folder)) {
+ mail_op =
+ modest_mail_operation_new_with_error_handling (MODEST_MAIL_OPERATION_TYPE_RECEIVE,
G_OBJECT(win),
modest_ui_actions_move_folder_error_handler,
NULL);
- modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
+ modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
- modest_mail_operation_xfer_folder (mail_op,
- TNY_FOLDER (src_folder),
- folder_store,
- TRUE,
- NULL,
- NULL);
- /* Unref mail operation */
- g_object_unref (G_OBJECT (mail_op));
- }
+ modest_mail_operation_xfer_folder (mail_op,
+ TNY_FOLDER (src_folder),
+ folder_store,
+ TRUE, NULL, NULL);
+ /* Unref mail operation */
+ g_object_unref (G_OBJECT (mail_op));
+ }
- /* Frees */
- g_object_unref (G_OBJECT (src_folder));
+ /* Frees */
+ g_object_unref (G_OBJECT (src_folder));
+ }
} else {
if (gtk_widget_is_focus (header_view)) {
- TnyList *headers;
- gint response;
+ TnyList *headers = NULL;
+ gint response = 0;
+ /* TODO: Check for connection if the headers are on a network account. */
headers = modest_header_view_get_selected_headers (MODEST_HEADER_VIEW (header_view));
/* Ask for user confirmation */
g_object_unref (headers);
}
}
+
end:
if (folder_store != NULL)
g_object_unref (folder_store);
+
gtk_widget_destroy (dialog);
}
ModestMsgViewWindow *win)
{
GtkWidget *dialog, *folder_view, *tree_view = NULL;
- gint result;
- ModestMainWindow *main_window;
- TnyHeader *header;
- TnyList *headers;
+ gint result = 0;
+ ModestMainWindow *main_window = NULL;
+ TnyHeader *header = NULL;
+ TnyList *headers = NULL;
/* Get the folder view */
main_window = MODEST_MAIN_WINDOW (modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ()));
header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (win));
g_return_if_fail (header != NULL);
- headers = tny_simple_list_new ();
- tny_list_prepend (headers, G_OBJECT (header));
- g_object_unref (header);
-
- /* Ask user for confirmation. MSG-NOT404 */
+ /* Offer the connection dialog if necessary: */
+ /* TODO: What's the extra g_object_ref() for? Isn't this leaking a ref? */
folder_store = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (g_object_ref (tree_view)));
- response = msgs_move_to_confirmation (GTK_WINDOW (win),
+ TnyFolder *header_folder = tny_header_get_folder(header);
+ if (modest_platform_connect_and_wait_if_network_folderstore (NULL, folder_store) &&
+ modest_platform_connect_and_wait_if_network_folderstore (NULL, TNY_FOLDER_STORE (header_folder))) {
+
+ headers = tny_simple_list_new ();
+ tny_list_prepend (headers, G_OBJECT (header));
+ g_object_unref (header);
+
+ /* Ask user for confirmation. MSG-NOT404 */
+ response = msgs_move_to_confirmation (GTK_WINDOW (win),
TNY_FOLDER (folder_store),
headers);
- /* Transfer current msg */
- if (response == GTK_RESPONSE_OK) {
- ModestMailOperation *mail_op;
+ /* Transfer current msg */
+ if (response == GTK_RESPONSE_OK) {
+ ModestMailOperation *mail_op;
- /* Create mail op */
- mail_op = modest_mail_operation_new (MODEST_MAIL_OPERATION_TYPE_RECEIVE, G_OBJECT(win));
- modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
+ /* Create mail op */
+ mail_op = modest_mail_operation_new (MODEST_MAIL_OPERATION_TYPE_RECEIVE, G_OBJECT(win));
+ modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
mail_op);
- /* Transfer messages */
- modest_mail_operation_xfer_msgs (mail_op,
+ /* Transfer messages */
+ modest_mail_operation_xfer_msgs (mail_op,
headers,
TNY_FOLDER (folder_store),
TRUE,
transfer_msgs_from_viewer_cb,
NULL);
- g_object_unref (G_OBJECT (mail_op));
+ g_object_unref (G_OBJECT (mail_op));
+ }
}
- g_object_unref (headers);
- g_object_unref (folder_store);
+
+ if (header_folder)
+ g_object_unref (header_folder);
+
+ if (headers)
+ g_object_unref (headers);
+
+ if (folder_store)
+ g_object_unref (folder_store);
}
+
gtk_widget_destroy (dialog);
}
GtkSelectionData *selection_data,
DndHelper *helper)
{
- ModestMailOperation *mail_op;
+ ModestMailOperation *mail_op = NULL;
GtkTreeIter parent_iter, iter;
- TnyFolderStore *parent_folder;
- TnyFolder *folder;
+ TnyFolderStore *parent_folder = NULL;
+ TnyFolder *folder = NULL;
/* Check if the drag is possible */
/* if (!gtk_tree_path_compare (helper->source_row, dest_row) || */
TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN,
&folder, -1);
- /* Do the mail operation */
- mail_op = modest_mail_operation_new_with_error_handling (MODEST_MAIL_OPERATION_TYPE_RECEIVE,
+ /* Offer the connection dialog if necessary, for the destination parent folder and source folder: */
+ if (modest_platform_connect_and_wait_if_network_folderstore (NULL, parent_folder) &&
+ modest_platform_connect_and_wait_if_network_folderstore (NULL, TNY_FOLDER_STORE (folder))) {
+ /* Do the mail operation */
+ mail_op = modest_mail_operation_new_with_error_handling (MODEST_MAIL_OPERATION_TYPE_RECEIVE,
NULL,
modest_ui_actions_move_folder_error_handler,
NULL);
- modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
+ modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
mail_op);
- g_signal_connect (G_OBJECT (mail_op), "progress-changed",
- G_CALLBACK (on_progress_changed), helper);
+ g_signal_connect (G_OBJECT (mail_op), "progress-changed",
+ G_CALLBACK (on_progress_changed), helper);
- modest_mail_operation_xfer_folder (mail_op,
+ modest_mail_operation_xfer_folder (mail_op,
folder,
parent_folder,
helper->delete_source,
NULL,
NULL);
+ }
/* Frees */
g_object_unref (G_OBJECT (parent_folder));