2007-07-02 Murray Cumming <murrayc@murrayc.com
[modest] / src / modest-tny-account.c
index 3998145..ca2e6c8 100644 (file)
@@ -32,6 +32,7 @@
 #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>
@@ -123,6 +124,86 @@ modest_tny_account_get_special_folder (TnyAccount *account,
        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,
+                * because libconic says we are offline.
+                * So ask the user to go online:
+                *
+                * 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);
+       } else if (status == TNY_CONNECTION_STATUS_CONNECTED_BROKEN) {
+               printf ("DEBUG: %s: Connection broken. Forcing TnyDevice offline.\n", 
+                       __FUNCTION__);
+                       
+               /* Something went wrong during some network operation.
+                * Stop trying to use the network now,
+                * by forcing accounts into offline mode:
+                * 
+                * When libconic reconnects, it will set the device back online again,
+                * regardless of it being forced offline before.
+                */
+               TnyDevice *device = modest_runtime_get_device ();
+               tny_device_force_offline (device);
+       }
+}
+
 /* Camel options: */
 
 /* These seem to be listed in 
@@ -166,7 +247,8 @@ modest_tny_account_get_special_folder (TnyAccount *account,
 /**
  * modest_tny_account_new_from_server_account:
  * @account_mgr: a valid account mgr instance
- * @account_name: the server account name for which to create a corresponding tny account
+ * @session: A valid TnySessionCamel instance.
+ * @account_data: the server account for which to create a corresponding tny account
  * @type: the type of account to create (TNY_ACCOUNT_TYPE_STORE or TNY_ACCOUNT_TYPE_TRANSPORT)
  * 
  * get a tnyaccount corresponding to the server_accounts (store or transport) for this account.
@@ -176,11 +258,13 @@ modest_tny_account_get_special_folder (TnyAccount *account,
  */
 static TnyAccount*
 modest_tny_account_new_from_server_account (ModestAccountMgr *account_mgr,
+                                           TnySessionCamel *session,
                                            ModestServerAccountData *account_data)
 {
        gchar *url = NULL;
 
        g_return_val_if_fail (account_mgr, NULL);
+       g_return_val_if_fail (session, NULL);
        g_return_val_if_fail (account_data, NULL);
 
        /* sanity checks */
@@ -216,6 +300,14 @@ modest_tny_account_new_from_server_account (ModestAccountMgr *account_mgr,
        }
        tny_account_set_id (tny_account, account_data->account_name);
 
+       /* This must be set quite early, or other set() functions will fail. */
+    tny_camel_account_set_session (TNY_CAMEL_ACCOUNT (tny_account), session);
+    
+       /* Handle connection requests:
+        * This (badly-named) signal will be called when we try to use an offline account. */
+       g_signal_connect (G_OBJECT (tny_account), "connection-status-changed",
+                       G_CALLBACK (on_connection_status_changed), NULL);
+
        /* Proto */
        const gchar* proto_name =
                modest_protocol_info_get_transport_store_protocol_name(account_data->proto);
@@ -335,7 +427,8 @@ modest_tny_account_new_from_server_account (ModestAccountMgr *account_mgr,
 
 TnyAccount*
 modest_tny_account_new_from_server_account_name (ModestAccountMgr *account_mgr,
-                                           const gchar *server_account_name)
+                                               TnySessionCamel *session,
+                                               const gchar *server_account_name)
 {
        ModestServerAccountData *account_data = 
                modest_account_mgr_get_server_account_data (account_mgr, 
@@ -344,7 +437,7 @@ modest_tny_account_new_from_server_account_name (ModestAccountMgr *account_mgr,
                return NULL;
 
        TnyAccount *result = modest_tny_account_new_from_server_account (
-               account_mgr, account_data);
+               account_mgr, session, account_data);
 
        modest_account_mgr_free_server_account_data (account_mgr, account_data);
        
@@ -377,6 +470,7 @@ modest_tny_account_new_from_account (ModestAccountMgr *account_mgr, const gchar
 
        g_return_val_if_fail (account_mgr, NULL);
        g_return_val_if_fail (account_name, NULL);
+       g_return_val_if_fail (session, NULL);
 
        account_data = modest_account_mgr_get_account_data (account_mgr, account_name);
        if (!account_data) {
@@ -396,7 +490,7 @@ modest_tny_account_new_from_account (ModestAccountMgr *account_mgr, const gchar
                return NULL;
        }
        
-       tny_account = modest_tny_account_new_from_server_account (account_mgr, server_data);
+       tny_account = modest_tny_account_new_from_server_account (account_mgr, session, server_data);
        if (!tny_account) { 
                g_printerr ("modest: failed to create tny account for %s (%s)\n",
                            account_data->account_name, server_data->account_name);
@@ -404,7 +498,6 @@ modest_tny_account_new_from_account (ModestAccountMgr *account_mgr, const gchar
                return NULL;
        }
        
-       tny_camel_account_set_session (TNY_CAMEL_ACCOUNT(tny_account), session);
        tny_account_set_forget_pass_func (tny_account,
                                          forget_pass_func ? forget_pass_func : forget_pass_dummy);
        tny_account_set_pass_func (tny_account,
@@ -448,6 +541,9 @@ typedef struct
        gpointer user_data;
 } GetMmcAccountNameData;
 
+
+
+
 /* Gets the memory card name: */
 static void 
 on_modest_file_system_info(HildonFileSystemInfoHandle *handle,
@@ -460,27 +556,23 @@ on_modest_file_system_info(HildonFileSystemInfoHandle *handle,
                g_warning ("%s: error=%s", __FUNCTION__, error->message);
        }
        
+       TnyAccount *account = TNY_ACCOUNT (callback_data->account);
+       
+       const gchar *previous_display_name = NULL;
+       
        const gchar *display_name = NULL;
        if (!error && info) {
                display_name = hildon_file_system_info_get_display_name(info);
-               printf ("DEBUG: %s: display name=%s\n", __FUNCTION__,  display_name);
+               previous_display_name = tny_account_get_name (account);
        }
-       
-       TnyAccount *account = TNY_ACCOUNT (callback_data->account);
-       
-       const gchar * previous_display_name = tny_account_get_name (account);
-       
-       /* Use the new name if it is different: */
-       if (display_name && 
-               (previous_display_name && (strcmp (display_name, previous_display_name) != 0))) {
-               /* printf ("DEBUG: %s: display name=%s\n", __FUNCTION__,  display_name); */
-               tny_account_set_name (account, display_name);
+                
+       /* printf ("DEBUG: %s: display name=%s\n", __FUNCTION__,  display_name); */
+       tny_account_set_name (account, display_name);
                
-               /* Inform the application that the name is now ready: */
-               if (callback_data->callback)
-                       (*(callback_data->callback)) (callback_data->account, 
-                               callback_data->user_data);
-       }
+       /* Inform the application that the name is now ready: */
+       if (callback_data->callback)
+               (*(callback_data->callback)) (callback_data->account, 
+                       callback_data->user_data);
        
        g_object_unref (callback_data->account);
        g_slice_free (GetMmcAccountNameData, callback_data);
@@ -488,32 +580,54 @@ on_modest_file_system_info(HildonFileSystemInfoHandle *handle,
 
 void modest_tny_account_get_mmc_account_name (TnyStoreAccount* self, ModestTnyAccountGetMmcAccountNameCallback callback, gpointer user_data)
 {
+       /* Just use the hard-coded path for the single memory card,
+        * rather than try to figure out the path to the specific card by 
+        * looking at the maildir URI:
+        */
+       const gchar *uri_real = MODEST_MCC1_VOLUMEPATH_URI;
+
+       /*
        gchar* uri = tny_account_get_url_string (TNY_ACCOUNT (self));
        if (!uri)
                return;
+
+       TODO: This gets the name of the folder, but we want the name of the volume.
+       gchar *uri_real = NULL;
+       const gchar* prefix = "maildir://localhost/";
+       if ((strstr (uri, prefix) == uri) && (strlen(uri) > strlen(prefix)) )
+               uri_real = g_strconcat ("file:///", uri + strlen (prefix), NULL);
+       */
+
+       if (uri_real) {
+               //This is freed in the callback:
+               GetMmcAccountNameData * callback_data = g_slice_new0(GetMmcAccountNameData);
+               callback_data->account = self;
+               g_object_ref (callback_data->account); /* Unrefed when we destroy the struct. */
+               callback_data->callback = callback;
+               callback_data->user_data = user_data;
                
-       //This is freed in the callback:
-       GetMmcAccountNameData * callback_data = g_slice_new0(GetMmcAccountNameData);
-       callback_data->account = self;
-       g_object_ref (callback_data->account); /* Unrefed when we destroy the struct. */
-       callback_data->user_data = user_data;
-               
-       /* TODO: gnome_vfs_volume_get_display_name() does not return 
-        * the same string. But why not? Why does hildon needs its own 
-        * function for this?
-        */
-       printf ("DEBUG: %s Calling hildon_file_system_info_async_new() with URI=%s\n", __FUNCTION__, uri);
-       hildon_file_system_info_async_new(uri, 
-               on_modest_file_system_info, callback_data /* user_data */);
+               /* TODO: gnome_vfs_volume_get_display_name() does not return 
+                * the same string. But why not? Why does hildon needs its own 
+                * function for this?
+                */
+               /* printf ("DEBUG: %s Calling hildon_file_system_info_async_new() with URI=%s\n", __FUNCTION__, uri_real); */
+               hildon_file_system_info_async_new(uri_real, 
+                       on_modest_file_system_info, callback_data /* user_data */);
+
+               /* g_free (uri_real); */
+       }
 
-       g_free (uri);
+       /* g_free (uri); */
 }
 
                                
 
 TnyAccount*
-modest_tny_account_new_for_local_folders (ModestAccountMgr *account_mgr, TnySessionCamel *session, const gchar* location_filepath)
+modest_tny_account_new_for_local_folders (ModestAccountMgr *account_mgr, TnySessionCamel *session,
+                                         const gchar* location_filepath)
 {
+
+       
        /* Make sure that the directories exist: */
        modest_init_local_folders (location_filepath);
 
@@ -522,6 +636,8 @@ modest_tny_account_new_for_local_folders (ModestAccountMgr *account_mgr, TnySess
        gchar *maildir, *url_string;
 
        g_return_val_if_fail (account_mgr, NULL);
+       g_return_val_if_fail (session, NULL);
+
        
        if (!location_filepath) {
                /* A NULL filepath means that this is the special local-folders maildir 
@@ -607,10 +723,13 @@ modest_tny_account_new_for_local_folders (ModestAccountMgr *account_mgr, TnySess
 
 
 TnyAccount*
-modest_tny_account_new_for_per_account_local_outbox_folder (ModestAccountMgr *account_mgr, const gchar* account_name, TnySessionCamel *session)
+modest_tny_account_new_for_per_account_local_outbox_folder (ModestAccountMgr *account_mgr,
+                                                           const gchar* account_name,
+                                                           TnySessionCamel *session)
 {
        g_return_val_if_fail (account_mgr, NULL);
        g_return_val_if_fail (account_name, NULL);
+       g_return_val_if_fail (session, NULL);
        
        /* Notice that we create a ModestTnyOutboxAccount here, 
         * instead of just a TnyCamelStoreAccount,