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); */
744 /* tinymail calls this if the connection failed due to an incorrect password.
745 * And it seems to call this for any general connection failure. */
747 forget_password (TnyAccount *account)
749 printf ("DEBUG: %s\n", __FUNCTION__);
750 ModestTnyAccountStore *self;
751 ModestTnyAccountStorePrivate *priv;
752 const TnyAccountStore *account_store;
756 account_store = TNY_ACCOUNT_STORE(g_object_get_data (G_OBJECT(account),
758 self = MODEST_TNY_ACCOUNT_STORE (account_store);
759 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
760 key = tny_account_get_id (account);
762 /* Do not remove the key, this will allow us to detect that we
763 have already asked for it at least once */
764 pwd = g_hash_table_lookup (priv->password_hash, key);
766 memset (pwd, 0, strlen (pwd));
767 g_hash_table_insert (priv->password_hash, g_strdup (key), NULL);
770 /* Remove from configuration system */
772 modest_account_mgr_unset (priv->account_mgr,
773 key, MODEST_ACCOUNT_PASSWORD, TRUE);
778 modest_tny_account_store_finalize (GObject *obj)
780 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(obj);
781 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
783 g_free (priv->cache_dir);
784 priv->cache_dir = NULL;
786 if (priv->password_hash) {
787 g_hash_table_destroy (priv->password_hash);
788 priv->password_hash = NULL;
791 if (priv->account_settings_dialog_hash) {
792 g_hash_table_destroy (priv->account_settings_dialog_hash);
793 priv->account_settings_dialog_hash = NULL;
796 if (priv->outbox_of_transport) {
797 g_hash_table_destroy (priv->outbox_of_transport);
798 priv->outbox_of_transport = NULL;
801 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
802 priv->sighandlers = NULL;
804 if (priv->account_mgr) {
805 g_object_unref (G_OBJECT(priv->account_mgr));
806 priv->account_mgr = NULL;
810 g_object_unref (G_OBJECT(priv->device));
814 /* Destroy all accounts. Disconnect all accounts before they are destroyed */
815 if (priv->store_accounts) {
816 tny_list_foreach (priv->store_accounts, foreach_account_disconnect, NULL);
817 g_object_unref (priv->store_accounts);
818 priv->store_accounts = NULL;
821 if (priv->transport_accounts) {
822 tny_list_foreach (priv->transport_accounts, foreach_account_disconnect, NULL);
823 g_object_unref (priv->transport_accounts);
824 priv->transport_accounts = NULL;
827 if (priv->store_accounts_outboxes) {
828 g_object_unref (priv->store_accounts_outboxes);
829 priv->store_accounts_outboxes = NULL;
833 camel_object_unref (CAMEL_OBJECT(priv->session));
834 priv->session = NULL;
837 G_OBJECT_CLASS(parent_class)->finalize (obj);
841 volume_path_is_mounted (const gchar* path)
843 g_return_val_if_fail (path, FALSE);
845 gboolean result = FALSE;
846 gchar * path_as_uri = g_filename_to_uri (path, NULL, NULL);
847 g_return_val_if_fail (path_as_uri, FALSE);
849 /* Get the monitor singleton: */
850 GnomeVFSVolumeMonitor *monitor = gnome_vfs_get_volume_monitor();
852 /* This seems like a simpler way to do this, but it returns a
853 * GnomeVFSVolume even if the drive is not mounted: */
855 GnomeVFSVolume *volume = gnome_vfs_volume_monitor_get_volume_for_path (monitor,
856 MODEST_MCC1_VOLUMEPATH);
858 gnome_vfs_volume_unref(volume);
862 /* Get the mounted volumes from the monitor: */
863 GList *list = gnome_vfs_volume_monitor_get_mounted_volumes (monitor);
865 for (iter = list; iter; iter = g_list_next (iter)) {
866 GnomeVFSVolume *volume = (GnomeVFSVolume*)iter->data;
870 gnome_vfs_volume_get_display_name (volume);
871 printf ("volume display name=%s\n", display_name);
872 g_free (display_name);
876 gnome_vfs_volume_get_activation_uri (volume);
877 /* printf (" uri=%s\n", uri); */
878 if (uri && (strcmp (uri, path_as_uri) == 0))
883 gnome_vfs_volume_unref (volume);
889 g_free (path_as_uri);
894 ModestTnyAccountStore*
895 modest_tny_account_store_new (ModestAccountMgr *account_mgr,
899 ModestTnyAccountStorePrivate *priv;
900 TnyAccount *local_account = NULL;
902 g_return_val_if_fail (account_mgr, NULL);
903 g_return_val_if_fail (device, NULL);
905 obj = G_OBJECT(g_object_new(MODEST_TYPE_TNY_ACCOUNT_STORE, NULL));
906 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
908 priv->account_mgr = g_object_ref (G_OBJECT(account_mgr));
909 priv->device = g_object_ref (device);
911 priv->session = tny_session_camel_new (TNY_ACCOUNT_STORE(obj));
912 if (!priv->session) {
913 g_warning ("failed to get TnySessionCamel");
917 /* Set the ui locker */
918 tny_session_camel_set_ui_locker (priv->session, tny_gtk_lockable_new ());
920 /* Connect signals */
921 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
922 G_OBJECT(account_mgr), "account_inserted",
923 G_CALLBACK (on_account_inserted), obj);
924 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
925 G_OBJECT(account_mgr), "account_changed",
926 G_CALLBACK (on_account_changed), obj);
927 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
928 G_OBJECT(account_mgr), "account_removed",
929 G_CALLBACK (on_account_removed), obj);
931 /* Create the lists of accounts */
932 priv->store_accounts = tny_simple_list_new ();
933 priv->transport_accounts = tny_simple_list_new ();
934 priv->store_accounts_outboxes = tny_simple_list_new ();
936 /* Create the local folders account */
938 modest_tny_account_new_for_local_folders (priv->account_mgr, priv->session, NULL);
939 tny_list_append (priv->store_accounts, G_OBJECT(local_account));
940 g_object_unref (local_account);
942 /* Add the other remote accounts. Do this after adding the
943 local account, because we need to add our outboxes to the
944 global OUTBOX hosted in the local account */
945 add_existing_accounts (MODEST_TNY_ACCOUNT_STORE (obj));
947 /* FIXME: I'm doing this (adding an "if (FALSE)"because this
948 stuff is not working properly and could cause SIGSEVs, for
949 example one send queue will be created for each connection
950 specific SMTP server, so when tinymail asks for the outbox
951 it will return NULL because there is no outbox folder for
952 this specific transport accounts, and it's a must that the
953 send queue returns an outbox */
955 /* Add connection-specific transport accounts */
956 add_connection_specific_transport_accounts (MODEST_TNY_ACCOUNT_STORE(obj));
958 /* This is a singleton, so it does not need to be unrefed. */
959 if (volume_path_is_mounted (MODEST_MCC1_VOLUMEPATH)) {
961 add_mmc_account (MODEST_TNY_ACCOUNT_STORE (obj), FALSE /* don't emit the insert signal. */);
964 return MODEST_TNY_ACCOUNT_STORE(obj);
968 modest_tny_account_store_get_accounts (TnyAccountStore *self,
970 TnyGetAccountsRequestType request_type)
972 ModestTnyAccountStorePrivate *priv;
974 g_return_if_fail (self);
975 g_return_if_fail (TNY_IS_LIST(list));
977 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
979 switch (request_type) {
980 case TNY_ACCOUNT_STORE_BOTH:
981 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
982 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
984 case TNY_ACCOUNT_STORE_STORE_ACCOUNTS:
985 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
987 case TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS:
988 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
991 g_return_if_reached ();
994 /* Initialize session. Why do we need this ??? */
995 tny_session_camel_set_initialized (priv->session);
1000 modest_tny_account_store_get_cache_dir (TnyAccountStore *self)
1002 ModestTnyAccountStorePrivate *priv;
1003 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1005 if (!priv->cache_dir)
1006 priv->cache_dir = g_build_filename (g_get_home_dir(),
1007 MODEST_DIR, MODEST_CACHE_DIR, NULL);
1008 return priv->cache_dir;
1013 * callers need to unref
1016 modest_tny_account_store_get_device (TnyAccountStore *self)
1018 ModestTnyAccountStorePrivate *priv;
1020 g_return_val_if_fail (self, NULL);
1022 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1025 return g_object_ref (G_OBJECT(priv->device));
1032 modest_tny_account_store_find_account_by_url (TnyAccountStore *self, const gchar* url_string)
1034 return modest_tny_account_store_get_tny_account_by (MODEST_TNY_ACCOUNT_STORE (self),
1035 MODEST_TNY_ACCOUNT_STORE_QUERY_URL,
1042 modest_tny_account_store_alert (TnyAccountStore *self,
1043 TnyAccount *account,
1046 const GError *error)
1048 ModestTransportStoreProtocol proto =
1049 MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN;
1050 const gchar* server_name = NULL;
1051 gchar *prompt = NULL;
1055 g_return_val_if_fail (account, FALSE);
1056 g_return_val_if_fail (error, FALSE);
1058 if ((error->domain != TNY_ACCOUNT_ERROR) && (error->domain != TNY_ACCOUNT_STORE_ERROR))
1061 /* Get the server name: */
1062 server_name = tny_account_get_hostname (account);
1065 const gchar *proto_name = tny_account_get_proto (account);
1067 proto = modest_protocol_info_get_transport_store_protocol (proto_name);
1069 g_warning("modest: %s: account with id=%s has no proto.\n", __FUNCTION__,
1070 tny_account_get_id (account));
1075 switch (error->code) {
1076 case TNY_ACCOUNT_STORE_ERROR_CANCEL_ALERT:
1077 case TNY_ACCOUNT_ERROR_TRY_CONNECT_USER_CANCEL:
1078 /* Don't show waste the user's time by showing him a dialog telling
1079 * him that he has just cancelled something: */
1082 case TNY_ACCOUNT_ERROR_TRY_CONNECT_HOST_LOOKUP_FAILED:
1083 case TNY_ACCOUNT_ERROR_TRY_CONNECT_SERVICE_UNAVAILABLE:
1084 /* TODO: Show the appropriate message, depending on whether it's POP or IMAP: */
1086 case MODEST_PROTOCOL_STORE_POP:
1087 prompt = g_strdup_printf (_("emev_ni_ui_pop3_msg_connect_error"),
1090 case MODEST_PROTOCOL_STORE_IMAP:
1091 prompt = g_strdup_printf (_("emev_ni_ui_imap_connect_server_error"),
1094 case MODEST_PROTOCOL_TRANSPORT_SMTP:
1095 prompt = g_strdup_printf (_("emev_ib_ui_smtp_server_invalid"),
1099 g_return_val_if_reached (FALSE);
1103 case TNY_ACCOUNT_ERROR_TRY_CONNECT_AUTHENTICATION_NOT_SUPPORTED:
1104 /* This is "Secure connection failed", even though the logical
1105 * ID has _certificate_ in the name: */
1106 prompt = g_strdup (_("mail_ni_ssl_certificate_error"));
1109 case TNY_ACCOUNT_ERROR_TRY_CONNECT_CERTIFICATE:
1110 /* We'll show the proper dialog later */
1113 case TNY_ACCOUNT_ERROR_TRY_CONNECT:
1114 /* The tinymail camel implementation just sends us this for almost
1115 * everything, so we have to guess at the cause.
1116 * It could be a wrong password, or inability to resolve a hostname,
1117 * or lack of network, or incorrect authentication method, or something entirely different: */
1118 /* TODO: Fix camel to provide specific error codes, and then use the
1119 * specific dialog messages from Chapter 12 of the UI spec.
1121 case TNY_ACCOUNT_STORE_ERROR_UNKNOWN_ALERT:
1124 g_return_val_if_reached (FALSE);
1128 if (error->code == TNY_ACCOUNT_ERROR_TRY_CONNECT_CERTIFICATE)
1129 retval = modest_platform_run_certificate_conformation_dialog (server_name,
1132 retval = modest_platform_run_alert_dialog (prompt, question);
1142 modest_tny_account_store_init (gpointer g, gpointer iface_data)
1144 TnyAccountStoreIface *klass;
1146 g_return_if_fail (g);
1148 klass = (TnyAccountStoreIface *)g;
1150 klass->get_accounts_func =
1151 modest_tny_account_store_get_accounts;
1152 klass->get_cache_dir_func =
1153 modest_tny_account_store_get_cache_dir;
1154 klass->get_device_func =
1155 modest_tny_account_store_get_device;
1157 modest_tny_account_store_alert;
1158 klass->find_account_func =
1159 modest_tny_account_store_find_account_by_url;
1163 modest_tny_account_store_set_get_pass_func (ModestTnyAccountStore *self,
1164 ModestTnyGetPassFunc func)
1166 /* not implemented, we use signals */
1167 g_printerr ("modest: set_get_pass_func not implemented\n");
1171 modest_tny_account_store_get_session (TnyAccountStore *self)
1173 g_return_val_if_fail (self, NULL);
1174 return MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self)->session;
1178 get_tny_account_by (TnyList *accounts,
1179 ModestTnyAccountStoreQueryType type,
1182 TnyIterator *iter = NULL;
1183 gboolean found = FALSE;
1184 TnyAccount *retval = NULL;
1186 iter = tny_list_create_iterator (accounts);
1187 while (!tny_iterator_is_done (iter) && !found) {
1188 TnyAccount *tmp_account = NULL;
1189 const gchar *val = NULL;
1191 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1193 case MODEST_TNY_ACCOUNT_STORE_QUERY_ID:
1194 val = tny_account_get_id (tmp_account);
1196 case MODEST_TNY_ACCOUNT_STORE_QUERY_URL:
1197 val = tny_account_get_url_string (tmp_account);
1201 if (type == MODEST_TNY_ACCOUNT_STORE_QUERY_URL &&
1202 tny_account_matches_url_string (tmp_account, str)) {
1203 retval = g_object_ref (tmp_account);
1206 if (strcmp (val, str) == 0) {
1207 retval = g_object_ref (tmp_account);
1211 g_object_unref (tmp_account);
1212 tny_iterator_next (iter);
1214 g_object_unref (iter);
1220 modest_tny_account_store_get_tny_account_by (ModestTnyAccountStore *self,
1221 ModestTnyAccountStoreQueryType type,
1224 TnyAccount *account = NULL;
1225 ModestTnyAccountStorePrivate *priv;
1227 g_return_val_if_fail (self, NULL);
1228 g_return_val_if_fail (str, NULL);
1230 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1232 /* Search in store accounts */
1233 account = get_tny_account_by (priv->store_accounts, type, str);
1235 /* If we already found something, no need to search the transport accounts */
1237 account = get_tny_account_by (priv->transport_accounts, type, str);
1239 /* If we already found something, no need to search the
1240 per-account outbox accounts */
1242 account = get_tny_account_by (priv->store_accounts_outboxes, type, str);
1245 /* Warn if nothing was found. This is generally unusual. */
1247 g_warning("%s: Failed to find account with %s=%s\n",
1249 (type == MODEST_TNY_ACCOUNT_STORE_QUERY_ID) ? "ID" : "URL",
1253 /* Returns a new reference to the account if found */
1258 modest_tny_account_store_get_server_account (ModestTnyAccountStore *self,
1259 const gchar *account_name,
1260 TnyAccountType type)
1262 ModestTnyAccountStorePrivate *priv = NULL;
1263 TnyAccount *retval = NULL;
1264 TnyList *account_list = NULL;
1265 TnyIterator *iter = NULL;
1268 g_return_val_if_fail (self, NULL);
1269 g_return_val_if_fail (account_name, NULL);
1270 g_return_val_if_fail (type == TNY_ACCOUNT_TYPE_STORE ||
1271 type == TNY_ACCOUNT_TYPE_TRANSPORT,
1274 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1276 account_list = (type == TNY_ACCOUNT_TYPE_STORE) ?
1277 priv->store_accounts :
1278 priv->transport_accounts;
1280 if (!account_list) {
1281 g_printerr ("%s: No server accounts of type %s\n", __FUNCTION__,
1282 (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport");
1286 /* Look for the server account */
1288 iter = tny_list_create_iterator (account_list);
1289 while (!tny_iterator_is_done (iter) && !found) {
1290 const gchar *modest_acc_name;
1291 TnyAccount *tmp_account;
1293 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1295 modest_tny_account_get_parent_modest_account_name_for_server_account (tmp_account);
1297 if (!strcmp (account_name, modest_acc_name)) {
1299 retval = g_object_ref (tmp_account);
1301 /* Free and continue */
1302 g_object_unref (tmp_account);
1303 tny_iterator_next (iter);
1307 g_printerr ("modest: %s: could not get tny %s account for %s\n." \
1308 "Number of server accounts of this type=%d\n", __FUNCTION__,
1309 (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport",
1310 account_name, tny_list_get_length (account_list));
1313 /* Returns a new reference */
1318 get_smtp_specific_transport_account_for_open_connection (ModestTnyAccountStore *self,
1319 const gchar *account_name)
1321 /* Get the current connection: */
1322 TnyDevice *device = modest_runtime_get_device ();
1324 if (!tny_device_is_online (device))
1327 g_return_val_if_fail (self, NULL);
1330 #ifdef MODEST_PLATFORM_MAEMO
1331 g_assert (TNY_IS_MAEMO_CONIC_DEVICE (device));
1332 TnyMaemoConicDevice *maemo_device = TNY_MAEMO_CONIC_DEVICE (device);
1333 const gchar* iap_id = tny_maemo_conic_device_get_current_iap_id (maemo_device);
1334 /* printf ("DEBUG: %s: iap_id=%s\n", __FUNCTION__, iap_id); */
1338 ConIcIap* connection = tny_maemo_conic_device_get_iap (maemo_device, iap_id);
1342 const gchar *connection_name = con_ic_iap_get_name (connection);
1343 /* printf ("DEBUG: %s: connection_name=%s\n", __FUNCTION__, connection_name); */
1344 if (!connection_name)
1347 /* Get the connection-specific transport acccount, if any: */
1348 ModestAccountMgr *account_manager = modest_runtime_get_account_mgr ();
1350 /* Check if this account has connection-specific SMTP enabled */
1351 if (!modest_account_mgr_get_use_connection_specific_smtp (account_manager, account_name)) {
1355 gchar* server_account_name = modest_account_mgr_get_connection_specific_smtp (account_manager,
1358 /* printf ("DEBUG: %s: server_account_name=%s\n", __FUNCTION__, server_account_name); */
1359 if (!server_account_name) {
1360 return NULL; /* No connection-specific SMTP server was specified for this connection. */
1363 TnyAccount* account = modest_tny_account_store_get_tny_account_by (self,
1364 MODEST_TNY_ACCOUNT_STORE_QUERY_ID,
1365 server_account_name);
1367 /* printf ("DEBUG: %s: account=%p\n", __FUNCTION__, account); */
1368 g_free (server_account_name);
1370 /* Unref the get()ed object, as required by the tny_maemo_conic_device_get_iap() documentation. */
1371 g_object_unref (connection);
1375 return NULL; /* TODO: Implement this for GNOME, instead of just Maemo? */
1376 #endif /* MODEST_PLATFORM_MAEMO */
1381 modest_tny_account_store_get_transport_account_for_open_connection (ModestTnyAccountStore *self,
1382 const gchar *account_name)
1384 g_return_val_if_fail (self, NULL);
1385 g_return_val_if_fail (account_name, NULL);
1387 if (!account_name || !self)
1390 /* Get the connection-specific transport acccount, if any: */
1391 /* Note: This gives us a reference: */
1392 TnyAccount *account =
1393 get_smtp_specific_transport_account_for_open_connection (self, account_name);
1395 /* If there is no connection-specific transport account (the common case),
1396 * just get the regular transport account: */
1398 /* The special local folders don't have transport accounts. */
1399 if (strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0)
1402 /* Note: This gives us a reference: */
1403 account = modest_tny_account_store_get_server_account (self, account_name,
1404 TNY_ACCOUNT_TYPE_TRANSPORT);
1408 /* returns a reference. */
1413 modest_tny_account_store_get_local_folders_account (ModestTnyAccountStore *self)
1415 TnyAccount *account = NULL;
1416 ModestTnyAccountStorePrivate *priv;
1420 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1422 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1425 iter = tny_list_create_iterator (priv->store_accounts);
1426 while (!tny_iterator_is_done (iter) && !found) {
1427 TnyAccount *tmp_account;
1429 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1430 if (modest_tny_account_is_virtual_local_folders (tmp_account)) {
1431 account = g_object_ref (tmp_account);
1434 g_object_unref (tmp_account);
1435 tny_iterator_next (iter);
1437 g_object_unref (iter);
1439 /* Returns a new reference to the account */
1443 /*********************************************************************************/
1445 add_existing_accounts (ModestTnyAccountStore *self)
1447 GSList *account_names = NULL, *iter = NULL;
1448 ModestTnyAccountStorePrivate *priv = NULL;
1450 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1452 /* These are account names, not server_account names */
1453 account_names = modest_account_mgr_account_names (priv->account_mgr, FALSE);
1455 for (iter = account_names; iter != NULL; iter = g_slist_next (iter)) {
1456 const gchar *account_name = (const gchar*) iter->data;
1458 /* Insert all enabled accounts without notifying */
1459 if (modest_account_mgr_get_enabled (priv->account_mgr, account_name))
1460 insert_account (self, account_name, FALSE);
1462 modest_account_mgr_free_account_names (account_names);
1466 create_tny_account (ModestTnyAccountStore *self,
1468 TnyAccountType type)
1470 TnyAccount *account = NULL;
1471 ModestTnyAccountStorePrivate *priv = NULL;
1473 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1475 account = modest_tny_account_new_from_account (priv->account_mgr,
1482 /* Forget any cached password for the account, so that
1483 we use a new account if any */
1484 modest_tny_account_store_forget_password_in_memory (self,
1485 tny_account_get_id (account));
1486 /* Set the account store */
1487 g_object_set_data (G_OBJECT(account), "account_store", self);
1489 g_printerr ("modest: failed to create account for %s\n", name);
1497 add_outbox_from_transport_account_to_global_outbox (ModestTnyAccountStore *self,
1498 const gchar *account_name,
1499 TnyAccount *transport_account)
1501 TnyList *folders = NULL;
1502 TnyIterator *iter_folders = NULL;
1503 TnyAccount *local_account = NULL, *account_outbox = NULL;
1504 TnyFolder *per_account_outbox = NULL;
1505 ModestTnyAccountStorePrivate *priv = NULL;
1507 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1509 /* Create per account local outbox */
1511 modest_tny_account_new_for_per_account_local_outbox_folder (priv->account_mgr,
1514 tny_list_append (priv->store_accounts_outboxes, G_OBJECT (account_outbox));
1516 /* Get the outbox folder */
1517 folders = tny_simple_list_new ();
1518 tny_folder_store_get_folders (TNY_FOLDER_STORE (account_outbox), folders, NULL, NULL);
1519 g_assert (tny_list_get_length (folders) == 1);
1521 iter_folders = tny_list_create_iterator (folders);
1522 per_account_outbox = TNY_FOLDER (tny_iterator_get_current (iter_folders));
1523 g_object_unref (iter_folders);
1524 g_object_unref (folders);
1525 g_object_unref (account_outbox);
1527 /* Add the outbox of the new per-account-local-outbox account
1528 to the global local merged OUTBOX of the local folders
1530 local_account = modest_tny_account_store_get_local_folders_account (self);
1531 modest_tny_local_folders_account_add_folder_to_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1532 per_account_outbox);
1533 /* Add the pair to the hash table */
1534 g_hash_table_insert (priv->outbox_of_transport,
1536 per_account_outbox);
1538 g_object_unref (local_account);
1539 g_object_unref (per_account_outbox);
1544 * This function will be used for both adding new accounts and for the
1545 * initialization. In the initialization we do not want to emit
1546 * signals so notify will be FALSE, in the case of account additions
1547 * we do want to notify the observers
1550 insert_account (ModestTnyAccountStore *self,
1551 const gchar *account,
1554 ModestTnyAccountStorePrivate *priv = NULL;
1555 TnyAccount *store_account = NULL, *transport_account = NULL;
1557 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1559 /* Get the server and the transport account */
1560 store_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_STORE);
1561 transport_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT);
1563 /* Add to the list, and notify the observers */
1564 if (store_account) {
1565 tny_list_append (priv->store_accounts, G_OBJECT (store_account));
1567 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, store_account);
1568 g_object_unref (store_account);
1571 /* Add to the list, and notify the observers */
1572 if (transport_account) {
1573 /* Add account to the list */
1574 tny_list_append (priv->transport_accounts, G_OBJECT (transport_account));
1575 g_assert (TNY_IS_ACCOUNT (transport_account));
1577 /* Create a new pseudo-account with an outbox for this
1578 transport account and add it to the global outbox
1579 in the local account */
1580 add_outbox_from_transport_account_to_global_outbox (self, account, transport_account);
1583 TnyAccount *local_account = NULL;
1585 /* Notify that the local account changed */
1586 local_account = modest_tny_account_store_get_local_folders_account (self);
1587 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1588 g_object_unref (local_account);
1590 /* Notify the observers about the new account */
1591 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, transport_account);
1594 g_object_unref (transport_account);
1599 on_account_inserted (ModestAccountMgr *acc_mgr,
1600 const gchar *account,
1603 /* Insert the account and notify the observers */
1604 insert_account (MODEST_TNY_ACCOUNT_STORE (user_data), account, TRUE);
1608 on_account_removed (ModestAccountMgr *acc_mgr,
1609 const gchar *account,
1612 TnyAccount *store_account = NULL, *transport_account = NULL;
1613 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(user_data);
1615 /* Get the server and the transport account */
1617 modest_tny_account_store_get_server_account (self, account, TNY_ACCOUNT_TYPE_STORE);
1619 modest_tny_account_store_get_server_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT);
1621 /* If there was any problem creating the account, for example,
1622 with the configuration system this could not exist */
1623 if (store_account) {
1624 /* Clear the cache */
1625 tny_store_account_delete_cache (TNY_STORE_ACCOUNT (store_account));
1627 /* Notify the observers */
1628 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 0, store_account);
1629 g_object_unref (store_account);
1631 g_warning ("There is no store account for account %s\n", account);
1634 /* If there was any problem creating the account, for example,
1635 with the configuration system this could not exist */
1636 if (transport_account) {
1637 TnyAccount *local_account = NULL;
1638 TnyFolder *outbox = NULL;
1639 ModestTnyAccountStorePrivate *priv = NULL;
1641 /* Remove the OUTBOX of the account from the global outbox */
1642 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1643 outbox = g_hash_table_lookup (priv->outbox_of_transport, transport_account);
1645 if (TNY_IS_FOLDER (outbox)) {
1646 local_account = modest_tny_account_store_get_local_folders_account (self);
1647 modest_tny_local_folders_account_remove_folder_from_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1649 g_hash_table_remove (priv->outbox_of_transport, transport_account);
1651 /* Notify the change in the local account */
1652 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1653 g_object_unref (local_account);
1655 g_warning ("Removing a transport account that has no outbox");
1658 /* Notify the observers */
1659 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 0, transport_account);
1660 g_object_unref (transport_account);
1662 g_warning ("There is no transport account for account %s\n", account);
1667 add_connection_specific_transport_accounts (ModestTnyAccountStore *self)
1669 ModestTnyAccountStorePrivate *priv = NULL;
1670 GSList *list_specifics = NULL, *iter = NULL;
1672 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1674 ModestConf *conf = modest_runtime_get_conf ();
1677 list_specifics = modest_conf_get_list (conf,
1678 MODEST_CONF_CONNECTION_SPECIFIC_SMTP_LIST,
1679 MODEST_CONF_VALUE_STRING, &err);
1681 g_printerr ("modest: %s: error getting list: %s\n.", __FUNCTION__, err->message);
1686 /* Look at each connection-specific transport account for the
1687 * modest account: */
1688 iter = list_specifics;
1690 /* The list alternates between the connection name and the transport name: */
1691 iter = g_slist_next (iter);
1693 const gchar* transport_account_name = (const gchar*) (iter->data);
1694 if (transport_account_name) {
1695 TnyAccount * tny_account = NULL;
1696 /* Add the account: */
1698 modest_tny_account_new_from_server_account_name (priv->account_mgr,
1700 transport_account_name);
1702 g_object_set_data (G_OBJECT(tny_account),
1706 tny_list_append (priv->transport_accounts, G_OBJECT (tny_account));
1707 g_object_unref (tny_account);
1709 g_printerr ("modest: failed to create smtp-specific account for %s\n",
1710 transport_account_name);
1713 iter = g_slist_next (iter);