Show a generic error (instead of the one from Tinymail) when
[modest] / src / modest-tny-account-store.c
1 /* Copyright (c) 2006, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <string.h>
31 #include <glib/gi18n.h>
32
33 #include <tny-account.h>
34 #include <tny-account-store.h>
35 #include <tny-store-account.h>
36 #include <tny-error.h>
37 #include <tny-transport-account.h>
38 #include <tny-simple-list.h>
39 #include <tny-account-store.h>
40 #include <tny-camel-transport-account.h>
41 #include <tny-camel-imap-store-account.h>
42 #include <tny-camel-pop-store-account.h>
43
44 #include <modest-runtime.h>
45 #include <modest-marshal.h>
46 #include <modest-protocol-info.h>
47 #include <modest-local-folder-info.h>
48 #include <modest-tny-account.h>
49 #include <modest-tny-local-folders-account.h>
50 #include <modest-account-mgr.h>
51 #include <modest-account-mgr-helpers.h>
52 #include <widgets/modest-window-mgr.h>
53 #include <modest-signal-mgr.h>
54 #include <modest-debug.h>
55
56 #include "modest-tny-account-store.h"
57 #include "modest-tny-platform-factory.h"
58 #include <tny-gtk-lockable.h>
59 #include <camel/camel.h>
60 #include <modest-platform.h>
61
62 #ifdef MODEST_PLATFORM_MAEMO
63 #include <tny-maemo-conic-device.h>
64 #include <maemo/modest-maemo-utils.h>
65 #include <maemo/modest-account-settings-dialog.h>
66 #endif
67
68 #include <libgnomevfs/gnome-vfs-volume-monitor.h>
69
70 /* 'private'/'protected' functions */
71 static void    modest_tny_account_store_class_init   (ModestTnyAccountStoreClass *klass);
72 static void    modest_tny_account_store_finalize     (GObject *obj);
73 static void    modest_tny_account_store_instance_init (ModestTnyAccountStore *obj);
74 static void    modest_tny_account_store_init          (gpointer g, gpointer iface_data);
75 static void    modest_tny_account_store_base_init     (gpointer g_class);
76
77 static void    on_account_inserted         (ModestAccountMgr *acc_mgr, 
78                                             const gchar *account,
79                                             gpointer user_data);
80
81 static void    add_existing_accounts       (ModestTnyAccountStore *self);
82
83 static void    insert_account              (ModestTnyAccountStore *self,
84                                             const gchar *account,
85                                             gboolean notify);
86
87 static void    on_account_removed          (ModestAccountMgr *acc_mgr, 
88                                             const gchar *account,
89                                             gpointer user_data);
90
91 static gchar*  get_password                (TnyAccount *account, 
92                                             const gchar * prompt_not_used, 
93                                             gboolean *cancel);
94
95 static void    forget_password             (TnyAccount *account);
96
97 static void    on_vfs_volume_mounted       (GnomeVFSVolumeMonitor *volume_monitor, 
98                                             GnomeVFSVolume *volume, 
99                                             gpointer user_data);
100
101 static void    on_vfs_volume_unmounted     (GnomeVFSVolumeMonitor *volume_monitor, 
102                                             GnomeVFSVolume *volume, 
103                                             gpointer user_data);
104
105 static void    modest_tny_account_store_forget_password_in_memory (ModestTnyAccountStore *self, 
106                                                                    const gchar *server_account_name);
107
108 static void    add_connection_specific_transport_accounts         (ModestTnyAccountStore *self);
109
110 /* list my signals */
111 enum {
112         ACCOUNT_CHANGED_SIGNAL,
113         ACCOUNT_INSERTED_SIGNAL,
114         ACCOUNT_REMOVED_SIGNAL,
115
116         PASSWORD_REQUESTED_SIGNAL,
117         LAST_SIGNAL
118 };
119
120 typedef struct _ModestTnyAccountStorePrivate ModestTnyAccountStorePrivate;
121 struct _ModestTnyAccountStorePrivate {
122         gchar              *cache_dir;  
123         GHashTable         *password_hash;
124 #ifdef MODEST_PLATFORM_MAEMO
125         GHashTable         *account_settings_dialog_hash;
126 #endif
127         ModestAccountMgr   *account_mgr;
128         TnySessionCamel    *session;
129         TnyDevice          *device;
130
131         GSList *sighandlers;
132         
133         /* We cache the lists of accounts here */
134         TnyList             *store_accounts;
135         TnyList             *transport_accounts;
136         TnyList             *store_accounts_outboxes;
137         
138         /* Matches transport accounts and outbox folder */
139         GHashTable          *outbox_of_transport;
140 };
141
142 #define MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
143                                                       MODEST_TYPE_TNY_ACCOUNT_STORE, \
144                                                       ModestTnyAccountStorePrivate))
145
146 /* globals */
147 static GObjectClass *parent_class = NULL;
148
149 static guint signals[LAST_SIGNAL] = {0};
150
151 GType
152 modest_tny_account_store_get_type (void)
153 {
154         static GType my_type = 0;
155
156         if (!my_type) {
157                 static const GTypeInfo my_info = {
158                         sizeof(ModestTnyAccountStoreClass),
159                         modest_tny_account_store_base_init,     /* base init */
160                         NULL,           /* base finalize */
161                         (GClassInitFunc) modest_tny_account_store_class_init,
162                         NULL,           /* class finalize */
163                         NULL,           /* class data */
164                         sizeof(ModestTnyAccountStore),
165                         0,              /* n_preallocs */
166                         (GInstanceInitFunc) modest_tny_account_store_instance_init,
167                         NULL
168                 };
169
170                 static const GInterfaceInfo iface_info = {
171                         (GInterfaceInitFunc) modest_tny_account_store_init,
172                         NULL,         /* interface_finalize */
173                         NULL          /* interface_data */
174                 };
175                 /* hack hack */
176                 my_type = g_type_register_static (G_TYPE_OBJECT,
177                                                   "ModestTnyAccountStore",
178                                                   &my_info, 0);
179                 g_type_add_interface_static (my_type, TNY_TYPE_ACCOUNT_STORE,
180                                              &iface_info);
181         }
182         return my_type;
183 }
184
185
186 static void
187 modest_tny_account_store_base_init (gpointer g_class)
188 {
189         static gboolean tny_account_store_initialized = FALSE;
190
191         if (!tny_account_store_initialized) {
192
193                 signals[ACCOUNT_CHANGED_SIGNAL] =
194                         g_signal_new ("account_changed",
195                                       MODEST_TYPE_TNY_ACCOUNT_STORE,
196                                       G_SIGNAL_RUN_FIRST,
197                                       G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_changed),
198                                       NULL, NULL,
199                                       g_cclosure_marshal_VOID__OBJECT,
200                                       G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
201
202                 signals[ACCOUNT_INSERTED_SIGNAL] =
203                         g_signal_new ("account_inserted",
204                                       MODEST_TYPE_TNY_ACCOUNT_STORE,
205                                       G_SIGNAL_RUN_FIRST,
206                                       G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_inserted),
207                                       NULL, NULL,
208                                       g_cclosure_marshal_VOID__OBJECT,
209                                       G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
210                 
211                 signals[ACCOUNT_REMOVED_SIGNAL] =
212                         g_signal_new ("account_removed",
213                                       MODEST_TYPE_TNY_ACCOUNT_STORE,
214                                       G_SIGNAL_RUN_FIRST,
215                                       G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_removed),
216                                       NULL, NULL,
217                                       g_cclosure_marshal_VOID__OBJECT,
218                                       G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
219
220                 signals[PASSWORD_REQUESTED_SIGNAL] =
221                         g_signal_new ("password_requested",
222                                       MODEST_TYPE_TNY_ACCOUNT_STORE,
223                                       G_SIGNAL_RUN_FIRST,
224                                       G_STRUCT_OFFSET(ModestTnyAccountStoreClass, password_requested),
225                                       NULL, NULL,
226                                       modest_marshal_VOID__STRING_POINTER_POINTER_POINTER_POINTER,
227                                       G_TYPE_NONE, 5, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER,
228                                       G_TYPE_POINTER);          
229
230                 tny_account_store_initialized = TRUE;
231         }
232 }
233
234
235 static void
236 modest_tny_account_store_class_init (ModestTnyAccountStoreClass *klass)
237 {
238         GObjectClass *gobject_class;
239         gobject_class = (GObjectClass*) klass;
240
241         parent_class            = g_type_class_peek_parent (klass);
242         gobject_class->finalize = modest_tny_account_store_finalize;
243
244         g_type_class_add_private (gobject_class,
245                                   sizeof(ModestTnyAccountStorePrivate));
246 }
247      
248 static void
249 modest_tny_account_store_instance_init (ModestTnyAccountStore *obj)
250 {
251         GnomeVFSVolumeMonitor* monitor = NULL;
252         ModestTnyAccountStorePrivate *priv;
253
254         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
255
256         priv->cache_dir              = NULL;
257         priv->account_mgr            = NULL;
258         priv->session                = NULL;
259         priv->device                 = NULL;
260         priv->sighandlers            = NULL;
261         
262         priv->outbox_of_transport = g_hash_table_new_full (g_direct_hash,
263                                                            g_direct_equal,
264                                                            NULL,
265                                                            NULL);
266
267         /* An in-memory store of passwords, 
268          * for passwords that are not remembered in the configuration,
269          * so they need to be asked for from the user once in each session:
270          */
271         priv->password_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
272                                                      g_free, g_free);
273
274 #ifdef MODEST_PLATFORM_MAEMO                                                         
275         /* A hash-map of modest account names to dialog pointers,
276          * so we can avoid showing the account settings twice for the same modest account: */                                 
277         priv->account_settings_dialog_hash = g_hash_table_new_full (g_str_hash, g_str_equal, 
278                                                                     g_free, NULL);
279 #endif
280         
281         /* Respond to volume mounts and unmounts, such 
282          * as the insertion/removal of the memory card: */
283         /* This is a singleton, so it does not need to be unrefed. */
284         monitor = gnome_vfs_get_volume_monitor();
285
286         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers, 
287                                                        G_OBJECT(monitor), 
288                                                        "volume-mounted",
289                                                        G_CALLBACK(on_vfs_volume_mounted),
290                                                        obj);
291         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers, 
292                                                        G_OBJECT(monitor), "volume-unmounted",
293                                                        G_CALLBACK(on_vfs_volume_unmounted),
294                                                        obj);
295 }
296
297 /* disconnect the list of TnyAccounts */
298 static void
299 account_disconnect (TnyAccount *account)
300 {
301         g_return_if_fail (account && TNY_IS_ACCOUNT(account));
302         tny_camel_account_set_online (TNY_CAMEL_ACCOUNT(account), FALSE, NULL, NULL);
303 }
304
305
306 /* disconnect the list of TnyAccounts */
307 static void
308 account_verify_last_ref (TnyAccount *account, const gchar *str)
309 {
310         gchar *txt;
311
312         g_return_if_fail (account && TNY_IS_ACCOUNT(account));
313
314         txt = g_strdup_printf ("%s: %s", str ? str : "?", tny_account_get_name(account));
315         MODEST_DEBUG_VERIFY_OBJECT_LAST_REF(G_OBJECT(account),txt);
316         g_free (txt);
317 }
318
319
320
321
322 static void
323 foreach_account_append_to_list (gpointer data, 
324                                 gpointer user_data)
325 {
326         TnyList *list;
327         
328         list = TNY_LIST (user_data);
329         tny_list_append (list, G_OBJECT (data));
330 }
331
332 /********************************************************************/
333 /*           Control the state of the MMC local account             */
334 /********************************************************************/
335
336 /** Only call this if the memory card is really mounted.
337  */ 
338 static void
339 add_mmc_account(ModestTnyAccountStore *self, gboolean emit_insert_signal)
340 {
341         ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
342         g_return_if_fail (priv->session);
343         
344         TnyAccount *mmc_account = modest_tny_account_new_for_local_folders (priv->account_mgr, 
345                                                                         priv->session, 
346                                                                         MODEST_MCC1_VOLUMEPATH);
347
348         /* Add to the list of store accounts */
349         tny_list_append (priv->store_accounts, G_OBJECT (mmc_account));
350
351         if (emit_insert_signal) {
352                 g_signal_emit (G_OBJECT (self), 
353                                signals [ACCOUNT_INSERTED_SIGNAL],
354                                0, mmc_account);
355         }
356
357         /* Free */
358         g_object_unref (mmc_account);
359 }
360
361 static void
362 on_vfs_volume_mounted(GnomeVFSVolumeMonitor *volume_monitor, 
363                       GnomeVFSVolume *volume, 
364                       gpointer user_data)
365 {
366         ModestTnyAccountStore *self;
367         ModestTnyAccountStorePrivate *priv;
368  
369         gchar *uri = NULL;
370
371         self = MODEST_TNY_ACCOUNT_STORE(user_data);
372         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
373         
374         /* Check whether this was the external MMC1 card: */
375         uri = gnome_vfs_volume_get_activation_uri (volume);
376
377         if (uri && (!strcmp (uri, MODEST_MCC1_VOLUMEPATH_URI))) {
378                 add_mmc_account (self, TRUE /* emit the insert signal. */);
379         }
380         
381         g_free (uri);
382 }
383
384 static void
385 on_vfs_volume_unmounted(GnomeVFSVolumeMonitor *volume_monitor, 
386                         GnomeVFSVolume *volume, 
387                         gpointer user_data)
388 {
389         ModestTnyAccountStore *self;
390         ModestTnyAccountStorePrivate *priv;
391         gchar *uri = NULL;
392
393         self = MODEST_TNY_ACCOUNT_STORE(user_data);
394         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
395         
396         /* Check whether this was the external MMC1 card: */
397         uri = gnome_vfs_volume_get_activation_uri (volume);
398         if (uri && (strcmp (uri, MODEST_MCC1_VOLUMEPATH_URI) == 0)) {
399                 TnyAccount *mmc_account = NULL;
400                 gboolean found = FALSE;
401                 TnyIterator *iter = NULL;
402
403                 iter = tny_list_create_iterator (priv->store_accounts);
404                 while (!tny_iterator_is_done (iter) && !found) {
405                         TnyAccount *account;
406
407                         account = TNY_ACCOUNT (tny_iterator_get_current (iter));
408                         if (modest_tny_account_is_memory_card_account (account)) {
409                                 found = TRUE;
410                                 mmc_account = g_object_ref (account);
411                         }
412                         g_object_unref (account);
413                         tny_iterator_next (iter);
414                 }
415                 g_object_unref (iter);
416
417                 if (found) {
418                         /* Remove from the list */
419                         tny_list_remove (priv->store_accounts, G_OBJECT (mmc_account));
420                         
421                         /* Notify observers */
422                         g_signal_emit (G_OBJECT (self),
423                                        signals [ACCOUNT_REMOVED_SIGNAL],
424                                        0, mmc_account);
425
426                         g_object_unref (mmc_account);
427                 } else {
428                         g_warning ("%s: there was no store account for the unmounted MMC",
429                                    __FUNCTION__);
430                 }
431         }
432         g_free (uri);
433 }
434
435 /**
436  * modest_tny_account_store_forget_password_in_memory
437  * @self: a TnyAccountStore instance
438  * @account: A server account.
439  * 
440  * Forget any password stored in memory for this account.
441  * For instance, this should be called when the user has changed the password in the account settings.
442  */
443 static void
444 modest_tny_account_store_forget_password_in_memory (ModestTnyAccountStore *self, const gchar * server_account_name)
445 {
446         /* printf ("DEBUG: %s\n", __FUNCTION__); */
447         ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
448
449         if (server_account_name && priv->password_hash) {
450                 g_hash_table_remove (priv->password_hash, server_account_name);
451         }
452 }
453
454 static void
455 on_account_changed (ModestAccountMgr *acc_mgr, 
456                     const gchar *account_name, 
457                     TnyAccountType account_type,
458                     gpointer user_data)
459 {
460         ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(user_data);
461         ModestTnyAccountStorePrivate *priv;
462         TnyList* account_list;
463         gboolean found = FALSE;
464         TnyIterator *iter = NULL;
465
466         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
467         account_list = (account_type == TNY_ACCOUNT_TYPE_STORE ? 
468                         priv->store_accounts : 
469                         priv->transport_accounts);
470         
471         iter = tny_list_create_iterator (account_list);
472         while (!tny_iterator_is_done (iter) && !found) {
473                 TnyAccount *tny_account;
474                 tny_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
475                 if (tny_account) {
476                         if (!strcmp (tny_account_get_id (tny_account), account_name)) {
477                                 found = TRUE;
478                                 modest_tny_account_update_from_account (tny_account);
479                                 g_signal_emit (G_OBJECT(self), signals[ACCOUNT_CHANGED_SIGNAL], 0, tny_account);
480                         }
481                         g_object_unref (tny_account);
482                 }
483                 tny_iterator_next (iter);
484         }
485
486         if (iter)
487                 g_object_unref (iter);
488 }
489
490 #ifdef MODEST_PLATFORM_MAEMO
491 static void 
492 on_account_settings_hide (GtkWidget *widget, gpointer user_data)
493 {
494         TnyAccount *account = (TnyAccount*)user_data;
495         
496         /* This is easier than using a struct for the user_data: */
497         ModestTnyAccountStore *self = modest_runtime_get_account_store();
498         ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
499         
500         const gchar *modest_account_name = 
501                         modest_tny_account_get_parent_modest_account_name_for_server_account (account);
502         if (modest_account_name)
503                 g_hash_table_remove (priv->account_settings_dialog_hash, modest_account_name);
504 }
505 #endif
506
507 static void 
508 show_password_warning_only ()
509 {
510         ModestWindow *main_window = 
511                 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (), FALSE); /* don't create */
512         
513         /* Show an explanatory temporary banner: */
514         if (main_window) 
515                 modest_platform_information_banner (GTK_WIDGET(main_window), NULL, 
516                                                     _("mcen_ib_username_pw_incorrect"));
517         else
518                 g_warning ("%s: %s", __FUNCTION__, _("mcen_ib_username_pw_incorrect"));
519 }
520
521 #ifdef MODEST_PLATFORM_MAEMO
522 static void 
523 show_wrong_password_dialog (TnyAccount *account)
524
525         /* This is easier than using a struct for the user_data: */
526         ModestTnyAccountStore *self = modest_runtime_get_account_store();
527         ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
528         ModestWindow *main_window;
529         const gchar *modest_account_name;
530
531         main_window = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (),
532                                                          FALSE); /* don't create */
533         if (!main_window) {
534                 g_warning ("%s: password was wrong; ignoring because no main window", __FUNCTION__);
535                 return;
536         }
537
538         modest_account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
539         if (!modest_account_name) {
540                 g_warning ("%s: modest_tny_account_get_parent_modest_account_name_for_server_account() failed.\n", 
541                         __FUNCTION__);
542         }
543         
544         /* Check whether this window is already open,
545          * for instance because of a previous get_password() call: 
546          */
547         gpointer dialog_as_gpointer = NULL;
548         gboolean found = FALSE;
549         if (priv->account_settings_dialog_hash) {
550                 found = g_hash_table_lookup_extended (priv->account_settings_dialog_hash,
551                         modest_account_name, NULL, (gpointer*)&dialog_as_gpointer);
552         }
553         ModestAccountSettingsDialog *dialog = dialog_as_gpointer;
554                                         
555         gboolean created_dialog = FALSE;
556         if (!found || !dialog) {
557                 ModestAccountSettings *settings;
558                 dialog = modest_account_settings_dialog_new ();
559                 settings = modest_account_mgr_load_account_settings (priv->account_mgr, modest_account_name);
560                 modest_account_settings_dialog_set_account (dialog, settings);
561                 g_object_unref (settings);
562                 modest_account_settings_dialog_switch_to_user_info (dialog);
563                 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), GTK_WINDOW (dialog));
564                 
565                 g_hash_table_insert (priv->account_settings_dialog_hash, g_strdup (modest_account_name), dialog);
566                 
567                 created_dialog = TRUE;
568         }
569         
570         /* Show an explanatory temporary banner: */
571         modest_platform_information_banner (GTK_WIDGET(dialog), NULL, _("mcen_ib_username_pw_incorrect"));
572                 
573         if (created_dialog) {
574                 /* Forget it when it closes: */
575                 g_signal_connect_object (G_OBJECT (dialog), "hide", G_CALLBACK (on_account_settings_hide), 
576                         account, 0);
577                         
578                 /* Show it and delete it when it closes: */
579                 gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (main_window));
580                 g_signal_connect_swapped (dialog, 
581                                           "response", 
582                                           G_CALLBACK (gtk_widget_destroy), 
583                                           dialog);
584                 gtk_widget_show (GTK_WIDGET (dialog));
585         }
586         else {
587                 /* Just show it instead of showing it and deleting it when it closes,
588                  * though it is probably open already: */
589                 gtk_window_present (GTK_WINDOW (dialog));
590         }
591 }
592 #endif
593
594 /* This callback will be called by Tinymail when it needs the password
595  * from the user or the account settings.
596  * It can also call forget_password() before calling this,
597  * so that we clear wrong passwords out of our account settings.
598  * Note that TnyAccount here will be the server account. */
599 static gchar*
600 get_password (TnyAccount *account, const gchar * prompt_not_used, gboolean *cancel)
601 {
602         /* TODO: Settting cancel to FALSE does not actually cancel everything.
603          * We still get multiple requests afterwards, so we end up showing the 
604          * same dialogs repeatedly.
605          */       
606         const TnyAccountStore *account_store = NULL;
607         ModestTnyAccountStore *self = NULL;
608         ModestTnyAccountStorePrivate *priv;
609         gchar *username = NULL;
610         gchar *pwd = NULL;
611         gpointer pwd_ptr = NULL;
612         gboolean already_asked = FALSE;
613
614         g_return_val_if_fail (account, NULL);
615         
616         MODEST_DEBUG_BLOCK(
617                 g_debug ("DEBUG: modest: %s: prompt (not shown) = %s\n", __FUNCTION__, prompt_not_used);
618         );
619         
620         /* Initialize the output parameter: */
621         if (cancel)
622                 *cancel = FALSE;
623                 
624         const gchar *server_account_name = tny_account_get_id (account);
625         account_store = TNY_ACCOUNT_STORE(g_object_get_data (G_OBJECT(account),
626                                                              "account_store"));
627
628         if (!server_account_name || !account_store) {
629                 g_warning ("modest: %s: could not retrieve account_store for account %s",
630                            __FUNCTION__, server_account_name ? server_account_name : "<NULL>");
631                 if (cancel)
632                         *cancel = TRUE;
633                 
634                 return NULL;
635         }
636
637         self = MODEST_TNY_ACCOUNT_STORE (account_store);
638         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
639         
640         /* This hash map stores passwords, including passwords that are not stored in gconf. */
641         /* Is it in the hash? if it's already there, it must be wrong... */
642         pwd_ptr = (gpointer)&pwd; /* pwd_ptr so the compiler does not complained about
643                                    * type-punned ptrs...*/
644         already_asked = priv->password_hash && 
645                                 g_hash_table_lookup_extended (priv->password_hash,
646                                                       server_account_name,
647                                                       NULL,
648                                                       (gpointer*)&pwd_ptr);
649         MODEST_DEBUG_BLOCK(
650                 g_debug ("DEBUG: modest: %s: Already asked = %d\n", __FUNCTION__, already_asked);
651         );
652                 
653         /* If the password is not already there, try ModestConf */
654         if (!already_asked) {
655                 pwd  = modest_account_mgr_get_server_account_password (priv->account_mgr,
656                                                                        server_account_name);
657                 g_hash_table_insert (priv->password_hash, g_strdup (server_account_name), g_strdup (pwd));
658         }
659
660         /* If it was already asked, it must have been wrong, so ask again */
661         if (already_asked || !pwd || strlen(pwd) == 0) {
662                 /* As per the UI spec, if no password was set in the account settings, 
663                  * ask for it now. But if the password is wrong in the account settings, 
664                  * then show a banner and the account settings dialog so it can be corrected:
665                  */
666                 const gboolean settings_have_password = 
667                         modest_account_mgr_get_server_account_has_password (priv->account_mgr, server_account_name);
668                 MODEST_DEBUG_BLOCK(
669                         printf ("DEBUG: modest: %s: settings_have_password=%d\n",
670                                 __FUNCTION__, settings_have_password);
671                 );
672                 if (settings_have_password) {
673                         /* The password must be wrong, so show the account settings dialog so it can be corrected: */
674 #ifdef MODEST_PLATFORM_MAEMO
675                         show_wrong_password_dialog (account);
676 #endif
677                         
678                         if (cancel)
679                                 *cancel = TRUE;
680                                 
681                         return NULL;
682                 }
683         
684                 /* we don't have it yet. Get the password from the user */
685                 const gchar* account_id = tny_account_get_id (account);
686                 gboolean remember = FALSE;
687                 pwd = NULL;
688                 
689                 if (already_asked) {
690                         /* Show an info banner, before we show the protected password dialog: */
691                         show_password_warning_only();
692                 }
693
694                 /* Request password */
695                 g_signal_emit (G_OBJECT(account_store), signals[PASSWORD_REQUESTED_SIGNAL], 0,
696                                account_id, /* server_account_name */
697                                &username, &pwd, cancel, &remember);
698
699                 
700                 if (!*cancel) {
701                         /* The password will be returned as the result,
702                          * but we need to tell tinymail about the username too: */
703                         tny_account_set_user (account, username);
704                         
705                         /* Do not save the password in gconf, because
706                          * the UI spec says "The password will never
707                          * be saved in the account": */
708
709                         /* We need to dup the string even knowing that
710                            it's already a dup of the contents of an
711                            entry, because it if it's wrong, then camel
712                            will free it */
713                         g_hash_table_insert (priv->password_hash, g_strdup (server_account_name), g_strdup(pwd));
714                 } else {
715                         g_hash_table_remove (priv->password_hash, server_account_name);
716                         
717                         g_free (pwd);
718                         pwd = NULL;
719                 }
720
721                 g_free (username);
722                 username = NULL;
723         } else
724                 if (cancel)
725                         *cancel = FALSE;        
726         return pwd;
727 }
728
729 void 
730 modest_tny_account_store_forget_already_asked (ModestTnyAccountStore *self, TnyAccount *account)
731 {
732         g_return_if_fail (account);
733           
734         ModestTnyAccountStorePrivate *priv;
735         gchar *pwd = NULL;
736         gpointer pwd_ptr = NULL;
737         gboolean already_asked = FALSE;
738                 
739         const gchar *server_account_name = tny_account_get_id (account);
740
741         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
742         
743         /* This hash map stores passwords, including passwords that are not stored in gconf. */
744         pwd_ptr = (gpointer)&pwd; /* pwd_ptr so the compiler does not complained about
745                                    * type-punned ptrs...*/
746         already_asked = priv->password_hash && 
747                                 g_hash_table_lookup_extended (priv->password_hash,
748                                                       server_account_name,
749                                                       NULL,
750                                                       (gpointer*)&pwd_ptr);
751
752         if (already_asked) {
753                 g_hash_table_remove (priv->password_hash, server_account_name);         
754                 g_free (pwd);
755                 pwd = NULL;
756         }
757
758         return;
759 }
760
761 /* tinymail calls this if the connection failed due to an incorrect password.
762  * And it seems to call this for any general connection failure. */
763 static void
764 forget_password (TnyAccount *account)
765 {
766         printf ("DEBUG: %s\n", __FUNCTION__);
767         ModestTnyAccountStore *self;
768         ModestTnyAccountStorePrivate *priv;
769         const TnyAccountStore *account_store;
770         gchar *pwd;
771         const gchar *key;
772         
773         account_store = TNY_ACCOUNT_STORE(g_object_get_data (G_OBJECT(account),
774                                                              "account_store"));
775         self = MODEST_TNY_ACCOUNT_STORE (account_store);
776         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
777         key  = tny_account_get_id (account);
778
779         /* Do not remove the key, this will allow us to detect that we
780            have already asked for it at least once */
781         pwd = g_hash_table_lookup (priv->password_hash, key);
782         if (pwd) {
783                 memset (pwd, 0, strlen (pwd));
784                 g_hash_table_insert (priv->password_hash, g_strdup (key), NULL);
785         }
786
787         /* Remove from configuration system */
788         /*
789         modest_account_mgr_unset (priv->account_mgr,
790                                   key, MODEST_ACCOUNT_PASSWORD, TRUE);
791         */
792 }
793
794 static void
795 modest_tny_account_store_finalize (GObject *obj)
796 {
797         ModestTnyAccountStore *self        = MODEST_TNY_ACCOUNT_STORE(obj);
798         ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
799
800         g_free (priv->cache_dir);
801         priv->cache_dir = NULL;
802         
803         if (priv->password_hash) {
804                 g_hash_table_destroy (priv->password_hash);
805                 priv->password_hash = NULL;
806         }
807
808 #ifdef MODEST_PLATFORM_MAEMO
809         if (priv->account_settings_dialog_hash) {
810                 g_hash_table_destroy (priv->account_settings_dialog_hash);
811                 priv->account_settings_dialog_hash = NULL;
812         }
813 #endif
814
815         if (priv->outbox_of_transport) {
816                 g_hash_table_destroy (priv->outbox_of_transport);
817                 priv->outbox_of_transport = NULL;
818         }
819
820         modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
821         priv->sighandlers = NULL;       
822
823         if (priv->account_mgr) {
824                 g_object_unref (G_OBJECT(priv->account_mgr));
825                 priv->account_mgr = NULL;
826         }
827
828         if (priv->device) {
829                 g_object_unref (G_OBJECT(priv->device));
830                 priv->device = NULL;
831         }
832
833         /* Destroy all accounts. Disconnect all accounts before they are destroyed */
834         if (priv->store_accounts) {
835                 tny_list_foreach (priv->store_accounts, (GFunc)account_disconnect, NULL);
836                 tny_list_foreach (priv->store_accounts, (GFunc)account_verify_last_ref, "store");
837                 g_object_unref (priv->store_accounts);
838                 priv->store_accounts = NULL;
839         }
840         
841         if (priv->transport_accounts) {
842                 tny_list_foreach (priv->transport_accounts, (GFunc)account_disconnect, NULL);
843                 tny_list_foreach (priv->transport_accounts, (GFunc)account_verify_last_ref, "transport");
844                 g_object_unref (priv->transport_accounts);
845                 priv->transport_accounts = NULL;
846         }
847
848         if (priv->store_accounts_outboxes) {
849                 g_object_unref (priv->store_accounts_outboxes);
850                 priv->store_accounts_outboxes = NULL;
851         }
852                 
853         if (priv->session) {
854                 camel_object_unref (CAMEL_OBJECT(priv->session));
855                 priv->session = NULL;
856         }
857         
858         G_OBJECT_CLASS(parent_class)->finalize (obj);
859 }
860
861 gboolean 
862 volume_path_is_mounted (const gchar* path)
863 {
864         g_return_val_if_fail (path, FALSE);
865
866         gboolean result = FALSE;
867         gchar * path_as_uri = g_filename_to_uri (path, NULL, NULL);
868         g_return_val_if_fail (path_as_uri, FALSE);
869
870         /* Get the monitor singleton: */
871         GnomeVFSVolumeMonitor *monitor = gnome_vfs_get_volume_monitor();
872
873         /* This seems like a simpler way to do this, but it returns a   
874          * GnomeVFSVolume even if the drive is not mounted: */
875         /*
876         GnomeVFSVolume *volume = gnome_vfs_volume_monitor_get_volume_for_path (monitor, 
877                 MODEST_MCC1_VOLUMEPATH);
878         if (volume) {
879                 gnome_vfs_volume_unref(volume);
880         }
881         */
882
883         /* Get the mounted volumes from the monitor: */
884         GList *list = gnome_vfs_volume_monitor_get_mounted_volumes (monitor);
885         GList *iter = list;
886         for (iter = list; iter; iter = g_list_next (iter)) {
887                 GnomeVFSVolume *volume = (GnomeVFSVolume*)iter->data;
888                 if (volume) {
889                         /*
890                         char *display_name = 
891                                 gnome_vfs_volume_get_display_name (volume);
892                         printf ("volume display name=%s\n", display_name);
893                         g_free (display_name);
894                         */
895                         
896                         char *uri = 
897                                 gnome_vfs_volume_get_activation_uri (volume);
898                         /* printf ("  uri=%s\n", uri); */
899                         if (uri && (strcmp (uri, path_as_uri) == 0))
900                                 result = TRUE;
901
902                         g_free (uri);
903
904                         gnome_vfs_volume_unref (volume);
905                 }
906         }
907
908         g_list_free (list);
909
910         g_free (path_as_uri);
911
912         return result;
913 }
914
915 ModestTnyAccountStore*
916 modest_tny_account_store_new (ModestAccountMgr *account_mgr, 
917                               TnyDevice *device) 
918 {
919         GObject *obj;
920         ModestTnyAccountStorePrivate *priv;
921         TnyAccount *local_account = NULL;
922         
923         g_return_val_if_fail (account_mgr, NULL);
924         g_return_val_if_fail (device, NULL);
925
926         obj  = G_OBJECT(g_object_new(MODEST_TYPE_TNY_ACCOUNT_STORE, NULL));
927         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
928
929         priv->account_mgr = g_object_ref (G_OBJECT(account_mgr));
930         priv->device = g_object_ref (device);
931         
932         priv->session = tny_session_camel_new (TNY_ACCOUNT_STORE(obj));
933         if (!priv->session) {
934                 g_warning ("failed to get TnySessionCamel");
935                 return NULL;
936         }
937
938         /* Set the ui locker */ 
939         tny_session_camel_set_ui_locker (priv->session,  tny_gtk_lockable_new ());
940         
941         /* Connect signals */
942         priv->sighandlers  =  modest_signal_mgr_connect (priv->sighandlers,
943                                                          G_OBJECT(account_mgr), "account_inserted",
944                                                          G_CALLBACK (on_account_inserted), obj);
945         priv->sighandlers  =  modest_signal_mgr_connect (priv->sighandlers,
946                                                          G_OBJECT(account_mgr), "account_changed",
947                                                          G_CALLBACK (on_account_changed), obj);
948         priv->sighandlers  =  modest_signal_mgr_connect (priv->sighandlers,
949                                                          G_OBJECT(account_mgr), "account_removed",
950                                                          G_CALLBACK (on_account_removed), obj);
951
952         /* Create the lists of accounts */
953         priv->store_accounts = tny_simple_list_new ();
954         priv->transport_accounts = tny_simple_list_new ();
955         priv->store_accounts_outboxes = tny_simple_list_new ();
956
957         /* Create the local folders account */
958         local_account = 
959                 modest_tny_account_new_for_local_folders (priv->account_mgr, priv->session, NULL);
960         tny_list_append (priv->store_accounts, G_OBJECT(local_account));
961         g_object_unref (local_account); 
962
963         /* Add the other remote accounts. Do this after adding the
964            local account, because we need to add our outboxes to the
965            global OUTBOX hosted in the local account */
966         add_existing_accounts (MODEST_TNY_ACCOUNT_STORE (obj));
967         
968         /* FIXME: I'm doing this (adding an "if (FALSE)"because this
969            stuff is not working properly and could cause SIGSEVs, for
970            example one send queue will be created for each connection
971            specific SMTP server, so when tinymail asks for the outbox
972            it will return NULL because there is no outbox folder for
973            this specific transport accounts, and it's a must that the
974            send queue returns an outbox */
975         if (TRUE)
976                 /* Add connection-specific transport accounts */
977                 add_connection_specific_transport_accounts (MODEST_TNY_ACCOUNT_STORE(obj));
978         
979         /* This is a singleton, so it does not need to be unrefed. */
980         if (volume_path_is_mounted (MODEST_MCC1_VOLUMEPATH)) {
981                 /* It is mounted: */
982                 add_mmc_account (MODEST_TNY_ACCOUNT_STORE (obj), FALSE /* don't emit the insert signal. */); 
983         }
984         
985         return MODEST_TNY_ACCOUNT_STORE(obj);
986 }
987
988 static void
989 modest_tny_account_store_get_accounts  (TnyAccountStore *self, 
990                                         TnyList *list,
991                                         TnyGetAccountsRequestType request_type)
992 {
993         ModestTnyAccountStorePrivate *priv;
994         
995         g_return_if_fail (self);
996         g_return_if_fail (TNY_IS_LIST(list));
997         
998         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
999         
1000         switch (request_type) {
1001         case TNY_ACCOUNT_STORE_BOTH:
1002                 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
1003                 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
1004                 break;
1005         case TNY_ACCOUNT_STORE_STORE_ACCOUNTS:
1006                 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
1007                 break;
1008         case TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS:
1009                 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
1010                 break;
1011         default:
1012                 g_return_if_reached ();
1013         }
1014
1015         /* Initialize session. Why do we need this ??? */
1016         tny_session_camel_set_initialized (priv->session);
1017 }
1018
1019
1020 static const gchar*
1021 modest_tny_account_store_get_cache_dir (TnyAccountStore *self)
1022 {
1023         ModestTnyAccountStorePrivate *priv;
1024         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1025         
1026         if (!priv->cache_dir)
1027                 priv->cache_dir = g_build_filename (g_get_home_dir(), 
1028                                                     MODEST_DIR, MODEST_CACHE_DIR, NULL);
1029         return priv->cache_dir;
1030 }
1031
1032
1033 /*
1034  * callers need to unref
1035  */
1036 static TnyDevice*
1037 modest_tny_account_store_get_device (TnyAccountStore *self)
1038 {
1039         ModestTnyAccountStorePrivate *priv;
1040
1041         g_return_val_if_fail (self, NULL);
1042         
1043         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1044         
1045         if (priv->device) 
1046                 return g_object_ref (G_OBJECT(priv->device));
1047         else
1048                 return NULL;
1049 }
1050
1051
1052 static TnyAccount*
1053 modest_tny_account_store_find_account_by_url (TnyAccountStore *self, const gchar* url_string)
1054 {
1055         return modest_tny_account_store_get_tny_account_by (MODEST_TNY_ACCOUNT_STORE (self), 
1056                                                             MODEST_TNY_ACCOUNT_STORE_QUERY_URL,
1057                                                             url_string);
1058 }
1059
1060
1061
1062 static gboolean
1063 modest_tny_account_store_alert (TnyAccountStore *self, 
1064                                 TnyAccount *account, 
1065                                 TnyAlertType type,
1066                                 gboolean question, 
1067                                 const GError *error)
1068 {
1069         ModestTransportStoreProtocol proto =
1070                 MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN; 
1071         const gchar* server_name = NULL;
1072         gchar *prompt = NULL;
1073         gboolean retval;
1074
1075
1076         g_return_val_if_fail (account, FALSE);
1077         g_return_val_if_fail (error, FALSE);
1078         
1079         if ((error->domain != TNY_ACCOUNT_ERROR) && (error->domain != TNY_ACCOUNT_STORE_ERROR))
1080                 return FALSE;
1081         
1082         /* Get the server name: */
1083         server_name = tny_account_get_hostname (account);
1084
1085         if (account) {
1086                 const gchar *proto_name = tny_account_get_proto (account);
1087                 if (proto_name)
1088                         proto = modest_protocol_info_get_transport_store_protocol (proto_name);
1089                 else {
1090                         g_warning("modest: %s: account with id=%s has no proto.\n", __FUNCTION__, 
1091                                   tny_account_get_id (account));
1092                         return FALSE;
1093                 }
1094         }
1095
1096         switch (error->code) {
1097         case TNY_ACCOUNT_STORE_ERROR_CANCEL_ALERT:
1098         case TNY_ACCOUNT_ERROR_TRY_CONNECT_USER_CANCEL:
1099                 /* Don't show waste the user's time by showing him a dialog telling 
1100                  * him that he has just cancelled something: */
1101                 return TRUE;
1102
1103         case TNY_ACCOUNT_ERROR_TRY_CONNECT_HOST_LOOKUP_FAILED:
1104         case TNY_ACCOUNT_ERROR_TRY_CONNECT_SERVICE_UNAVAILABLE:
1105                 /* TODO: Show the appropriate message, depending on whether it's POP or IMAP: */                
1106                 switch (proto) {
1107                 case MODEST_PROTOCOL_STORE_POP:
1108                         prompt = g_strdup_printf (_("emev_ni_ui_pop3_msg_connect_error"),
1109                                                   server_name);
1110                         break;
1111                 case MODEST_PROTOCOL_STORE_IMAP:
1112                         prompt = g_strdup_printf (_("emev_ni_ui_imap_connect_server_error"),
1113                                                   server_name);
1114                         break;
1115                 case MODEST_PROTOCOL_TRANSPORT_SMTP:
1116                         prompt = g_strdup_printf (_("emev_ib_ui_smtp_server_invalid"),
1117                                                   server_name);
1118                         break;
1119                 default:
1120                         g_return_val_if_reached (FALSE);
1121                 }
1122                 break;
1123                 
1124         case TNY_ACCOUNT_ERROR_TRY_CONNECT_AUTHENTICATION_NOT_SUPPORTED:
1125                 /* This is "Secure connection failed", even though the logical
1126                  * ID has _certificate_ in the name: */
1127                 prompt = g_strdup (_("mail_ni_ssl_certificate_error")); 
1128                 break;
1129                         
1130         case TNY_ACCOUNT_ERROR_TRY_CONNECT_CERTIFICATE:
1131                 /* We'll show the proper dialog later */
1132                 break;
1133                 
1134         case TNY_ACCOUNT_ERROR_TRY_CONNECT:
1135                 /* The tinymail camel implementation just sends us this for almost 
1136                  * everything, so we have to guess at the cause.
1137                  * It could be a wrong password, or inability to resolve a hostname, 
1138                  * or lack of network, or incorrect authentication method, or something entirely different: */
1139                 /* TODO: Fix camel to provide specific error codes, and then use the 
1140                  * specific dialog messages from Chapter 12 of the UI spec.
1141                  */
1142         case TNY_ACCOUNT_STORE_ERROR_UNKNOWN_ALERT: 
1143                 return FALSE;                   
1144         default:
1145                 g_return_val_if_reached (FALSE);
1146         }
1147         
1148
1149         if (error->code == TNY_ACCOUNT_ERROR_TRY_CONNECT_CERTIFICATE)
1150                 retval = modest_platform_run_certificate_confirmation_dialog (server_name,
1151                                                                               error->message);
1152         else
1153                 retval = modest_platform_run_alert_dialog (prompt, question);
1154         
1155         if (prompt)
1156                 g_free (prompt);
1157         
1158         return retval;
1159 }
1160
1161
1162 static void
1163 modest_tny_account_store_init (gpointer g, gpointer iface_data)
1164 {
1165         TnyAccountStoreIface *klass;
1166
1167         g_return_if_fail (g);
1168
1169         klass = (TnyAccountStoreIface *)g;
1170
1171         klass->get_accounts_func =
1172                 modest_tny_account_store_get_accounts;
1173         klass->get_cache_dir_func =
1174                 modest_tny_account_store_get_cache_dir;
1175         klass->get_device_func =
1176                 modest_tny_account_store_get_device;
1177         klass->alert_func =
1178                 modest_tny_account_store_alert;
1179         klass->find_account_func =
1180                 modest_tny_account_store_find_account_by_url;
1181 }
1182
1183 void
1184 modest_tny_account_store_set_get_pass_func (ModestTnyAccountStore *self,
1185                                             ModestTnyGetPassFunc func)
1186 {
1187         /* not implemented, we use signals */
1188         g_printerr ("modest: set_get_pass_func not implemented\n");
1189 }
1190
1191 TnySessionCamel*
1192 modest_tny_account_store_get_session  (TnyAccountStore *self)
1193 {
1194         g_return_val_if_fail (self, NULL);
1195         return MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self)->session;
1196 }
1197
1198 static TnyAccount*
1199 get_tny_account_by (TnyList *accounts,
1200                     ModestTnyAccountStoreQueryType type,
1201                     const gchar *str)
1202 {
1203         TnyIterator *iter = NULL;
1204         gboolean found = FALSE;
1205         TnyAccount *retval = NULL;
1206
1207         g_return_val_if_fail (accounts && TNY_IS_LIST(accounts), NULL);
1208
1209         iter = tny_list_create_iterator (accounts);
1210         while (!tny_iterator_is_done (iter) && !found) {
1211                 TnyAccount *tmp_account = NULL;
1212                 const gchar *val = NULL;
1213
1214                 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1215                 switch (type) {
1216                 case MODEST_TNY_ACCOUNT_STORE_QUERY_ID:
1217                         val = tny_account_get_id (tmp_account);
1218                         break;
1219                 case MODEST_TNY_ACCOUNT_STORE_QUERY_URL:
1220                         val = tny_account_get_url_string (tmp_account);
1221                         break;
1222                 }
1223                 
1224                 if (type == MODEST_TNY_ACCOUNT_STORE_QUERY_URL && 
1225                     tny_account_matches_url_string (tmp_account, str)) {
1226                         retval = g_object_ref (tmp_account);
1227                         found = TRUE;
1228                 } else {
1229                         if (strcmp (val, str) == 0) {
1230                                 retval = g_object_ref (tmp_account);
1231                                 found = TRUE;
1232                         }
1233                 }
1234                 g_object_unref (tmp_account);
1235                 tny_iterator_next (iter);
1236         }
1237         g_object_unref (iter);
1238
1239         return retval;
1240 }
1241
1242 TnyAccount*
1243 modest_tny_account_store_get_tny_account_by (ModestTnyAccountStore *self, 
1244                                              ModestTnyAccountStoreQueryType type,
1245                                              const gchar *str)
1246 {
1247         TnyAccount *account = NULL;
1248         ModestTnyAccountStorePrivate *priv;     
1249         
1250         g_return_val_if_fail (self, NULL);
1251         g_return_val_if_fail (str, NULL);
1252         
1253         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1254         
1255         /* Search in store accounts */
1256         account = get_tny_account_by (priv->store_accounts, type, str);
1257
1258         /* If we already found something, no need to search the transport accounts */
1259         if (!account) {
1260                 account = get_tny_account_by (priv->transport_accounts, type, str);
1261
1262                 /* If we already found something, no need to search the
1263                    per-account outbox accounts */
1264                 if (!account)
1265                         account = get_tny_account_by (priv->store_accounts_outboxes, type, str);
1266         }
1267
1268         /* Warn if nothing was found. This is generally unusual. */
1269         if (!account) {
1270                 g_warning("%s: Failed to find account with %s=%s\n", 
1271                           __FUNCTION__, 
1272                           (type == MODEST_TNY_ACCOUNT_STORE_QUERY_ID) ? "ID" : "URL",                     
1273                           str);
1274         }
1275
1276         /* Returns a new reference to the account if found */   
1277         return account;
1278 }
1279
1280
1281 TnyAccount*
1282 modest_tny_account_store_get_server_account (ModestTnyAccountStore *self,
1283                                              const gchar *account_name,
1284                                              TnyAccountType type)
1285 {
1286         ModestTnyAccountStorePrivate *priv = NULL;
1287         TnyAccount *retval = NULL;
1288         TnyList *account_list = NULL;
1289         TnyIterator *iter = NULL;
1290         gboolean found;
1291
1292         g_return_val_if_fail (self, NULL);
1293         g_return_val_if_fail (account_name, NULL);
1294         g_return_val_if_fail (type == TNY_ACCOUNT_TYPE_STORE || 
1295                               type == TNY_ACCOUNT_TYPE_TRANSPORT,
1296                               NULL);
1297         
1298         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1299
1300         account_list = (type == TNY_ACCOUNT_TYPE_STORE) ? 
1301                 priv->store_accounts : 
1302                 priv->transport_accounts;
1303
1304         if (!account_list) {
1305                 g_printerr ("%s: No server accounts of type %s\n", __FUNCTION__, 
1306                         (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport");
1307                 return NULL;
1308         }
1309         
1310         /* Look for the server account */
1311         found = FALSE;
1312         iter = tny_list_create_iterator (account_list);
1313         while (!tny_iterator_is_done (iter) && !found) {
1314                 const gchar *modest_acc_name;
1315                 TnyAccount *tmp_account;
1316
1317                 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1318                 modest_acc_name = 
1319                         modest_tny_account_get_parent_modest_account_name_for_server_account (tmp_account);
1320                 
1321                 if (account_name && modest_acc_name && !strcmp (account_name, modest_acc_name)) {
1322                         found = TRUE;
1323                         retval = g_object_ref (tmp_account);
1324                 }
1325                 /* Free and continue */
1326                 g_object_unref (tmp_account);
1327                 tny_iterator_next (iter);
1328         }
1329
1330         if (!found) {
1331                 g_printerr ("modest: %s: could not get tny %s account for %s\n." \
1332                             "Number of server accounts of this type=%d\n", __FUNCTION__,
1333                             (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport",
1334                             account_name, tny_list_get_length (account_list));
1335         }
1336
1337         /* Returns a new reference */
1338         return retval;
1339 }
1340
1341 TnyAccount*
1342 modest_tny_account_store_get_smtp_specific_transport_account_for_open_connection (ModestTnyAccountStore *self,
1343                                                                                   const gchar *account_name)
1344 {
1345         TnyDevice *device;
1346
1347         g_return_val_if_fail (self && MODEST_IS_TNY_ACCOUNT_STORE(self), NULL);
1348         g_return_val_if_fail (account_name, NULL);
1349
1350         /* Get the current connection: */
1351         device = modest_runtime_get_device ();
1352         
1353         if (!tny_device_is_online (device))
1354                 return NULL;
1355         
1356 #ifdef MODEST_HAVE_CONIC
1357         g_return_val_if_fail (TNY_IS_MAEMO_CONIC_DEVICE (device), NULL);
1358         
1359         TnyMaemoConicDevice *maemo_device = TNY_MAEMO_CONIC_DEVICE (device);    
1360         const gchar* iap_id = tny_maemo_conic_device_get_current_iap_id (maemo_device);
1361         /* printf ("DEBUG: %s: iap_id=%s\n", __FUNCTION__, iap_id); */
1362         if (!iap_id)
1363                 return NULL;
1364                 
1365         ConIcIap* connection = tny_maemo_conic_device_get_iap (maemo_device, iap_id);
1366         if (!connection)
1367                 return NULL;
1368                 
1369         const gchar *connection_name = con_ic_iap_get_name (connection);
1370         /* printf ("DEBUG: %s: connection_name=%s\n", __FUNCTION__, connection_name); */
1371         if (!connection_name)
1372                 return NULL;
1373         
1374         /*  Get the connection-specific transport acccount, if any: */
1375         ModestAccountMgr *account_manager = modest_runtime_get_account_mgr ();
1376
1377         /* Check if this account has connection-specific SMTP enabled */
1378         if (!modest_account_mgr_get_use_connection_specific_smtp (account_manager, account_name)) {
1379                 return NULL;
1380         }
1381
1382         gchar* server_account_name = modest_account_mgr_get_connection_specific_smtp (account_manager, 
1383                 connection_name);
1384
1385         /* printf ("DEBUG: %s: server_account_name=%s\n", __FUNCTION__, server_account_name); */
1386         if (!server_account_name) {
1387                 return NULL; /* No connection-specific SMTP server was specified for this connection. */
1388         }
1389                 
1390         TnyAccount* account = modest_tny_account_store_get_tny_account_by (self, 
1391                                                                            MODEST_TNY_ACCOUNT_STORE_QUERY_ID, 
1392                                                                            server_account_name);
1393
1394         /* printf ("DEBUG: %s: account=%p\n", __FUNCTION__, account); */
1395         g_free (server_account_name);   
1396
1397         /* Unref the get()ed object, as required by the tny_maemo_conic_device_get_iap() documentation. */
1398         g_object_unref (connection);
1399         
1400         return account;
1401 #else
1402         return NULL; /* TODO: Implement this for GNOME, instead of just Maemo? */
1403 #endif /* MODEST_HAVE_CONIC */
1404 }
1405
1406                                                                  
1407 TnyAccount*
1408 modest_tny_account_store_get_transport_account_for_open_connection (ModestTnyAccountStore *self,
1409                                                                     const gchar *account_name)
1410 {
1411         g_return_val_if_fail (self, NULL);
1412         g_return_val_if_fail (account_name, NULL);
1413
1414         if (!account_name || !self)
1415                 return NULL;
1416         
1417         /*  Get the connection-specific transport acccount, if any: */
1418         /* Note: This gives us a reference: */
1419         TnyAccount *account =
1420                 modest_tny_account_store_get_smtp_specific_transport_account_for_open_connection (self, account_name);
1421                         
1422         /* If there is no connection-specific transport account (the common case), 
1423          * just get the regular transport account: */
1424         if (!account) {
1425                 /* The special local folders don't have transport accounts. */
1426                 if (strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0)
1427                         account = NULL;
1428                 else {
1429                         /* Note: This gives us a reference: */
1430                         account = modest_tny_account_store_get_server_account (self, account_name, 
1431                                                      TNY_ACCOUNT_TYPE_TRANSPORT);
1432                 }
1433         }
1434                         
1435         /* returns a reference. */     
1436         return account;
1437 }
1438
1439 TnyAccount*
1440 modest_tny_account_store_get_local_folders_account (ModestTnyAccountStore *self)
1441 {
1442         TnyAccount *account = NULL;
1443         ModestTnyAccountStorePrivate *priv;
1444         TnyIterator *iter;
1445         gboolean found;
1446
1447         g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1448         
1449         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1450
1451         found = FALSE;
1452         iter = tny_list_create_iterator (priv->store_accounts);
1453         while (!tny_iterator_is_done (iter) && !found) {
1454                 TnyAccount *tmp_account;
1455
1456                 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1457                 if (modest_tny_account_is_virtual_local_folders (tmp_account)) {
1458                         account = g_object_ref (tmp_account);
1459                         found = TRUE;
1460                 }
1461                 g_object_unref (tmp_account);
1462                 tny_iterator_next (iter);
1463         }
1464         g_object_unref (iter);
1465
1466         /* Returns a new reference to the account */
1467         return account;
1468 }
1469
1470 TnyAccount*
1471 modest_tny_account_store_get_mmc_folders_account (ModestTnyAccountStore *self)
1472 {
1473         g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1474         
1475         return modest_tny_account_store_get_tny_account_by (self, MODEST_TNY_ACCOUNT_STORE_QUERY_ID,
1476                                                             MODEST_MMC_ACCOUNT_ID);
1477
1478 }
1479
1480 /*********************************************************************************/
1481 static void
1482 add_existing_accounts (ModestTnyAccountStore *self)
1483 {
1484         GSList *account_names = NULL, *iter = NULL;
1485         ModestTnyAccountStorePrivate *priv = NULL;
1486         
1487         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1488
1489         /* These are account names, not server_account names */
1490         account_names = modest_account_mgr_account_names (priv->account_mgr, FALSE);
1491
1492         for (iter = account_names; iter != NULL; iter = g_slist_next (iter)) {
1493                 const gchar *account_name = (const gchar*) iter->data;
1494                 
1495                 /* Insert all enabled accounts without notifying */
1496                 if (modest_account_mgr_get_enabled (priv->account_mgr, account_name))
1497                         insert_account (self, account_name, FALSE);
1498         }
1499         modest_account_mgr_free_account_names (account_names);
1500 }
1501
1502 static TnyAccount*
1503 create_tny_account (ModestTnyAccountStore *self,
1504                     const gchar *name,
1505                     TnyAccountType type)
1506 {
1507         TnyAccount *account = NULL;
1508         ModestTnyAccountStorePrivate *priv = NULL;
1509         
1510         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1511
1512         account = modest_tny_account_new_from_account (priv->account_mgr,
1513                                                        name, type, 
1514                                                        priv->session,
1515                                                        get_password,
1516                                                        forget_password);
1517
1518         if (account) {
1519                 /* Forget any cached password for the account, so that
1520                    we use a new account if any */
1521                 modest_tny_account_store_forget_password_in_memory (self, 
1522                                                                     tny_account_get_id (account));
1523                 /* Set the account store */                             
1524                 g_object_set_data (G_OBJECT(account), "account_store", self);
1525         } else {
1526                 g_printerr ("modest: failed to create account for %s\n", name);
1527         }
1528
1529         return account;
1530 }
1531
1532
1533 static void
1534 add_outbox_from_transport_account_to_global_outbox (ModestTnyAccountStore *self,
1535                                                     const gchar *account_name,
1536                                                     TnyAccount *transport_account)
1537 {
1538         TnyList *folders = NULL;
1539         TnyIterator *iter_folders = NULL;
1540         TnyAccount *local_account = NULL, *account_outbox = NULL;
1541         TnyFolder *per_account_outbox = NULL;
1542         ModestTnyAccountStorePrivate *priv = NULL;
1543
1544         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1545
1546         /* Create per account local outbox */
1547         account_outbox = 
1548                 modest_tny_account_new_for_per_account_local_outbox_folder (priv->account_mgr, 
1549                                                                             account_name, 
1550                                                                             priv->session);
1551         tny_list_append (priv->store_accounts_outboxes, G_OBJECT (account_outbox));
1552
1553         /* Get the outbox folder */
1554         folders = tny_simple_list_new ();
1555         tny_folder_store_get_folders (TNY_FOLDER_STORE (account_outbox), folders, NULL, NULL);
1556         if (tny_list_get_length (folders) != 1) {
1557                 g_warning ("%s: > 1 outbox found (%d)?!", __FUNCTION__,
1558                            tny_list_get_length (folders));
1559         }
1560                         
1561         iter_folders = tny_list_create_iterator (folders);
1562         per_account_outbox = TNY_FOLDER (tny_iterator_get_current (iter_folders));
1563         g_object_unref (iter_folders);
1564         g_object_unref (folders);
1565         g_object_unref (account_outbox);
1566
1567         /* Add the outbox of the new per-account-local-outbox account
1568            to the global local merged OUTBOX of the local folders
1569            account */
1570         local_account = modest_tny_account_store_get_local_folders_account (self);
1571         modest_tny_local_folders_account_add_folder_to_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1572                                                                per_account_outbox);
1573         /* Add the pair to the hash table */
1574         g_hash_table_insert (priv->outbox_of_transport,
1575                              transport_account,
1576                              per_account_outbox);
1577         
1578         g_object_unref (local_account);
1579         g_object_unref (per_account_outbox);
1580 }
1581
1582 /*
1583  * This function will be used for both adding new accounts and for the
1584  * initialization. In the initialization we do not want to emit
1585  * signals so notify will be FALSE, in the case of account additions
1586  * we do want to notify the observers
1587  */
1588 static void
1589 insert_account (ModestTnyAccountStore *self,
1590                 const gchar *account,
1591                 gboolean notify)
1592 {
1593         ModestTnyAccountStorePrivate *priv = NULL;
1594         TnyAccount *store_account = NULL, *transport_account = NULL;
1595         
1596         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1597
1598         /* Get the server and the transport account */
1599         store_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_STORE);
1600         if (!store_account || !TNY_IS_ACCOUNT(store_account)) {
1601                 g_warning ("%s: failed to create store account", __FUNCTION__);
1602                 return;
1603         }
1604
1605         transport_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT);
1606         if (!transport_account || !TNY_IS_ACCOUNT(transport_account)) {
1607                 g_warning ("%s: failed to create transport account", __FUNCTION__);
1608                 g_object_unref (store_account);
1609                 return;
1610         }
1611
1612         /* Add accounts to the lists */
1613         tny_list_append (priv->store_accounts, G_OBJECT (store_account));
1614         tny_list_append (priv->transport_accounts, G_OBJECT (transport_account));
1615         
1616         /* Create a new pseudo-account with an outbox for this
1617            transport account and add it to the global outbox
1618            in the local account */
1619         add_outbox_from_transport_account_to_global_outbox (self, account, transport_account);
1620         
1621         /* Notify the observers. We do it after everything is
1622            created */
1623         if (notify) {
1624                 TnyAccount *local_account = NULL;
1625                 
1626                 /* Notify the observers about the new server & transport accounts */
1627                 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, store_account);   
1628                 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, transport_account);
1629
1630                 /* Notify that the local account changed */
1631                 local_account = modest_tny_account_store_get_local_folders_account (self);
1632                 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1633                 g_object_unref (local_account);
1634         }
1635
1636         /* Frees */
1637         g_object_unref (store_account);
1638         g_object_unref (transport_account);
1639 }
1640
1641 static void
1642 on_account_inserted (ModestAccountMgr *acc_mgr, 
1643                      const gchar *account,
1644                      gpointer user_data)
1645 {
1646         /* Insert the account and notify the observers */
1647         insert_account (MODEST_TNY_ACCOUNT_STORE (user_data), account, TRUE);
1648 }
1649
1650 /* This is the callback of the tny_camel_account_set_online called in
1651    on_account_removed to disconnect the account */
1652 static void
1653 on_account_disconnect_when_removing (TnyCamelAccount *account, 
1654                                      gboolean canceled, 
1655                                      GError *err, 
1656                                      gpointer user_data)
1657 {
1658         ModestTnyAccountStore *self;
1659         ModestTnyAccountStorePrivate *priv;
1660
1661         self = MODEST_TNY_ACCOUNT_STORE (user_data);
1662         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1663
1664         /* Remove it from the list of accounts */
1665         if (TNY_IS_STORE_ACCOUNT (account))
1666                 tny_list_remove (priv->store_accounts, (GObject *) account);
1667         else
1668                 tny_list_remove (priv->transport_accounts, (GObject *) account);
1669
1670         /* Notify the observers */
1671         g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 
1672                        0, account);
1673         
1674         /* Unref the extra reference added by get_server_account */
1675         g_object_unref (account);
1676
1677         /* Clear the cache if it's an store account */
1678         if (TNY_IS_STORE_ACCOUNT (account))
1679                 tny_store_account_delete_cache (TNY_STORE_ACCOUNT (account));
1680 }
1681
1682 static void
1683 on_account_removed (ModestAccountMgr *acc_mgr, const gchar *account,
1684                     gpointer user_data)
1685 {
1686         TnyAccount *store_account = NULL, *transport_account = NULL;
1687         ModestTnyAccountStore *self;
1688         ModestTnyAccountStorePrivate *priv;
1689         
1690         self = MODEST_TNY_ACCOUNT_STORE (user_data);
1691         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1692
1693         /* Get the server and the transport account */
1694         store_account = 
1695                 modest_tny_account_store_get_server_account (self, account, TNY_ACCOUNT_TYPE_STORE);
1696         transport_account = 
1697                 modest_tny_account_store_get_server_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT);
1698         
1699         /* If there was any problem creating the account, for example,
1700            with the configuration system this could not exist */
1701         if (store_account) {
1702                 /* Disconnect before deleting the cache, because the
1703                    disconnection will rewrite the cache to the
1704                    disk */
1705                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (store_account), FALSE,
1706                                               on_account_disconnect_when_removing, self);
1707         } else {
1708                 g_warning ("There is no store account for account %s\n", account);
1709         }
1710
1711         /* If there was any problem creating the account, for example,
1712            with the configuration system this could not exist */
1713         if (transport_account) {
1714                 TnyAccount *local_account = NULL;
1715                 TnyFolder *outbox = NULL;
1716                 ModestTnyAccountStorePrivate *priv = NULL;
1717         
1718                 /* Remove the OUTBOX of the account from the global outbox */
1719                 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1720                 outbox = g_hash_table_lookup (priv->outbox_of_transport, transport_account);
1721
1722                 if (TNY_IS_FOLDER (outbox)) {
1723                         local_account = modest_tny_account_store_get_local_folders_account (self);
1724                         modest_tny_local_folders_account_remove_folder_from_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1725                                                                                     outbox);
1726                         g_hash_table_remove (priv->outbox_of_transport, transport_account);
1727
1728                         /* Notify the change in the local account */
1729                         g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1730                         g_object_unref (local_account);
1731                 } else {
1732                         g_warning ("Removing a transport account that has no outbox");
1733                 }
1734
1735                 /* Disconnect and notify the observers. The callback will free the reference */
1736                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (transport_account), FALSE,
1737                                               on_account_disconnect_when_removing, self);
1738         } else {
1739                 g_warning ("There is no transport account for account %s\n", account);
1740         }
1741 }
1742
1743 TnyTransportAccount *
1744 modest_tny_account_store_new_connection_specific_transport_account (ModestTnyAccountStore *self,
1745                                                                     const gchar *name)
1746 {
1747         ModestTnyAccountStorePrivate *priv = NULL;
1748         TnyAccount * tny_account = NULL;
1749
1750         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1751
1752         /* Add the account: */
1753         tny_account = 
1754                 modest_tny_account_new_from_server_account_name (priv->account_mgr, 
1755                                                                  priv->session, 
1756                                                                  name,
1757                                                                  get_password,
1758                                                                  forget_password);
1759         if (tny_account) {
1760                 g_object_set_data (G_OBJECT(tny_account), 
1761                                    "account_store", 
1762                                    (gpointer)self);
1763                 
1764                 tny_list_append (priv->transport_accounts, G_OBJECT (tny_account));
1765                 add_outbox_from_transport_account_to_global_outbox (self, 
1766                                                                     name, 
1767                                                                     tny_account);
1768                 
1769         } else
1770                 g_printerr ("modest: failed to create smtp-specific account for %s\n",
1771                             name);
1772
1773         return TNY_TRANSPORT_ACCOUNT (tny_account);
1774 }
1775
1776
1777 static void
1778 add_connection_specific_transport_accounts (ModestTnyAccountStore *self)
1779 {
1780         ModestTnyAccountStorePrivate *priv = NULL;
1781         GSList *list_specifics = NULL, *iter = NULL;
1782
1783         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1784
1785         ModestConf *conf = modest_runtime_get_conf ();
1786
1787         GError *err = NULL;
1788         list_specifics = modest_conf_get_list (conf,
1789                                                MODEST_CONF_CONNECTION_SPECIFIC_SMTP_LIST,
1790                                                MODEST_CONF_VALUE_STRING, &err);
1791         if (err) {
1792                 g_printerr ("modest: %s: error getting list: %s\n.", __FUNCTION__, err->message);
1793                 g_error_free (err);
1794                 err = NULL;
1795         }
1796                                 
1797         /* Look at each connection-specific transport account for the 
1798          * modest account: */
1799         iter = list_specifics;
1800         while (iter) {
1801                 /* The list alternates between the connection name and the transport name: */
1802                 iter = g_slist_next (iter);
1803                 if (iter) {
1804                         const gchar* transport_account_name = (const gchar*) (iter->data);
1805                         TnyTransportAccount * account = NULL;
1806                         account = modest_tny_account_store_new_connection_specific_transport_account (
1807                                 self, transport_account_name);
1808                         if (account)
1809                                 g_object_unref (account);
1810                 }                               
1811                 iter = g_slist_next (iter);
1812         }
1813 }
1814
1815 TnyMsg *
1816 modest_tny_account_store_find_msg_in_outboxes (ModestTnyAccountStore *self, 
1817                                                const gchar *uri,
1818                                                TnyAccount **ac_out)
1819 {
1820         TnyIterator *acc_iter;
1821         ModestTnyAccountStorePrivate *priv;
1822         TnyMsg *msg = NULL;
1823         TnyAccount *msg_account = NULL;
1824
1825         g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1826         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1827
1828         acc_iter = tny_list_create_iterator (priv->store_accounts_outboxes);
1829         while (!msg && !tny_iterator_is_done (acc_iter)) {
1830                 TnyList *folders = tny_simple_list_new ();
1831                 TnyAccount *account = TNY_ACCOUNT (tny_iterator_get_current (acc_iter));
1832                 TnyIterator *folders_iter = NULL;
1833
1834                 tny_folder_store_get_folders (TNY_FOLDER_STORE (account), folders, NULL, NULL);
1835                 folders_iter = tny_list_create_iterator (folders);
1836
1837                 while (msg == NULL && !tny_iterator_is_done (folders_iter)) {
1838                         TnyFolder *folder = TNY_FOLDER (tny_iterator_get_current (folders_iter));
1839                         msg = tny_folder_find_msg (folder, uri, NULL);
1840
1841                         if (msg)
1842                                 msg_account = g_object_ref (account);
1843
1844                         g_object_unref (folder);
1845                         tny_iterator_next (folders_iter);
1846                 }
1847
1848                 g_object_unref (folders);
1849                 g_object_unref (account);
1850                 tny_iterator_next (acc_iter);
1851         }
1852
1853         g_object_unref (acc_iter);
1854
1855         if (ac_out != NULL)
1856                 *ac_out = msg_account;
1857
1858         return msg;
1859 }
1860
1861 TnyTransportAccount *
1862 modest_tny_account_store_get_transport_account_from_outbox_header(ModestTnyAccountStore *self, TnyHeader *header)
1863 {
1864         TnyIterator *acc_iter;
1865         ModestTnyAccountStorePrivate *priv;
1866         TnyTransportAccount *header_acc = NULL;
1867         const gchar *msg_id;
1868
1869         g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1870         g_return_val_if_fail (TNY_IS_HEADER (header), NULL);
1871         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1872
1873         msg_id = modest_tny_send_queue_get_msg_id (header);
1874         acc_iter = tny_list_create_iterator (priv->transport_accounts);
1875         while (!header_acc && !tny_iterator_is_done (acc_iter)) {
1876                 TnyTransportAccount *account = TNY_TRANSPORT_ACCOUNT (tny_iterator_get_current (acc_iter));
1877                 ModestTnySendQueue *send_queue;
1878                 ModestTnySendQueueStatus status;
1879                 send_queue = modest_runtime_get_send_queue(TNY_TRANSPORT_ACCOUNT(account));
1880                 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
1881                 if (status != MODEST_TNY_SEND_QUEUE_UNKNOWN) {
1882                         header_acc = g_object_ref(account);
1883                 }
1884                 g_object_unref (account);
1885                 tny_iterator_next (acc_iter);
1886         }
1887
1888         g_object_unref(acc_iter);
1889         return header_acc;
1890 }