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-error.h>
34 #include <tny-account.h>
35 #include <tny-account-store.h>
36 #include <tny-store-account.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-signal-mgr.h>
54 #include <modest-debug.h>
56 #include "modest-tny-account-store.h"
57 #include "modest-tny-platform-factory.h"
58 #include <tny-gtk-lockable.h>
59 #include <camel/camel.h>
60 #include <modest-platform.h>
61 #include "modest-ui-actions.h"
62 #include <widgets/modest-account-settings-dialog.h>
64 #ifdef MODEST_PLATFORM_MAEMO
65 #include <tny-maemo-conic-device.h>
66 #include <maemo/modest-maemo-utils.h>
69 #include <libgnomevfs/gnome-vfs-volume-monitor.h>
71 /* 'private'/'protected' functions */
72 static void modest_tny_account_store_class_init (ModestTnyAccountStoreClass *klass);
73 static void modest_tny_account_store_finalize (GObject *obj);
74 static void modest_tny_account_store_instance_init (ModestTnyAccountStore *obj);
75 static void modest_tny_account_store_init (gpointer g, gpointer iface_data);
76 static void modest_tny_account_store_base_init (gpointer g_class);
78 static void on_account_inserted (ModestAccountMgr *acc_mgr,
82 static void add_existing_accounts (ModestTnyAccountStore *self);
84 static void insert_account (ModestTnyAccountStore *self,
88 static void on_account_removed (ModestAccountMgr *acc_mgr,
92 static gchar* get_password (TnyAccount *account,
93 const gchar * prompt_not_used,
96 static void forget_password (TnyAccount *account);
98 static void on_vfs_volume_mounted (GnomeVFSVolumeMonitor *volume_monitor,
99 GnomeVFSVolume *volume,
102 static void on_vfs_volume_unmounted (GnomeVFSVolumeMonitor *volume_monitor,
103 GnomeVFSVolume *volume,
106 static void forget_password_in_memory (ModestTnyAccountStore *self,
107 const gchar *server_account_name);
109 static void add_connection_specific_transport_accounts (ModestTnyAccountStore *self);
111 static void connection_status_changed (TnyAccount *account,
112 TnyConnectionStatus status,
115 /* list my signals */
117 ACCOUNT_CHANGED_SIGNAL,
118 ACCOUNT_INSERTED_SIGNAL,
119 ACCOUNT_REMOVED_SIGNAL,
121 PASSWORD_REQUESTED_SIGNAL,
125 typedef struct _ModestTnyAccountStorePrivate ModestTnyAccountStorePrivate;
126 struct _ModestTnyAccountStorePrivate {
128 GHashTable *password_hash;
129 GHashTable *account_settings_dialog_hash;
130 ModestAccountMgr *account_mgr;
131 TnySessionCamel *session;
136 /* We cache the lists of accounts here */
137 TnyList *store_accounts;
138 TnyList *transport_accounts;
139 TnyList *store_accounts_outboxes;
141 /* Matches transport accounts and outbox folder */
142 GHashTable *outbox_of_transport;
145 #define MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
146 MODEST_TYPE_TNY_ACCOUNT_STORE, \
147 ModestTnyAccountStorePrivate))
150 static GObjectClass *parent_class = NULL;
152 static guint signals[LAST_SIGNAL] = {0};
155 modest_tny_account_store_get_type (void)
157 static GType my_type = 0;
160 static const GTypeInfo my_info = {
161 sizeof(ModestTnyAccountStoreClass),
162 modest_tny_account_store_base_init, /* base init */
163 NULL, /* base finalize */
164 (GClassInitFunc) modest_tny_account_store_class_init,
165 NULL, /* class finalize */
166 NULL, /* class data */
167 sizeof(ModestTnyAccountStore),
169 (GInstanceInitFunc) modest_tny_account_store_instance_init,
173 static const GInterfaceInfo iface_info = {
174 (GInterfaceInitFunc) modest_tny_account_store_init,
175 NULL, /* interface_finalize */
176 NULL /* interface_data */
179 my_type = g_type_register_static (G_TYPE_OBJECT,
180 "ModestTnyAccountStore",
182 g_type_add_interface_static (my_type, TNY_TYPE_ACCOUNT_STORE,
190 modest_tny_account_store_base_init (gpointer g_class)
192 static gboolean tny_account_store_initialized = FALSE;
194 if (!tny_account_store_initialized) {
196 signals[ACCOUNT_CHANGED_SIGNAL] =
197 g_signal_new ("account_changed",
198 MODEST_TYPE_TNY_ACCOUNT_STORE,
200 G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_changed),
202 g_cclosure_marshal_VOID__OBJECT,
203 G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
205 signals[ACCOUNT_INSERTED_SIGNAL] =
206 g_signal_new ("account_inserted",
207 MODEST_TYPE_TNY_ACCOUNT_STORE,
209 G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_inserted),
211 g_cclosure_marshal_VOID__OBJECT,
212 G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
214 signals[ACCOUNT_REMOVED_SIGNAL] =
215 g_signal_new ("account_removed",
216 MODEST_TYPE_TNY_ACCOUNT_STORE,
218 G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_removed),
220 g_cclosure_marshal_VOID__OBJECT,
221 G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
223 signals[PASSWORD_REQUESTED_SIGNAL] =
224 g_signal_new ("password_requested",
225 MODEST_TYPE_TNY_ACCOUNT_STORE,
227 G_STRUCT_OFFSET(ModestTnyAccountStoreClass, password_requested),
229 modest_marshal_VOID__STRING_POINTER_POINTER_POINTER_POINTER,
230 G_TYPE_NONE, 5, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER,
233 tny_account_store_initialized = TRUE;
239 modest_tny_account_store_class_init (ModestTnyAccountStoreClass *klass)
241 GObjectClass *gobject_class;
242 gobject_class = (GObjectClass*) klass;
244 parent_class = g_type_class_peek_parent (klass);
245 gobject_class->finalize = modest_tny_account_store_finalize;
247 g_type_class_add_private (gobject_class,
248 sizeof(ModestTnyAccountStorePrivate));
252 modest_tny_account_store_instance_init (ModestTnyAccountStore *obj)
254 GnomeVFSVolumeMonitor* monitor = NULL;
255 ModestTnyAccountStorePrivate *priv;
257 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
259 priv->cache_dir = NULL;
260 priv->account_mgr = NULL;
261 priv->session = NULL;
263 priv->sighandlers = NULL;
265 priv->outbox_of_transport = g_hash_table_new_full (g_direct_hash,
270 /* An in-memory store of passwords,
271 * for passwords that are not remembered in the configuration,
272 * so they need to be asked for from the user once in each session:
274 priv->password_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
277 /* A hash-map of modest account names to dialog pointers,
278 * so we can avoid showing the account settings twice for the same modest account: */
279 priv->account_settings_dialog_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
282 /* Respond to volume mounts and unmounts, such
283 * as the insertion/removal of the memory card: */
284 /* This is a singleton, so it does not need to be unrefed. */
285 monitor = gnome_vfs_get_volume_monitor();
287 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
290 G_CALLBACK(on_vfs_volume_mounted),
292 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
293 G_OBJECT(monitor), "volume-unmounted",
294 G_CALLBACK(on_vfs_volume_unmounted),
298 /* disconnect the list of TnyAccounts */
300 account_disconnect (TnyAccount *account)
302 g_return_if_fail (account && TNY_IS_ACCOUNT(account));
304 if (TNY_IS_STORE_ACCOUNT (account) &&
305 !modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
308 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT(account), FALSE, NULL, NULL);
312 /* disconnect the list of TnyAccounts */
314 account_verify_last_ref (TnyAccount *account, const gchar *str)
318 g_return_if_fail (account && TNY_IS_ACCOUNT(account));
320 txt = g_strdup_printf ("%s: %s", str ? str : "?", tny_account_get_name(account));
321 MODEST_DEBUG_VERIFY_OBJECT_LAST_REF(G_OBJECT(account),txt);
329 foreach_account_append_to_list (gpointer data,
334 list = TNY_LIST (user_data);
335 tny_list_append (list, G_OBJECT (data));
338 /********************************************************************/
339 /* Control the state of the MMC local account */
340 /********************************************************************/
342 /** Only call this if the memory card is really mounted.
345 add_mmc_account(ModestTnyAccountStore *self, gboolean emit_insert_signal)
347 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
348 g_return_if_fail (priv->session);
350 TnyAccount *mmc_account = modest_tny_account_new_for_local_folders (priv->account_mgr,
352 MODEST_MCC1_VOLUMEPATH);
354 /* Add to the list of store accounts */
355 tny_list_append (priv->store_accounts, G_OBJECT (mmc_account));
357 if (emit_insert_signal) {
358 g_signal_emit (G_OBJECT (self),
359 signals [ACCOUNT_INSERTED_SIGNAL],
364 g_object_unref (mmc_account);
368 on_vfs_volume_mounted(GnomeVFSVolumeMonitor *volume_monitor,
369 GnomeVFSVolume *volume,
372 ModestTnyAccountStore *self;
373 ModestTnyAccountStorePrivate *priv;
377 self = MODEST_TNY_ACCOUNT_STORE(user_data);
378 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
380 /* Check whether this was the external MMC1 card: */
381 uri = gnome_vfs_volume_get_activation_uri (volume);
383 if (uri && (!strcmp (uri, MODEST_MCC1_VOLUMEPATH_URI))) {
384 add_mmc_account (self, TRUE /* emit the insert signal. */);
391 on_vfs_volume_unmounted(GnomeVFSVolumeMonitor *volume_monitor,
392 GnomeVFSVolume *volume,
395 ModestTnyAccountStore *self;
396 ModestTnyAccountStorePrivate *priv;
399 self = MODEST_TNY_ACCOUNT_STORE(user_data);
400 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
402 /* Check whether this was the external MMC1 card: */
403 uri = gnome_vfs_volume_get_activation_uri (volume);
404 if (uri && (strcmp (uri, MODEST_MCC1_VOLUMEPATH_URI) == 0)) {
405 TnyAccount *mmc_account = NULL;
406 gboolean found = FALSE;
407 TnyIterator *iter = NULL;
409 iter = tny_list_create_iterator (priv->store_accounts);
410 while (!tny_iterator_is_done (iter) && !found) {
413 account = TNY_ACCOUNT (tny_iterator_get_current (iter));
414 if (modest_tny_account_is_memory_card_account (account)) {
416 mmc_account = g_object_ref (account);
418 g_object_unref (account);
419 tny_iterator_next (iter);
421 g_object_unref (iter);
424 /* Remove from the list */
425 tny_list_remove (priv->store_accounts, G_OBJECT (mmc_account));
427 /* Notify observers */
428 g_signal_emit (G_OBJECT (self),
429 signals [ACCOUNT_REMOVED_SIGNAL],
432 g_object_unref (mmc_account);
434 g_warning ("%s: there was no store account for the unmounted MMC",
442 * forget_password_in_memory
443 * @self: a TnyAccountStore instance
444 * @account: A server account.
446 * Forget any password stored in memory for this account.
447 * For instance, this should be called when the user has changed the password in the account settings.
450 forget_password_in_memory (ModestTnyAccountStore *self,
451 const gchar * server_account_name)
453 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
455 if (server_account_name && priv->password_hash) {
456 g_hash_table_remove (priv->password_hash, server_account_name);
461 on_account_changed (ModestAccountMgr *acc_mgr,
462 const gchar *account_name,
463 TnyAccountType account_type,
466 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(user_data);
467 ModestTnyAccountStorePrivate *priv;
468 TnyList* account_list;
469 gboolean found = FALSE;
470 TnyIterator *iter = NULL;
472 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
473 account_list = (account_type == TNY_ACCOUNT_TYPE_STORE ?
474 priv->store_accounts :
475 priv->transport_accounts);
477 iter = tny_list_create_iterator (account_list);
478 while (!tny_iterator_is_done (iter) && !found) {
479 TnyAccount *tny_account;
480 tny_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
482 if (!strcmp (tny_account_get_id (tny_account), account_name)) {
484 modest_tny_account_update_from_account (tny_account, get_password, forget_password);
485 g_signal_emit (G_OBJECT(self), signals[ACCOUNT_CHANGED_SIGNAL], 0, tny_account);
487 g_object_unref (tny_account);
489 tny_iterator_next (iter);
493 g_object_unref (iter);
497 on_account_settings_hide (GtkWidget *widget, gpointer user_data)
499 /* This is easier than using a struct for the user_data: */
500 ModestTnyAccountStore *self = modest_runtime_get_account_store();
501 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
503 gchar *account_name = (gchar *) user_data;
505 g_hash_table_remove (priv->account_settings_dialog_hash, account_name);
509 show_password_warning_only (const gchar *msg)
511 ModestWindow *main_window =
512 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (), FALSE); /* don't create */
514 /* Show an explanatory temporary banner: */
516 modest_platform_information_banner (NULL, NULL, msg);
520 show_wrong_password_dialog (TnyAccount *account)
522 /* This is easier than using a struct for the user_data: */
523 ModestTnyAccountStore *self = modest_runtime_get_account_store();
524 GtkWidget *main_window;
525 GtkWidget *dialog = NULL;
527 main_window = (GtkWidget *) modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (),
528 FALSE); /* don't create */
530 g_warning ("%s: password was wrong; ignoring because no main window", __FUNCTION__);
534 if (g_object_get_data (G_OBJECT (account), "connection_specific") != NULL) {
535 modest_ui_actions_on_smtp_servers (NULL, NULL);
537 const gchar *modest_account_name;
538 modest_account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
539 dialog = modest_tny_account_store_show_account_settings_dialog (self, modest_account_name);
541 /* Show an explanatory temporary banner: */
542 modest_platform_information_banner (dialog, NULL, _("mcen_ib_username_pw_incorrect"));
545 /* This callback will be called by Tinymail when it needs the password
546 * from the user or the account settings.
547 * It can also call forget_password() before calling this,
548 * so that we clear wrong passwords out of our account settings.
549 * Note that TnyAccount here will be the server account. */
551 get_password (TnyAccount *account, const gchar * prompt_not_used, gboolean *cancel)
553 ModestTnyAccountStore *self = NULL;
554 ModestTnyAccountStorePrivate *priv;
555 gchar *username = NULL;
557 gpointer pwd_ptr = NULL;
558 gboolean already_asked = FALSE;
559 const gchar *server_account_name;
562 g_return_val_if_fail (account, NULL);
565 g_debug ("%s: prompt (not shown) = %s\n", __FUNCTION__, prompt_not_used);
568 /* Get a reference to myself */
569 self = MODEST_TNY_ACCOUNT_STORE (g_object_get_data (G_OBJECT(account), "account_store"));
570 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
572 /* Ensure that we still have this account. It could happen
573 that a set_online was requested *before* removing an
574 account, and due to tinymail emits the get_password
575 function using a g_idle the account could be actually
576 removed *before* this function was really called */
577 url_string = tny_account_get_url_string (account);
579 TnyAccount *tmp_account;
581 tmp_account = tny_account_store_find_account (TNY_ACCOUNT_STORE (self),
589 g_object_unref (tmp_account);
592 server_account_name = tny_account_get_id (account);
593 if (!server_account_name || !self) {
594 g_warning ("modest: %s: could not retrieve account_store for account %s",
595 __FUNCTION__, server_account_name ? server_account_name : "<NULL>");
602 /* This hash map stores passwords, including passwords that are not stored in gconf. */
603 /* Is it in the hash? if it's already there, it must be wrong... */
604 pwd_ptr = (gpointer)&pwd; /* pwd_ptr so the compiler does not complained about
605 * type-punned ptrs...*/
606 already_asked = priv->password_hash &&
607 g_hash_table_lookup_extended (priv->password_hash,
610 (gpointer*)&pwd_ptr);
612 g_debug ("%s: Already asked = %d\n", __FUNCTION__, already_asked);
615 /* If the password is not already there, try ModestConf */
616 if (!already_asked) {
617 pwd = modest_account_mgr_get_server_account_password (priv->account_mgr,
618 server_account_name);
619 g_hash_table_insert (priv->password_hash, g_strdup (server_account_name), g_strdup (pwd));
622 /* If it was already asked, it must have been wrong, so ask again */
623 if (already_asked || !pwd || strlen(pwd) == 0) {
624 /* As per the UI spec, if no password was set in the account settings,
625 * ask for it now. But if the password is wrong in the account settings,
626 * then show a banner and the account settings dialog so it can be corrected:
628 ModestTransportStoreProtocol proto;
629 const gboolean settings_have_password =
630 modest_account_mgr_get_server_account_has_password (priv->account_mgr, server_account_name);
632 /* Show an error and after that ask for a password */
633 proto = modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (account));
634 if (proto == MODEST_PROTOCOL_TRANSPORT_SMTP) {
635 gchar *username = NULL, *msg = NULL;
636 username = modest_account_mgr_get_server_account_username (priv->account_mgr,
637 server_account_name);
638 if (!username || strlen(username) == 0) {
639 msg = g_strdup_printf (_("emev_ni_ui_smtp_userid_invalid"),
640 tny_account_get_name (account),
641 tny_account_get_hostname (account));
644 password = modest_account_mgr_get_server_account_password (priv->account_mgr,
645 server_account_name);
646 if (!password || strlen(password) == 0)
647 msg = g_strdup_printf (_("emev_ni_ui_smtp_passwd_invalid"),
648 tny_account_get_name (account),
649 tny_account_get_hostname (account));
651 msg = g_strdup_printf (_("emev_ni_ui_smtp_authentication_fail_error"),
652 tny_account_get_hostname (account));
657 modest_platform_run_information_dialog (NULL, msg, TRUE);
664 if (settings_have_password) {
665 /* The password must be wrong, so show the account settings dialog so it can be corrected: */
666 show_wrong_password_dialog (account);
674 /* we don't have it yet. Get the password from the user */
675 const gchar* account_id = tny_account_get_id (account);
676 gboolean remember = FALSE;
681 gboolean username_known =
682 modest_account_mgr_get_server_account_username_has_succeeded(priv->account_mgr,
683 server_account_name);
684 /* If the login has ever succeeded then show a specific message */
686 msg = dgettext ("hildon-common-strings", "ecdg_ib_set_password_incorrect");
688 msg = _("mcen_ib_username_pw_incorrect");
689 show_password_warning_only (msg);
692 /* Request password */
693 g_signal_emit (G_OBJECT (self), signals[PASSWORD_REQUESTED_SIGNAL], 0,
694 account_id, /* server_account_name */
695 &username, &pwd, cancel, &remember);
699 /* The password will be returned as the result,
700 * but we need to tell tinymail about the username too: */
702 /* WARNING: I disabled setting username as this can cause locks. Anyway,
703 * as now we have the password dialog username entry always dimmed
704 * this shouldn't be a problem */
707 /* tny_account_set_user (account, username); */
709 /* Do not save the password in gconf, because
710 * the UI spec says "The password will never
711 * be saved in the account": */
713 /* We need to dup the string even knowing that
714 it's already a dup of the contents of an
715 entry, because it if it's wrong, then camel
717 g_hash_table_insert (priv->password_hash, g_strdup (server_account_name), g_strdup(pwd));
719 g_hash_table_remove (priv->password_hash, server_account_name);
734 modest_tny_account_store_forget_already_asked (ModestTnyAccountStore *self, TnyAccount *account)
736 g_return_if_fail (account);
738 ModestTnyAccountStorePrivate *priv;
740 gpointer pwd_ptr = NULL;
741 gboolean already_asked = FALSE;
743 const gchar *server_account_name = tny_account_get_id (account);
745 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
747 /* This hash map stores passwords, including passwords that are not stored in gconf. */
748 pwd_ptr = (gpointer)&pwd; /* pwd_ptr so the compiler does not complained about
749 * type-punned ptrs...*/
750 already_asked = priv->password_hash &&
751 g_hash_table_lookup_extended (priv->password_hash,
754 (gpointer*)&pwd_ptr);
757 g_hash_table_remove (priv->password_hash, server_account_name);
765 /* tinymail calls this if the connection failed due to an incorrect password.
766 * And it seems to call this for any general connection failure. */
768 forget_password (TnyAccount *account)
770 ModestTnyAccountStore *self;
771 ModestTnyAccountStorePrivate *priv;
772 const TnyAccountStore *account_store;
776 account_store = TNY_ACCOUNT_STORE(g_object_get_data (G_OBJECT(account),
778 self = MODEST_TNY_ACCOUNT_STORE (account_store);
779 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
780 key = tny_account_get_id (account);
782 /* Do not remove the key, this will allow us to detect that we
783 have already asked for it at least once */
784 pwd = g_hash_table_lookup (priv->password_hash, key);
786 memset (pwd, 0, strlen (pwd));
787 g_hash_table_insert (priv->password_hash, g_strdup (key), NULL);
790 /* Remove from configuration system */
792 modest_account_mgr_unset (priv->account_mgr,
793 key, MODEST_ACCOUNT_PASSWORD, TRUE);
798 modest_tny_account_store_finalize (GObject *obj)
800 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(obj);
801 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
803 g_free (priv->cache_dir);
804 priv->cache_dir = NULL;
806 if (priv->password_hash) {
807 g_hash_table_destroy (priv->password_hash);
808 priv->password_hash = NULL;
811 if (priv->account_settings_dialog_hash) {
812 g_hash_table_destroy (priv->account_settings_dialog_hash);
813 priv->account_settings_dialog_hash = NULL;
816 if (priv->outbox_of_transport) {
817 g_hash_table_destroy (priv->outbox_of_transport);
818 priv->outbox_of_transport = NULL;
821 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
822 priv->sighandlers = NULL;
824 if (priv->account_mgr) {
825 g_object_unref (G_OBJECT(priv->account_mgr));
826 priv->account_mgr = NULL;
830 g_object_unref (G_OBJECT(priv->device));
834 /* Destroy all accounts. Disconnect all accounts before they are destroyed */
835 if (priv->store_accounts) {
836 tny_list_foreach (priv->store_accounts, (GFunc)account_disconnect, NULL);
837 tny_list_foreach (priv->store_accounts, (GFunc)account_verify_last_ref, "store");
838 g_object_unref (priv->store_accounts);
839 priv->store_accounts = NULL;
842 if (priv->transport_accounts) {
843 tny_list_foreach (priv->transport_accounts, (GFunc)account_disconnect, NULL);
844 tny_list_foreach (priv->transport_accounts, (GFunc)account_verify_last_ref, "transport");
845 g_object_unref (priv->transport_accounts);
846 priv->transport_accounts = NULL;
849 if (priv->store_accounts_outboxes) {
850 g_object_unref (priv->store_accounts_outboxes);
851 priv->store_accounts_outboxes = NULL;
855 camel_object_unref (CAMEL_OBJECT(priv->session));
856 priv->session = NULL;
861 G_OBJECT_CLASS(parent_class)->finalize (obj);
865 volume_path_is_mounted (const gchar* path)
867 g_return_val_if_fail (path, FALSE);
869 gboolean result = FALSE;
870 gchar * path_as_uri = g_filename_to_uri (path, NULL, NULL);
871 g_return_val_if_fail (path_as_uri, FALSE);
873 /* Get the monitor singleton: */
874 GnomeVFSVolumeMonitor *monitor = gnome_vfs_get_volume_monitor();
876 /* This seems like a simpler way to do this, but it returns a
877 * GnomeVFSVolume even if the drive is not mounted: */
879 GnomeVFSVolume *volume = gnome_vfs_volume_monitor_get_volume_for_path (monitor,
880 MODEST_MCC1_VOLUMEPATH);
882 gnome_vfs_volume_unref(volume);
886 /* Get the mounted volumes from the monitor: */
887 GList *list = gnome_vfs_volume_monitor_get_mounted_volumes (monitor);
889 for (iter = list; iter; iter = g_list_next (iter)) {
890 GnomeVFSVolume *volume = (GnomeVFSVolume*)iter->data;
894 gnome_vfs_volume_get_display_name (volume);
895 printf ("volume display name=%s\n", display_name);
896 g_free (display_name);
900 gnome_vfs_volume_get_activation_uri (volume);
901 /* printf (" uri=%s\n", uri); */
902 if (uri && (strcmp (uri, path_as_uri) == 0))
907 gnome_vfs_volume_unref (volume);
913 g_free (path_as_uri);
918 ModestTnyAccountStore*
919 modest_tny_account_store_new (ModestAccountMgr *account_mgr,
923 ModestTnyAccountStorePrivate *priv;
924 TnyAccount *local_account = NULL;
926 g_return_val_if_fail (account_mgr, NULL);
927 g_return_val_if_fail (device, NULL);
929 obj = G_OBJECT(g_object_new(MODEST_TYPE_TNY_ACCOUNT_STORE, NULL));
930 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
932 priv->account_mgr = g_object_ref (G_OBJECT(account_mgr));
933 priv->device = g_object_ref (device);
935 priv->session = tny_session_camel_new (TNY_ACCOUNT_STORE(obj));
936 if (!priv->session) {
937 g_warning ("failed to get TnySessionCamel");
941 /* Set the ui locker */
942 tny_session_camel_set_ui_locker (priv->session, tny_gtk_lockable_new ());
944 /* Connect signals */
945 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
946 G_OBJECT(account_mgr), "account_inserted",
947 G_CALLBACK (on_account_inserted), obj);
948 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
949 G_OBJECT(account_mgr), "account_changed",
950 G_CALLBACK (on_account_changed), obj);
951 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
952 G_OBJECT(account_mgr), "account_removed",
953 G_CALLBACK (on_account_removed), obj);
955 /* Create the lists of accounts */
956 priv->store_accounts = tny_simple_list_new ();
957 priv->transport_accounts = tny_simple_list_new ();
958 priv->store_accounts_outboxes = tny_simple_list_new ();
960 /* Create the local folders account */
962 modest_tny_account_new_for_local_folders (priv->account_mgr, priv->session, NULL);
963 tny_list_append (priv->store_accounts, G_OBJECT(local_account));
964 g_object_unref (local_account);
966 /* Add the other remote accounts. Do this after adding the
967 local account, because we need to add our outboxes to the
968 global OUTBOX hosted in the local account */
969 add_existing_accounts (MODEST_TNY_ACCOUNT_STORE (obj));
971 /* Add connection-specific transport accounts */
972 add_connection_specific_transport_accounts (MODEST_TNY_ACCOUNT_STORE(obj));
974 /* This is a singleton, so it does not need to be unrefed. */
975 if (volume_path_is_mounted (MODEST_MCC1_VOLUMEPATH)) {
977 add_mmc_account (MODEST_TNY_ACCOUNT_STORE (obj), FALSE /* don't emit the insert signal. */);
980 return MODEST_TNY_ACCOUNT_STORE(obj);
984 modest_tny_account_store_get_accounts (TnyAccountStore *self,
986 TnyGetAccountsRequestType request_type)
988 ModestTnyAccountStorePrivate *priv;
990 g_return_if_fail (self);
991 g_return_if_fail (TNY_IS_LIST(list));
993 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
995 switch (request_type) {
996 case TNY_ACCOUNT_STORE_BOTH:
997 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
998 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
1000 case TNY_ACCOUNT_STORE_STORE_ACCOUNTS:
1001 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
1003 case TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS:
1004 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
1007 g_return_if_reached ();
1010 /* Initialize session. Why do we need this ??? */
1011 tny_session_camel_set_initialized (priv->session);
1016 modest_tny_account_store_get_cache_dir (TnyAccountStore *self)
1018 ModestTnyAccountStorePrivate *priv;
1019 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1021 if (!priv->cache_dir)
1022 priv->cache_dir = g_build_filename (g_get_home_dir(),
1023 MODEST_DIR, MODEST_CACHE_DIR, NULL);
1024 return priv->cache_dir;
1029 * callers need to unref
1032 modest_tny_account_store_get_device (TnyAccountStore *self)
1034 ModestTnyAccountStorePrivate *priv;
1036 g_return_val_if_fail (self, NULL);
1038 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1041 return g_object_ref (G_OBJECT(priv->device));
1048 modest_tny_account_store_find_account_by_url (TnyAccountStore *self, const gchar* url_string)
1050 return modest_tny_account_store_get_tny_account_by (MODEST_TNY_ACCOUNT_STORE (self),
1051 MODEST_TNY_ACCOUNT_STORE_QUERY_URL,
1058 modest_tny_account_store_alert (TnyAccountStore *self,
1059 TnyAccount *account,
1064 ModestTransportStoreProtocol proto =
1065 MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN;
1066 const gchar* server_name = "";
1067 gchar *prompt = NULL;
1070 /* NOTE: account may be NULL in some cases */
1071 g_return_val_if_fail (error, FALSE);
1073 /* Get the server name: */
1075 server_name = tny_account_get_hostname (account);
1076 const gchar *proto_name = tny_account_get_proto (account);
1078 proto = modest_protocol_info_get_transport_store_protocol (proto_name);
1080 g_warning("modest: %s: account with id=%s has no proto.\n", __FUNCTION__,
1081 tny_account_get_id (account));
1086 switch (error->code) {
1087 case TNY_SYSTEM_ERROR_CANCEL:
1088 /* Don't show waste the user's time by showing him a dialog telling
1089 * him that he has just cancelled something: */
1092 case TNY_SERVICE_ERROR_PROTOCOL:
1093 /* Like a BAD from IMAP (protocol error) */
1094 case TNY_SERVICE_ERROR_LOST_CONNECTION:
1095 /* Lost the connection with the service */
1096 case TNY_SERVICE_ERROR_UNAVAILABLE:
1097 /* You must be working online for this operation */
1098 case TNY_SERVICE_ERROR_CONNECT:
1100 case MODEST_PROTOCOL_STORE_POP:
1101 prompt = g_strdup_printf (_("emev_ni_ui_pop3_msg_connect_error"),
1104 case MODEST_PROTOCOL_STORE_IMAP:
1105 prompt = g_strdup_printf (_("emev_ni_ui_imap_connect_server_error"),
1108 case MODEST_PROTOCOL_TRANSPORT_SMTP:
1109 prompt = g_strdup_printf (_("emev_ib_ui_smtp_server_invalid"),
1113 g_return_val_if_reached (FALSE);
1117 case TNY_SERVICE_ERROR_AUTHENTICATE:
1118 /* It seems that there's no better error to show with
1119 * POP and IMAP because TNY_SERVICE_ERROR_AUTHENTICATE
1120 * may appear if there's a timeout during auth */
1122 case MODEST_PROTOCOL_STORE_POP:
1123 prompt = g_strdup_printf (_("emev_ni_ui_pop3_msg_connect_error"),
1126 case MODEST_PROTOCOL_STORE_IMAP:
1127 prompt = g_strdup_printf (_("emev_ni_ui_imap_connect_server_error"),
1130 case MODEST_PROTOCOL_TRANSPORT_SMTP:
1131 prompt = g_strdup_printf (_("emev_ni_ui_smtp_authentication_fail_error"),
1135 g_return_val_if_reached (FALSE);
1139 case TNY_SERVICE_ERROR_CERTIFICATE:
1140 /* We'll show the proper dialog later */
1143 case TNY_SYSTEM_ERROR_MEMORY:
1144 /* Can't allocate memory for this operation */
1146 case TNY_SERVICE_ERROR_UNKNOWN:
1149 g_return_val_if_reached (FALSE);
1153 if (error->code == TNY_SERVICE_ERROR_CERTIFICATE)
1154 retval = modest_platform_run_certificate_confirmation_dialog (server_name,
1157 modest_platform_run_information_dialog (NULL, prompt, TRUE);
1159 /* Show the account dialog if it was wrong */
1160 if (error->code == TNY_SERVICE_ERROR_CONNECT ||
1161 error->code == TNY_SERVICE_ERROR_AUTHENTICATE)
1162 show_wrong_password_dialog (account);
1176 modest_tny_account_store_init (gpointer g, gpointer iface_data)
1178 TnyAccountStoreIface *klass;
1180 g_return_if_fail (g);
1182 klass = (TnyAccountStoreIface *)g;
1184 klass->get_accounts =
1185 modest_tny_account_store_get_accounts;
1186 klass->get_cache_dir =
1187 modest_tny_account_store_get_cache_dir;
1189 modest_tny_account_store_get_device;
1191 modest_tny_account_store_alert;
1192 klass->find_account =
1193 modest_tny_account_store_find_account_by_url;
1197 modest_tny_account_store_set_get_pass_func (ModestTnyAccountStore *self,
1198 ModestTnyGetPassFunc func)
1200 /* not implemented, we use signals */
1201 g_printerr ("modest: set_get_pass_func not implemented\n");
1205 modest_tny_account_store_get_session (TnyAccountStore *self)
1207 g_return_val_if_fail (self, NULL);
1208 return MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self)->session;
1212 get_tny_account_by (TnyList *accounts,
1213 ModestTnyAccountStoreQueryType type,
1216 TnyIterator *iter = NULL;
1217 gboolean found = FALSE;
1218 TnyAccount *retval = NULL;
1220 g_return_val_if_fail (TNY_IS_LIST(accounts), NULL);
1222 if (tny_list_get_length(accounts) == 0) {
1223 g_warning ("%s: account list is empty", __FUNCTION__);
1227 iter = tny_list_create_iterator (accounts);
1228 while (!tny_iterator_is_done (iter) && !found) {
1229 TnyAccount *tmp_account = NULL;
1230 const gchar *val = NULL;
1232 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1233 if (!TNY_IS_ACCOUNT(tmp_account)) {
1234 g_warning ("%s: not a valid account", __FUNCTION__);
1240 case MODEST_TNY_ACCOUNT_STORE_QUERY_ID:
1241 val = tny_account_get_id (tmp_account);
1243 case MODEST_TNY_ACCOUNT_STORE_QUERY_URL:
1244 val = tny_account_get_url_string (tmp_account);
1248 if (type == MODEST_TNY_ACCOUNT_STORE_QUERY_URL &&
1249 tny_account_matches_url_string (tmp_account, str)) {
1250 retval = g_object_ref (tmp_account);
1253 if (val && str && strcmp (val, str) == 0) {
1254 retval = g_object_ref (tmp_account);
1258 g_object_unref (tmp_account);
1259 tny_iterator_next (iter);
1261 g_object_unref (iter);
1267 modest_tny_account_store_get_tny_account_by (ModestTnyAccountStore *self,
1268 ModestTnyAccountStoreQueryType type,
1271 TnyAccount *account = NULL;
1272 ModestTnyAccountStorePrivate *priv;
1274 g_return_val_if_fail (self, NULL);
1275 g_return_val_if_fail (str, NULL);
1277 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1279 /* Search in store accounts */
1280 account = get_tny_account_by (priv->store_accounts, type, str);
1282 /* If we already found something, no need to search the transport accounts */
1284 account = get_tny_account_by (priv->transport_accounts, type, str);
1286 /* If we already found something, no need to search the
1287 per-account outbox accounts */
1289 account = get_tny_account_by (priv->store_accounts_outboxes, type, str);
1292 /* Warn if nothing was found. This is generally unusual. */
1294 g_warning("%s: Failed to find account with %s=%s\n",
1296 (type == MODEST_TNY_ACCOUNT_STORE_QUERY_ID) ? "ID" : "URL",
1300 /* Returns a new reference to the account if found */
1306 modest_tny_account_store_get_server_account (ModestTnyAccountStore *self,
1307 const gchar *account_name,
1308 TnyAccountType type)
1310 ModestTnyAccountStorePrivate *priv = NULL;
1311 TnyAccount *retval = NULL;
1312 TnyList *account_list = NULL;
1313 TnyIterator *iter = NULL;
1316 g_return_val_if_fail (self, NULL);
1317 g_return_val_if_fail (account_name, NULL);
1318 g_return_val_if_fail (type == TNY_ACCOUNT_TYPE_STORE ||
1319 type == TNY_ACCOUNT_TYPE_TRANSPORT,
1322 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1324 account_list = (type == TNY_ACCOUNT_TYPE_STORE) ?
1325 priv->store_accounts :
1326 priv->transport_accounts;
1328 if (!account_list) {
1329 g_printerr ("%s: No server accounts of type %s\n", __FUNCTION__,
1330 (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport");
1334 /* Look for the server account */
1336 iter = tny_list_create_iterator (account_list);
1337 while (!tny_iterator_is_done (iter) && !found) {
1338 const gchar *modest_acc_name;
1339 TnyAccount *tmp_account;
1341 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1343 modest_tny_account_get_parent_modest_account_name_for_server_account (tmp_account);
1345 if (account_name && modest_acc_name && !strcmp (account_name, modest_acc_name)) {
1347 retval = g_object_ref (tmp_account);
1349 /* Free and continue */
1350 g_object_unref (tmp_account);
1351 tny_iterator_next (iter);
1353 g_object_unref (iter);
1356 g_printerr ("modest: %s: could not get tny %s account for %s\n." \
1357 "Number of server accounts of this type=%d\n", __FUNCTION__,
1358 (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport",
1359 account_name, tny_list_get_length (account_list));
1362 /* Returns a new reference */
1367 modest_tny_account_store_get_smtp_specific_transport_account_for_open_connection (
1368 ModestTnyAccountStore *self, const gchar *account_name)
1372 g_return_val_if_fail (self && MODEST_IS_TNY_ACCOUNT_STORE(self), NULL);
1373 g_return_val_if_fail (account_name, NULL);
1375 /* Get the current connection: */
1376 device = modest_runtime_get_device ();
1379 g_warning ("%s: could not get device", __FUNCTION__);
1383 if (!tny_device_is_online (device))
1386 #ifdef MODEST_HAVE_CONIC
1387 g_return_val_if_fail (TNY_IS_MAEMO_CONIC_DEVICE (device), NULL);
1389 TnyMaemoConicDevice *maemo_device = TNY_MAEMO_CONIC_DEVICE (device);
1390 const gchar* iap_id = tny_maemo_conic_device_get_current_iap_id (maemo_device);
1391 /* printf ("DEBUG: %s: iap_id=%s\n", __FUNCTION__, iap_id); */
1395 ConIcIap* connection = tny_maemo_conic_device_get_iap (maemo_device, iap_id);
1399 const gchar *connection_id = con_ic_iap_get_id (connection);
1400 /* printf ("DEBUG: %s: connection_id=%s\n", __FUNCTION__, connection_id); */
1404 /* Get the connection-specific transport acccount, if any: */
1405 ModestAccountMgr *account_manager = modest_runtime_get_account_mgr ();
1407 /* Check if this account has connection-specific SMTP enabled */
1408 if (!modest_account_mgr_get_use_connection_specific_smtp (account_manager, account_name)) {
1412 gchar* server_account_name = modest_account_mgr_get_connection_specific_smtp (account_manager,
1415 /* printf ("DEBUG: %s: server_account_name=%s\n", __FUNCTION__, server_account_name); */
1416 if (!server_account_name) {
1417 return NULL; /* No connection-specific SMTP server was specified for this connection. */
1420 TnyAccount* account = modest_tny_account_store_get_tny_account_by (self,
1421 MODEST_TNY_ACCOUNT_STORE_QUERY_ID,
1422 server_account_name);
1424 /* printf ("DEBUG: %s: account=%p\n", __FUNCTION__, account); */
1425 g_free (server_account_name);
1427 /* Unref the get()ed object, as required by the tny_maemo_conic_device_get_iap() documentation. */
1428 g_object_unref (connection);
1432 return NULL; /* TODO: Implement this for GNOME, instead of just Maemo? */
1433 #endif /* MODEST_HAVE_CONIC */
1438 modest_tny_account_store_get_transport_account_for_open_connection (ModestTnyAccountStore *self,
1439 const gchar *account_name)
1441 g_return_val_if_fail (self, NULL);
1442 g_return_val_if_fail (account_name, NULL);
1444 if (!account_name || !self)
1447 /* Get the connection-specific transport acccount, if any: */
1448 /* Note: This gives us a reference: */
1449 TnyAccount *account =
1450 modest_tny_account_store_get_smtp_specific_transport_account_for_open_connection (self, account_name);
1452 /* If there is no connection-specific transport account (the common case),
1453 * just get the regular transport account: */
1455 /* The special local folders don't have transport accounts. */
1456 if (strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0)
1459 /* Note: This gives us a reference: */
1460 account = modest_tny_account_store_get_server_account (self, account_name,
1461 TNY_ACCOUNT_TYPE_TRANSPORT);
1465 /* returns a reference. */
1470 modest_tny_account_store_get_local_folders_account (ModestTnyAccountStore *self)
1472 TnyAccount *account = NULL;
1473 ModestTnyAccountStorePrivate *priv;
1477 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1479 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1482 iter = tny_list_create_iterator (priv->store_accounts);
1483 while (!tny_iterator_is_done (iter) && !found) {
1484 TnyAccount *tmp_account;
1486 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1487 if (modest_tny_account_is_virtual_local_folders (tmp_account)) {
1488 account = g_object_ref (tmp_account);
1491 g_object_unref (tmp_account);
1492 tny_iterator_next (iter);
1494 g_object_unref (iter);
1496 /* Returns a new reference to the account */
1501 modest_tny_account_store_get_mmc_folders_account (ModestTnyAccountStore *self)
1503 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1506 return modest_tny_account_store_get_tny_account_by (self, MODEST_TNY_ACCOUNT_STORE_QUERY_ID,
1507 MODEST_MMC_ACCOUNT_ID);
1511 /*********************************************************************************/
1513 add_existing_accounts (ModestTnyAccountStore *self)
1515 GSList *account_names = NULL, *iter = NULL;
1516 ModestTnyAccountStorePrivate *priv = NULL;
1518 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1520 /* These are account names, not server_account names */
1521 account_names = modest_account_mgr_account_names (priv->account_mgr, FALSE);
1523 for (iter = account_names; iter != NULL; iter = g_slist_next (iter)) {
1524 const gchar *account_name = (const gchar*) iter->data;
1526 /* Insert all enabled accounts without notifying */
1527 if (modest_account_mgr_get_enabled (priv->account_mgr, account_name))
1528 insert_account (self, account_name, FALSE);
1530 modest_account_mgr_free_account_names (account_names);
1534 connection_status_changed (TnyAccount *account,
1535 TnyConnectionStatus status,
1538 /* We do this here and not in the connection policy because we
1539 don't want to do it for every account, just for the
1540 accounts that are interactively added when modest is
1542 if (status == TNY_CONNECTION_STATUS_CONNECTED) {
1543 const gchar *account_name;
1544 ModestWindow *main_window;
1545 ModestTnyAccountStorePrivate *priv = NULL;
1547 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (data);
1549 /* Remove this handler */
1550 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
1552 "connection_status_changed");
1554 /* Perform a send receive */
1555 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
1556 main_window = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (), FALSE);
1557 modest_ui_actions_do_send_receive (account_name, FALSE, FALSE, FALSE, main_window);
1562 create_tny_account (ModestTnyAccountStore *self,
1564 TnyAccountType type,
1567 TnyAccount *account = NULL;
1568 ModestTnyAccountStorePrivate *priv = NULL;
1570 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1572 account = modest_tny_account_new_from_account (priv->account_mgr,
1579 /* Forget any cached password for the account, so that
1580 we use a new account if any */
1581 forget_password_in_memory (self, tny_account_get_id (account));
1583 /* Install a signal handler that will refresh the
1584 account the first time it becomes online. Do this
1585 only if we're adding a new account while the
1586 program is running (we do not want to do this
1588 if (type == TNY_ACCOUNT_TYPE_STORE && notify)
1589 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
1591 "connection_status_changed",
1592 G_CALLBACK (connection_status_changed),
1595 /* Set the account store */
1596 g_object_set_data (G_OBJECT(account), "account_store", self);
1598 g_printerr ("modest: failed to create account for %s\n", name);
1604 typedef struct _AddOutboxInfo {
1605 ModestTnyAccountStore *account_store;
1606 TnyAccount *transport_account;
1610 add_outbox_from_transport_account_to_global_outbox_get_folders_cb (TnyFolderStore *folder_store,
1616 TnyIterator *iter_folders;
1617 TnyFolder *per_account_outbox;
1618 TnyAccount *local_account = NULL;
1619 AddOutboxInfo *info = (AddOutboxInfo *) userdata;
1620 ModestTnyAccountStorePrivate *priv = NULL;
1621 ModestTnyAccountStore *self;
1623 self = MODEST_TNY_ACCOUNT_STORE (info->account_store);
1624 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1626 /* Note that this could happen if there is not enough space
1627 available on disk, then the outbox folder could not be
1629 if (tny_list_get_length (list) != 1) {
1630 g_warning ("%s: could not create outbox folder (%d folders found)", __FUNCTION__,
1631 tny_list_get_length (list));
1635 iter_folders = tny_list_create_iterator (list);
1636 per_account_outbox = TNY_FOLDER (tny_iterator_get_current (iter_folders));
1637 g_object_unref (iter_folders);
1638 g_object_unref (list);
1640 /* Add the outbox of the new per-account-local-outbox account
1641 to the global local merged OUTBOX of the local folders
1643 local_account = modest_tny_account_store_get_local_folders_account (info->account_store);
1644 modest_tny_local_folders_account_add_folder_to_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1645 per_account_outbox);
1646 /* Add the pair to the hash table */
1647 g_hash_table_insert (priv->outbox_of_transport,
1648 info->transport_account,
1649 per_account_outbox);
1651 /* Notify that the local account changed */
1652 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1653 g_object_unref (local_account);
1654 g_object_unref (per_account_outbox);
1657 g_object_unref (info->transport_account);
1658 g_slice_free (AddOutboxInfo, info);
1663 add_outbox_from_transport_account_to_global_outbox (ModestTnyAccountStore *self,
1664 const gchar *account_name,
1665 TnyAccount *transport_account)
1667 TnyList *folders = NULL;
1668 TnyAccount *account_outbox = NULL;
1669 ModestTnyAccountStorePrivate *priv = NULL;
1670 AddOutboxInfo *info;
1672 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1674 /* Create per account local outbox */
1676 modest_tny_account_new_for_per_account_local_outbox_folder (priv->account_mgr,
1680 if (!G_IS_OBJECT (account_outbox)) {
1681 g_warning ("%s: could not create per account local outbox folder", __FUNCTION__);
1685 tny_list_append (priv->store_accounts_outboxes, G_OBJECT (account_outbox));
1687 /* Get the outbox folder */
1688 folders = tny_simple_list_new ();
1689 info = g_slice_new0 (AddOutboxInfo);
1690 info->account_store = self;
1691 info->transport_account = g_object_ref (transport_account);
1692 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (account_outbox), folders, NULL,
1693 add_outbox_from_transport_account_to_global_outbox_get_folders_cb, NULL, (gpointer) info);
1694 g_object_unref (account_outbox);
1698 * This function will be used for both adding new accounts and for the
1699 * initialization. In the initialization we do not want to emit
1700 * signals so notify will be FALSE, in the case of account additions
1701 * we do want to notify the observers
1704 insert_account (ModestTnyAccountStore *self,
1705 const gchar *account,
1708 ModestTnyAccountStorePrivate *priv = NULL;
1709 TnyAccount *store_account = NULL, *transport_account = NULL;
1711 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1713 /* Get the server and the transport account */
1714 store_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_STORE, notify);
1715 if (!store_account || !TNY_IS_ACCOUNT(store_account)) {
1716 g_warning ("%s: failed to create store account", __FUNCTION__);
1720 transport_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT, notify);
1721 if (!transport_account || !TNY_IS_ACCOUNT(transport_account)) {
1722 g_warning ("%s: failed to create transport account", __FUNCTION__);
1723 g_object_unref (store_account);
1727 /* Add accounts to the lists */
1728 tny_list_append (priv->store_accounts, G_OBJECT (store_account));
1729 tny_list_append (priv->transport_accounts, G_OBJECT (transport_account));
1731 /* Create a new pseudo-account with an outbox for this
1732 transport account and add it to the global outbox
1733 in the local account */
1734 add_outbox_from_transport_account_to_global_outbox (self, account, transport_account);
1736 /* Notify the observers. We do it after everything is
1739 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, store_account);
1740 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, transport_account);
1744 g_object_unref (store_account);
1745 g_object_unref (transport_account);
1749 on_account_inserted (ModestAccountMgr *acc_mgr,
1750 const gchar *account,
1753 /* Insert the account and notify the observers */
1754 insert_account (MODEST_TNY_ACCOUNT_STORE (user_data), account, TRUE);
1757 /* This is the callback of the tny_camel_account_set_online called in
1758 on_account_removed to disconnect the account */
1760 on_account_disconnect_when_removing (TnyCamelAccount *account,
1765 ModestTnyAccountStore *self;
1766 ModestTnyAccountStorePrivate *priv;
1768 self = MODEST_TNY_ACCOUNT_STORE (user_data);
1769 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1771 /* Remove the connection-status-changed handler if it's still there */
1772 if (modest_signal_mgr_is_connected (priv->sighandlers,
1774 "connection_status_changed")) {
1775 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
1777 "connection_status_changed");
1780 /* Cancel all pending operations */
1781 tny_account_cancel (TNY_ACCOUNT (account));
1783 /* Unref the extra reference added by get_server_account */
1784 g_object_unref (account);
1786 /* Clear the cache if it's an store account */
1787 if (TNY_IS_STORE_ACCOUNT (account)) {
1788 tny_store_account_delete_cache (TNY_STORE_ACCOUNT (account));
1789 } else if (TNY_IS_TRANSPORT_ACCOUNT (account)) {
1790 ModestTnySendQueue* send_queue;
1791 send_queue = modest_runtime_get_send_queue (TNY_TRANSPORT_ACCOUNT (account), FALSE);
1792 if (TNY_IS_SEND_QUEUE (send_queue)) {
1793 if (modest_tny_send_queue_sending_in_progress (send_queue))
1794 tny_send_queue_cancel (TNY_SEND_QUEUE (send_queue),
1795 TNY_SEND_QUEUE_CANCEL_ACTION_REMOVE,
1797 modest_runtime_remove_send_queue (TNY_TRANSPORT_ACCOUNT (account));
1803 on_account_removed (ModestAccountMgr *acc_mgr,
1804 const gchar *account,
1807 TnyAccount *store_account = NULL, *transport_account = NULL;
1808 ModestTnyAccountStore *self;
1809 ModestTnyAccountStorePrivate *priv;
1811 self = MODEST_TNY_ACCOUNT_STORE (user_data);
1812 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1814 /* Get the server and the transport account */
1816 modest_tny_account_store_get_server_account (self, account,
1817 TNY_ACCOUNT_TYPE_STORE);
1819 modest_tny_account_store_get_server_account (self, account,
1820 TNY_ACCOUNT_TYPE_TRANSPORT);
1822 /* If there was any problem creating the account, for example,
1823 with the configuration system this could not exist */
1824 if (TNY_IS_STORE_ACCOUNT(store_account)) {
1825 /* Forget any cached password for the account */
1826 forget_password_in_memory (self, tny_account_get_id (store_account));
1828 /* Remove it from the list of accounts and notify the
1829 observers. Do not need to wait for account
1831 tny_list_remove (priv->store_accounts, (GObject *) store_account);
1832 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 0, store_account);
1834 /* Cancel all pending operations */
1835 tny_account_cancel (TNY_ACCOUNT (store_account));
1837 /* Disconnect before deleting the cache, because the
1838 disconnection will rewrite the cache to the
1840 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (store_account), FALSE,
1841 on_account_disconnect_when_removing, self);
1843 g_warning ("%s: no store account for account %s\n",
1844 __FUNCTION__, account);
1847 /* If there was any problem creating the account, for example,
1848 with the configuration system this could not exist */
1849 if (TNY_IS_TRANSPORT_ACCOUNT(transport_account)) {
1850 TnyAccount *local_account = NULL;
1851 TnyFolder *outbox = NULL;
1853 /* Forget any cached password for the account */
1854 forget_password_in_memory (self, tny_account_get_id (transport_account));
1856 /* Remove it from the list of accounts and notify the
1857 observers. Do not need to wait for account
1859 tny_list_remove (priv->transport_accounts, (GObject *) transport_account);
1860 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 0, transport_account);
1862 /* Remove the OUTBOX of the account from the global outbox */
1863 outbox = g_hash_table_lookup (priv->outbox_of_transport, transport_account);
1865 if (TNY_IS_FOLDER (outbox)) {
1866 TnyAccount *outbox_account = tny_folder_get_account (outbox);
1868 if (outbox_account) {
1869 tny_list_remove (priv->store_accounts_outboxes, G_OBJECT (outbox_account));
1870 /* Remove existing emails to send */
1871 tny_store_account_delete_cache (TNY_STORE_ACCOUNT (outbox_account));
1872 g_object_unref (outbox_account);
1875 local_account = modest_tny_account_store_get_local_folders_account (self);
1876 modest_tny_local_folders_account_remove_folder_from_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1879 g_hash_table_remove (priv->outbox_of_transport, transport_account);
1881 /* Notify the change in the local account */
1882 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1883 g_object_unref (local_account);
1885 g_warning ("Removing a transport account that has no outbox");
1888 /* Cancel all pending operations */
1889 tny_account_cancel (TNY_ACCOUNT (transport_account));
1891 /* Disconnect and notify the observers. The callback will free the reference */
1892 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (transport_account), FALSE,
1893 on_account_disconnect_when_removing, self);
1895 g_warning ("%s: no transport account for account %s\n",
1896 __FUNCTION__, account);
1900 TnyTransportAccount *
1901 modest_tny_account_store_new_connection_specific_transport_account (ModestTnyAccountStore *self,
1904 ModestTnyAccountStorePrivate *priv = NULL;
1905 TnyAccount * tny_account = NULL;
1907 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1909 /* Add the account: */
1911 modest_tny_account_new_from_server_account_name (priv->account_mgr,
1917 g_object_set_data (G_OBJECT(tny_account),
1920 g_object_set_data (G_OBJECT(tny_account),
1921 "connection_specific",
1922 GINT_TO_POINTER (TRUE));
1924 tny_list_append (priv->transport_accounts, G_OBJECT (tny_account));
1925 add_outbox_from_transport_account_to_global_outbox (self,
1930 g_printerr ("modest: failed to create smtp-specific account for %s\n",
1933 return TNY_TRANSPORT_ACCOUNT (tny_account);
1938 add_connection_specific_transport_accounts (ModestTnyAccountStore *self)
1940 ModestTnyAccountStorePrivate *priv = NULL;
1941 GSList *list_specifics = NULL, *iter = NULL;
1943 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1945 ModestConf *conf = modest_runtime_get_conf ();
1948 list_specifics = modest_conf_get_list (conf,
1949 MODEST_CONF_CONNECTION_SPECIFIC_SMTP_LIST,
1950 MODEST_CONF_VALUE_STRING, &err);
1952 g_printerr ("modest: %s: error getting list: %s\n.", __FUNCTION__, err->message);
1957 /* Look at each connection-specific transport account for the
1958 * modest account: */
1959 iter = list_specifics;
1961 /* The list alternates between the connection name and the transport name: */
1962 iter = g_slist_next (iter);
1964 const gchar* transport_account_name = (const gchar*) (iter->data);
1965 TnyTransportAccount * account = NULL;
1966 account = modest_tny_account_store_new_connection_specific_transport_account (
1967 self, transport_account_name);
1969 g_object_unref (account);
1971 iter = g_slist_next (iter);
1976 modest_tny_account_store_find_msg_in_outboxes (ModestTnyAccountStore *self,
1978 TnyAccount **ac_out)
1980 TnyIterator *acc_iter;
1981 ModestTnyAccountStorePrivate *priv;
1983 TnyAccount *msg_account = NULL;
1985 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1986 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1988 acc_iter = tny_list_create_iterator (priv->store_accounts_outboxes);
1989 while (!msg && !tny_iterator_is_done (acc_iter)) {
1990 TnyList *folders = tny_simple_list_new ();
1991 TnyAccount *account = TNY_ACCOUNT (tny_iterator_get_current (acc_iter));
1992 TnyIterator *folders_iter = NULL;
1994 tny_folder_store_get_folders (TNY_FOLDER_STORE (account), folders, NULL, NULL);
1995 folders_iter = tny_list_create_iterator (folders);
1997 while (msg == NULL && !tny_iterator_is_done (folders_iter)) {
1998 TnyFolder *folder = TNY_FOLDER (tny_iterator_get_current (folders_iter));
1999 msg = tny_folder_find_msg (folder, uri, NULL);
2002 msg_account = g_object_ref (account);
2004 g_object_unref (folder);
2005 tny_iterator_next (folders_iter);
2007 g_object_unref (folders_iter);
2009 g_object_unref (folders);
2010 g_object_unref (account);
2011 tny_iterator_next (acc_iter);
2014 g_object_unref (acc_iter);
2017 *ac_out = msg_account;
2022 TnyTransportAccount *
2023 modest_tny_account_store_get_transport_account_from_outbox_header(ModestTnyAccountStore *self, TnyHeader *header)
2025 TnyIterator *acc_iter;
2026 ModestTnyAccountStorePrivate *priv;
2027 TnyTransportAccount *header_acc = NULL;
2030 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
2031 g_return_val_if_fail (TNY_IS_HEADER (header), NULL);
2032 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2033 msg_id = modest_tny_send_queue_get_msg_id (header);
2034 acc_iter = tny_list_create_iterator (priv->transport_accounts);
2035 while (!header_acc && !tny_iterator_is_done (acc_iter)) {
2036 TnyTransportAccount *account = TNY_TRANSPORT_ACCOUNT (tny_iterator_get_current (acc_iter));
2037 ModestTnySendQueue *send_queue;
2038 ModestTnySendQueueStatus status;
2039 send_queue = modest_runtime_get_send_queue(TNY_TRANSPORT_ACCOUNT(account), TRUE);
2040 if (TNY_IS_SEND_QUEUE (send_queue)) {
2041 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2042 if (status != MODEST_TNY_SEND_QUEUE_UNKNOWN)
2043 header_acc = g_object_ref(account);
2045 g_object_unref (account);
2046 tny_iterator_next (acc_iter);
2048 g_object_unref(acc_iter);
2056 modest_tny_account_store_show_account_settings_dialog (ModestTnyAccountStore *self,
2057 const gchar *account_name)
2059 ModestTnyAccountStorePrivate *priv;
2060 gpointer dialog_as_gpointer = NULL;
2063 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
2064 found = g_hash_table_lookup_extended (priv->account_settings_dialog_hash,
2065 account_name, NULL, (gpointer*)&dialog_as_gpointer);
2068 modest_account_settings_dialog_check_allow_changes ((ModestAccountSettingsDialog *) dialog_as_gpointer);
2069 return (GtkWidget *) dialog_as_gpointer;
2071 ModestAccountSettings *settings;
2073 dialog = (GtkWidget *) modest_account_settings_dialog_new ();
2074 settings = modest_account_mgr_load_account_settings (priv->account_mgr, account_name);
2075 modest_account_settings_dialog_save_password (MODEST_ACCOUNT_SETTINGS_DIALOG (dialog));
2076 modest_account_settings_dialog_set_account (MODEST_ACCOUNT_SETTINGS_DIALOG (dialog), settings);
2077 g_object_unref (settings);
2078 modest_account_settings_dialog_switch_to_user_info (MODEST_ACCOUNT_SETTINGS_DIALOG (dialog));
2079 modest_account_settings_dialog_check_allow_changes (MODEST_ACCOUNT_SETTINGS_DIALOG (dialog));
2080 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), GTK_WINDOW (dialog));
2082 g_hash_table_insert (priv->account_settings_dialog_hash, g_strdup (account_name), dialog);
2084 g_signal_connect (G_OBJECT (dialog), "hide", G_CALLBACK (on_account_settings_hide),
2085 g_strdup (account_name));
2087 /* Show it and delete it when it closes: */
2088 g_signal_connect_swapped (dialog,
2090 G_CALLBACK (gtk_widget_destroy),
2092 gtk_widget_show (GTK_WIDGET (dialog));