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>
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;
128 gulong acc_inserted_handler;
129 gulong acc_changed_handler;
130 gulong acc_removed_handler;
131 gulong volume_mounted_handler;
132 gulong volume_unmounted_handler;
134 /* We cache the lists of accounts here */
135 TnyList *store_accounts;
136 TnyList *transport_accounts;
137 TnyList *store_accounts_outboxes;
139 /* Matches transport accounts and outbox folder */
140 GHashTable *outbox_of_transport;
143 #define MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
144 MODEST_TYPE_TNY_ACCOUNT_STORE, \
145 ModestTnyAccountStorePrivate))
148 static GObjectClass *parent_class = NULL;
150 static guint signals[LAST_SIGNAL] = {0};
153 modest_tny_account_store_get_type (void)
155 static GType my_type = 0;
158 static const GTypeInfo my_info = {
159 sizeof(ModestTnyAccountStoreClass),
160 modest_tny_account_store_base_init, /* base init */
161 NULL, /* base finalize */
162 (GClassInitFunc) modest_tny_account_store_class_init,
163 NULL, /* class finalize */
164 NULL, /* class data */
165 sizeof(ModestTnyAccountStore),
167 (GInstanceInitFunc) modest_tny_account_store_instance_init,
171 static const GInterfaceInfo iface_info = {
172 (GInterfaceInitFunc) modest_tny_account_store_init,
173 NULL, /* interface_finalize */
174 NULL /* interface_data */
177 my_type = g_type_register_static (G_TYPE_OBJECT,
178 "ModestTnyAccountStore",
180 g_type_add_interface_static (my_type, TNY_TYPE_ACCOUNT_STORE,
188 modest_tny_account_store_base_init (gpointer g_class)
190 static gboolean tny_account_store_initialized = FALSE;
192 if (!tny_account_store_initialized) {
194 signals[ACCOUNT_CHANGED_SIGNAL] =
195 g_signal_new ("account_changed",
196 MODEST_TYPE_TNY_ACCOUNT_STORE,
198 G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_changed),
200 g_cclosure_marshal_VOID__OBJECT,
201 G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
203 signals[ACCOUNT_INSERTED_SIGNAL] =
204 g_signal_new ("account_inserted",
205 MODEST_TYPE_TNY_ACCOUNT_STORE,
207 G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_inserted),
209 g_cclosure_marshal_VOID__OBJECT,
210 G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
212 signals[ACCOUNT_REMOVED_SIGNAL] =
213 g_signal_new ("account_removed",
214 MODEST_TYPE_TNY_ACCOUNT_STORE,
216 G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_removed),
218 g_cclosure_marshal_VOID__OBJECT,
219 G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
221 /* signals[TNY_ACCOUNT_STORE_CONNECTING_FINISHED] = */
222 /* g_signal_new ("connecting_finished", */
223 /* TNY_TYPE_ACCOUNT_STORE, */
224 /* G_SIGNAL_RUN_FIRST, */
225 /* G_STRUCT_OFFSET (TnyAccountStoreIface, connecting_finished), */
227 /* g_cclosure_marshal_VOID__VOID, */
228 /* G_TYPE_NONE, 0); */
230 signals[PASSWORD_REQUESTED_SIGNAL] =
231 g_signal_new ("password_requested",
232 MODEST_TYPE_TNY_ACCOUNT_STORE,
234 G_STRUCT_OFFSET(ModestTnyAccountStoreClass, password_requested),
236 modest_marshal_VOID__STRING_POINTER_POINTER_POINTER_POINTER,
237 G_TYPE_NONE, 5, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER,
240 tny_account_store_initialized = TRUE;
246 modest_tny_account_store_class_init (ModestTnyAccountStoreClass *klass)
248 GObjectClass *gobject_class;
249 gobject_class = (GObjectClass*) klass;
251 parent_class = g_type_class_peek_parent (klass);
252 gobject_class->finalize = modest_tny_account_store_finalize;
254 g_type_class_add_private (gobject_class,
255 sizeof(ModestTnyAccountStorePrivate));
259 modest_tny_account_store_instance_init (ModestTnyAccountStore *obj)
261 GnomeVFSVolumeMonitor* monitor = NULL;
262 ModestTnyAccountStorePrivate *priv;
264 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
266 priv->cache_dir = NULL;
267 priv->account_mgr = NULL;
268 priv->session = NULL;
271 priv->outbox_of_transport = g_hash_table_new_full (g_direct_hash,
276 /* An in-memory store of passwords,
277 * for passwords that are not remembered in the configuration,
278 * so they need to be asked for from the user once in each session:
280 priv->password_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
283 /* A hash-map of modest account names to dialog pointers,
284 * so we can avoid showing the account settings twice for the same modest account: */
285 priv->account_settings_dialog_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
288 /* Respond to volume mounts and unmounts, such
289 * as the insertion/removal of the memory card: */
290 /* This is a singleton, so it does not need to be unrefed. */
291 monitor = gnome_vfs_get_volume_monitor();
293 priv->volume_mounted_handler = g_signal_connect (G_OBJECT(monitor),
295 G_CALLBACK(on_vfs_volume_mounted),
298 priv->volume_unmounted_handler = g_signal_connect (G_OBJECT(monitor), "volume-unmounted",
299 G_CALLBACK(on_vfs_volume_unmounted),
303 /* disconnect the list of TnyAccounts */
305 foreach_account_disconnect (gpointer data,
308 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT(data), FALSE, NULL, NULL);
313 foreach_account_append_to_list (gpointer data,
318 list = TNY_LIST (user_data);
319 tny_list_append (list, G_OBJECT (data));
322 /********************************************************************/
323 /* Control the state of the MMC local account */
324 /********************************************************************/
326 /** Only call this if the memory card is really mounted.
329 add_mmc_account(ModestTnyAccountStore *self, gboolean emit_insert_signal)
331 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
332 g_return_if_fail (priv->session);
334 TnyAccount *mmc_account = modest_tny_account_new_for_local_folders (priv->account_mgr,
336 MODEST_MCC1_VOLUMEPATH);
338 /* Add to the list of store accounts */
339 tny_list_append (priv->store_accounts, G_OBJECT (mmc_account));
341 if (emit_insert_signal) {
342 g_signal_emit (G_OBJECT (self),
343 signals [ACCOUNT_INSERTED_SIGNAL],
348 g_object_unref (mmc_account);
352 on_vfs_volume_mounted(GnomeVFSVolumeMonitor *volume_monitor,
353 GnomeVFSVolume *volume,
356 ModestTnyAccountStore *self;
357 ModestTnyAccountStorePrivate *priv;
361 self = MODEST_TNY_ACCOUNT_STORE(user_data);
362 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
364 /* Check whether this was the external MMC1 card: */
365 uri = gnome_vfs_volume_get_activation_uri (volume);
367 if (uri && (!strcmp (uri, MODEST_MCC1_VOLUMEPATH_URI))) {
368 add_mmc_account (self, TRUE /* emit the insert signal. */);
375 on_vfs_volume_unmounted(GnomeVFSVolumeMonitor *volume_monitor,
376 GnomeVFSVolume *volume,
379 ModestTnyAccountStore *self;
380 ModestTnyAccountStorePrivate *priv;
383 self = MODEST_TNY_ACCOUNT_STORE(user_data);
384 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
386 /* Check whether this was the external MMC1 card: */
387 uri = gnome_vfs_volume_get_activation_uri (volume);
388 if (uri && (strcmp (uri, MODEST_MCC1_VOLUMEPATH_URI) == 0)) {
389 TnyAccount *mmc_account = NULL;
390 gboolean found = FALSE;
391 TnyIterator *iter = NULL;
393 iter = tny_list_create_iterator (priv->store_accounts);
394 while (!tny_iterator_is_done (iter) && !found) {
397 account = TNY_ACCOUNT (tny_iterator_get_current (iter));
398 if (modest_tny_account_is_memory_card_account (account)) {
400 mmc_account = g_object_ref (account);
402 g_object_unref (account);
403 tny_iterator_next (iter);
405 g_object_unref (iter);
408 /* Remove from the list */
409 tny_list_remove (priv->store_accounts, G_OBJECT (mmc_account));
411 /* Notify observers */
412 g_signal_emit (G_OBJECT (self),
413 signals [ACCOUNT_REMOVED_SIGNAL],
416 g_object_unref (mmc_account);
418 g_warning ("%s: there was no store account for the unmounted MMC",
426 * modest_tny_account_store_forget_password_in_memory
427 * @self: a TnyAccountStore instance
428 * @account: A server account.
430 * Forget any password stored in memory for this account.
431 * For instance, this should be called when the user has changed the password in the account settings.
434 modest_tny_account_store_forget_password_in_memory (ModestTnyAccountStore *self, const gchar * server_account_name)
436 /* printf ("DEBUG: %s\n", __FUNCTION__); */
437 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
439 if (server_account_name && priv->password_hash) {
440 g_hash_table_remove (priv->password_hash, server_account_name);
446 update_tny_account_for_account (ModestTnyAccountStore *self, ModestAccountMgr *acc_mgr,
447 const gchar *account_name, TnyAccountType type)
449 ModestTnyAccountStorePrivate *priv;
450 TnyList* account_list;
451 gboolean found = FALSE;
452 TnyIterator *iter = NULL;
454 g_return_val_if_fail (self, FALSE);
455 g_return_val_if_fail (account_name, FALSE);
456 g_return_val_if_fail (type == TNY_ACCOUNT_TYPE_STORE ||
457 type == TNY_ACCOUNT_TYPE_TRANSPORT,
460 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
461 account_list = (type == TNY_ACCOUNT_TYPE_STORE ? priv->store_accounts : priv->transport_accounts);
463 iter = tny_list_create_iterator (account_list);
464 while (!tny_iterator_is_done (iter) && !found) {
465 TnyAccount *tny_account;
466 tny_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
468 TnyConnectionStatus conn_status = tny_account_get_connection_status (tny_account);
470 if (conn_status != TNY_CONNECTION_STATUS_RECONNECTING &&
471 conn_status != TNY_CONNECTION_STATUS_INIT) {
472 const gchar* parent_name;
473 parent_name = modest_tny_account_get_parent_modest_account_name_for_server_account (tny_account);
474 if (parent_name && strcmp (parent_name, account_name) == 0) {
476 modest_tny_account_update_from_account (tny_account, acc_mgr, account_name, type);
477 g_signal_emit (G_OBJECT(self), signals[ACCOUNT_CHANGED_SIGNAL], 0, tny_account);
480 g_object_unref (tny_account);
482 tny_iterator_next (iter);
486 g_object_unref (iter);
493 on_account_changed (ModestAccountMgr *acc_mgr,
494 const gchar *account_name,
497 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(user_data);
499 /* g_debug ("DEBUG: modest: %s\n", __FUNCTION__); */
501 /* /\* Ignore the change if it's a change in the last_updated value *\/ */
502 /* if (key && g_str_has_suffix ((const gchar *) key, MODEST_ACCOUNT_LAST_UPDATED)) */
505 if (!update_tny_account_for_account (self, acc_mgr, account_name, TNY_ACCOUNT_TYPE_STORE))
506 g_warning ("%s: failed to update store account for %s", __FUNCTION__, account_name);
507 if (!update_tny_account_for_account (self, acc_mgr, account_name, TNY_ACCOUNT_TYPE_TRANSPORT))
508 g_warning ("%s: failed to update transport account for %s", __FUNCTION__, account_name);
512 on_account_settings_hide (GtkWidget *widget, gpointer user_data)
514 TnyAccount *account = (TnyAccount*)user_data;
516 /* This is easier than using a struct for the user_data: */
517 ModestTnyAccountStore *self = modest_runtime_get_account_store();
518 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
520 const gchar *modest_account_name =
521 modest_tny_account_get_parent_modest_account_name_for_server_account (account);
522 if (modest_account_name)
523 g_hash_table_remove (priv->account_settings_dialog_hash, modest_account_name);
527 show_password_warning_only ()
529 ModestWindow *main_window =
530 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ());
532 /* Show an explanatory temporary banner: */
533 hildon_banner_show_information (
534 GTK_WIDGET(main_window), NULL, _("mcen_ib_username_pw_incorrect"));
538 show_wrong_password_dialog (TnyAccount *account)
540 /* This is easier than using a struct for the user_data: */
541 ModestTnyAccountStore *self = modest_runtime_get_account_store();
542 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
544 const gchar *modest_account_name =
545 modest_tny_account_get_parent_modest_account_name_for_server_account (account);
546 if (!modest_account_name) {
547 g_warning ("%s: modest_tny_account_get_parent_modest_account_name_for_server_account() failed.\n",
551 /* Check whether this window is already open,
552 * for instance because of a previous get_password() call:
554 gpointer dialog_as_gpointer = NULL;
555 gboolean found = FALSE;
556 if (priv->account_settings_dialog_hash) {
557 found = g_hash_table_lookup_extended (priv->account_settings_dialog_hash,
558 modest_account_name, NULL, (gpointer*)&dialog_as_gpointer);
560 ModestAccountSettingsDialog *dialog = dialog_as_gpointer;
562 ModestWindow *main_window =
563 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ());
565 gboolean created_dialog = FALSE;
566 if (!found || !dialog) {
567 dialog = modest_account_settings_dialog_new ();
568 modest_account_settings_dialog_set_account_name (dialog, modest_account_name);
569 modest_account_settings_dialog_switch_to_user_info (dialog);
571 g_hash_table_insert (priv->account_settings_dialog_hash, g_strdup (modest_account_name), dialog);
573 created_dialog = TRUE;
576 /* Show an explanatory temporary banner: */
577 hildon_banner_show_information (
578 GTK_WIDGET(dialog), NULL, _("mcen_ib_username_pw_incorrect"));
580 if (created_dialog) {
581 /* Forget it when it closes: */
582 g_signal_connect_object (G_OBJECT (dialog), "hide", G_CALLBACK (on_account_settings_hide),
585 /* Show it and delete it when it closes: */
586 modest_maemo_show_dialog_and_forget (GTK_WINDOW (main_window), GTK_DIALOG (dialog));
589 /* Just show it instead of showing it and deleting it when it closes,
590 * though it is probably open already: */
591 gtk_window_present (GTK_WINDOW (dialog));
598 request_password_and_wait (ModestTnyAccountStore *account_store,
599 const gchar* server_account_id,
605 g_signal_emit (G_OBJECT(account_store), signals[PASSWORD_REQUESTED_SIGNAL], 0,
606 server_account_id, /* server_account_name */
607 username, password, cancel, remember);
610 /* This callback will be called by Tinymail when it needs the password
611 * from the user or the account settings.
612 * It can also call forget_password() before calling this,
613 * so that we clear wrong passwords out of our account settings.
614 * Note that TnyAccount here will be the server account. */
616 get_password (TnyAccount *account, const gchar * prompt_not_used, gboolean *cancel)
618 /* TODO: Settting cancel to FALSE does not actually cancel everything.
619 * We still get multiple requests afterwards, so we end up showing the
620 * same dialogs repeatedly.
623 printf ("DEBUG: modest: %s: prompt (not shown) = %s\n", __FUNCTION__, prompt_not_used);
625 g_return_val_if_fail (account, NULL);
627 const TnyAccountStore *account_store = NULL;
628 ModestTnyAccountStore *self = NULL;
629 ModestTnyAccountStorePrivate *priv;
630 gchar *username = NULL;
632 gpointer pwd_ptr = NULL;
633 gboolean already_asked = FALSE;
635 /* Initialize the output parameter: */
639 const gchar *server_account_name = tny_account_get_id (account);
640 account_store = TNY_ACCOUNT_STORE(g_object_get_data (G_OBJECT(account),
643 if (!server_account_name || !account_store) {
644 g_warning ("modest: %s: could not retrieve account_store for account %s",
645 __FUNCTION__, server_account_name ? server_account_name : "<NULL>");
652 self = MODEST_TNY_ACCOUNT_STORE (account_store);
653 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
655 /* This hash map stores passwords, including passwords that are not stored in gconf. */
656 /* Is it in the hash? if it's already there, it must be wrong... */
657 pwd_ptr = (gpointer)&pwd; /* pwd_ptr so the compiler does not complained about
658 * type-punned ptrs...*/
659 already_asked = priv->password_hash &&
660 g_hash_table_lookup_extended (priv->password_hash,
663 (gpointer*)&pwd_ptr);
665 printf ("DEBUG: modest: %s: Already asked = %d\n", __FUNCTION__, already_asked);
667 /* If the password is not already there, try ModestConf */
668 if (!already_asked) {
669 pwd = modest_server_account_get_password (priv->account_mgr,
670 server_account_name);
671 g_hash_table_insert (priv->password_hash, g_strdup (server_account_name), g_strdup (pwd));
674 /* If it was already asked, it must have been wrong, so ask again */
675 if (already_asked || !pwd || strlen(pwd) == 0) {
676 /* As per the UI spec, if no password was set in the account settings,
677 * ask for it now. But if the password is wrong in the account settings,
678 * then show a banner and the account settings dialog so it can be corrected:
680 const gboolean settings_have_password =
681 modest_server_account_get_has_password (priv->account_mgr, server_account_name);
682 printf ("DEBUG: modest: %s: settings_have_password=%d\n", __FUNCTION__, settings_have_password);
683 if (settings_have_password) {
684 /* The password must be wrong, so show the account settings dialog so it can be corrected: */
685 show_wrong_password_dialog (account);
693 /* we don't have it yet. Get the password from the user */
694 const gchar* account_id = tny_account_get_id (account);
695 gboolean remember = FALSE;
699 /* Show an info banner, before we show the protected password dialog: */
700 show_password_warning_only();
703 request_password_and_wait (self, account_id,
704 &username, &pwd, cancel, &remember);
707 /* The password will be returned as the result,
708 * but we need to tell tinymail about the username too: */
709 tny_account_set_user (account, username);
711 /* Do not save the password in gconf,
712 * because the UI spec says "The password will never be saved in the account": */
715 printf ("%s: Storing username=%s, password=%s\n",
716 __FUNCTION__, username, pwd);
717 modest_server_account_set_username (priv->account_mgr, server_account_name,
719 modest_server_account_set_password (priv->account_mgr, server_account_name,
724 /* We need to dup the string even knowing that
725 it's already a dup of the contents of an
726 entry, because it if it's wrong, then camel
728 g_hash_table_insert (priv->password_hash, g_strdup (server_account_name), g_strdup(pwd));
730 g_hash_table_remove (priv->password_hash, server_account_name);
741 /* printf(" DEBUG: %s: returning %s\n", __FUNCTION__, pwd); */
746 /* tinymail calls this if the connection failed due to an incorrect password.
747 * And it seems to call this for any general connection failure. */
749 forget_password (TnyAccount *account)
751 printf ("DEBUG: %s\n", __FUNCTION__);
752 ModestTnyAccountStore *self;
753 ModestTnyAccountStorePrivate *priv;
754 const TnyAccountStore *account_store;
758 account_store = TNY_ACCOUNT_STORE(g_object_get_data (G_OBJECT(account),
760 self = MODEST_TNY_ACCOUNT_STORE (account_store);
761 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
762 key = tny_account_get_id (account);
764 /* Do not remove the key, this will allow us to detect that we
765 have already asked for it at least once */
766 pwd = g_hash_table_lookup (priv->password_hash, key);
768 memset (pwd, 0, strlen (pwd));
769 g_hash_table_insert (priv->password_hash, g_strdup (key), NULL);
772 /* Remove from configuration system */
774 modest_account_mgr_unset (priv->account_mgr,
775 key, MODEST_ACCOUNT_PASSWORD, TRUE);
780 modest_tny_account_store_finalize (GObject *obj)
782 GnomeVFSVolumeMonitor *volume_monitor;
783 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(obj);
784 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
786 g_free (priv->cache_dir);
787 priv->cache_dir = NULL;
789 if (priv->password_hash) {
790 g_hash_table_destroy (priv->password_hash);
791 priv->password_hash = NULL;
794 if (priv->account_settings_dialog_hash) {
795 g_hash_table_destroy (priv->account_settings_dialog_hash);
796 priv->account_settings_dialog_hash = NULL;
799 if (priv->outbox_of_transport) {
800 g_hash_table_destroy (priv->outbox_of_transport);
801 priv->outbox_of_transport = NULL;
805 /* Disconnect VFS signals */
806 volume_monitor = gnome_vfs_get_volume_monitor ();
807 if (g_signal_handler_is_connected (volume_monitor,
808 priv->volume_mounted_handler))
809 g_signal_handler_disconnect (volume_monitor,
810 priv->volume_mounted_handler);
811 if (g_signal_handler_is_connected (volume_monitor,
812 priv->volume_unmounted_handler))
813 g_signal_handler_disconnect (volume_monitor,
814 priv->volume_unmounted_handler);
816 if (priv->account_mgr) {
817 /* Disconnect signals */
818 if (g_signal_handler_is_connected (priv->account_mgr,
819 priv->acc_inserted_handler))
820 g_signal_handler_disconnect (priv->account_mgr,
821 priv->acc_inserted_handler);
822 if (g_signal_handler_is_connected (priv->account_mgr,
823 priv->acc_changed_handler))
824 g_signal_handler_disconnect (priv->account_mgr,
825 priv->acc_changed_handler);
826 if (g_signal_handler_is_connected (priv->account_mgr,
827 priv->acc_removed_handler))
828 g_signal_handler_disconnect (priv->account_mgr,
829 priv->acc_removed_handler);
831 g_object_unref (G_OBJECT(priv->account_mgr));
832 priv->account_mgr = NULL;
836 g_object_unref (G_OBJECT(priv->device));
840 /* Destroy all accounts. Disconnect all accounts before they are destroyed */
841 if (priv->store_accounts) {
842 tny_list_foreach (priv->store_accounts, foreach_account_disconnect, NULL);
843 g_object_unref (priv->store_accounts);
844 priv->store_accounts = NULL;
847 if (priv->transport_accounts) {
848 tny_list_foreach (priv->transport_accounts, foreach_account_disconnect, NULL);
849 g_object_unref (priv->transport_accounts);
850 priv->transport_accounts = NULL;
853 if (priv->store_accounts_outboxes) {
854 g_object_unref (priv->store_accounts_outboxes);
855 priv->store_accounts_outboxes = NULL;
859 camel_object_unref (CAMEL_OBJECT(priv->session));
860 priv->session = NULL;
863 G_OBJECT_CLASS(parent_class)->finalize (obj);
867 volume_path_is_mounted (const gchar* path)
869 g_return_val_if_fail (path, FALSE);
871 gboolean result = FALSE;
872 gchar * path_as_uri = g_filename_to_uri (path, NULL, NULL);
873 g_return_val_if_fail (path_as_uri, FALSE);
875 /* Get the monitor singleton: */
876 GnomeVFSVolumeMonitor *monitor = gnome_vfs_get_volume_monitor();
878 /* This seems like a simpler way to do this, but it returns a
879 * GnomeVFSVolume even if the drive is not mounted: */
881 GnomeVFSVolume *volume = gnome_vfs_volume_monitor_get_volume_for_path (monitor,
882 MODEST_MCC1_VOLUMEPATH);
884 gnome_vfs_volume_unref(volume);
888 /* Get the mounted volumes from the monitor: */
889 GList *list = gnome_vfs_volume_monitor_get_mounted_volumes (monitor);
891 for (iter = list; iter; iter = g_list_next (iter)) {
892 GnomeVFSVolume *volume = (GnomeVFSVolume*)iter->data;
896 gnome_vfs_volume_get_display_name (volume);
897 printf ("volume display name=%s\n", display_name);
898 g_free (display_name);
902 gnome_vfs_volume_get_activation_uri (volume);
903 /* printf (" uri=%s\n", uri); */
904 if (uri && (strcmp (uri, path_as_uri) == 0))
909 gnome_vfs_volume_unref (volume);
915 g_free (path_as_uri);
920 ModestTnyAccountStore*
921 modest_tny_account_store_new (ModestAccountMgr *account_mgr,
925 ModestTnyAccountStorePrivate *priv;
926 TnyAccount *local_account = NULL;
928 g_return_val_if_fail (account_mgr, NULL);
929 g_return_val_if_fail (device, NULL);
931 obj = G_OBJECT(g_object_new(MODEST_TYPE_TNY_ACCOUNT_STORE, NULL));
932 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
934 priv->account_mgr = g_object_ref (G_OBJECT(account_mgr));
935 priv->device = g_object_ref (device);
937 priv->session = tny_session_camel_new (TNY_ACCOUNT_STORE(obj));
938 if (!priv->session) {
939 g_warning ("failed to get TnySessionCamel");
943 /* Set the ui locker */
944 tny_session_camel_set_ui_locker (priv->session, tny_gtk_lockable_new ());
946 /* Connect signals */
947 priv->acc_inserted_handler = g_signal_connect (G_OBJECT(account_mgr), "account_inserted",
948 G_CALLBACK (on_account_inserted), obj);
949 priv->acc_changed_handler = g_signal_connect (G_OBJECT(account_mgr), "account_changed",
950 G_CALLBACK (on_account_changed), obj);
951 priv->acc_removed_handler = g_signal_connect (G_OBJECT(account_mgr), "account_removed",
952 G_CALLBACK (on_account_removed), obj);
954 /* Create the lists of accounts */
955 priv->store_accounts = tny_simple_list_new ();
956 priv->transport_accounts = tny_simple_list_new ();
957 priv->store_accounts_outboxes = tny_simple_list_new ();
959 /* Create the local folders account */
961 modest_tny_account_new_for_local_folders (priv->account_mgr, priv->session, NULL);
962 tny_list_append (priv->store_accounts, G_OBJECT(local_account));
963 g_object_unref (local_account);
965 /* Add the other remote accounts. Do this after adding the
966 local account, because we need to add our outboxes to the
967 global OUTBOX hosted in the local account */
968 add_existing_accounts (MODEST_TNY_ACCOUNT_STORE (obj));
970 /* FIXME: I'm doing this (adding an "if (FALSE)"because this
971 stuff is not working properly and could cause SIGSEVs, for
972 example one send queue will be created for each connection
973 specific SMTP server, so when tinymail asks for the outbox
974 it will return NULL because there is no outbox folder for
975 this specific transport accounts, and it's a must that the
976 send queue returns an outbox */
978 /* Add connection-specific transport accounts */
979 add_connection_specific_transport_accounts (MODEST_TNY_ACCOUNT_STORE(obj));
981 /* This is a singleton, so it does not need to be unrefed. */
982 if (volume_path_is_mounted (MODEST_MCC1_VOLUMEPATH)) {
984 add_mmc_account (MODEST_TNY_ACCOUNT_STORE (obj), FALSE /* don't emit the insert signal. */);
987 return MODEST_TNY_ACCOUNT_STORE(obj);
991 modest_tny_account_store_get_accounts (TnyAccountStore *self,
993 TnyGetAccountsRequestType request_type)
995 ModestTnyAccountStorePrivate *priv;
997 g_return_if_fail (self);
998 g_return_if_fail (TNY_IS_LIST(list));
1000 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1002 switch (request_type) {
1003 case TNY_ACCOUNT_STORE_BOTH:
1004 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
1005 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
1007 case TNY_ACCOUNT_STORE_STORE_ACCOUNTS:
1008 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
1010 case TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS:
1011 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
1014 g_return_if_reached ();
1017 /* Initialize session. Why do we need this ??? */
1018 tny_session_camel_set_initialized (priv->session);
1023 modest_tny_account_store_get_cache_dir (TnyAccountStore *self)
1025 ModestTnyAccountStorePrivate *priv;
1026 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1028 if (!priv->cache_dir)
1029 priv->cache_dir = g_build_filename (g_get_home_dir(),
1030 MODEST_DIR, MODEST_CACHE_DIR, NULL);
1031 return priv->cache_dir;
1036 * callers need to unref
1039 modest_tny_account_store_get_device (TnyAccountStore *self)
1041 ModestTnyAccountStorePrivate *priv;
1043 g_return_val_if_fail (self, NULL);
1045 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1048 return g_object_ref (G_OBJECT(priv->device));
1055 modest_tny_account_store_find_account_by_url (TnyAccountStore *self, const gchar* url_string)
1057 return modest_tny_account_store_get_tny_account_by (MODEST_TNY_ACCOUNT_STORE (self),
1058 MODEST_TNY_ACCOUNT_STORE_QUERY_URL,
1065 modest_tny_account_store_alert (TnyAccountStore *self,
1066 TnyAccount *account,
1069 const GError *error)
1071 ModestTransportStoreProtocol proto =
1072 MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN;
1073 const gchar* server_name = NULL;
1074 gchar *prompt = NULL;
1078 g_return_val_if_fail (account, FALSE);
1079 g_return_val_if_fail (error, FALSE);
1081 if ((error->domain != TNY_ACCOUNT_ERROR) && (error->domain != TNY_ACCOUNT_STORE_ERROR))
1084 /* Get the server name: */
1085 server_name = tny_account_get_hostname (account);
1088 const gchar *proto_name = tny_account_get_proto (account);
1090 proto = modest_protocol_info_get_transport_store_protocol (proto_name);
1092 g_warning("modest: %s: account with id=%s has no proto.\n", __FUNCTION__,
1093 tny_account_get_id (account));
1098 switch (error->code) {
1099 case TNY_ACCOUNT_STORE_ERROR_CANCEL_ALERT:
1100 case TNY_ACCOUNT_ERROR_TRY_CONNECT_USER_CANCEL:
1101 /* Don't show waste the user's time by showing him a dialog telling
1102 * him that he has just cancelled something: */
1105 case TNY_ACCOUNT_ERROR_TRY_CONNECT_HOST_LOOKUP_FAILED:
1106 case TNY_ACCOUNT_ERROR_TRY_CONNECT_SERVICE_UNAVAILABLE:
1107 /* TODO: Show the appropriate message, depending on whether it's POP or IMAP: */
1109 case MODEST_PROTOCOL_STORE_POP:
1110 prompt = g_strdup_printf (_("emev_ni_ui_pop3_msg_connect_error"),
1113 case MODEST_PROTOCOL_STORE_IMAP:
1114 prompt = g_strdup_printf (_("emev_ni_ui_imap_connect_server_error"),
1117 case MODEST_PROTOCOL_TRANSPORT_SMTP:
1118 prompt = g_strdup_printf (_("emev_ib_ui_smtp_server_invalid"),
1122 g_return_val_if_reached (FALSE);
1126 case TNY_ACCOUNT_ERROR_TRY_CONNECT_AUTHENTICATION_NOT_SUPPORTED:
1127 /* This is "Secure connection failed", even though the logical
1128 * ID has _certificate_ in the name: */
1129 prompt = g_strdup (_("mail_ni_ssl_certificate_error"));
1132 case TNY_ACCOUNT_ERROR_TRY_CONNECT_CERTIFICATE:
1133 /* We'll show the proper dialog later */
1136 case TNY_ACCOUNT_ERROR_TRY_CONNECT:
1137 /* The tinymail camel implementation just sends us this for almost
1138 * everything, so we have to guess at the cause.
1139 * It could be a wrong password, or inability to resolve a hostname,
1140 * or lack of network, or incorrect authentication method, or something entirely different: */
1141 /* TODO: Fix camel to provide specific error codes, and then use the
1142 * specific dialog messages from Chapter 12 of the UI spec.
1144 case TNY_ACCOUNT_STORE_ERROR_UNKNOWN_ALERT:
1147 g_return_val_if_reached (FALSE);
1151 if (error->code == TNY_ACCOUNT_ERROR_TRY_CONNECT_CERTIFICATE)
1152 retval = modest_platform_run_certificate_conformation_dialog (server_name,
1155 retval = modest_platform_run_alert_dialog (prompt, question);
1165 modest_tny_account_store_init (gpointer g, gpointer iface_data)
1167 TnyAccountStoreIface *klass;
1169 g_return_if_fail (g);
1171 klass = (TnyAccountStoreIface *)g;
1173 klass->get_accounts_func =
1174 modest_tny_account_store_get_accounts;
1175 klass->get_cache_dir_func =
1176 modest_tny_account_store_get_cache_dir;
1177 klass->get_device_func =
1178 modest_tny_account_store_get_device;
1180 modest_tny_account_store_alert;
1181 klass->find_account_func =
1182 modest_tny_account_store_find_account_by_url;
1186 modest_tny_account_store_set_get_pass_func (ModestTnyAccountStore *self,
1187 ModestTnyGetPassFunc func)
1189 /* not implemented, we use signals */
1190 g_printerr ("modest: set_get_pass_func not implemented\n");
1194 modest_tny_account_store_get_session (TnyAccountStore *self)
1196 g_return_val_if_fail (self, NULL);
1197 return MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self)->session;
1201 get_tny_account_by (TnyList *accounts,
1202 ModestTnyAccountStoreQueryType type,
1205 TnyIterator *iter = NULL;
1206 gboolean found = FALSE;
1207 TnyAccount *retval = NULL;
1209 iter = tny_list_create_iterator (accounts);
1210 while (!tny_iterator_is_done (iter) && !found) {
1211 TnyAccount *tmp_account = NULL;
1212 const gchar *val = NULL;
1214 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1216 case MODEST_TNY_ACCOUNT_STORE_QUERY_ID:
1217 val = tny_account_get_id (tmp_account);
1219 case MODEST_TNY_ACCOUNT_STORE_QUERY_URL:
1220 val = tny_account_get_url_string (tmp_account);
1224 if (type == MODEST_TNY_ACCOUNT_STORE_QUERY_URL &&
1225 tny_account_matches_url_string (tmp_account, str)) {
1226 retval = g_object_ref (tmp_account);
1229 if (strcmp (val, str) == 0) {
1230 retval = g_object_ref (tmp_account);
1234 g_object_unref (tmp_account);
1235 tny_iterator_next (iter);
1237 g_object_unref (iter);
1243 modest_tny_account_store_get_tny_account_by (ModestTnyAccountStore *self,
1244 ModestTnyAccountStoreQueryType type,
1247 TnyAccount *account = NULL;
1248 ModestTnyAccountStorePrivate *priv;
1250 g_return_val_if_fail (self, NULL);
1251 g_return_val_if_fail (str, NULL);
1253 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1255 /* Search in store accounts */
1256 account = get_tny_account_by (priv->store_accounts, type, str);
1258 /* If we already found something, no need to search the transport accounts */
1260 account = get_tny_account_by (priv->transport_accounts, type, str);
1262 /* If we already found something, no need to search the
1263 per-account outbox accounts */
1265 account = get_tny_account_by (priv->store_accounts_outboxes, type, str);
1268 /* Warn if nothing was found. This is generally unusual. */
1270 g_warning("%s: Failed to find account with %s=%s\n",
1272 (type == MODEST_TNY_ACCOUNT_STORE_QUERY_ID) ? "ID" : "URL",
1276 /* Returns a new reference to the account if found */
1281 modest_tny_account_store_get_server_account (ModestTnyAccountStore *self,
1282 const gchar *account_name,
1283 TnyAccountType type)
1285 ModestTnyAccountStorePrivate *priv = NULL;
1286 TnyAccount *retval = NULL;
1287 TnyList *account_list = NULL;
1288 TnyIterator *iter = NULL;
1291 g_return_val_if_fail (self, NULL);
1292 g_return_val_if_fail (account_name, NULL);
1293 g_return_val_if_fail (type == TNY_ACCOUNT_TYPE_STORE ||
1294 type == TNY_ACCOUNT_TYPE_TRANSPORT,
1297 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1299 account_list = (type == TNY_ACCOUNT_TYPE_STORE) ?
1300 priv->store_accounts :
1301 priv->transport_accounts;
1303 if (!account_list) {
1304 g_printerr ("%s: No server accounts of type %s\n", __FUNCTION__,
1305 (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport");
1309 /* Look for the server account */
1311 iter = tny_list_create_iterator (account_list);
1312 while (!tny_iterator_is_done (iter) && !found) {
1313 const gchar *modest_acc_name;
1314 TnyAccount *tmp_account;
1316 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1318 modest_tny_account_get_parent_modest_account_name_for_server_account (tmp_account);
1320 if (!strcmp (account_name, modest_acc_name)) {
1322 retval = g_object_ref (tmp_account);
1324 /* Free and continue */
1325 g_object_unref (tmp_account);
1326 tny_iterator_next (iter);
1330 g_printerr ("modest: %s: could not get tny %s account for %s\n." \
1331 "Number of server accounts of this type=%d\n", __FUNCTION__,
1332 (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport",
1333 account_name, tny_list_get_length (account_list));
1336 /* Returns a new reference */
1341 get_smtp_specific_transport_account_for_open_connection (ModestTnyAccountStore *self,
1342 const gchar *account_name)
1344 /* Get the current connection: */
1345 TnyDevice *device = modest_runtime_get_device ();
1347 if (!tny_device_is_online (device))
1350 g_return_val_if_fail (self, NULL);
1353 #ifdef MODEST_PLATFORM_MAEMO
1354 g_assert (TNY_IS_MAEMO_CONIC_DEVICE (device));
1355 TnyMaemoConicDevice *maemo_device = TNY_MAEMO_CONIC_DEVICE (device);
1356 const gchar* iap_id = tny_maemo_conic_device_get_current_iap_id (maemo_device);
1357 /* printf ("DEBUG: %s: iap_id=%s\n", __FUNCTION__, iap_id); */
1361 ConIcIap* connection = tny_maemo_conic_device_get_iap (maemo_device, iap_id);
1365 const gchar *connection_name = con_ic_iap_get_name (connection);
1366 /* printf ("DEBUG: %s: connection_name=%s\n", __FUNCTION__, connection_name); */
1367 if (!connection_name)
1370 /* Get the connection-specific transport acccount, if any: */
1371 ModestAccountMgr *account_manager = modest_runtime_get_account_mgr ();
1373 /* Check if this account has connection-specific SMTP enabled */
1374 if (!modest_account_mgr_get_use_connection_specific_smtp (account_manager, account_name)) {
1378 gchar* server_account_name = modest_account_mgr_get_connection_specific_smtp (account_manager,
1381 /* printf ("DEBUG: %s: server_account_name=%s\n", __FUNCTION__, server_account_name); */
1382 if (!server_account_name) {
1383 return NULL; /* No connection-specific SMTP server was specified for this connection. */
1386 TnyAccount* account = modest_tny_account_store_get_tny_account_by (self,
1387 MODEST_TNY_ACCOUNT_STORE_QUERY_ID,
1388 server_account_name);
1390 /* printf ("DEBUG: %s: account=%p\n", __FUNCTION__, account); */
1391 g_free (server_account_name);
1393 /* Unref the get()ed object, as required by the tny_maemo_conic_device_get_iap() documentation. */
1394 g_object_unref (connection);
1398 return NULL; /* TODO: Implement this for GNOME, instead of just Maemo? */
1399 #endif /* MODEST_PLATFORM_MAEMO */
1404 modest_tny_account_store_get_transport_account_for_open_connection (ModestTnyAccountStore *self,
1405 const gchar *account_name)
1407 g_return_val_if_fail (self, NULL);
1408 g_return_val_if_fail (account_name, NULL);
1410 if (!account_name || !self)
1413 /* Get the connection-specific transport acccount, if any: */
1414 /* Note: This gives us a reference: */
1415 TnyAccount *account =
1416 get_smtp_specific_transport_account_for_open_connection (self, account_name);
1418 /* If there is no connection-specific transport account (the common case),
1419 * just get the regular transport account: */
1421 /* The special local folders don't have transport accounts. */
1422 if (strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0)
1425 /* Note: This gives us a reference: */
1426 account = modest_tny_account_store_get_server_account (self, account_name,
1427 TNY_ACCOUNT_TYPE_TRANSPORT);
1431 /* returns a reference. */
1436 modest_tny_account_store_get_local_folders_account (ModestTnyAccountStore *self)
1438 TnyAccount *account = NULL;
1439 ModestTnyAccountStorePrivate *priv;
1443 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1445 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1448 iter = tny_list_create_iterator (priv->store_accounts);
1449 while (!tny_iterator_is_done (iter) && !found) {
1450 TnyAccount *tmp_account;
1452 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1453 if (modest_tny_account_is_virtual_local_folders (tmp_account)) {
1454 account = g_object_ref (tmp_account);
1457 g_object_unref (tmp_account);
1458 tny_iterator_next (iter);
1460 g_object_unref (iter);
1462 /* Returns a new reference to the account */
1466 /*********************************************************************************/
1468 add_existing_accounts (ModestTnyAccountStore *self)
1470 GSList *account_names = NULL, *iter = NULL;
1471 ModestTnyAccountStorePrivate *priv = NULL;
1473 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1475 /* These are account names, not server_account names */
1476 account_names = modest_account_mgr_account_names (priv->account_mgr, FALSE);
1478 for (iter = account_names; iter != NULL; iter = g_slist_next (iter)) {
1479 const gchar *account_name = (const gchar*) iter->data;
1481 /* Insert all enabled accounts without notifying */
1482 if (modest_account_mgr_get_enabled (priv->account_mgr, account_name))
1483 insert_account (self, account_name, FALSE);
1485 modest_account_mgr_free_account_names (account_names);
1489 create_tny_account (ModestTnyAccountStore *self,
1491 TnyAccountType type)
1493 TnyAccount *account = NULL;
1494 ModestTnyAccountStorePrivate *priv = NULL;
1496 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1498 account = modest_tny_account_new_from_account (priv->account_mgr,
1505 /* Forget any cached password for the account, so that
1506 we use a new account if any */
1507 modest_tny_account_store_forget_password_in_memory (self,
1508 tny_account_get_id (account));
1509 /* Set the account store */
1510 g_object_set_data (G_OBJECT(account), "account_store", self);
1512 g_printerr ("modest: failed to create account for %s\n", name);
1520 add_outbox_from_transport_account_to_global_outbox (ModestTnyAccountStore *self,
1521 const gchar *account_name,
1522 TnyAccount *transport_account)
1524 TnyList *folders = NULL;
1525 TnyIterator *iter_folders = NULL;
1526 TnyAccount *local_account = NULL, *account_outbox = NULL;
1527 TnyFolder *per_account_outbox = NULL;
1528 ModestTnyAccountStorePrivate *priv = NULL;
1530 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1532 /* Create per account local outbox */
1534 modest_tny_account_new_for_per_account_local_outbox_folder (priv->account_mgr,
1537 tny_list_append (priv->store_accounts_outboxes, G_OBJECT (account_outbox));
1539 /* Get the outbox folder */
1540 folders = tny_simple_list_new ();
1541 tny_folder_store_get_folders (TNY_FOLDER_STORE (account_outbox), folders, NULL, NULL);
1542 g_assert (tny_list_get_length (folders) == 1);
1544 iter_folders = tny_list_create_iterator (folders);
1545 per_account_outbox = TNY_FOLDER (tny_iterator_get_current (iter_folders));
1546 g_object_unref (iter_folders);
1547 g_object_unref (folders);
1548 g_object_unref (account_outbox);
1550 /* Add the outbox of the new per-account-local-outbox account
1551 to the global local merged OUTBOX of the local folders
1553 local_account = modest_tny_account_store_get_local_folders_account (self);
1554 modest_tny_local_folders_account_add_folder_to_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1555 per_account_outbox);
1556 /* Add the pair to the hash table */
1557 g_hash_table_insert (priv->outbox_of_transport,
1559 per_account_outbox);
1561 g_object_unref (local_account);
1562 g_object_unref (per_account_outbox);
1567 * This function will be used for both adding new accounts and for the
1568 * initialization. In the initialization we do not want to emit
1569 * signals so notify will be FALSE, in the case of account additions
1570 * we do want to notify the observers
1573 insert_account (ModestTnyAccountStore *self,
1574 const gchar *account,
1577 ModestTnyAccountStorePrivate *priv = NULL;
1578 TnyAccount *store_account = NULL, *transport_account = NULL;
1580 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1582 /* Get the server and the transport account */
1583 store_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_STORE);
1584 transport_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT);
1586 /* Add to the list, and notify the observers */
1587 if (store_account) {
1588 tny_list_append (priv->store_accounts, G_OBJECT (store_account));
1590 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, store_account);
1591 g_object_unref (store_account);
1594 /* Add to the list, and notify the observers */
1595 if (transport_account) {
1596 /* Add account to the list */
1597 tny_list_append (priv->transport_accounts, G_OBJECT (transport_account));
1598 g_assert (TNY_IS_ACCOUNT (transport_account));
1600 /* Create a new pseudo-account with an outbox for this
1601 transport account and add it to the global outbox
1602 in the local account */
1603 add_outbox_from_transport_account_to_global_outbox (self, account, transport_account);
1606 TnyAccount *local_account = NULL;
1608 /* Notify that the local account changed */
1609 local_account = modest_tny_account_store_get_local_folders_account (self);
1610 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1611 g_object_unref (local_account);
1613 /* Notify the observers about the new account */
1614 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, transport_account);
1617 g_object_unref (transport_account);
1622 on_account_inserted (ModestAccountMgr *acc_mgr,
1623 const gchar *account,
1626 /* Insert the account and notify the observers */
1627 insert_account (MODEST_TNY_ACCOUNT_STORE (user_data), account, TRUE);
1631 on_account_removed (ModestAccountMgr *acc_mgr,
1632 const gchar *account,
1635 TnyAccount *store_account = NULL, *transport_account = NULL;
1636 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(user_data);
1638 /* Get the server and the transport account */
1640 modest_tny_account_store_get_server_account (self, account, TNY_ACCOUNT_TYPE_STORE);
1642 modest_tny_account_store_get_server_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT);
1644 /* If there was any problem creating the account, for example,
1645 with the configuration system this could not exist */
1646 if (store_account) {
1647 /* Clear the cache */
1648 tny_store_account_delete_cache (TNY_STORE_ACCOUNT (store_account));
1650 /* Notify the observers */
1651 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 0, store_account);
1652 g_object_unref (store_account);
1654 g_warning ("There is no store account for account %s\n", account);
1657 /* If there was any problem creating the account, for example,
1658 with the configuration system this could not exist */
1659 if (transport_account) {
1660 TnyAccount *local_account = NULL;
1661 TnyFolder *outbox = NULL;
1662 ModestTnyAccountStorePrivate *priv = NULL;
1664 /* Remove the OUTBOX of the account from the global outbox */
1665 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1666 outbox = g_hash_table_lookup (priv->outbox_of_transport, transport_account);
1668 if (TNY_IS_FOLDER (outbox)) {
1669 local_account = modest_tny_account_store_get_local_folders_account (self);
1670 modest_tny_local_folders_account_remove_folder_from_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1672 g_hash_table_remove (priv->outbox_of_transport, transport_account);
1674 /* Notify the change in the local account */
1675 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1676 g_object_unref (local_account);
1678 g_warning ("Removing a transport account that has no outbox");
1681 /* Notify the observers */
1682 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 0, transport_account);
1683 g_object_unref (transport_account);
1685 g_warning ("There is no transport account for account %s\n", account);
1690 add_connection_specific_transport_accounts (ModestTnyAccountStore *self)
1692 ModestTnyAccountStorePrivate *priv = NULL;
1693 GSList *list_specifics = NULL, *iter = NULL;
1695 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1697 ModestConf *conf = modest_runtime_get_conf ();
1700 list_specifics = modest_conf_get_list (conf,
1701 MODEST_CONF_CONNECTION_SPECIFIC_SMTP_LIST,
1702 MODEST_CONF_VALUE_STRING, &err);
1704 g_printerr ("modest: %s: error getting list: %s\n.", __FUNCTION__, err->message);
1709 /* Look at each connection-specific transport account for the
1710 * modest account: */
1711 iter = list_specifics;
1713 /* The list alternates between the connection name and the transport name: */
1714 iter = g_slist_next (iter);
1716 const gchar* transport_account_name = (const gchar*) (iter->data);
1717 if (transport_account_name) {
1718 TnyAccount * tny_account = NULL;
1719 /* Add the account: */
1721 modest_tny_account_new_from_server_account_name (priv->account_mgr,
1723 transport_account_name);
1725 g_object_set_data (G_OBJECT(tny_account),
1729 tny_list_append (priv->transport_accounts, G_OBJECT (tny_account));
1730 g_object_unref (tny_account);
1732 g_printerr ("modest: failed to create smtp-specific account for %s\n",
1733 transport_account_name);
1736 iter = g_slist_next (iter);