3bf4ac31f406fe752868afb43e510ee7ef8f3d64
[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-error.h>
34 #include <tny-account.h>
35 #include <tny-account-store.h>
36 #include <tny-store-account.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 ("%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 ("%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 ("%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         ModestTnyAccountStore *self;
767         ModestTnyAccountStorePrivate *priv;
768         const TnyAccountStore *account_store;
769         gchar *pwd;
770         const gchar *key;
771         
772         account_store = TNY_ACCOUNT_STORE(g_object_get_data (G_OBJECT(account),
773                                                              "account_store"));
774         self = MODEST_TNY_ACCOUNT_STORE (account_store);
775         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
776         key  = tny_account_get_id (account);
777
778         /* Do not remove the key, this will allow us to detect that we
779            have already asked for it at least once */
780         pwd = g_hash_table_lookup (priv->password_hash, key);
781         if (pwd) {
782                 memset (pwd, 0, strlen (pwd));
783                 g_hash_table_insert (priv->password_hash, g_strdup (key), NULL);
784         }
785
786         /* Remove from configuration system */
787         /*
788         modest_account_mgr_unset (priv->account_mgr,
789                                   key, MODEST_ACCOUNT_PASSWORD, TRUE);
790         */
791 }
792
793 static void
794 modest_tny_account_store_finalize (GObject *obj)
795 {
796         ModestTnyAccountStore *self        = MODEST_TNY_ACCOUNT_STORE(obj);
797         ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
798
799         g_free (priv->cache_dir);
800         priv->cache_dir = NULL;
801         
802         if (priv->password_hash) {
803                 g_hash_table_destroy (priv->password_hash);
804                 priv->password_hash = NULL;
805         }
806
807 #ifdef MODEST_PLATFORM_MAEMO
808         if (priv->account_settings_dialog_hash) {
809                 g_hash_table_destroy (priv->account_settings_dialog_hash);
810                 priv->account_settings_dialog_hash = NULL;
811         }
812 #endif
813
814         if (priv->outbox_of_transport) {
815                 g_hash_table_destroy (priv->outbox_of_transport);
816                 priv->outbox_of_transport = NULL;
817         }
818
819         modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
820         priv->sighandlers = NULL;       
821
822         if (priv->account_mgr) {
823                 g_object_unref (G_OBJECT(priv->account_mgr));
824                 priv->account_mgr = NULL;
825         }
826
827         if (priv->device) {
828                 g_object_unref (G_OBJECT(priv->device));
829                 priv->device = NULL;
830         }
831
832         /* Destroy all accounts. Disconnect all accounts before they are destroyed */
833         if (priv->store_accounts) {
834                 tny_list_foreach (priv->store_accounts, (GFunc)account_disconnect, NULL);
835                 tny_list_foreach (priv->store_accounts, (GFunc)account_verify_last_ref, "store");
836                 g_object_unref (priv->store_accounts);
837                 priv->store_accounts = NULL;
838         }
839         
840         if (priv->transport_accounts) {
841                 tny_list_foreach (priv->transport_accounts, (GFunc)account_disconnect, NULL);
842                 tny_list_foreach (priv->transport_accounts, (GFunc)account_verify_last_ref, "transport");
843                 g_object_unref (priv->transport_accounts);
844                 priv->transport_accounts = NULL;
845         }
846
847         if (priv->store_accounts_outboxes) {
848                 g_object_unref (priv->store_accounts_outboxes);
849                 priv->store_accounts_outboxes = NULL;
850         }
851                 
852         if (priv->session) {
853                 camel_object_unref (CAMEL_OBJECT(priv->session));
854                 priv->session = NULL;
855         }
856
857         camel_shutdown ();
858         
859         G_OBJECT_CLASS(parent_class)->finalize (obj);
860 }
861
862 gboolean 
863 volume_path_is_mounted (const gchar* path)
864 {
865         g_return_val_if_fail (path, FALSE);
866
867         gboolean result = FALSE;
868         gchar * path_as_uri = g_filename_to_uri (path, NULL, NULL);
869         g_return_val_if_fail (path_as_uri, FALSE);
870
871         /* Get the monitor singleton: */
872         GnomeVFSVolumeMonitor *monitor = gnome_vfs_get_volume_monitor();
873
874         /* This seems like a simpler way to do this, but it returns a   
875          * GnomeVFSVolume even if the drive is not mounted: */
876         /*
877         GnomeVFSVolume *volume = gnome_vfs_volume_monitor_get_volume_for_path (monitor, 
878                 MODEST_MCC1_VOLUMEPATH);
879         if (volume) {
880                 gnome_vfs_volume_unref(volume);
881         }
882         */
883
884         /* Get the mounted volumes from the monitor: */
885         GList *list = gnome_vfs_volume_monitor_get_mounted_volumes (monitor);
886         GList *iter = list;
887         for (iter = list; iter; iter = g_list_next (iter)) {
888                 GnomeVFSVolume *volume = (GnomeVFSVolume*)iter->data;
889                 if (volume) {
890                         /*
891                         char *display_name = 
892                                 gnome_vfs_volume_get_display_name (volume);
893                         printf ("volume display name=%s\n", display_name);
894                         g_free (display_name);
895                         */
896                         
897                         char *uri = 
898                                 gnome_vfs_volume_get_activation_uri (volume);
899                         /* printf ("  uri=%s\n", uri); */
900                         if (uri && (strcmp (uri, path_as_uri) == 0))
901                                 result = TRUE;
902
903                         g_free (uri);
904
905                         gnome_vfs_volume_unref (volume);
906                 }
907         }
908
909         g_list_free (list);
910
911         g_free (path_as_uri);
912
913         return result;
914 }
915
916 ModestTnyAccountStore*
917 modest_tny_account_store_new (ModestAccountMgr *account_mgr, 
918                               TnyDevice *device) 
919 {
920         GObject *obj;
921         ModestTnyAccountStorePrivate *priv;
922         TnyAccount *local_account = NULL;
923         
924         g_return_val_if_fail (account_mgr, NULL);
925         g_return_val_if_fail (device, NULL);
926
927         obj  = G_OBJECT(g_object_new(MODEST_TYPE_TNY_ACCOUNT_STORE, NULL));
928         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
929
930         priv->account_mgr = g_object_ref (G_OBJECT(account_mgr));
931         priv->device = g_object_ref (device);
932         
933         priv->session = tny_session_camel_new (TNY_ACCOUNT_STORE(obj));
934         if (!priv->session) {
935                 g_warning ("failed to get TnySessionCamel");
936                 return NULL;
937         }
938
939         /* Set the ui locker */ 
940         tny_session_camel_set_ui_locker (priv->session,  tny_gtk_lockable_new ());
941         
942         /* Connect signals */
943         priv->sighandlers  =  modest_signal_mgr_connect (priv->sighandlers,
944                                                          G_OBJECT(account_mgr), "account_inserted",
945                                                          G_CALLBACK (on_account_inserted), obj);
946         priv->sighandlers  =  modest_signal_mgr_connect (priv->sighandlers,
947                                                          G_OBJECT(account_mgr), "account_changed",
948                                                          G_CALLBACK (on_account_changed), obj);
949         priv->sighandlers  =  modest_signal_mgr_connect (priv->sighandlers,
950                                                          G_OBJECT(account_mgr), "account_removed",
951                                                          G_CALLBACK (on_account_removed), obj);
952
953         /* Create the lists of accounts */
954         priv->store_accounts = tny_simple_list_new ();
955         priv->transport_accounts = tny_simple_list_new ();
956         priv->store_accounts_outboxes = tny_simple_list_new ();
957
958         /* Create the local folders account */
959         local_account = 
960                 modest_tny_account_new_for_local_folders (priv->account_mgr, priv->session, NULL);
961         tny_list_append (priv->store_accounts, G_OBJECT(local_account));
962         g_object_unref (local_account); 
963
964         /* Add the other remote accounts. Do this after adding the
965            local account, because we need to add our outboxes to the
966            global OUTBOX hosted in the local account */
967         add_existing_accounts (MODEST_TNY_ACCOUNT_STORE (obj));
968         
969         /* FIXME: I'm doing this (adding an "if (FALSE)"because this
970            stuff is not working properly and could cause SIGSEVs, for
971            example one send queue will be created for each connection
972            specific SMTP server, so when tinymail asks for the outbox
973            it will return NULL because there is no outbox folder for
974            this specific transport accounts, and it's a must that the
975            send queue returns an outbox */
976         if (TRUE)
977                 /* Add connection-specific transport accounts */
978                 add_connection_specific_transport_accounts (MODEST_TNY_ACCOUNT_STORE(obj));
979         
980         /* This is a singleton, so it does not need to be unrefed. */
981         if (volume_path_is_mounted (MODEST_MCC1_VOLUMEPATH)) {
982                 /* It is mounted: */
983                 add_mmc_account (MODEST_TNY_ACCOUNT_STORE (obj), FALSE /* don't emit the insert signal. */); 
984         }
985         
986         return MODEST_TNY_ACCOUNT_STORE(obj);
987 }
988
989 static void
990 modest_tny_account_store_get_accounts  (TnyAccountStore *self, 
991                                         TnyList *list,
992                                         TnyGetAccountsRequestType request_type)
993 {
994         ModestTnyAccountStorePrivate *priv;
995         
996         g_return_if_fail (self);
997         g_return_if_fail (TNY_IS_LIST(list));
998         
999         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1000         
1001         switch (request_type) {
1002         case TNY_ACCOUNT_STORE_BOTH:
1003                 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
1004                 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
1005                 break;
1006         case TNY_ACCOUNT_STORE_STORE_ACCOUNTS:
1007                 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
1008                 break;
1009         case TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS:
1010                 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
1011                 break;
1012         default:
1013                 g_return_if_reached ();
1014         }
1015
1016         /* Initialize session. Why do we need this ??? */
1017         tny_session_camel_set_initialized (priv->session);
1018 }
1019
1020
1021 static const gchar*
1022 modest_tny_account_store_get_cache_dir (TnyAccountStore *self)
1023 {
1024         ModestTnyAccountStorePrivate *priv;
1025         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1026         
1027         if (!priv->cache_dir)
1028                 priv->cache_dir = g_build_filename (g_get_home_dir(), 
1029                                                     MODEST_DIR, MODEST_CACHE_DIR, NULL);
1030         return priv->cache_dir;
1031 }
1032
1033
1034 /*
1035  * callers need to unref
1036  */
1037 static TnyDevice*
1038 modest_tny_account_store_get_device (TnyAccountStore *self)
1039 {
1040         ModestTnyAccountStorePrivate *priv;
1041
1042         g_return_val_if_fail (self, NULL);
1043         
1044         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1045         
1046         if (priv->device) 
1047                 return g_object_ref (G_OBJECT(priv->device));
1048         else
1049                 return NULL;
1050 }
1051
1052
1053 static TnyAccount*
1054 modest_tny_account_store_find_account_by_url (TnyAccountStore *self, const gchar* url_string)
1055 {
1056         return modest_tny_account_store_get_tny_account_by (MODEST_TNY_ACCOUNT_STORE (self), 
1057                                                             MODEST_TNY_ACCOUNT_STORE_QUERY_URL,
1058                                                             url_string);
1059 }
1060
1061
1062
1063 static gboolean
1064 modest_tny_account_store_alert (TnyAccountStore *self, 
1065                                 TnyAccount *account, 
1066                                 TnyAlertType type,
1067                                 gboolean question, 
1068                                 GError *error)
1069 {
1070         ModestTransportStoreProtocol proto =
1071                 MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN; 
1072         const gchar* server_name = NULL;
1073         gchar *prompt = NULL;
1074         gboolean retval;
1075
1076
1077         g_return_val_if_fail (account, FALSE);
1078         g_return_val_if_fail (error, FALSE);
1079         
1080         /* Get the server name: */
1081         server_name = tny_account_get_hostname (account);
1082
1083         if (account) {
1084                 const gchar *proto_name = tny_account_get_proto (account);
1085                 if (proto_name)
1086                         proto = modest_protocol_info_get_transport_store_protocol (proto_name);
1087                 else {
1088                         g_warning("modest: %s: account with id=%s has no proto.\n", __FUNCTION__, 
1089                                   tny_account_get_id (account));
1090                         return FALSE;
1091                 }
1092         }
1093
1094         switch (error->code) {
1095         case TNY_SYSTEM_ERROR_CANCEL:
1096                 /* Don't show waste the user's time by showing him a dialog telling 
1097                  * him that he has just cancelled something: */
1098                 return TRUE;
1099
1100         case TNY_SERVICE_ERROR_PROTOCOL:
1101                 /* Like a BAD from IMAP (protocol error) */
1102         case TNY_SERVICE_ERROR_LOST_CONNECTION:
1103                 /* Lost the connection with the service */
1104         case TNY_SERVICE_ERROR_UNAVAILABLE:
1105                 /* You must be working online for this operation */
1106         case TNY_SERVICE_ERROR_CONNECT:
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_SERVICE_ERROR_AUTHENTICATE:
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_SERVICE_ERROR_CERTIFICATE:
1133                 /* We'll show the proper dialog later */
1134                 break;
1135
1136         case TNY_SYSTEM_ERROR_MEMORY:
1137                 /* Can't allocate memory for this operation */
1138
1139         case TNY_SERVICE_ERROR_UNKNOWN: 
1140                 return FALSE;                   
1141         default:
1142                 g_return_val_if_reached (FALSE);
1143         }
1144         
1145
1146         if (error->code == TNY_SERVICE_ERROR_CERTIFICATE)
1147                 retval = modest_platform_run_certificate_confirmation_dialog (server_name,
1148                                                                               error->message);
1149         else
1150                 retval = modest_platform_run_alert_dialog (prompt, question);
1151         
1152         if (prompt)
1153                 g_free (prompt);
1154         
1155         return retval;
1156 }
1157
1158
1159 static void
1160 modest_tny_account_store_init (gpointer g, gpointer iface_data)
1161 {
1162         TnyAccountStoreIface *klass;
1163
1164         g_return_if_fail (g);
1165
1166         klass = (TnyAccountStoreIface *)g;
1167
1168         klass->get_accounts =
1169                 modest_tny_account_store_get_accounts;
1170         klass->get_cache_dir =
1171                 modest_tny_account_store_get_cache_dir;
1172         klass->get_device =
1173                 modest_tny_account_store_get_device;
1174         klass->alert =
1175                 modest_tny_account_store_alert;
1176         klass->find_account =
1177                 modest_tny_account_store_find_account_by_url;
1178 }
1179
1180 void
1181 modest_tny_account_store_set_get_pass_func (ModestTnyAccountStore *self,
1182                                             ModestTnyGetPassFunc func)
1183 {
1184         /* not implemented, we use signals */
1185         g_printerr ("modest: set_get_pass_func not implemented\n");
1186 }
1187
1188 TnySessionCamel*
1189 modest_tny_account_store_get_session  (TnyAccountStore *self)
1190 {
1191         g_return_val_if_fail (self, NULL);
1192         return MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self)->session;
1193 }
1194
1195 static TnyAccount*
1196 get_tny_account_by (TnyList *accounts,
1197                     ModestTnyAccountStoreQueryType type,
1198                     const gchar *str)
1199 {
1200         TnyIterator *iter = NULL;
1201         gboolean found = FALSE;
1202         TnyAccount *retval = NULL;
1203
1204         g_return_val_if_fail (TNY_IS_LIST(accounts), NULL);
1205
1206         if (tny_list_get_length(accounts) == 0) {
1207                 g_warning ("%s: account list is empty", __FUNCTION__);
1208                 return NULL;
1209         }
1210         
1211         iter = tny_list_create_iterator (accounts);
1212         while (!tny_iterator_is_done (iter) && !found) {
1213                 TnyAccount *tmp_account = NULL;
1214                 const gchar *val = NULL;
1215
1216                 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1217                 if (!TNY_IS_ACCOUNT(tmp_account)) {
1218                         g_warning ("%s: not a valid account", __FUNCTION__);
1219                         tmp_account = NULL;
1220                         break;
1221                 }
1222
1223                 switch (type) {
1224                 case MODEST_TNY_ACCOUNT_STORE_QUERY_ID:
1225                         val = tny_account_get_id (tmp_account);
1226                         break;
1227                 case MODEST_TNY_ACCOUNT_STORE_QUERY_URL:
1228                         val = tny_account_get_url_string (tmp_account);
1229                         break;
1230                 }
1231                 
1232                 if (type == MODEST_TNY_ACCOUNT_STORE_QUERY_URL && 
1233                     tny_account_matches_url_string (tmp_account, str)) {
1234                         retval = g_object_ref (tmp_account);
1235                         found = TRUE;
1236                 } else {
1237                         if (val && str && strcmp (val, str) == 0) {
1238                                 retval = g_object_ref (tmp_account);
1239                                 found = TRUE;
1240                         }
1241                 }
1242                 g_object_unref (tmp_account);
1243                 tny_iterator_next (iter);
1244         }
1245         g_object_unref (iter);
1246
1247         return retval;
1248 }
1249
1250 TnyAccount*
1251 modest_tny_account_store_get_tny_account_by (ModestTnyAccountStore *self, 
1252                                              ModestTnyAccountStoreQueryType type,
1253                                              const gchar *str)
1254 {
1255         TnyAccount *account = NULL;
1256         ModestTnyAccountStorePrivate *priv;     
1257         
1258         g_return_val_if_fail (self, NULL);
1259         g_return_val_if_fail (str, NULL);
1260         
1261         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1262         
1263         /* Search in store accounts */
1264         account = get_tny_account_by (priv->store_accounts, type, str);
1265
1266         /* If we already found something, no need to search the transport accounts */
1267         if (!account) {
1268                 account = get_tny_account_by (priv->transport_accounts, type, str);
1269
1270                 /* If we already found something, no need to search the
1271                    per-account outbox accounts */
1272                 if (!account)
1273                         account = get_tny_account_by (priv->store_accounts_outboxes, type, str);
1274         }
1275
1276         /* Warn if nothing was found. This is generally unusual. */
1277         if (!account) {
1278                 g_warning("%s: Failed to find account with %s=%s\n", 
1279                           __FUNCTION__, 
1280                           (type == MODEST_TNY_ACCOUNT_STORE_QUERY_ID) ? "ID" : "URL",                     
1281                           str);
1282         }
1283
1284         /* Returns a new reference to the account if found */   
1285         return account;
1286 }
1287
1288
1289 TnyAccount*
1290 modest_tny_account_store_get_server_account (ModestTnyAccountStore *self,
1291                                              const gchar *account_name,
1292                                              TnyAccountType type)
1293 {
1294         ModestTnyAccountStorePrivate *priv = NULL;
1295         TnyAccount *retval = NULL;
1296         TnyList *account_list = NULL;
1297         TnyIterator *iter = NULL;
1298         gboolean found;
1299
1300         g_return_val_if_fail (self, NULL);
1301         g_return_val_if_fail (account_name, NULL);
1302         g_return_val_if_fail (type == TNY_ACCOUNT_TYPE_STORE || 
1303                               type == TNY_ACCOUNT_TYPE_TRANSPORT,
1304                               NULL);
1305         
1306         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1307
1308         account_list = (type == TNY_ACCOUNT_TYPE_STORE) ? 
1309                 priv->store_accounts : 
1310                 priv->transport_accounts;
1311
1312         if (!account_list) {
1313                 g_printerr ("%s: No server accounts of type %s\n", __FUNCTION__, 
1314                         (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport");
1315                 return NULL;
1316         }
1317         
1318         /* Look for the server account */
1319         found = FALSE;
1320         iter = tny_list_create_iterator (account_list);
1321         while (!tny_iterator_is_done (iter) && !found) {
1322                 const gchar *modest_acc_name;
1323                 TnyAccount *tmp_account;
1324
1325                 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1326                 modest_acc_name = 
1327                         modest_tny_account_get_parent_modest_account_name_for_server_account (tmp_account);
1328                 
1329                 if (account_name && modest_acc_name && !strcmp (account_name, modest_acc_name)) {
1330                         found = TRUE;
1331                         retval = g_object_ref (tmp_account);
1332                 }
1333                 /* Free and continue */
1334                 g_object_unref (tmp_account);
1335                 tny_iterator_next (iter);
1336         }
1337         g_object_unref (iter);
1338
1339         if (!found) {
1340                 g_printerr ("modest: %s: could not get tny %s account for %s\n." \
1341                             "Number of server accounts of this type=%d\n", __FUNCTION__,
1342                             (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport",
1343                             account_name, tny_list_get_length (account_list));
1344         }
1345
1346         /* Returns a new reference */
1347         return retval;
1348 }
1349
1350 TnyAccount*
1351 modest_tny_account_store_get_smtp_specific_transport_account_for_open_connection (
1352         ModestTnyAccountStore *self, const gchar *account_name)
1353 {
1354         TnyDevice *device;
1355
1356         g_return_val_if_fail (self && MODEST_IS_TNY_ACCOUNT_STORE(self), NULL);
1357         g_return_val_if_fail (account_name, NULL);
1358
1359         /* Get the current connection: */
1360         device = modest_runtime_get_device ();
1361
1362         if (!device) {
1363                 g_warning ("%s: could not get device", __FUNCTION__);
1364                 return NULL;
1365         }
1366                 
1367         if (!tny_device_is_online (device))
1368                 return NULL;
1369         
1370 #ifdef MODEST_HAVE_CONIC
1371         g_return_val_if_fail (TNY_IS_MAEMO_CONIC_DEVICE (device), NULL);
1372         
1373         TnyMaemoConicDevice *maemo_device = TNY_MAEMO_CONIC_DEVICE (device);    
1374         const gchar* iap_id = tny_maemo_conic_device_get_current_iap_id (maemo_device);
1375         /* printf ("DEBUG: %s: iap_id=%s\n", __FUNCTION__, iap_id); */
1376         if (!iap_id)
1377                 return NULL;
1378                 
1379         ConIcIap* connection = tny_maemo_conic_device_get_iap (maemo_device, iap_id);
1380         if (!connection)
1381                 return NULL;
1382                 
1383         const gchar *connection_id = con_ic_iap_get_id (connection);
1384         /* printf ("DEBUG: %s: connection_id=%s\n", __FUNCTION__, connection_id); */
1385         if (!connection_id)
1386                 return NULL;
1387         
1388         /*  Get the connection-specific transport acccount, if any: */
1389         ModestAccountMgr *account_manager = modest_runtime_get_account_mgr ();
1390
1391         /* Check if this account has connection-specific SMTP enabled */
1392         if (!modest_account_mgr_get_use_connection_specific_smtp (account_manager, account_name)) {
1393                 return NULL;
1394         }
1395
1396         gchar* server_account_name = modest_account_mgr_get_connection_specific_smtp (account_manager, 
1397                 connection_id);
1398
1399         /* printf ("DEBUG: %s: server_account_name=%s\n", __FUNCTION__, server_account_name); */
1400         if (!server_account_name) {
1401                 return NULL; /* No connection-specific SMTP server was specified for this connection. */
1402         }
1403                 
1404         TnyAccount* account = modest_tny_account_store_get_tny_account_by (self, 
1405                                                                            MODEST_TNY_ACCOUNT_STORE_QUERY_ID, 
1406                                                                            server_account_name);
1407
1408         /* printf ("DEBUG: %s: account=%p\n", __FUNCTION__, account); */
1409         g_free (server_account_name);   
1410
1411         /* Unref the get()ed object, as required by the tny_maemo_conic_device_get_iap() documentation. */
1412         g_object_unref (connection);
1413         
1414         return account;
1415 #else
1416         return NULL; /* TODO: Implement this for GNOME, instead of just Maemo? */
1417 #endif /* MODEST_HAVE_CONIC */
1418 }
1419
1420                                                                  
1421 TnyAccount*
1422 modest_tny_account_store_get_transport_account_for_open_connection (ModestTnyAccountStore *self,
1423                                                                     const gchar *account_name)
1424 {
1425         g_return_val_if_fail (self, NULL);
1426         g_return_val_if_fail (account_name, NULL);
1427
1428         if (!account_name || !self)
1429                 return NULL;
1430         
1431         /*  Get the connection-specific transport acccount, if any: */
1432         /* Note: This gives us a reference: */
1433         TnyAccount *account =
1434                 modest_tny_account_store_get_smtp_specific_transport_account_for_open_connection (self, account_name);
1435                         
1436         /* If there is no connection-specific transport account (the common case), 
1437          * just get the regular transport account: */
1438         if (!account) {
1439                 /* The special local folders don't have transport accounts. */
1440                 if (strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0)
1441                         account = NULL;
1442                 else {
1443                         /* Note: This gives us a reference: */
1444                         account = modest_tny_account_store_get_server_account (self, account_name, 
1445                                                      TNY_ACCOUNT_TYPE_TRANSPORT);
1446                 }
1447         }
1448                         
1449         /* returns a reference. */     
1450         return account;
1451 }
1452
1453 TnyAccount*
1454 modest_tny_account_store_get_local_folders_account (ModestTnyAccountStore *self)
1455 {
1456         TnyAccount *account = NULL;
1457         ModestTnyAccountStorePrivate *priv;
1458         TnyIterator *iter;
1459         gboolean found;
1460
1461         g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1462         
1463         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1464
1465         found = FALSE;
1466         iter = tny_list_create_iterator (priv->store_accounts);
1467         while (!tny_iterator_is_done (iter) && !found) {
1468                 TnyAccount *tmp_account;
1469
1470                 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1471                 if (modest_tny_account_is_virtual_local_folders (tmp_account)) {
1472                         account = g_object_ref (tmp_account);
1473                         found = TRUE;
1474                 }
1475                 g_object_unref (tmp_account);
1476                 tny_iterator_next (iter);
1477         }
1478         g_object_unref (iter);
1479
1480         /* Returns a new reference to the account */
1481         return account;
1482 }
1483
1484 TnyAccount*
1485 modest_tny_account_store_get_mmc_folders_account (ModestTnyAccountStore *self)
1486 {
1487         g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1488         
1489         /* New reference */
1490         return modest_tny_account_store_get_tny_account_by (self, MODEST_TNY_ACCOUNT_STORE_QUERY_ID,
1491                                                             MODEST_MMC_ACCOUNT_ID);
1492
1493 }
1494
1495 /*********************************************************************************/
1496 static void
1497 add_existing_accounts (ModestTnyAccountStore *self)
1498 {
1499         GSList *account_names = NULL, *iter = NULL;
1500         ModestTnyAccountStorePrivate *priv = NULL;
1501         
1502         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1503
1504         /* These are account names, not server_account names */
1505         account_names = modest_account_mgr_account_names (priv->account_mgr, FALSE);
1506
1507         for (iter = account_names; iter != NULL; iter = g_slist_next (iter)) {
1508                 const gchar *account_name = (const gchar*) iter->data;
1509                 
1510                 /* Insert all enabled accounts without notifying */
1511                 if (modest_account_mgr_get_enabled (priv->account_mgr, account_name))
1512                         insert_account (self, account_name, FALSE);
1513         }
1514         modest_account_mgr_free_account_names (account_names);
1515 }
1516
1517 static TnyAccount*
1518 create_tny_account (ModestTnyAccountStore *self,
1519                     const gchar *name,
1520                     TnyAccountType type)
1521 {
1522         TnyAccount *account = NULL;
1523         ModestTnyAccountStorePrivate *priv = NULL;
1524         
1525         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1526
1527         account = modest_tny_account_new_from_account (priv->account_mgr,
1528                                                        name, type, 
1529                                                        priv->session,
1530                                                        get_password,
1531                                                        forget_password);
1532
1533         if (account) {
1534                 /* Forget any cached password for the account, so that
1535                    we use a new account if any */
1536                 modest_tny_account_store_forget_password_in_memory (self, 
1537                                                                     tny_account_get_id (account));
1538                 /* Set the account store */                             
1539                 g_object_set_data (G_OBJECT(account), "account_store", self);
1540         } else {
1541                 g_printerr ("modest: failed to create account for %s\n", name);
1542         }
1543
1544         return account;
1545 }
1546
1547
1548 static void
1549 add_outbox_from_transport_account_to_global_outbox (ModestTnyAccountStore *self,
1550                                                     const gchar *account_name,
1551                                                     TnyAccount *transport_account)
1552 {
1553         TnyList *folders = NULL;
1554         TnyIterator *iter_folders = NULL;
1555         TnyAccount *local_account = NULL, *account_outbox = NULL;
1556         TnyFolder *per_account_outbox = NULL;
1557         ModestTnyAccountStorePrivate *priv = NULL;
1558
1559         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1560
1561         /* Create per account local outbox */
1562         account_outbox = 
1563                 modest_tny_account_new_for_per_account_local_outbox_folder (priv->account_mgr, 
1564                                                                             account_name, 
1565                                                                             priv->session);
1566         tny_list_append (priv->store_accounts_outboxes, G_OBJECT (account_outbox));
1567
1568         /* Get the outbox folder */
1569         folders = tny_simple_list_new ();
1570         tny_folder_store_get_folders (TNY_FOLDER_STORE (account_outbox), folders, NULL, NULL);
1571         if (tny_list_get_length (folders) != 1) {
1572                 g_warning ("%s: > 1 outbox found (%d)?!", __FUNCTION__,
1573                            tny_list_get_length (folders));
1574         }
1575                         
1576         iter_folders = tny_list_create_iterator (folders);
1577         per_account_outbox = TNY_FOLDER (tny_iterator_get_current (iter_folders));
1578         g_object_unref (iter_folders);
1579         g_object_unref (folders);
1580         g_object_unref (account_outbox);
1581
1582         /* Add the outbox of the new per-account-local-outbox account
1583            to the global local merged OUTBOX of the local folders
1584            account */
1585         local_account = modest_tny_account_store_get_local_folders_account (self);
1586         modest_tny_local_folders_account_add_folder_to_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1587                                                                per_account_outbox);
1588         /* Add the pair to the hash table */
1589         g_hash_table_insert (priv->outbox_of_transport,
1590                              transport_account,
1591                              per_account_outbox);
1592         
1593         g_object_unref (local_account);
1594         g_object_unref (per_account_outbox);
1595 }
1596
1597 /*
1598  * This function will be used for both adding new accounts and for the
1599  * initialization. In the initialization we do not want to emit
1600  * signals so notify will be FALSE, in the case of account additions
1601  * we do want to notify the observers
1602  */
1603 static void
1604 insert_account (ModestTnyAccountStore *self,
1605                 const gchar *account,
1606                 gboolean notify)
1607 {
1608         ModestTnyAccountStorePrivate *priv = NULL;
1609         TnyAccount *store_account = NULL, *transport_account = NULL;
1610         
1611         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1612
1613         /* Get the server and the transport account */
1614         store_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_STORE);
1615         if (!store_account || !TNY_IS_ACCOUNT(store_account)) {
1616                 g_warning ("%s: failed to create store account", __FUNCTION__);
1617                 return;
1618         }
1619
1620         transport_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT);
1621         if (!transport_account || !TNY_IS_ACCOUNT(transport_account)) {
1622                 g_warning ("%s: failed to create transport account", __FUNCTION__);
1623                 g_object_unref (store_account);
1624                 return;
1625         }
1626
1627         /* Add accounts to the lists */
1628         tny_list_append (priv->store_accounts, G_OBJECT (store_account));
1629         tny_list_append (priv->transport_accounts, G_OBJECT (transport_account));
1630         
1631         /* Create a new pseudo-account with an outbox for this
1632            transport account and add it to the global outbox
1633            in the local account */
1634         add_outbox_from_transport_account_to_global_outbox (self, account, transport_account);
1635         
1636         /* Notify the observers. We do it after everything is
1637            created */
1638         if (notify) {
1639                 TnyAccount *local_account = NULL;
1640                 
1641                 /* Notify the observers about the new server & transport accounts */
1642                 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, store_account);   
1643                 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, transport_account);
1644
1645                 /* Notify that the local account changed */
1646                 local_account = modest_tny_account_store_get_local_folders_account (self);
1647                 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1648                 g_object_unref (local_account);
1649         }
1650
1651         /* Frees */
1652         g_object_unref (store_account);
1653         g_object_unref (transport_account);
1654 }
1655
1656 static void
1657 on_account_inserted (ModestAccountMgr *acc_mgr, 
1658                      const gchar *account,
1659                      gpointer user_data)
1660 {
1661         /* Insert the account and notify the observers */
1662         insert_account (MODEST_TNY_ACCOUNT_STORE (user_data), account, TRUE);
1663 }
1664
1665 /* This is the callback of the tny_camel_account_set_online called in
1666    on_account_removed to disconnect the account */
1667 static void
1668 on_account_disconnect_when_removing (TnyCamelAccount *account, 
1669                                      gboolean canceled, 
1670                                      GError *err, 
1671                                      gpointer user_data)
1672 {
1673         ModestTnyAccountStore *self;
1674         ModestTnyAccountStorePrivate *priv;
1675
1676         self = MODEST_TNY_ACCOUNT_STORE (user_data);
1677         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1678
1679         /* Remove it from the list of accounts */
1680         if (TNY_IS_STORE_ACCOUNT (account))
1681                 tny_list_remove (priv->store_accounts, (GObject *) account);
1682         else
1683                 tny_list_remove (priv->transport_accounts, (GObject *) account);
1684
1685         /* Notify the observers */
1686         g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 
1687                        0, account);
1688         
1689         /* Unref the extra reference added by get_server_account */
1690         g_object_unref (account);
1691
1692         /* Clear the cache if it's an store account */
1693         if (TNY_IS_STORE_ACCOUNT (account))
1694                 tny_store_account_delete_cache (TNY_STORE_ACCOUNT (account));
1695 }
1696
1697 static void
1698 on_account_removed (ModestAccountMgr *acc_mgr, 
1699                     const gchar *account,
1700                     gpointer user_data)
1701 {
1702         TnyAccount *store_account = NULL, *transport_account = NULL;
1703         ModestTnyAccountStore *self;
1704         ModestTnyAccountStorePrivate *priv;
1705         
1706         self = MODEST_TNY_ACCOUNT_STORE (user_data);
1707         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1708
1709         /* Get the server and the transport account */
1710         store_account = 
1711                 modest_tny_account_store_get_server_account (self, account, TNY_ACCOUNT_TYPE_STORE);
1712         transport_account = 
1713                 modest_tny_account_store_get_server_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT);
1714         
1715         /* If there was any problem creating the account, for example,
1716            with the configuration system this could not exist */
1717         if (store_account) {
1718                 /* Disconnect before deleting the cache, because the
1719                    disconnection will rewrite the cache to the
1720                    disk */
1721                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (store_account), FALSE,
1722                                               on_account_disconnect_when_removing, self);
1723         } else {
1724                 g_warning ("There is no store account for account %s\n", account);
1725         }
1726
1727         /* If there was any problem creating the account, for example,
1728            with the configuration system this could not exist */
1729         if (transport_account) {
1730                 TnyAccount *local_account = NULL;
1731                 TnyFolder *outbox = NULL;
1732                 ModestTnyAccountStorePrivate *priv = NULL;
1733         
1734                 /* Remove the OUTBOX of the account from the global outbox */
1735                 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1736                 outbox = g_hash_table_lookup (priv->outbox_of_transport, transport_account);
1737
1738                 if (TNY_IS_FOLDER (outbox)) {
1739                         local_account = modest_tny_account_store_get_local_folders_account (self);
1740                         modest_tny_local_folders_account_remove_folder_from_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1741                                                                                     outbox);
1742                         g_hash_table_remove (priv->outbox_of_transport, transport_account);
1743
1744                         /* Notify the change in the local account */
1745                         g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1746                         g_object_unref (local_account);
1747                 } else {
1748                         g_warning ("Removing a transport account that has no outbox");
1749                 }
1750
1751                 /* Disconnect and notify the observers. The callback will free the reference */
1752                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (transport_account), FALSE,
1753                                               on_account_disconnect_when_removing, self);
1754         } else {
1755                 g_warning ("There is no transport account for account %s\n", account);
1756         }
1757 }
1758
1759 TnyTransportAccount *
1760 modest_tny_account_store_new_connection_specific_transport_account (ModestTnyAccountStore *self,
1761                                                                     const gchar *name)
1762 {
1763         ModestTnyAccountStorePrivate *priv = NULL;
1764         TnyAccount * tny_account = NULL;
1765
1766         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1767
1768         /* Add the account: */
1769         tny_account = 
1770                 modest_tny_account_new_from_server_account_name (priv->account_mgr, 
1771                                                                  priv->session, 
1772                                                                  name,
1773                                                                  get_password,
1774                                                                  forget_password);
1775         if (tny_account) {
1776                 g_object_set_data (G_OBJECT(tny_account), 
1777                                    "account_store", 
1778                                    (gpointer)self);
1779                 
1780                 tny_list_append (priv->transport_accounts, G_OBJECT (tny_account));
1781                 add_outbox_from_transport_account_to_global_outbox (self, 
1782                                                                     name, 
1783                                                                     tny_account);
1784                 
1785         } else
1786                 g_printerr ("modest: failed to create smtp-specific account for %s\n",
1787                             name);
1788
1789         return TNY_TRANSPORT_ACCOUNT (tny_account);
1790 }
1791
1792
1793 static void
1794 add_connection_specific_transport_accounts (ModestTnyAccountStore *self)
1795 {
1796         ModestTnyAccountStorePrivate *priv = NULL;
1797         GSList *list_specifics = NULL, *iter = NULL;
1798
1799         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1800
1801         ModestConf *conf = modest_runtime_get_conf ();
1802
1803         GError *err = NULL;
1804         list_specifics = modest_conf_get_list (conf,
1805                                                MODEST_CONF_CONNECTION_SPECIFIC_SMTP_LIST,
1806                                                MODEST_CONF_VALUE_STRING, &err);
1807         if (err) {
1808                 g_printerr ("modest: %s: error getting list: %s\n.", __FUNCTION__, err->message);
1809                 g_error_free (err);
1810                 err = NULL;
1811         }
1812                                 
1813         /* Look at each connection-specific transport account for the 
1814          * modest account: */
1815         iter = list_specifics;
1816         while (iter) {
1817                 /* The list alternates between the connection name and the transport name: */
1818                 iter = g_slist_next (iter);
1819                 if (iter) {
1820                         const gchar* transport_account_name = (const gchar*) (iter->data);
1821                         TnyTransportAccount * account = NULL;
1822                         account = modest_tny_account_store_new_connection_specific_transport_account (
1823                                 self, transport_account_name);
1824                         if (account)
1825                                 g_object_unref (account);
1826                 }                               
1827                 iter = g_slist_next (iter);
1828         }
1829 }
1830
1831 TnyMsg *
1832 modest_tny_account_store_find_msg_in_outboxes (ModestTnyAccountStore *self, 
1833                                                const gchar *uri,
1834                                                TnyAccount **ac_out)
1835 {
1836         TnyIterator *acc_iter;
1837         ModestTnyAccountStorePrivate *priv;
1838         TnyMsg *msg = NULL;
1839         TnyAccount *msg_account = NULL;
1840
1841         g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1842         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1843
1844         acc_iter = tny_list_create_iterator (priv->store_accounts_outboxes);
1845         while (!msg && !tny_iterator_is_done (acc_iter)) {
1846                 TnyList *folders = tny_simple_list_new ();
1847                 TnyAccount *account = TNY_ACCOUNT (tny_iterator_get_current (acc_iter));
1848                 TnyIterator *folders_iter = NULL;
1849
1850                 tny_folder_store_get_folders (TNY_FOLDER_STORE (account), folders, NULL, NULL);
1851                 folders_iter = tny_list_create_iterator (folders);
1852
1853                 while (msg == NULL && !tny_iterator_is_done (folders_iter)) {
1854                         TnyFolder *folder = TNY_FOLDER (tny_iterator_get_current (folders_iter));
1855                         msg = tny_folder_find_msg (folder, uri, NULL);
1856
1857                         if (msg)
1858                                 msg_account = g_object_ref (account);
1859
1860                         g_object_unref (folder);
1861                         tny_iterator_next (folders_iter);
1862                 }
1863                 g_object_unref (folders_iter);
1864
1865                 g_object_unref (folders);
1866                 g_object_unref (account);
1867                 tny_iterator_next (acc_iter);
1868         }
1869
1870         g_object_unref (acc_iter);
1871
1872         if (ac_out != NULL)
1873                 *ac_out = msg_account;
1874
1875         return msg;
1876 }
1877
1878 TnyTransportAccount *
1879 modest_tny_account_store_get_transport_account_from_outbox_header(ModestTnyAccountStore *self, TnyHeader *header)
1880 {
1881         TnyIterator *acc_iter;
1882         ModestTnyAccountStorePrivate *priv;
1883         TnyTransportAccount *header_acc = NULL;
1884         const gchar *msg_id;
1885
1886         g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1887         g_return_val_if_fail (TNY_IS_HEADER (header), NULL);
1888         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1889
1890         msg_id = modest_tny_send_queue_get_msg_id (header);
1891         acc_iter = tny_list_create_iterator (priv->transport_accounts);
1892         while (!header_acc && !tny_iterator_is_done (acc_iter)) {
1893                 TnyTransportAccount *account = TNY_TRANSPORT_ACCOUNT (tny_iterator_get_current (acc_iter));
1894                 ModestTnySendQueue *send_queue;
1895                 ModestTnySendQueueStatus status;
1896                 send_queue = modest_runtime_get_send_queue(TNY_TRANSPORT_ACCOUNT(account));
1897                 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
1898                 if (status != MODEST_TNY_SEND_QUEUE_UNKNOWN) {
1899                         header_acc = g_object_ref(account);
1900                 }
1901                 g_object_unref (account);
1902                 tny_iterator_next (acc_iter);
1903         }
1904         g_object_unref(acc_iter);
1905
1906         /* New reference */
1907         return header_acc;
1908 }