* Fixes NB#85964, do not crash when opening Drafts in memory full condition
[modest] / src / modest-tny-account-store.c
index 8891dba..eb1f357 100644 (file)
@@ -79,7 +79,7 @@ static void    on_account_inserted         (ModestAccountMgr *acc_mgr,
                                            const gchar *account,
                                            gpointer user_data);
 
-static void    add_existing_accounts       (ModestTnyAccountStore *self);
+static void   add_existing_accounts       (ModestTnyAccountStore *self);
 
 static void    insert_account              (ModestTnyAccountStore *self,
                                            const gchar *account,
@@ -108,10 +108,14 @@ static void    forget_password_in_memory (ModestTnyAccountStore *self,
 
 static void    add_connection_specific_transport_accounts         (ModestTnyAccountStore *self);
 
+static void    remove_connection_specific_transport_accounts      (ModestTnyAccountStore *self);
+
 static void    connection_status_changed   (TnyAccount *account, 
                                            TnyConnectionStatus status, 
                                            gpointer data);
 
+static gboolean only_local_accounts        (ModestTnyAccountStore *self);
+
 /* list my signals */
 enum {
        ACCOUNT_CHANGED_SIGNAL,
@@ -297,20 +301,6 @@ modest_tny_account_store_instance_init (ModestTnyAccountStore *obj)
 
 /* disconnect the list of TnyAccounts */
 static void
-account_disconnect (TnyAccount *account)
-{
-       g_return_if_fail (account && TNY_IS_ACCOUNT(account));
-
-       if (TNY_IS_STORE_ACCOUNT (account) && 
-           !modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
-               return;
-
-       tny_camel_account_set_online (TNY_CAMEL_ACCOUNT(account), FALSE, NULL, NULL);
-}
-
-
-/* disconnect the list of TnyAccounts */
-static void
 account_verify_last_ref (TnyAccount *account, const gchar *str)
 {
        gchar *txt;
@@ -521,9 +511,8 @@ show_wrong_password_dialog (TnyAccount *account)
 { 
        /* This is easier than using a struct for the user_data: */
        ModestTnyAccountStore *self = modest_runtime_get_account_store();
-       const gchar *modest_account_name;
        GtkWidget *main_window;
-       GtkWidget *dialog;
+       GtkWidget *dialog = NULL;
 
        main_window = (GtkWidget *) modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (),
                                                                       FALSE); /* don't create */
@@ -532,16 +521,15 @@ show_wrong_password_dialog (TnyAccount *account)
                return;
        }
 
-       modest_account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
-       if (!modest_account_name) {
-               g_warning ("%s: modest_tny_account_get_parent_modest_account_name_for_server_account() failed.\n", 
-                       __FUNCTION__);
+       if (g_object_get_data (G_OBJECT (account), "connection_specific") != NULL) {
+               modest_ui_actions_on_smtp_servers (NULL, NULL);
+       } else {
+               const gchar *modest_account_name;
+               modest_account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);   
+               dialog = modest_tny_account_store_show_account_settings_dialog (self, modest_account_name);
        }
-       
-       dialog = modest_tny_account_store_show_account_settings_dialog (self, modest_account_name);
-       modest_account_settings_dialog_save_password (MODEST_ACCOUNT_SETTINGS_DIALOG (dialog));
        /* Show an explanatory temporary banner: */
-       modest_platform_information_banner (GTK_WIDGET(dialog), NULL, _("mcen_ib_username_pw_incorrect"));
+       modest_platform_information_banner (dialog, NULL, _("mcen_ib_username_pw_incorrect"));
 }
 
 /* This callback will be called by Tinymail when it needs the password
@@ -700,7 +688,13 @@ get_password (TnyAccount *account, const gchar * prompt_not_used, gboolean *canc
                if (!*cancel) {
                        /* The password will be returned as the result,
                         * but we need to tell tinymail about the username too: */
-                       tny_account_set_user (account, username);
+
+                       /* WARNING: I disabled setting username as this can cause locks. Anyway,
+                        * as now we have the password dialog username entry always dimmed
+                        * this shouldn't be a problem */
+
+                       /* if (username) */
+                       /*      tny_account_set_user (account, username); */
                        
                        /* Do not save the password in gconf, because
                         * the UI spec says "The password will never
@@ -829,14 +823,12 @@ modest_tny_account_store_finalize (GObject *obj)
 
        /* Destroy all accounts. Disconnect all accounts before they are destroyed */
        if (priv->store_accounts) {
-               tny_list_foreach (priv->store_accounts, (GFunc)account_disconnect, NULL);
                tny_list_foreach (priv->store_accounts, (GFunc)account_verify_last_ref, "store");
                g_object_unref (priv->store_accounts);
                priv->store_accounts = NULL;
        }
        
        if (priv->transport_accounts) {
-               tny_list_foreach (priv->transport_accounts, (GFunc)account_disconnect, NULL);
                tny_list_foreach (priv->transport_accounts, (GFunc)account_verify_last_ref, "transport");
                g_object_unref (priv->transport_accounts);
                priv->transport_accounts = NULL;
@@ -964,15 +956,9 @@ modest_tny_account_store_new (ModestAccountMgr *account_mgr,
           global OUTBOX hosted in the local account */
        add_existing_accounts (MODEST_TNY_ACCOUNT_STORE (obj));
        
-       /* FIXME: I'm doing this (adding an "if (FALSE)"because this
-          stuff is not working properly and could cause SIGSEVs, for
-          example one send queue will be created for each connection
-          specific SMTP server, so when tinymail asks for the outbox
-          it will return NULL because there is no outbox folder for
-          this specific transport accounts, and it's a must that the
-          send queue returns an outbox */
-       if (TRUE)
-               /* Add connection-specific transport accounts */
+       /* Add connection-specific transport accounts if there are any
+          accounts available */
+       if (!only_local_accounts (MODEST_TNY_ACCOUNT_STORE(obj)))
                add_connection_specific_transport_accounts (MODEST_TNY_ACCOUNT_STORE(obj));
        
        /* This is a singleton, so it does not need to be unrefed. */
@@ -1067,18 +1053,16 @@ modest_tny_account_store_alert (TnyAccountStore *self,
 {
        ModestTransportStoreProtocol proto =
                MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN; 
-       const gchar* server_name = NULL;
+       const gchar* server_name = "";
        gchar *prompt = NULL;
        gboolean retval;
 
-
-       g_return_val_if_fail (account, FALSE);
+       /* NOTE: account may be NULL in some cases */
        g_return_val_if_fail (error, FALSE);
        
        /* Get the server name: */
-       server_name = tny_account_get_hostname (account);
-
        if (account) {
+               server_name = tny_account_get_hostname (account);
                const gchar *proto_name = tny_account_get_proto (account);
                if (proto_name)
                        proto = modest_protocol_info_get_transport_store_protocol (proto_name);
@@ -1159,8 +1143,17 @@ modest_tny_account_store_alert (TnyAccountStore *self,
        if (error->code == TNY_SERVICE_ERROR_CERTIFICATE)
                retval = modest_platform_run_certificate_confirmation_dialog (server_name,
                                                                              error->message);
-       else
-               retval = modest_platform_run_alert_dialog (prompt, question);
+       else {
+               modest_platform_run_information_dialog (NULL, prompt, TRUE);
+
+               /* Show the account dialog if it was wrong */
+               if (error->code == TNY_SERVICE_ERROR_CONNECT || 
+                   error->code == TNY_SERVICE_ERROR_AUTHENTICATE)
+                       show_wrong_password_dialog (account);
+
+               retval = TRUE;
+       }
+
        
        if (prompt)
                g_free (prompt);
@@ -1598,54 +1591,97 @@ create_tny_account (ModestTnyAccountStore *self,
        return account;
 }
 
+typedef struct _AddOutboxInfo {
+       ModestTnyAccountStore *account_store;
+       TnyAccount *transport_account;
+} AddOutboxInfo;
 
 static void
-add_outbox_from_transport_account_to_global_outbox (ModestTnyAccountStore *self,
-                                                   const gchar *account_name,
-                                                   TnyAccount *transport_account)
+add_outbox_from_transport_account_to_global_outbox_get_folders_cb (TnyFolderStore *folder_store,
+                                                                  gboolean cancelled,
+                                                                  TnyList *list,
+                                                                  GError *err,
+                                                                  gpointer userdata)
 {
-       TnyList *folders = NULL;
-       TnyIterator *iter_folders = NULL;
-       TnyAccount *local_account = NULL, *account_outbox = NULL;
-       TnyFolder *per_account_outbox = NULL;
+       TnyIterator *iter_folders;
+       TnyFolder *per_account_outbox;
+       TnyAccount *local_account = NULL;
+       AddOutboxInfo *info = (AddOutboxInfo *) userdata;
        ModestTnyAccountStorePrivate *priv = NULL;
+       ModestTnyAccountStore *self;
 
+       self = MODEST_TNY_ACCOUNT_STORE (info->account_store);
        priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
-
-       /* Create per account local outbox */
-       account_outbox = 
-               modest_tny_account_new_for_per_account_local_outbox_folder (priv->account_mgr, 
-                                                                           account_name, 
-                                                                           priv->session);
-       tny_list_append (priv->store_accounts_outboxes, G_OBJECT (account_outbox));
-
-       /* Get the outbox folder */
-       folders = tny_simple_list_new ();
-       tny_folder_store_get_folders (TNY_FOLDER_STORE (account_outbox), folders, NULL, NULL);
-       if (tny_list_get_length (folders) != 1) {
-               g_warning ("%s: > 1 outbox found (%d)?!", __FUNCTION__,
-                          tny_list_get_length (folders));
+       
+       /* Note that this could happen if there is not enough space
+          available on disk, then the outbox folder could not be
+          created */
+       if (tny_list_get_length (list) != 1) {
+               g_warning ("%s: could not create outbox folder (%d folders found)", __FUNCTION__,
+                          tny_list_get_length (list));
+               goto frees;
        }
                        
-       iter_folders = tny_list_create_iterator (folders);
+       iter_folders = tny_list_create_iterator (list);
        per_account_outbox = TNY_FOLDER (tny_iterator_get_current (iter_folders));
        g_object_unref (iter_folders);
-       g_object_unref (folders);
-       g_object_unref (account_outbox);
+       g_object_unref (list);
 
        /* Add the outbox of the new per-account-local-outbox account
           to the global local merged OUTBOX of the local folders
           account */
-       local_account = modest_tny_account_store_get_local_folders_account (self);
+       local_account = modest_tny_account_store_get_local_folders_account (info->account_store);
        modest_tny_local_folders_account_add_folder_to_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
                                                               per_account_outbox);
        /* Add the pair to the hash table */
        g_hash_table_insert (priv->outbox_of_transport,
-                            transport_account,
+                            info->transport_account,
                             per_account_outbox);
        
+       /* Notify that the local account changed */
+       g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
        g_object_unref (local_account);
        g_object_unref (per_account_outbox);
+
+ frees:
+       g_object_unref (info->transport_account);
+       g_slice_free (AddOutboxInfo, info);
+}
+                                                                  
+
+static void
+add_outbox_from_transport_account_to_global_outbox (ModestTnyAccountStore *self,
+                                                   const gchar *account_name,
+                                                   TnyAccount *transport_account)
+{
+       TnyList *folders = NULL;
+       TnyAccount *account_outbox = NULL;
+       ModestTnyAccountStorePrivate *priv = NULL;
+       AddOutboxInfo *info;
+
+       priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
+
+       /* Create per account local outbox */
+       account_outbox = 
+               modest_tny_account_new_for_per_account_local_outbox_folder (priv->account_mgr, 
+                                                                           account_name, 
+                                                                           priv->session);
+
+       if (!G_IS_OBJECT (account_outbox)) {
+               g_warning ("%s: could not create per account local outbox folder", __FUNCTION__);
+               return;
+       }
+
+       tny_list_append (priv->store_accounts_outboxes, G_OBJECT (account_outbox));
+       
+       /* Get the outbox folder */
+       folders = tny_simple_list_new ();
+       info = g_slice_new0 (AddOutboxInfo);
+       info->account_store = self;
+       info->transport_account = g_object_ref (transport_account);
+       tny_folder_store_get_folders_async (TNY_FOLDER_STORE (account_outbox), folders, NULL, 
+                                           add_outbox_from_transport_account_to_global_outbox_get_folders_cb, NULL, (gpointer) info);
+       g_object_unref (account_outbox);
 }
 
 /*
@@ -1685,21 +1721,13 @@ insert_account (ModestTnyAccountStore *self,
        /* Create a new pseudo-account with an outbox for this
           transport account and add it to the global outbox
           in the local account */
-       add_outbox_from_transport_account_to_global_outbox (self, account, transport_account);
-       
+       add_outbox_from_transport_account_to_global_outbox (self, account, transport_account);  
+
        /* Notify the observers. We do it after everything is
           created */
        if (notify) {
-               TnyAccount *local_account = NULL;
-               
-               /* Notify the observers about the new server & transport accounts */
                g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, store_account);   
                g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, transport_account);
-
-               /* Notify that the local account changed */
-               local_account = modest_tny_account_store_get_local_folders_account (self);
-               g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
-               g_object_unref (local_account);
        }
 
        /* Frees */
@@ -1707,13 +1735,46 @@ insert_account (ModestTnyAccountStore *self,
        g_object_unref (transport_account);
 }
 
+static gboolean
+only_local_accounts (ModestTnyAccountStore *self)
+{
+       ModestTnyAccountStorePrivate *priv = NULL;
+       gboolean only_local = TRUE;
+       TnyIterator *iter;
+
+       /* Check if this is the first remote account we add */
+       priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
+       iter = tny_list_create_iterator (priv->store_accounts);
+
+       while (!tny_iterator_is_done (iter) && only_local) {
+               TnyAccount *account = (TnyAccount *) tny_iterator_get_current (iter);
+               if (modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
+                       only_local = FALSE;
+               g_object_unref (account);
+               tny_iterator_next (iter);
+       }
+       g_object_unref (iter);
+
+       return only_local;
+}
+
 static void
 on_account_inserted (ModestAccountMgr *acc_mgr, 
                     const gchar *account,
                     gpointer user_data)
 {
+       gboolean add_specific;
+
+       add_specific = only_local_accounts (MODEST_TNY_ACCOUNT_STORE (user_data));
+               
        /* Insert the account and notify the observers */
        insert_account (MODEST_TNY_ACCOUNT_STORE (user_data), account, TRUE);
+
+       /* If it's the first remote account then add the connection
+          specific SMTP servers as well */
+       if (add_specific)
+               add_connection_specific_transport_accounts (MODEST_TNY_ACCOUNT_STORE (user_data));
+
 }
 
 /* This is the callback of the tny_camel_account_set_online called in
@@ -1746,8 +1807,73 @@ on_account_disconnect_when_removing (TnyCamelAccount *account,
        g_object_unref (account);
 
        /* Clear the cache if it's an store account */
-       if (TNY_IS_STORE_ACCOUNT (account))
+       if (TNY_IS_STORE_ACCOUNT (account)) {
                tny_store_account_delete_cache (TNY_STORE_ACCOUNT (account));
+       } else if (TNY_IS_TRANSPORT_ACCOUNT (account)) {
+               ModestTnySendQueue* send_queue;
+               send_queue = modest_runtime_get_send_queue (TNY_TRANSPORT_ACCOUNT (account), FALSE);
+               if (TNY_IS_SEND_QUEUE (send_queue)) {
+                       if (modest_tny_send_queue_sending_in_progress (send_queue))
+                               tny_send_queue_cancel (TNY_SEND_QUEUE (send_queue),
+                                                      TNY_SEND_QUEUE_CANCEL_ACTION_REMOVE, 
+                                                      NULL);
+                       modest_runtime_remove_send_queue (TNY_TRANSPORT_ACCOUNT (account));
+               }
+       }
+}
+
+/*
+ * We use this one for both removing "normal" and "connection
+ * specific" transport accounts
+ */
+static void
+remove_transport_account (ModestTnyAccountStore *self,
+                         TnyTransportAccount *transport_account)
+{
+       ModestTnyAccountStorePrivate *priv;
+       TnyFolder *outbox = NULL;
+       
+       priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
+
+       /* Remove it from the list of accounts and notify the
+          observers. Do not need to wait for account
+          disconnection */
+       g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 0, transport_account);
+       tny_list_remove (priv->transport_accounts, (GObject *) transport_account);
+               
+       /* Remove the OUTBOX of the account from the global outbox */
+       outbox = g_hash_table_lookup (priv->outbox_of_transport, transport_account);
+
+       if (TNY_IS_FOLDER (outbox)) {
+               TnyAccount *local_account = NULL;
+               TnyAccount *outbox_account = tny_folder_get_account (outbox);
+
+               if (outbox_account) {
+                       tny_list_remove (priv->store_accounts_outboxes, G_OBJECT (outbox_account));
+                       /* Remove existing emails to send */
+                       tny_store_account_delete_cache (TNY_STORE_ACCOUNT (outbox_account));
+                       g_object_unref (outbox_account);
+               }
+
+               local_account = modest_tny_account_store_get_local_folders_account (self);
+               modest_tny_local_folders_account_remove_folder_from_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
+                                                                           outbox);
+
+               g_hash_table_remove (priv->outbox_of_transport, transport_account);
+
+               /* Notify the change in the local account */
+               g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
+               g_object_unref (local_account);
+       } else {
+               g_warning ("Removing a transport account that has no outbox");
+       }
+
+       /* Cancel all pending operations */
+       tny_account_cancel (TNY_ACCOUNT (transport_account));
+
+       /* Disconnect and notify the observers. The callback will free the reference */
+       tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (transport_account), FALSE,
+                                     on_account_disconnect_when_removing, self);
 }
 
 static void
@@ -1764,13 +1890,15 @@ on_account_removed (ModestAccountMgr *acc_mgr,
 
        /* Get the server and the transport account */
        store_account = 
-               modest_tny_account_store_get_server_account (self, account, TNY_ACCOUNT_TYPE_STORE);
+               modest_tny_account_store_get_server_account (self, account, 
+                                                            TNY_ACCOUNT_TYPE_STORE);
        transport_account = 
-               modest_tny_account_store_get_server_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT);
+               modest_tny_account_store_get_server_account (self, account,
+                                                            TNY_ACCOUNT_TYPE_TRANSPORT);
        
        /* If there was any problem creating the account, for example,
           with the configuration system this could not exist */
-       if (store_account) {
+       if (TNY_IS_STORE_ACCOUNT(store_account)) {
                /* Forget any cached password for the account */
                forget_password_in_memory (self, tny_account_get_id (store_account));
 
@@ -1789,56 +1917,29 @@ on_account_removed (ModestAccountMgr *acc_mgr,
                tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (store_account), FALSE,
                                              on_account_disconnect_when_removing, self);
        } else {
-               g_warning ("There is no store account for account %s\n", account);
+               g_warning ("%s: no store account for account %s\n", 
+                          __FUNCTION__, account);
        }
 
        /* If there was any problem creating the account, for example,
           with the configuration system this could not exist */
-       if (transport_account) {
-               TnyAccount *local_account = NULL;
-               TnyFolder *outbox = NULL;
+       if (TNY_IS_TRANSPORT_ACCOUNT(transport_account)) {
 
                /* Forget any cached password for the account */
                forget_password_in_memory (self, tny_account_get_id (transport_account));
 
-               /* Remove it from the list of accounts and notify the
-                  observers. Do not need to wait for account
-                  disconnection */
-               tny_list_remove (priv->transport_accounts, (GObject *) transport_account);
-               g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 0, transport_account);
-       
-               /* Remove the OUTBOX of the account from the global outbox */
-               outbox = g_hash_table_lookup (priv->outbox_of_transport, transport_account);
-
-               if (TNY_IS_FOLDER (outbox)) {
-                       TnyAccount *outbox_account = tny_folder_get_account (outbox);
-
-                       if (outbox_account) {
-                               tny_list_remove (priv->store_accounts_outboxes, G_OBJECT (outbox_account));
-                               g_object_unref (outbox_account);
-                       }
-
-                       local_account = modest_tny_account_store_get_local_folders_account (self);
-                       modest_tny_local_folders_account_remove_folder_from_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
-                                                                                   outbox);
-                       g_hash_table_remove (priv->outbox_of_transport, transport_account);
-
-                       /* Notify the change in the local account */
-                       g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
-                       g_object_unref (local_account);
-               } else {
-                       g_warning ("Removing a transport account that has no outbox");
-               }
-
-               /* Cancel all pending operations */
-               tny_account_cancel (TNY_ACCOUNT (transport_account));
-
-               /* Disconnect and notify the observers. The callback will free the reference */
-               tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (transport_account), FALSE,
-                                             on_account_disconnect_when_removing, self);
+               /* Remove transport account. It'll free the reference
+                  added by get_server_account */
+               remove_transport_account (self, TNY_TRANSPORT_ACCOUNT (transport_account));
        } else {
-               g_warning ("There is no transport account for account %s\n", account);
+               g_warning ("%s: no transport account for account %s\n", 
+                          __FUNCTION__, account);
        }
+
+       /* If there are no more user accounts then delete the
+          transport specific SMTP servers */
+       if (only_local_accounts (self))
+               remove_connection_specific_transport_accounts (self);
 }
 
 TnyTransportAccount *
@@ -1861,6 +1962,9 @@ modest_tny_account_store_new_connection_specific_transport_account (ModestTnyAcc
                g_object_set_data (G_OBJECT(tny_account), 
                                   "account_store", 
                                   (gpointer)self);
+               g_object_set_data (G_OBJECT(tny_account), 
+                                  "connection_specific", 
+                                  GINT_TO_POINTER (TRUE));
                
                tny_list_append (priv->transport_accounts, G_OBJECT (tny_account));
                add_outbox_from_transport_account_to_global_outbox (self, 
@@ -1880,19 +1984,16 @@ add_connection_specific_transport_accounts (ModestTnyAccountStore *self)
 {
        ModestTnyAccountStorePrivate *priv = NULL;
        GSList *list_specifics = NULL, *iter = NULL;
+       GError *err = NULL;
 
        priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
 
-       ModestConf *conf = modest_runtime_get_conf ();
-
-       GError *err = NULL;
-       list_specifics = modest_conf_get_list (conf,
+       list_specifics = modest_conf_get_list (modest_runtime_get_conf (),
                                               MODEST_CONF_CONNECTION_SPECIFIC_SMTP_LIST,
                                               MODEST_CONF_VALUE_STRING, &err);
        if (err) {
-               g_printerr ("modest: %s: error getting list: %s\n.", __FUNCTION__, err->message);
                g_error_free (err);
-               err = NULL;
+               g_return_if_reached ();
        }
                                
        /* Look at each connection-specific transport account for the 
@@ -1913,6 +2014,46 @@ add_connection_specific_transport_accounts (ModestTnyAccountStore *self)
        }
 }
 
+static void
+remove_connection_specific_transport_accounts (ModestTnyAccountStore *self)
+{
+       ModestTnyAccountStorePrivate *priv = NULL;
+       GSList *list_specifics = NULL, *iter = NULL;
+       GError *err = NULL;
+
+       priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
+
+       err = NULL;
+       list_specifics = modest_conf_get_list (modest_runtime_get_conf (),
+                                              MODEST_CONF_CONNECTION_SPECIFIC_SMTP_LIST,
+                                              MODEST_CONF_VALUE_STRING, &err);
+       if (err) {
+               g_error_free (err);
+               g_return_if_reached ();
+       }
+                               
+       /* Look at each connection-specific transport account for the 
+        * modest account: */
+       iter = list_specifics;
+       while (iter) {
+               /* The list alternates between the connection name and the transport name: */
+               iter = g_slist_next (iter);
+               if (iter) {
+                       const gchar* transport_account_name = (const gchar*) (iter->data);
+                       TnyAccount * account;
+                       account = modest_tny_account_store_get_server_account (self,
+                                                                              transport_account_name,
+                                                                              TNY_ACCOUNT_TYPE_TRANSPORT);
+                       if (account) {
+                               remove_transport_account (self, TNY_TRANSPORT_ACCOUNT (account));
+                               g_object_unref (account);
+                       }
+               }                               
+               iter = g_slist_next (iter);
+       }
+}
+
+
 TnyMsg *
 modest_tny_account_store_find_msg_in_outboxes (ModestTnyAccountStore *self, 
                                               const gchar *uri,
@@ -1966,27 +2107,28 @@ modest_tny_account_store_get_transport_account_from_outbox_header(ModestTnyAccou
        TnyIterator *acc_iter;
        ModestTnyAccountStorePrivate *priv;
        TnyTransportAccount *header_acc = NULL;
-       const gchar *msg_id;
+       gchar *msg_id;
 
        g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
        g_return_val_if_fail (TNY_IS_HEADER (header), NULL);
        priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
-
        msg_id = modest_tny_send_queue_get_msg_id (header);
        acc_iter = tny_list_create_iterator (priv->transport_accounts);
        while (!header_acc && !tny_iterator_is_done (acc_iter)) {
                TnyTransportAccount *account = TNY_TRANSPORT_ACCOUNT (tny_iterator_get_current (acc_iter));
                ModestTnySendQueue *send_queue;
                ModestTnySendQueueStatus status;
-               send_queue = modest_runtime_get_send_queue(TNY_TRANSPORT_ACCOUNT(account));
-               status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
-               if (status != MODEST_TNY_SEND_QUEUE_UNKNOWN) {
-                       header_acc = g_object_ref(account);
+               send_queue = modest_runtime_get_send_queue(TNY_TRANSPORT_ACCOUNT(account), TRUE);
+               if (TNY_IS_SEND_QUEUE (send_queue)) {
+                       status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
+                       if (status != MODEST_TNY_SEND_QUEUE_UNKNOWN)
+                               header_acc = g_object_ref(account);
                }
                g_object_unref (account);
                tny_iterator_next (acc_iter);
        }
        g_object_unref(acc_iter);
+       g_free (msg_id);
 
        /* New reference */
        return header_acc;
@@ -2004,16 +2146,19 @@ modest_tny_account_store_show_account_settings_dialog (ModestTnyAccountStore *se
        found = g_hash_table_lookup_extended (priv->account_settings_dialog_hash,
                                              account_name, NULL, (gpointer*)&dialog_as_gpointer);
 
-       if (found)
+       if (found) {
+               modest_account_settings_dialog_check_allow_changes ((ModestAccountSettingsDialog *) dialog_as_gpointer);
                return (GtkWidget *) dialog_as_gpointer;
-       else {
+       } else {
                ModestAccountSettings *settings;
                GtkWidget *dialog;
                dialog = (GtkWidget *) modest_account_settings_dialog_new ();
                settings = modest_account_mgr_load_account_settings (priv->account_mgr, account_name);
+               modest_account_settings_dialog_save_password (MODEST_ACCOUNT_SETTINGS_DIALOG (dialog));
                modest_account_settings_dialog_set_account (MODEST_ACCOUNT_SETTINGS_DIALOG (dialog), settings);
                g_object_unref (settings);
                modest_account_settings_dialog_switch_to_user_info (MODEST_ACCOUNT_SETTINGS_DIALOG (dialog));
+               modest_account_settings_dialog_check_allow_changes (MODEST_ACCOUNT_SETTINGS_DIALOG (dialog));
                modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), GTK_WINDOW (dialog));
                
                g_hash_table_insert (priv->account_settings_dialog_hash, g_strdup (account_name), dialog);
@@ -2032,3 +2177,67 @@ modest_tny_account_store_show_account_settings_dialog (ModestTnyAccountStore *se
        }
        
 }
+
+typedef struct {
+       ModestTnyAccountStore *account_store;
+       ModestTnyAccountStoreShutdownCallback callback;
+       gpointer userdata;
+       gint pending;
+} ShutdownOpData;
+
+static void
+account_shutdown_callback (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer userdata)
+{
+       ShutdownOpData *op_data = (ShutdownOpData *) userdata;
+       op_data->pending--;
+       if (op_data->pending == 0) {
+               if (op_data->callback)
+                       op_data->callback (op_data->account_store, op_data->userdata);
+               g_object_unref (op_data->account_store);
+               g_free (op_data);
+       }
+}
+
+static void
+account_shutdown (TnyAccount *account, ShutdownOpData *op_data)
+{
+       g_return_if_fail (account && TNY_IS_ACCOUNT(account));
+
+       if (TNY_IS_STORE_ACCOUNT (account) && 
+           !modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
+               return;
+
+       op_data->pending++;
+
+       tny_camel_account_set_online (TNY_CAMEL_ACCOUNT(account), FALSE, account_shutdown_callback, op_data);
+}
+
+
+void 
+modest_tny_account_store_shutdown (ModestTnyAccountStore *self,
+                                  ModestTnyAccountStoreShutdownCallback callback,
+                                  gpointer userdata)
+{
+       ShutdownOpData *op_data = g_new0 (ShutdownOpData, 1);
+       ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
+       op_data->callback = callback;
+       op_data->userdata = userdata;
+       op_data->pending = 0;
+       op_data->account_store = g_object_ref (self);
+       
+       /* Destroy all accounts. Disconnect all accounts before they are destroyed */
+       if (priv->store_accounts) {
+               tny_list_foreach (priv->store_accounts, (GFunc)account_shutdown, op_data);
+       }
+       
+       if (priv->transport_accounts) {
+               tny_list_foreach (priv->transport_accounts, (GFunc)account_shutdown, op_data);
+       }
+
+       if (op_data->pending == 0) {
+               if (op_data->callback)
+                       op_data->callback (op_data->account_store, op_data->userdata);
+               g_object_unref (op_data->account_store);
+               g_free (op_data);
+       }
+}