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