* this is dirk's version of sergio's patch to only create
[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                 *cancel = FALSE;
712  
713     /* printf("  DEBUG: %s: returning %s\n", __FUNCTION__, pwd); */
714         
715         return pwd;
716 }
717
718 void 
719 modest_tny_account_store_forget_already_asked (ModestTnyAccountStore *self, TnyAccount *account)
720 {
721         g_return_if_fail (account);
722           
723         ModestTnyAccountStorePrivate *priv;
724         gchar *pwd = NULL;
725         gpointer pwd_ptr = NULL;
726         gboolean already_asked = FALSE;
727                 
728         const gchar *server_account_name = tny_account_get_id (account);
729
730         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
731         
732         /* This hash map stores passwords, including passwords that are not stored in gconf. */
733         pwd_ptr = (gpointer)&pwd; /* pwd_ptr so the compiler does not complained about
734                                    * type-punned ptrs...*/
735         already_asked = priv->password_hash && 
736                                 g_hash_table_lookup_extended (priv->password_hash,
737                                                       server_account_name,
738                                                       NULL,
739                                                       (gpointer*)&pwd_ptr);
740
741         if (already_asked) {
742                 g_hash_table_remove (priv->password_hash, server_account_name);         
743                 g_free (pwd);
744                 pwd = NULL;
745         }
746
747         return;
748 }
749
750 /* tinymail calls this if the connection failed due to an incorrect password.
751  * And it seems to call this for any general connection failure. */
752 static void
753 forget_password (TnyAccount *account)
754 {
755         printf ("DEBUG: %s\n", __FUNCTION__);
756         ModestTnyAccountStore *self;
757         ModestTnyAccountStorePrivate *priv;
758         const TnyAccountStore *account_store;
759         gchar *pwd;
760         const gchar *key;
761         
762         account_store = TNY_ACCOUNT_STORE(g_object_get_data (G_OBJECT(account),
763                                                              "account_store"));
764         self = MODEST_TNY_ACCOUNT_STORE (account_store);
765         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
766         key  = tny_account_get_id (account);
767
768         /* Do not remove the key, this will allow us to detect that we
769            have already asked for it at least once */
770         pwd = g_hash_table_lookup (priv->password_hash, key);
771         if (pwd) {
772                 memset (pwd, 0, strlen (pwd));
773                 g_hash_table_insert (priv->password_hash, g_strdup (key), NULL);
774         }
775
776         /* Remove from configuration system */
777         /*
778         modest_account_mgr_unset (priv->account_mgr,
779                                   key, MODEST_ACCOUNT_PASSWORD, TRUE);
780         */
781 }
782
783 static void
784 modest_tny_account_store_finalize (GObject *obj)
785 {
786         ModestTnyAccountStore *self        = MODEST_TNY_ACCOUNT_STORE(obj);
787         ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
788
789         g_free (priv->cache_dir);
790         priv->cache_dir = NULL;
791         
792         if (priv->password_hash) {
793                 g_hash_table_destroy (priv->password_hash);
794                 priv->password_hash = NULL;
795         }
796
797         if (priv->account_settings_dialog_hash) {
798                 g_hash_table_destroy (priv->account_settings_dialog_hash);
799                 priv->account_settings_dialog_hash = NULL;
800         }
801
802         if (priv->outbox_of_transport) {
803                 g_hash_table_destroy (priv->outbox_of_transport);
804                 priv->outbox_of_transport = NULL;
805         }
806
807         modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
808         priv->sighandlers = NULL;       
809
810         if (priv->account_mgr) {
811                 g_object_unref (G_OBJECT(priv->account_mgr));
812                 priv->account_mgr = NULL;
813         }
814
815         if (priv->device) {
816                 g_object_unref (G_OBJECT(priv->device));
817                 priv->device = NULL;
818         }
819
820         /* Destroy all accounts. Disconnect all accounts before they are destroyed */
821         if (priv->store_accounts) {
822                 tny_list_foreach (priv->store_accounts, foreach_account_disconnect, NULL);
823                 g_object_unref (priv->store_accounts);
824                 priv->store_accounts = NULL;
825         }
826
827         if (priv->transport_accounts) {
828                 tny_list_foreach (priv->transport_accounts, foreach_account_disconnect, NULL);
829                 g_object_unref (priv->transport_accounts);
830                 priv->transport_accounts = NULL;
831         }
832
833         if (priv->store_accounts_outboxes) {
834                 g_object_unref (priv->store_accounts_outboxes);
835                 priv->store_accounts_outboxes = NULL;
836         }
837                 
838         if (priv->session) {
839                 camel_object_unref (CAMEL_OBJECT(priv->session));
840                 priv->session = NULL;
841         }
842         
843         G_OBJECT_CLASS(parent_class)->finalize (obj);
844 }
845
846 gboolean 
847 volume_path_is_mounted (const gchar* path)
848 {
849         g_return_val_if_fail (path, FALSE);
850
851         gboolean result = FALSE;
852         gchar * path_as_uri = g_filename_to_uri (path, NULL, NULL);
853         g_return_val_if_fail (path_as_uri, FALSE);
854
855         /* Get the monitor singleton: */
856         GnomeVFSVolumeMonitor *monitor = gnome_vfs_get_volume_monitor();
857
858         /* This seems like a simpler way to do this, but it returns a   
859          * GnomeVFSVolume even if the drive is not mounted: */
860         /*
861         GnomeVFSVolume *volume = gnome_vfs_volume_monitor_get_volume_for_path (monitor, 
862                 MODEST_MCC1_VOLUMEPATH);
863         if (volume) {
864                 gnome_vfs_volume_unref(volume);
865         }
866         */
867
868         /* Get the mounted volumes from the monitor: */
869         GList *list = gnome_vfs_volume_monitor_get_mounted_volumes (monitor);
870         GList *iter = list;
871         for (iter = list; iter; iter = g_list_next (iter)) {
872                 GnomeVFSVolume *volume = (GnomeVFSVolume*)iter->data;
873                 if (volume) {
874                         /*
875                         char *display_name = 
876                                 gnome_vfs_volume_get_display_name (volume);
877                         printf ("volume display name=%s\n", display_name);
878                         g_free (display_name);
879                         */
880                         
881                         char *uri = 
882                                 gnome_vfs_volume_get_activation_uri (volume);
883                         /* printf ("  uri=%s\n", uri); */
884                         if (uri && (strcmp (uri, path_as_uri) == 0))
885                                 result = TRUE;
886
887                         g_free (uri);
888
889                         gnome_vfs_volume_unref (volume);
890                 }
891         }
892
893         g_list_free (list);
894
895         g_free (path_as_uri);
896
897         return result;
898 }
899
900 ModestTnyAccountStore*
901 modest_tny_account_store_new (ModestAccountMgr *account_mgr, 
902                               TnyDevice *device) 
903 {
904         GObject *obj;
905         ModestTnyAccountStorePrivate *priv;
906         TnyAccount *local_account = NULL;
907         
908         g_return_val_if_fail (account_mgr, NULL);
909         g_return_val_if_fail (device, NULL);
910
911         obj  = G_OBJECT(g_object_new(MODEST_TYPE_TNY_ACCOUNT_STORE, NULL));
912         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
913
914         priv->account_mgr = g_object_ref (G_OBJECT(account_mgr));
915         priv->device = g_object_ref (device);
916         
917         priv->session = tny_session_camel_new (TNY_ACCOUNT_STORE(obj));
918         if (!priv->session) {
919                 g_warning ("failed to get TnySessionCamel");
920                 return NULL;
921         }
922
923         /* Set the ui locker */ 
924         tny_session_camel_set_ui_locker (priv->session,  tny_gtk_lockable_new ());
925         
926         /* Connect signals */
927         priv->sighandlers  =  modest_signal_mgr_connect (priv->sighandlers,
928                                                          G_OBJECT(account_mgr), "account_inserted",
929                                                          G_CALLBACK (on_account_inserted), obj);
930         priv->sighandlers  =  modest_signal_mgr_connect (priv->sighandlers,
931                                                          G_OBJECT(account_mgr), "account_changed",
932                                                          G_CALLBACK (on_account_changed), obj);
933         priv->sighandlers  =  modest_signal_mgr_connect (priv->sighandlers,
934                                                          G_OBJECT(account_mgr), "account_removed",
935                                                          G_CALLBACK (on_account_removed), obj);
936
937         /* Create the lists of accounts */
938         priv->store_accounts = tny_simple_list_new ();
939         priv->transport_accounts = tny_simple_list_new ();
940         priv->store_accounts_outboxes = tny_simple_list_new ();
941
942         /* Create the local folders account */
943         local_account = 
944                 modest_tny_account_new_for_local_folders (priv->account_mgr, priv->session, NULL);
945         tny_list_append (priv->store_accounts, G_OBJECT(local_account));
946         g_object_unref (local_account); 
947
948         /* Add the other remote accounts. Do this after adding the
949            local account, because we need to add our outboxes to the
950            global OUTBOX hosted in the local account */
951         add_existing_accounts (MODEST_TNY_ACCOUNT_STORE (obj));
952         
953         /* FIXME: I'm doing this (adding an "if (FALSE)"because this
954            stuff is not working properly and could cause SIGSEVs, for
955            example one send queue will be created for each connection
956            specific SMTP server, so when tinymail asks for the outbox
957            it will return NULL because there is no outbox folder for
958            this specific transport accounts, and it's a must that the
959            send queue returns an outbox */
960         if (FALSE)
961                 /* Add connection-specific transport accounts */
962                 add_connection_specific_transport_accounts (MODEST_TNY_ACCOUNT_STORE(obj));
963         
964         /* This is a singleton, so it does not need to be unrefed. */
965         if (volume_path_is_mounted (MODEST_MCC1_VOLUMEPATH)) {
966                 /* It is mounted: */
967                 add_mmc_account (MODEST_TNY_ACCOUNT_STORE (obj), FALSE /* don't emit the insert signal. */); 
968         }
969         
970         return MODEST_TNY_ACCOUNT_STORE(obj);
971 }
972
973 static void
974 modest_tny_account_store_get_accounts  (TnyAccountStore *self, 
975                                         TnyList *list,
976                                         TnyGetAccountsRequestType request_type)
977 {
978         ModestTnyAccountStorePrivate *priv;
979         
980         g_return_if_fail (self);
981         g_return_if_fail (TNY_IS_LIST(list));
982         
983         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
984         
985         switch (request_type) {
986         case TNY_ACCOUNT_STORE_BOTH:
987                 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
988                 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
989                 break;
990         case TNY_ACCOUNT_STORE_STORE_ACCOUNTS:
991                 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
992                 break;
993         case TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS:
994                 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
995                 break;
996         default:
997                 g_return_if_reached ();
998         }
999
1000         /* Initialize session. Why do we need this ??? */
1001         tny_session_camel_set_initialized (priv->session);
1002 }
1003
1004
1005 static const gchar*
1006 modest_tny_account_store_get_cache_dir (TnyAccountStore *self)
1007 {
1008         ModestTnyAccountStorePrivate *priv;
1009         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1010         
1011         if (!priv->cache_dir)
1012                 priv->cache_dir = g_build_filename (g_get_home_dir(), 
1013                                                     MODEST_DIR, MODEST_CACHE_DIR, NULL);
1014         return priv->cache_dir;
1015 }
1016
1017
1018 /*
1019  * callers need to unref
1020  */
1021 static TnyDevice*
1022 modest_tny_account_store_get_device (TnyAccountStore *self)
1023 {
1024         ModestTnyAccountStorePrivate *priv;
1025
1026         g_return_val_if_fail (self, NULL);
1027         
1028         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1029
1030         if (priv->device)
1031                 return g_object_ref (G_OBJECT(priv->device));
1032         else
1033                 return NULL;
1034 }
1035
1036
1037 static TnyAccount*
1038 modest_tny_account_store_find_account_by_url (TnyAccountStore *self, const gchar* url_string)
1039 {
1040         return modest_tny_account_store_get_tny_account_by (MODEST_TNY_ACCOUNT_STORE (self), 
1041                                                             MODEST_TNY_ACCOUNT_STORE_QUERY_URL,
1042                                                             url_string);
1043 }
1044
1045
1046
1047 static gboolean
1048 modest_tny_account_store_alert (TnyAccountStore *self, 
1049                                 TnyAccount *account, 
1050                                 TnyAlertType type,
1051                                 gboolean question, 
1052                                 const GError *error)
1053 {
1054         ModestTransportStoreProtocol proto =
1055                 MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN; 
1056         const gchar* server_name = NULL;
1057         gchar *prompt = NULL;
1058         gboolean retval;
1059
1060
1061         g_return_val_if_fail (account, FALSE);
1062         g_return_val_if_fail (error, FALSE);
1063         
1064         if ((error->domain != TNY_ACCOUNT_ERROR) && (error->domain != TNY_ACCOUNT_STORE_ERROR))
1065                 return FALSE;
1066         
1067         /* Get the server name: */
1068         server_name = tny_account_get_hostname (account);
1069
1070         if (account) {
1071                 const gchar *proto_name = tny_account_get_proto (account);
1072                 if (proto_name)
1073                         proto = modest_protocol_info_get_transport_store_protocol (proto_name);
1074                 else {
1075                         g_warning("modest: %s: account with id=%s has no proto.\n", __FUNCTION__, 
1076                                   tny_account_get_id (account));
1077                         return FALSE;
1078                 }
1079         }
1080
1081         switch (error->code) {
1082         case TNY_ACCOUNT_STORE_ERROR_CANCEL_ALERT:
1083         case TNY_ACCOUNT_ERROR_TRY_CONNECT_USER_CANCEL:
1084                 /* Don't show waste the user's time by showing him a dialog telling 
1085                  * him that he has just cancelled something: */
1086                 return TRUE;
1087
1088         case TNY_ACCOUNT_ERROR_TRY_CONNECT_HOST_LOOKUP_FAILED:
1089         case TNY_ACCOUNT_ERROR_TRY_CONNECT_SERVICE_UNAVAILABLE:
1090                 /* TODO: Show the appropriate message, depending on whether it's POP or IMAP: */                
1091                 switch (proto) {
1092                 case MODEST_PROTOCOL_STORE_POP:
1093                         prompt = g_strdup_printf (_("emev_ni_ui_pop3_msg_connect_error"),
1094                                                   server_name);
1095                         break;
1096                 case MODEST_PROTOCOL_STORE_IMAP:
1097                         prompt = g_strdup_printf (_("emev_ni_ui_imap_connect_server_error"),
1098                                                   server_name);
1099                         break;
1100                 case MODEST_PROTOCOL_TRANSPORT_SMTP:
1101                         prompt = g_strdup_printf (_("emev_ib_ui_smtp_server_invalid"),
1102                                                   server_name);
1103                         break;
1104                 default:
1105                         g_return_val_if_reached (FALSE);
1106                 }
1107                 break;
1108                 
1109         case TNY_ACCOUNT_ERROR_TRY_CONNECT_AUTHENTICATION_NOT_SUPPORTED:
1110                 /* This is "Secure connection failed", even though the logical
1111                  * ID has _certificate_ in the name: */
1112                 prompt = g_strdup (_("mail_ni_ssl_certificate_error")); 
1113                 break;
1114                         
1115         case TNY_ACCOUNT_ERROR_TRY_CONNECT_CERTIFICATE:
1116                 /* We'll show the proper dialog later */
1117                 break;
1118                 
1119         case TNY_ACCOUNT_ERROR_TRY_CONNECT:
1120                 /* The tinymail camel implementation just sends us this for almost 
1121                  * everything, so we have to guess at the cause.
1122                  * It could be a wrong password, or inability to resolve a hostname, 
1123                  * or lack of network, or incorrect authentication method, or something entirely different: */
1124                 /* TODO: Fix camel to provide specific error codes, and then use the 
1125                  * specific dialog messages from Chapter 12 of the UI spec.
1126                  */
1127         case TNY_ACCOUNT_STORE_ERROR_UNKNOWN_ALERT: 
1128                 return FALSE;                   
1129         default:
1130                 g_return_val_if_reached (FALSE);
1131         }
1132         
1133
1134         if (error->code == TNY_ACCOUNT_ERROR_TRY_CONNECT_CERTIFICATE)
1135                 retval = modest_platform_run_certificate_confirmation_dialog (server_name,
1136                                                                               error->message);
1137         else
1138                 retval = modest_platform_run_alert_dialog (prompt, question);
1139         
1140         if (prompt)
1141                 g_free (prompt);
1142         
1143         return retval;
1144 }
1145
1146
1147 static void
1148 modest_tny_account_store_init (gpointer g, gpointer iface_data)
1149 {
1150         TnyAccountStoreIface *klass;
1151
1152         g_return_if_fail (g);
1153
1154         klass = (TnyAccountStoreIface *)g;
1155
1156         klass->get_accounts_func =
1157                 modest_tny_account_store_get_accounts;
1158         klass->get_cache_dir_func =
1159                 modest_tny_account_store_get_cache_dir;
1160         klass->get_device_func =
1161                 modest_tny_account_store_get_device;
1162         klass->alert_func =
1163                 modest_tny_account_store_alert;
1164         klass->find_account_func =
1165                 modest_tny_account_store_find_account_by_url;
1166 }
1167
1168 void
1169 modest_tny_account_store_set_get_pass_func (ModestTnyAccountStore *self,
1170                                             ModestTnyGetPassFunc func)
1171 {
1172         /* not implemented, we use signals */
1173         g_printerr ("modest: set_get_pass_func not implemented\n");
1174 }
1175
1176 TnySessionCamel*
1177 modest_tny_account_store_get_session  (TnyAccountStore *self)
1178 {
1179         g_return_val_if_fail (self, NULL);
1180         return MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self)->session;
1181 }
1182
1183 static TnyAccount*
1184 get_tny_account_by (TnyList *accounts,
1185                     ModestTnyAccountStoreQueryType type,
1186                     const gchar *str)
1187 {
1188         TnyIterator *iter = NULL;
1189         gboolean found = FALSE;
1190         TnyAccount *retval = NULL;
1191
1192         iter = tny_list_create_iterator (accounts);
1193         while (!tny_iterator_is_done (iter) && !found) {
1194                 TnyAccount *tmp_account = NULL;
1195                 const gchar *val = NULL;
1196
1197                 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1198                 switch (type) {
1199                 case MODEST_TNY_ACCOUNT_STORE_QUERY_ID:
1200                         val = tny_account_get_id (tmp_account);
1201                         break;
1202                 case MODEST_TNY_ACCOUNT_STORE_QUERY_URL:
1203                         val = tny_account_get_url_string (tmp_account);
1204                         break;
1205                 }
1206                 
1207                 if (type == MODEST_TNY_ACCOUNT_STORE_QUERY_URL && 
1208                     tny_account_matches_url_string (tmp_account, str)) {
1209                         retval = g_object_ref (tmp_account);
1210                         found = TRUE;
1211                 } else {
1212                         if (strcmp (val, str) == 0) {
1213                                 retval = g_object_ref (tmp_account);
1214                                 found = TRUE;
1215                         }
1216                 }
1217                 g_object_unref (tmp_account);
1218                 tny_iterator_next (iter);
1219         }
1220         g_object_unref (iter);
1221
1222         return retval;
1223 }
1224
1225 TnyAccount*
1226 modest_tny_account_store_get_tny_account_by (ModestTnyAccountStore *self, 
1227                                              ModestTnyAccountStoreQueryType type,
1228                                              const gchar *str)
1229 {
1230         TnyAccount *account = NULL;
1231         ModestTnyAccountStorePrivate *priv;     
1232         
1233         g_return_val_if_fail (self, NULL);
1234         g_return_val_if_fail (str, NULL);
1235         
1236         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1237         
1238         /* Search in store accounts */
1239         account = get_tny_account_by (priv->store_accounts, type, str);
1240
1241         /* If we already found something, no need to search the transport accounts */
1242         if (!account) {
1243                 account = get_tny_account_by (priv->transport_accounts, type, str);
1244
1245                 /* If we already found something, no need to search the
1246                    per-account outbox accounts */
1247                 if (!account)
1248                         account = get_tny_account_by (priv->store_accounts_outboxes, type, str);
1249         }
1250
1251         /* Warn if nothing was found. This is generally unusual. */
1252         if (!account) {
1253                 g_warning("%s: Failed to find account with %s=%s\n", 
1254                           __FUNCTION__, 
1255                           (type == MODEST_TNY_ACCOUNT_STORE_QUERY_ID) ? "ID" : "URL",                     
1256                           str);
1257         }
1258
1259         /* Returns a new reference to the account if found */   
1260         return account;
1261 }
1262
1263 TnyAccount*
1264 modest_tny_account_store_get_server_account (ModestTnyAccountStore *self,
1265                                              const gchar *account_name,
1266                                              TnyAccountType type)
1267 {
1268         ModestTnyAccountStorePrivate *priv = NULL;
1269         TnyAccount *retval = NULL;
1270         TnyList *account_list = NULL;
1271         TnyIterator *iter = NULL;
1272         gboolean found;
1273
1274         g_return_val_if_fail (self, NULL);
1275         g_return_val_if_fail (account_name, NULL);
1276         g_return_val_if_fail (type == TNY_ACCOUNT_TYPE_STORE || 
1277                               type == TNY_ACCOUNT_TYPE_TRANSPORT,
1278                               NULL);
1279         
1280         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1281
1282         account_list = (type == TNY_ACCOUNT_TYPE_STORE) ? 
1283                 priv->store_accounts : 
1284                 priv->transport_accounts;
1285
1286         if (!account_list) {
1287                 g_printerr ("%s: No server accounts of type %s\n", __FUNCTION__, 
1288                         (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport");
1289                 return NULL;
1290         }
1291         
1292         /* Look for the server account */
1293         found = FALSE;
1294         iter = tny_list_create_iterator (account_list);
1295         while (!tny_iterator_is_done (iter) && !found) {
1296                 const gchar *modest_acc_name;
1297                 TnyAccount *tmp_account;
1298
1299                 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1300                 modest_acc_name = 
1301                         modest_tny_account_get_parent_modest_account_name_for_server_account (tmp_account);
1302                 
1303                 if (!strcmp (account_name, modest_acc_name)) {
1304                         found = TRUE;
1305                         retval = g_object_ref (tmp_account);
1306                 }
1307                 /* Free and continue */
1308                 g_object_unref (tmp_account);
1309                 tny_iterator_next (iter);
1310         }
1311
1312         if (!found) {
1313                 g_printerr ("modest: %s: could not get tny %s account for %s\n." \
1314                             "Number of server accounts of this type=%d\n", __FUNCTION__,
1315                             (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport",
1316                             account_name, tny_list_get_length (account_list));
1317         }
1318
1319         /* Returns a new reference */
1320         return retval;
1321 }
1322
1323 static TnyAccount*
1324 get_smtp_specific_transport_account_for_open_connection (ModestTnyAccountStore *self,
1325         const gchar *account_name)
1326 {
1327         /* Get the current connection: */
1328         TnyDevice *device = modest_runtime_get_device ();
1329         
1330         if (!tny_device_is_online (device))
1331                 return NULL;
1332
1333         g_return_val_if_fail (self, NULL);
1334         
1335         
1336 #ifdef MODEST_PLATFORM_MAEMO
1337         g_assert (TNY_IS_MAEMO_CONIC_DEVICE (device));
1338         TnyMaemoConicDevice *maemo_device = TNY_MAEMO_CONIC_DEVICE (device);    
1339         const gchar* iap_id = tny_maemo_conic_device_get_current_iap_id (maemo_device);
1340         /* printf ("DEBUG: %s: iap_id=%s\n", __FUNCTION__, iap_id); */
1341         if (!iap_id)
1342                 return NULL;
1343                 
1344         ConIcIap* connection = tny_maemo_conic_device_get_iap (maemo_device, iap_id);
1345         if (!connection)
1346                 return NULL;
1347                 
1348         const gchar *connection_name = con_ic_iap_get_name (connection);
1349         /* printf ("DEBUG: %s: connection_name=%s\n", __FUNCTION__, connection_name); */
1350         if (!connection_name)
1351                 return NULL;
1352         
1353         /*  Get the connection-specific transport acccount, if any: */
1354         ModestAccountMgr *account_manager = modest_runtime_get_account_mgr ();
1355
1356         /* Check if this account has connection-specific SMTP enabled */
1357         if (!modest_account_mgr_get_use_connection_specific_smtp (account_manager, account_name)) {
1358                 return NULL;
1359         }
1360
1361         gchar* server_account_name = modest_account_mgr_get_connection_specific_smtp (account_manager, 
1362                 connection_name);
1363
1364         /* printf ("DEBUG: %s: server_account_name=%s\n", __FUNCTION__, server_account_name); */
1365         if (!server_account_name) {
1366                 return NULL; /* No connection-specific SMTP server was specified for this connection. */
1367         }
1368                 
1369         TnyAccount* account = modest_tny_account_store_get_tny_account_by (self, 
1370                                                                            MODEST_TNY_ACCOUNT_STORE_QUERY_ID, 
1371                                                                            server_account_name);
1372
1373         /* printf ("DEBUG: %s: account=%p\n", __FUNCTION__, account); */
1374         g_free (server_account_name);   
1375
1376         /* Unref the get()ed object, as required by the tny_maemo_conic_device_get_iap() documentation. */
1377         g_object_unref (connection);
1378         
1379         return account;
1380 #else
1381         return NULL; /* TODO: Implement this for GNOME, instead of just Maemo? */
1382 #endif /* MODEST_PLATFORM_MAEMO */
1383 }
1384
1385                                                                  
1386 TnyAccount*
1387 modest_tny_account_store_get_transport_account_for_open_connection (ModestTnyAccountStore *self,
1388                                                                     const gchar *account_name)
1389 {
1390         g_return_val_if_fail (self, NULL);
1391         g_return_val_if_fail (account_name, NULL);
1392
1393         if (!account_name || !self)
1394                 return NULL;
1395         
1396         /*  Get the connection-specific transport acccount, if any: */
1397         /* Note: This gives us a reference: */
1398         TnyAccount *account =
1399                 get_smtp_specific_transport_account_for_open_connection (self, account_name);
1400                         
1401         /* If there is no connection-specific transport account (the common case), 
1402          * just get the regular transport account: */
1403         if (!account) {
1404                 /* The special local folders don't have transport accounts. */
1405                 if (strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0)
1406                         account = NULL;
1407                 else {
1408                         /* Note: This gives us a reference: */
1409                         account = modest_tny_account_store_get_server_account (self, account_name, 
1410                                                      TNY_ACCOUNT_TYPE_TRANSPORT);
1411                 }
1412         }
1413                         
1414         /* returns a reference. */     
1415         return account;
1416 }
1417
1418 TnyAccount*
1419 modest_tny_account_store_get_local_folders_account (ModestTnyAccountStore *self)
1420 {
1421         TnyAccount *account = NULL;
1422         ModestTnyAccountStorePrivate *priv;
1423         TnyIterator *iter;
1424         gboolean found;
1425
1426         g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1427         
1428         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1429
1430         found = FALSE;
1431         iter = tny_list_create_iterator (priv->store_accounts);
1432         while (!tny_iterator_is_done (iter) && !found) {
1433                 TnyAccount *tmp_account;
1434
1435                 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1436                 if (modest_tny_account_is_virtual_local_folders (tmp_account)) {
1437                         account = g_object_ref (tmp_account);
1438                         found = TRUE;
1439                 }
1440                 g_object_unref (tmp_account);
1441                 tny_iterator_next (iter);
1442         }
1443         g_object_unref (iter);
1444
1445         /* Returns a new reference to the account */
1446         return account;
1447 }
1448
1449 TnyAccount*
1450 modest_tny_account_store_get_mmc_folders_account (ModestTnyAccountStore *self)
1451 {
1452         g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1453         
1454         return modest_tny_account_store_get_tny_account_by (self, MODEST_TNY_ACCOUNT_STORE_QUERY_ID,
1455                                                             MODEST_MMC_ACCOUNT_ID);
1456
1457 }
1458
1459 /*********************************************************************************/
1460 static void
1461 add_existing_accounts (ModestTnyAccountStore *self)
1462 {
1463         GSList *account_names = NULL, *iter = NULL;
1464         ModestTnyAccountStorePrivate *priv = NULL;
1465         
1466         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1467
1468         /* These are account names, not server_account names */
1469         account_names = modest_account_mgr_account_names (priv->account_mgr, FALSE);
1470
1471         for (iter = account_names; iter != NULL; iter = g_slist_next (iter)) {
1472                 const gchar *account_name = (const gchar*) iter->data;
1473                 
1474                 /* Insert all enabled accounts without notifying */
1475                 if (modest_account_mgr_get_enabled (priv->account_mgr, account_name))
1476                         insert_account (self, account_name, FALSE);
1477         }
1478         modest_account_mgr_free_account_names (account_names);
1479 }
1480
1481 static TnyAccount*
1482 create_tny_account (ModestTnyAccountStore *self,
1483                     const gchar *name,
1484                     TnyAccountType type)
1485 {
1486         TnyAccount *account = NULL;
1487         ModestTnyAccountStorePrivate *priv = NULL;
1488         
1489         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1490
1491         account = modest_tny_account_new_from_account (priv->account_mgr,
1492                                                        name, type, 
1493                                                        priv->session,
1494                                                        get_password,
1495                                                        forget_password);
1496
1497         if (account) {
1498                 /* Forget any cached password for the account, so that
1499                    we use a new account if any */
1500                 modest_tny_account_store_forget_password_in_memory (self, 
1501                                                                     tny_account_get_id (account));
1502                 /* Set the account store */                             
1503                 g_object_set_data (G_OBJECT(account), "account_store", self);
1504         } else {
1505                 g_printerr ("modest: failed to create account for %s\n", name);
1506         }
1507
1508         return account;
1509 }
1510
1511
1512 static void
1513 add_outbox_from_transport_account_to_global_outbox (ModestTnyAccountStore *self,
1514                                                     const gchar *account_name,
1515                                                     TnyAccount *transport_account)
1516 {
1517         TnyList *folders = NULL;
1518         TnyIterator *iter_folders = NULL;
1519         TnyAccount *local_account = NULL, *account_outbox = NULL;
1520         TnyFolder *per_account_outbox = NULL;
1521         ModestTnyAccountStorePrivate *priv = NULL;
1522
1523         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1524
1525         /* Create per account local outbox */
1526         account_outbox = 
1527                 modest_tny_account_new_for_per_account_local_outbox_folder (priv->account_mgr, 
1528                                                                             account_name, 
1529                                                                             priv->session);
1530         tny_list_append (priv->store_accounts_outboxes, G_OBJECT (account_outbox));
1531
1532         /* Get the outbox folder */
1533         folders = tny_simple_list_new ();
1534         tny_folder_store_get_folders (TNY_FOLDER_STORE (account_outbox), folders, NULL, NULL);
1535         g_assert (tny_list_get_length (folders) == 1);
1536                 
1537         iter_folders = tny_list_create_iterator (folders);
1538         per_account_outbox = TNY_FOLDER (tny_iterator_get_current (iter_folders));
1539         g_object_unref (iter_folders);
1540         g_object_unref (folders);
1541         g_object_unref (account_outbox);
1542
1543         /* Add the outbox of the new per-account-local-outbox account
1544            to the global local merged OUTBOX of the local folders
1545            account */
1546         local_account = modest_tny_account_store_get_local_folders_account (self);
1547         modest_tny_local_folders_account_add_folder_to_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1548                                                                per_account_outbox);
1549         /* Add the pair to the hash table */
1550         g_hash_table_insert (priv->outbox_of_transport,
1551                              transport_account,
1552                              per_account_outbox);
1553         
1554         g_object_unref (local_account);
1555         g_object_unref (per_account_outbox);
1556 }
1557
1558 /*
1559  * This function will be used for both adding new accounts and for the
1560  * initialization. In the initialization we do not want to emit
1561  * signals so notify will be FALSE, in the case of account additions
1562  * we do want to notify the observers
1563  */
1564 static void
1565 insert_account (ModestTnyAccountStore *self,
1566                 const gchar *account,
1567                 gboolean notify)
1568 {
1569         ModestTnyAccountStorePrivate *priv = NULL;
1570         TnyAccount *store_account = NULL, *transport_account = NULL;
1571         
1572         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1573
1574         /* Get the server and the transport account */
1575         store_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_STORE);
1576         transport_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT);
1577
1578         g_assert (store_account);
1579         g_assert (transport_account);
1580
1581         /* Add accounts to the lists */
1582         tny_list_append (priv->store_accounts, G_OBJECT (store_account));
1583         tny_list_append (priv->transport_accounts, G_OBJECT (transport_account));
1584
1585         /* Create a new pseudo-account with an outbox for this
1586            transport account and add it to the global outbox
1587            in the local account */
1588         add_outbox_from_transport_account_to_global_outbox (self, account, transport_account);
1589         
1590         /* Notify the observers. We do it after everything is
1591            created */
1592         if (notify) {
1593                 TnyAccount *local_account = NULL;
1594                 
1595                 /* Notify the observers about the new server & transport accounts */
1596                 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, store_account);   
1597                 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, transport_account);
1598
1599                 /* Notify that the local account changed */
1600                 local_account = modest_tny_account_store_get_local_folders_account (self);
1601                 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1602                 g_object_unref (local_account);
1603         }
1604
1605         /* Frees */
1606         g_object_unref (store_account);
1607         g_object_unref (transport_account);
1608 }
1609
1610 static void
1611 on_account_inserted (ModestAccountMgr *acc_mgr, 
1612                      const gchar *account,
1613                      gpointer user_data)
1614 {
1615         /* Insert the account and notify the observers */
1616         insert_account (MODEST_TNY_ACCOUNT_STORE (user_data), account, TRUE);
1617 }
1618
1619 static void
1620 on_account_removed (ModestAccountMgr *acc_mgr, 
1621                     const gchar *account,
1622                     gpointer user_data)
1623 {
1624         TnyAccount *store_account = NULL, *transport_account = NULL;
1625         ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(user_data);
1626         
1627         /* Get the server and the transport account */
1628         store_account = 
1629                 modest_tny_account_store_get_server_account (self, account, TNY_ACCOUNT_TYPE_STORE);
1630         transport_account = 
1631                 modest_tny_account_store_get_server_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT);
1632
1633         /* If there was any problem creating the account, for example,
1634            with the configuration system this could not exist */
1635         if (store_account) {
1636                 /* Clear the cache */
1637                 tny_store_account_delete_cache (TNY_STORE_ACCOUNT (store_account));
1638
1639                 /* Notify the observers */
1640                 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 0, store_account);
1641                 g_object_unref (store_account);
1642         } else {
1643                 g_warning ("There is no store account for account %s\n", account);
1644         }
1645
1646         /* If there was any problem creating the account, for example,
1647            with the configuration system this could not exist */
1648         if (transport_account) {
1649                 TnyAccount *local_account = NULL;
1650                 TnyFolder *outbox = NULL;
1651                 ModestTnyAccountStorePrivate *priv = NULL;
1652         
1653                 /* Remove the OUTBOX of the account from the global outbox */
1654                 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1655                 outbox = g_hash_table_lookup (priv->outbox_of_transport, transport_account);
1656
1657                 if (TNY_IS_FOLDER (outbox)) {
1658                         local_account = modest_tny_account_store_get_local_folders_account (self);
1659                         modest_tny_local_folders_account_remove_folder_from_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1660                                                                                     outbox);
1661                         g_hash_table_remove (priv->outbox_of_transport, transport_account);
1662
1663                         /* Notify the change in the local account */
1664                         g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1665                         g_object_unref (local_account);
1666                 } else {
1667                         g_warning ("Removing a transport account that has no outbox");
1668                 }
1669
1670                 /* Notify the observers */
1671                 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 0, transport_account);
1672                 g_object_unref (transport_account);
1673         } else {
1674                 g_warning ("There is no transport account for account %s\n", account);
1675         }
1676 }
1677
1678 static void
1679 add_connection_specific_transport_accounts (ModestTnyAccountStore *self)
1680 {
1681         ModestTnyAccountStorePrivate *priv = NULL;
1682         GSList *list_specifics = NULL, *iter = NULL;
1683
1684         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1685
1686         ModestConf *conf = modest_runtime_get_conf ();
1687
1688         GError *err = NULL;
1689         list_specifics = modest_conf_get_list (conf,
1690                                                MODEST_CONF_CONNECTION_SPECIFIC_SMTP_LIST,
1691                                                MODEST_CONF_VALUE_STRING, &err);
1692         if (err) {
1693                 g_printerr ("modest: %s: error getting list: %s\n.", __FUNCTION__, err->message);
1694                 g_error_free (err);
1695                 err = NULL;
1696         }
1697                                 
1698         /* Look at each connection-specific transport account for the 
1699          * modest account: */
1700         iter = list_specifics;
1701         while (iter) {
1702                 /* The list alternates between the connection name and the transport name: */
1703                 iter = g_slist_next (iter);
1704                 if (iter) {
1705                         const gchar* transport_account_name = (const gchar*) (iter->data);
1706                         if (transport_account_name) {
1707                                 TnyAccount * tny_account = NULL;
1708                                 /* Add the account: */
1709                                 tny_account = 
1710                                         modest_tny_account_new_from_server_account_name (priv->account_mgr, 
1711                                                                                          priv->session, 
1712                                                                                          transport_account_name);
1713                                 if (tny_account) {
1714                                         g_object_set_data (G_OBJECT(tny_account), 
1715                                                            "account_store", 
1716                                                            (gpointer)self);
1717
1718                                         tny_list_append (priv->transport_accounts, G_OBJECT (tny_account));
1719                                         g_object_unref (tny_account);
1720                                 } else
1721                                         g_printerr ("modest: failed to create smtp-specific account for %s\n",
1722                                                     transport_account_name);
1723                         }
1724                 }                               
1725                 iter = g_slist_next (iter);
1726         }
1727 }
1728
1729 TnyMsg *
1730 modest_tny_account_store_find_msg_in_outboxes (ModestTnyAccountStore *self, 
1731                                                const gchar *uri,
1732                                                TnyAccount **ac_out)
1733 {
1734         TnyIterator *acc_iter;
1735         ModestTnyAccountStorePrivate *priv;
1736         TnyMsg *msg = NULL;
1737         TnyAccount *msg_account = NULL;
1738
1739         g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1740         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1741
1742         acc_iter = tny_list_create_iterator (priv->store_accounts_outboxes);
1743         while (!msg && !tny_iterator_is_done (acc_iter)) {
1744                 TnyList *folders = tny_simple_list_new ();
1745                 TnyAccount *account = TNY_ACCOUNT (tny_iterator_get_current (acc_iter));
1746                 TnyIterator *folders_iter = NULL;
1747
1748                 tny_folder_store_get_folders (TNY_FOLDER_STORE (account), folders, NULL, NULL);
1749                 folders_iter = tny_list_create_iterator (folders);
1750
1751                 while (msg == NULL && !tny_iterator_is_done (folders_iter)) {
1752                         TnyFolder *folder = TNY_FOLDER (tny_iterator_get_current (folders_iter));
1753                         msg = tny_folder_find_msg (folder, uri, NULL);
1754
1755                         if (msg)
1756                                 msg_account = g_object_ref (account);
1757
1758                         g_object_unref (folder);
1759                         tny_iterator_next (folders_iter);
1760                 }
1761
1762                 g_object_unref (folders);
1763                 g_object_unref (account);
1764                 tny_iterator_next (acc_iter);
1765         }
1766
1767         g_object_unref (acc_iter);
1768
1769         if (ac_out != NULL)
1770                 *ac_out = msg_account;
1771
1772         return msg;
1773 }
1774
1775 TnyTransportAccount *
1776 modest_tny_account_store_get_transport_account_from_outbox_header(ModestTnyAccountStore *self, TnyHeader *header)
1777 {
1778         TnyIterator *acc_iter;
1779         ModestTnyAccountStorePrivate *priv;
1780         TnyTransportAccount *header_acc = NULL;
1781         const gchar *msg_id;
1782
1783         g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1784         g_return_val_if_fail (TNY_IS_HEADER (header), NULL);
1785         priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1786
1787         msg_id = modest_tny_send_queue_get_msg_id (header);
1788         acc_iter = tny_list_create_iterator (priv->transport_accounts);
1789         while (!header_acc && !tny_iterator_is_done (acc_iter)) {
1790                 TnyTransportAccount *account = TNY_TRANSPORT_ACCOUNT (tny_iterator_get_current (acc_iter));
1791                 ModestTnySendQueue *send_queue;
1792                 ModestTnySendQueueStatus status;
1793                 send_queue = modest_runtime_get_send_queue(TNY_TRANSPORT_ACCOUNT(account));
1794                 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
1795                 if (status != MODEST_TNY_SEND_QUEUE_UNKNOWN) {
1796                         header_acc = g_object_ref(account);
1797                 }
1798                 g_object_unref (account);
1799                 tny_iterator_next (acc_iter);
1800         }
1801
1802         g_object_unref(acc_iter);
1803         return header_acc;
1804 }