Fixes NB#131351, crash when exiting modest if there are new connection attempts
[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 #include "modest-text-utils.h"
44 #include <modest-runtime.h>
45 #include <modest-marshal.h>
46 #include <modest-protocol-registry.h>
47 #include <modest-local-folder-info.h>
48 #include "modest-account-protocol.h"
49 #include <modest-tny-account.h>
50 #include <modest-tny-local-folders-account.h>
51 #include <modest-account-mgr.h>
52 #include <modest-account-mgr-helpers.h>
53 #include <widgets/modest-window-mgr.h>
54 #include <modest-signal-mgr.h>
55 #include <modest-debug.h>
56 #include "modest-utils.h"
57 #include <modest-defs.h>
58 #include "modest-tny-account-store.h"
59 #include "modest-tny-platform-factory.h"
60 #include <tny-gtk-lockable.h>
61 #include <camel/camel.h>
62 #include <modest-platform.h>
63 #include "modest-ui-actions.h"
64 #include <widgets/modest-account-settings-dialog.h>
65
66 #ifdef MODEST_PLATFORM_MAEMO
67 #include <tny-maemo-conic-device.h>
68 #include <maemo/modest-maemo-utils.h>
69 #endif
70
71 #include <libgnomevfs/gnome-vfs-volume-monitor.h>
72
73 /* 'private'/'protected' functions */
74 static void    modest_tny_account_store_class_init   (ModestTnyAccountStoreClass *klass);
75 static void    modest_tny_account_store_finalize     (GObject *obj);
76 static void    modest_tny_account_store_instance_init (ModestTnyAccountStore *obj);
77 static void    modest_tny_account_store_init          (gpointer g, gpointer iface_data);
78 static void    modest_tny_account_store_base_init     (gpointer g_class);
79
80 static void    on_account_inserted         (ModestAccountMgr *acc_mgr,
81                                             const gchar *account,
82                                             gpointer user_data);
83
84 static void   add_existing_accounts       (ModestTnyAccountStore *self);
85
86 static void    insert_account              (ModestTnyAccountStore *self,
87                                             const gchar *account,
88                                             gboolean is_new);
89
90 static void    on_account_removed          (ModestAccountMgr *acc_mgr, 
91                                             const gchar *account,
92                                             gpointer user_data);
93
94 static gchar*  get_password                (TnyAccount *account, 
95                                             const gchar * prompt_not_used, 
96                                             gboolean *cancel);
97
98 static void    forget_password             (TnyAccount *account);
99
100 static void    on_vfs_volume_mounted       (GnomeVFSVolumeMonitor *volume_monitor, 
101                                             GnomeVFSVolume *volume, 
102                                             gpointer user_data);
103
104 static void    on_vfs_volume_unmounted     (GnomeVFSVolumeMonitor *volume_monitor, 
105                                             GnomeVFSVolume *volume, 
106                                             gpointer user_data);
107
108 static void    forget_password_in_memory (ModestTnyAccountStore *self, 
109                                           const gchar *server_account_name);
110
111 static void    add_connection_specific_transport_accounts         (ModestTnyAccountStore *self);
112
113 static void    remove_connection_specific_transport_accounts      (ModestTnyAccountStore *self);
114
115 static inline gboolean only_local_accounts        (ModestTnyAccountStore *self);
116
117 /* list my signals */
118 enum {
119         ACCOUNT_CHANGED_SIGNAL,
120         ACCOUNT_INSERTED_SIGNAL,
121         ACCOUNT_REMOVED_SIGNAL,
122
123         PASSWORD_REQUESTED_SIGNAL,
124         LAST_SIGNAL
125 };
126
127 typedef struct _ModestTnyAccountStorePrivate ModestTnyAccountStorePrivate;
128 struct _ModestTnyAccountStorePrivate {
129         gchar              *cache_dir;  
130         GHashTable         *password_hash;
131         ModestAccountMgr   *account_mgr;
132         TnySessionCamel    *session;
133         TnyDevice          *device;
134
135         GSList *sighandlers;
136         
137         /* We cache the lists of accounts here */
138         TnyList             *store_accounts;
139         TnyList             *transport_accounts;
140         TnyList             *store_accounts_outboxes;
141         
142         /* Matches transport accounts and outbox folder */
143         GHashTable          *outbox_of_transport;
144
145         /* is sending mail blocked? */
146         gboolean send_mail_blocked;
147 };
148
149 #define MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
150                                                       MODEST_TYPE_TNY_ACCOUNT_STORE, \
151                                                       ModestTnyAccountStorePrivate))
152
153 #define RETRY_ATTEMPTS 3
154
155 typedef struct _PwdAttempt {
156         gint count;
157         gchar *pwd;
158 } PwdAttempt;
159
160 /* globals */
161 static GObjectClass *parent_class = NULL;
162
163 static guint signals[LAST_SIGNAL] = {0};
164
165 GType
166 modest_tny_account_store_get_type (void)
167 {
168         static GType my_type = 0;
169
170         if (!my_type) {
171                 static const GTypeInfo my_info = {
172                         sizeof(ModestTnyAccountStoreClass),
173                         modest_tny_account_store_base_init,     /* base init */
174                         NULL,           /* base finalize */
175                         (GClassInitFunc) modest_tny_account_store_class_init,
176                         NULL,           /* class finalize */
177                         NULL,           /* class data */
178                         sizeof(ModestTnyAccountStore),
179                         0,              /* n_preallocs */
180                         (GInstanceInitFunc) modest_tny_account_store_instance_init,
181                         NULL
182                 };
183
184                 static const GInterfaceInfo iface_info = {
185                         (GInterfaceInitFunc) modest_tny_account_store_init,
186                         NULL,         /* interface_finalize */
187                         NULL          /* interface_data */
188                 };
189                 /* hack hack */
190                 my_type = g_type_register_static (G_TYPE_OBJECT,
191                                                   "ModestTnyAccountStore",
192                                                   &my_info, 0);
193                 g_type_add_interface_static (my_type, TNY_TYPE_ACCOUNT_STORE,
194                                              &iface_info);
195         }
196         return my_type;
197 }
198
199
200 static void
201 modest_tny_account_store_base_init (gpointer g_class)
202 {
203         static gboolean tny_account_store_initialized = FALSE;
204
205         if (!tny_account_store_initialized) {
206
207                 signals[ACCOUNT_CHANGED_SIGNAL] =
208                         g_signal_new ("account_changed",
209                                       MODEST_TYPE_TNY_ACCOUNT_STORE,
210                                       G_SIGNAL_RUN_FIRST,
211                                       G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_changed),
212                                       NULL, NULL,
213                                       g_cclosure_marshal_VOID__OBJECT,
214                                       G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
215
216                 signals[ACCOUNT_INSERTED_SIGNAL] =
217                         g_signal_new ("account_inserted",
218                                       MODEST_TYPE_TNY_ACCOUNT_STORE,
219                                       G_SIGNAL_RUN_FIRST,
220                                       G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_inserted),
221                                       NULL, NULL,
222                                       g_cclosure_marshal_VOID__OBJECT,
223                                       G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
224                 
225                 signals[ACCOUNT_REMOVED_SIGNAL] =
226                         g_signal_new ("account_removed",
227                                       MODEST_TYPE_TNY_ACCOUNT_STORE,
228                                       G_SIGNAL_RUN_FIRST,
229                                       G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_removed),
230                                       NULL, NULL,
231                                       g_cclosure_marshal_VOID__OBJECT,
232                                       G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
233
234                 signals[PASSWORD_REQUESTED_SIGNAL] =
235                         g_signal_new ("password_requested",
236                                       MODEST_TYPE_TNY_ACCOUNT_STORE,
237                                       G_SIGNAL_RUN_FIRST,
238                                       G_STRUCT_OFFSET(ModestTnyAccountStoreClass, password_requested),
239                                       NULL, NULL,
240                                       modest_marshal_VOID__STRING_POINTER_POINTER_POINTER_POINTER,
241                                       G_TYPE_NONE, 5, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER,
242                                       G_TYPE_POINTER);          
243
244                 tny_account_store_initialized = TRUE;
245         }
246 }
247
248
249 static void
250 modest_tny_account_store_class_init (ModestTnyAccountStoreClass *klass)
251 {
252         GObjectClass *gobject_class;
253         gobject_class = (GObjectClass*) klass;
254
255         parent_class            = g_type_class_peek_parent (klass);
256         gobject_class->finalize = modest_tny_account_store_finalize;
257
258         g_type_class_add_private (gobject_class,
259                                   sizeof(ModestTnyAccountStorePrivate));
260 }
261
262 static void
263 free_pwd_attempt (gpointer data)
264 {
265         PwdAttempt *attempt = (PwdAttempt *) data;
266
267         /* Note that we sometimes insert NULL */
268         if (!attempt)
269                 return;
270
271         if (attempt->pwd)
272                 g_free (attempt->pwd);
273         g_slice_free (PwdAttempt, attempt);
274 }
275
276 static void
277 modest_tny_account_store_instance_init (ModestTnyAccountStore *obj)
278 {
279         ModestTnyAccountStorePrivate *priv;
280
281         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
282
283         priv->cache_dir              = NULL;
284         priv->account_mgr            = NULL;
285         priv->session                = NULL;
286         priv->device                 = NULL;
287         priv->sighandlers            = NULL;
288         priv->send_mail_blocked      = FALSE;
289
290         priv->outbox_of_transport = g_hash_table_new_full (g_direct_hash,
291                                                            g_direct_equal,
292                                                            NULL,
293                                                            NULL);
294
295         /* An in-memory store of passwords, 
296          * for passwords that are not remembered in the configuration,
297          * so they need to be asked for from the user once in each session:
298          */
299         priv->password_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
300                                                      g_free, free_pwd_attempt);
301 }
302
303 /* disconnect the list of TnyAccounts */
304 static void
305 account_verify_last_ref (TnyAccount *account, const gchar *str)
306 {
307         gchar *txt;
308
309         g_return_if_fail (account && TNY_IS_ACCOUNT(account));
310
311         txt = g_strdup_printf ("%s: %s", str ? str : "?", tny_account_get_name(account));
312         MODEST_DEBUG_VERIFY_OBJECT_LAST_REF(G_OBJECT(account),txt);
313         g_free (txt);
314 }
315
316 static void
317 foreach_account_append_to_list (gpointer data, 
318                                 gpointer user_data)
319 {
320         TnyList *list;
321         
322         list = TNY_LIST (user_data);
323         tny_list_append (list, G_OBJECT (data));
324 }
325
326 /********************************************************************/
327 /*           Control the state of the MMC local account             */
328 /********************************************************************/
329
330 /** Only call this if the memory card is really mounted.
331  */ 
332 static void
333 add_mmc_account(ModestTnyAccountStore *self, gboolean emit_insert_signal)
334 {
335         ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
336         g_return_if_fail (priv->session);
337         
338         TnyAccount *mmc_account = modest_tny_account_new_for_local_folders (priv->account_mgr, 
339                                                                             priv->session, 
340                                                                             g_getenv (MODEST_MMC1_VOLUMEPATH_ENV));
341
342         /* Add to the list of store accounts */
343         tny_list_append (priv->store_accounts, G_OBJECT (mmc_account));
344
345         if (emit_insert_signal) {
346                 g_signal_emit (G_OBJECT (self), 
347                                signals [ACCOUNT_INSERTED_SIGNAL],
348                                0, mmc_account);
349         }
350
351         /* Free */
352         g_object_unref (mmc_account);
353 }
354
355 static void
356 on_vfs_volume_mounted(GnomeVFSVolumeMonitor *volume_monitor, 
357                       GnomeVFSVolume *volume, 
358                       gpointer user_data)
359 {
360         ModestTnyAccountStore *self;
361         ModestTnyAccountStorePrivate *priv;
362         gchar *volume_path_uri;
363  
364         gchar *uri = NULL;
365
366         self = MODEST_TNY_ACCOUNT_STORE(user_data);
367         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
368         
369         /* Check whether this was the external MMC1 card: */
370         uri = gnome_vfs_volume_get_activation_uri (volume);
371
372         volume_path_uri = g_strconcat (MODEST_MMC1_VOLUMEPATH_URI_PREFIX,
373                                        g_getenv (MODEST_MMC1_VOLUMEPATH_ENV),
374                                        NULL);
375         if (uri && (!strcmp (uri, volume_path_uri))) {
376                 add_mmc_account (self, TRUE /* emit the insert signal. */);
377         }
378
379         g_free (volume_path_uri);       
380         g_free (uri);
381 }
382
383 static void
384 on_vfs_volume_unmounted(GnomeVFSVolumeMonitor *volume_monitor, 
385                         GnomeVFSVolume *volume, 
386                         gpointer user_data)
387 {
388         ModestTnyAccountStore *self;
389         ModestTnyAccountStorePrivate *priv;
390         gchar *uri = NULL;
391         gchar *volume_path_uri;
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         volume_path_uri = g_strconcat (MODEST_MMC1_VOLUMEPATH_URI_PREFIX,
399                                        g_getenv (MODEST_MMC1_VOLUMEPATH_ENV),
400                                        NULL);
401         if (uri && (strcmp (uri, volume_path_uri) == 0)) {
402                 TnyAccount *mmc_account = NULL;
403                 gboolean found = FALSE;
404                 TnyIterator *iter = NULL;
405
406                 iter = tny_list_create_iterator (priv->store_accounts);
407                 while (!tny_iterator_is_done (iter) && !found) {
408                         TnyAccount *account;
409
410                         account = TNY_ACCOUNT (tny_iterator_get_current (iter));
411                         if (modest_tny_account_is_memory_card_account (account)) {
412                                 found = TRUE;
413                                 mmc_account = g_object_ref (account);
414                         }
415                         g_object_unref (account);
416                         tny_iterator_next (iter);
417                 }
418                 g_object_unref (iter);
419
420                 if (found) {
421                         /* Remove from the list */
422                         tny_list_remove (priv->store_accounts, G_OBJECT (mmc_account));
423                         
424                         /* Notify observers */
425                         g_signal_emit (G_OBJECT (self),
426                                        signals [ACCOUNT_REMOVED_SIGNAL],
427                                        0, mmc_account);
428
429                         g_object_unref (mmc_account);
430                 } else {
431                         g_debug ("%s: there was no store account for the unmounted MMC",
432                                  __FUNCTION__);
433                 }
434         }
435         g_free (volume_path_uri);
436         g_free (uri);
437 }
438
439 /**
440  * forget_password_in_memory
441  * @self: a TnyAccountStore instance
442  * @account: A server account.
443  * 
444  * Forget any password stored in memory for this account.
445  * For instance, this should be called when the user has changed the password in the account settings.
446  */
447 static void
448 forget_password_in_memory (ModestTnyAccountStore *self, 
449                            const gchar * server_account_name)
450 {
451         ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
452
453         if (server_account_name && priv->password_hash) {
454                 g_hash_table_remove (priv->password_hash, server_account_name);
455         }
456 }
457
458 static void
459 on_account_changed (ModestAccountMgr *acc_mgr, 
460                     const gchar *account_name, 
461                     TnyAccountType account_type,
462                     gpointer user_data)
463 {
464         ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(user_data);
465         ModestTnyAccountStorePrivate *priv;
466         TnyList* account_list;
467         gboolean found = FALSE;
468         TnyIterator *iter = NULL;
469
470         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
471         account_list = (account_type == TNY_ACCOUNT_TYPE_STORE ? 
472                         priv->store_accounts : 
473                         priv->transport_accounts);
474
475         iter = tny_list_create_iterator (account_list);
476         while (!tny_iterator_is_done (iter) && !found) {
477                 TnyAccount *tny_account;
478                 tny_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
479                 if (tny_account) {
480                         if (!strcmp (tny_account_get_id (tny_account), account_name)) {
481                                 found = TRUE;
482                                 modest_tny_account_update_from_account (tny_account, get_password, forget_password);
483                                 g_signal_emit (G_OBJECT(self), signals[ACCOUNT_CHANGED_SIGNAL], 0, tny_account);
484                         }
485                         g_object_unref (tny_account);
486                 }
487                 tny_iterator_next (iter);
488         }
489         g_object_unref (iter);
490 }
491
492 static void 
493 show_wrong_password_dialog (TnyAccount *account, 
494                             gboolean show_banner)
495
496         if (g_object_get_data (G_OBJECT (account), "connection_specific") != NULL) {
497                 modest_ui_actions_on_smtp_servers (NULL, NULL);
498         } else {
499                 ModestAccountProtocol *proto;
500                 ModestProtocolType proto_type;
501                 const gchar *modest_account_name;
502                 modest_account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
503
504                 /* Get proto */
505                 proto_type = modest_account_mgr_get_store_protocol (modest_runtime_get_account_mgr (), 
506                                                                     modest_account_name);
507                 proto = (ModestAccountProtocol *)
508                         modest_protocol_registry_get_protocol_by_type (modest_runtime_get_protocol_registry (), 
509                                                                        proto_type);
510
511                 /* Create and show the dialog */
512                 if (proto && MODEST_IS_ACCOUNT_PROTOCOL (proto)) {
513                         ModestAccountSettingsDialog *dialog =
514                                 modest_account_protocol_get_account_settings_dialog (proto, modest_account_name);
515                         modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), GTK_WINDOW (dialog), NULL);
516                         gtk_widget_show (GTK_WIDGET (dialog));
517                 }
518         }
519         /* Show an explanatory temporary banner: */
520         if (show_banner)
521                 modest_platform_information_banner (NULL, NULL, _("mcen_ib_username_pw_incorrect"));
522 }
523
524 /* This callback will be called by Tinymail when it needs the password
525  * from the user or the account settings.
526  * It can also call forget_password() before calling this,
527  * so that we clear wrong passwords out of our account settings.
528  * Note that TnyAccount here will be the server account. */
529 static gchar*
530 get_password (TnyAccount *account, const gchar * prompt_not_used, gboolean *cancel)
531 {
532         ModestTnyAccountStore *self = NULL;
533         ModestTnyAccountStorePrivate *priv;
534         gchar *username = NULL;
535         gchar *pwd = NULL;
536         gboolean already_asked = FALSE;
537         const gchar *server_account_name;
538         gchar *url_string;
539         PwdAttempt *attempt = NULL;
540         gpointer attempt_ptr = NULL;
541
542         g_return_val_if_fail (account, NULL);
543
544         MODEST_DEBUG_BLOCK(
545                 g_debug ("%s: prompt (not shown) = %s\n", __FUNCTION__, prompt_not_used);
546         );
547
548         /* Get a reference to myself */
549         self = MODEST_TNY_ACCOUNT_STORE (g_object_get_data (G_OBJECT(account), "account_store"));
550         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
551
552         /* Ensure that we still have this account. It could happen
553            that a set_online was requested *before* removing an
554            account, and due to tinymail emits the get_password
555            function using a g_idle the account could be actually
556            removed *before* this function was really called */
557         url_string = tny_account_get_url_string (account);
558         if (url_string) {
559                 TnyAccount *tmp_account;
560
561                 tmp_account = tny_account_store_find_account (TNY_ACCOUNT_STORE (self), 
562                                                               url_string);
563                 g_free (url_string);
564
565                 if (!tmp_account) {
566                         *cancel = TRUE;
567                         return NULL;
568                 }
569                 g_object_unref (tmp_account);
570         }
571
572         server_account_name = tny_account_get_id (account);
573         if (!server_account_name || !self) {
574                 g_warning ("%s: could not retrieve account_store for account %s",
575                            __FUNCTION__, server_account_name ? server_account_name : "<NULL>");
576                 if (cancel)
577                         *cancel = TRUE;
578
579                 return NULL;
580         }
581
582         /* We need to do this to avoid "dereferencing type-punned pointer will break strict-aliasing rules" */
583         attempt_ptr = (gpointer) &attempt;
584
585         /* This hash map stores passwords, including passwords that are not stored in gconf. */
586         /* Is it in the hash? if it's already there, it must be wrong... */
587         already_asked = priv->password_hash && g_hash_table_lookup_extended (priv->password_hash,
588                                                                              server_account_name,
589                                                                              NULL,
590                                                                              &attempt_ptr);
591
592         /* If the password is not already there, try ModestConf */
593         if (!already_asked) {
594                 pwd  = modest_account_mgr_get_server_account_password (priv->account_mgr,
595                                                                        server_account_name);
596                 PwdAttempt *new_attempt = g_slice_new0 (PwdAttempt);
597                 new_attempt->count = RETRY_ATTEMPTS;
598                 new_attempt->pwd = g_strdup (pwd);
599                 g_hash_table_insert (priv->password_hash, g_strdup (server_account_name), new_attempt);
600         } else if (attempt) {
601                 pwd = g_strdup (attempt->pwd);
602         }
603
604         /* This is horrible but we need it until we don't get a proper
605            fix into tinymail. Thing is that tinymail incorrectly asks
606            for password when the connection to the server failed due a
607            timeout (slow network connection, firewalls...). In those
608            cases it makes no sense to ask the user. It's better just
609            to cancel cleanly */
610         if (g_strstr_len (prompt_not_used, -1, "Connection timed out")) {
611                 g_debug ("%s, Incorrect get_password with connection issue %s",
612                          __FUNCTION__, (attempt && (attempt->count > 0)) ? "retrying" : "canceling");
613                 if (attempt) {
614                         if (attempt->count == 0) {
615                                 modest_tny_account_store_reset_attempt_count (self, account);
616                                 if (cancel)
617                                         *cancel = TRUE;
618                                 return NULL;
619                         } else {
620                                 return pwd;
621                         }
622                 } else {
623                         if (cancel)
624                                 *cancel = TRUE;
625                         return NULL;
626                 }
627         }
628
629         /* If it was already asked, it must have been wrong, so ask again */
630         if (already_asked || !pwd || strlen(pwd) == 0) {
631                 gboolean settings_have_password;
632                 ModestProtocolType protocol_type;
633
634                 /* As per the UI spec, if no password was set in the account settings,
635                  * ask for it now. But if the password is wrong in the account settings,
636                  * then show a banner and the account settings dialog so it can be corrected:
637                  */
638                 settings_have_password =
639                         modest_account_mgr_get_server_account_has_password (priv->account_mgr, server_account_name);
640
641                 protocol_type = modest_tny_account_get_protocol_type (account);
642
643                 /* Show an error and after that ask for a password */
644                 if (modest_protocol_registry_protocol_type_has_tag(modest_runtime_get_protocol_registry (), 
645                                                                    protocol_type, MODEST_PROTOCOL_REGISTRY_TRANSPORT_PROTOCOLS)) {
646                         gchar *username = NULL, *msg = NULL;
647                         username = modest_account_mgr_get_server_account_username (priv->account_mgr,
648                                                                                    server_account_name);
649                         if (!username || strlen(username) == 0) {
650                                 msg = g_strdup_printf (_("emev_ni_ui_smtp_userid_invalid"), 
651                                                        tny_account_get_name (account),
652                                                        tny_account_get_hostname (account));
653                         } else {
654                                 gchar *password;
655                                 password  = modest_account_mgr_get_server_account_password (priv->account_mgr,
656                                                                                             server_account_name);
657
658                                 if (!password || strlen(password) == 0) {
659                                         msg = g_strdup_printf (_("emev_ni_ui_smtp_passwd_invalid"), 
660                                                                tny_account_get_name (account),
661                                                                tny_account_get_hostname (account));
662                                 } else {
663                                         msg = g_strdup_printf (_("emev_ni_ui_smtp_authentication_fail_error"), 
664                                                                tny_account_get_hostname (account));
665                                 }
666                                 if (password)
667                                         g_free (password);
668                         }
669                         if (msg) {
670                                 modest_platform_run_information_dialog (NULL, msg, TRUE);
671                                 g_free (msg);
672                         }
673                         if (username)
674                                 g_free (username);
675                 } else {
676                         if (already_asked) {
677                                 const gchar *msg;
678                                 gboolean username_known = 
679                                         modest_account_mgr_get_server_account_username_has_succeeded(priv->account_mgr, 
680                                                                                              server_account_name);
681                                 /* If the login has ever succeeded then show a specific message */
682                                 if (username_known)
683                                         msg = _CS ("ecdg_ib_set_password_incorrect");
684                                 else
685                                         msg = _("mcen_ib_username_pw_incorrect");
686                                 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()))
687                                         modest_platform_information_banner (NULL, NULL, msg);
688                         }
689                 }
690
691                 if (settings_have_password) {
692                         /* The password must be wrong, so show the account settings dialog so it can be corrected: */
693                         show_wrong_password_dialog (account, TRUE);
694
695                         if (cancel)
696                                 *cancel = TRUE;
697
698                         return NULL;
699                 }
700
701                 /* we don't have it yet. Get the password from the user */
702                 pwd = NULL;
703                 const gchar* account_id = tny_account_get_id (account);
704                 gboolean remember = FALSE;
705                 g_signal_emit (G_OBJECT (self), signals[PASSWORD_REQUESTED_SIGNAL], 0,
706                                account_id, /* server_account_name */
707                                &username, &pwd, cancel, &remember);
708
709                 if (*cancel) {
710                         g_hash_table_remove (priv->password_hash, server_account_name);
711                         g_free (pwd);
712                         pwd = NULL;
713                 }
714
715                 g_free (username);
716                 username = NULL;
717         } else {
718                 if (cancel)
719                         *cancel = FALSE;
720         }
721         return pwd;
722 }
723
724 void 
725 modest_tny_account_store_forget_already_asked (ModestTnyAccountStore *self, TnyAccount *account)
726 {
727         g_return_if_fail (account);
728           
729         ModestTnyAccountStorePrivate *priv;
730         gchar *pwd = NULL;
731         gpointer pwd_ptr = NULL;
732         gboolean already_asked = FALSE;
733                 
734         const gchar *server_account_name = tny_account_get_id (account);
735
736         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
737         
738         /* This hash map stores passwords, including passwords that are not stored in gconf. */
739         pwd_ptr = (gpointer)&pwd; /* pwd_ptr so the compiler does not complained about
740                                    * type-punned ptrs...*/
741         already_asked = priv->password_hash && 
742                                 g_hash_table_lookup_extended (priv->password_hash,
743                                                       server_account_name,
744                                                       NULL,
745                                                       (gpointer*)&pwd_ptr);
746
747         if (already_asked) {
748                 g_hash_table_remove (priv->password_hash, server_account_name);
749                 g_free (pwd);
750                 pwd = NULL;
751         }
752
753         return;
754 }
755
756 /* tinymail calls this if the connection failed due to an incorrect password.
757  * And it seems to call this for any general connection failure. */
758 static void
759 forget_password (TnyAccount *account)
760 {
761         ModestTnyAccountStore *self;
762         ModestTnyAccountStorePrivate *priv;
763         const TnyAccountStore *account_store;
764         const gchar *key;
765         PwdAttempt *attempt;
766
767         account_store = TNY_ACCOUNT_STORE(g_object_get_data (G_OBJECT(account),
768                                                              "account_store"));
769         self = MODEST_TNY_ACCOUNT_STORE (account_store);
770         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
771         key  = tny_account_get_id (account);
772
773         /* Do not remove the key, this will allow us to detect that we
774            have already asked for it at least once */
775         attempt = g_hash_table_lookup (priv->password_hash, key);
776         if (attempt) {
777                 attempt->count--;
778                 g_debug ("%s, remaining %d for account %s", __FUNCTION__, attempt->count, key);
779                 if (attempt->count == 0) {
780                         if (attempt->pwd)
781                                 memset (attempt->pwd, 0, strlen (attempt->pwd));
782                         g_hash_table_insert (priv->password_hash, g_strdup (key), NULL);
783                 }
784         }
785 }
786
787 static void
788 modest_tny_account_store_finalize (GObject *obj)
789 {
790         ModestTnyAccountStore *self        = MODEST_TNY_ACCOUNT_STORE(obj);
791         ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
792
793         g_free (priv->cache_dir);
794         priv->cache_dir = NULL;
795
796         if (priv->password_hash) {
797                 g_hash_table_destroy (priv->password_hash);
798                 priv->password_hash = NULL;
799         }
800
801         if (priv->outbox_of_transport) {
802                 g_hash_table_destroy (priv->outbox_of_transport);
803                 priv->outbox_of_transport = NULL;
804         }
805
806         modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
807         priv->sighandlers = NULL;       
808
809         if (priv->account_mgr) {
810                 g_object_unref (G_OBJECT(priv->account_mgr));
811                 priv->account_mgr = NULL;
812         }
813
814         if (priv->device) {
815                 g_object_unref (G_OBJECT(priv->device));
816                 priv->device = NULL;
817         }
818
819         /* Destroy all accounts. Disconnect all accounts before they are destroyed */
820         if (priv->store_accounts) {
821                 tny_list_foreach (priv->store_accounts, (GFunc)account_verify_last_ref, "store");
822                 g_object_unref (priv->store_accounts);
823                 priv->store_accounts = NULL;
824         }
825         
826         if (priv->transport_accounts) {
827                 tny_list_foreach (priv->transport_accounts, (GFunc)account_verify_last_ref, "transport");
828                 g_object_unref (priv->transport_accounts);
829                 priv->transport_accounts = NULL;
830         }
831
832         if (priv->store_accounts_outboxes) {
833                 g_object_unref (priv->store_accounts_outboxes);
834                 priv->store_accounts_outboxes = NULL;
835         }
836                 
837         if (priv->session) {
838                 camel_object_unref (CAMEL_OBJECT(priv->session));
839                 priv->session = NULL;
840         }
841
842         G_OBJECT_CLASS(parent_class)->finalize (obj);
843 }
844
845 static gboolean 
846 volume_path_is_mounted (const gchar* path)
847 {
848         g_return_val_if_fail (path, FALSE);
849
850         gboolean result = FALSE;
851         gchar * path_as_uri = g_filename_to_uri (path, NULL, NULL);
852         g_return_val_if_fail (path_as_uri, FALSE);
853
854         /* Get the monitor singleton: */
855         GnomeVFSVolumeMonitor *monitor = gnome_vfs_get_volume_monitor();
856
857         /* This seems like a simpler way to do this, but it returns a   
858          * GnomeVFSVolume even if the drive is not mounted: */
859         /*
860         GnomeVFSVolume *volume = gnome_vfs_volume_monitor_get_volume_for_path (monitor, 
861                                  g_getenv (MODEST_MMC1_VOLUMEPATH_ENV));
862         if (volume) {
863                 gnome_vfs_volume_unref(volume);
864         }
865         */
866
867         /* Get the mounted volumes from the monitor: */
868         GList *list = gnome_vfs_volume_monitor_get_mounted_volumes (monitor);
869         GList *iter = list;
870         for (iter = list; iter; iter = g_list_next (iter)) {
871                 GnomeVFSVolume *volume = (GnomeVFSVolume*)iter->data;
872                 if (volume) {
873                         /*
874                         char *display_name = 
875                                 gnome_vfs_volume_get_display_name (volume);
876                         printf ("volume display name=%s\n", display_name);
877                         g_free (display_name);
878                         */
879                         
880                         char *uri = 
881                                 gnome_vfs_volume_get_activation_uri (volume);
882                         /* printf ("  uri=%s\n", uri); */
883                         if (uri && (strcmp (uri, path_as_uri) == 0))
884                                 result = TRUE;
885
886                         g_free (uri);
887
888                         gnome_vfs_volume_unref (volume);
889                 }
890         }
891
892         g_list_free (list);
893
894         g_free (path_as_uri);
895
896         return result;
897 }
898
899 ModestTnyAccountStore*
900 modest_tny_account_store_new (ModestAccountMgr *account_mgr,
901                               TnyDevice *device)
902 {
903         GObject *obj;
904         ModestTnyAccountStorePrivate *priv;
905         TnyAccount *local_account = NULL;
906         TnyLockable *lockable;
907         GnomeVFSVolumeMonitor* monitor = NULL;
908         gboolean auto_update;
909
910         g_return_val_if_fail (account_mgr, NULL);
911         g_return_val_if_fail (device, NULL);
912
913         obj  = G_OBJECT(g_object_new(MODEST_TYPE_TNY_ACCOUNT_STORE, NULL));
914         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
915
916         priv->account_mgr = g_object_ref (G_OBJECT(account_mgr));
917         priv->device = g_object_ref (device);
918
919         /* If autoupdate is off then we don't try to connect to the
920            accounts when they're added to the account store*/
921         auto_update = modest_conf_get_bool (modest_runtime_get_conf (),
922                                             MODEST_CONF_AUTO_UPDATE, NULL);
923         if (!auto_update)
924                 tny_device_force_offline (priv->device);
925
926         priv->session = tny_session_camel_new (TNY_ACCOUNT_STORE(obj));
927         if (!priv->session) {
928                 g_warning ("failed to get TnySessionCamel");
929                 return NULL;
930         }
931
932         /* Set the ui locker */
933         lockable = tny_gtk_lockable_new ();
934         tny_session_camel_set_ui_locker (priv->session, lockable);
935         g_object_unref (lockable);
936
937         /* Connect signals */
938         priv->sighandlers  =  modest_signal_mgr_connect (priv->sighandlers,
939                                                          G_OBJECT(account_mgr), "account_inserted",
940                                                          G_CALLBACK (on_account_inserted), obj);
941         priv->sighandlers  =  modest_signal_mgr_connect (priv->sighandlers,
942                                                          G_OBJECT(account_mgr), "account_changed",
943                                                          G_CALLBACK (on_account_changed), obj);
944         priv->sighandlers  =  modest_signal_mgr_connect (priv->sighandlers,
945                                                          G_OBJECT(account_mgr), "account_removed",
946                                                          G_CALLBACK (on_account_removed), obj);
947
948         /* Respond to volume mounts and unmounts, such as the
949            insertion/removal of the memory card. This is a singleton,
950            so it does not need to be unrefed */
951         monitor = gnome_vfs_get_volume_monitor();
952         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
953                                                        G_OBJECT(monitor),
954                                                        "volume-mounted",
955                                                        G_CALLBACK(on_vfs_volume_mounted),
956                                                        obj);
957         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
958                                                        G_OBJECT(monitor), "volume-unmounted",
959                                                        G_CALLBACK(on_vfs_volume_unmounted),
960                                                        obj);
961
962         /* Create the lists of accounts */
963         priv->store_accounts = tny_simple_list_new ();
964         priv->transport_accounts = tny_simple_list_new ();
965         priv->store_accounts_outboxes = tny_simple_list_new ();
966
967         /* Create the local folders account */
968         local_account =
969                 modest_tny_account_new_for_local_folders (priv->account_mgr, priv->session, NULL);
970         tny_list_append (priv->store_accounts, G_OBJECT(local_account));
971         g_object_unref (local_account);
972
973         /* Add the other remote accounts. Do this after adding the
974            local account, because we need to add our outboxes to the
975            global OUTBOX hosted in the local account */
976         add_existing_accounts (MODEST_TNY_ACCOUNT_STORE (obj));
977
978         /* Add connection-specific transport accounts if there are any
979            accounts available */
980         if (!only_local_accounts (MODEST_TNY_ACCOUNT_STORE(obj)))
981                 add_connection_specific_transport_accounts (MODEST_TNY_ACCOUNT_STORE(obj));
982
983         /* This is a singleton, so it does not need to be unrefed. */
984         if (volume_path_is_mounted (g_getenv (MODEST_MMC1_VOLUMEPATH_ENV))) {
985                 /* It is mounted: */
986                 add_mmc_account (MODEST_TNY_ACCOUNT_STORE (obj), FALSE /* don't emit the insert signal. */);
987         }
988
989         /* Initialize session */
990         tny_session_camel_set_initialized (priv->session);
991
992         return MODEST_TNY_ACCOUNT_STORE(obj);
993 }
994
995 static void
996 modest_tny_account_store_get_accounts  (TnyAccountStore *self, 
997                                         TnyList *list,
998                                         TnyGetAccountsRequestType request_type)
999 {
1000         ModestTnyAccountStorePrivate *priv;
1001         
1002         g_return_if_fail (self);
1003         g_return_if_fail (TNY_IS_LIST(list));
1004         
1005         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1006         
1007         switch (request_type) {
1008         case TNY_ACCOUNT_STORE_BOTH:
1009                 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
1010                 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
1011                 break;
1012         case TNY_ACCOUNT_STORE_STORE_ACCOUNTS:
1013                 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
1014                 break;
1015         case TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS:
1016                 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
1017                 break;
1018         default:
1019                 g_return_if_reached ();
1020         }
1021 }
1022
1023
1024 static const gchar*
1025 modest_tny_account_store_get_cache_dir (TnyAccountStore *self)
1026 {
1027         ModestTnyAccountStorePrivate *priv;
1028         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1029         
1030         if (!priv->cache_dir)
1031                 priv->cache_dir = g_build_filename (g_get_home_dir(), 
1032                                                     MODEST_DIR, MODEST_CACHE_DIR, NULL);
1033         return priv->cache_dir;
1034 }
1035
1036
1037 /*
1038  * callers need to unref
1039  */
1040 static TnyDevice*
1041 modest_tny_account_store_get_device (TnyAccountStore *self)
1042 {
1043         ModestTnyAccountStorePrivate *priv;
1044
1045         g_return_val_if_fail (self, NULL);
1046         
1047         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1048         
1049         if (priv->device) 
1050                 return g_object_ref (G_OBJECT(priv->device));
1051         else
1052                 return NULL;
1053 }
1054
1055
1056 static TnyAccount*
1057 modest_tny_account_store_find_account_by_url (TnyAccountStore *self, const gchar* url_string)
1058 {
1059         return modest_tny_account_store_get_tny_account_by (MODEST_TNY_ACCOUNT_STORE (self), 
1060                                                             MODEST_TNY_ACCOUNT_STORE_QUERY_URL,
1061                                                             url_string);
1062 }
1063
1064
1065
1066 static gboolean
1067 modest_tny_account_store_alert (TnyAccountStore *self, 
1068                                 TnyAccount *account, 
1069                                 TnyAlertType type,
1070                                 gboolean question, 
1071                                 GError *error)
1072 {
1073         ModestProtocolType protocol_type = MODEST_PROTOCOL_REGISTRY_TYPE_INVALID;
1074         ModestProtocol *protocol = NULL;
1075         const gchar* server_name = "";
1076         gchar *prompt = NULL;
1077         gboolean retval = TRUE;
1078
1079         /* NOTE: account may be NULL in some cases */
1080         g_return_val_if_fail (error, FALSE);
1081
1082         /* Get the server name: */
1083         if (account) {
1084                 server_name = tny_account_get_hostname (account);
1085                 protocol_type = modest_tny_account_get_protocol_type (account);
1086                 if (protocol_type == MODEST_PROTOCOL_REGISTRY_TYPE_INVALID){
1087                         g_warning("%s: account with id=%s has no proto.\n", __FUNCTION__, 
1088                                   tny_account_get_id (account));
1089                         return FALSE;
1090                 }
1091                 protocol = modest_protocol_registry_get_protocol_by_type (modest_runtime_get_protocol_registry (),
1092                                                                           protocol_type);
1093         }
1094
1095         switch (error->code) {
1096         case TNY_SYSTEM_ERROR_CANCEL:
1097                 /* Don't show waste the user's time by showing him a dialog telling 
1098                  * him that he has just cancelled something: */
1099                 return TRUE;
1100
1101         case TNY_SERVICE_ERROR_PROTOCOL:
1102                 /* Like a BAD from IMAP (protocol error) */
1103         case TNY_SERVICE_ERROR_LOST_CONNECTION:
1104                 /* Lost the connection with the service */
1105         case TNY_SERVICE_ERROR_UNAVAILABLE:
1106                 /* You must be working online for this operation */
1107         case TNY_SERVICE_ERROR_CONNECT:
1108                 if (protocol) {
1109                         prompt = modest_protocol_get_translation (protocol, MODEST_PROTOCOL_TRANSLATION_CONNECT_ERROR, server_name);
1110                 }
1111                 if (!prompt) {
1112                         g_return_val_if_reached (FALSE);
1113                 }
1114                 break;
1115         case TNY_SERVICE_ERROR_AUTHENTICATE:
1116                 /* It seems that there's no better error to show with
1117                  * POP and IMAP because TNY_SERVICE_ERROR_AUTHENTICATE
1118                  * may appear if there's a timeout during auth */
1119                 if (protocol) {
1120                         prompt = modest_protocol_get_translation (protocol, MODEST_PROTOCOL_TRANSLATION_AUTH_ERROR, server_name);
1121                 }
1122                 if (!prompt) {
1123                         g_return_val_if_reached (FALSE);
1124                 }
1125                 break;
1126         case TNY_SERVICE_ERROR_CERTIFICATE:
1127                 /* We'll show the proper dialog later */
1128                 break;
1129
1130         case TNY_SYSTEM_ERROR_MEMORY:
1131                 /* Can't allocate memory for this operation */
1132                 if (modest_tny_account_store_check_disk_full_error ((ModestTnyAccountStore*)self,
1133                                                                     NULL, error, account, NULL))
1134                         retval = FALSE;
1135                 break;
1136         case TNY_SERVICE_ERROR_UNKNOWN:
1137                 return FALSE;
1138         default:
1139                 /* We don't treat this as an error, but as a not handled message. Then,
1140                  * debug message, and return false */
1141                 g_debug ("Unexpected error %d (%s)", error->code, error->message);
1142                 return 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 if (error->code == TNY_SERVICE_ERROR_AUTHENTICATE ||
1150                  error->code == TNY_SERVICE_ERROR_CONNECT) {
1151                 TnyDevice *device = modest_runtime_get_device ();
1152
1153                 if (error->code == TNY_SERVICE_ERROR_CONNECT) {
1154                         gboolean success;
1155                         success = modest_account_mgr_get_server_account_username_has_succeeded (modest_runtime_get_account_mgr (),
1156                                                                                                 tny_account_get_id (account));
1157                         if (success)
1158                                 goto end;
1159                 }
1160
1161                 modest_platform_run_information_dialog (NULL, prompt, TRUE);
1162
1163                 /* Show the account dialog. Checking the online status
1164                    allows us to minimize the number of times that we
1165                    incorrectly show the dialog */
1166                 if (tny_device_is_online (device))
1167                         show_wrong_password_dialog (account,
1168                                                     (error->code == TNY_SERVICE_ERROR_CONNECT) ? FALSE : TRUE);
1169
1170                 retval = TRUE;
1171         }
1172  end:
1173         g_debug ("%s: error code %d (%s", __FUNCTION__, error->code, error->message);
1174
1175         if (prompt)
1176                 g_free (prompt);
1177
1178         return retval;
1179 }
1180
1181
1182 static void
1183 modest_tny_account_store_init (gpointer g, gpointer iface_data)
1184 {
1185         TnyAccountStoreIface *klass;
1186
1187         g_return_if_fail (g);
1188
1189         klass = (TnyAccountStoreIface *)g;
1190
1191         klass->get_accounts =
1192                 modest_tny_account_store_get_accounts;
1193         klass->get_cache_dir =
1194                 modest_tny_account_store_get_cache_dir;
1195         klass->get_device =
1196                 modest_tny_account_store_get_device;
1197         klass->alert =
1198                 modest_tny_account_store_alert;
1199         klass->find_account =
1200                 modest_tny_account_store_find_account_by_url;
1201 }
1202
1203 void
1204 modest_tny_account_store_set_get_pass_func (ModestTnyAccountStore *self,
1205                                             ModestTnyGetPassFunc func)
1206 {
1207         /* not implemented, we use signals */
1208         g_printerr ("modest: set_get_pass_func not implemented\n");
1209 }
1210
1211 TnySessionCamel*
1212 modest_tny_account_store_get_session  (TnyAccountStore *self)
1213 {
1214         g_return_val_if_fail (self, NULL);
1215         return MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self)->session;
1216 }
1217
1218 static TnyAccount*
1219 get_tny_account_by (TnyList *accounts,
1220                     ModestTnyAccountStoreQueryType type,
1221                     const gchar *str)
1222 {
1223         TnyIterator *iter = NULL;
1224         gboolean found = FALSE;
1225         TnyAccount *retval = NULL;
1226
1227         g_return_val_if_fail (TNY_IS_LIST(accounts), NULL);
1228
1229         if (tny_list_get_length(accounts) == 0) {
1230                 g_warning ("%s: account list is empty", __FUNCTION__);
1231                 return NULL;
1232         }
1233         
1234         iter = tny_list_create_iterator (accounts);
1235         while (!tny_iterator_is_done (iter) && !found) {
1236                 TnyAccount *tmp_account = NULL;
1237                 const gchar *val = NULL;
1238
1239                 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1240                 if (!TNY_IS_ACCOUNT(tmp_account)) {
1241                         g_warning ("%s: not a valid account", __FUNCTION__);
1242                         tmp_account = NULL;
1243                         break;
1244                 }
1245
1246                 switch (type) {
1247                 case MODEST_TNY_ACCOUNT_STORE_QUERY_ID:
1248                         val = tny_account_get_id (tmp_account);
1249                         break;
1250                 case MODEST_TNY_ACCOUNT_STORE_QUERY_URL:
1251                         val = tny_account_get_url_string (tmp_account);
1252                         break;
1253                 }
1254                 
1255                 if (type == MODEST_TNY_ACCOUNT_STORE_QUERY_URL && 
1256                     tny_account_matches_url_string (tmp_account, str)) {
1257                         retval = g_object_ref (tmp_account);
1258                         found = TRUE;
1259                 } else {
1260                         if (val && str && strcmp (val, str) == 0) {
1261                                 retval = g_object_ref (tmp_account);
1262                                 found = TRUE;
1263                         }
1264                 }
1265                 g_object_unref (tmp_account);
1266                 tny_iterator_next (iter);
1267         }
1268         g_object_unref (iter);
1269
1270         return retval;
1271 }
1272
1273 TnyAccount*
1274 modest_tny_account_store_get_tny_account_by (ModestTnyAccountStore *self, 
1275                                              ModestTnyAccountStoreQueryType type,
1276                                              const gchar *str)
1277 {
1278         TnyAccount *account = NULL;
1279         ModestTnyAccountStorePrivate *priv;     
1280         
1281         g_return_val_if_fail (self, NULL);
1282         g_return_val_if_fail (str, NULL);
1283         
1284         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1285         
1286         /* Search in store accounts */
1287         account = get_tny_account_by (priv->store_accounts, type, str);
1288
1289         /* If we already found something, no need to search the transport accounts */
1290         if (!account) {
1291                 account = get_tny_account_by (priv->transport_accounts, type, str);
1292
1293                 /* If we already found something, no need to search the
1294                    per-account outbox accounts */
1295                 if (!account)
1296                         account = get_tny_account_by (priv->store_accounts_outboxes, type, str);
1297         }
1298
1299         /* Warn if nothing was found. This is generally unusual. */
1300         if (!account) {
1301                 g_warning("%s: Failed to find account with %s=%s\n", 
1302                           __FUNCTION__, 
1303                           (type == MODEST_TNY_ACCOUNT_STORE_QUERY_ID) ? "ID" : "URL",                     
1304                           str);
1305         }
1306
1307         /* Returns a new reference to the account if found */   
1308         return account;
1309 }
1310
1311
1312 TnyAccount*
1313 modest_tny_account_store_get_server_account (ModestTnyAccountStore *self,
1314                                              const gchar *account_name,
1315                                              TnyAccountType type)
1316 {
1317         ModestTnyAccountStorePrivate *priv = NULL;
1318         TnyAccount *retval = NULL;
1319         TnyList *account_list = NULL;
1320         TnyIterator *iter = NULL;
1321         gboolean found;
1322
1323         g_return_val_if_fail (self, NULL);
1324         g_return_val_if_fail (account_name, NULL);
1325         g_return_val_if_fail (type == TNY_ACCOUNT_TYPE_STORE || 
1326                               type == TNY_ACCOUNT_TYPE_TRANSPORT,
1327                               NULL);
1328         
1329         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1330
1331         account_list = (type == TNY_ACCOUNT_TYPE_STORE) ? 
1332                 priv->store_accounts : 
1333                 priv->transport_accounts;
1334
1335         if (!account_list) {
1336                 g_printerr ("%s: No server accounts of type %s\n", __FUNCTION__, 
1337                         (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport");
1338                 return NULL;
1339         }
1340         
1341         /* Look for the server account */
1342         found = FALSE;
1343         iter = tny_list_create_iterator (account_list);
1344         while (!tny_iterator_is_done (iter) && !found) {
1345                 const gchar *modest_acc_name;
1346                 TnyAccount *tmp_account;
1347
1348                 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1349                 modest_acc_name = 
1350                         modest_tny_account_get_parent_modest_account_name_for_server_account (tmp_account);
1351                 
1352                 if (account_name && modest_acc_name && !strcmp (account_name, modest_acc_name)) {
1353                         found = TRUE;
1354                         retval = g_object_ref (tmp_account);
1355                 }
1356                 /* Free and continue */
1357                 g_object_unref (tmp_account);
1358                 tny_iterator_next (iter);
1359         }
1360         g_object_unref (iter);
1361
1362         if (!found) {
1363                 g_printerr ("modest: %s: could not get tny %s account for %s\n." \
1364                             "Number of server accounts of this type=%d\n", __FUNCTION__,
1365                             (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport",
1366                             account_name, tny_list_get_length (account_list));
1367         }
1368
1369         /* Returns a new reference */
1370         return retval;
1371 }
1372
1373 TnyAccount*
1374 modest_tny_account_store_get_smtp_specific_transport_account_for_open_connection (
1375         ModestTnyAccountStore *self, const gchar *account_name)
1376 {
1377         TnyDevice *device;
1378
1379         g_return_val_if_fail (self && MODEST_IS_TNY_ACCOUNT_STORE(self), NULL);
1380         g_return_val_if_fail (account_name, NULL);
1381
1382         /* Get the current connection: */
1383         device = modest_runtime_get_device ();
1384
1385         if (!device) {
1386                 g_warning ("%s: could not get device", __FUNCTION__);
1387                 return NULL;
1388         }
1389                 
1390         if (!tny_device_is_online (device))
1391                 return NULL;
1392         
1393 #ifdef MODEST_HAVE_CONIC
1394         g_return_val_if_fail (TNY_IS_MAEMO_CONIC_DEVICE (device), NULL);
1395         
1396         TnyMaemoConicDevice *maemo_device = TNY_MAEMO_CONIC_DEVICE (device);    
1397         const gchar* iap_id = tny_maemo_conic_device_get_current_iap_id (maemo_device);
1398         /* printf ("DEBUG: %s: iap_id=%s\n", __FUNCTION__, iap_id); */
1399         if (!iap_id)
1400                 return NULL;
1401                 
1402         ConIcIap* connection = tny_maemo_conic_device_get_iap (maemo_device, iap_id);
1403         if (!connection)
1404                 return NULL;
1405                 
1406         const gchar *connection_id = con_ic_iap_get_id (connection);
1407         /* printf ("DEBUG: %s: connection_id=%s\n", __FUNCTION__, connection_id); */
1408         if (!connection_id)
1409                 return NULL;
1410         
1411         /*  Get the connection-specific transport acccount, if any: */
1412         ModestAccountMgr *account_manager = modest_runtime_get_account_mgr ();
1413
1414         /* Check if this account has connection-specific SMTP enabled */
1415         if (!modest_account_mgr_get_use_connection_specific_smtp (account_manager, account_name)) {
1416                 return NULL;
1417         }
1418
1419         gchar* server_account_name = modest_account_mgr_get_connection_specific_smtp (account_manager, 
1420                 connection_id);
1421
1422         /* printf ("DEBUG: %s: server_account_name=%s\n", __FUNCTION__, server_account_name); */
1423         if (!server_account_name) {
1424                 return NULL; /* No connection-specific SMTP server was specified for this connection. */
1425         }
1426
1427         TnyAccount* account = modest_tny_account_store_get_tny_account_by (self, 
1428                                                                            MODEST_TNY_ACCOUNT_STORE_QUERY_ID, 
1429                                                                            server_account_name);
1430
1431         /* printf ("DEBUG: %s: account=%p\n", __FUNCTION__, account); */
1432         g_free (server_account_name);
1433
1434         /* Unref the get()ed object, as required by the tny_maemo_conic_device_get_iap() documentation. */
1435         g_object_unref (connection);
1436
1437         return account;
1438 #else
1439         return NULL; /* TODO: Implement this for GNOME, instead of just Maemo? */
1440 #endif /* MODEST_HAVE_CONIC */
1441 }
1442
1443                                                                  
1444 TnyAccount*
1445 modest_tny_account_store_get_transport_account_for_open_connection (ModestTnyAccountStore *self,
1446                                                                     const gchar *account_name)
1447 {
1448         g_return_val_if_fail (self, NULL);
1449         g_return_val_if_fail (account_name, NULL);
1450
1451         if (!account_name || !self)
1452                 return NULL;
1453         
1454         /*  Get the connection-specific transport acccount, if any: */
1455         /* Note: This gives us a reference: */
1456         TnyAccount *account =
1457                 modest_tny_account_store_get_smtp_specific_transport_account_for_open_connection (self, account_name);
1458                         
1459         /* If there is no connection-specific transport account (the common case), 
1460          * just get the regular transport account: */
1461         if (!account) {
1462                 /* The special local folders don't have transport accounts. */
1463                 if (strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0)
1464                         account = NULL;
1465                 else {
1466                         /* Note: This gives us a reference: */
1467                         account = modest_tny_account_store_get_server_account (self, account_name, 
1468                                                      TNY_ACCOUNT_TYPE_TRANSPORT);
1469                 }
1470         }
1471                         
1472         /* returns a reference. */     
1473         return account;
1474 }
1475
1476 TnyAccount*
1477 modest_tny_account_store_get_local_folders_account (ModestTnyAccountStore *self)
1478 {
1479         TnyAccount *account = NULL;
1480         ModestTnyAccountStorePrivate *priv;
1481         TnyIterator *iter;
1482         gboolean found;
1483
1484         g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1485         
1486         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1487
1488         found = FALSE;
1489         iter = tny_list_create_iterator (priv->store_accounts);
1490         while (!tny_iterator_is_done (iter) && !found) {
1491                 TnyAccount *tmp_account;
1492
1493                 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1494                 if (modest_tny_account_is_virtual_local_folders (tmp_account)) {
1495                         account = g_object_ref (tmp_account);
1496                         found = TRUE;
1497                 }
1498                 g_object_unref (tmp_account);
1499                 tny_iterator_next (iter);
1500         }
1501         g_object_unref (iter);
1502
1503         /* Returns a new reference to the account */
1504         return account;
1505 }
1506
1507 TnyAccount*
1508 modest_tny_account_store_get_mmc_folders_account (ModestTnyAccountStore *self)
1509 {
1510         g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1511         
1512         /* New reference */
1513         return modest_tny_account_store_get_tny_account_by (self, MODEST_TNY_ACCOUNT_STORE_QUERY_ID,
1514                                                             MODEST_MMC_ACCOUNT_ID);
1515
1516 }
1517
1518 /*********************************************************************************/
1519 static void
1520 add_existing_accounts (ModestTnyAccountStore *self)
1521 {
1522         GSList *account_names = NULL, *iter = NULL;
1523         ModestTnyAccountStorePrivate *priv = NULL;
1524         
1525         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1526
1527         /* These are account names, not server_account names */
1528         account_names = modest_account_mgr_account_names (priv->account_mgr, FALSE);
1529
1530         for (iter = account_names; iter != NULL; iter = g_slist_next (iter)) {
1531                 const gchar *account_name = (const gchar*) iter->data;
1532                 
1533                 /* Insert all enabled accounts without notifying */
1534                 if (modest_account_mgr_get_enabled (priv->account_mgr, account_name))
1535                         insert_account (self, account_name, FALSE);
1536         }
1537         modest_account_mgr_free_account_names (account_names);
1538 }
1539
1540 static TnyAccount*
1541 create_tny_account (ModestTnyAccountStore *self,
1542                     const gchar *name,
1543                     TnyAccountType type,
1544                     gboolean notify)
1545 {
1546         TnyAccount *account = NULL;
1547         ModestTnyAccountStorePrivate *priv = NULL;
1548
1549         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1550
1551         account = modest_tny_account_new_from_account (priv->account_mgr,
1552                                                        name, type, 
1553                                                        priv->session,
1554                                                        get_password,
1555                                                        forget_password);
1556
1557         if (account) {
1558                 /* Forget any cached password for the account, so that
1559                    we use a new account if any */
1560                 forget_password_in_memory (self, tny_account_get_id (account));
1561
1562                 /* Set the account store */
1563                 g_object_set_data (G_OBJECT(account), "account_store", self);
1564         } else {
1565                 g_printerr ("modest: failed to create account for %s\n", name);
1566         }
1567
1568         return account;
1569 }
1570
1571 typedef struct _AddOutboxInfo {
1572         ModestTnyAccountStore *account_store;
1573         TnyAccount *transport_account;
1574 } AddOutboxInfo;
1575
1576 static void
1577 add_outbox_from_transport_account_to_global_outbox_get_folders_cb (TnyFolderStore *folder_store,
1578                                                                    gboolean cancelled,
1579                                                                    TnyList *list,
1580                                                                    GError *err,
1581                                                                    gpointer userdata)
1582 {
1583         TnyIterator *iter_folders;
1584         TnyFolder *per_account_outbox;
1585         TnyAccount *local_account = NULL;
1586         AddOutboxInfo *info = (AddOutboxInfo *) userdata;
1587         ModestTnyAccountStorePrivate *priv = NULL;
1588         ModestTnyAccountStore *self;
1589
1590         self = MODEST_TNY_ACCOUNT_STORE (info->account_store);
1591         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1592         
1593         /* Note that this could happen if there is not enough space
1594            available on disk, then the outbox folder could not be
1595            created */
1596         if (tny_list_get_length (list) != 1) {
1597                 g_warning ("%s: could not create outbox folder (%d folders found)", __FUNCTION__,
1598                            tny_list_get_length (list));
1599                 goto frees;
1600         }
1601                         
1602         iter_folders = tny_list_create_iterator (list);
1603         per_account_outbox = TNY_FOLDER (tny_iterator_get_current (iter_folders));
1604         g_object_unref (iter_folders);
1605         g_object_unref (list);
1606
1607         /* Add the outbox of the new per-account-local-outbox account
1608            to the global local merged OUTBOX of the local folders
1609            account */
1610         local_account = modest_tny_account_store_get_local_folders_account (info->account_store);
1611         modest_tny_local_folders_account_add_folder_to_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1612                                                                per_account_outbox);
1613         /* Add the pair to the hash table */
1614         g_hash_table_insert (priv->outbox_of_transport,
1615                              info->transport_account,
1616                              per_account_outbox);
1617         
1618         /* Notify that the local account changed */
1619         g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1620         g_object_unref (local_account);
1621         g_object_unref (per_account_outbox);
1622
1623  frees:
1624         g_object_unref (info->transport_account);
1625         g_slice_free (AddOutboxInfo, info);
1626 }
1627                                                                    
1628
1629 static void
1630 add_outbox_from_transport_account_to_global_outbox (ModestTnyAccountStore *self,
1631                                                     const gchar *account_name,
1632                                                     TnyAccount *transport_account)
1633 {
1634         TnyList *folders = NULL;
1635         TnyAccount *account_outbox = NULL;
1636         ModestTnyAccountStorePrivate *priv = NULL;
1637         AddOutboxInfo *info;
1638
1639         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1640
1641         /* Create per account local outbox */
1642         account_outbox = 
1643                 modest_tny_account_new_for_per_account_local_outbox_folder (priv->account_mgr, 
1644                                                                             account_name, 
1645                                                                             priv->session);
1646
1647         if (!G_IS_OBJECT (account_outbox)) {
1648                 g_warning ("%s: could not create per account local outbox folder", __FUNCTION__);
1649                 return;
1650         }
1651
1652         tny_list_append (priv->store_accounts_outboxes, G_OBJECT (account_outbox));
1653         
1654         /* Get the outbox folder */
1655         folders = tny_simple_list_new ();
1656         info = g_slice_new0 (AddOutboxInfo);
1657         info->account_store = self;
1658         info->transport_account = g_object_ref (transport_account);
1659         tny_folder_store_get_folders_async (TNY_FOLDER_STORE (account_outbox), folders, NULL, FALSE, 
1660                                             add_outbox_from_transport_account_to_global_outbox_get_folders_cb, NULL, (gpointer) info);
1661         g_object_unref (account_outbox);
1662 }
1663
1664 /*
1665  * This function will be used for both adding new accounts and for the
1666  * initialization. In the initialization we do not want to emit
1667  * signals so notify will be FALSE, in the case of account additions
1668  * we do want to notify the observers
1669  */
1670 static void
1671 insert_account (ModestTnyAccountStore *self,
1672                 const gchar *account,
1673                 gboolean is_new)
1674 {
1675         ModestTnyAccountStorePrivate *priv = NULL;
1676         TnyAccount *store_account = NULL, *transport_account = NULL;
1677
1678         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1679
1680         /* Get the server and the transport account */
1681         store_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_STORE, is_new);
1682         if (!store_account || !TNY_IS_ACCOUNT(store_account)) {
1683                 g_warning ("%s: failed to create store account", __FUNCTION__);
1684                 return;
1685         }
1686
1687         transport_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT, is_new);
1688         if (!transport_account || !TNY_IS_ACCOUNT(transport_account)) {
1689                 g_warning ("%s: failed to create transport account", __FUNCTION__);
1690                 g_object_unref (store_account);
1691                 return;
1692         }
1693
1694         /* Add accounts to the lists */
1695         tny_list_append (priv->store_accounts, G_OBJECT (store_account));
1696         tny_list_append (priv->transport_accounts, G_OBJECT (transport_account));
1697
1698         /* Create a new pseudo-account with an outbox for this
1699            transport account and add it to the global outbox
1700            in the local account */
1701         add_outbox_from_transport_account_to_global_outbox (self, account, transport_account);
1702
1703         /* Force the creation of the send queue, this way send queues
1704            will automatically send missing emails when the connections
1705            become active */
1706         /* Notify the observers. We do it after everything is
1707            created */
1708         if (is_new) {
1709                 /* We only have to do this for new accounts, already
1710                    existing accounts at boot time are instantiated by
1711                    modest_tny_account_store_start_send_queues */
1712                 modest_runtime_get_send_queue ((TnyTransportAccount *) transport_account, TRUE);
1713
1714                 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, store_account);
1715                 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, transport_account);
1716         }
1717
1718         /* Frees */
1719         g_object_unref (store_account);
1720         g_object_unref (transport_account);
1721 }
1722
1723 static inline gboolean
1724 only_local_accounts (ModestTnyAccountStore *self)
1725 {
1726         return (modest_tny_account_store_get_num_remote_accounts (self) > 0) ? FALSE : TRUE;
1727 }
1728
1729 static void
1730 on_account_inserted (ModestAccountMgr *acc_mgr, 
1731                      const gchar *account,
1732                      gpointer user_data)
1733 {
1734         gboolean add_specific;
1735
1736         add_specific = only_local_accounts (MODEST_TNY_ACCOUNT_STORE (user_data));
1737
1738         /* Insert the account and notify the observers */
1739         insert_account (MODEST_TNY_ACCOUNT_STORE (user_data), account, TRUE);
1740
1741         /* If it's the first remote account then add the connection
1742            specific SMTP servers as well */
1743         if (add_specific)
1744                 add_connection_specific_transport_accounts (MODEST_TNY_ACCOUNT_STORE (user_data));
1745
1746 }
1747
1748 /* This is the callback of the tny_camel_account_set_online called in
1749    on_account_removed to disconnect the account */
1750 static void
1751 on_account_disconnect_when_removing (TnyCamelAccount *account, 
1752                                      gboolean canceled, 
1753                                      GError *err, 
1754                                      gpointer user_data)
1755 {
1756         ModestTnyAccountStore *self;
1757         ModestTnyAccountStorePrivate *priv;
1758
1759         self = MODEST_TNY_ACCOUNT_STORE (user_data);
1760         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1761
1762         /* Cancel all pending operations */
1763         tny_account_cancel (TNY_ACCOUNT (account));
1764         
1765         /* Unref the extra reference added by get_server_account */
1766         g_object_unref (account);
1767
1768         /* Clear the cache if it's an store account */
1769         if (TNY_IS_STORE_ACCOUNT (account)) {
1770                 tny_store_account_delete_cache (TNY_STORE_ACCOUNT (account));
1771         } else if (TNY_IS_TRANSPORT_ACCOUNT (account)) {
1772                 ModestTnySendQueue* send_queue;
1773                 send_queue = modest_runtime_get_send_queue (TNY_TRANSPORT_ACCOUNT (account), FALSE);
1774                 if (TNY_IS_SEND_QUEUE (send_queue)) {
1775                         if (modest_tny_send_queue_sending_in_progress (send_queue))
1776                                 tny_send_queue_cancel (TNY_SEND_QUEUE (send_queue),
1777                                                        TNY_SEND_QUEUE_CANCEL_ACTION_REMOVE, 
1778                                                        NULL);
1779                         modest_runtime_remove_send_queue (TNY_TRANSPORT_ACCOUNT (account));
1780                 }
1781         }
1782 }
1783
1784 /*
1785  * We use this one for both removing "normal" and "connection
1786  * specific" transport accounts
1787  */
1788 static void
1789 remove_transport_account (ModestTnyAccountStore *self,
1790                           TnyTransportAccount *transport_account)
1791 {
1792         ModestTnyAccountStorePrivate *priv;
1793         TnyFolder *outbox = NULL;
1794         
1795         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1796
1797         /* Remove it from the list of accounts and notify the
1798            observers. Do not need to wait for account
1799            disconnection */
1800         g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 0, transport_account);
1801         tny_list_remove (priv->transport_accounts, (GObject *) transport_account);
1802                 
1803         /* Remove the OUTBOX of the account from the global outbox */
1804         outbox = g_hash_table_lookup (priv->outbox_of_transport, transport_account);
1805
1806         if (TNY_IS_FOLDER (outbox)) {
1807                 TnyAccount *local_account = NULL;
1808                 TnyAccount *outbox_account = tny_folder_get_account (outbox);
1809
1810                 if (outbox_account) {
1811                         tny_list_remove (priv->store_accounts_outboxes, G_OBJECT (outbox_account));
1812                         /* Remove existing emails to send */
1813                         tny_store_account_delete_cache (TNY_STORE_ACCOUNT (outbox_account));
1814                         g_object_unref (outbox_account);
1815                 }
1816
1817                 local_account = modest_tny_account_store_get_local_folders_account (self);
1818                 modest_tny_local_folders_account_remove_folder_from_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1819                                                                             outbox);
1820
1821                 g_hash_table_remove (priv->outbox_of_transport, transport_account);
1822
1823                 /* Notify the change in the local account */
1824                 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1825                 g_object_unref (local_account);
1826         } else {
1827                 g_warning ("Removing a transport account that has no outbox");
1828         }
1829
1830         /* Cancel all pending operations */
1831         tny_account_cancel (TNY_ACCOUNT (transport_account));
1832
1833         /* Disconnect and notify the observers. The callback will free the reference */
1834         tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (transport_account), FALSE,
1835                                       on_account_disconnect_when_removing, self);
1836 }
1837
1838 static gboolean
1839 images_cache_remove_filter (TnyStreamCache *self, const gchar *id, const gchar *account_name)
1840 {
1841         gchar *account_name_with_separator;
1842         gboolean result;
1843         if (account_name == NULL || account_name[0] == '\0')
1844                 return FALSE;
1845
1846         if (id == NULL || id[0] == '\0')
1847                 return FALSE;
1848
1849         account_name_with_separator = g_strconcat (account_name, "__", NULL);
1850
1851         result = (g_str_has_prefix (id, account_name));
1852         g_free (account_name_with_separator);
1853
1854         return result;
1855 }
1856
1857 static void
1858 on_account_removed (ModestAccountMgr *acc_mgr, 
1859                     const gchar *account,
1860                     gpointer user_data)
1861 {
1862         TnyAccount *store_account = NULL, *transport_account = NULL;
1863         ModestTnyAccountStore *self;
1864         ModestTnyAccountStorePrivate *priv;
1865         TnyStreamCache *stream_cache;
1866         
1867         self = MODEST_TNY_ACCOUNT_STORE (user_data);
1868         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1869
1870         /* Get the server and the transport account */
1871         store_account = 
1872                 modest_tny_account_store_get_server_account (self, account, 
1873                                                              TNY_ACCOUNT_TYPE_STORE);
1874         transport_account = 
1875                 modest_tny_account_store_get_server_account (self, account,
1876                                                              TNY_ACCOUNT_TYPE_TRANSPORT);
1877         
1878         /* If there was any problem creating the account, for example,
1879            with the configuration system this could not exist */
1880         if (TNY_IS_STORE_ACCOUNT(store_account)) {
1881                 /* Forget any cached password for the account */
1882                 forget_password_in_memory (self, tny_account_get_id (store_account));
1883
1884                 /* Remove it from the list of accounts and notify the
1885                    observers. Do not need to wait for account
1886                    disconnection */
1887                 tny_list_remove (priv->store_accounts, (GObject *) store_account);
1888                 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 0, store_account);
1889
1890                 /* Cancel all pending operations */
1891                 tny_account_cancel (TNY_ACCOUNT (store_account));
1892
1893                 /* Disconnect before deleting the cache, because the
1894                    disconnection will rewrite the cache to the
1895                    disk */
1896                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (store_account), FALSE,
1897                                               on_account_disconnect_when_removing, self);
1898         } else {
1899                 g_warning ("%s: no store account for account %s\n", 
1900                            __FUNCTION__, account);
1901         }
1902
1903         /* If there was any problem creating the account, for example,
1904            with the configuration system this could not exist */
1905         if (TNY_IS_TRANSPORT_ACCOUNT(transport_account)) {
1906
1907                 /* Forget any cached password for the account */
1908                 forget_password_in_memory (self, tny_account_get_id (transport_account));
1909
1910                 /* Remove transport account. It'll free the reference
1911                    added by get_server_account */
1912                 remove_transport_account (self, TNY_TRANSPORT_ACCOUNT (transport_account));
1913         } else {
1914                 g_warning ("%s: no transport account for account %s\n", 
1915                            __FUNCTION__, account);
1916         }
1917
1918         /* Remove cached images */
1919         stream_cache = modest_runtime_get_images_cache ();
1920         tny_stream_cache_remove (stream_cache, (TnyStreamCacheRemoveFilter) images_cache_remove_filter, (gpointer) account);
1921
1922         /* If there are no more user accounts then delete the
1923            transport specific SMTP servers */
1924         if (only_local_accounts (self))
1925                 remove_connection_specific_transport_accounts (self);
1926 }
1927
1928 TnyTransportAccount *
1929 modest_tny_account_store_new_connection_specific_transport_account (ModestTnyAccountStore *self,
1930                                                                     const gchar *name)
1931 {
1932         ModestTnyAccountStorePrivate *priv = NULL;
1933         TnyAccount * tny_account = NULL;
1934
1935         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1936
1937         /* Add the account: */
1938         tny_account = 
1939                 modest_tny_account_new_from_server_account_name (priv->account_mgr, 
1940                                                                  priv->session, 
1941                                                                  name,
1942                                                                  get_password,
1943                                                                  forget_password);
1944         if (tny_account) {
1945                 g_object_set_data (G_OBJECT(tny_account), 
1946                                    "account_store", 
1947                                    (gpointer)self);
1948                 g_object_set_data (G_OBJECT(tny_account), 
1949                                    "connection_specific", 
1950                                    GINT_TO_POINTER (TRUE));
1951                 
1952                 tny_list_append (priv->transport_accounts, G_OBJECT (tny_account));
1953                 add_outbox_from_transport_account_to_global_outbox (self, 
1954                                                                     name, 
1955                                                                     tny_account);
1956                 
1957         } else
1958                 g_printerr ("modest: failed to create smtp-specific account for %s\n",
1959                             name);
1960
1961         return TNY_TRANSPORT_ACCOUNT (tny_account);
1962 }
1963
1964 static void 
1965 foreach_free_string(gpointer data,
1966                     gpointer user_data)
1967 {
1968         g_free (data);
1969 }
1970
1971 static void
1972 add_connection_specific_transport_accounts (ModestTnyAccountStore *self)
1973 {
1974         ModestTnyAccountStorePrivate *priv = NULL;
1975         GSList *list_specifics = NULL, *iter = NULL;
1976         GError *err = NULL;
1977
1978         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1979
1980         list_specifics = modest_conf_get_list (modest_runtime_get_conf (),
1981                                                MODEST_CONF_CONNECTION_SPECIFIC_SMTP_LIST,
1982                                                MODEST_CONF_VALUE_STRING, &err);
1983         if (err) {
1984                 g_error_free (err);
1985                 g_return_if_reached ();
1986                 return;
1987         }
1988                                 
1989         /* Look at each connection-specific transport account for the 
1990          * modest account: */
1991         iter = list_specifics;
1992         while (iter) {
1993                 /* The list alternates between the connection name and the transport name: */
1994                 iter = g_slist_next (iter);
1995                 if (iter) {
1996                         const gchar* transport_account_name = (const gchar*) (iter->data);
1997                         TnyTransportAccount * account = NULL;
1998                         account = modest_tny_account_store_new_connection_specific_transport_account (
1999                                 self, transport_account_name);
2000                         if (account)
2001                                 g_object_unref (account);
2002                 }                               
2003                 iter = g_slist_next (iter);
2004         }
2005
2006         /* Free the list */
2007         g_slist_foreach (list_specifics, foreach_free_string, NULL);
2008         g_slist_free (list_specifics);
2009 }
2010
2011 static void
2012 remove_connection_specific_transport_accounts (ModestTnyAccountStore *self)
2013 {
2014         ModestTnyAccountStorePrivate *priv = NULL;
2015         GSList *list_specifics = NULL, *iter = NULL;
2016         GError *err = NULL;
2017
2018         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
2019
2020         err = NULL;
2021         list_specifics = modest_conf_get_list (modest_runtime_get_conf (),
2022                                                MODEST_CONF_CONNECTION_SPECIFIC_SMTP_LIST,
2023                                                MODEST_CONF_VALUE_STRING, &err);
2024         if (err) {
2025                 g_error_free (err);
2026                 g_return_if_reached ();
2027                 return;
2028         }
2029                                 
2030         /* Look at each connection-specific transport account for the 
2031          * modest account: */
2032         iter = list_specifics;
2033         while (iter) {
2034                 /* The list alternates between the connection name and the transport name: */
2035                 iter = g_slist_next (iter);
2036                 if (iter) {
2037                         const gchar* transport_account_name = (const gchar*) (iter->data);
2038                         TnyAccount * account;
2039                         account = modest_tny_account_store_get_server_account (self,
2040                                                                                transport_account_name,
2041                                                                                TNY_ACCOUNT_TYPE_TRANSPORT);
2042
2043                         /* the call will free the reference */
2044                         if (account)
2045                                 remove_transport_account (self, TNY_TRANSPORT_ACCOUNT (account));
2046                 }                               
2047                 iter = g_slist_next (iter);
2048         }
2049
2050         /* Free the list */
2051         g_slist_foreach (list_specifics, foreach_free_string, NULL);
2052         g_slist_free (list_specifics);
2053 }
2054
2055
2056 TnyMsg *
2057 modest_tny_account_store_find_msg_in_outboxes (ModestTnyAccountStore *self, 
2058                                                const gchar *uri,
2059                                                TnyAccount **ac_out)
2060 {
2061         TnyIterator *acc_iter;
2062         ModestTnyAccountStorePrivate *priv;
2063         TnyMsg *msg = NULL;
2064         TnyAccount *msg_account = NULL;
2065
2066         g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
2067         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2068
2069         acc_iter = tny_list_create_iterator (priv->store_accounts_outboxes);
2070         while (!msg && !tny_iterator_is_done (acc_iter)) {
2071                 TnyList *folders = tny_simple_list_new ();
2072                 TnyAccount *account = TNY_ACCOUNT (tny_iterator_get_current (acc_iter));
2073                 TnyIterator *folders_iter = NULL;
2074
2075                 tny_folder_store_get_folders (TNY_FOLDER_STORE (account), folders, NULL, FALSE, NULL);
2076                 folders_iter = tny_list_create_iterator (folders);
2077
2078                 while (msg == NULL && !tny_iterator_is_done (folders_iter)) {
2079                         TnyFolder *folder = TNY_FOLDER (tny_iterator_get_current (folders_iter));
2080                         msg = tny_folder_find_msg (folder, uri, NULL);
2081
2082                         if (msg)
2083                                 msg_account = g_object_ref (account);
2084
2085                         g_object_unref (folder);
2086                         tny_iterator_next (folders_iter);
2087                 }
2088                 g_object_unref (folders_iter);
2089
2090                 g_object_unref (folders);
2091                 g_object_unref (account);
2092                 tny_iterator_next (acc_iter);
2093         }
2094
2095         g_object_unref (acc_iter);
2096
2097         if (ac_out != NULL)
2098                 *ac_out = msg_account;
2099
2100         return msg;
2101 }
2102
2103 TnyTransportAccount *
2104 modest_tny_account_store_get_transport_account_from_outbox_header(ModestTnyAccountStore *self, TnyHeader *header)
2105 {
2106         TnyIterator *acc_iter;
2107         ModestTnyAccountStorePrivate *priv;
2108         TnyTransportAccount *header_acc = NULL;
2109         gchar *msg_id;
2110
2111         g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
2112         g_return_val_if_fail (TNY_IS_HEADER (header), NULL);
2113         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2114         msg_id = modest_tny_send_queue_get_msg_id (header);
2115         acc_iter = tny_list_create_iterator (priv->transport_accounts);
2116         while (!header_acc && !tny_iterator_is_done (acc_iter)) {
2117                 TnyTransportAccount *account = TNY_TRANSPORT_ACCOUNT (tny_iterator_get_current (acc_iter));
2118                 ModestTnySendQueue *send_queue;
2119                 ModestTnySendQueueStatus status;
2120                 send_queue = modest_runtime_get_send_queue(TNY_TRANSPORT_ACCOUNT(account), TRUE);
2121                 if (TNY_IS_SEND_QUEUE (send_queue)) {
2122                         status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2123                         if (status != MODEST_TNY_SEND_QUEUE_UNKNOWN)
2124                                 header_acc = g_object_ref(account);
2125                 }
2126                 g_object_unref (account);
2127                 tny_iterator_next (acc_iter);
2128         }
2129         g_object_unref(acc_iter);
2130         g_free (msg_id);
2131
2132         /* New reference */
2133         return header_acc;
2134 }
2135
2136 typedef struct {
2137         ModestTnyAccountStore *account_store;
2138         ModestTnyAccountStoreShutdownCallback callback;
2139         gpointer userdata;
2140         gint pending;
2141 } ShutdownOpData;
2142
2143 static void
2144 account_shutdown_callback (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer userdata)
2145 {
2146         ShutdownOpData *op_data = (ShutdownOpData *) userdata;
2147         op_data->pending--;
2148         if (op_data->pending == 0) {
2149                 if (op_data->callback)
2150                         op_data->callback (op_data->account_store, op_data->userdata);
2151                 g_object_unref (op_data->account_store);
2152                 g_free (op_data);
2153         }
2154 }
2155
2156 static void
2157 account_shutdown (TnyAccount *account, ShutdownOpData *op_data)
2158 {
2159         g_return_if_fail (account && TNY_IS_ACCOUNT(account));
2160
2161         if (TNY_IS_STORE_ACCOUNT (account) && 
2162             !modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
2163                 op_data->pending--;
2164                 return;
2165         }
2166
2167         /* Disconnect account */
2168         tny_camel_account_set_online (TNY_CAMEL_ACCOUNT(account), FALSE, 
2169                                       account_shutdown_callback, op_data);
2170
2171 }
2172
2173
2174 void
2175 modest_tny_account_store_shutdown (ModestTnyAccountStore *self,
2176                                    ModestTnyAccountStoreShutdownCallback callback,
2177                                    gpointer userdata)
2178 {
2179         gint num_accounts;
2180         ShutdownOpData *op_data;
2181         ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2182
2183         /* Get references */
2184         num_accounts = 0;
2185         if (priv->store_accounts)
2186                 num_accounts += tny_list_get_length (priv->store_accounts);
2187         if (priv->transport_accounts)
2188                 num_accounts += tny_list_get_length (priv->transport_accounts);
2189
2190         /* Create the helper object */
2191         op_data = g_new0 (ShutdownOpData, 1);
2192         op_data->callback = callback;
2193         op_data->userdata = userdata;
2194         op_data->pending = num_accounts;
2195         op_data->account_store = g_object_ref (self);
2196
2197         /* Force the TnyDevice to be offline. This way new
2198            undesired connections won't be initiated */
2199         tny_device_force_offline (priv->device);
2200
2201         /* Destroy all accounts. Disconnect all accounts before they are destroyed */
2202         if (priv->store_accounts) {
2203                 tny_list_foreach (priv->store_accounts, (GFunc)account_shutdown, op_data);
2204         }
2205
2206         if (priv->transport_accounts) {
2207                 tny_list_foreach (priv->transport_accounts, (GFunc)account_shutdown, op_data);
2208         }
2209
2210         if (op_data->pending == 0) {
2211                 if (op_data->callback)
2212                         op_data->callback (op_data->account_store, op_data->userdata);
2213                 g_object_unref (op_data->account_store);
2214                 g_free (op_data);
2215         }
2216 }
2217
2218 gboolean 
2219 modest_tny_account_store_is_shutdown (ModestTnyAccountStore *self)
2220 {
2221         ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2222         TnyIterator *iter;
2223         gboolean found;
2224
2225         found = FALSE;
2226
2227         for (iter = tny_list_create_iterator (priv->store_accounts);
2228              !found && !tny_iterator_is_done (iter);
2229              tny_iterator_next (iter)) {
2230                 TnyAccount *account;
2231
2232                 account = (TnyAccount *) tny_iterator_get_current (iter);
2233                 if (TNY_IS_ACCOUNT (account)) {
2234                         found = (tny_account_get_connection_status (account) == TNY_CONNECTION_STATUS_CONNECTED) ||
2235                                 (tny_account_get_connection_status (account) == TNY_CONNECTION_STATUS_RECONNECTING);
2236                 }
2237                 g_object_unref (account);
2238         }
2239         g_object_unref (iter);
2240
2241         if (found)
2242                 return !found;
2243
2244         for (iter = tny_list_create_iterator (priv->transport_accounts);
2245              !found && !tny_iterator_is_done (iter);
2246              tny_iterator_next (iter)) {
2247                 TnyAccount *account;
2248
2249                 account = (TnyAccount *) tny_iterator_get_current (iter);
2250                 if (TNY_IS_ACCOUNT (account)) {
2251                         found = (tny_account_get_connection_status (account) == TNY_CONNECTION_STATUS_CONNECTED) ||
2252                                 (tny_account_get_connection_status (account) == TNY_CONNECTION_STATUS_RECONNECTING);
2253                 }
2254                 g_object_unref (account);
2255         }
2256         g_object_unref (iter);
2257
2258         return !found;
2259
2260 }
2261
2262
2263 gboolean 
2264 modest_tny_account_store_is_send_mail_blocked (ModestTnyAccountStore *self)
2265 {
2266         ModestTnyAccountStorePrivate *priv;
2267
2268         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
2269
2270         return priv->send_mail_blocked;
2271 }
2272
2273 void 
2274 modest_tny_account_store_set_send_mail_blocked (ModestTnyAccountStore *self, 
2275                                                 gboolean blocked)
2276 {
2277         ModestTnyAccountStorePrivate *priv;
2278
2279         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
2280
2281         priv->send_mail_blocked = blocked;
2282 }
2283
2284 static void
2285 count_remote_accounts (gpointer data, gpointer user_data)
2286 {
2287         TnyFolderStore *account = TNY_FOLDER_STORE (data);
2288         gint *count = (gint *) user_data;
2289
2290         if (modest_tny_folder_store_is_remote (account))
2291                 (*count)++;
2292 }
2293
2294 guint
2295 modest_tny_account_store_get_num_remote_accounts (ModestTnyAccountStore *self)
2296 {
2297         ModestTnyAccountStorePrivate *priv;
2298         gint count = 0;
2299
2300         g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), 0);
2301
2302         /* Count remote accounts */
2303         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2304         tny_list_foreach (priv->store_accounts, (GFunc) count_remote_accounts, &count);
2305
2306         return count;
2307 }
2308
2309 static void
2310 init_send_queue (TnyAccount *account, gpointer user_data)
2311 {
2312         modest_runtime_get_send_queue ((TnyTransportAccount *) account, TRUE);
2313 }
2314
2315 void
2316 modest_tny_account_store_start_send_queues (ModestTnyAccountStore *self)
2317 {
2318         ModestTnyAccountStorePrivate *priv;
2319         TnyList *tmp;
2320
2321         g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self));
2322
2323         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2324
2325         /* We need to create a copy of the list because if the send
2326            queues are created they'll directly access to the TnyList
2327            of transport accounts, and thus we'll end up blocked in the
2328            mutex the TnyList uses to synchronize accesses */
2329         tmp = tny_list_copy (priv->transport_accounts);
2330
2331         /* Just instantiate them. They'll begin to listen for
2332            connection changes to send messages ASAP */
2333         tny_list_foreach (tmp, (GFunc) init_send_queue, NULL);
2334         g_object_unref (tmp);
2335 }
2336
2337
2338 gboolean
2339 modest_tny_account_store_check_disk_full_error (ModestTnyAccountStore *self,
2340                                                 GtkWidget *parent_window,
2341                                                 GError *err,
2342                                                 TnyAccount *account,
2343                                                 const gchar *alternate)
2344 {
2345         if (err == NULL)
2346                 return FALSE;
2347
2348         if (modest_tny_account_store_is_disk_full_error (self, err, account)) {
2349                 gboolean is_mcc = modest_tny_account_is_memory_card_account (account);
2350                 if (is_mcc && alternate) {
2351                         modest_platform_information_banner (parent_window, NULL, alternate);
2352                 } else {
2353                         gchar *msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
2354                         modest_platform_information_banner (parent_window, NULL, msg);
2355                         g_free (msg);
2356                 }
2357         } else if (err->code == TNY_SYSTEM_ERROR_MEMORY)
2358                 /* If the account was created in memory full
2359                    conditions then tinymail won't be able to
2360                    connect so it'll return this error code */
2361                 modest_platform_information_banner (parent_window,
2362                                                     NULL, _("emev_ui_imap_inbox_select_error"));
2363         else
2364                 return FALSE;
2365
2366         return TRUE;
2367 }
2368
2369 gboolean
2370 modest_tny_account_store_is_disk_full_error (ModestTnyAccountStore *self,
2371                                              GError *error,
2372                                              TnyAccount *account)
2373 {
2374         gboolean enough_free_space = TRUE;
2375         GnomeVFSURI *cache_dir_uri;
2376         const gchar *cache_dir = NULL;
2377         GnomeVFSFileSize free_space;
2378
2379         /* Cache dir is different in case we're using an external storage (like MMC account) */
2380         if (account && modest_tny_account_is_memory_card_account (account))
2381                 cache_dir = g_getenv (MODEST_MMC1_VOLUMEPATH_ENV);
2382
2383         /* Get the default local cache dir */
2384         if (!cache_dir)
2385                 cache_dir = tny_account_store_get_cache_dir ((TnyAccountStore *) self);
2386
2387         cache_dir_uri = gnome_vfs_uri_new (cache_dir);
2388         if (cache_dir_uri) {
2389                 if (gnome_vfs_get_volume_free_space (cache_dir_uri, &free_space) == GNOME_VFS_OK) {
2390                         if (free_space < MODEST_TNY_ACCOUNT_STORE_MIN_FREE_SPACE)
2391                                 enough_free_space = FALSE;
2392                 }
2393                 gnome_vfs_uri_unref (cache_dir_uri);
2394         }
2395
2396         if ((error->code == TNY_SYSTEM_ERROR_MEMORY ||
2397              /* When asking for a mail and no space left on device
2398                 tinymail returns this error */
2399              error->code == TNY_SERVICE_ERROR_MESSAGE_NOT_AVAILABLE ||
2400              /* When the folder summary could not be read or
2401                 written */
2402              error->code == TNY_IO_ERROR_WRITE ||
2403              error->code == TNY_IO_ERROR_READ) &&
2404             !enough_free_space) {
2405                 return TRUE;
2406         } else {
2407                 return FALSE;
2408         }
2409 }
2410
2411 void
2412 modest_tny_account_store_reset_attempt_count (ModestTnyAccountStore *self,
2413                                               TnyAccount *account)
2414 {
2415         ModestTnyAccountStorePrivate *priv;
2416         PwdAttempt *attempt;
2417
2418         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
2419
2420         /* Reset the count */
2421         attempt = g_hash_table_lookup (priv->password_hash, tny_account_get_id (account));
2422         if (attempt) {
2423                 attempt->count = RETRY_ATTEMPTS;
2424                 g_debug ("%s, reseting the attempt count for account %s", __FUNCTION__, tny_account_get_id (account));
2425         }
2426 }