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