Fixes NB#125495, do not show account settings dialog if the settings are ok
[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                         if (pwd) {
693                                 /* The password must be wrong, so show the account settings dialog so it can be corrected: */
694                                 show_wrong_password_dialog (account, TRUE);
695
696                                 if (cancel)
697                                         *cancel = TRUE;
698
699                                 return NULL;
700                         } else {
701                                 /* Get the password from the account settings */
702                                 return modest_account_mgr_get_server_account_password (priv->account_mgr, server_account_name);
703                         }
704                 }
705
706                 /* we don't have it yet. Get the password from the user */
707                 pwd = NULL;
708                 const gchar* account_id = tny_account_get_id (account);
709                 gboolean remember = FALSE;
710                 g_signal_emit (G_OBJECT (self), signals[PASSWORD_REQUESTED_SIGNAL], 0,
711                                account_id, /* server_account_name */
712                                &username, &pwd, cancel, &remember);
713
714                 if (*cancel) {
715                         g_hash_table_remove (priv->password_hash, server_account_name);
716                         g_free (pwd);
717                         pwd = NULL;
718                 }
719
720                 g_free (username);
721                 username = NULL;
722         } else {
723                 if (cancel)
724                         *cancel = FALSE;
725         }
726         return pwd;
727 }
728
729 void 
730 modest_tny_account_store_forget_already_asked (ModestTnyAccountStore *self, TnyAccount *account)
731 {
732         g_return_if_fail (account);
733           
734         ModestTnyAccountStorePrivate *priv;
735         gchar *pwd = NULL;
736         gpointer pwd_ptr = NULL;
737         gboolean already_asked = FALSE;
738                 
739         const gchar *server_account_name = tny_account_get_id (account);
740
741         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
742         
743         /* This hash map stores passwords, including passwords that are not stored in gconf. */
744         pwd_ptr = (gpointer)&pwd; /* pwd_ptr so the compiler does not complained about
745                                    * type-punned ptrs...*/
746         already_asked = priv->password_hash && 
747                                 g_hash_table_lookup_extended (priv->password_hash,
748                                                       server_account_name,
749                                                       NULL,
750                                                       (gpointer*)&pwd_ptr);
751
752         if (already_asked) {
753                 g_hash_table_remove (priv->password_hash, server_account_name);
754                 g_free (pwd);
755                 pwd = NULL;
756         }
757
758         return;
759 }
760
761 /* tinymail calls this if the connection failed due to an incorrect password.
762  * And it seems to call this for any general connection failure. */
763 static void
764 forget_password (TnyAccount *account)
765 {
766         ModestTnyAccountStore *self;
767         ModestTnyAccountStorePrivate *priv;
768         const TnyAccountStore *account_store;
769         const gchar *key;
770         PwdAttempt *attempt;
771
772         account_store = TNY_ACCOUNT_STORE(g_object_get_data (G_OBJECT(account),
773                                                              "account_store"));
774         self = MODEST_TNY_ACCOUNT_STORE (account_store);
775         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
776         key  = tny_account_get_id (account);
777
778         /* Do not remove the key, this will allow us to detect that we
779            have already asked for it at least once */
780         attempt = g_hash_table_lookup (priv->password_hash, key);
781         if (attempt) {
782                 attempt->count--;
783                 g_debug ("%s, remaining %d for account %s", __FUNCTION__, attempt->count, key);
784                 if (attempt->count == 0) {
785                         if (attempt->pwd)
786                                 memset (attempt->pwd, 0, strlen (attempt->pwd));
787                         g_hash_table_insert (priv->password_hash, g_strdup (key), NULL);
788                 }
789         }
790 }
791
792 static void
793 modest_tny_account_store_finalize (GObject *obj)
794 {
795         ModestTnyAccountStore *self        = MODEST_TNY_ACCOUNT_STORE(obj);
796         ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
797
798         g_free (priv->cache_dir);
799         priv->cache_dir = NULL;
800
801         if (priv->password_hash) {
802                 g_hash_table_destroy (priv->password_hash);
803                 priv->password_hash = NULL;
804         }
805
806         if (priv->outbox_of_transport) {
807                 g_hash_table_destroy (priv->outbox_of_transport);
808                 priv->outbox_of_transport = NULL;
809         }
810
811         modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
812         priv->sighandlers = NULL;       
813
814         if (priv->account_mgr) {
815                 g_object_unref (G_OBJECT(priv->account_mgr));
816                 priv->account_mgr = NULL;
817         }
818
819         if (priv->device) {
820                 g_object_unref (G_OBJECT(priv->device));
821                 priv->device = NULL;
822         }
823
824         /* Destroy all accounts. Disconnect all accounts before they are destroyed */
825         if (priv->store_accounts) {
826                 tny_list_foreach (priv->store_accounts, (GFunc)account_verify_last_ref, "store");
827                 g_object_unref (priv->store_accounts);
828                 priv->store_accounts = NULL;
829         }
830         
831         if (priv->transport_accounts) {
832                 tny_list_foreach (priv->transport_accounts, (GFunc)account_verify_last_ref, "transport");
833                 g_object_unref (priv->transport_accounts);
834                 priv->transport_accounts = NULL;
835         }
836
837         if (priv->store_accounts_outboxes) {
838                 g_object_unref (priv->store_accounts_outboxes);
839                 priv->store_accounts_outboxes = NULL;
840         }
841                 
842         if (priv->session) {
843                 camel_object_unref (CAMEL_OBJECT(priv->session));
844                 priv->session = NULL;
845         }
846
847         G_OBJECT_CLASS(parent_class)->finalize (obj);
848 }
849
850 static gboolean 
851 volume_path_is_mounted (const gchar* path)
852 {
853         g_return_val_if_fail (path, FALSE);
854
855         gboolean result = FALSE;
856         gchar * path_as_uri = g_filename_to_uri (path, NULL, NULL);
857         g_return_val_if_fail (path_as_uri, FALSE);
858
859         /* Get the monitor singleton: */
860         GnomeVFSVolumeMonitor *monitor = gnome_vfs_get_volume_monitor();
861
862         /* This seems like a simpler way to do this, but it returns a   
863          * GnomeVFSVolume even if the drive is not mounted: */
864         /*
865         GnomeVFSVolume *volume = gnome_vfs_volume_monitor_get_volume_for_path (monitor, 
866                                  g_getenv (MODEST_MMC1_VOLUMEPATH_ENV));
867         if (volume) {
868                 gnome_vfs_volume_unref(volume);
869         }
870         */
871
872         /* Get the mounted volumes from the monitor: */
873         GList *list = gnome_vfs_volume_monitor_get_mounted_volumes (monitor);
874         GList *iter = list;
875         for (iter = list; iter; iter = g_list_next (iter)) {
876                 GnomeVFSVolume *volume = (GnomeVFSVolume*)iter->data;
877                 if (volume) {
878                         /*
879                         char *display_name = 
880                                 gnome_vfs_volume_get_display_name (volume);
881                         printf ("volume display name=%s\n", display_name);
882                         g_free (display_name);
883                         */
884                         
885                         char *uri = 
886                                 gnome_vfs_volume_get_activation_uri (volume);
887                         /* printf ("  uri=%s\n", uri); */
888                         if (uri && (strcmp (uri, path_as_uri) == 0))
889                                 result = TRUE;
890
891                         g_free (uri);
892
893                         gnome_vfs_volume_unref (volume);
894                 }
895         }
896
897         g_list_free (list);
898
899         g_free (path_as_uri);
900
901         return result;
902 }
903
904 ModestTnyAccountStore*
905 modest_tny_account_store_new (ModestAccountMgr *account_mgr,
906                               TnyDevice *device)
907 {
908         GObject *obj;
909         ModestTnyAccountStorePrivate *priv;
910         TnyAccount *local_account = NULL;
911         TnyLockable *lockable;
912         GnomeVFSVolumeMonitor* monitor = NULL;
913         gboolean auto_update;
914
915         g_return_val_if_fail (account_mgr, NULL);
916         g_return_val_if_fail (device, NULL);
917
918         obj  = G_OBJECT(g_object_new(MODEST_TYPE_TNY_ACCOUNT_STORE, NULL));
919         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
920
921         priv->account_mgr = g_object_ref (G_OBJECT(account_mgr));
922         priv->device = g_object_ref (device);
923
924         /* If autoupdate is off then we don't try to connect to the
925            accounts when they're added to the account store*/
926         auto_update = modest_conf_get_bool (modest_runtime_get_conf (),
927                                             MODEST_CONF_AUTO_UPDATE, NULL);
928         if (!auto_update)
929                 tny_device_force_offline (priv->device);
930
931         priv->session = tny_session_camel_new (TNY_ACCOUNT_STORE(obj));
932         if (!priv->session) {
933                 g_warning ("failed to get TnySessionCamel");
934                 return NULL;
935         }
936
937         /* Set the ui locker */
938         lockable = tny_gtk_lockable_new ();
939         tny_session_camel_set_ui_locker (priv->session, lockable);
940         g_object_unref (lockable);
941
942         /* Connect signals */
943         priv->sighandlers  =  modest_signal_mgr_connect (priv->sighandlers,
944                                                          G_OBJECT(account_mgr), "account_inserted",
945                                                          G_CALLBACK (on_account_inserted), obj);
946         priv->sighandlers  =  modest_signal_mgr_connect (priv->sighandlers,
947                                                          G_OBJECT(account_mgr), "account_changed",
948                                                          G_CALLBACK (on_account_changed), obj);
949         priv->sighandlers  =  modest_signal_mgr_connect (priv->sighandlers,
950                                                          G_OBJECT(account_mgr), "account_removed",
951                                                          G_CALLBACK (on_account_removed), obj);
952
953         /* Respond to volume mounts and unmounts, such as the
954            insertion/removal of the memory card. This is a singleton,
955            so it does not need to be unrefed */
956         monitor = gnome_vfs_get_volume_monitor();
957         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
958                                                        G_OBJECT(monitor),
959                                                        "volume-mounted",
960                                                        G_CALLBACK(on_vfs_volume_mounted),
961                                                        obj);
962         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
963                                                        G_OBJECT(monitor), "volume-unmounted",
964                                                        G_CALLBACK(on_vfs_volume_unmounted),
965                                                        obj);
966
967         /* Create the lists of accounts */
968         priv->store_accounts = tny_simple_list_new ();
969         priv->transport_accounts = tny_simple_list_new ();
970         priv->store_accounts_outboxes = tny_simple_list_new ();
971
972         /* Create the local folders account */
973         local_account =
974                 modest_tny_account_new_for_local_folders (priv->account_mgr, priv->session, NULL);
975         tny_list_append (priv->store_accounts, G_OBJECT(local_account));
976         g_object_unref (local_account);
977
978         /* Add the other remote accounts. Do this after adding the
979            local account, because we need to add our outboxes to the
980            global OUTBOX hosted in the local account */
981         add_existing_accounts (MODEST_TNY_ACCOUNT_STORE (obj));
982
983         /* Add connection-specific transport accounts if there are any
984            accounts available */
985         if (!only_local_accounts (MODEST_TNY_ACCOUNT_STORE(obj)))
986                 add_connection_specific_transport_accounts (MODEST_TNY_ACCOUNT_STORE(obj));
987
988         /* This is a singleton, so it does not need to be unrefed. */
989         if (volume_path_is_mounted (g_getenv (MODEST_MMC1_VOLUMEPATH_ENV))) {
990                 /* It is mounted: */
991                 add_mmc_account (MODEST_TNY_ACCOUNT_STORE (obj), FALSE /* don't emit the insert signal. */);
992         }
993
994         /* Initialize session */
995         tny_session_camel_set_initialized (priv->session);
996
997         return MODEST_TNY_ACCOUNT_STORE(obj);
998 }
999
1000 static void
1001 modest_tny_account_store_get_accounts  (TnyAccountStore *self, 
1002                                         TnyList *list,
1003                                         TnyGetAccountsRequestType request_type)
1004 {
1005         ModestTnyAccountStorePrivate *priv;
1006         
1007         g_return_if_fail (self);
1008         g_return_if_fail (TNY_IS_LIST(list));
1009         
1010         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1011         
1012         switch (request_type) {
1013         case TNY_ACCOUNT_STORE_BOTH:
1014                 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
1015                 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
1016                 break;
1017         case TNY_ACCOUNT_STORE_STORE_ACCOUNTS:
1018                 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
1019                 break;
1020         case TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS:
1021                 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
1022                 break;
1023         default:
1024                 g_return_if_reached ();
1025         }
1026 }
1027
1028
1029 static const gchar*
1030 modest_tny_account_store_get_cache_dir (TnyAccountStore *self)
1031 {
1032         ModestTnyAccountStorePrivate *priv;
1033         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1034         
1035         if (!priv->cache_dir)
1036                 priv->cache_dir = g_build_filename (g_get_home_dir(), 
1037                                                     MODEST_DIR, MODEST_CACHE_DIR, NULL);
1038         return priv->cache_dir;
1039 }
1040
1041
1042 /*
1043  * callers need to unref
1044  */
1045 static TnyDevice*
1046 modest_tny_account_store_get_device (TnyAccountStore *self)
1047 {
1048         ModestTnyAccountStorePrivate *priv;
1049
1050         g_return_val_if_fail (self, NULL);
1051         
1052         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1053         
1054         if (priv->device) 
1055                 return g_object_ref (G_OBJECT(priv->device));
1056         else
1057                 return NULL;
1058 }
1059
1060
1061 static TnyAccount*
1062 modest_tny_account_store_find_account_by_url (TnyAccountStore *self, const gchar* url_string)
1063 {
1064         return modest_tny_account_store_get_tny_account_by (MODEST_TNY_ACCOUNT_STORE (self), 
1065                                                             MODEST_TNY_ACCOUNT_STORE_QUERY_URL,
1066                                                             url_string);
1067 }
1068
1069
1070
1071 static gboolean
1072 modest_tny_account_store_alert (TnyAccountStore *self, 
1073                                 TnyAccount *account, 
1074                                 TnyAlertType type,
1075                                 gboolean question, 
1076                                 GError *error)
1077 {
1078         ModestProtocolType protocol_type = MODEST_PROTOCOL_REGISTRY_TYPE_INVALID;
1079         ModestProtocol *protocol = NULL;
1080         const gchar* server_name = "";
1081         gchar *prompt = NULL;
1082         gboolean retval = TRUE;
1083
1084         /* NOTE: account may be NULL in some cases */
1085         g_return_val_if_fail (error, FALSE);
1086
1087         /* Get the server name: */
1088         if (account) {
1089                 server_name = tny_account_get_hostname (account);
1090                 protocol_type = modest_tny_account_get_protocol_type (account);
1091                 if (protocol_type == MODEST_PROTOCOL_REGISTRY_TYPE_INVALID){
1092                         g_warning("%s: account with id=%s has no proto.\n", __FUNCTION__, 
1093                                   tny_account_get_id (account));
1094                         return FALSE;
1095                 }
1096                 protocol = modest_protocol_registry_get_protocol_by_type (modest_runtime_get_protocol_registry (),
1097                                                                           protocol_type);
1098         }
1099
1100         switch (error->code) {
1101         case TNY_SYSTEM_ERROR_CANCEL:
1102                 /* Don't show waste the user's time by showing him a dialog telling 
1103                  * him that he has just cancelled something: */
1104                 return TRUE;
1105
1106         case TNY_SERVICE_ERROR_PROTOCOL:
1107                 /* Like a BAD from IMAP (protocol error) */
1108         case TNY_SERVICE_ERROR_LOST_CONNECTION:
1109                 /* Lost the connection with the service */
1110         case TNY_SERVICE_ERROR_UNAVAILABLE:
1111                 /* You must be working online for this operation */
1112         case TNY_SERVICE_ERROR_CONNECT:
1113                 if (protocol) {
1114                         prompt = modest_protocol_get_translation (protocol, MODEST_PROTOCOL_TRANSLATION_CONNECT_ERROR, server_name);
1115                 }
1116                 if (!prompt) {
1117                         g_return_val_if_reached (FALSE);
1118                 }
1119                 break;
1120         case TNY_SERVICE_ERROR_AUTHENTICATE:
1121                 /* It seems that there's no better error to show with
1122                  * POP and IMAP because TNY_SERVICE_ERROR_AUTHENTICATE
1123                  * may appear if there's a timeout during auth */
1124                 if (protocol) {
1125                         prompt = modest_protocol_get_translation (protocol, MODEST_PROTOCOL_TRANSLATION_AUTH_ERROR, server_name);
1126                 }
1127                 if (!prompt) {
1128                         g_return_val_if_reached (FALSE);
1129                 }
1130                 break;
1131         case TNY_SERVICE_ERROR_CERTIFICATE:
1132                 /* We'll show the proper dialog later */
1133                 break;
1134
1135         case TNY_SYSTEM_ERROR_MEMORY:
1136                 /* Can't allocate memory for this operation */
1137                 if (modest_tny_account_store_check_disk_full_error ((ModestTnyAccountStore*)self,
1138                                                                     NULL, error, account, NULL))
1139                         retval = FALSE;
1140                 break;
1141         case TNY_SERVICE_ERROR_UNKNOWN:
1142                 return FALSE;
1143         default:
1144                 /* We don't treat this as an error, but as a not handled message. Then,
1145                  * debug message, and return false */
1146                 g_debug ("Unexpected error %d (%s)", error->code, error->message);
1147                 return FALSE;
1148         }
1149
1150
1151         if (error->code == TNY_SERVICE_ERROR_CERTIFICATE)
1152                 retval = modest_platform_run_certificate_confirmation_dialog (server_name,
1153                                                                               error->message);
1154         else if (error->code == TNY_SERVICE_ERROR_AUTHENTICATE ||
1155                  error->code == TNY_SERVICE_ERROR_CONNECT) {
1156                 TnyDevice *device = modest_runtime_get_device ();
1157                 gboolean success;
1158
1159                 /* If we get the connection error after establishing a
1160                    proper connection then do not show the dialog as we
1161                    are probably behind a firewall, or in a network
1162                    with connection issues. We just keep this code to
1163                    detect situations were the user does not enter the
1164                    server info properly */
1165                 success = modest_account_mgr_get_server_account_username_has_succeeded (modest_runtime_get_account_mgr (),
1166                                                                                         tny_account_get_id (account));
1167
1168                 if (!success) {
1169
1170                         modest_platform_run_information_dialog (NULL, prompt, TRUE);
1171
1172                         /* Show the account dialog. Checking the online status
1173                            allows us to minimize the number of times that we
1174                            incorrectly show the dialog */
1175                         if (tny_device_is_online (device))
1176                                 show_wrong_password_dialog (account,
1177                                                             (error->code == TNY_SERVICE_ERROR_CONNECT) ? FALSE : TRUE);
1178                         retval = TRUE;
1179                 }
1180         }
1181
1182         g_debug ("%s: error code %d (%s", __FUNCTION__, error->code, error->message);
1183
1184         if (prompt)
1185                 g_free (prompt);
1186
1187         return retval;
1188 }
1189
1190
1191 static void
1192 modest_tny_account_store_init (gpointer g, gpointer iface_data)
1193 {
1194         TnyAccountStoreIface *klass;
1195
1196         g_return_if_fail (g);
1197
1198         klass = (TnyAccountStoreIface *)g;
1199
1200         klass->get_accounts =
1201                 modest_tny_account_store_get_accounts;
1202         klass->get_cache_dir =
1203                 modest_tny_account_store_get_cache_dir;
1204         klass->get_device =
1205                 modest_tny_account_store_get_device;
1206         klass->alert =
1207                 modest_tny_account_store_alert;
1208         klass->find_account =
1209                 modest_tny_account_store_find_account_by_url;
1210 }
1211
1212 void
1213 modest_tny_account_store_set_get_pass_func (ModestTnyAccountStore *self,
1214                                             ModestTnyGetPassFunc func)
1215 {
1216         /* not implemented, we use signals */
1217         g_printerr ("modest: set_get_pass_func not implemented\n");
1218 }
1219
1220 TnySessionCamel*
1221 modest_tny_account_store_get_session  (TnyAccountStore *self)
1222 {
1223         g_return_val_if_fail (self, NULL);
1224         return MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self)->session;
1225 }
1226
1227 static TnyAccount*
1228 get_tny_account_by (TnyList *accounts,
1229                     ModestTnyAccountStoreQueryType type,
1230                     const gchar *str)
1231 {
1232         TnyIterator *iter = NULL;
1233         gboolean found = FALSE;
1234         TnyAccount *retval = NULL;
1235
1236         g_return_val_if_fail (TNY_IS_LIST(accounts), NULL);
1237
1238         if (tny_list_get_length(accounts) == 0) {
1239                 g_warning ("%s: account list is empty", __FUNCTION__);
1240                 return NULL;
1241         }
1242         
1243         iter = tny_list_create_iterator (accounts);
1244         while (!tny_iterator_is_done (iter) && !found) {
1245                 TnyAccount *tmp_account = NULL;
1246                 const gchar *val = NULL;
1247
1248                 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1249                 if (!TNY_IS_ACCOUNT(tmp_account)) {
1250                         g_warning ("%s: not a valid account", __FUNCTION__);
1251                         tmp_account = NULL;
1252                         break;
1253                 }
1254
1255                 switch (type) {
1256                 case MODEST_TNY_ACCOUNT_STORE_QUERY_ID:
1257                         val = tny_account_get_id (tmp_account);
1258                         break;
1259                 case MODEST_TNY_ACCOUNT_STORE_QUERY_URL:
1260                         val = tny_account_get_url_string (tmp_account);
1261                         break;
1262                 }
1263                 
1264                 if (type == MODEST_TNY_ACCOUNT_STORE_QUERY_URL && 
1265                     tny_account_matches_url_string (tmp_account, str)) {
1266                         retval = g_object_ref (tmp_account);
1267                         found = TRUE;
1268                 } else {
1269                         if (val && str && strcmp (val, str) == 0) {
1270                                 retval = g_object_ref (tmp_account);
1271                                 found = TRUE;
1272                         }
1273                 }
1274                 g_object_unref (tmp_account);
1275                 tny_iterator_next (iter);
1276         }
1277         g_object_unref (iter);
1278
1279         return retval;
1280 }
1281
1282 TnyAccount*
1283 modest_tny_account_store_get_tny_account_by (ModestTnyAccountStore *self, 
1284                                              ModestTnyAccountStoreQueryType type,
1285                                              const gchar *str)
1286 {
1287         TnyAccount *account = NULL;
1288         ModestTnyAccountStorePrivate *priv;     
1289         
1290         g_return_val_if_fail (self, NULL);
1291         g_return_val_if_fail (str, NULL);
1292         
1293         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1294         
1295         /* Search in store accounts */
1296         account = get_tny_account_by (priv->store_accounts, type, str);
1297
1298         /* If we already found something, no need to search the transport accounts */
1299         if (!account) {
1300                 account = get_tny_account_by (priv->transport_accounts, type, str);
1301
1302                 /* If we already found something, no need to search the
1303                    per-account outbox accounts */
1304                 if (!account)
1305                         account = get_tny_account_by (priv->store_accounts_outboxes, type, str);
1306         }
1307
1308         /* Warn if nothing was found. This is generally unusual. */
1309         if (!account) {
1310                 g_warning("%s: Failed to find account with %s=%s\n", 
1311                           __FUNCTION__, 
1312                           (type == MODEST_TNY_ACCOUNT_STORE_QUERY_ID) ? "ID" : "URL",                     
1313                           str);
1314         }
1315
1316         /* Returns a new reference to the account if found */   
1317         return account;
1318 }
1319
1320
1321 TnyAccount*
1322 modest_tny_account_store_get_server_account (ModestTnyAccountStore *self,
1323                                              const gchar *account_name,
1324                                              TnyAccountType type)
1325 {
1326         ModestTnyAccountStorePrivate *priv = NULL;
1327         TnyAccount *retval = NULL;
1328         TnyList *account_list = NULL;
1329         TnyIterator *iter = NULL;
1330         gboolean found;
1331
1332         g_return_val_if_fail (self, NULL);
1333         g_return_val_if_fail (account_name, NULL);
1334         g_return_val_if_fail (type == TNY_ACCOUNT_TYPE_STORE || 
1335                               type == TNY_ACCOUNT_TYPE_TRANSPORT,
1336                               NULL);
1337         
1338         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1339
1340         account_list = (type == TNY_ACCOUNT_TYPE_STORE) ? 
1341                 priv->store_accounts : 
1342                 priv->transport_accounts;
1343
1344         if (!account_list) {
1345                 g_printerr ("%s: No server accounts of type %s\n", __FUNCTION__, 
1346                         (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport");
1347                 return NULL;
1348         }
1349         
1350         /* Look for the server account */
1351         found = FALSE;
1352         iter = tny_list_create_iterator (account_list);
1353         while (!tny_iterator_is_done (iter) && !found) {
1354                 const gchar *modest_acc_name;
1355                 TnyAccount *tmp_account;
1356
1357                 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1358                 modest_acc_name = 
1359                         modest_tny_account_get_parent_modest_account_name_for_server_account (tmp_account);
1360                 
1361                 if (account_name && modest_acc_name && !strcmp (account_name, modest_acc_name)) {
1362                         found = TRUE;
1363                         retval = g_object_ref (tmp_account);
1364                 }
1365                 /* Free and continue */
1366                 g_object_unref (tmp_account);
1367                 tny_iterator_next (iter);
1368         }
1369         g_object_unref (iter);
1370
1371         if (!found) {
1372                 g_printerr ("modest: %s: could not get tny %s account for %s\n." \
1373                             "Number of server accounts of this type=%d\n", __FUNCTION__,
1374                             (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport",
1375                             account_name, tny_list_get_length (account_list));
1376         }
1377
1378         /* Returns a new reference */
1379         return retval;
1380 }
1381
1382 TnyAccount*
1383 modest_tny_account_store_get_smtp_specific_transport_account_for_open_connection (
1384         ModestTnyAccountStore *self, const gchar *account_name)
1385 {
1386         TnyDevice *device;
1387
1388         g_return_val_if_fail (self && MODEST_IS_TNY_ACCOUNT_STORE(self), NULL);
1389         g_return_val_if_fail (account_name, NULL);
1390
1391         /* Get the current connection: */
1392         device = modest_runtime_get_device ();
1393
1394         if (!device) {
1395                 g_warning ("%s: could not get device", __FUNCTION__);
1396                 return NULL;
1397         }
1398                 
1399         if (!tny_device_is_online (device))
1400                 return NULL;
1401         
1402 #ifdef MODEST_HAVE_CONIC
1403         g_return_val_if_fail (TNY_IS_MAEMO_CONIC_DEVICE (device), NULL);
1404         
1405         TnyMaemoConicDevice *maemo_device = TNY_MAEMO_CONIC_DEVICE (device);    
1406         const gchar* iap_id = tny_maemo_conic_device_get_current_iap_id (maemo_device);
1407         /* printf ("DEBUG: %s: iap_id=%s\n", __FUNCTION__, iap_id); */
1408         if (!iap_id)
1409                 return NULL;
1410                 
1411         ConIcIap* connection = tny_maemo_conic_device_get_iap (maemo_device, iap_id);
1412         if (!connection)
1413                 return NULL;
1414                 
1415         const gchar *connection_id = con_ic_iap_get_id (connection);
1416         /* printf ("DEBUG: %s: connection_id=%s\n", __FUNCTION__, connection_id); */
1417         if (!connection_id)
1418                 return NULL;
1419         
1420         /*  Get the connection-specific transport acccount, if any: */
1421         ModestAccountMgr *account_manager = modest_runtime_get_account_mgr ();
1422
1423         /* Check if this account has connection-specific SMTP enabled */
1424         if (!modest_account_mgr_get_use_connection_specific_smtp (account_manager, account_name)) {
1425                 return NULL;
1426         }
1427
1428         gchar* server_account_name = modest_account_mgr_get_connection_specific_smtp (account_manager, 
1429                 connection_id);
1430
1431         /* printf ("DEBUG: %s: server_account_name=%s\n", __FUNCTION__, server_account_name); */
1432         if (!server_account_name) {
1433                 return NULL; /* No connection-specific SMTP server was specified for this connection. */
1434         }
1435
1436         TnyAccount* account = modest_tny_account_store_get_tny_account_by (self, 
1437                                                                            MODEST_TNY_ACCOUNT_STORE_QUERY_ID, 
1438                                                                            server_account_name);
1439
1440         /* printf ("DEBUG: %s: account=%p\n", __FUNCTION__, account); */
1441         g_free (server_account_name);
1442
1443         /* Unref the get()ed object, as required by the tny_maemo_conic_device_get_iap() documentation. */
1444         g_object_unref (connection);
1445
1446         return account;
1447 #else
1448         return NULL; /* TODO: Implement this for GNOME, instead of just Maemo? */
1449 #endif /* MODEST_HAVE_CONIC */
1450 }
1451
1452                                                                  
1453 TnyAccount*
1454 modest_tny_account_store_get_transport_account_for_open_connection (ModestTnyAccountStore *self,
1455                                                                     const gchar *account_name)
1456 {
1457         g_return_val_if_fail (self, NULL);
1458         g_return_val_if_fail (account_name, NULL);
1459
1460         if (!account_name || !self)
1461                 return NULL;
1462         
1463         /*  Get the connection-specific transport acccount, if any: */
1464         /* Note: This gives us a reference: */
1465         TnyAccount *account =
1466                 modest_tny_account_store_get_smtp_specific_transport_account_for_open_connection (self, account_name);
1467                         
1468         /* If there is no connection-specific transport account (the common case), 
1469          * just get the regular transport account: */
1470         if (!account) {
1471                 /* The special local folders don't have transport accounts. */
1472                 if (strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0)
1473                         account = NULL;
1474                 else {
1475                         /* Note: This gives us a reference: */
1476                         account = modest_tny_account_store_get_server_account (self, account_name, 
1477                                                      TNY_ACCOUNT_TYPE_TRANSPORT);
1478                 }
1479         }
1480                         
1481         /* returns a reference. */     
1482         return account;
1483 }
1484
1485 TnyAccount*
1486 modest_tny_account_store_get_local_folders_account (ModestTnyAccountStore *self)
1487 {
1488         TnyAccount *account = NULL;
1489         ModestTnyAccountStorePrivate *priv;
1490         TnyIterator *iter;
1491         gboolean found;
1492
1493         g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1494         
1495         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1496
1497         found = FALSE;
1498         iter = tny_list_create_iterator (priv->store_accounts);
1499         while (!tny_iterator_is_done (iter) && !found) {
1500                 TnyAccount *tmp_account;
1501
1502                 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1503                 if (modest_tny_account_is_virtual_local_folders (tmp_account)) {
1504                         account = g_object_ref (tmp_account);
1505                         found = TRUE;
1506                 }
1507                 g_object_unref (tmp_account);
1508                 tny_iterator_next (iter);
1509         }
1510         g_object_unref (iter);
1511
1512         /* Returns a new reference to the account */
1513         return account;
1514 }
1515
1516 TnyAccount*
1517 modest_tny_account_store_get_mmc_folders_account (ModestTnyAccountStore *self)
1518 {
1519         g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1520         
1521         /* New reference */
1522         return modest_tny_account_store_get_tny_account_by (self, MODEST_TNY_ACCOUNT_STORE_QUERY_ID,
1523                                                             MODEST_MMC_ACCOUNT_ID);
1524
1525 }
1526
1527 /*********************************************************************************/
1528 static void
1529 add_existing_accounts (ModestTnyAccountStore *self)
1530 {
1531         GSList *account_names = NULL, *iter = NULL;
1532         ModestTnyAccountStorePrivate *priv = NULL;
1533         
1534         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1535
1536         /* These are account names, not server_account names */
1537         account_names = modest_account_mgr_account_names (priv->account_mgr, FALSE);
1538
1539         for (iter = account_names; iter != NULL; iter = g_slist_next (iter)) {
1540                 const gchar *account_name = (const gchar*) iter->data;
1541                 
1542                 /* Insert all enabled accounts without notifying */
1543                 if (modest_account_mgr_get_enabled (priv->account_mgr, account_name))
1544                         insert_account (self, account_name, FALSE);
1545         }
1546         modest_account_mgr_free_account_names (account_names);
1547 }
1548
1549 static TnyAccount*
1550 create_tny_account (ModestTnyAccountStore *self,
1551                     const gchar *name,
1552                     TnyAccountType type,
1553                     gboolean notify)
1554 {
1555         TnyAccount *account = NULL;
1556         ModestTnyAccountStorePrivate *priv = NULL;
1557
1558         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1559
1560         account = modest_tny_account_new_from_account (priv->account_mgr,
1561                                                        name, type, 
1562                                                        priv->session,
1563                                                        get_password,
1564                                                        forget_password);
1565
1566         if (account) {
1567                 /* Forget any cached password for the account, so that
1568                    we use a new account if any */
1569                 forget_password_in_memory (self, tny_account_get_id (account));
1570
1571                 /* Set the account store */
1572                 g_object_set_data (G_OBJECT(account), "account_store", self);
1573         } else {
1574                 g_printerr ("modest: failed to create account for %s\n", name);
1575         }
1576
1577         return account;
1578 }
1579
1580 typedef struct _AddOutboxInfo {
1581         ModestTnyAccountStore *account_store;
1582         TnyAccount *transport_account;
1583 } AddOutboxInfo;
1584
1585 static void
1586 add_outbox_from_transport_account_to_global_outbox_get_folders_cb (TnyFolderStore *folder_store,
1587                                                                    gboolean cancelled,
1588                                                                    TnyList *list,
1589                                                                    GError *err,
1590                                                                    gpointer userdata)
1591 {
1592         TnyIterator *iter_folders;
1593         TnyFolder *per_account_outbox;
1594         TnyAccount *local_account = NULL;
1595         AddOutboxInfo *info = (AddOutboxInfo *) userdata;
1596         ModestTnyAccountStorePrivate *priv = NULL;
1597         ModestTnyAccountStore *self;
1598
1599         self = MODEST_TNY_ACCOUNT_STORE (info->account_store);
1600         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1601         
1602         /* Note that this could happen if there is not enough space
1603            available on disk, then the outbox folder could not be
1604            created */
1605         if (tny_list_get_length (list) != 1) {
1606                 g_warning ("%s: could not create outbox folder (%d folders found)", __FUNCTION__,
1607                            tny_list_get_length (list));
1608                 goto frees;
1609         }
1610                         
1611         iter_folders = tny_list_create_iterator (list);
1612         per_account_outbox = TNY_FOLDER (tny_iterator_get_current (iter_folders));
1613         g_object_unref (iter_folders);
1614         g_object_unref (list);
1615
1616         /* Add the outbox of the new per-account-local-outbox account
1617            to the global local merged OUTBOX of the local folders
1618            account */
1619         local_account = modest_tny_account_store_get_local_folders_account (info->account_store);
1620         modest_tny_local_folders_account_add_folder_to_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1621                                                                per_account_outbox);
1622         /* Add the pair to the hash table */
1623         g_hash_table_insert (priv->outbox_of_transport,
1624                              info->transport_account,
1625                              per_account_outbox);
1626         
1627         /* Notify that the local account changed */
1628         g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1629         g_object_unref (local_account);
1630         g_object_unref (per_account_outbox);
1631
1632  frees:
1633         g_object_unref (info->transport_account);
1634         g_slice_free (AddOutboxInfo, info);
1635 }
1636                                                                    
1637
1638 static void
1639 add_outbox_from_transport_account_to_global_outbox (ModestTnyAccountStore *self,
1640                                                     const gchar *account_name,
1641                                                     TnyAccount *transport_account)
1642 {
1643         TnyList *folders = NULL;
1644         TnyAccount *account_outbox = NULL;
1645         ModestTnyAccountStorePrivate *priv = NULL;
1646         AddOutboxInfo *info;
1647
1648         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1649
1650         /* Create per account local outbox */
1651         account_outbox = 
1652                 modest_tny_account_new_for_per_account_local_outbox_folder (priv->account_mgr, 
1653                                                                             account_name, 
1654                                                                             priv->session);
1655
1656         if (!G_IS_OBJECT (account_outbox)) {
1657                 g_warning ("%s: could not create per account local outbox folder", __FUNCTION__);
1658                 return;
1659         }
1660
1661         tny_list_append (priv->store_accounts_outboxes, G_OBJECT (account_outbox));
1662         
1663         /* Get the outbox folder */
1664         folders = tny_simple_list_new ();
1665         info = g_slice_new0 (AddOutboxInfo);
1666         info->account_store = self;
1667         info->transport_account = g_object_ref (transport_account);
1668         tny_folder_store_get_folders_async (TNY_FOLDER_STORE (account_outbox), folders, NULL, FALSE, 
1669                                             add_outbox_from_transport_account_to_global_outbox_get_folders_cb, NULL, (gpointer) info);
1670         g_object_unref (account_outbox);
1671 }
1672
1673 /*
1674  * This function will be used for both adding new accounts and for the
1675  * initialization. In the initialization we do not want to emit
1676  * signals so notify will be FALSE, in the case of account additions
1677  * we do want to notify the observers
1678  */
1679 static void
1680 insert_account (ModestTnyAccountStore *self,
1681                 const gchar *account,
1682                 gboolean is_new)
1683 {
1684         ModestTnyAccountStorePrivate *priv = NULL;
1685         TnyAccount *store_account = NULL, *transport_account = NULL;
1686
1687         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1688
1689         /* Get the server and the transport account */
1690         store_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_STORE, is_new);
1691         if (!store_account || !TNY_IS_ACCOUNT(store_account)) {
1692                 g_warning ("%s: failed to create store account", __FUNCTION__);
1693                 return;
1694         }
1695
1696         transport_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT, is_new);
1697         if (!transport_account || !TNY_IS_ACCOUNT(transport_account)) {
1698                 g_warning ("%s: failed to create transport account", __FUNCTION__);
1699                 g_object_unref (store_account);
1700                 return;
1701         }
1702
1703         /* Add accounts to the lists */
1704         tny_list_append (priv->store_accounts, G_OBJECT (store_account));
1705         tny_list_append (priv->transport_accounts, G_OBJECT (transport_account));
1706
1707         /* Create a new pseudo-account with an outbox for this
1708            transport account and add it to the global outbox
1709            in the local account */
1710         add_outbox_from_transport_account_to_global_outbox (self, account, transport_account);
1711
1712         /* Force the creation of the send queue, this way send queues
1713            will automatically send missing emails when the connections
1714            become active */
1715         /* Notify the observers. We do it after everything is
1716            created */
1717         if (is_new) {
1718                 /* We only have to do this for new accounts, already
1719                    existing accounts at boot time are instantiated by
1720                    modest_tny_account_store_start_send_queues */
1721                 modest_runtime_get_send_queue ((TnyTransportAccount *) transport_account, TRUE);
1722
1723                 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, store_account);
1724                 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, transport_account);
1725         }
1726
1727         /* Frees */
1728         g_object_unref (store_account);
1729         g_object_unref (transport_account);
1730 }
1731
1732 static inline gboolean
1733 only_local_accounts (ModestTnyAccountStore *self)
1734 {
1735         return (modest_tny_account_store_get_num_remote_accounts (self) > 0) ? FALSE : TRUE;
1736 }
1737
1738 static void
1739 on_account_inserted (ModestAccountMgr *acc_mgr, 
1740                      const gchar *account,
1741                      gpointer user_data)
1742 {
1743         gboolean add_specific;
1744
1745         add_specific = only_local_accounts (MODEST_TNY_ACCOUNT_STORE (user_data));
1746
1747         /* Insert the account and notify the observers */
1748         insert_account (MODEST_TNY_ACCOUNT_STORE (user_data), account, TRUE);
1749
1750         /* If it's the first remote account then add the connection
1751            specific SMTP servers as well */
1752         if (add_specific)
1753                 add_connection_specific_transport_accounts (MODEST_TNY_ACCOUNT_STORE (user_data));
1754
1755 }
1756
1757 /* This is the callback of the tny_camel_account_set_online called in
1758    on_account_removed to disconnect the account */
1759 static void
1760 on_account_disconnect_when_removing (TnyCamelAccount *account, 
1761                                      gboolean canceled, 
1762                                      GError *err, 
1763                                      gpointer user_data)
1764 {
1765         ModestTnyAccountStore *self;
1766         ModestTnyAccountStorePrivate *priv;
1767
1768         self = MODEST_TNY_ACCOUNT_STORE (user_data);
1769         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1770
1771         /* Cancel all pending operations */
1772         tny_account_cancel (TNY_ACCOUNT (account));
1773         
1774         /* Unref the extra reference added by get_server_account */
1775         g_object_unref (account);
1776
1777         /* Clear the cache if it's an store account */
1778         if (TNY_IS_STORE_ACCOUNT (account)) {
1779                 tny_store_account_delete_cache (TNY_STORE_ACCOUNT (account));
1780         } else if (TNY_IS_TRANSPORT_ACCOUNT (account)) {
1781                 ModestTnySendQueue* send_queue;
1782                 send_queue = modest_runtime_get_send_queue (TNY_TRANSPORT_ACCOUNT (account), FALSE);
1783                 if (TNY_IS_SEND_QUEUE (send_queue)) {
1784                         if (modest_tny_send_queue_sending_in_progress (send_queue))
1785                                 tny_send_queue_cancel (TNY_SEND_QUEUE (send_queue),
1786                                                        TNY_SEND_QUEUE_CANCEL_ACTION_REMOVE, 
1787                                                        NULL);
1788                         modest_runtime_remove_send_queue (TNY_TRANSPORT_ACCOUNT (account));
1789                 }
1790         }
1791 }
1792
1793 /*
1794  * We use this one for both removing "normal" and "connection
1795  * specific" transport accounts
1796  */
1797 static void
1798 remove_transport_account (ModestTnyAccountStore *self,
1799                           TnyTransportAccount *transport_account)
1800 {
1801         ModestTnyAccountStorePrivate *priv;
1802         TnyFolder *outbox = NULL;
1803         
1804         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1805
1806         /* Remove it from the list of accounts and notify the
1807            observers. Do not need to wait for account
1808            disconnection */
1809         g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 0, transport_account);
1810         tny_list_remove (priv->transport_accounts, (GObject *) transport_account);
1811                 
1812         /* Remove the OUTBOX of the account from the global outbox */
1813         outbox = g_hash_table_lookup (priv->outbox_of_transport, transport_account);
1814
1815         if (TNY_IS_FOLDER (outbox)) {
1816                 TnyAccount *local_account = NULL;
1817                 TnyAccount *outbox_account = tny_folder_get_account (outbox);
1818
1819                 if (outbox_account) {
1820                         tny_list_remove (priv->store_accounts_outboxes, G_OBJECT (outbox_account));
1821                         /* Remove existing emails to send */
1822                         tny_store_account_delete_cache (TNY_STORE_ACCOUNT (outbox_account));
1823                         g_object_unref (outbox_account);
1824                 }
1825
1826                 local_account = modest_tny_account_store_get_local_folders_account (self);
1827                 modest_tny_local_folders_account_remove_folder_from_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1828                                                                             outbox);
1829
1830                 g_hash_table_remove (priv->outbox_of_transport, transport_account);
1831
1832                 /* Notify the change in the local account */
1833                 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1834                 g_object_unref (local_account);
1835         } else {
1836                 g_warning ("Removing a transport account that has no outbox");
1837         }
1838
1839         /* Cancel all pending operations */
1840         tny_account_cancel (TNY_ACCOUNT (transport_account));
1841
1842         /* Disconnect and notify the observers. The callback will free the reference */
1843         tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (transport_account), FALSE,
1844                                       on_account_disconnect_when_removing, self);
1845 }
1846
1847 static gboolean
1848 images_cache_remove_filter (TnyStreamCache *self, const gchar *id, const gchar *account_name)
1849 {
1850         gchar *account_name_with_separator;
1851         gboolean result;
1852         if (account_name == NULL || account_name[0] == '\0')
1853                 return FALSE;
1854
1855         if (id == NULL || id[0] == '\0')
1856                 return FALSE;
1857
1858         account_name_with_separator = g_strconcat (account_name, "__", NULL);
1859
1860         result = (g_str_has_prefix (id, account_name));
1861         g_free (account_name_with_separator);
1862
1863         return result;
1864 }
1865
1866 static void
1867 on_account_removed (ModestAccountMgr *acc_mgr, 
1868                     const gchar *account,
1869                     gpointer user_data)
1870 {
1871         TnyAccount *store_account = NULL, *transport_account = NULL;
1872         ModestTnyAccountStore *self;
1873         ModestTnyAccountStorePrivate *priv;
1874         TnyStreamCache *stream_cache;
1875         
1876         self = MODEST_TNY_ACCOUNT_STORE (user_data);
1877         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1878
1879         /* Get the server and the transport account */
1880         store_account = 
1881                 modest_tny_account_store_get_server_account (self, account, 
1882                                                              TNY_ACCOUNT_TYPE_STORE);
1883         transport_account = 
1884                 modest_tny_account_store_get_server_account (self, account,
1885                                                              TNY_ACCOUNT_TYPE_TRANSPORT);
1886         
1887         /* If there was any problem creating the account, for example,
1888            with the configuration system this could not exist */
1889         if (TNY_IS_STORE_ACCOUNT(store_account)) {
1890                 /* Forget any cached password for the account */
1891                 forget_password_in_memory (self, tny_account_get_id (store_account));
1892
1893                 /* Remove it from the list of accounts and notify the
1894                    observers. Do not need to wait for account
1895                    disconnection */
1896                 tny_list_remove (priv->store_accounts, (GObject *) store_account);
1897                 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 0, store_account);
1898
1899                 /* Cancel all pending operations */
1900                 tny_account_cancel (TNY_ACCOUNT (store_account));
1901
1902                 /* Disconnect before deleting the cache, because the
1903                    disconnection will rewrite the cache to the
1904                    disk */
1905                 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (store_account), FALSE,
1906                                               on_account_disconnect_when_removing, self);
1907         } else {
1908                 g_warning ("%s: no store account for account %s\n", 
1909                            __FUNCTION__, account);
1910         }
1911
1912         /* If there was any problem creating the account, for example,
1913            with the configuration system this could not exist */
1914         if (TNY_IS_TRANSPORT_ACCOUNT(transport_account)) {
1915
1916                 /* Forget any cached password for the account */
1917                 forget_password_in_memory (self, tny_account_get_id (transport_account));
1918
1919                 /* Remove transport account. It'll free the reference
1920                    added by get_server_account */
1921                 remove_transport_account (self, TNY_TRANSPORT_ACCOUNT (transport_account));
1922         } else {
1923                 g_warning ("%s: no transport account for account %s\n", 
1924                            __FUNCTION__, account);
1925         }
1926
1927         /* Remove cached images */
1928         stream_cache = modest_runtime_get_images_cache ();
1929         tny_stream_cache_remove (stream_cache, (TnyStreamCacheRemoveFilter) images_cache_remove_filter, (gpointer) account);
1930
1931         /* If there are no more user accounts then delete the
1932            transport specific SMTP servers */
1933         if (only_local_accounts (self))
1934                 remove_connection_specific_transport_accounts (self);
1935 }
1936
1937 TnyTransportAccount *
1938 modest_tny_account_store_new_connection_specific_transport_account (ModestTnyAccountStore *self,
1939                                                                     const gchar *name)
1940 {
1941         ModestTnyAccountStorePrivate *priv = NULL;
1942         TnyAccount * tny_account = NULL;
1943
1944         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1945
1946         /* Add the account: */
1947         tny_account = 
1948                 modest_tny_account_new_from_server_account_name (priv->account_mgr, 
1949                                                                  priv->session, 
1950                                                                  name,
1951                                                                  get_password,
1952                                                                  forget_password);
1953         if (tny_account) {
1954                 g_object_set_data (G_OBJECT(tny_account), 
1955                                    "account_store", 
1956                                    (gpointer)self);
1957                 g_object_set_data (G_OBJECT(tny_account), 
1958                                    "connection_specific", 
1959                                    GINT_TO_POINTER (TRUE));
1960                 
1961                 tny_list_append (priv->transport_accounts, G_OBJECT (tny_account));
1962                 add_outbox_from_transport_account_to_global_outbox (self, 
1963                                                                     name, 
1964                                                                     tny_account);
1965                 
1966         } else
1967                 g_printerr ("modest: failed to create smtp-specific account for %s\n",
1968                             name);
1969
1970         return TNY_TRANSPORT_ACCOUNT (tny_account);
1971 }
1972
1973 static void 
1974 foreach_free_string(gpointer data,
1975                     gpointer user_data)
1976 {
1977         g_free (data);
1978 }
1979
1980 static void
1981 add_connection_specific_transport_accounts (ModestTnyAccountStore *self)
1982 {
1983         ModestTnyAccountStorePrivate *priv = NULL;
1984         GSList *list_specifics = NULL, *iter = NULL;
1985         GError *err = NULL;
1986
1987         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1988
1989         list_specifics = modest_conf_get_list (modest_runtime_get_conf (),
1990                                                MODEST_CONF_CONNECTION_SPECIFIC_SMTP_LIST,
1991                                                MODEST_CONF_VALUE_STRING, &err);
1992         if (err) {
1993                 g_error_free (err);
1994                 g_return_if_reached ();
1995                 return;
1996         }
1997                                 
1998         /* Look at each connection-specific transport account for the 
1999          * modest account: */
2000         iter = list_specifics;
2001         while (iter) {
2002                 /* The list alternates between the connection name and the transport name: */
2003                 iter = g_slist_next (iter);
2004                 if (iter) {
2005                         const gchar* transport_account_name = (const gchar*) (iter->data);
2006                         TnyTransportAccount * account = NULL;
2007                         account = modest_tny_account_store_new_connection_specific_transport_account (
2008                                 self, transport_account_name);
2009                         if (account)
2010                                 g_object_unref (account);
2011                 }                               
2012                 iter = g_slist_next (iter);
2013         }
2014
2015         /* Free the list */
2016         g_slist_foreach (list_specifics, foreach_free_string, NULL);
2017         g_slist_free (list_specifics);
2018 }
2019
2020 static void
2021 remove_connection_specific_transport_accounts (ModestTnyAccountStore *self)
2022 {
2023         ModestTnyAccountStorePrivate *priv = NULL;
2024         GSList *list_specifics = NULL, *iter = NULL;
2025         GError *err = NULL;
2026
2027         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
2028
2029         err = NULL;
2030         list_specifics = modest_conf_get_list (modest_runtime_get_conf (),
2031                                                MODEST_CONF_CONNECTION_SPECIFIC_SMTP_LIST,
2032                                                MODEST_CONF_VALUE_STRING, &err);
2033         if (err) {
2034                 g_error_free (err);
2035                 g_return_if_reached ();
2036                 return;
2037         }
2038                                 
2039         /* Look at each connection-specific transport account for the 
2040          * modest account: */
2041         iter = list_specifics;
2042         while (iter) {
2043                 /* The list alternates between the connection name and the transport name: */
2044                 iter = g_slist_next (iter);
2045                 if (iter) {
2046                         const gchar* transport_account_name = (const gchar*) (iter->data);
2047                         TnyAccount * account;
2048                         account = modest_tny_account_store_get_server_account (self,
2049                                                                                transport_account_name,
2050                                                                                TNY_ACCOUNT_TYPE_TRANSPORT);
2051
2052                         /* the call will free the reference */
2053                         if (account)
2054                                 remove_transport_account (self, TNY_TRANSPORT_ACCOUNT (account));
2055                 }                               
2056                 iter = g_slist_next (iter);
2057         }
2058
2059         /* Free the list */
2060         g_slist_foreach (list_specifics, foreach_free_string, NULL);
2061         g_slist_free (list_specifics);
2062 }
2063
2064
2065 TnyMsg *
2066 modest_tny_account_store_find_msg_in_outboxes (ModestTnyAccountStore *self, 
2067                                                const gchar *uri,
2068                                                TnyAccount **ac_out)
2069 {
2070         TnyIterator *acc_iter;
2071         ModestTnyAccountStorePrivate *priv;
2072         TnyMsg *msg = NULL;
2073         TnyAccount *msg_account = NULL;
2074
2075         g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
2076         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2077
2078         acc_iter = tny_list_create_iterator (priv->store_accounts_outboxes);
2079         while (!msg && !tny_iterator_is_done (acc_iter)) {
2080                 TnyList *folders = tny_simple_list_new ();
2081                 TnyAccount *account = TNY_ACCOUNT (tny_iterator_get_current (acc_iter));
2082                 TnyIterator *folders_iter = NULL;
2083
2084                 tny_folder_store_get_folders (TNY_FOLDER_STORE (account), folders, NULL, FALSE, NULL);
2085                 folders_iter = tny_list_create_iterator (folders);
2086
2087                 while (msg == NULL && !tny_iterator_is_done (folders_iter)) {
2088                         TnyFolder *folder = TNY_FOLDER (tny_iterator_get_current (folders_iter));
2089                         msg = tny_folder_find_msg (folder, uri, NULL);
2090
2091                         if (msg)
2092                                 msg_account = g_object_ref (account);
2093
2094                         g_object_unref (folder);
2095                         tny_iterator_next (folders_iter);
2096                 }
2097                 g_object_unref (folders_iter);
2098
2099                 g_object_unref (folders);
2100                 g_object_unref (account);
2101                 tny_iterator_next (acc_iter);
2102         }
2103
2104         g_object_unref (acc_iter);
2105
2106         if (ac_out != NULL)
2107                 *ac_out = msg_account;
2108
2109         return msg;
2110 }
2111
2112 TnyTransportAccount *
2113 modest_tny_account_store_get_transport_account_from_outbox_header(ModestTnyAccountStore *self, TnyHeader *header)
2114 {
2115         TnyIterator *acc_iter;
2116         ModestTnyAccountStorePrivate *priv;
2117         TnyTransportAccount *header_acc = NULL;
2118         gchar *msg_id;
2119
2120         g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
2121         g_return_val_if_fail (TNY_IS_HEADER (header), NULL);
2122         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2123         msg_id = modest_tny_send_queue_get_msg_id (header);
2124         acc_iter = tny_list_create_iterator (priv->transport_accounts);
2125         while (!header_acc && !tny_iterator_is_done (acc_iter)) {
2126                 TnyTransportAccount *account = TNY_TRANSPORT_ACCOUNT (tny_iterator_get_current (acc_iter));
2127                 ModestTnySendQueue *send_queue;
2128                 ModestTnySendQueueStatus status;
2129                 send_queue = modest_runtime_get_send_queue(TNY_TRANSPORT_ACCOUNT(account), TRUE);
2130                 if (TNY_IS_SEND_QUEUE (send_queue)) {
2131                         status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2132                         if (status != MODEST_TNY_SEND_QUEUE_UNKNOWN)
2133                                 header_acc = g_object_ref(account);
2134                 }
2135                 g_object_unref (account);
2136                 tny_iterator_next (acc_iter);
2137         }
2138         g_object_unref(acc_iter);
2139         g_free (msg_id);
2140
2141         /* New reference */
2142         return header_acc;
2143 }
2144
2145 typedef struct {
2146         ModestTnyAccountStore *account_store;
2147         ModestTnyAccountStoreShutdownCallback callback;
2148         gpointer userdata;
2149         gint pending;
2150 } ShutdownOpData;
2151
2152 static void
2153 account_shutdown_callback (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer userdata)
2154 {
2155         ShutdownOpData *op_data = (ShutdownOpData *) userdata;
2156         op_data->pending--;
2157         if (op_data->pending == 0) {
2158                 if (op_data->callback)
2159                         op_data->callback (op_data->account_store, op_data->userdata);
2160                 g_object_unref (op_data->account_store);
2161                 g_free (op_data);
2162         }
2163 }
2164
2165 static void
2166 account_shutdown (TnyAccount *account, ShutdownOpData *op_data)
2167 {
2168         g_return_if_fail (account && TNY_IS_ACCOUNT(account));
2169
2170         if (TNY_IS_STORE_ACCOUNT (account) && 
2171             !modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
2172                 op_data->pending--;
2173                 return;
2174         }
2175
2176         /* Disconnect account */
2177         tny_camel_account_set_online (TNY_CAMEL_ACCOUNT(account), FALSE, 
2178                                       account_shutdown_callback, op_data);
2179
2180 }
2181
2182
2183 void
2184 modest_tny_account_store_shutdown (ModestTnyAccountStore *self,
2185                                    ModestTnyAccountStoreShutdownCallback callback,
2186                                    gpointer userdata)
2187 {
2188         gint num_accounts;
2189         ShutdownOpData *op_data;
2190         ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2191
2192         /* Get references */
2193         num_accounts = 0;
2194         if (priv->store_accounts)
2195                 num_accounts += tny_list_get_length (priv->store_accounts);
2196         if (priv->transport_accounts)
2197                 num_accounts += tny_list_get_length (priv->transport_accounts);
2198
2199         /* Create the helper object */
2200         op_data = g_new0 (ShutdownOpData, 1);
2201         op_data->callback = callback;
2202         op_data->userdata = userdata;
2203         op_data->pending = num_accounts;
2204         op_data->account_store = g_object_ref (self);
2205
2206         /* Force the TnyDevice to be offline. This way new
2207            undesired connections won't be initiated */
2208         tny_device_force_offline (priv->device);
2209
2210         /* Destroy all accounts. Disconnect all accounts before they are destroyed */
2211         if (priv->store_accounts) {
2212                 tny_list_foreach (priv->store_accounts, (GFunc)account_shutdown, op_data);
2213         }
2214
2215         if (priv->transport_accounts) {
2216                 tny_list_foreach (priv->transport_accounts, (GFunc)account_shutdown, op_data);
2217         }
2218
2219         if (op_data->pending == 0) {
2220                 if (op_data->callback)
2221                         op_data->callback (op_data->account_store, op_data->userdata);
2222                 g_object_unref (op_data->account_store);
2223                 g_free (op_data);
2224         }
2225 }
2226
2227 gboolean 
2228 modest_tny_account_store_is_shutdown (ModestTnyAccountStore *self)
2229 {
2230         ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2231         TnyIterator *iter;
2232         gboolean found;
2233
2234         found = FALSE;
2235
2236         for (iter = tny_list_create_iterator (priv->store_accounts);
2237              !found && !tny_iterator_is_done (iter);
2238              tny_iterator_next (iter)) {
2239                 TnyAccount *account;
2240
2241                 account = (TnyAccount *) tny_iterator_get_current (iter);
2242                 if (TNY_IS_ACCOUNT (account)) {
2243                         found = (tny_account_get_connection_status (account) == TNY_CONNECTION_STATUS_CONNECTED) ||
2244                                 (tny_account_get_connection_status (account) == TNY_CONNECTION_STATUS_RECONNECTING);
2245                 }
2246                 g_object_unref (account);
2247         }
2248         g_object_unref (iter);
2249
2250         if (found)
2251                 return !found;
2252
2253         for (iter = tny_list_create_iterator (priv->transport_accounts);
2254              !found && !tny_iterator_is_done (iter);
2255              tny_iterator_next (iter)) {
2256                 TnyAccount *account;
2257
2258                 account = (TnyAccount *) tny_iterator_get_current (iter);
2259                 if (TNY_IS_ACCOUNT (account)) {
2260                         found = (tny_account_get_connection_status (account) == TNY_CONNECTION_STATUS_CONNECTED) ||
2261                                 (tny_account_get_connection_status (account) == TNY_CONNECTION_STATUS_RECONNECTING);
2262                 }
2263                 g_object_unref (account);
2264         }
2265         g_object_unref (iter);
2266
2267         return !found;
2268
2269 }
2270
2271
2272 gboolean 
2273 modest_tny_account_store_is_send_mail_blocked (ModestTnyAccountStore *self)
2274 {
2275         ModestTnyAccountStorePrivate *priv;
2276
2277         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
2278
2279         return priv->send_mail_blocked;
2280 }
2281
2282 void 
2283 modest_tny_account_store_set_send_mail_blocked (ModestTnyAccountStore *self, 
2284                                                 gboolean blocked)
2285 {
2286         ModestTnyAccountStorePrivate *priv;
2287
2288         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
2289
2290         priv->send_mail_blocked = blocked;
2291 }
2292
2293 static void
2294 count_remote_accounts (gpointer data, gpointer user_data)
2295 {
2296         TnyFolderStore *account = TNY_FOLDER_STORE (data);
2297         gint *count = (gint *) user_data;
2298
2299         if (modest_tny_folder_store_is_remote (account))
2300                 (*count)++;
2301 }
2302
2303 guint
2304 modest_tny_account_store_get_num_remote_accounts (ModestTnyAccountStore *self)
2305 {
2306         ModestTnyAccountStorePrivate *priv;
2307         gint count = 0;
2308
2309         g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), 0);
2310
2311         /* Count remote accounts */
2312         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2313         tny_list_foreach (priv->store_accounts, (GFunc) count_remote_accounts, &count);
2314
2315         return count;
2316 }
2317
2318 static void
2319 init_send_queue (TnyAccount *account, gpointer user_data)
2320 {
2321         modest_runtime_get_send_queue ((TnyTransportAccount *) account, TRUE);
2322 }
2323
2324 void
2325 modest_tny_account_store_start_send_queues (ModestTnyAccountStore *self)
2326 {
2327         ModestTnyAccountStorePrivate *priv;
2328         TnyList *tmp;
2329
2330         g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self));
2331
2332         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2333
2334         /* We need to create a copy of the list because if the send
2335            queues are created they'll directly access to the TnyList
2336            of transport accounts, and thus we'll end up blocked in the
2337            mutex the TnyList uses to synchronize accesses */
2338         tmp = tny_list_copy (priv->transport_accounts);
2339
2340         /* Just instantiate them. They'll begin to listen for
2341            connection changes to send messages ASAP */
2342         tny_list_foreach (tmp, (GFunc) init_send_queue, NULL);
2343         g_object_unref (tmp);
2344 }
2345
2346
2347 gboolean
2348 modest_tny_account_store_check_disk_full_error (ModestTnyAccountStore *self,
2349                                                 GtkWidget *parent_window,
2350                                                 GError *err,
2351                                                 TnyAccount *account,
2352                                                 const gchar *alternate)
2353 {
2354         if (err == NULL)
2355                 return FALSE;
2356
2357         if (modest_tny_account_store_is_disk_full_error (self, err, account)) {
2358                 gboolean is_mcc = modest_tny_account_is_memory_card_account (account);
2359                 if (is_mcc && alternate) {
2360                         modest_platform_information_banner (parent_window, NULL, alternate);
2361                 } else {
2362                         gchar *msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
2363                         modest_platform_information_banner (parent_window, NULL, msg);
2364                         g_free (msg);
2365                 }
2366         } else if (err->code == TNY_SYSTEM_ERROR_MEMORY)
2367                 /* If the account was created in memory full
2368                    conditions then tinymail won't be able to
2369                    connect so it'll return this error code */
2370                 modest_platform_information_banner (parent_window,
2371                                                     NULL, _("emev_ui_imap_inbox_select_error"));
2372         else
2373                 return FALSE;
2374
2375         return TRUE;
2376 }
2377
2378 gboolean
2379 modest_tny_account_store_is_disk_full_error (ModestTnyAccountStore *self,
2380                                              GError *error,
2381                                              TnyAccount *account)
2382 {
2383         gboolean enough_free_space = TRUE;
2384         GnomeVFSURI *cache_dir_uri;
2385         const gchar *cache_dir = NULL;
2386         GnomeVFSFileSize free_space;
2387
2388         /* Cache dir is different in case we're using an external storage (like MMC account) */
2389         if (account && modest_tny_account_is_memory_card_account (account))
2390                 cache_dir = g_getenv (MODEST_MMC1_VOLUMEPATH_ENV);
2391
2392         /* Get the default local cache dir */
2393         if (!cache_dir)
2394                 cache_dir = tny_account_store_get_cache_dir ((TnyAccountStore *) self);
2395
2396         cache_dir_uri = gnome_vfs_uri_new (cache_dir);
2397         if (cache_dir_uri) {
2398                 if (gnome_vfs_get_volume_free_space (cache_dir_uri, &free_space) == GNOME_VFS_OK) {
2399                         if (free_space < MODEST_TNY_ACCOUNT_STORE_MIN_FREE_SPACE)
2400                                 enough_free_space = FALSE;
2401                 }
2402                 gnome_vfs_uri_unref (cache_dir_uri);
2403         }
2404
2405         if ((error->code == TNY_SYSTEM_ERROR_MEMORY ||
2406              /* When asking for a mail and no space left on device
2407                 tinymail returns this error */
2408              error->code == TNY_SERVICE_ERROR_MESSAGE_NOT_AVAILABLE ||
2409              /* When the folder summary could not be read or
2410                 written */
2411              error->code == TNY_IO_ERROR_WRITE ||
2412              error->code == TNY_IO_ERROR_READ) &&
2413             !enough_free_space) {
2414                 return TRUE;
2415         } else {
2416                 return FALSE;
2417         }
2418 }
2419
2420 void
2421 modest_tny_account_store_reset_attempt_count (ModestTnyAccountStore *self,
2422                                               TnyAccount *account)
2423 {
2424         ModestTnyAccountStorePrivate *priv;
2425         PwdAttempt *attempt;
2426
2427         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
2428
2429         /* Reset the count */
2430         attempt = g_hash_table_lookup (priv->password_hash, tny_account_get_id (account));
2431         if (attempt) {
2432                 attempt->count = RETRY_ATTEMPTS;
2433                 g_debug ("%s, reseting the attempt count for account %s", __FUNCTION__, tny_account_get_id (account));
2434         }
2435 }