1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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.
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.
31 #include <glib/gi18n.h>
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>
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>
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>
63 #ifdef MODEST_PLATFORM_MAEMO
64 #include <tny-maemo-conic-device.h>
67 #include <libgnomevfs/gnome-vfs-volume-monitor.h>
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);
76 static void on_account_inserted (ModestAccountMgr *acc_mgr,
80 static void add_existing_accounts (ModestTnyAccountStore *self);
82 static void insert_account (ModestTnyAccountStore *self,
86 static void on_account_removed (ModestAccountMgr *acc_mgr,
90 static gchar* get_password (TnyAccount *account,
91 const gchar * prompt_not_used,
94 static void forget_password (TnyAccount *account);
96 static void on_vfs_volume_mounted (GnomeVFSVolumeMonitor *volume_monitor,
97 GnomeVFSVolume *volume,
100 static void on_vfs_volume_unmounted (GnomeVFSVolumeMonitor *volume_monitor,
101 GnomeVFSVolume *volume,
104 static void modest_tny_account_store_forget_password_in_memory (ModestTnyAccountStore *self,
105 const gchar *server_account_name);
107 static void add_connection_specific_transport_accounts (ModestTnyAccountStore *self);
109 /* list my signals */
111 ACCOUNT_CHANGED_SIGNAL,
112 ACCOUNT_INSERTED_SIGNAL,
113 ACCOUNT_REMOVED_SIGNAL,
115 PASSWORD_REQUESTED_SIGNAL,
119 typedef struct _ModestTnyAccountStorePrivate ModestTnyAccountStorePrivate;
120 struct _ModestTnyAccountStorePrivate {
122 GHashTable *password_hash;
123 GHashTable *account_settings_dialog_hash;
124 ModestAccountMgr *account_mgr;
125 TnySessionCamel *session;
130 /* We cache the lists of accounts here */
131 TnyList *store_accounts;
132 TnyList *transport_accounts;
133 TnyList *store_accounts_outboxes;
135 /* Matches transport accounts and outbox folder */
136 GHashTable *outbox_of_transport;
139 #define MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
140 MODEST_TYPE_TNY_ACCOUNT_STORE, \
141 ModestTnyAccountStorePrivate))
144 static GObjectClass *parent_class = NULL;
146 static guint signals[LAST_SIGNAL] = {0};
149 modest_tny_account_store_get_type (void)
151 static GType my_type = 0;
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),
163 (GInstanceInitFunc) modest_tny_account_store_instance_init,
167 static const GInterfaceInfo iface_info = {
168 (GInterfaceInitFunc) modest_tny_account_store_init,
169 NULL, /* interface_finalize */
170 NULL /* interface_data */
173 my_type = g_type_register_static (G_TYPE_OBJECT,
174 "ModestTnyAccountStore",
176 g_type_add_interface_static (my_type, TNY_TYPE_ACCOUNT_STORE,
184 modest_tny_account_store_base_init (gpointer g_class)
186 static gboolean tny_account_store_initialized = FALSE;
188 if (!tny_account_store_initialized) {
190 signals[ACCOUNT_CHANGED_SIGNAL] =
191 g_signal_new ("account_changed",
192 MODEST_TYPE_TNY_ACCOUNT_STORE,
194 G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_changed),
196 g_cclosure_marshal_VOID__OBJECT,
197 G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
199 signals[ACCOUNT_INSERTED_SIGNAL] =
200 g_signal_new ("account_inserted",
201 MODEST_TYPE_TNY_ACCOUNT_STORE,
203 G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_inserted),
205 g_cclosure_marshal_VOID__OBJECT,
206 G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
208 signals[ACCOUNT_REMOVED_SIGNAL] =
209 g_signal_new ("account_removed",
210 MODEST_TYPE_TNY_ACCOUNT_STORE,
212 G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_removed),
214 g_cclosure_marshal_VOID__OBJECT,
215 G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
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), */
223 /* g_cclosure_marshal_VOID__VOID, */
224 /* G_TYPE_NONE, 0); */
226 signals[PASSWORD_REQUESTED_SIGNAL] =
227 g_signal_new ("password_requested",
228 MODEST_TYPE_TNY_ACCOUNT_STORE,
230 G_STRUCT_OFFSET(ModestTnyAccountStoreClass, password_requested),
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,
236 tny_account_store_initialized = TRUE;
242 modest_tny_account_store_class_init (ModestTnyAccountStoreClass *klass)
244 GObjectClass *gobject_class;
245 gobject_class = (GObjectClass*) klass;
247 parent_class = g_type_class_peek_parent (klass);
248 gobject_class->finalize = modest_tny_account_store_finalize;
250 g_type_class_add_private (gobject_class,
251 sizeof(ModestTnyAccountStorePrivate));
255 modest_tny_account_store_instance_init (ModestTnyAccountStore *obj)
257 GnomeVFSVolumeMonitor* monitor = NULL;
258 ModestTnyAccountStorePrivate *priv;
260 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
262 priv->cache_dir = NULL;
263 priv->account_mgr = NULL;
264 priv->session = NULL;
266 priv->sighandlers = NULL;
268 priv->outbox_of_transport = g_hash_table_new_full (g_direct_hash,
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:
277 priv->password_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
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,
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();
290 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
293 G_CALLBACK(on_vfs_volume_mounted),
295 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
296 G_OBJECT(monitor), "volume-unmounted",
297 G_CALLBACK(on_vfs_volume_unmounted),
301 /* disconnect the list of TnyAccounts */
303 account_disconnect (TnyAccount *account)
305 g_return_if_fail (account && TNY_IS_ACCOUNT(account));
306 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT(account), FALSE, NULL, NULL);
310 /* disconnect the list of TnyAccounts */
312 account_verify_last_ref (TnyAccount *account, const gchar *str)
316 g_return_if_fail (account && TNY_IS_ACCOUNT(account));
318 txt = g_strdup_printf ("%s: %s", str ? str : "?", tny_account_get_name(account));
319 modest_runtime_verify_object_last_ref(G_OBJECT(account),txt);
327 foreach_account_append_to_list (gpointer data,
332 list = TNY_LIST (user_data);
333 tny_list_append (list, G_OBJECT (data));
336 /********************************************************************/
337 /* Control the state of the MMC local account */
338 /********************************************************************/
340 /** Only call this if the memory card is really mounted.
343 add_mmc_account(ModestTnyAccountStore *self, gboolean emit_insert_signal)
345 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
346 g_return_if_fail (priv->session);
348 TnyAccount *mmc_account = modest_tny_account_new_for_local_folders (priv->account_mgr,
350 MODEST_MCC1_VOLUMEPATH);
352 /* Add to the list of store accounts */
353 tny_list_append (priv->store_accounts, G_OBJECT (mmc_account));
355 if (emit_insert_signal) {
356 g_signal_emit (G_OBJECT (self),
357 signals [ACCOUNT_INSERTED_SIGNAL],
362 g_object_unref (mmc_account);
366 on_vfs_volume_mounted(GnomeVFSVolumeMonitor *volume_monitor,
367 GnomeVFSVolume *volume,
370 ModestTnyAccountStore *self;
371 ModestTnyAccountStorePrivate *priv;
375 self = MODEST_TNY_ACCOUNT_STORE(user_data);
376 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
378 /* Check whether this was the external MMC1 card: */
379 uri = gnome_vfs_volume_get_activation_uri (volume);
381 if (uri && (!strcmp (uri, MODEST_MCC1_VOLUMEPATH_URI))) {
382 add_mmc_account (self, TRUE /* emit the insert signal. */);
389 on_vfs_volume_unmounted(GnomeVFSVolumeMonitor *volume_monitor,
390 GnomeVFSVolume *volume,
393 ModestTnyAccountStore *self;
394 ModestTnyAccountStorePrivate *priv;
397 self = MODEST_TNY_ACCOUNT_STORE(user_data);
398 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
400 /* Check whether this was the external MMC1 card: */
401 uri = gnome_vfs_volume_get_activation_uri (volume);
402 if (uri && (strcmp (uri, MODEST_MCC1_VOLUMEPATH_URI) == 0)) {
403 TnyAccount *mmc_account = NULL;
404 gboolean found = FALSE;
405 TnyIterator *iter = NULL;
407 iter = tny_list_create_iterator (priv->store_accounts);
408 while (!tny_iterator_is_done (iter) && !found) {
411 account = TNY_ACCOUNT (tny_iterator_get_current (iter));
412 if (modest_tny_account_is_memory_card_account (account)) {
414 mmc_account = g_object_ref (account);
416 g_object_unref (account);
417 tny_iterator_next (iter);
419 g_object_unref (iter);
422 /* Remove from the list */
423 tny_list_remove (priv->store_accounts, G_OBJECT (mmc_account));
425 /* Notify observers */
426 g_signal_emit (G_OBJECT (self),
427 signals [ACCOUNT_REMOVED_SIGNAL],
430 g_object_unref (mmc_account);
432 g_warning ("%s: there was no store account for the unmounted MMC",
440 * modest_tny_account_store_forget_password_in_memory
441 * @self: a TnyAccountStore instance
442 * @account: A server account.
444 * Forget any password stored in memory for this account.
445 * For instance, this should be called when the user has changed the password in the account settings.
448 modest_tny_account_store_forget_password_in_memory (ModestTnyAccountStore *self, const gchar * server_account_name)
450 /* printf ("DEBUG: %s\n", __FUNCTION__); */
451 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
453 if (server_account_name && priv->password_hash) {
454 g_hash_table_remove (priv->password_hash, server_account_name);
459 on_account_changed (ModestAccountMgr *acc_mgr,
460 const gchar *account_name,
461 TnyAccountType account_type,
464 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(user_data);
465 ModestTnyAccountStorePrivate *priv;
466 TnyList* account_list;
467 gboolean found = FALSE;
468 TnyIterator *iter = NULL;
470 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
471 account_list = (account_type == TNY_ACCOUNT_TYPE_STORE ?
472 priv->store_accounts :
473 priv->transport_accounts);
475 iter = tny_list_create_iterator (account_list);
476 while (!tny_iterator_is_done (iter) && !found) {
477 TnyAccount *tny_account;
478 tny_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
480 TnyConnectionStatus conn_status = tny_account_get_connection_status (tny_account);
482 if (conn_status != TNY_CONNECTION_STATUS_RECONNECTING &&
483 conn_status != TNY_CONNECTION_STATUS_INIT) {
484 if (!strcmp (tny_account_get_id (tny_account), account_name)) {
486 modest_tny_account_update_from_account (tny_account);
487 g_signal_emit (G_OBJECT(self), signals[ACCOUNT_CHANGED_SIGNAL], 0, tny_account);
490 g_object_unref (tny_account);
492 tny_iterator_next (iter);
496 g_object_unref (iter);
500 on_account_settings_hide (GtkWidget *widget, gpointer user_data)
502 TnyAccount *account = (TnyAccount*)user_data;
504 /* This is easier than using a struct for the user_data: */
505 ModestTnyAccountStore *self = modest_runtime_get_account_store();
506 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
508 const gchar *modest_account_name =
509 modest_tny_account_get_parent_modest_account_name_for_server_account (account);
510 if (modest_account_name)
511 g_hash_table_remove (priv->account_settings_dialog_hash, modest_account_name);
515 show_password_warning_only ()
517 ModestWindow *main_window =
518 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (), FALSE); /* don't create */
520 /* Show an explanatory temporary banner: */
522 hildon_banner_show_information (
523 GTK_WIDGET(main_window), NULL, _("mcen_ib_username_pw_incorrect"));
525 g_warning ("%s: %s", __FUNCTION__, _("mcen_ib_username_pw_incorrect"));
530 show_wrong_password_dialog (TnyAccount *account)
532 /* This is easier than using a struct for the user_data: */
533 ModestTnyAccountStore *self = modest_runtime_get_account_store();
534 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
535 ModestWindow *main_window;
536 const gchar *modest_account_name;
538 main_window = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (),
539 FALSE); /* don't create */
541 g_warning ("%s: password was wrong; ignoring because no main window", __FUNCTION__);
545 modest_account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
546 if (!modest_account_name) {
547 g_warning ("%s: modest_tny_account_get_parent_modest_account_name_for_server_account() failed.\n",
551 /* Check whether this window is already open,
552 * for instance because of a previous get_password() call:
554 gpointer dialog_as_gpointer = NULL;
555 gboolean found = FALSE;
556 if (priv->account_settings_dialog_hash) {
557 found = g_hash_table_lookup_extended (priv->account_settings_dialog_hash,
558 modest_account_name, NULL, (gpointer*)&dialog_as_gpointer);
560 ModestAccountSettingsDialog *dialog = dialog_as_gpointer;
562 gboolean created_dialog = FALSE;
563 if (!found || !dialog) {
564 dialog = modest_account_settings_dialog_new ();
565 modest_account_settings_dialog_set_account_name (dialog, modest_account_name);
566 modest_account_settings_dialog_switch_to_user_info (dialog);
567 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), GTK_WINDOW (dialog));
569 g_hash_table_insert (priv->account_settings_dialog_hash, g_strdup (modest_account_name), dialog);
571 created_dialog = TRUE;
574 /* Show an explanatory temporary banner: */
575 hildon_banner_show_information (GTK_WIDGET(dialog), NULL, _("mcen_ib_username_pw_incorrect"));
577 if (created_dialog) {
578 /* Forget it when it closes: */
579 g_signal_connect_object (G_OBJECT (dialog), "hide", G_CALLBACK (on_account_settings_hide),
582 /* Show it and delete it when it closes: */
583 modest_maemo_show_dialog_and_forget (GTK_WINDOW (main_window), GTK_DIALOG (dialog));
586 /* Just show it instead of showing it and deleting it when it closes,
587 * though it is probably open already: */
588 gtk_window_present (GTK_WINDOW (dialog));
595 request_password_and_wait (ModestTnyAccountStore *account_store,
596 const gchar* server_account_id,
602 g_signal_emit (G_OBJECT(account_store), signals[PASSWORD_REQUESTED_SIGNAL], 0,
603 server_account_id, /* server_account_name */
604 username, password, cancel, remember);
607 /* This callback will be called by Tinymail when it needs the password
608 * from the user or the account settings.
609 * It can also call forget_password() before calling this,
610 * so that we clear wrong passwords out of our account settings.
611 * Note that TnyAccount here will be the server account. */
613 get_password (TnyAccount *account, const gchar * prompt_not_used, gboolean *cancel)
615 /* TODO: Settting cancel to FALSE does not actually cancel everything.
616 * We still get multiple requests afterwards, so we end up showing the
617 * same dialogs repeatedly.
620 printf ("DEBUG: modest: %s: prompt (not shown) = %s\n", __FUNCTION__, prompt_not_used);
622 g_return_val_if_fail (account, NULL);
624 const TnyAccountStore *account_store = NULL;
625 ModestTnyAccountStore *self = NULL;
626 ModestTnyAccountStorePrivate *priv;
627 gchar *username = NULL;
629 gpointer pwd_ptr = NULL;
630 gboolean already_asked = FALSE;
632 /* Initialize the output parameter: */
636 const gchar *server_account_name = tny_account_get_id (account);
637 account_store = TNY_ACCOUNT_STORE(g_object_get_data (G_OBJECT(account),
640 if (!server_account_name || !account_store) {
641 g_warning ("modest: %s: could not retrieve account_store for account %s",
642 __FUNCTION__, server_account_name ? server_account_name : "<NULL>");
649 self = MODEST_TNY_ACCOUNT_STORE (account_store);
650 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
652 /* This hash map stores passwords, including passwords that are not stored in gconf. */
653 /* Is it in the hash? if it's already there, it must be wrong... */
654 pwd_ptr = (gpointer)&pwd; /* pwd_ptr so the compiler does not complained about
655 * type-punned ptrs...*/
656 already_asked = priv->password_hash &&
657 g_hash_table_lookup_extended (priv->password_hash,
660 (gpointer*)&pwd_ptr);
662 printf ("DEBUG: modest: %s: Already asked = %d\n", __FUNCTION__, already_asked);
664 /* If the password is not already there, try ModestConf */
665 if (!already_asked) {
666 pwd = modest_account_mgr_get_server_account_password (priv->account_mgr,
667 server_account_name);
668 g_hash_table_insert (priv->password_hash, g_strdup (server_account_name), g_strdup (pwd));
671 /* If it was already asked, it must have been wrong, so ask again */
672 if (already_asked || !pwd || strlen(pwd) == 0) {
673 /* As per the UI spec, if no password was set in the account settings,
674 * ask for it now. But if the password is wrong in the account settings,
675 * then show a banner and the account settings dialog so it can be corrected:
677 const gboolean settings_have_password =
678 modest_account_mgr_get_server_account_has_password (priv->account_mgr, server_account_name);
679 printf ("DEBUG: modest: %s: settings_have_password=%d\n", __FUNCTION__, settings_have_password);
680 if (settings_have_password) {
681 /* The password must be wrong, so show the account settings dialog so it can be corrected: */
682 show_wrong_password_dialog (account);
690 /* we don't have it yet. Get the password from the user */
691 const gchar* account_id = tny_account_get_id (account);
692 gboolean remember = FALSE;
696 /* Show an info banner, before we show the protected password dialog: */
697 show_password_warning_only();
700 request_password_and_wait (self, account_id,
701 &username, &pwd, cancel, &remember);
704 /* The password will be returned as the result,
705 * but we need to tell tinymail about the username too: */
706 tny_account_set_user (account, username);
708 /* Do not save the password in gconf, because
709 * the UI spec says "The password will never
710 * be saved in the account": */
712 /* We need to dup the string even knowing that
713 it's already a dup of the contents of an
714 entry, because it if it's wrong, then camel
716 g_hash_table_insert (priv->password_hash, g_strdup (server_account_name), g_strdup(pwd));
718 g_hash_table_remove (priv->password_hash, server_account_name);
730 /* printf(" DEBUG: %s: returning %s\n", __FUNCTION__, pwd); */
736 modest_tny_account_store_forget_already_asked (ModestTnyAccountStore *self, TnyAccount *account)
738 g_return_if_fail (account);
740 ModestTnyAccountStorePrivate *priv;
742 gpointer pwd_ptr = NULL;
743 gboolean already_asked = FALSE;
745 const gchar *server_account_name = tny_account_get_id (account);
747 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
749 /* This hash map stores passwords, including passwords that are not stored in gconf. */
750 pwd_ptr = (gpointer)&pwd; /* pwd_ptr so the compiler does not complained about
751 * type-punned ptrs...*/
752 already_asked = priv->password_hash &&
753 g_hash_table_lookup_extended (priv->password_hash,
756 (gpointer*)&pwd_ptr);
759 g_hash_table_remove (priv->password_hash, server_account_name);
767 /* tinymail calls this if the connection failed due to an incorrect password.
768 * And it seems to call this for any general connection failure. */
770 forget_password (TnyAccount *account)
772 printf ("DEBUG: %s\n", __FUNCTION__);
773 ModestTnyAccountStore *self;
774 ModestTnyAccountStorePrivate *priv;
775 const TnyAccountStore *account_store;
779 account_store = TNY_ACCOUNT_STORE(g_object_get_data (G_OBJECT(account),
781 self = MODEST_TNY_ACCOUNT_STORE (account_store);
782 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
783 key = tny_account_get_id (account);
785 /* Do not remove the key, this will allow us to detect that we
786 have already asked for it at least once */
787 pwd = g_hash_table_lookup (priv->password_hash, key);
789 memset (pwd, 0, strlen (pwd));
790 g_hash_table_insert (priv->password_hash, g_strdup (key), NULL);
793 /* Remove from configuration system */
795 modest_account_mgr_unset (priv->account_mgr,
796 key, MODEST_ACCOUNT_PASSWORD, TRUE);
801 modest_tny_account_store_finalize (GObject *obj)
803 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(obj);
804 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
806 g_free (priv->cache_dir);
807 priv->cache_dir = NULL;
809 if (priv->password_hash) {
810 g_hash_table_destroy (priv->password_hash);
811 priv->password_hash = NULL;
814 if (priv->account_settings_dialog_hash) {
815 g_hash_table_destroy (priv->account_settings_dialog_hash);
816 priv->account_settings_dialog_hash = NULL;
819 if (priv->outbox_of_transport) {
820 g_hash_table_destroy (priv->outbox_of_transport);
821 priv->outbox_of_transport = NULL;
824 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
825 priv->sighandlers = NULL;
827 if (priv->account_mgr) {
828 g_object_unref (G_OBJECT(priv->account_mgr));
829 priv->account_mgr = NULL;
833 g_object_unref (G_OBJECT(priv->device));
837 /* Destroy all accounts. Disconnect all accounts before they are destroyed */
838 if (priv->store_accounts) {
839 tny_list_foreach (priv->store_accounts, (GFunc)account_disconnect, NULL);
840 tny_list_foreach (priv->store_accounts, (GFunc)account_verify_last_ref, "store");
841 g_object_unref (priv->store_accounts);
842 priv->store_accounts = NULL;
845 if (priv->transport_accounts) {
846 tny_list_foreach (priv->transport_accounts, (GFunc)account_disconnect, NULL);
847 tny_list_foreach (priv->transport_accounts, (GFunc)account_verify_last_ref, "transport");
848 g_object_unref (priv->transport_accounts);
849 priv->transport_accounts = NULL;
852 if (priv->store_accounts_outboxes) {
853 g_object_unref (priv->store_accounts_outboxes);
854 priv->store_accounts_outboxes = NULL;
858 camel_object_unref (CAMEL_OBJECT(priv->session));
859 priv->session = NULL;
862 G_OBJECT_CLASS(parent_class)->finalize (obj);
866 volume_path_is_mounted (const gchar* path)
868 g_return_val_if_fail (path, FALSE);
870 gboolean result = FALSE;
871 gchar * path_as_uri = g_filename_to_uri (path, NULL, NULL);
872 g_return_val_if_fail (path_as_uri, FALSE);
874 /* Get the monitor singleton: */
875 GnomeVFSVolumeMonitor *monitor = gnome_vfs_get_volume_monitor();
877 /* This seems like a simpler way to do this, but it returns a
878 * GnomeVFSVolume even if the drive is not mounted: */
880 GnomeVFSVolume *volume = gnome_vfs_volume_monitor_get_volume_for_path (monitor,
881 MODEST_MCC1_VOLUMEPATH);
883 gnome_vfs_volume_unref(volume);
887 /* Get the mounted volumes from the monitor: */
888 GList *list = gnome_vfs_volume_monitor_get_mounted_volumes (monitor);
890 for (iter = list; iter; iter = g_list_next (iter)) {
891 GnomeVFSVolume *volume = (GnomeVFSVolume*)iter->data;
895 gnome_vfs_volume_get_display_name (volume);
896 printf ("volume display name=%s\n", display_name);
897 g_free (display_name);
901 gnome_vfs_volume_get_activation_uri (volume);
902 /* printf (" uri=%s\n", uri); */
903 if (uri && (strcmp (uri, path_as_uri) == 0))
908 gnome_vfs_volume_unref (volume);
914 g_free (path_as_uri);
919 ModestTnyAccountStore*
920 modest_tny_account_store_new (ModestAccountMgr *account_mgr,
924 ModestTnyAccountStorePrivate *priv;
925 TnyAccount *local_account = NULL;
927 g_return_val_if_fail (account_mgr, NULL);
928 g_return_val_if_fail (device, NULL);
930 obj = G_OBJECT(g_object_new(MODEST_TYPE_TNY_ACCOUNT_STORE, NULL));
931 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
933 priv->account_mgr = g_object_ref (G_OBJECT(account_mgr));
934 priv->device = g_object_ref (device);
936 priv->session = tny_session_camel_new (TNY_ACCOUNT_STORE(obj));
937 if (!priv->session) {
938 g_warning ("failed to get TnySessionCamel");
942 /* Set the ui locker */
943 tny_session_camel_set_ui_locker (priv->session, tny_gtk_lockable_new ());
945 /* Connect signals */
946 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
947 G_OBJECT(account_mgr), "account_inserted",
948 G_CALLBACK (on_account_inserted), obj);
949 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
950 G_OBJECT(account_mgr), "account_changed",
951 G_CALLBACK (on_account_changed), obj);
952 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
953 G_OBJECT(account_mgr), "account_removed",
954 G_CALLBACK (on_account_removed), obj);
956 /* Create the lists of accounts */
957 priv->store_accounts = tny_simple_list_new ();
958 priv->transport_accounts = tny_simple_list_new ();
959 priv->store_accounts_outboxes = tny_simple_list_new ();
961 /* Create the local folders account */
963 modest_tny_account_new_for_local_folders (priv->account_mgr, priv->session, NULL);
964 tny_list_append (priv->store_accounts, G_OBJECT(local_account));
965 g_object_unref (local_account);
967 /* Add the other remote accounts. Do this after adding the
968 local account, because we need to add our outboxes to the
969 global OUTBOX hosted in the local account */
970 add_existing_accounts (MODEST_TNY_ACCOUNT_STORE (obj));
972 /* FIXME: I'm doing this (adding an "if (FALSE)"because this
973 stuff is not working properly and could cause SIGSEVs, for
974 example one send queue will be created for each connection
975 specific SMTP server, so when tinymail asks for the outbox
976 it will return NULL because there is no outbox folder for
977 this specific transport accounts, and it's a must that the
978 send queue returns an outbox */
980 /* Add connection-specific transport accounts */
981 add_connection_specific_transport_accounts (MODEST_TNY_ACCOUNT_STORE(obj));
983 /* This is a singleton, so it does not need to be unrefed. */
984 if (volume_path_is_mounted (MODEST_MCC1_VOLUMEPATH)) {
986 add_mmc_account (MODEST_TNY_ACCOUNT_STORE (obj), FALSE /* don't emit the insert signal. */);
989 return MODEST_TNY_ACCOUNT_STORE(obj);
993 modest_tny_account_store_get_accounts (TnyAccountStore *self,
995 TnyGetAccountsRequestType request_type)
997 ModestTnyAccountStorePrivate *priv;
999 g_return_if_fail (self);
1000 g_return_if_fail (TNY_IS_LIST(list));
1002 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1004 switch (request_type) {
1005 case TNY_ACCOUNT_STORE_BOTH:
1006 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
1007 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
1009 case TNY_ACCOUNT_STORE_STORE_ACCOUNTS:
1010 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
1012 case TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS:
1013 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
1016 g_return_if_reached ();
1019 /* Initialize session. Why do we need this ??? */
1020 tny_session_camel_set_initialized (priv->session);
1025 modest_tny_account_store_get_cache_dir (TnyAccountStore *self)
1027 ModestTnyAccountStorePrivate *priv;
1028 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1030 if (!priv->cache_dir)
1031 priv->cache_dir = g_build_filename (g_get_home_dir(),
1032 MODEST_DIR, MODEST_CACHE_DIR, NULL);
1033 return priv->cache_dir;
1038 * callers need to unref
1041 modest_tny_account_store_get_device (TnyAccountStore *self)
1043 ModestTnyAccountStorePrivate *priv;
1045 g_return_val_if_fail (self, NULL);
1047 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1050 return g_object_ref (G_OBJECT(priv->device));
1057 modest_tny_account_store_find_account_by_url (TnyAccountStore *self, const gchar* url_string)
1059 return modest_tny_account_store_get_tny_account_by (MODEST_TNY_ACCOUNT_STORE (self),
1060 MODEST_TNY_ACCOUNT_STORE_QUERY_URL,
1067 modest_tny_account_store_alert (TnyAccountStore *self,
1068 TnyAccount *account,
1071 const GError *error)
1073 ModestTransportStoreProtocol proto =
1074 MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN;
1075 const gchar* server_name = NULL;
1076 gchar *prompt = NULL;
1080 g_return_val_if_fail (account, FALSE);
1081 g_return_val_if_fail (error, FALSE);
1083 if ((error->domain != TNY_ACCOUNT_ERROR) && (error->domain != TNY_ACCOUNT_STORE_ERROR))
1086 /* Get the server name: */
1087 server_name = tny_account_get_hostname (account);
1090 const gchar *proto_name = tny_account_get_proto (account);
1092 proto = modest_protocol_info_get_transport_store_protocol (proto_name);
1094 g_warning("modest: %s: account with id=%s has no proto.\n", __FUNCTION__,
1095 tny_account_get_id (account));
1100 switch (error->code) {
1101 case TNY_ACCOUNT_STORE_ERROR_CANCEL_ALERT:
1102 case TNY_ACCOUNT_ERROR_TRY_CONNECT_USER_CANCEL:
1103 /* Don't show waste the user's time by showing him a dialog telling
1104 * him that he has just cancelled something: */
1107 case TNY_ACCOUNT_ERROR_TRY_CONNECT_HOST_LOOKUP_FAILED:
1108 case TNY_ACCOUNT_ERROR_TRY_CONNECT_SERVICE_UNAVAILABLE:
1109 /* TODO: Show the appropriate message, depending on whether it's POP or IMAP: */
1111 case MODEST_PROTOCOL_STORE_POP:
1112 prompt = g_strdup_printf (_("emev_ni_ui_pop3_msg_connect_error"),
1115 case MODEST_PROTOCOL_STORE_IMAP:
1116 prompt = g_strdup_printf (_("emev_ni_ui_imap_connect_server_error"),
1119 case MODEST_PROTOCOL_TRANSPORT_SMTP:
1120 prompt = g_strdup_printf (_("emev_ib_ui_smtp_server_invalid"),
1124 g_return_val_if_reached (FALSE);
1128 case TNY_ACCOUNT_ERROR_TRY_CONNECT_AUTHENTICATION_NOT_SUPPORTED:
1129 /* This is "Secure connection failed", even though the logical
1130 * ID has _certificate_ in the name: */
1131 prompt = g_strdup (_("mail_ni_ssl_certificate_error"));
1134 case TNY_ACCOUNT_ERROR_TRY_CONNECT_CERTIFICATE:
1135 /* We'll show the proper dialog later */
1138 case TNY_ACCOUNT_ERROR_TRY_CONNECT:
1139 /* The tinymail camel implementation just sends us this for almost
1140 * everything, so we have to guess at the cause.
1141 * It could be a wrong password, or inability to resolve a hostname,
1142 * or lack of network, or incorrect authentication method, or something entirely different: */
1143 /* TODO: Fix camel to provide specific error codes, and then use the
1144 * specific dialog messages from Chapter 12 of the UI spec.
1146 case TNY_ACCOUNT_STORE_ERROR_UNKNOWN_ALERT:
1149 g_return_val_if_reached (FALSE);
1153 if (error->code == TNY_ACCOUNT_ERROR_TRY_CONNECT_CERTIFICATE)
1154 retval = modest_platform_run_certificate_confirmation_dialog (server_name,
1157 retval = modest_platform_run_alert_dialog (prompt, question);
1167 modest_tny_account_store_init (gpointer g, gpointer iface_data)
1169 TnyAccountStoreIface *klass;
1171 g_return_if_fail (g);
1173 klass = (TnyAccountStoreIface *)g;
1175 klass->get_accounts_func =
1176 modest_tny_account_store_get_accounts;
1177 klass->get_cache_dir_func =
1178 modest_tny_account_store_get_cache_dir;
1179 klass->get_device_func =
1180 modest_tny_account_store_get_device;
1182 modest_tny_account_store_alert;
1183 klass->find_account_func =
1184 modest_tny_account_store_find_account_by_url;
1188 modest_tny_account_store_set_get_pass_func (ModestTnyAccountStore *self,
1189 ModestTnyGetPassFunc func)
1191 /* not implemented, we use signals */
1192 g_printerr ("modest: set_get_pass_func not implemented\n");
1196 modest_tny_account_store_get_session (TnyAccountStore *self)
1198 g_return_val_if_fail (self, NULL);
1199 return MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self)->session;
1203 get_tny_account_by (TnyList *accounts,
1204 ModestTnyAccountStoreQueryType type,
1207 TnyIterator *iter = NULL;
1208 gboolean found = FALSE;
1209 TnyAccount *retval = NULL;
1211 iter = tny_list_create_iterator (accounts);
1212 while (!tny_iterator_is_done (iter) && !found) {
1213 TnyAccount *tmp_account = NULL;
1214 const gchar *val = NULL;
1216 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1218 case MODEST_TNY_ACCOUNT_STORE_QUERY_ID:
1219 val = tny_account_get_id (tmp_account);
1221 case MODEST_TNY_ACCOUNT_STORE_QUERY_URL:
1222 val = tny_account_get_url_string (tmp_account);
1226 if (type == MODEST_TNY_ACCOUNT_STORE_QUERY_URL &&
1227 tny_account_matches_url_string (tmp_account, str)) {
1228 retval = g_object_ref (tmp_account);
1231 if (strcmp (val, str) == 0) {
1232 retval = g_object_ref (tmp_account);
1236 g_object_unref (tmp_account);
1237 tny_iterator_next (iter);
1239 g_object_unref (iter);
1245 modest_tny_account_store_get_tny_account_by (ModestTnyAccountStore *self,
1246 ModestTnyAccountStoreQueryType type,
1249 TnyAccount *account = NULL;
1250 ModestTnyAccountStorePrivate *priv;
1252 g_return_val_if_fail (self, NULL);
1253 g_return_val_if_fail (str, NULL);
1255 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1257 /* Search in store accounts */
1258 account = get_tny_account_by (priv->store_accounts, type, str);
1260 /* If we already found something, no need to search the transport accounts */
1262 account = get_tny_account_by (priv->transport_accounts, type, str);
1264 /* If we already found something, no need to search the
1265 per-account outbox accounts */
1267 account = get_tny_account_by (priv->store_accounts_outboxes, type, str);
1270 /* Warn if nothing was found. This is generally unusual. */
1272 g_warning("%s: Failed to find account with %s=%s\n",
1274 (type == MODEST_TNY_ACCOUNT_STORE_QUERY_ID) ? "ID" : "URL",
1278 /* Returns a new reference to the account if found */
1284 modest_tny_account_store_get_server_account (ModestTnyAccountStore *self,
1285 const gchar *account_name,
1286 TnyAccountType type)
1288 ModestTnyAccountStorePrivate *priv = NULL;
1289 TnyAccount *retval = NULL;
1290 TnyList *account_list = NULL;
1291 TnyIterator *iter = NULL;
1294 g_return_val_if_fail (self, NULL);
1295 g_return_val_if_fail (account_name, NULL);
1296 g_return_val_if_fail (type == TNY_ACCOUNT_TYPE_STORE ||
1297 type == TNY_ACCOUNT_TYPE_TRANSPORT,
1300 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1302 account_list = (type == TNY_ACCOUNT_TYPE_STORE) ?
1303 priv->store_accounts :
1304 priv->transport_accounts;
1306 if (!account_list) {
1307 g_printerr ("%s: No server accounts of type %s\n", __FUNCTION__,
1308 (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport");
1312 /* Look for the server account */
1314 iter = tny_list_create_iterator (account_list);
1315 while (!tny_iterator_is_done (iter) && !found) {
1316 const gchar *modest_acc_name;
1317 TnyAccount *tmp_account;
1319 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1321 modest_tny_account_get_parent_modest_account_name_for_server_account (tmp_account);
1323 if (!strcmp (account_name, modest_acc_name)) {
1325 retval = g_object_ref (tmp_account);
1327 /* Free and continue */
1328 g_object_unref (tmp_account);
1329 tny_iterator_next (iter);
1333 g_printerr ("modest: %s: could not get tny %s account for %s\n." \
1334 "Number of server accounts of this type=%d\n", __FUNCTION__,
1335 (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport",
1336 account_name, tny_list_get_length (account_list));
1339 /* Returns a new reference */
1344 modest_tny_account_store_get_smtp_specific_transport_account_for_open_connection (ModestTnyAccountStore *self,
1345 const gchar *account_name)
1347 /* Get the current connection: */
1348 TnyDevice *device = modest_runtime_get_device ();
1350 if (!tny_device_is_online (device))
1353 g_return_val_if_fail (self, NULL);
1356 #ifdef MODEST_PLATFORM_MAEMO
1357 g_assert (TNY_IS_MAEMO_CONIC_DEVICE (device));
1358 TnyMaemoConicDevice *maemo_device = TNY_MAEMO_CONIC_DEVICE (device);
1359 const gchar* iap_id = tny_maemo_conic_device_get_current_iap_id (maemo_device);
1360 /* printf ("DEBUG: %s: iap_id=%s\n", __FUNCTION__, iap_id); */
1364 ConIcIap* connection = tny_maemo_conic_device_get_iap (maemo_device, iap_id);
1368 const gchar *connection_name = con_ic_iap_get_name (connection);
1369 /* printf ("DEBUG: %s: connection_name=%s\n", __FUNCTION__, connection_name); */
1370 if (!connection_name)
1373 /* Get the connection-specific transport acccount, if any: */
1374 ModestAccountMgr *account_manager = modest_runtime_get_account_mgr ();
1376 /* Check if this account has connection-specific SMTP enabled */
1377 if (!modest_account_mgr_get_use_connection_specific_smtp (account_manager, account_name)) {
1381 gchar* server_account_name = modest_account_mgr_get_connection_specific_smtp (account_manager,
1384 /* printf ("DEBUG: %s: server_account_name=%s\n", __FUNCTION__, server_account_name); */
1385 if (!server_account_name) {
1386 return NULL; /* No connection-specific SMTP server was specified for this connection. */
1389 TnyAccount* account = modest_tny_account_store_get_tny_account_by (self,
1390 MODEST_TNY_ACCOUNT_STORE_QUERY_ID,
1391 server_account_name);
1393 /* printf ("DEBUG: %s: account=%p\n", __FUNCTION__, account); */
1394 g_free (server_account_name);
1396 /* Unref the get()ed object, as required by the tny_maemo_conic_device_get_iap() documentation. */
1397 g_object_unref (connection);
1401 return NULL; /* TODO: Implement this for GNOME, instead of just Maemo? */
1402 #endif /* MODEST_PLATFORM_MAEMO */
1407 modest_tny_account_store_get_transport_account_for_open_connection (ModestTnyAccountStore *self,
1408 const gchar *account_name)
1410 g_return_val_if_fail (self, NULL);
1411 g_return_val_if_fail (account_name, NULL);
1413 if (!account_name || !self)
1416 /* Get the connection-specific transport acccount, if any: */
1417 /* Note: This gives us a reference: */
1418 TnyAccount *account =
1419 modest_tny_account_store_get_smtp_specific_transport_account_for_open_connection (self, account_name);
1421 /* If there is no connection-specific transport account (the common case),
1422 * just get the regular transport account: */
1424 /* The special local folders don't have transport accounts. */
1425 if (strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0)
1428 /* Note: This gives us a reference: */
1429 account = modest_tny_account_store_get_server_account (self, account_name,
1430 TNY_ACCOUNT_TYPE_TRANSPORT);
1434 /* returns a reference. */
1439 modest_tny_account_store_get_local_folders_account (ModestTnyAccountStore *self)
1441 TnyAccount *account = NULL;
1442 ModestTnyAccountStorePrivate *priv;
1446 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1448 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1451 iter = tny_list_create_iterator (priv->store_accounts);
1452 while (!tny_iterator_is_done (iter) && !found) {
1453 TnyAccount *tmp_account;
1455 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1456 if (modest_tny_account_is_virtual_local_folders (tmp_account)) {
1457 account = g_object_ref (tmp_account);
1460 g_object_unref (tmp_account);
1461 tny_iterator_next (iter);
1463 g_object_unref (iter);
1465 /* Returns a new reference to the account */
1470 modest_tny_account_store_get_mmc_folders_account (ModestTnyAccountStore *self)
1472 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1474 return modest_tny_account_store_get_tny_account_by (self, MODEST_TNY_ACCOUNT_STORE_QUERY_ID,
1475 MODEST_MMC_ACCOUNT_ID);
1479 /*********************************************************************************/
1481 add_existing_accounts (ModestTnyAccountStore *self)
1483 GSList *account_names = NULL, *iter = NULL;
1484 ModestTnyAccountStorePrivate *priv = NULL;
1486 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1488 /* These are account names, not server_account names */
1489 account_names = modest_account_mgr_account_names (priv->account_mgr, FALSE);
1491 for (iter = account_names; iter != NULL; iter = g_slist_next (iter)) {
1492 const gchar *account_name = (const gchar*) iter->data;
1494 /* Insert all enabled accounts without notifying */
1495 if (modest_account_mgr_get_enabled (priv->account_mgr, account_name))
1496 insert_account (self, account_name, FALSE);
1498 modest_account_mgr_free_account_names (account_names);
1502 create_tny_account (ModestTnyAccountStore *self,
1504 TnyAccountType type)
1506 TnyAccount *account = NULL;
1507 ModestTnyAccountStorePrivate *priv = NULL;
1509 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1511 account = modest_tny_account_new_from_account (priv->account_mgr,
1518 /* Forget any cached password for the account, so that
1519 we use a new account if any */
1520 modest_tny_account_store_forget_password_in_memory (self,
1521 tny_account_get_id (account));
1522 /* Set the account store */
1523 g_object_set_data (G_OBJECT(account), "account_store", self);
1525 g_printerr ("modest: failed to create account for %s\n", name);
1533 add_outbox_from_transport_account_to_global_outbox (ModestTnyAccountStore *self,
1534 const gchar *account_name,
1535 TnyAccount *transport_account)
1537 TnyList *folders = NULL;
1538 TnyIterator *iter_folders = NULL;
1539 TnyAccount *local_account = NULL, *account_outbox = NULL;
1540 TnyFolder *per_account_outbox = NULL;
1541 ModestTnyAccountStorePrivate *priv = NULL;
1543 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1545 /* Create per account local outbox */
1547 modest_tny_account_new_for_per_account_local_outbox_folder (priv->account_mgr,
1550 tny_list_append (priv->store_accounts_outboxes, G_OBJECT (account_outbox));
1552 /* Get the outbox folder */
1553 folders = tny_simple_list_new ();
1554 tny_folder_store_get_folders (TNY_FOLDER_STORE (account_outbox), folders, NULL, NULL);
1555 g_assert (tny_list_get_length (folders) == 1);
1557 iter_folders = tny_list_create_iterator (folders);
1558 per_account_outbox = TNY_FOLDER (tny_iterator_get_current (iter_folders));
1559 g_object_unref (iter_folders);
1560 g_object_unref (folders);
1561 g_object_unref (account_outbox);
1563 /* Add the outbox of the new per-account-local-outbox account
1564 to the global local merged OUTBOX of the local folders
1566 local_account = modest_tny_account_store_get_local_folders_account (self);
1567 modest_tny_local_folders_account_add_folder_to_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1568 per_account_outbox);
1569 /* Add the pair to the hash table */
1570 g_hash_table_insert (priv->outbox_of_transport,
1572 per_account_outbox);
1574 g_object_unref (local_account);
1575 g_object_unref (per_account_outbox);
1579 * This function will be used for both adding new accounts and for the
1580 * initialization. In the initialization we do not want to emit
1581 * signals so notify will be FALSE, in the case of account additions
1582 * we do want to notify the observers
1585 insert_account (ModestTnyAccountStore *self,
1586 const gchar *account,
1589 ModestTnyAccountStorePrivate *priv = NULL;
1590 TnyAccount *store_account = NULL, *transport_account = NULL;
1592 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1594 /* Get the server and the transport account */
1595 store_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_STORE);
1596 transport_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT);
1598 g_assert (store_account);
1599 g_assert (transport_account);
1601 /* Add accounts to the lists */
1602 tny_list_append (priv->store_accounts, G_OBJECT (store_account));
1603 tny_list_append (priv->transport_accounts, G_OBJECT (transport_account));
1605 /* Create a new pseudo-account with an outbox for this
1606 transport account and add it to the global outbox
1607 in the local account */
1608 add_outbox_from_transport_account_to_global_outbox (self, account, transport_account);
1610 /* Notify the observers. We do it after everything is
1613 TnyAccount *local_account = NULL;
1615 /* Notify the observers about the new server & transport accounts */
1616 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, store_account);
1617 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, transport_account);
1619 /* Notify that the local account changed */
1620 local_account = modest_tny_account_store_get_local_folders_account (self);
1621 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1622 g_object_unref (local_account);
1626 g_object_unref (store_account);
1627 g_object_unref (transport_account);
1631 on_account_inserted (ModestAccountMgr *acc_mgr,
1632 const gchar *account,
1635 /* Insert the account and notify the observers */
1636 insert_account (MODEST_TNY_ACCOUNT_STORE (user_data), account, TRUE);
1640 on_account_removed (ModestAccountMgr *acc_mgr, const gchar *account,
1643 TnyAccount *store_account = NULL, *transport_account = NULL;
1644 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(user_data);
1646 /* Get the server and the transport account */
1648 modest_tny_account_store_get_server_account (self, account, TNY_ACCOUNT_TYPE_STORE);
1650 modest_tny_account_store_get_server_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT);
1652 /* If there was any problem creating the account, for example,
1653 with the configuration system this could not exist */
1654 if (store_account) {
1655 /* Clear the cache */
1656 tny_store_account_delete_cache (TNY_STORE_ACCOUNT (store_account));
1658 /* Notify the observers */
1659 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 0, store_account);
1660 account_disconnect (store_account); /* disconnect the account */
1661 g_object_unref (store_account);
1663 g_warning ("There is no store account for account %s\n", account);
1666 /* If there was any problem creating the account, for example,
1667 with the configuration system this could not exist */
1668 if (transport_account) {
1669 TnyAccount *local_account = NULL;
1670 TnyFolder *outbox = NULL;
1671 ModestTnyAccountStorePrivate *priv = NULL;
1673 /* Remove the OUTBOX of the account from the global outbox */
1674 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1675 outbox = g_hash_table_lookup (priv->outbox_of_transport, transport_account);
1677 if (TNY_IS_FOLDER (outbox)) {
1678 local_account = modest_tny_account_store_get_local_folders_account (self);
1679 modest_tny_local_folders_account_remove_folder_from_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1681 g_hash_table_remove (priv->outbox_of_transport, transport_account);
1683 /* Notify the change in the local account */
1684 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1685 g_object_unref (local_account);
1687 g_warning ("Removing a transport account that has no outbox");
1690 /* Notify the observers */
1691 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 0, transport_account);
1692 account_disconnect (transport_account); /* disconnect the account */
1693 g_object_unref (transport_account);
1695 g_warning ("There is no transport account for account %s\n", account);
1699 TnyTransportAccount *
1700 modest_tny_account_store_new_connection_specific_transport_account (ModestTnyAccountStore *self,
1703 ModestTnyAccountStorePrivate *priv = NULL;
1704 TnyAccount * tny_account = NULL;
1706 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1708 /* Add the account: */
1710 modest_tny_account_new_from_server_account_name (priv->account_mgr,
1716 g_object_set_data (G_OBJECT(tny_account),
1720 tny_list_append (priv->transport_accounts, G_OBJECT (tny_account));
1721 add_outbox_from_transport_account_to_global_outbox (self,
1726 g_printerr ("modest: failed to create smtp-specific account for %s\n",
1729 return TNY_TRANSPORT_ACCOUNT (tny_account);
1734 add_connection_specific_transport_accounts (ModestTnyAccountStore *self)
1736 ModestTnyAccountStorePrivate *priv = NULL;
1737 GSList *list_specifics = NULL, *iter = NULL;
1739 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1741 ModestConf *conf = modest_runtime_get_conf ();
1744 list_specifics = modest_conf_get_list (conf,
1745 MODEST_CONF_CONNECTION_SPECIFIC_SMTP_LIST,
1746 MODEST_CONF_VALUE_STRING, &err);
1748 g_printerr ("modest: %s: error getting list: %s\n.", __FUNCTION__, err->message);
1753 /* Look at each connection-specific transport account for the
1754 * modest account: */
1755 iter = list_specifics;
1757 /* The list alternates between the connection name and the transport name: */
1758 iter = g_slist_next (iter);
1760 const gchar* transport_account_name = (const gchar*) (iter->data);
1761 TnyTransportAccount * account = NULL;
1762 account = modest_tny_account_store_new_connection_specific_transport_account (
1763 self, transport_account_name);
1765 g_object_unref (account);
1767 iter = g_slist_next (iter);
1772 modest_tny_account_store_find_msg_in_outboxes (ModestTnyAccountStore *self,
1774 TnyAccount **ac_out)
1776 TnyIterator *acc_iter;
1777 ModestTnyAccountStorePrivate *priv;
1779 TnyAccount *msg_account = NULL;
1781 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1782 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1784 acc_iter = tny_list_create_iterator (priv->store_accounts_outboxes);
1785 while (!msg && !tny_iterator_is_done (acc_iter)) {
1786 TnyList *folders = tny_simple_list_new ();
1787 TnyAccount *account = TNY_ACCOUNT (tny_iterator_get_current (acc_iter));
1788 TnyIterator *folders_iter = NULL;
1790 tny_folder_store_get_folders (TNY_FOLDER_STORE (account), folders, NULL, NULL);
1791 folders_iter = tny_list_create_iterator (folders);
1793 while (msg == NULL && !tny_iterator_is_done (folders_iter)) {
1794 TnyFolder *folder = TNY_FOLDER (tny_iterator_get_current (folders_iter));
1795 msg = tny_folder_find_msg (folder, uri, NULL);
1798 msg_account = g_object_ref (account);
1800 g_object_unref (folder);
1801 tny_iterator_next (folders_iter);
1804 g_object_unref (folders);
1805 g_object_unref (account);
1806 tny_iterator_next (acc_iter);
1809 g_object_unref (acc_iter);
1812 *ac_out = msg_account;
1817 TnyTransportAccount *
1818 modest_tny_account_store_get_transport_account_from_outbox_header(ModestTnyAccountStore *self, TnyHeader *header)
1820 TnyIterator *acc_iter;
1821 ModestTnyAccountStorePrivate *priv;
1822 TnyTransportAccount *header_acc = NULL;
1823 const gchar *msg_id;
1825 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1826 g_return_val_if_fail (TNY_IS_HEADER (header), NULL);
1827 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1829 msg_id = modest_tny_send_queue_get_msg_id (header);
1830 acc_iter = tny_list_create_iterator (priv->transport_accounts);
1831 while (!header_acc && !tny_iterator_is_done (acc_iter)) {
1832 TnyTransportAccount *account = TNY_TRANSPORT_ACCOUNT (tny_iterator_get_current (acc_iter));
1833 ModestTnySendQueue *send_queue;
1834 ModestTnySendQueueStatus status;
1835 send_queue = modest_runtime_get_send_queue(TNY_TRANSPORT_ACCOUNT(account));
1836 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
1837 if (status != MODEST_TNY_SEND_QUEUE_UNKNOWN) {
1838 header_acc = g_object_ref(account);
1840 g_object_unref (account);
1841 tny_iterator_next (acc_iter);
1844 g_object_unref(acc_iter);