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