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 const gchar* parent_name =
469 modest_tny_account_get_parent_modest_account_name_for_server_account (tny_account);
470 if (parent_name && strcmp (parent_name, account_name) == 0) {
472 modest_tny_account_update_from_account (tny_account, acc_mgr, account_name, type);
473 g_signal_emit (G_OBJECT(self), signals[ACCOUNT_CHANGED_SIGNAL], 0, tny_account);
475 g_object_unref (tny_account);
477 tny_iterator_next (iter);
481 g_object_unref (iter);
488 on_account_changed (ModestAccountMgr *acc_mgr,
489 const gchar *account_name,
492 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(user_data);
494 g_debug ("DEBUG: modest: %s\n", __FUNCTION__);
496 /* Ignore the change if it's a change in the last_updated value */
497 // if (key && g_str_has_suffix ((const gchar *) key, MODEST_ACCOUNT_LAST_UPDATED))
500 if (!update_tny_account_for_account (self, acc_mgr, account_name, TNY_ACCOUNT_TYPE_STORE))
501 g_warning ("%s: failed to update store account for %s", __FUNCTION__, account_name);
502 if (!update_tny_account_for_account (self, acc_mgr, account_name, TNY_ACCOUNT_TYPE_TRANSPORT))
503 g_warning ("%s: failed to update transport account for %s", __FUNCTION__, account_name);
507 on_account_settings_hide (GtkWidget *widget, gpointer user_data)
509 TnyAccount *account = (TnyAccount*)user_data;
511 /* This is easier than using a struct for the user_data: */
512 ModestTnyAccountStore *self = modest_runtime_get_account_store();
513 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
515 const gchar *modest_account_name =
516 modest_tny_account_get_parent_modest_account_name_for_server_account (account);
517 if (modest_account_name)
518 g_hash_table_remove (priv->account_settings_dialog_hash, modest_account_name);
522 show_password_warning_only ()
524 ModestWindow *main_window =
525 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ());
527 /* Show an explanatory temporary banner: */
528 hildon_banner_show_information (
529 GTK_WIDGET(main_window), NULL, _("mcen_ib_username_pw_incorrect"));
533 show_wrong_password_dialog (TnyAccount *account)
535 /* This is easier than using a struct for the user_data: */
536 ModestTnyAccountStore *self = modest_runtime_get_account_store();
537 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
539 const gchar *modest_account_name =
540 modest_tny_account_get_parent_modest_account_name_for_server_account (account);
541 if (!modest_account_name) {
542 g_warning ("%s: modest_tny_account_get_parent_modest_account_name_for_server_account() failed.\n",
546 /* Check whether this window is already open,
547 * for instance because of a previous get_password() call:
549 gpointer dialog_as_gpointer = NULL;
550 gboolean found = FALSE;
551 if (priv->account_settings_dialog_hash) {
552 found = g_hash_table_lookup_extended (priv->account_settings_dialog_hash,
553 modest_account_name, NULL, (gpointer*)&dialog_as_gpointer);
555 ModestAccountSettingsDialog *dialog = dialog_as_gpointer;
557 ModestWindow *main_window =
558 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ());
560 gboolean created_dialog = FALSE;
561 if (!found || !dialog) {
562 dialog = modest_account_settings_dialog_new ();
563 modest_account_settings_dialog_set_account_name (dialog, modest_account_name);
564 modest_account_settings_dialog_switch_to_user_info (dialog);
566 g_hash_table_insert (priv->account_settings_dialog_hash, g_strdup (modest_account_name), dialog);
568 created_dialog = TRUE;
571 /* Show an explanatory temporary banner: */
572 hildon_banner_show_information (
573 GTK_WIDGET(dialog), NULL, _("mcen_ib_username_pw_incorrect"));
575 if (created_dialog) {
576 /* Forget it when it closes: */
577 g_signal_connect_object (G_OBJECT (dialog), "hide", G_CALLBACK (on_account_settings_hide),
580 /* Show it and delete it when it closes: */
581 modest_maemo_show_dialog_and_forget (GTK_WINDOW (main_window), GTK_DIALOG (dialog));
584 /* Just show it instead of showing it and deleting it when it closes,
585 * though it is probably open already: */
586 gtk_window_present (GTK_WINDOW (dialog));
593 request_password_and_wait (ModestTnyAccountStore *account_store,
594 const gchar* server_account_id,
600 g_signal_emit (G_OBJECT(account_store), signals[PASSWORD_REQUESTED_SIGNAL], 0,
601 server_account_id, /* server_account_name */
602 username, password, cancel, remember);
605 /* This callback will be called by Tinymail when it needs the password
606 * from the user or the account settings.
607 * It can also call forget_password() before calling this,
608 * so that we clear wrong passwords out of our account settings.
609 * Note that TnyAccount here will be the server account. */
611 get_password (TnyAccount *account, const gchar * prompt_not_used, gboolean *cancel)
613 /* TODO: Settting cancel to FALSE does not actually cancel everything.
614 * We still get multiple requests afterwards, so we end up showing the
615 * same dialogs repeatedly.
618 printf ("DEBUG: modest: %s: prompt (not shown) = %s\n", __FUNCTION__, prompt_not_used);
620 g_return_val_if_fail (account, NULL);
622 const TnyAccountStore *account_store = NULL;
623 ModestTnyAccountStore *self = NULL;
624 ModestTnyAccountStorePrivate *priv;
625 gchar *username = NULL;
627 gpointer pwd_ptr = NULL;
628 gboolean already_asked = FALSE;
630 /* Initialize the output parameter: */
634 const gchar *server_account_name = tny_account_get_id (account);
635 account_store = TNY_ACCOUNT_STORE(g_object_get_data (G_OBJECT(account),
638 if (!server_account_name || !account_store) {
639 g_warning ("modest: %s: could not retrieve account_store for account %s",
640 __FUNCTION__, server_account_name ? server_account_name : "<NULL>");
647 self = MODEST_TNY_ACCOUNT_STORE (account_store);
648 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
650 /* This hash map stores passwords, including passwords that are not stored in gconf. */
651 /* Is it in the hash? if it's already there, it must be wrong... */
652 pwd_ptr = (gpointer)&pwd; /* pwd_ptr so the compiler does not complained about
653 * type-punned ptrs...*/
654 already_asked = priv->password_hash &&
655 g_hash_table_lookup_extended (priv->password_hash,
658 (gpointer*)&pwd_ptr);
660 printf ("DEBUG: modest: %s: Already asked = %d\n", __FUNCTION__, already_asked);
662 /* If the password is not already there, try ModestConf */
663 if (!already_asked) {
664 pwd = modest_server_account_get_password (priv->account_mgr,
665 server_account_name);
666 g_hash_table_insert (priv->password_hash, g_strdup (server_account_name), g_strdup (pwd));
669 /* If it was already asked, it must have been wrong, so ask again */
670 if (already_asked || !pwd || strlen(pwd) == 0) {
671 /* As per the UI spec, if no password was set in the account settings,
672 * ask for it now. But if the password is wrong in the account settings,
673 * then show a banner and the account settings dialog so it can be corrected:
675 const gboolean settings_have_password =
676 modest_server_account_get_has_password (priv->account_mgr, server_account_name);
677 printf ("DEBUG: modest: %s: settings_have_password=%d\n", __FUNCTION__, settings_have_password);
678 if (settings_have_password) {
679 /* The password must be wrong, so show the account settings dialog so it can be corrected: */
680 show_wrong_password_dialog (account);
688 /* we don't have it yet. Get the password from the user */
689 const gchar* account_id = tny_account_get_id (account);
690 gboolean remember = FALSE;
694 /* Show an info banner, before we show the protected password dialog: */
695 show_password_warning_only();
698 request_password_and_wait (self, account_id,
699 &username, &pwd, cancel, &remember);
702 /* The password will be returned as the result,
703 * but we need to tell tinymail about the username too: */
704 tny_account_set_user (account, username);
706 /* Do not save the password in gconf,
707 * because the UI spec says "The password will never be saved in the account": */
710 printf ("%s: Storing username=%s, password=%s\n",
711 __FUNCTION__, username, pwd);
712 modest_server_account_set_username (priv->account_mgr, server_account_name,
714 modest_server_account_set_password (priv->account_mgr, server_account_name,
719 /* We need to dup the string even knowing that
720 it's already a dup of the contents of an
721 entry, because it if it's wrong, then camel
723 g_hash_table_insert (priv->password_hash, g_strdup (server_account_name), g_strdup(pwd));
725 g_hash_table_remove (priv->password_hash, server_account_name);
736 /* printf(" DEBUG: %s: returning %s\n", __FUNCTION__, pwd); */
741 /* tinymail calls this if the connection failed due to an incorrect password.
742 * And it seems to call this for any general connection failure. */
744 forget_password (TnyAccount *account)
746 printf ("DEBUG: %s\n", __FUNCTION__);
747 ModestTnyAccountStore *self;
748 ModestTnyAccountStorePrivate *priv;
749 const TnyAccountStore *account_store;
753 account_store = TNY_ACCOUNT_STORE(g_object_get_data (G_OBJECT(account),
755 self = MODEST_TNY_ACCOUNT_STORE (account_store);
756 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
757 key = tny_account_get_id (account);
759 /* Do not remove the key, this will allow us to detect that we
760 have already asked for it at least once */
761 pwd = g_hash_table_lookup (priv->password_hash, key);
763 memset (pwd, 0, strlen (pwd));
764 g_hash_table_insert (priv->password_hash, g_strdup (key), NULL);
767 /* Remove from configuration system */
769 modest_account_mgr_unset (priv->account_mgr,
770 key, MODEST_ACCOUNT_PASSWORD, TRUE);
775 modest_tny_account_store_finalize (GObject *obj)
777 GnomeVFSVolumeMonitor *volume_monitor;
778 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(obj);
779 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
781 g_free (priv->cache_dir);
782 priv->cache_dir = NULL;
784 if (priv->password_hash) {
785 g_hash_table_destroy (priv->password_hash);
786 priv->password_hash = NULL;
789 if (priv->account_settings_dialog_hash) {
790 g_hash_table_destroy (priv->account_settings_dialog_hash);
791 priv->account_settings_dialog_hash = NULL;
794 if (priv->outbox_of_transport) {
795 g_hash_table_destroy (priv->outbox_of_transport);
796 priv->outbox_of_transport = NULL;
800 /* Disconnect VFS signals */
801 volume_monitor = gnome_vfs_get_volume_monitor ();
802 if (g_signal_handler_is_connected (volume_monitor,
803 priv->volume_mounted_handler))
804 g_signal_handler_disconnect (volume_monitor,
805 priv->volume_mounted_handler);
806 if (g_signal_handler_is_connected (volume_monitor,
807 priv->volume_unmounted_handler))
808 g_signal_handler_disconnect (volume_monitor,
809 priv->volume_unmounted_handler);
811 if (priv->account_mgr) {
812 /* Disconnect signals */
813 if (g_signal_handler_is_connected (priv->account_mgr,
814 priv->acc_inserted_handler))
815 g_signal_handler_disconnect (priv->account_mgr,
816 priv->acc_inserted_handler);
817 if (g_signal_handler_is_connected (priv->account_mgr,
818 priv->acc_changed_handler))
819 g_signal_handler_disconnect (priv->account_mgr,
820 priv->acc_changed_handler);
821 if (g_signal_handler_is_connected (priv->account_mgr,
822 priv->acc_removed_handler))
823 g_signal_handler_disconnect (priv->account_mgr,
824 priv->acc_removed_handler);
826 g_object_unref (G_OBJECT(priv->account_mgr));
827 priv->account_mgr = NULL;
831 g_object_unref (G_OBJECT(priv->device));
835 /* Destroy all accounts. Disconnect all accounts before they are destroyed */
836 if (priv->store_accounts) {
837 tny_list_foreach (priv->store_accounts, foreach_account_disconnect, NULL);
838 g_object_unref (priv->store_accounts);
839 priv->store_accounts = NULL;
842 if (priv->transport_accounts) {
843 tny_list_foreach (priv->transport_accounts, foreach_account_disconnect, NULL);
844 g_object_unref (priv->transport_accounts);
845 priv->transport_accounts = NULL;
848 if (priv->store_accounts_outboxes) {
849 g_object_unref (priv->store_accounts_outboxes);
850 priv->store_accounts_outboxes = NULL;
854 camel_object_unref (CAMEL_OBJECT(priv->session));
855 priv->session = NULL;
858 G_OBJECT_CLASS(parent_class)->finalize (obj);
862 volume_path_is_mounted (const gchar* path)
864 g_return_val_if_fail (path, FALSE);
866 gboolean result = FALSE;
867 gchar * path_as_uri = g_filename_to_uri (path, NULL, NULL);
868 g_return_val_if_fail (path_as_uri, FALSE);
870 /* Get the monitor singleton: */
871 GnomeVFSVolumeMonitor *monitor = gnome_vfs_get_volume_monitor();
873 /* This seems like a simpler way to do this, but it returns a
874 * GnomeVFSVolume even if the drive is not mounted: */
876 GnomeVFSVolume *volume = gnome_vfs_volume_monitor_get_volume_for_path (monitor,
877 MODEST_MCC1_VOLUMEPATH);
879 gnome_vfs_volume_unref(volume);
883 /* Get the mounted volumes from the monitor: */
884 GList *list = gnome_vfs_volume_monitor_get_mounted_volumes (monitor);
886 for (iter = list; iter; iter = g_list_next (iter)) {
887 GnomeVFSVolume *volume = (GnomeVFSVolume*)iter->data;
891 gnome_vfs_volume_get_display_name (volume);
892 printf ("volume display name=%s\n", display_name);
893 g_free (display_name);
897 gnome_vfs_volume_get_activation_uri (volume);
898 /* printf (" uri=%s\n", uri); */
899 if (uri && (strcmp (uri, path_as_uri) == 0))
904 gnome_vfs_volume_unref (volume);
910 g_free (path_as_uri);
915 ModestTnyAccountStore*
916 modest_tny_account_store_new (ModestAccountMgr *account_mgr,
920 ModestTnyAccountStorePrivate *priv;
921 TnyAccount *local_account = NULL;
923 g_return_val_if_fail (account_mgr, NULL);
924 g_return_val_if_fail (device, NULL);
926 obj = G_OBJECT(g_object_new(MODEST_TYPE_TNY_ACCOUNT_STORE, NULL));
927 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
929 priv->account_mgr = g_object_ref (G_OBJECT(account_mgr));
930 priv->device = g_object_ref (device);
932 priv->session = tny_session_camel_new (TNY_ACCOUNT_STORE(obj));
933 if (!priv->session) {
934 g_warning ("failed to get TnySessionCamel");
938 /* Set the ui locker */
939 tny_session_camel_set_ui_locker (priv->session, tny_gtk_lockable_new ());
941 /* Connect signals */
942 priv->acc_inserted_handler = g_signal_connect (G_OBJECT(account_mgr), "account_inserted",
943 G_CALLBACK (on_account_inserted), obj);
944 priv->acc_changed_handler = g_signal_connect (G_OBJECT(account_mgr), "account_changed",
945 G_CALLBACK (on_account_changed), obj);
946 priv->acc_removed_handler = g_signal_connect (G_OBJECT(account_mgr), "account_removed",
947 G_CALLBACK (on_account_removed), obj);
949 /* Create the lists of accounts */
950 priv->store_accounts = tny_simple_list_new ();
951 priv->transport_accounts = tny_simple_list_new ();
952 priv->store_accounts_outboxes = tny_simple_list_new ();
954 /* Create the local folders account */
956 modest_tny_account_new_for_local_folders (priv->account_mgr, priv->session, NULL);
957 tny_list_append (priv->store_accounts, G_OBJECT(local_account));
958 g_object_unref (local_account);
960 /* Add the other remote accounts. Do this after adding the
961 local account, because we need to add our outboxes to the
962 global OUTBOX hosted in the local account */
963 add_existing_accounts (MODEST_TNY_ACCOUNT_STORE (obj));
965 /* FIXME: I'm doing this (adding an "if (FALSE)"because this
966 stuff is not working properly and could cause SIGSEVs, for
967 example one send queue will be created for each connection
968 specific SMTP server, so when tinymail asks for the outbox
969 it will return NULL because there is no outbox folder for
970 this specific transport accounts, and it's a must that the
971 send queue returns an outbox */
973 /* Add connection-specific transport accounts */
974 add_connection_specific_transport_accounts (MODEST_TNY_ACCOUNT_STORE(obj));
976 /* This is a singleton, so it does not need to be unrefed. */
977 if (volume_path_is_mounted (MODEST_MCC1_VOLUMEPATH)) {
979 add_mmc_account (MODEST_TNY_ACCOUNT_STORE (obj), FALSE /* don't emit the insert signal. */);
982 return MODEST_TNY_ACCOUNT_STORE(obj);
986 modest_tny_account_store_get_accounts (TnyAccountStore *self,
988 TnyGetAccountsRequestType request_type)
990 ModestTnyAccountStorePrivate *priv;
992 g_return_if_fail (self);
993 g_return_if_fail (TNY_IS_LIST(list));
995 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
997 switch (request_type) {
998 case TNY_ACCOUNT_STORE_BOTH:
999 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
1000 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
1002 case TNY_ACCOUNT_STORE_STORE_ACCOUNTS:
1003 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
1005 case TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS:
1006 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
1009 g_return_if_reached ();
1012 /* Initialize session. Why do we need this ??? */
1013 tny_session_camel_set_initialized (priv->session);
1018 modest_tny_account_store_get_cache_dir (TnyAccountStore *self)
1020 ModestTnyAccountStorePrivate *priv;
1021 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1023 if (!priv->cache_dir)
1024 priv->cache_dir = g_build_filename (g_get_home_dir(),
1025 MODEST_DIR, MODEST_CACHE_DIR, NULL);
1026 return priv->cache_dir;
1031 * callers need to unref
1034 modest_tny_account_store_get_device (TnyAccountStore *self)
1036 ModestTnyAccountStorePrivate *priv;
1038 g_return_val_if_fail (self, NULL);
1040 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1043 return g_object_ref (G_OBJECT(priv->device));
1050 modest_tny_account_store_find_account_by_url (TnyAccountStore *self, const gchar* url_string)
1052 return modest_tny_account_store_get_tny_account_by (MODEST_TNY_ACCOUNT_STORE (self),
1053 MODEST_TNY_ACCOUNT_STORE_QUERY_URL,
1060 modest_tny_account_store_alert (TnyAccountStore *self,
1061 TnyAccount *account,
1064 const GError *error)
1066 ModestTransportStoreProtocol proto =
1067 MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN;
1068 const gchar* server_name = NULL;
1069 gchar *prompt = NULL;
1073 g_return_val_if_fail (account, FALSE);
1074 g_return_val_if_fail (error, FALSE);
1076 if ((error->domain != TNY_ACCOUNT_ERROR) && (error->domain != TNY_ACCOUNT_STORE_ERROR))
1079 /* Get the server name: */
1080 server_name = tny_account_get_hostname (account);
1083 const gchar *proto_name = tny_account_get_proto (account);
1085 proto = modest_protocol_info_get_transport_store_protocol (proto_name);
1087 g_warning("modest: %s: account with id=%s has no proto.\n", __FUNCTION__,
1088 tny_account_get_id (account));
1093 switch (error->code) {
1094 case TNY_ACCOUNT_STORE_ERROR_CANCEL_ALERT:
1095 case TNY_ACCOUNT_ERROR_TRY_CONNECT_USER_CANCEL:
1096 /* Don't show waste the user's time by showing him a dialog telling
1097 * him that he has just cancelled something: */
1100 case TNY_ACCOUNT_ERROR_TRY_CONNECT_HOST_LOOKUP_FAILED:
1101 case TNY_ACCOUNT_ERROR_TRY_CONNECT_SERVICE_UNAVAILABLE:
1102 /* TODO: Show the appropriate message, depending on whether it's POP or IMAP: */
1104 case MODEST_PROTOCOL_STORE_POP:
1105 prompt = g_strdup_printf (_("emev_ni_ui_pop3_msg_connect_error"),
1108 case MODEST_PROTOCOL_STORE_IMAP:
1109 prompt = g_strdup_printf (_("emev_ni_ui_imap_connect_server_error"),
1112 case MODEST_PROTOCOL_TRANSPORT_SMTP:
1113 prompt = g_strdup_printf (_("emev_ib_ui_smtp_server_invalid"),
1117 g_return_val_if_reached (FALSE);
1121 case TNY_ACCOUNT_ERROR_TRY_CONNECT_AUTHENTICATION_NOT_SUPPORTED:
1122 /* This is "Secure connection failed", even though the logical
1123 * ID has _certificate_ in the name: */
1124 prompt = g_strdup (_("mail_ni_ssl_certificate_error"));
1127 case TNY_ACCOUNT_ERROR_TRY_CONNECT_CERTIFICATE:
1128 /* We'll show the proper dialog later */
1131 case TNY_ACCOUNT_ERROR_TRY_CONNECT:
1132 /* The tinymail camel implementation just sends us this for almost
1133 * everything, so we have to guess at the cause.
1134 * It could be a wrong password, or inability to resolve a hostname,
1135 * or lack of network, or incorrect authentication method, or something entirely different: */
1136 /* TODO: Fix camel to provide specific error codes, and then use the
1137 * specific dialog messages from Chapter 12 of the UI spec.
1139 case TNY_ACCOUNT_STORE_ERROR_UNKNOWN_ALERT:
1141 /* TODO: Remove the internal error message for the real release.
1142 * This is just so the testers can give us more information: */
1143 /* However, I haven't seen this for a few weeks, so maybe the users
1144 * will never see it. murrayc. */
1145 /* prompt = _("Modest account not yet fully configured."); */
1146 prompt = g_strdup_printf(
1147 "%s\n (Internal error message, often very misleading):\n%s",
1148 _("Incorrect Account Settings"),
1151 /* Note: If the password was wrong then get_password() would be called again,
1152 * instead of this vfunc being called. */
1156 g_return_val_if_reached (FALSE);
1160 if (error->code == TNY_ACCOUNT_ERROR_TRY_CONNECT_CERTIFICATE)
1161 retval = modest_platform_run_certificate_conformation_dialog (server_name,
1164 retval = modest_platform_run_alert_dialog (prompt, question);
1174 modest_tny_account_store_init (gpointer g, gpointer iface_data)
1176 TnyAccountStoreIface *klass;
1178 g_return_if_fail (g);
1180 klass = (TnyAccountStoreIface *)g;
1182 klass->get_accounts_func =
1183 modest_tny_account_store_get_accounts;
1184 klass->get_cache_dir_func =
1185 modest_tny_account_store_get_cache_dir;
1186 klass->get_device_func =
1187 modest_tny_account_store_get_device;
1189 modest_tny_account_store_alert;
1190 klass->find_account_func =
1191 modest_tny_account_store_find_account_by_url;
1195 modest_tny_account_store_set_get_pass_func (ModestTnyAccountStore *self,
1196 ModestTnyGetPassFunc func)
1198 /* not implemented, we use signals */
1199 g_printerr ("modest: set_get_pass_func not implemented\n");
1203 modest_tny_account_store_get_session (TnyAccountStore *self)
1205 g_return_val_if_fail (self, NULL);
1206 return MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self)->session;
1210 get_tny_account_by (TnyList *accounts,
1211 ModestTnyAccountStoreQueryType type,
1214 TnyIterator *iter = NULL;
1215 gboolean found = FALSE;
1216 TnyAccount *retval = NULL;
1218 iter = tny_list_create_iterator (accounts);
1219 while (!tny_iterator_is_done (iter) && !found) {
1220 TnyAccount *tmp_account = NULL;
1221 const gchar *val = NULL;
1223 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1225 case MODEST_TNY_ACCOUNT_STORE_QUERY_ID:
1226 val = tny_account_get_id (tmp_account);
1228 case MODEST_TNY_ACCOUNT_STORE_QUERY_URL:
1229 val = tny_account_get_url_string (tmp_account);
1233 if (type == MODEST_TNY_ACCOUNT_STORE_QUERY_URL &&
1234 tny_account_matches_url_string (tmp_account, str)) {
1235 retval = g_object_ref (tmp_account);
1238 if (strcmp (val, str) == 0) {
1239 retval = g_object_ref (tmp_account);
1243 g_object_unref (tmp_account);
1244 tny_iterator_next (iter);
1246 g_object_unref (iter);
1252 modest_tny_account_store_get_tny_account_by (ModestTnyAccountStore *self,
1253 ModestTnyAccountStoreQueryType type,
1256 TnyAccount *account = NULL;
1257 ModestTnyAccountStorePrivate *priv;
1259 g_return_val_if_fail (self, NULL);
1260 g_return_val_if_fail (str, NULL);
1262 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1264 /* Search in store accounts */
1265 account = get_tny_account_by (priv->store_accounts, type, str);
1267 /* If we already found something, no need to search the transport accounts */
1269 account = get_tny_account_by (priv->transport_accounts, type, str);
1271 /* If we already found something, no need to search the
1272 per-account outbox accounts */
1274 account = get_tny_account_by (priv->store_accounts_outboxes, type, str);
1277 /* Warn if nothing was found. This is generally unusual. */
1279 g_warning("%s: Failed to find account with %s=%s\n",
1281 (type == MODEST_TNY_ACCOUNT_STORE_QUERY_ID) ? "ID" : "URL",
1285 /* Returns a new reference to the account if found */
1290 modest_tny_account_store_get_server_account (ModestTnyAccountStore *self,
1291 const gchar *account_name,
1292 TnyAccountType type)
1294 ModestTnyAccountStorePrivate *priv = NULL;
1295 TnyAccount *retval = NULL;
1296 TnyList *account_list = NULL;
1297 TnyIterator *iter = NULL;
1300 g_return_val_if_fail (self, NULL);
1301 g_return_val_if_fail (account_name, NULL);
1302 g_return_val_if_fail (type == TNY_ACCOUNT_TYPE_STORE ||
1303 type == TNY_ACCOUNT_TYPE_TRANSPORT,
1306 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1308 account_list = (type == TNY_ACCOUNT_TYPE_STORE) ?
1309 priv->store_accounts :
1310 priv->transport_accounts;
1312 if (!account_list) {
1313 g_printerr ("%s: No server accounts of type %s\n", __FUNCTION__,
1314 (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport");
1318 /* Look for the server account */
1320 iter = tny_list_create_iterator (account_list);
1321 while (!tny_iterator_is_done (iter) && !found) {
1322 const gchar *modest_acc_name;
1323 TnyAccount *tmp_account;
1325 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1327 modest_tny_account_get_parent_modest_account_name_for_server_account (tmp_account);
1329 if (!strcmp (account_name, modest_acc_name)) {
1331 retval = g_object_ref (tmp_account);
1333 /* Free and continue */
1334 g_object_unref (tmp_account);
1335 tny_iterator_next (iter);
1339 g_printerr ("modest: %s: could not get tny %s account for %s\n." \
1340 "Number of server accounts of this type=%d\n", __FUNCTION__,
1341 (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport",
1342 account_name, tny_list_get_length (account_list));
1345 /* Returns a new reference */
1350 get_smtp_specific_transport_account_for_open_connection (ModestTnyAccountStore *self,
1351 const gchar *account_name)
1353 /* Get the current connection: */
1354 TnyDevice *device = modest_runtime_get_device ();
1356 if (!tny_device_is_online (device))
1359 g_return_val_if_fail (self, NULL);
1362 #ifdef MODEST_PLATFORM_MAEMO
1363 g_assert (TNY_IS_MAEMO_CONIC_DEVICE (device));
1364 TnyMaemoConicDevice *maemo_device = TNY_MAEMO_CONIC_DEVICE (device);
1365 const gchar* iap_id = tny_maemo_conic_device_get_current_iap_id (maemo_device);
1366 /* printf ("DEBUG: %s: iap_id=%s\n", __FUNCTION__, iap_id); */
1370 ConIcIap* connection = tny_maemo_conic_device_get_iap (maemo_device, iap_id);
1374 const gchar *connection_name = con_ic_iap_get_name (connection);
1375 /* printf ("DEBUG: %s: connection_name=%s\n", __FUNCTION__, connection_name); */
1376 if (!connection_name)
1379 /* Get the connection-specific transport acccount, if any: */
1380 ModestAccountMgr *account_manager = modest_runtime_get_account_mgr ();
1382 /* Check if this account has connection-specific SMTP enabled */
1383 if (!modest_account_mgr_get_use_connection_specific_smtp (account_manager, account_name)) {
1387 gchar* server_account_name = modest_account_mgr_get_connection_specific_smtp (account_manager,
1390 /* printf ("DEBUG: %s: server_account_name=%s\n", __FUNCTION__, server_account_name); */
1391 if (!server_account_name) {
1392 return NULL; /* No connection-specific SMTP server was specified for this connection. */
1395 TnyAccount* account = modest_tny_account_store_get_tny_account_by (self,
1396 MODEST_TNY_ACCOUNT_STORE_QUERY_ID,
1397 server_account_name);
1399 /* printf ("DEBUG: %s: account=%p\n", __FUNCTION__, account); */
1400 g_free (server_account_name);
1402 /* Unref the get()ed object, as required by the tny_maemo_conic_device_get_iap() documentation. */
1403 g_object_unref (connection);
1407 return NULL; /* TODO: Implement this for GNOME, instead of just Maemo? */
1408 #endif /* MODEST_PLATFORM_MAEMO */
1413 modest_tny_account_store_get_transport_account_for_open_connection (ModestTnyAccountStore *self,
1414 const gchar *account_name)
1416 g_return_val_if_fail (self, NULL);
1417 g_return_val_if_fail (account_name, NULL);
1419 if (!account_name || !self)
1422 /* Get the connection-specific transport acccount, if any: */
1423 /* Note: This gives us a reference: */
1424 TnyAccount *account =
1425 get_smtp_specific_transport_account_for_open_connection (self, account_name);
1427 /* If there is no connection-specific transport account (the common case),
1428 * just get the regular transport account: */
1430 /* The special local folders don't have transport accounts. */
1431 if (strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0)
1434 /* Note: This gives us a reference: */
1435 account = modest_tny_account_store_get_server_account (self, account_name,
1436 TNY_ACCOUNT_TYPE_TRANSPORT);
1440 /* returns a reference. */
1445 modest_tny_account_store_get_local_folders_account (ModestTnyAccountStore *self)
1447 TnyAccount *account = NULL;
1448 ModestTnyAccountStorePrivate *priv;
1452 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1454 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1457 iter = tny_list_create_iterator (priv->store_accounts);
1458 while (!tny_iterator_is_done (iter) && !found) {
1459 TnyAccount *tmp_account;
1461 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1462 if (modest_tny_account_is_virtual_local_folders (tmp_account)) {
1463 account = g_object_ref (tmp_account);
1466 g_object_unref (tmp_account);
1467 tny_iterator_next (iter);
1469 g_object_unref (iter);
1471 /* Returns a new reference to the account */
1475 /*********************************************************************************/
1477 add_existing_accounts (ModestTnyAccountStore *self)
1479 GSList *account_names = NULL, *iter = NULL;
1480 ModestTnyAccountStorePrivate *priv = NULL;
1482 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1484 /* These are account names, not server_account names */
1485 account_names = modest_account_mgr_account_names (priv->account_mgr, FALSE);
1487 for (iter = account_names; iter != NULL; iter = g_slist_next (iter)) {
1488 const gchar *account_name = (const gchar*) iter->data;
1490 /* Insert all enabled accounts without notifying */
1491 if (modest_account_mgr_get_enabled (priv->account_mgr, account_name))
1492 insert_account (self, account_name, FALSE);
1494 modest_account_mgr_free_account_names (account_names);
1498 create_tny_account (ModestTnyAccountStore *self,
1500 TnyAccountType type)
1502 TnyAccount *account = NULL;
1503 ModestTnyAccountStorePrivate *priv = NULL;
1505 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1507 account = modest_tny_account_new_from_account (priv->account_mgr,
1514 /* Forget any cached password for the account, so that
1515 we use a new account if any */
1516 modest_tny_account_store_forget_password_in_memory (self,
1517 tny_account_get_id (account));
1518 /* Set the account store */
1519 g_object_set_data (G_OBJECT(account), "account_store", self);
1521 g_printerr ("modest: failed to create account for %s\n", name);
1529 add_outbox_from_transport_account_to_global_outbox (ModestTnyAccountStore *self,
1530 const gchar *account_name,
1531 TnyAccount *transport_account)
1533 TnyList *folders = NULL;
1534 TnyIterator *iter_folders = NULL;
1535 TnyAccount *local_account = NULL, *account_outbox = NULL;
1536 TnyFolder *per_account_outbox = NULL;
1537 ModestTnyAccountStorePrivate *priv = NULL;
1539 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1541 /* Create per account local outbox */
1543 modest_tny_account_new_for_per_account_local_outbox_folder (priv->account_mgr,
1546 tny_list_append (priv->store_accounts_outboxes, G_OBJECT (account_outbox));
1548 /* Get the outbox folder */
1549 folders = tny_simple_list_new ();
1550 tny_folder_store_get_folders (TNY_FOLDER_STORE (account_outbox), folders, NULL, NULL);
1551 g_assert (tny_list_get_length (folders) == 1);
1553 iter_folders = tny_list_create_iterator (folders);
1554 per_account_outbox = TNY_FOLDER (tny_iterator_get_current (iter_folders));
1555 g_object_unref (iter_folders);
1556 g_object_unref (folders);
1557 g_object_unref (account_outbox);
1559 /* Add the outbox of the new per-account-local-outbox account
1560 to the global local merged OUTBOX of the local folders
1562 local_account = modest_tny_account_store_get_local_folders_account (self);
1563 modest_tny_local_folders_account_add_folder_to_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1564 per_account_outbox);
1565 /* Add the pair to the hash table */
1566 g_hash_table_insert (priv->outbox_of_transport,
1568 per_account_outbox);
1570 g_object_unref (local_account);
1571 g_object_unref (per_account_outbox);
1576 * This function will be used for both adding new accounts and for the
1577 * initialization. In the initialization we do not want to emit
1578 * signals so notify will be FALSE, in the case of account additions
1579 * we do want to notify the observers
1582 insert_account (ModestTnyAccountStore *self,
1583 const gchar *account,
1586 ModestTnyAccountStorePrivate *priv = NULL;
1587 TnyAccount *store_account = NULL, *transport_account = NULL;
1589 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1591 /* Get the server and the transport account */
1592 store_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_STORE);
1593 transport_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT);
1595 /* Add to the list, and notify the observers */
1596 if (store_account) {
1597 tny_list_append (priv->store_accounts, G_OBJECT (store_account));
1599 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, store_account);
1600 g_object_unref (store_account);
1603 /* Add to the list, and notify the observers */
1604 if (transport_account) {
1605 /* Add account to the list */
1606 tny_list_append (priv->transport_accounts, G_OBJECT (transport_account));
1607 g_assert (TNY_IS_ACCOUNT (transport_account));
1609 /* Create a new pseudo-account with an outbox for this
1610 transport account and add it to the global outbox
1611 in the local account */
1612 add_outbox_from_transport_account_to_global_outbox (self, account, transport_account);
1615 TnyAccount *local_account = NULL;
1617 /* Notify that the local account changed */
1618 local_account = modest_tny_account_store_get_local_folders_account (self);
1619 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1620 g_object_unref (local_account);
1622 /* Notify the observers about the new account */
1623 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, transport_account);
1626 g_object_unref (transport_account);
1631 on_account_inserted (ModestAccountMgr *acc_mgr,
1632 const gchar *account,
1635 /* Insert the account and notify the observers */
1636 insert_account (MODEST_TNY_ACCOUNT_STORE (user_data), account, TRUE);
1640 on_account_removed (ModestAccountMgr *acc_mgr,
1641 const gchar *account,
1644 TnyAccount *store_account = NULL, *transport_account = NULL;
1645 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(user_data);
1647 /* Get the server and the transport account */
1649 modest_tny_account_store_get_server_account (self, account, TNY_ACCOUNT_TYPE_STORE);
1651 modest_tny_account_store_get_server_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT);
1653 /* If there was any problem creating the account, for example,
1654 with the configuration system this could not exist */
1655 if (store_account) {
1656 /* Clear the cache */
1657 tny_store_account_delete_cache (TNY_STORE_ACCOUNT (store_account));
1659 /* Notify the observers */
1660 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 0, store_account);
1661 g_object_unref (store_account);
1663 g_warning ("There is no store account for account %s\n", account);
1666 /* If there was any problem creating the account, for example,
1667 with the configuration system this could not exist */
1668 if (transport_account) {
1669 TnyAccount *local_account = NULL;
1670 TnyFolder *outbox = NULL;
1671 ModestTnyAccountStorePrivate *priv = NULL;
1673 /* Remove the OUTBOX of the account from the global outbox */
1674 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1675 outbox = g_hash_table_lookup (priv->outbox_of_transport, transport_account);
1677 if (TNY_IS_FOLDER (outbox)) {
1678 local_account = modest_tny_account_store_get_local_folders_account (self);
1679 modest_tny_local_folders_account_remove_folder_from_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1681 g_hash_table_remove (priv->outbox_of_transport, transport_account);
1683 /* Notify the change in the local account */
1684 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1685 g_object_unref (local_account);
1687 g_warning ("Removing a transport account that has no outbox");
1690 /* Notify the observers */
1691 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 0, transport_account);
1692 g_object_unref (transport_account);
1694 g_warning ("There is no transport account for account %s\n", account);
1699 add_connection_specific_transport_accounts (ModestTnyAccountStore *self)
1701 ModestTnyAccountStorePrivate *priv = NULL;
1702 GSList *list_specifics = NULL, *iter = NULL;
1704 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1706 ModestConf *conf = modest_runtime_get_conf ();
1709 list_specifics = modest_conf_get_list (conf,
1710 MODEST_CONF_CONNECTION_SPECIFIC_SMTP_LIST,
1711 MODEST_CONF_VALUE_STRING, &err);
1713 g_printerr ("modest: %s: error getting list: %s\n.", __FUNCTION__, err->message);
1718 /* Look at each connection-specific transport account for the
1719 * modest account: */
1720 iter = list_specifics;
1722 /* The list alternates between the connection name and the transport name: */
1723 iter = g_slist_next (iter);
1725 const gchar* transport_account_name = (const gchar*) (iter->data);
1726 if (transport_account_name) {
1727 TnyAccount * tny_account = NULL;
1728 /* Add the account: */
1730 modest_tny_account_new_from_server_account_name (priv->account_mgr,
1732 transport_account_name);
1734 g_object_set_data (G_OBJECT(tny_account),
1738 tny_list_append (priv->transport_accounts, G_OBJECT (tny_account));
1739 g_object_unref (tny_account);
1741 g_printerr ("modest: failed to create smtp-specific account for %s\n",
1742 transport_account_name);
1745 iter = g_slist_next (iter);