* Removed some comments
[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                         TnyConnectionStatus conn_status = tny_account_get_connection_status (tny_account);
477
478                         if (conn_status != TNY_CONNECTION_STATUS_RECONNECTING &&
479                             conn_status != TNY_CONNECTION_STATUS_INIT) {
480                                 if (!strcmp (tny_account_get_id (tny_account), account_name)) {
481                                         found = TRUE;
482                                         modest_tny_account_update_from_account (tny_account);
483                                         g_signal_emit (G_OBJECT(self), signals[ACCOUNT_CHANGED_SIGNAL], 0, tny_account);
484                                 }
485                         }
486                         g_object_unref (tny_account);
487                 }
488                 tny_iterator_next (iter);
489         }
490
491         if (iter)
492                 g_object_unref (iter);
493 }
494
495 #ifdef MODEST_PLATFORM_MAEMO
496 static void 
497 on_account_settings_hide (GtkWidget *widget, gpointer user_data)
498 {
499         TnyAccount *account = (TnyAccount*)user_data;
500         
501         /* This is easier than using a struct for the user_data: */
502         ModestTnyAccountStore *self = modest_runtime_get_account_store();
503         ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
504         
505         const gchar *modest_account_name = 
506                         modest_tny_account_get_parent_modest_account_name_for_server_account (account);
507         if (modest_account_name)
508                 g_hash_table_remove (priv->account_settings_dialog_hash, modest_account_name);
509 }
510 #endif
511
512 static void 
513 show_password_warning_only ()
514 {
515         ModestWindow *main_window = 
516                 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (), FALSE); /* don't create */
517         
518         /* Show an explanatory temporary banner: */
519         if (main_window) 
520                 modest_platform_information_banner (GTK_WIDGET(main_window), NULL, 
521                                                     _("mcen_ib_username_pw_incorrect"));
522         else
523                 g_warning ("%s: %s", __FUNCTION__, _("mcen_ib_username_pw_incorrect"));
524 }
525
526 #ifdef MODEST_PLATFORM_MAEMO
527 static void 
528 show_wrong_password_dialog (TnyAccount *account)
529
530         /* This is easier than using a struct for the user_data: */
531         ModestTnyAccountStore *self = modest_runtime_get_account_store();
532         ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
533         ModestWindow *main_window;
534         const gchar *modest_account_name;
535
536         main_window = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (),
537                                                          FALSE); /* don't create */
538         if (!main_window) {
539                 g_warning ("%s: password was wrong; ignoring because no main window", __FUNCTION__);
540                 return;
541         }
542
543         modest_account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
544         if (!modest_account_name) {
545                 g_warning ("%s: modest_tny_account_get_parent_modest_account_name_for_server_account() failed.\n", 
546                         __FUNCTION__);
547         }
548         
549         /* Check whether this window is already open,
550          * for instance because of a previous get_password() call: 
551          */
552         gpointer dialog_as_gpointer = NULL;
553         gboolean found = FALSE;
554         if (priv->account_settings_dialog_hash) {
555                 found = g_hash_table_lookup_extended (priv->account_settings_dialog_hash,
556                         modest_account_name, NULL, (gpointer*)&dialog_as_gpointer);
557         }
558         ModestAccountSettingsDialog *dialog = dialog_as_gpointer;
559                                         
560         gboolean created_dialog = FALSE;
561         if (!found || !dialog) {
562                 dialog = modest_account_settings_dialog_new ();
563                 modest_account_settings_dialog_set_account_name (dialog, modest_account_name);
564                 modest_account_settings_dialog_switch_to_user_info (dialog);
565                 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), GTK_WINDOW (dialog));
566                 
567                 g_hash_table_insert (priv->account_settings_dialog_hash, g_strdup (modest_account_name), dialog);
568                 
569                 created_dialog = TRUE;
570         }
571         
572         /* Show an explanatory temporary banner: */
573         modest_platform_information_banner (GTK_WIDGET(dialog), NULL, _("mcen_ib_username_pw_incorrect"));
574                 
575         if (created_dialog) {
576                 /* Forget it when it closes: */
577                 g_signal_connect_object (G_OBJECT (dialog), "hide", G_CALLBACK (on_account_settings_hide), 
578                         account, 0);
579                         
580                 /* Show it and delete it when it closes: */
581                 gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (main_window));
582                 g_signal_connect_swapped (dialog, 
583                                           "response", 
584                                           G_CALLBACK (gtk_widget_destroy), 
585                                           dialog);
586                 gtk_widget_show (GTK_WIDGET (dialog));
587         }
588         else {
589                 /* Just show it instead of showing it and deleting it when it closes,
590                  * though it is probably open already: */
591                 gtk_window_present (GTK_WINDOW (dialog));
592         }
593 }
594 #endif
595
596 /* This callback will be called by Tinymail when it needs the password
597  * from the user or the account settings.
598  * It can also call forget_password() before calling this,
599  * so that we clear wrong passwords out of our account settings.
600  * Note that TnyAccount here will be the server account. */
601 static gchar*
602 get_password (TnyAccount *account, const gchar * prompt_not_used, gboolean *cancel)
603 {
604         /* TODO: Settting cancel to FALSE does not actually cancel everything.
605          * We still get multiple requests afterwards, so we end up showing the 
606          * same dialogs repeatedly.
607          */       
608         const TnyAccountStore *account_store = NULL;
609         ModestTnyAccountStore *self = NULL;
610         ModestTnyAccountStorePrivate *priv;
611         gchar *username = NULL;
612         gchar *pwd = NULL;
613         gpointer pwd_ptr = NULL;
614         gboolean already_asked = FALSE;
615
616         g_return_val_if_fail (account, NULL);
617         
618         MODEST_DEBUG_BLOCK(
619                 g_debug ("DEBUG: modest: %s: prompt (not shown) = %s\n", __FUNCTION__, prompt_not_used);
620         );
621         
622         /* Initialize the output parameter: */
623         if (cancel)
624                 *cancel = FALSE;
625                 
626         const gchar *server_account_name = tny_account_get_id (account);
627         account_store = TNY_ACCOUNT_STORE(g_object_get_data (G_OBJECT(account),
628                                                              "account_store"));
629
630         if (!server_account_name || !account_store) {
631                 g_warning ("modest: %s: could not retrieve account_store for account %s",
632                            __FUNCTION__, server_account_name ? server_account_name : "<NULL>");
633                 if (cancel)
634                         *cancel = TRUE;
635                 
636                 return NULL;
637         }
638
639         self = MODEST_TNY_ACCOUNT_STORE (account_store);
640         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
641         
642         /* This hash map stores passwords, including passwords that are not stored in gconf. */
643         /* Is it in the hash? if it's already there, it must be wrong... */
644         pwd_ptr = (gpointer)&pwd; /* pwd_ptr so the compiler does not complained about
645                                    * type-punned ptrs...*/
646         already_asked = priv->password_hash && 
647                                 g_hash_table_lookup_extended (priv->password_hash,
648                                                       server_account_name,
649                                                       NULL,
650                                                       (gpointer*)&pwd_ptr);
651         MODEST_DEBUG_BLOCK(
652                 g_debug ("DEBUG: modest: %s: Already asked = %d\n", __FUNCTION__, already_asked);
653         );
654                 
655         /* If the password is not already there, try ModestConf */
656         if (!already_asked) {
657                 pwd  = modest_account_mgr_get_server_account_password (priv->account_mgr,
658                                                                        server_account_name);
659                 g_hash_table_insert (priv->password_hash, g_strdup (server_account_name), g_strdup (pwd));
660         }
661
662         /* If it was already asked, it must have been wrong, so ask again */
663         if (already_asked || !pwd || strlen(pwd) == 0) {
664                 /* As per the UI spec, if no password was set in the account settings, 
665                  * ask for it now. But if the password is wrong in the account settings, 
666                  * then show a banner and the account settings dialog so it can be corrected:
667                  */
668                 const gboolean settings_have_password = 
669                         modest_account_mgr_get_server_account_has_password (priv->account_mgr, server_account_name);
670                 MODEST_DEBUG_BLOCK(
671                         printf ("DEBUG: modest: %s: settings_have_password=%d\n",
672                                 __FUNCTION__, settings_have_password);
673                 );
674                 if (settings_have_password) {
675                         /* The password must be wrong, so show the account settings dialog so it can be corrected: */
676 #ifdef MODEST_PLATFORM_MAEMO
677                         show_wrong_password_dialog (account);
678 #endif
679                         
680                         if (cancel)
681                                 *cancel = TRUE;
682                                 
683                         return NULL;
684                 }
685         
686                 /* we don't have it yet. Get the password from the user */
687                 const gchar* account_id = tny_account_get_id (account);
688                 gboolean remember = FALSE;
689                 pwd = NULL;
690                 
691                 if (already_asked) {
692                         /* Show an info banner, before we show the protected password dialog: */
693                         show_password_warning_only();
694                 }
695
696                 /* Request password */
697                 g_signal_emit (G_OBJECT(account_store), signals[PASSWORD_REQUESTED_SIGNAL], 0,
698                                account_id, /* server_account_name */
699                                &username, &pwd, cancel, &remember);
700
701                 
702                 if (!*cancel) {
703                         /* The password will be returned as the result,
704                          * but we need to tell tinymail about the username too: */
705                         tny_account_set_user (account, username);
706                         
707                         /* Do not save the password in gconf, because
708                          * the UI spec says "The password will never
709                          * be saved in the account": */
710
711                         /* We need to dup the string even knowing that
712                            it's already a dup of the contents of an
713                            entry, because it if it's wrong, then camel
714                            will free it */
715                         g_hash_table_insert (priv->password_hash, g_strdup (server_account_name), g_strdup(pwd));
716                 } else {
717                         g_hash_table_remove (priv->password_hash, server_account_name);
718                         
719                         g_free (pwd);
720                         pwd = NULL;
721                 }
722
723                 g_free (username);
724                 username = NULL;
725         } else
726                 if (cancel)
727                         *cancel = FALSE;        
728         return pwd;
729 }
730
731 void 
732 modest_tny_account_store_forget_already_asked (ModestTnyAccountStore *self, TnyAccount *account)
733 {
734         g_return_if_fail (account);
735           
736         ModestTnyAccountStorePrivate *priv;
737         gchar *pwd = NULL;
738         gpointer pwd_ptr = NULL;
739         gboolean already_asked = FALSE;
740                 
741         const gchar *server_account_name = tny_account_get_id (account);
742
743         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
744         
745         /* This hash map stores passwords, including passwords that are not stored in gconf. */
746         pwd_ptr = (gpointer)&pwd; /* pwd_ptr so the compiler does not complained about
747                                    * type-punned ptrs...*/
748         already_asked = priv->password_hash && 
749                                 g_hash_table_lookup_extended (priv->password_hash,
750                                                       server_account_name,
751                                                       NULL,
752                                                       (gpointer*)&pwd_ptr);
753
754         if (already_asked) {
755                 g_hash_table_remove (priv->password_hash, server_account_name);         
756                 g_free (pwd);
757                 pwd = NULL;
758         }
759
760         return;
761 }
762
763 /* tinymail calls this if the connection failed due to an incorrect password.
764  * And it seems to call this for any general connection failure. */
765 static void
766 forget_password (TnyAccount *account)
767 {
768         printf ("DEBUG: %s\n", __FUNCTION__);
769         ModestTnyAccountStore *self;
770         ModestTnyAccountStorePrivate *priv;
771         const TnyAccountStore *account_store;
772         gchar *pwd;
773         const gchar *key;
774         
775         account_store = TNY_ACCOUNT_STORE(g_object_get_data (G_OBJECT(account),
776                                                              "account_store"));
777         self = MODEST_TNY_ACCOUNT_STORE (account_store);
778         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
779         key  = tny_account_get_id (account);
780
781         /* Do not remove the key, this will allow us to detect that we
782            have already asked for it at least once */
783         pwd = g_hash_table_lookup (priv->password_hash, key);
784         if (pwd) {
785                 memset (pwd, 0, strlen (pwd));
786                 g_hash_table_insert (priv->password_hash, g_strdup (key), NULL);
787         }
788
789         /* Remove from configuration system */
790         /*
791         modest_account_mgr_unset (priv->account_mgr,
792                                   key, MODEST_ACCOUNT_PASSWORD, TRUE);
793         */
794 }
795
796 static void
797 modest_tny_account_store_finalize (GObject *obj)
798 {
799         ModestTnyAccountStore *self        = MODEST_TNY_ACCOUNT_STORE(obj);
800         ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
801
802         g_free (priv->cache_dir);
803         priv->cache_dir = NULL;
804         
805         if (priv->password_hash) {
806                 g_hash_table_destroy (priv->password_hash);
807                 priv->password_hash = NULL;
808         }
809
810 #ifdef MODEST_PLATFORM_MAEMO
811         if (priv->account_settings_dialog_hash) {
812                 g_hash_table_destroy (priv->account_settings_dialog_hash);
813                 priv->account_settings_dialog_hash = NULL;
814         }
815 #endif
816
817         if (priv->outbox_of_transport) {
818                 g_hash_table_destroy (priv->outbox_of_transport);
819                 priv->outbox_of_transport = NULL;
820         }
821
822         modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
823         priv->sighandlers = NULL;       
824
825         if (priv->account_mgr) {
826                 g_object_unref (G_OBJECT(priv->account_mgr));
827                 priv->account_mgr = NULL;
828         }
829
830         if (priv->device) {
831                 g_object_unref (G_OBJECT(priv->device));
832                 priv->device = NULL;
833         }
834
835         /* Destroy all accounts. Disconnect all accounts before they are destroyed */
836         if (priv->store_accounts) {
837                 tny_list_foreach (priv->store_accounts, (GFunc)account_disconnect, NULL);
838                 tny_list_foreach (priv->store_accounts, (GFunc)account_verify_last_ref, "store");
839                 g_object_unref (priv->store_accounts);
840                 priv->store_accounts = NULL;
841         }
842         
843         if (priv->transport_accounts) {
844                 tny_list_foreach (priv->transport_accounts, (GFunc)account_disconnect, NULL);
845                 tny_list_foreach (priv->transport_accounts, (GFunc)account_verify_last_ref, "transport");
846                 g_object_unref (priv->transport_accounts);
847                 priv->transport_accounts = NULL;
848         }
849
850         if (priv->store_accounts_outboxes) {
851                 g_object_unref (priv->store_accounts_outboxes);
852                 priv->store_accounts_outboxes = NULL;
853         }
854                 
855         if (priv->session) {
856                 camel_object_unref (CAMEL_OBJECT(priv->session));
857                 priv->session = NULL;
858         }
859         
860         G_OBJECT_CLASS(parent_class)->finalize (obj);
861 }
862
863 gboolean 
864 volume_path_is_mounted (const gchar* path)
865 {
866         g_return_val_if_fail (path, FALSE);
867
868         gboolean result = FALSE;
869         gchar * path_as_uri = g_filename_to_uri (path, NULL, NULL);
870         g_return_val_if_fail (path_as_uri, FALSE);
871
872         /* Get the monitor singleton: */
873         GnomeVFSVolumeMonitor *monitor = gnome_vfs_get_volume_monitor();
874
875         /* This seems like a simpler way to do this, but it returns a   
876          * GnomeVFSVolume even if the drive is not mounted: */
877         /*
878         GnomeVFSVolume *volume = gnome_vfs_volume_monitor_get_volume_for_path (monitor, 
879                 MODEST_MCC1_VOLUMEPATH);
880         if (volume) {
881                 gnome_vfs_volume_unref(volume);
882         }
883         */
884
885         /* Get the mounted volumes from the monitor: */
886         GList *list = gnome_vfs_volume_monitor_get_mounted_volumes (monitor);
887         GList *iter = list;
888         for (iter = list; iter; iter = g_list_next (iter)) {
889                 GnomeVFSVolume *volume = (GnomeVFSVolume*)iter->data;
890                 if (volume) {
891                         /*
892                         char *display_name = 
893                                 gnome_vfs_volume_get_display_name (volume);
894                         printf ("volume display name=%s\n", display_name);
895                         g_free (display_name);
896                         */
897                         
898                         char *uri = 
899                                 gnome_vfs_volume_get_activation_uri (volume);
900                         /* printf ("  uri=%s\n", uri); */
901                         if (uri && (strcmp (uri, path_as_uri) == 0))
902                                 result = TRUE;
903
904                         g_free (uri);
905
906                         gnome_vfs_volume_unref (volume);
907                 }
908         }
909
910         g_list_free (list);
911
912         g_free (path_as_uri);
913
914         return result;
915 }
916
917 ModestTnyAccountStore*
918 modest_tny_account_store_new (ModestAccountMgr *account_mgr, 
919                               TnyDevice *device) 
920 {
921         GObject *obj;
922         ModestTnyAccountStorePrivate *priv;
923         TnyAccount *local_account = NULL;
924         
925         g_return_val_if_fail (account_mgr, NULL);
926         g_return_val_if_fail (device, NULL);
927
928         obj  = G_OBJECT(g_object_new(MODEST_TYPE_TNY_ACCOUNT_STORE, NULL));
929         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
930
931         priv->account_mgr = g_object_ref (G_OBJECT(account_mgr));
932         priv->device = g_object_ref (device);
933         
934         priv->session = tny_session_camel_new (TNY_ACCOUNT_STORE(obj));
935         if (!priv->session) {
936                 g_warning ("failed to get TnySessionCamel");
937                 return NULL;
938         }
939
940         /* Set the ui locker */ 
941         tny_session_camel_set_ui_locker (priv->session,  tny_gtk_lockable_new ());
942         
943         /* Connect signals */
944         priv->sighandlers  =  modest_signal_mgr_connect (priv->sighandlers,
945                                                          G_OBJECT(account_mgr), "account_inserted",
946                                                          G_CALLBACK (on_account_inserted), obj);
947         priv->sighandlers  =  modest_signal_mgr_connect (priv->sighandlers,
948                                                          G_OBJECT(account_mgr), "account_changed",
949                                                          G_CALLBACK (on_account_changed), obj);
950         priv->sighandlers  =  modest_signal_mgr_connect (priv->sighandlers,
951                                                          G_OBJECT(account_mgr), "account_removed",
952                                                          G_CALLBACK (on_account_removed), obj);
953
954         /* Create the lists of accounts */
955         priv->store_accounts = tny_simple_list_new ();
956         priv->transport_accounts = tny_simple_list_new ();
957         priv->store_accounts_outboxes = tny_simple_list_new ();
958
959         /* Create the local folders account */
960         local_account = 
961                 modest_tny_account_new_for_local_folders (priv->account_mgr, priv->session, NULL);
962         tny_list_append (priv->store_accounts, G_OBJECT(local_account));
963         g_object_unref (local_account); 
964
965         /* Add the other remote accounts. Do this after adding the
966            local account, because we need to add our outboxes to the
967            global OUTBOX hosted in the local account */
968         add_existing_accounts (MODEST_TNY_ACCOUNT_STORE (obj));
969         
970         /* FIXME: I'm doing this (adding an "if (FALSE)"because this
971            stuff is not working properly and could cause SIGSEVs, for
972            example one send queue will be created for each connection
973            specific SMTP server, so when tinymail asks for the outbox
974            it will return NULL because there is no outbox folder for
975            this specific transport accounts, and it's a must that the
976            send queue returns an outbox */
977         if (TRUE)
978                 /* Add connection-specific transport accounts */
979                 add_connection_specific_transport_accounts (MODEST_TNY_ACCOUNT_STORE(obj));
980         
981         /* This is a singleton, so it does not need to be unrefed. */
982         if (volume_path_is_mounted (MODEST_MCC1_VOLUMEPATH)) {
983                 /* It is mounted: */
984                 add_mmc_account (MODEST_TNY_ACCOUNT_STORE (obj), FALSE /* don't emit the insert signal. */); 
985         }
986         
987         return MODEST_TNY_ACCOUNT_STORE(obj);
988 }
989
990 static void
991 modest_tny_account_store_get_accounts  (TnyAccountStore *self, 
992                                         TnyList *list,
993                                         TnyGetAccountsRequestType request_type)
994 {
995         ModestTnyAccountStorePrivate *priv;
996         
997         g_return_if_fail (self);
998         g_return_if_fail (TNY_IS_LIST(list));
999         
1000         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1001         
1002         switch (request_type) {
1003         case TNY_ACCOUNT_STORE_BOTH:
1004                 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
1005                 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
1006                 break;
1007         case TNY_ACCOUNT_STORE_STORE_ACCOUNTS:
1008                 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
1009                 break;
1010         case TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS:
1011                 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
1012                 break;
1013         default:
1014                 g_return_if_reached ();
1015         }
1016
1017         /* Initialize session. Why do we need this ??? */
1018         tny_session_camel_set_initialized (priv->session);
1019 }
1020
1021
1022 static const gchar*
1023 modest_tny_account_store_get_cache_dir (TnyAccountStore *self)
1024 {
1025         ModestTnyAccountStorePrivate *priv;
1026         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1027         
1028         if (!priv->cache_dir)
1029                 priv->cache_dir = g_build_filename (g_get_home_dir(), 
1030                                                     MODEST_DIR, MODEST_CACHE_DIR, NULL);
1031         return priv->cache_dir;
1032 }
1033
1034
1035 /*
1036  * callers need to unref
1037  */
1038 static TnyDevice*
1039 modest_tny_account_store_get_device (TnyAccountStore *self)
1040 {
1041         ModestTnyAccountStorePrivate *priv;
1042
1043         g_return_val_if_fail (self, NULL);
1044         
1045         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1046         
1047         if (priv->device) 
1048                 return g_object_ref (G_OBJECT(priv->device));
1049         else
1050                 return NULL;
1051 }
1052
1053
1054 static TnyAccount*
1055 modest_tny_account_store_find_account_by_url (TnyAccountStore *self, const gchar* url_string)
1056 {
1057         return modest_tny_account_store_get_tny_account_by (MODEST_TNY_ACCOUNT_STORE (self), 
1058                                                             MODEST_TNY_ACCOUNT_STORE_QUERY_URL,
1059                                                             url_string);
1060 }
1061
1062
1063
1064 static gboolean
1065 modest_tny_account_store_alert (TnyAccountStore *self, 
1066                                 TnyAccount *account, 
1067                                 TnyAlertType type,
1068                                 gboolean question, 
1069                                 const GError *error)
1070 {
1071         ModestTransportStoreProtocol proto =
1072                 MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN; 
1073         const gchar* server_name = NULL;
1074         gchar *prompt = NULL;
1075         gboolean retval;
1076
1077
1078         g_return_val_if_fail (account, FALSE);
1079         g_return_val_if_fail (error, FALSE);
1080         
1081         if ((error->domain != TNY_ACCOUNT_ERROR) && (error->domain != TNY_ACCOUNT_STORE_ERROR))
1082                 return FALSE;
1083         
1084         /* Get the server name: */
1085         server_name = tny_account_get_hostname (account);
1086
1087         if (account) {
1088                 const gchar *proto_name = tny_account_get_proto (account);
1089                 if (proto_name)
1090                         proto = modest_protocol_info_get_transport_store_protocol (proto_name);
1091                 else {
1092                         g_warning("modest: %s: account with id=%s has no proto.\n", __FUNCTION__, 
1093                                   tny_account_get_id (account));
1094                         return FALSE;
1095                 }
1096         }
1097
1098         switch (error->code) {
1099         case TNY_ACCOUNT_STORE_ERROR_CANCEL_ALERT:
1100         case TNY_ACCOUNT_ERROR_TRY_CONNECT_USER_CANCEL:
1101                 /* Don't show waste the user's time by showing him a dialog telling 
1102                  * him that he has just cancelled something: */
1103                 return TRUE;
1104
1105         case TNY_ACCOUNT_ERROR_TRY_CONNECT_HOST_LOOKUP_FAILED:
1106         case TNY_ACCOUNT_ERROR_TRY_CONNECT_SERVICE_UNAVAILABLE:
1107                 /* TODO: Show the appropriate message, depending on whether it's POP or IMAP: */                
1108                 switch (proto) {
1109                 case MODEST_PROTOCOL_STORE_POP:
1110                         prompt = g_strdup_printf (_("emev_ni_ui_pop3_msg_connect_error"),
1111                                                   server_name);
1112                         break;
1113                 case MODEST_PROTOCOL_STORE_IMAP:
1114                         prompt = g_strdup_printf (_("emev_ni_ui_imap_connect_server_error"),
1115                                                   server_name);
1116                         break;
1117                 case MODEST_PROTOCOL_TRANSPORT_SMTP:
1118                         prompt = g_strdup_printf (_("emev_ib_ui_smtp_server_invalid"),
1119                                                   server_name);
1120                         break;
1121                 default:
1122                         g_return_val_if_reached (FALSE);
1123                 }
1124                 break;
1125                 
1126         case TNY_ACCOUNT_ERROR_TRY_CONNECT_AUTHENTICATION_NOT_SUPPORTED:
1127                 /* This is "Secure connection failed", even though the logical
1128                  * ID has _certificate_ in the name: */
1129                 prompt = g_strdup (_("mail_ni_ssl_certificate_error")); 
1130                 break;
1131                         
1132         case TNY_ACCOUNT_ERROR_TRY_CONNECT_CERTIFICATE:
1133                 /* We'll show the proper dialog later */
1134                 break;
1135                 
1136         case TNY_ACCOUNT_ERROR_TRY_CONNECT:
1137                 /* The tinymail camel implementation just sends us this for almost 
1138                  * everything, so we have to guess at the cause.
1139                  * It could be a wrong password, or inability to resolve a hostname, 
1140                  * or lack of network, or incorrect authentication method, or something entirely different: */
1141                 /* TODO: Fix camel to provide specific error codes, and then use the 
1142                  * specific dialog messages from Chapter 12 of the UI spec.
1143                  */
1144         case TNY_ACCOUNT_STORE_ERROR_UNKNOWN_ALERT: 
1145                 return FALSE;                   
1146         default:
1147                 g_return_val_if_reached (FALSE);
1148         }
1149         
1150
1151         if (error->code == TNY_ACCOUNT_ERROR_TRY_CONNECT_CERTIFICATE)
1152                 retval = modest_platform_run_certificate_confirmation_dialog (server_name,
1153                                                                               error->message);
1154         else
1155                 retval = modest_platform_run_alert_dialog (prompt, question);
1156         
1157         if (prompt)
1158                 g_free (prompt);
1159         
1160         return retval;
1161 }
1162
1163
1164 static void
1165 modest_tny_account_store_init (gpointer g, gpointer iface_data)
1166 {
1167         TnyAccountStoreIface *klass;
1168
1169         g_return_if_fail (g);
1170
1171         klass = (TnyAccountStoreIface *)g;
1172
1173         klass->get_accounts_func =
1174                 modest_tny_account_store_get_accounts;
1175         klass->get_cache_dir_func =
1176                 modest_tny_account_store_get_cache_dir;
1177         klass->get_device_func =
1178                 modest_tny_account_store_get_device;
1179         klass->alert_func =
1180                 modest_tny_account_store_alert;
1181         klass->find_account_func =
1182                 modest_tny_account_store_find_account_by_url;
1183 }
1184
1185 void
1186 modest_tny_account_store_set_get_pass_func (ModestTnyAccountStore *self,
1187                                             ModestTnyGetPassFunc func)
1188 {
1189         /* not implemented, we use signals */
1190         g_printerr ("modest: set_get_pass_func not implemented\n");
1191 }
1192
1193 TnySessionCamel*
1194 modest_tny_account_store_get_session  (TnyAccountStore *self)
1195 {
1196         g_return_val_if_fail (self, NULL);
1197         return MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self)->session;
1198 }
1199
1200 static TnyAccount*
1201 get_tny_account_by (TnyList *accounts,
1202                     ModestTnyAccountStoreQueryType type,
1203                     const gchar *str)
1204 {
1205         TnyIterator *iter = NULL;
1206         gboolean found = FALSE;
1207         TnyAccount *retval = 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         /* Get the current connection: */
1346         TnyDevice *device = modest_runtime_get_device ();
1347         
1348         if (!tny_device_is_online (device))
1349                 return NULL;
1350
1351         g_return_val_if_fail (self, NULL);
1352         
1353         
1354 #ifdef MODEST_HAVE_CONIC
1355         g_return_val_if_fail (TNY_IS_MAEMO_CONIC_DEVICE (device), NULL);
1356         
1357         TnyMaemoConicDevice *maemo_device = TNY_MAEMO_CONIC_DEVICE (device);    
1358         const gchar* iap_id = tny_maemo_conic_device_get_current_iap_id (maemo_device);
1359         /* printf ("DEBUG: %s: iap_id=%s\n", __FUNCTION__, iap_id); */
1360         if (!iap_id)
1361                 return NULL;
1362                 
1363         ConIcIap* connection = tny_maemo_conic_device_get_iap (maemo_device, iap_id);
1364         if (!connection)
1365                 return NULL;
1366                 
1367         const gchar *connection_name = con_ic_iap_get_name (connection);
1368         /* printf ("DEBUG: %s: connection_name=%s\n", __FUNCTION__, connection_name); */
1369         if (!connection_name)
1370                 return NULL;
1371         
1372         /*  Get the connection-specific transport acccount, if any: */
1373         ModestAccountMgr *account_manager = modest_runtime_get_account_mgr ();
1374
1375         /* Check if this account has connection-specific SMTP enabled */
1376         if (!modest_account_mgr_get_use_connection_specific_smtp (account_manager, account_name)) {
1377                 return NULL;
1378         }
1379
1380         gchar* server_account_name = modest_account_mgr_get_connection_specific_smtp (account_manager, 
1381                 connection_name);
1382
1383         /* printf ("DEBUG: %s: server_account_name=%s\n", __FUNCTION__, server_account_name); */
1384         if (!server_account_name) {
1385                 return NULL; /* No connection-specific SMTP server was specified for this connection. */
1386         }
1387                 
1388         TnyAccount* account = modest_tny_account_store_get_tny_account_by (self, 
1389                                                                            MODEST_TNY_ACCOUNT_STORE_QUERY_ID, 
1390                                                                            server_account_name);
1391
1392         /* printf ("DEBUG: %s: account=%p\n", __FUNCTION__, account); */
1393         g_free (server_account_name);   
1394
1395         /* Unref the get()ed object, as required by the tny_maemo_conic_device_get_iap() documentation. */
1396         g_object_unref (connection);
1397         
1398         return account;
1399 #else
1400         return NULL; /* TODO: Implement this for GNOME, instead of just Maemo? */
1401 #endif /* MODEST_HAVE_CONIC */
1402 }
1403
1404                                                                  
1405 TnyAccount*
1406 modest_tny_account_store_get_transport_account_for_open_connection (ModestTnyAccountStore *self,
1407                                                                     const gchar *account_name)
1408 {
1409         g_return_val_if_fail (self, NULL);
1410         g_return_val_if_fail (account_name, NULL);
1411
1412         if (!account_name || !self)
1413                 return NULL;
1414         
1415         /*  Get the connection-specific transport acccount, if any: */
1416         /* Note: This gives us a reference: */
1417         TnyAccount *account =
1418                 modest_tny_account_store_get_smtp_specific_transport_account_for_open_connection (self, account_name);
1419                         
1420         /* If there is no connection-specific transport account (the common case), 
1421          * just get the regular transport account: */
1422         if (!account) {
1423                 /* The special local folders don't have transport accounts. */
1424                 if (strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0)
1425                         account = NULL;
1426                 else {
1427                         /* Note: This gives us a reference: */
1428                         account = modest_tny_account_store_get_server_account (self, account_name, 
1429                                                      TNY_ACCOUNT_TYPE_TRANSPORT);
1430                 }
1431         }
1432                         
1433         /* returns a reference. */     
1434         return account;
1435 }
1436
1437 TnyAccount*
1438 modest_tny_account_store_get_local_folders_account (ModestTnyAccountStore *self)
1439 {
1440         TnyAccount *account = NULL;
1441         ModestTnyAccountStorePrivate *priv;
1442         TnyIterator *iter;
1443         gboolean found;
1444
1445         g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1446         
1447         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1448
1449         found = FALSE;
1450         iter = tny_list_create_iterator (priv->store_accounts);
1451         while (!tny_iterator_is_done (iter) && !found) {
1452                 TnyAccount *tmp_account;
1453
1454                 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1455                 if (modest_tny_account_is_virtual_local_folders (tmp_account)) {
1456                         account = g_object_ref (tmp_account);
1457                         found = TRUE;
1458                 }
1459                 g_object_unref (tmp_account);
1460                 tny_iterator_next (iter);
1461         }
1462         g_object_unref (iter);
1463
1464         /* Returns a new reference to the account */
1465         return account;
1466 }
1467
1468 TnyAccount*
1469 modest_tny_account_store_get_mmc_folders_account (ModestTnyAccountStore *self)
1470 {
1471         g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1472         
1473         return modest_tny_account_store_get_tny_account_by (self, MODEST_TNY_ACCOUNT_STORE_QUERY_ID,
1474                                                             MODEST_MMC_ACCOUNT_ID);
1475
1476 }
1477
1478 /*********************************************************************************/
1479 static void
1480 add_existing_accounts (ModestTnyAccountStore *self)
1481 {
1482         GSList *account_names = NULL, *iter = NULL;
1483         ModestTnyAccountStorePrivate *priv = NULL;
1484         
1485         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1486
1487         /* These are account names, not server_account names */
1488         account_names = modest_account_mgr_account_names (priv->account_mgr, FALSE);
1489
1490         for (iter = account_names; iter != NULL; iter = g_slist_next (iter)) {
1491                 const gchar *account_name = (const gchar*) iter->data;
1492                 
1493                 /* Insert all enabled accounts without notifying */
1494                 if (modest_account_mgr_get_enabled (priv->account_mgr, account_name))
1495                         insert_account (self, account_name, FALSE);
1496         }
1497         modest_account_mgr_free_account_names (account_names);
1498 }
1499
1500 static TnyAccount*
1501 create_tny_account (ModestTnyAccountStore *self,
1502                     const gchar *name,
1503                     TnyAccountType type)
1504 {
1505         TnyAccount *account = NULL;
1506         ModestTnyAccountStorePrivate *priv = NULL;
1507         
1508         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1509
1510         account = modest_tny_account_new_from_account (priv->account_mgr,
1511                                                        name, type, 
1512                                                        priv->session,
1513                                                        get_password,
1514                                                        forget_password);
1515
1516         if (account) {
1517                 /* Forget any cached password for the account, so that
1518                    we use a new account if any */
1519                 modest_tny_account_store_forget_password_in_memory (self, 
1520                                                                     tny_account_get_id (account));
1521                 /* Set the account store */                             
1522                 g_object_set_data (G_OBJECT(account), "account_store", self);
1523         } else {
1524                 g_printerr ("modest: failed to create account for %s\n", name);
1525         }
1526
1527         return account;
1528 }
1529
1530
1531 static void
1532 add_outbox_from_transport_account_to_global_outbox (ModestTnyAccountStore *self,
1533                                                     const gchar *account_name,
1534                                                     TnyAccount *transport_account)
1535 {
1536         TnyList *folders = NULL;
1537         TnyIterator *iter_folders = NULL;
1538         TnyAccount *local_account = NULL, *account_outbox = NULL;
1539         TnyFolder *per_account_outbox = NULL;
1540         ModestTnyAccountStorePrivate *priv = NULL;
1541
1542         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1543
1544         /* Create per account local outbox */
1545         account_outbox = 
1546                 modest_tny_account_new_for_per_account_local_outbox_folder (priv->account_mgr, 
1547                                                                             account_name, 
1548                                                                             priv->session);
1549         tny_list_append (priv->store_accounts_outboxes, G_OBJECT (account_outbox));
1550
1551         /* Get the outbox folder */
1552         folders = tny_simple_list_new ();
1553         tny_folder_store_get_folders (TNY_FOLDER_STORE (account_outbox), folders, NULL, NULL);
1554         if (tny_list_get_length (folders) != 1) {
1555                 g_warning ("%s: > 1 outbox found (%d)?!", __FUNCTION__,
1556                            tny_list_get_length (folders));
1557         }
1558                         
1559         iter_folders = tny_list_create_iterator (folders);
1560         per_account_outbox = TNY_FOLDER (tny_iterator_get_current (iter_folders));
1561         g_object_unref (iter_folders);
1562         g_object_unref (folders);
1563         g_object_unref (account_outbox);
1564
1565         /* Add the outbox of the new per-account-local-outbox account
1566            to the global local merged OUTBOX of the local folders
1567            account */
1568         local_account = modest_tny_account_store_get_local_folders_account (self);
1569         modest_tny_local_folders_account_add_folder_to_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1570                                                                per_account_outbox);
1571         /* Add the pair to the hash table */
1572         g_hash_table_insert (priv->outbox_of_transport,
1573                              transport_account,
1574                              per_account_outbox);
1575         
1576         g_object_unref (local_account);
1577         g_object_unref (per_account_outbox);
1578 }
1579
1580 /*
1581  * This function will be used for both adding new accounts and for the
1582  * initialization. In the initialization we do not want to emit
1583  * signals so notify will be FALSE, in the case of account additions
1584  * we do want to notify the observers
1585  */
1586 static void
1587 insert_account (ModestTnyAccountStore *self,
1588                 const gchar *account,
1589                 gboolean notify)
1590 {
1591         ModestTnyAccountStorePrivate *priv = NULL;
1592         TnyAccount *store_account = NULL, *transport_account = NULL;
1593         
1594         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1595
1596         /* Get the server and the transport account */
1597         store_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_STORE);
1598         if (!store_account || !TNY_IS_ACCOUNT(store_account)) {
1599                 g_warning ("%s: failed to create store account", __FUNCTION__);
1600                 return;
1601         }
1602
1603         transport_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT);
1604         if (!transport_account || !TNY_IS_ACCOUNT(transport_account)) {
1605                 g_warning ("%s: failed to create transport account", __FUNCTION__);
1606                 g_object_unref (store_account);
1607                 return;
1608         }
1609
1610         /* Add accounts to the lists */
1611         tny_list_append (priv->store_accounts, G_OBJECT (store_account));
1612         tny_list_append (priv->transport_accounts, G_OBJECT (transport_account));
1613         
1614         /* Create a new pseudo-account with an outbox for this
1615            transport account and add it to the global outbox
1616            in the local account */
1617         add_outbox_from_transport_account_to_global_outbox (self, account, transport_account);
1618         
1619         /* Notify the observers. We do it after everything is
1620            created */
1621         if (notify) {
1622                 TnyAccount *local_account = NULL;
1623                 
1624                 /* Notify the observers about the new server & transport accounts */
1625                 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, store_account);   
1626                 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, transport_account);
1627
1628                 /* Notify that the local account changed */
1629                 local_account = modest_tny_account_store_get_local_folders_account (self);
1630                 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1631                 g_object_unref (local_account);
1632         }
1633
1634         /* Frees */
1635         g_object_unref (store_account);
1636         g_object_unref (transport_account);
1637 }
1638
1639 static void
1640 on_account_inserted (ModestAccountMgr *acc_mgr, 
1641                      const gchar *account,
1642                      gpointer user_data)
1643 {
1644         /* Insert the account and notify the observers */
1645         insert_account (MODEST_TNY_ACCOUNT_STORE (user_data), account, TRUE);
1646 }
1647
1648 /* This is the callback of the tny_camel_account_set_online called in
1649    on_account_removed to disconnect the account */
1650 static void
1651 on_account_disconnect_when_removing (TnyCamelAccount *account, 
1652                                      gboolean canceled, 
1653                                      GError *err, 
1654                                      gpointer user_data)
1655 {
1656         ModestTnyAccountStore *self;
1657         ModestTnyAccountStorePrivate *priv;
1658
1659         self = MODEST_TNY_ACCOUNT_STORE (user_data);
1660         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1661
1662         if (canceled || err) {
1663                 /* The account was not cancelled */
1664         } else {
1665                 /* Clear the cache if it's an store account */
1666                 if (TNY_IS_STORE_ACCOUNT (account))
1667                         tny_store_account_delete_cache (TNY_STORE_ACCOUNT (account));
1668         }
1669
1670         /* Remove it from the list of accounts */
1671         if (TNY_IS_STORE_ACCOUNT (account))
1672                 tny_list_remove (priv->store_accounts, (GObject *) account);
1673         else
1674                 tny_list_remove (priv->transport_accounts, (GObject *) account);
1675
1676         /* Notify the observers */
1677         g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 
1678                        0, account);
1679         
1680         /* Unref the extra reference added by get_server_account */
1681         g_object_unref (account);
1682 }
1683
1684 static void
1685 on_account_removed (ModestAccountMgr *acc_mgr, const gchar *account,
1686                     gpointer user_data)
1687 {
1688         TnyAccount *store_account = NULL, *transport_account = NULL;
1689         ModestTnyAccountStore *self;
1690         ModestTnyAccountStorePrivate *priv;
1691         
1692         self = MODEST_TNY_ACCOUNT_STORE (user_data);
1693         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1694
1695         /* Get the server and the transport account */
1696         store_account = 
1697                 modest_tny_account_store_get_server_account (self, account, TNY_ACCOUNT_TYPE_STORE);
1698         transport_account = 
1699                 modest_tny_account_store_get_server_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT);
1700         
1701         /* If there was any problem creating the account, for example,
1702            with the configuration system this could not exist */
1703         if (store_account) {
1704                 /* Disconnect before deleting the cache, because the
1705                    disconnection will rewrite the cache to the
1706                    disk */
1707                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (store_account), FALSE,
1708                                               on_account_disconnect_when_removing, self);
1709         } else {
1710                 g_warning ("There is no store account for account %s\n", account);
1711         }
1712
1713         /* If there was any problem creating the account, for example,
1714            with the configuration system this could not exist */
1715         if (transport_account) {
1716                 TnyAccount *local_account = NULL;
1717                 TnyFolder *outbox = NULL;
1718                 ModestTnyAccountStorePrivate *priv = NULL;
1719         
1720                 /* Remove the OUTBOX of the account from the global outbox */
1721                 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1722                 outbox = g_hash_table_lookup (priv->outbox_of_transport, transport_account);
1723
1724                 if (TNY_IS_FOLDER (outbox)) {
1725                         local_account = modest_tny_account_store_get_local_folders_account (self);
1726                         modest_tny_local_folders_account_remove_folder_from_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1727                                                                                     outbox);
1728                         g_hash_table_remove (priv->outbox_of_transport, transport_account);
1729
1730                         /* Notify the change in the local account */
1731                         g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1732                         g_object_unref (local_account);
1733                 } else {
1734                         g_warning ("Removing a transport account that has no outbox");
1735                 }
1736
1737                 /* Disconnect and notify the observers. The callback will free the reference */
1738                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (transport_account), FALSE,
1739                                               on_account_disconnect_when_removing, self);
1740         } else {
1741                 g_warning ("There is no transport account for account %s\n", account);
1742         }
1743 }
1744
1745 TnyTransportAccount *
1746 modest_tny_account_store_new_connection_specific_transport_account (ModestTnyAccountStore *self,
1747                                                                     const gchar *name)
1748 {
1749         ModestTnyAccountStorePrivate *priv = NULL;
1750         TnyAccount * tny_account = NULL;
1751
1752         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1753
1754         /* Add the account: */
1755         tny_account = 
1756                 modest_tny_account_new_from_server_account_name (priv->account_mgr, 
1757                                                                  priv->session, 
1758                                                                  name,
1759                                                                  get_password,
1760                                                                  forget_password);
1761         if (tny_account) {
1762                 g_object_set_data (G_OBJECT(tny_account), 
1763                                    "account_store", 
1764                                    (gpointer)self);
1765                 
1766                 tny_list_append (priv->transport_accounts, G_OBJECT (tny_account));
1767                 add_outbox_from_transport_account_to_global_outbox (self, 
1768                                                                     name, 
1769                                                                     tny_account);
1770                 
1771         } else
1772                 g_printerr ("modest: failed to create smtp-specific account for %s\n",
1773                             name);
1774
1775         return TNY_TRANSPORT_ACCOUNT (tny_account);
1776 }
1777
1778
1779 static void
1780 add_connection_specific_transport_accounts (ModestTnyAccountStore *self)
1781 {
1782         ModestTnyAccountStorePrivate *priv = NULL;
1783         GSList *list_specifics = NULL, *iter = NULL;
1784
1785         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1786
1787         ModestConf *conf = modest_runtime_get_conf ();
1788
1789         GError *err = NULL;
1790         list_specifics = modest_conf_get_list (conf,
1791                                                MODEST_CONF_CONNECTION_SPECIFIC_SMTP_LIST,
1792                                                MODEST_CONF_VALUE_STRING, &err);
1793         if (err) {
1794                 g_printerr ("modest: %s: error getting list: %s\n.", __FUNCTION__, err->message);
1795                 g_error_free (err);
1796                 err = NULL;
1797         }
1798                                 
1799         /* Look at each connection-specific transport account for the 
1800          * modest account: */
1801         iter = list_specifics;
1802         while (iter) {
1803                 /* The list alternates between the connection name and the transport name: */
1804                 iter = g_slist_next (iter);
1805                 if (iter) {
1806                         const gchar* transport_account_name = (const gchar*) (iter->data);
1807                         TnyTransportAccount * account = NULL;
1808                         account = modest_tny_account_store_new_connection_specific_transport_account (
1809                                 self, transport_account_name);
1810                         if (account)
1811                                 g_object_unref (account);
1812                 }                               
1813                 iter = g_slist_next (iter);
1814         }
1815 }
1816
1817 TnyMsg *
1818 modest_tny_account_store_find_msg_in_outboxes (ModestTnyAccountStore *self, 
1819                                                const gchar *uri,
1820                                                TnyAccount **ac_out)
1821 {
1822         TnyIterator *acc_iter;
1823         ModestTnyAccountStorePrivate *priv;
1824         TnyMsg *msg = NULL;
1825         TnyAccount *msg_account = NULL;
1826
1827         g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1828         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1829
1830         acc_iter = tny_list_create_iterator (priv->store_accounts_outboxes);
1831         while (!msg && !tny_iterator_is_done (acc_iter)) {
1832                 TnyList *folders = tny_simple_list_new ();
1833                 TnyAccount *account = TNY_ACCOUNT (tny_iterator_get_current (acc_iter));
1834                 TnyIterator *folders_iter = NULL;
1835
1836                 tny_folder_store_get_folders (TNY_FOLDER_STORE (account), folders, NULL, NULL);
1837                 folders_iter = tny_list_create_iterator (folders);
1838
1839                 while (msg == NULL && !tny_iterator_is_done (folders_iter)) {
1840                         TnyFolder *folder = TNY_FOLDER (tny_iterator_get_current (folders_iter));
1841                         msg = tny_folder_find_msg (folder, uri, NULL);
1842
1843                         if (msg)
1844                                 msg_account = g_object_ref (account);
1845
1846                         g_object_unref (folder);
1847                         tny_iterator_next (folders_iter);
1848                 }
1849
1850                 g_object_unref (folders);
1851                 g_object_unref (account);
1852                 tny_iterator_next (acc_iter);
1853         }
1854
1855         g_object_unref (acc_iter);
1856
1857         if (ac_out != NULL)
1858                 *ac_out = msg_account;
1859
1860         return msg;
1861 }
1862
1863 TnyTransportAccount *
1864 modest_tny_account_store_get_transport_account_from_outbox_header(ModestTnyAccountStore *self, TnyHeader *header)
1865 {
1866         TnyIterator *acc_iter;
1867         ModestTnyAccountStorePrivate *priv;
1868         TnyTransportAccount *header_acc = NULL;
1869         const gchar *msg_id;
1870
1871         g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1872         g_return_val_if_fail (TNY_IS_HEADER (header), NULL);
1873         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1874
1875         msg_id = modest_tny_send_queue_get_msg_id (header);
1876         acc_iter = tny_list_create_iterator (priv->transport_accounts);
1877         while (!header_acc && !tny_iterator_is_done (acc_iter)) {
1878                 TnyTransportAccount *account = TNY_TRANSPORT_ACCOUNT (tny_iterator_get_current (acc_iter));
1879                 ModestTnySendQueue *send_queue;
1880                 ModestTnySendQueueStatus status;
1881                 send_queue = modest_runtime_get_send_queue(TNY_TRANSPORT_ACCOUNT(account));
1882                 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
1883                 if (status != MODEST_TNY_SEND_QUEUE_UNKNOWN) {
1884                         header_acc = g_object_ref(account);
1885                 }
1886                 g_object_unref (account);
1887                 tny_iterator_next (acc_iter);
1888         }
1889
1890         g_object_unref(acc_iter);
1891         return header_acc;
1892 }