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 foreach_account_disconnect (gpointer data,
306 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT(data), FALSE, NULL, NULL);
311 foreach_account_append_to_list (gpointer data,
316 list = TNY_LIST (user_data);
317 tny_list_append (list, G_OBJECT (data));
320 /********************************************************************/
321 /* Control the state of the MMC local account */
322 /********************************************************************/
324 /** Only call this if the memory card is really mounted.
327 add_mmc_account(ModestTnyAccountStore *self, gboolean emit_insert_signal)
329 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
330 g_return_if_fail (priv->session);
332 TnyAccount *mmc_account = modest_tny_account_new_for_local_folders (priv->account_mgr,
334 MODEST_MCC1_VOLUMEPATH);
336 /* Add to the list of store accounts */
337 tny_list_append (priv->store_accounts, G_OBJECT (mmc_account));
339 if (emit_insert_signal) {
340 g_signal_emit (G_OBJECT (self),
341 signals [ACCOUNT_INSERTED_SIGNAL],
346 g_object_unref (mmc_account);
350 on_vfs_volume_mounted(GnomeVFSVolumeMonitor *volume_monitor,
351 GnomeVFSVolume *volume,
354 ModestTnyAccountStore *self;
355 ModestTnyAccountStorePrivate *priv;
359 self = MODEST_TNY_ACCOUNT_STORE(user_data);
360 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
362 /* Check whether this was the external MMC1 card: */
363 uri = gnome_vfs_volume_get_activation_uri (volume);
365 if (uri && (!strcmp (uri, MODEST_MCC1_VOLUMEPATH_URI))) {
366 add_mmc_account (self, TRUE /* emit the insert signal. */);
373 on_vfs_volume_unmounted(GnomeVFSVolumeMonitor *volume_monitor,
374 GnomeVFSVolume *volume,
377 ModestTnyAccountStore *self;
378 ModestTnyAccountStorePrivate *priv;
381 self = MODEST_TNY_ACCOUNT_STORE(user_data);
382 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
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;
391 iter = tny_list_create_iterator (priv->store_accounts);
392 while (!tny_iterator_is_done (iter) && !found) {
395 account = TNY_ACCOUNT (tny_iterator_get_current (iter));
396 if (modest_tny_account_is_memory_card_account (account)) {
398 mmc_account = g_object_ref (account);
400 g_object_unref (account);
401 tny_iterator_next (iter);
403 g_object_unref (iter);
406 /* Remove from the list */
407 tny_list_remove (priv->store_accounts, G_OBJECT (mmc_account));
409 /* Notify observers */
410 g_signal_emit (G_OBJECT (self),
411 signals [ACCOUNT_REMOVED_SIGNAL],
414 g_object_unref (mmc_account);
416 g_warning ("%s: there was no store account for the unmounted MMC",
424 * modest_tny_account_store_forget_password_in_memory
425 * @self: a TnyAccountStore instance
426 * @account: A server account.
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.
432 modest_tny_account_store_forget_password_in_memory (ModestTnyAccountStore *self, const gchar * server_account_name)
434 /* printf ("DEBUG: %s\n", __FUNCTION__); */
435 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
437 if (server_account_name && priv->password_hash) {
438 g_hash_table_remove (priv->password_hash, server_account_name);
444 update_tny_account_for_account (ModestTnyAccountStore *self, ModestAccountMgr *acc_mgr,
445 const gchar *account_name, TnyAccountType type)
447 ModestTnyAccountStorePrivate *priv;
448 TnyList* account_list;
449 gboolean found = FALSE;
450 TnyIterator *iter = NULL;
452 g_return_val_if_fail (self, FALSE);
453 g_return_val_if_fail (account_name, FALSE);
454 g_return_val_if_fail (type == TNY_ACCOUNT_TYPE_STORE ||
455 type == TNY_ACCOUNT_TYPE_TRANSPORT,
458 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
459 account_list = (type == TNY_ACCOUNT_TYPE_STORE ? priv->store_accounts : priv->transport_accounts);
461 iter = tny_list_create_iterator (account_list);
462 while (!tny_iterator_is_done (iter) && !found) {
463 TnyAccount *tny_account;
464 tny_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
466 TnyConnectionStatus conn_status = tny_account_get_connection_status (tny_account);
468 if (conn_status != TNY_CONNECTION_STATUS_RECONNECTING &&
469 conn_status != TNY_CONNECTION_STATUS_INIT) {
470 const gchar* parent_name;
471 parent_name = modest_tny_account_get_parent_modest_account_name_for_server_account (tny_account);
472 if (parent_name && strcmp (parent_name, account_name) == 0) {
474 modest_tny_account_update_from_account (tny_account, acc_mgr, account_name, type);
475 g_signal_emit (G_OBJECT(self), signals[ACCOUNT_CHANGED_SIGNAL], 0, tny_account);
478 g_object_unref (tny_account);
480 tny_iterator_next (iter);
484 g_object_unref (iter);
491 on_account_changed (ModestAccountMgr *acc_mgr,
492 const gchar *account_name,
495 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(user_data);
497 /* g_debug ("DEBUG: modest: %s\n", __FUNCTION__); */
499 /* /\* Ignore the change if it's a change in the last_updated value *\/ */
500 /* if (key && g_str_has_suffix ((const gchar *) key, MODEST_ACCOUNT_LAST_UPDATED)) */
503 if (!update_tny_account_for_account (self, acc_mgr, account_name, TNY_ACCOUNT_TYPE_STORE))
504 g_warning ("%s: failed to update store account for %s", __FUNCTION__, account_name);
505 if (!update_tny_account_for_account (self, acc_mgr, account_name, TNY_ACCOUNT_TYPE_TRANSPORT))
506 g_warning ("%s: failed to update transport account for %s", __FUNCTION__, account_name);
510 on_account_settings_hide (GtkWidget *widget, gpointer user_data)
512 TnyAccount *account = (TnyAccount*)user_data;
514 /* This is easier than using a struct for the user_data: */
515 ModestTnyAccountStore *self = modest_runtime_get_account_store();
516 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
518 const gchar *modest_account_name =
519 modest_tny_account_get_parent_modest_account_name_for_server_account (account);
520 if (modest_account_name)
521 g_hash_table_remove (priv->account_settings_dialog_hash, modest_account_name);
525 show_password_warning_only ()
527 ModestWindow *main_window =
528 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ());
530 /* Show an explanatory temporary banner: */
531 hildon_banner_show_information (
532 GTK_WIDGET(main_window), NULL, _("mcen_ib_username_pw_incorrect"));
536 show_wrong_password_dialog (TnyAccount *account)
538 /* This is easier than using a struct for the user_data: */
539 ModestTnyAccountStore *self = modest_runtime_get_account_store();
540 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
542 const gchar *modest_account_name =
543 modest_tny_account_get_parent_modest_account_name_for_server_account (account);
544 if (!modest_account_name) {
545 g_warning ("%s: modest_tny_account_get_parent_modest_account_name_for_server_account() failed.\n",
549 /* Check whether this window is already open,
550 * for instance because of a previous get_password() call:
552 gpointer dialog_as_gpointer = NULL;
553 gboolean found = FALSE;
554 if (priv->account_settings_dialog_hash) {
555 found = g_hash_table_lookup_extended (priv->account_settings_dialog_hash,
556 modest_account_name, NULL, (gpointer*)&dialog_as_gpointer);
558 ModestAccountSettingsDialog *dialog = dialog_as_gpointer;
560 ModestWindow *main_window =
561 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ());
563 gboolean created_dialog = FALSE;
564 if (!found || !dialog) {
565 dialog = modest_account_settings_dialog_new ();
566 modest_account_settings_dialog_set_account_name (dialog, modest_account_name);
567 modest_account_settings_dialog_switch_to_user_info (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 (
576 GTK_WIDGET(dialog), NULL, _("mcen_ib_username_pw_incorrect"));
578 if (created_dialog) {
579 /* Forget it when it closes: */
580 g_signal_connect_object (G_OBJECT (dialog), "hide", G_CALLBACK (on_account_settings_hide),
583 /* Show it and delete it when it closes: */
584 modest_maemo_show_dialog_and_forget (GTK_WINDOW (main_window), GTK_DIALOG (dialog));
587 /* Just show it instead of showing it and deleting it when it closes,
588 * though it is probably open already: */
589 gtk_window_present (GTK_WINDOW (dialog));
596 request_password_and_wait (ModestTnyAccountStore *account_store,
597 const gchar* server_account_id,
603 g_signal_emit (G_OBJECT(account_store), signals[PASSWORD_REQUESTED_SIGNAL], 0,
604 server_account_id, /* server_account_name */
605 username, password, cancel, remember);
608 /* This callback will be called by Tinymail when it needs the password
609 * from the user or the account settings.
610 * It can also call forget_password() before calling this,
611 * so that we clear wrong passwords out of our account settings.
612 * Note that TnyAccount here will be the server account. */
614 get_password (TnyAccount *account, const gchar * prompt_not_used, gboolean *cancel)
616 /* TODO: Settting cancel to FALSE does not actually cancel everything.
617 * We still get multiple requests afterwards, so we end up showing the
618 * same dialogs repeatedly.
621 printf ("DEBUG: modest: %s: prompt (not shown) = %s\n", __FUNCTION__, prompt_not_used);
623 g_return_val_if_fail (account, NULL);
625 const TnyAccountStore *account_store = NULL;
626 ModestTnyAccountStore *self = NULL;
627 ModestTnyAccountStorePrivate *priv;
628 gchar *username = NULL;
630 gpointer pwd_ptr = NULL;
631 gboolean already_asked = FALSE;
633 /* Initialize the output parameter: */
637 const gchar *server_account_name = tny_account_get_id (account);
638 account_store = TNY_ACCOUNT_STORE(g_object_get_data (G_OBJECT(account),
641 if (!server_account_name || !account_store) {
642 g_warning ("modest: %s: could not retrieve account_store for account %s",
643 __FUNCTION__, server_account_name ? server_account_name : "<NULL>");
650 self = MODEST_TNY_ACCOUNT_STORE (account_store);
651 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
653 /* This hash map stores passwords, including passwords that are not stored in gconf. */
654 /* Is it in the hash? if it's already there, it must be wrong... */
655 pwd_ptr = (gpointer)&pwd; /* pwd_ptr so the compiler does not complained about
656 * type-punned ptrs...*/
657 already_asked = priv->password_hash &&
658 g_hash_table_lookup_extended (priv->password_hash,
661 (gpointer*)&pwd_ptr);
663 printf ("DEBUG: modest: %s: Already asked = %d\n", __FUNCTION__, already_asked);
665 /* If the password is not already there, try ModestConf */
666 if (!already_asked) {
667 pwd = modest_server_account_get_password (priv->account_mgr,
668 server_account_name);
669 g_hash_table_insert (priv->password_hash, g_strdup (server_account_name), g_strdup (pwd));
672 /* If it was already asked, it must have been wrong, so ask again */
673 if (already_asked || !pwd || strlen(pwd) == 0) {
674 /* As per the UI spec, if no password was set in the account settings,
675 * ask for it now. But if the password is wrong in the account settings,
676 * then show a banner and the account settings dialog so it can be corrected:
678 const gboolean settings_have_password =
679 modest_server_account_get_has_password (priv->account_mgr, server_account_name);
680 printf ("DEBUG: modest: %s: settings_have_password=%d\n", __FUNCTION__, settings_have_password);
681 if (settings_have_password) {
682 /* The password must be wrong, so show the account settings dialog so it can be corrected: */
683 show_wrong_password_dialog (account);
691 /* we don't have it yet. Get the password from the user */
692 const gchar* account_id = tny_account_get_id (account);
693 gboolean remember = FALSE;
697 /* Show an info banner, before we show the protected password dialog: */
698 show_password_warning_only();
701 request_password_and_wait (self, account_id,
702 &username, &pwd, cancel, &remember);
705 /* The password will be returned as the result,
706 * but we need to tell tinymail about the username too: */
707 tny_account_set_user (account, username);
709 /* Do not save the password in gconf,
710 * because the UI spec says "The password will never be saved in the account": */
713 printf ("%s: Storing username=%s, password=%s\n",
714 __FUNCTION__, username, pwd);
715 modest_server_account_set_username (priv->account_mgr, server_account_name,
717 modest_server_account_set_password (priv->account_mgr, server_account_name,
722 /* We need to dup the string even knowing that
723 it's already a dup of the contents of an
724 entry, because it if it's wrong, then camel
726 g_hash_table_insert (priv->password_hash, g_strdup (server_account_name), g_strdup(pwd));
728 g_hash_table_remove (priv->password_hash, server_account_name);
739 /* printf(" DEBUG: %s: returning %s\n", __FUNCTION__, pwd); */
745 modest_tny_account_store_forget_already_asked (ModestTnyAccountStore *self, TnyAccount *account)
747 g_return_if_fail (account);
749 ModestTnyAccountStorePrivate *priv;
751 gpointer pwd_ptr = NULL;
752 gboolean already_asked = FALSE;
754 const gchar *server_account_name = tny_account_get_id (account);
756 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
758 /* This hash map stores passwords, including passwords that are not stored in gconf. */
759 pwd_ptr = (gpointer)&pwd; /* pwd_ptr so the compiler does not complained about
760 * type-punned ptrs...*/
761 already_asked = priv->password_hash &&
762 g_hash_table_lookup_extended (priv->password_hash,
765 (gpointer*)&pwd_ptr);
768 g_hash_table_remove (priv->password_hash, server_account_name);
776 /* tinymail calls this if the connection failed due to an incorrect password.
777 * And it seems to call this for any general connection failure. */
779 forget_password (TnyAccount *account)
781 printf ("DEBUG: %s\n", __FUNCTION__);
782 ModestTnyAccountStore *self;
783 ModestTnyAccountStorePrivate *priv;
784 const TnyAccountStore *account_store;
788 account_store = TNY_ACCOUNT_STORE(g_object_get_data (G_OBJECT(account),
790 self = MODEST_TNY_ACCOUNT_STORE (account_store);
791 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
792 key = tny_account_get_id (account);
794 /* Do not remove the key, this will allow us to detect that we
795 have already asked for it at least once */
796 pwd = g_hash_table_lookup (priv->password_hash, key);
798 memset (pwd, 0, strlen (pwd));
799 g_hash_table_insert (priv->password_hash, g_strdup (key), NULL);
802 /* Remove from configuration system */
804 modest_account_mgr_unset (priv->account_mgr,
805 key, MODEST_ACCOUNT_PASSWORD, TRUE);
810 modest_tny_account_store_finalize (GObject *obj)
812 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(obj);
813 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
815 g_free (priv->cache_dir);
816 priv->cache_dir = NULL;
818 if (priv->password_hash) {
819 g_hash_table_destroy (priv->password_hash);
820 priv->password_hash = NULL;
823 if (priv->account_settings_dialog_hash) {
824 g_hash_table_destroy (priv->account_settings_dialog_hash);
825 priv->account_settings_dialog_hash = NULL;
828 if (priv->outbox_of_transport) {
829 g_hash_table_destroy (priv->outbox_of_transport);
830 priv->outbox_of_transport = NULL;
833 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
834 priv->sighandlers = NULL;
836 if (priv->account_mgr) {
837 g_object_unref (G_OBJECT(priv->account_mgr));
838 priv->account_mgr = NULL;
842 g_object_unref (G_OBJECT(priv->device));
846 /* Destroy all accounts. Disconnect all accounts before they are destroyed */
847 if (priv->store_accounts) {
848 tny_list_foreach (priv->store_accounts, foreach_account_disconnect, NULL);
849 g_object_unref (priv->store_accounts);
850 priv->store_accounts = NULL;
853 if (priv->transport_accounts) {
854 tny_list_foreach (priv->transport_accounts, foreach_account_disconnect, NULL);
855 g_object_unref (priv->transport_accounts);
856 priv->transport_accounts = NULL;
859 if (priv->store_accounts_outboxes) {
860 g_object_unref (priv->store_accounts_outboxes);
861 priv->store_accounts_outboxes = NULL;
865 camel_object_unref (CAMEL_OBJECT(priv->session));
866 priv->session = NULL;
869 G_OBJECT_CLASS(parent_class)->finalize (obj);
873 volume_path_is_mounted (const gchar* path)
875 g_return_val_if_fail (path, FALSE);
877 gboolean result = FALSE;
878 gchar * path_as_uri = g_filename_to_uri (path, NULL, NULL);
879 g_return_val_if_fail (path_as_uri, FALSE);
881 /* Get the monitor singleton: */
882 GnomeVFSVolumeMonitor *monitor = gnome_vfs_get_volume_monitor();
884 /* This seems like a simpler way to do this, but it returns a
885 * GnomeVFSVolume even if the drive is not mounted: */
887 GnomeVFSVolume *volume = gnome_vfs_volume_monitor_get_volume_for_path (monitor,
888 MODEST_MCC1_VOLUMEPATH);
890 gnome_vfs_volume_unref(volume);
894 /* Get the mounted volumes from the monitor: */
895 GList *list = gnome_vfs_volume_monitor_get_mounted_volumes (monitor);
897 for (iter = list; iter; iter = g_list_next (iter)) {
898 GnomeVFSVolume *volume = (GnomeVFSVolume*)iter->data;
902 gnome_vfs_volume_get_display_name (volume);
903 printf ("volume display name=%s\n", display_name);
904 g_free (display_name);
908 gnome_vfs_volume_get_activation_uri (volume);
909 /* printf (" uri=%s\n", uri); */
910 if (uri && (strcmp (uri, path_as_uri) == 0))
915 gnome_vfs_volume_unref (volume);
921 g_free (path_as_uri);
926 ModestTnyAccountStore*
927 modest_tny_account_store_new (ModestAccountMgr *account_mgr,
931 ModestTnyAccountStorePrivate *priv;
932 TnyAccount *local_account = NULL;
934 g_return_val_if_fail (account_mgr, NULL);
935 g_return_val_if_fail (device, NULL);
937 obj = G_OBJECT(g_object_new(MODEST_TYPE_TNY_ACCOUNT_STORE, NULL));
938 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
940 priv->account_mgr = g_object_ref (G_OBJECT(account_mgr));
941 priv->device = g_object_ref (device);
943 priv->session = tny_session_camel_new (TNY_ACCOUNT_STORE(obj));
944 if (!priv->session) {
945 g_warning ("failed to get TnySessionCamel");
949 /* Set the ui locker */
950 tny_session_camel_set_ui_locker (priv->session, tny_gtk_lockable_new ());
952 /* Connect signals */
953 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
954 G_OBJECT(account_mgr), "account_inserted",
955 G_CALLBACK (on_account_inserted), obj);
956 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
957 G_OBJECT(account_mgr), "account_changed",
958 G_CALLBACK (on_account_changed), obj);
959 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
960 G_OBJECT(account_mgr), "account_removed",
961 G_CALLBACK (on_account_removed), obj);
963 /* Create the lists of accounts */
964 priv->store_accounts = tny_simple_list_new ();
965 priv->transport_accounts = tny_simple_list_new ();
966 priv->store_accounts_outboxes = tny_simple_list_new ();
968 /* Create the local folders account */
970 modest_tny_account_new_for_local_folders (priv->account_mgr, priv->session, NULL);
971 tny_list_append (priv->store_accounts, G_OBJECT(local_account));
972 g_object_unref (local_account);
974 /* Add the other remote accounts. Do this after adding the
975 local account, because we need to add our outboxes to the
976 global OUTBOX hosted in the local account */
977 add_existing_accounts (MODEST_TNY_ACCOUNT_STORE (obj));
979 /* FIXME: I'm doing this (adding an "if (FALSE)"because this
980 stuff is not working properly and could cause SIGSEVs, for
981 example one send queue will be created for each connection
982 specific SMTP server, so when tinymail asks for the outbox
983 it will return NULL because there is no outbox folder for
984 this specific transport accounts, and it's a must that the
985 send queue returns an outbox */
987 /* Add connection-specific transport accounts */
988 add_connection_specific_transport_accounts (MODEST_TNY_ACCOUNT_STORE(obj));
990 /* This is a singleton, so it does not need to be unrefed. */
991 if (volume_path_is_mounted (MODEST_MCC1_VOLUMEPATH)) {
993 add_mmc_account (MODEST_TNY_ACCOUNT_STORE (obj), FALSE /* don't emit the insert signal. */);
996 return MODEST_TNY_ACCOUNT_STORE(obj);
1000 modest_tny_account_store_get_accounts (TnyAccountStore *self,
1002 TnyGetAccountsRequestType request_type)
1004 ModestTnyAccountStorePrivate *priv;
1006 g_return_if_fail (self);
1007 g_return_if_fail (TNY_IS_LIST(list));
1009 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1011 switch (request_type) {
1012 case TNY_ACCOUNT_STORE_BOTH:
1013 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
1014 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
1016 case TNY_ACCOUNT_STORE_STORE_ACCOUNTS:
1017 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
1019 case TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS:
1020 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
1023 g_return_if_reached ();
1026 /* Initialize session. Why do we need this ??? */
1027 tny_session_camel_set_initialized (priv->session);
1032 modest_tny_account_store_get_cache_dir (TnyAccountStore *self)
1034 ModestTnyAccountStorePrivate *priv;
1035 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1037 if (!priv->cache_dir)
1038 priv->cache_dir = g_build_filename (g_get_home_dir(),
1039 MODEST_DIR, MODEST_CACHE_DIR, NULL);
1040 return priv->cache_dir;
1045 * callers need to unref
1048 modest_tny_account_store_get_device (TnyAccountStore *self)
1050 ModestTnyAccountStorePrivate *priv;
1052 g_return_val_if_fail (self, NULL);
1054 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1057 return g_object_ref (G_OBJECT(priv->device));
1064 modest_tny_account_store_find_account_by_url (TnyAccountStore *self, const gchar* url_string)
1066 return modest_tny_account_store_get_tny_account_by (MODEST_TNY_ACCOUNT_STORE (self),
1067 MODEST_TNY_ACCOUNT_STORE_QUERY_URL,
1074 modest_tny_account_store_alert (TnyAccountStore *self,
1075 TnyAccount *account,
1078 const GError *error)
1080 ModestTransportStoreProtocol proto =
1081 MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN;
1082 const gchar* server_name = NULL;
1083 gchar *prompt = NULL;
1087 g_return_val_if_fail (account, FALSE);
1088 g_return_val_if_fail (error, FALSE);
1090 if ((error->domain != TNY_ACCOUNT_ERROR) && (error->domain != TNY_ACCOUNT_STORE_ERROR))
1093 /* Get the server name: */
1094 server_name = tny_account_get_hostname (account);
1097 const gchar *proto_name = tny_account_get_proto (account);
1099 proto = modest_protocol_info_get_transport_store_protocol (proto_name);
1101 g_warning("modest: %s: account with id=%s has no proto.\n", __FUNCTION__,
1102 tny_account_get_id (account));
1107 switch (error->code) {
1108 case TNY_ACCOUNT_STORE_ERROR_CANCEL_ALERT:
1109 case TNY_ACCOUNT_ERROR_TRY_CONNECT_USER_CANCEL:
1110 /* Don't show waste the user's time by showing him a dialog telling
1111 * him that he has just cancelled something: */
1114 case TNY_ACCOUNT_ERROR_TRY_CONNECT_HOST_LOOKUP_FAILED:
1115 case TNY_ACCOUNT_ERROR_TRY_CONNECT_SERVICE_UNAVAILABLE:
1116 /* TODO: Show the appropriate message, depending on whether it's POP or IMAP: */
1118 case MODEST_PROTOCOL_STORE_POP:
1119 prompt = g_strdup_printf (_("emev_ni_ui_pop3_msg_connect_error"),
1122 case MODEST_PROTOCOL_STORE_IMAP:
1123 prompt = g_strdup_printf (_("emev_ni_ui_imap_connect_server_error"),
1126 case MODEST_PROTOCOL_TRANSPORT_SMTP:
1127 prompt = g_strdup_printf (_("emev_ib_ui_smtp_server_invalid"),
1131 g_return_val_if_reached (FALSE);
1135 case TNY_ACCOUNT_ERROR_TRY_CONNECT_AUTHENTICATION_NOT_SUPPORTED:
1136 /* This is "Secure connection failed", even though the logical
1137 * ID has _certificate_ in the name: */
1138 prompt = g_strdup (_("mail_ni_ssl_certificate_error"));
1141 case TNY_ACCOUNT_ERROR_TRY_CONNECT_CERTIFICATE:
1142 /* We'll show the proper dialog later */
1145 case TNY_ACCOUNT_ERROR_TRY_CONNECT:
1146 /* The tinymail camel implementation just sends us this for almost
1147 * everything, so we have to guess at the cause.
1148 * It could be a wrong password, or inability to resolve a hostname,
1149 * or lack of network, or incorrect authentication method, or something entirely different: */
1150 /* TODO: Fix camel to provide specific error codes, and then use the
1151 * specific dialog messages from Chapter 12 of the UI spec.
1153 case TNY_ACCOUNT_STORE_ERROR_UNKNOWN_ALERT:
1156 g_return_val_if_reached (FALSE);
1160 if (error->code == TNY_ACCOUNT_ERROR_TRY_CONNECT_CERTIFICATE)
1161 retval = modest_platform_run_certificate_conformation_dialog (server_name,
1164 retval = modest_platform_run_alert_dialog (prompt, question);
1174 modest_tny_account_store_init (gpointer g, gpointer iface_data)
1176 TnyAccountStoreIface *klass;
1178 g_return_if_fail (g);
1180 klass = (TnyAccountStoreIface *)g;
1182 klass->get_accounts_func =
1183 modest_tny_account_store_get_accounts;
1184 klass->get_cache_dir_func =
1185 modest_tny_account_store_get_cache_dir;
1186 klass->get_device_func =
1187 modest_tny_account_store_get_device;
1189 modest_tny_account_store_alert;
1190 klass->find_account_func =
1191 modest_tny_account_store_find_account_by_url;
1195 modest_tny_account_store_set_get_pass_func (ModestTnyAccountStore *self,
1196 ModestTnyGetPassFunc func)
1198 /* not implemented, we use signals */
1199 g_printerr ("modest: set_get_pass_func not implemented\n");
1203 modest_tny_account_store_get_session (TnyAccountStore *self)
1205 g_return_val_if_fail (self, NULL);
1206 return MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self)->session;
1210 get_tny_account_by (TnyList *accounts,
1211 ModestTnyAccountStoreQueryType type,
1214 TnyIterator *iter = NULL;
1215 gboolean found = FALSE;
1216 TnyAccount *retval = NULL;
1218 iter = tny_list_create_iterator (accounts);
1219 while (!tny_iterator_is_done (iter) && !found) {
1220 TnyAccount *tmp_account = NULL;
1221 const gchar *val = NULL;
1223 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1225 case MODEST_TNY_ACCOUNT_STORE_QUERY_ID:
1226 val = tny_account_get_id (tmp_account);
1228 case MODEST_TNY_ACCOUNT_STORE_QUERY_URL:
1229 val = tny_account_get_url_string (tmp_account);
1233 if (type == MODEST_TNY_ACCOUNT_STORE_QUERY_URL &&
1234 tny_account_matches_url_string (tmp_account, str)) {
1235 retval = g_object_ref (tmp_account);
1238 if (strcmp (val, str) == 0) {
1239 retval = g_object_ref (tmp_account);
1243 g_object_unref (tmp_account);
1244 tny_iterator_next (iter);
1246 g_object_unref (iter);
1252 modest_tny_account_store_get_tny_account_by (ModestTnyAccountStore *self,
1253 ModestTnyAccountStoreQueryType type,
1256 TnyAccount *account = NULL;
1257 ModestTnyAccountStorePrivate *priv;
1259 g_return_val_if_fail (self, NULL);
1260 g_return_val_if_fail (str, NULL);
1262 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1264 /* Search in store accounts */
1265 account = get_tny_account_by (priv->store_accounts, type, str);
1267 /* If we already found something, no need to search the transport accounts */
1269 account = get_tny_account_by (priv->transport_accounts, type, str);
1271 /* If we already found something, no need to search the
1272 per-account outbox accounts */
1274 account = get_tny_account_by (priv->store_accounts_outboxes, type, str);
1277 /* Warn if nothing was found. This is generally unusual. */
1279 g_warning("%s: Failed to find account with %s=%s\n",
1281 (type == MODEST_TNY_ACCOUNT_STORE_QUERY_ID) ? "ID" : "URL",
1285 /* Returns a new reference to the account if found */
1290 modest_tny_account_store_get_server_account (ModestTnyAccountStore *self,
1291 const gchar *account_name,
1292 TnyAccountType type)
1294 ModestTnyAccountStorePrivate *priv = NULL;
1295 TnyAccount *retval = NULL;
1296 TnyList *account_list = NULL;
1297 TnyIterator *iter = NULL;
1300 g_return_val_if_fail (self, NULL);
1301 g_return_val_if_fail (account_name, NULL);
1302 g_return_val_if_fail (type == TNY_ACCOUNT_TYPE_STORE ||
1303 type == TNY_ACCOUNT_TYPE_TRANSPORT,
1306 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1308 account_list = (type == TNY_ACCOUNT_TYPE_STORE) ?
1309 priv->store_accounts :
1310 priv->transport_accounts;
1312 if (!account_list) {
1313 g_printerr ("%s: No server accounts of type %s\n", __FUNCTION__,
1314 (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport");
1318 /* Look for the server account */
1320 iter = tny_list_create_iterator (account_list);
1321 while (!tny_iterator_is_done (iter) && !found) {
1322 const gchar *modest_acc_name;
1323 TnyAccount *tmp_account;
1325 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1327 modest_tny_account_get_parent_modest_account_name_for_server_account (tmp_account);
1329 if (!strcmp (account_name, modest_acc_name)) {
1331 retval = g_object_ref (tmp_account);
1333 /* Free and continue */
1334 g_object_unref (tmp_account);
1335 tny_iterator_next (iter);
1339 g_printerr ("modest: %s: could not get tny %s account for %s\n." \
1340 "Number of server accounts of this type=%d\n", __FUNCTION__,
1341 (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport",
1342 account_name, tny_list_get_length (account_list));
1345 /* Returns a new reference */
1350 get_smtp_specific_transport_account_for_open_connection (ModestTnyAccountStore *self,
1351 const gchar *account_name)
1353 /* Get the current connection: */
1354 TnyDevice *device = modest_runtime_get_device ();
1356 if (!tny_device_is_online (device))
1359 g_return_val_if_fail (self, NULL);
1362 #ifdef MODEST_PLATFORM_MAEMO
1363 g_assert (TNY_IS_MAEMO_CONIC_DEVICE (device));
1364 TnyMaemoConicDevice *maemo_device = TNY_MAEMO_CONIC_DEVICE (device);
1365 const gchar* iap_id = tny_maemo_conic_device_get_current_iap_id (maemo_device);
1366 /* printf ("DEBUG: %s: iap_id=%s\n", __FUNCTION__, iap_id); */
1370 ConIcIap* connection = tny_maemo_conic_device_get_iap (maemo_device, iap_id);
1374 const gchar *connection_name = con_ic_iap_get_name (connection);
1375 /* printf ("DEBUG: %s: connection_name=%s\n", __FUNCTION__, connection_name); */
1376 if (!connection_name)
1379 /* Get the connection-specific transport acccount, if any: */
1380 ModestAccountMgr *account_manager = modest_runtime_get_account_mgr ();
1382 /* Check if this account has connection-specific SMTP enabled */
1383 if (!modest_account_mgr_get_use_connection_specific_smtp (account_manager, account_name)) {
1387 gchar* server_account_name = modest_account_mgr_get_connection_specific_smtp (account_manager,
1390 /* printf ("DEBUG: %s: server_account_name=%s\n", __FUNCTION__, server_account_name); */
1391 if (!server_account_name) {
1392 return NULL; /* No connection-specific SMTP server was specified for this connection. */
1395 TnyAccount* account = modest_tny_account_store_get_tny_account_by (self,
1396 MODEST_TNY_ACCOUNT_STORE_QUERY_ID,
1397 server_account_name);
1399 /* printf ("DEBUG: %s: account=%p\n", __FUNCTION__, account); */
1400 g_free (server_account_name);
1402 /* Unref the get()ed object, as required by the tny_maemo_conic_device_get_iap() documentation. */
1403 g_object_unref (connection);
1407 return NULL; /* TODO: Implement this for GNOME, instead of just Maemo? */
1408 #endif /* MODEST_PLATFORM_MAEMO */
1413 modest_tny_account_store_get_transport_account_for_open_connection (ModestTnyAccountStore *self,
1414 const gchar *account_name)
1416 g_return_val_if_fail (self, NULL);
1417 g_return_val_if_fail (account_name, NULL);
1419 if (!account_name || !self)
1422 /* Get the connection-specific transport acccount, if any: */
1423 /* Note: This gives us a reference: */
1424 TnyAccount *account =
1425 get_smtp_specific_transport_account_for_open_connection (self, account_name);
1427 /* If there is no connection-specific transport account (the common case),
1428 * just get the regular transport account: */
1430 /* The special local folders don't have transport accounts. */
1431 if (strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0)
1434 /* Note: This gives us a reference: */
1435 account = modest_tny_account_store_get_server_account (self, account_name,
1436 TNY_ACCOUNT_TYPE_TRANSPORT);
1440 /* returns a reference. */
1445 modest_tny_account_store_get_local_folders_account (ModestTnyAccountStore *self)
1447 TnyAccount *account = NULL;
1448 ModestTnyAccountStorePrivate *priv;
1452 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1454 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1457 iter = tny_list_create_iterator (priv->store_accounts);
1458 while (!tny_iterator_is_done (iter) && !found) {
1459 TnyAccount *tmp_account;
1461 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1462 if (modest_tny_account_is_virtual_local_folders (tmp_account)) {
1463 account = g_object_ref (tmp_account);
1466 g_object_unref (tmp_account);
1467 tny_iterator_next (iter);
1469 g_object_unref (iter);
1471 /* Returns a new reference to the account */
1475 /*********************************************************************************/
1477 add_existing_accounts (ModestTnyAccountStore *self)
1479 GSList *account_names = NULL, *iter = NULL;
1480 ModestTnyAccountStorePrivate *priv = NULL;
1482 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1484 /* These are account names, not server_account names */
1485 account_names = modest_account_mgr_account_names (priv->account_mgr, FALSE);
1487 for (iter = account_names; iter != NULL; iter = g_slist_next (iter)) {
1488 const gchar *account_name = (const gchar*) iter->data;
1490 /* Insert all enabled accounts without notifying */
1491 if (modest_account_mgr_get_enabled (priv->account_mgr, account_name))
1492 insert_account (self, account_name, FALSE);
1494 modest_account_mgr_free_account_names (account_names);
1498 create_tny_account (ModestTnyAccountStore *self,
1500 TnyAccountType type)
1502 TnyAccount *account = NULL;
1503 ModestTnyAccountStorePrivate *priv = NULL;
1505 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1507 account = modest_tny_account_new_from_account (priv->account_mgr,
1514 /* Forget any cached password for the account, so that
1515 we use a new account if any */
1516 modest_tny_account_store_forget_password_in_memory (self,
1517 tny_account_get_id (account));
1518 /* Set the account store */
1519 g_object_set_data (G_OBJECT(account), "account_store", self);
1521 g_printerr ("modest: failed to create account for %s\n", name);
1529 add_outbox_from_transport_account_to_global_outbox (ModestTnyAccountStore *self,
1530 const gchar *account_name,
1531 TnyAccount *transport_account)
1533 TnyList *folders = NULL;
1534 TnyIterator *iter_folders = NULL;
1535 TnyAccount *local_account = NULL, *account_outbox = NULL;
1536 TnyFolder *per_account_outbox = NULL;
1537 ModestTnyAccountStorePrivate *priv = NULL;
1539 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1541 /* Create per account local outbox */
1543 modest_tny_account_new_for_per_account_local_outbox_folder (priv->account_mgr,
1546 tny_list_append (priv->store_accounts_outboxes, G_OBJECT (account_outbox));
1548 /* Get the outbox folder */
1549 folders = tny_simple_list_new ();
1550 tny_folder_store_get_folders (TNY_FOLDER_STORE (account_outbox), folders, NULL, NULL);
1551 g_assert (tny_list_get_length (folders) == 1);
1553 iter_folders = tny_list_create_iterator (folders);
1554 per_account_outbox = TNY_FOLDER (tny_iterator_get_current (iter_folders));
1555 g_object_unref (iter_folders);
1556 g_object_unref (folders);
1557 g_object_unref (account_outbox);
1559 /* Add the outbox of the new per-account-local-outbox account
1560 to the global local merged OUTBOX of the local folders
1562 local_account = modest_tny_account_store_get_local_folders_account (self);
1563 modest_tny_local_folders_account_add_folder_to_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1564 per_account_outbox);
1565 /* Add the pair to the hash table */
1566 g_hash_table_insert (priv->outbox_of_transport,
1568 per_account_outbox);
1570 g_object_unref (local_account);
1571 g_object_unref (per_account_outbox);
1576 * This function will be used for both adding new accounts and for the
1577 * initialization. In the initialization we do not want to emit
1578 * signals so notify will be FALSE, in the case of account additions
1579 * we do want to notify the observers
1582 insert_account (ModestTnyAccountStore *self,
1583 const gchar *account,
1586 ModestTnyAccountStorePrivate *priv = NULL;
1587 TnyAccount *store_account = NULL, *transport_account = NULL;
1589 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1591 /* Get the server and the transport account */
1592 store_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_STORE);
1593 transport_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT);
1595 /* Add to the list, and notify the observers */
1596 if (store_account) {
1597 tny_list_append (priv->store_accounts, G_OBJECT (store_account));
1599 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, store_account);
1600 g_object_unref (store_account);
1603 /* Add to the list, and notify the observers */
1604 if (transport_account) {
1605 /* Add account to the list */
1606 tny_list_append (priv->transport_accounts, G_OBJECT (transport_account));
1607 g_assert (TNY_IS_ACCOUNT (transport_account));
1609 /* Create a new pseudo-account with an outbox for this
1610 transport account and add it to the global outbox
1611 in the local account */
1612 add_outbox_from_transport_account_to_global_outbox (self, account, transport_account);
1615 TnyAccount *local_account = NULL;
1617 /* Notify that the local account changed */
1618 local_account = modest_tny_account_store_get_local_folders_account (self);
1619 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1620 g_object_unref (local_account);
1622 /* Notify the observers about the new account */
1623 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, transport_account);
1626 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,
1641 const gchar *account,
1644 TnyAccount *store_account = NULL, *transport_account = NULL;
1645 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(user_data);
1647 /* Get the server and the transport account */
1649 modest_tny_account_store_get_server_account (self, account, TNY_ACCOUNT_TYPE_STORE);
1651 modest_tny_account_store_get_server_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT);
1653 /* If there was any problem creating the account, for example,
1654 with the configuration system this could not exist */
1655 if (store_account) {
1656 /* Clear the cache */
1657 tny_store_account_delete_cache (TNY_STORE_ACCOUNT (store_account));
1659 /* Notify the observers */
1660 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 0, store_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 g_object_unref (transport_account);
1694 g_warning ("There is no transport account for account %s\n", account);
1699 add_connection_specific_transport_accounts (ModestTnyAccountStore *self)
1701 ModestTnyAccountStorePrivate *priv = NULL;
1702 GSList *list_specifics = NULL, *iter = NULL;
1704 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1706 ModestConf *conf = modest_runtime_get_conf ();
1709 list_specifics = modest_conf_get_list (conf,
1710 MODEST_CONF_CONNECTION_SPECIFIC_SMTP_LIST,
1711 MODEST_CONF_VALUE_STRING, &err);
1713 g_printerr ("modest: %s: error getting list: %s\n.", __FUNCTION__, err->message);
1718 /* Look at each connection-specific transport account for the
1719 * modest account: */
1720 iter = list_specifics;
1722 /* The list alternates between the connection name and the transport name: */
1723 iter = g_slist_next (iter);
1725 const gchar* transport_account_name = (const gchar*) (iter->data);
1726 if (transport_account_name) {
1727 TnyAccount * tny_account = NULL;
1728 /* Add the account: */
1730 modest_tny_account_new_from_server_account_name (priv->account_mgr,
1732 transport_account_name);
1734 g_object_set_data (G_OBJECT(tny_account),
1738 tny_list_append (priv->transport_accounts, G_OBJECT (tny_account));
1739 g_object_unref (tny_account);
1741 g_printerr ("modest: failed to create smtp-specific account for %s\n",
1742 transport_account_name);
1745 iter = g_slist_next (iter);