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 (modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
305 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT(account), FALSE, NULL, NULL);
309 /* disconnect the list of TnyAccounts */
311 account_verify_last_ref (TnyAccount *account, const gchar *str)
315 g_return_if_fail (account && TNY_IS_ACCOUNT(account));
317 txt = g_strdup_printf ("%s: %s", str ? str : "?", tny_account_get_name(account));
318 MODEST_DEBUG_VERIFY_OBJECT_LAST_REF(G_OBJECT(account),txt);
326 foreach_account_append_to_list (gpointer data,
331 list = TNY_LIST (user_data);
332 tny_list_append (list, G_OBJECT (data));
335 /********************************************************************/
336 /* Control the state of the MMC local account */
337 /********************************************************************/
339 /** Only call this if the memory card is really mounted.
342 add_mmc_account(ModestTnyAccountStore *self, gboolean emit_insert_signal)
344 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
345 g_return_if_fail (priv->session);
347 TnyAccount *mmc_account = modest_tny_account_new_for_local_folders (priv->account_mgr,
349 MODEST_MCC1_VOLUMEPATH);
351 /* Add to the list of store accounts */
352 tny_list_append (priv->store_accounts, G_OBJECT (mmc_account));
354 if (emit_insert_signal) {
355 g_signal_emit (G_OBJECT (self),
356 signals [ACCOUNT_INSERTED_SIGNAL],
361 g_object_unref (mmc_account);
365 on_vfs_volume_mounted(GnomeVFSVolumeMonitor *volume_monitor,
366 GnomeVFSVolume *volume,
369 ModestTnyAccountStore *self;
370 ModestTnyAccountStorePrivate *priv;
374 self = MODEST_TNY_ACCOUNT_STORE(user_data);
375 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
377 /* Check whether this was the external MMC1 card: */
378 uri = gnome_vfs_volume_get_activation_uri (volume);
380 if (uri && (!strcmp (uri, MODEST_MCC1_VOLUMEPATH_URI))) {
381 add_mmc_account (self, TRUE /* emit the insert signal. */);
388 on_vfs_volume_unmounted(GnomeVFSVolumeMonitor *volume_monitor,
389 GnomeVFSVolume *volume,
392 ModestTnyAccountStore *self;
393 ModestTnyAccountStorePrivate *priv;
396 self = MODEST_TNY_ACCOUNT_STORE(user_data);
397 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
399 /* Check whether this was the external MMC1 card: */
400 uri = gnome_vfs_volume_get_activation_uri (volume);
401 if (uri && (strcmp (uri, MODEST_MCC1_VOLUMEPATH_URI) == 0)) {
402 TnyAccount *mmc_account = NULL;
403 gboolean found = FALSE;
404 TnyIterator *iter = NULL;
406 iter = tny_list_create_iterator (priv->store_accounts);
407 while (!tny_iterator_is_done (iter) && !found) {
410 account = TNY_ACCOUNT (tny_iterator_get_current (iter));
411 if (modest_tny_account_is_memory_card_account (account)) {
413 mmc_account = g_object_ref (account);
415 g_object_unref (account);
416 tny_iterator_next (iter);
418 g_object_unref (iter);
421 /* Remove from the list */
422 tny_list_remove (priv->store_accounts, G_OBJECT (mmc_account));
424 /* Notify observers */
425 g_signal_emit (G_OBJECT (self),
426 signals [ACCOUNT_REMOVED_SIGNAL],
429 g_object_unref (mmc_account);
431 g_warning ("%s: there was no store account for the unmounted MMC",
439 * forget_password_in_memory
440 * @self: a TnyAccountStore instance
441 * @account: A server account.
443 * Forget any password stored in memory for this account.
444 * For instance, this should be called when the user has changed the password in the account settings.
447 forget_password_in_memory (ModestTnyAccountStore *self,
448 const gchar * server_account_name)
450 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
452 if (server_account_name && priv->password_hash) {
453 g_hash_table_remove (priv->password_hash, server_account_name);
458 on_account_changed (ModestAccountMgr *acc_mgr,
459 const gchar *account_name,
460 TnyAccountType account_type,
463 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(user_data);
464 ModestTnyAccountStorePrivate *priv;
465 TnyList* account_list;
466 gboolean found = FALSE;
467 TnyIterator *iter = NULL;
469 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
470 account_list = (account_type == TNY_ACCOUNT_TYPE_STORE ?
471 priv->store_accounts :
472 priv->transport_accounts);
474 iter = tny_list_create_iterator (account_list);
475 while (!tny_iterator_is_done (iter) && !found) {
476 TnyAccount *tny_account;
477 tny_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
479 if (!strcmp (tny_account_get_id (tny_account), account_name)) {
481 modest_tny_account_update_from_account (tny_account, get_password, forget_password);
482 g_signal_emit (G_OBJECT(self), signals[ACCOUNT_CHANGED_SIGNAL], 0, tny_account);
484 g_object_unref (tny_account);
486 tny_iterator_next (iter);
490 g_object_unref (iter);
494 on_account_settings_hide (GtkWidget *widget, gpointer user_data)
496 /* This is easier than using a struct for the user_data: */
497 ModestTnyAccountStore *self = modest_runtime_get_account_store();
498 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
500 gchar *account_name = (gchar *) user_data;
502 g_hash_table_remove (priv->account_settings_dialog_hash, account_name);
506 show_password_warning_only (const gchar *msg)
508 ModestWindow *main_window =
509 modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (), FALSE); /* don't create */
511 /* Show an explanatory temporary banner: */
513 modest_platform_information_banner (NULL, NULL, msg);
517 show_wrong_password_dialog (TnyAccount *account)
519 /* This is easier than using a struct for the user_data: */
520 ModestTnyAccountStore *self = modest_runtime_get_account_store();
521 const gchar *modest_account_name;
522 GtkWidget *main_window;
525 main_window = (GtkWidget *) modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (),
526 FALSE); /* don't create */
528 g_warning ("%s: password was wrong; ignoring because no main window", __FUNCTION__);
532 modest_account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
533 if (!modest_account_name) {
534 g_warning ("%s: modest_tny_account_get_parent_modest_account_name_for_server_account() failed.\n",
538 dialog = modest_tny_account_store_show_account_settings_dialog (self, modest_account_name);
539 modest_account_settings_dialog_save_password (MODEST_ACCOUNT_SETTINGS_DIALOG (dialog));
540 /* Show an explanatory temporary banner: */
541 modest_platform_information_banner (GTK_WIDGET(dialog), NULL, _("mcen_ib_username_pw_incorrect"));
544 /* This callback will be called by Tinymail when it needs the password
545 * from the user or the account settings.
546 * It can also call forget_password() before calling this,
547 * so that we clear wrong passwords out of our account settings.
548 * Note that TnyAccount here will be the server account. */
550 get_password (TnyAccount *account, const gchar * prompt_not_used, gboolean *cancel)
552 ModestTnyAccountStore *self = NULL;
553 ModestTnyAccountStorePrivate *priv;
554 gchar *username = NULL;
556 gpointer pwd_ptr = NULL;
557 gboolean already_asked = FALSE;
558 const gchar *server_account_name;
561 g_return_val_if_fail (account, NULL);
564 g_debug ("%s: prompt (not shown) = %s\n", __FUNCTION__, prompt_not_used);
567 /* Get a reference to myself */
568 self = MODEST_TNY_ACCOUNT_STORE (g_object_get_data (G_OBJECT(account), "account_store"));
569 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
571 /* Ensure that we still have this account. It could happen
572 that a set_online was requested *before* removing an
573 account, and due to tinymail emits the get_password
574 function using a g_idle the account could be actually
575 removed *before* this function was really called */
576 url_string = tny_account_get_url_string (account);
578 TnyAccount *tmp_account;
580 tmp_account = tny_account_store_find_account (TNY_ACCOUNT_STORE (self),
588 g_object_unref (tmp_account);
591 server_account_name = tny_account_get_id (account);
592 if (!server_account_name || !self) {
593 g_warning ("modest: %s: could not retrieve account_store for account %s",
594 __FUNCTION__, server_account_name ? server_account_name : "<NULL>");
601 /* This hash map stores passwords, including passwords that are not stored in gconf. */
602 /* Is it in the hash? if it's already there, it must be wrong... */
603 pwd_ptr = (gpointer)&pwd; /* pwd_ptr so the compiler does not complained about
604 * type-punned ptrs...*/
605 already_asked = priv->password_hash &&
606 g_hash_table_lookup_extended (priv->password_hash,
609 (gpointer*)&pwd_ptr);
611 g_debug ("%s: Already asked = %d\n", __FUNCTION__, already_asked);
614 /* If the password is not already there, try ModestConf */
615 if (!already_asked) {
616 pwd = modest_account_mgr_get_server_account_password (priv->account_mgr,
617 server_account_name);
618 g_hash_table_insert (priv->password_hash, g_strdup (server_account_name), g_strdup (pwd));
621 /* If it was already asked, it must have been wrong, so ask again */
622 if (already_asked || !pwd || strlen(pwd) == 0) {
623 /* As per the UI spec, if no password was set in the account settings,
624 * ask for it now. But if the password is wrong in the account settings,
625 * then show a banner and the account settings dialog so it can be corrected:
627 ModestTransportStoreProtocol proto;
628 const gboolean settings_have_password =
629 modest_account_mgr_get_server_account_has_password (priv->account_mgr, server_account_name);
631 /* Show an error and after that ask for a password */
632 proto = modest_protocol_info_get_transport_store_protocol (tny_account_get_proto (account));
633 if (proto == MODEST_PROTOCOL_TRANSPORT_SMTP) {
634 gchar *username = NULL, *msg = NULL;
635 username = modest_account_mgr_get_server_account_username (priv->account_mgr,
636 server_account_name);
637 if (!username || strlen(username) == 0) {
638 msg = g_strdup_printf (_("emev_ni_ui_smtp_userid_invalid"),
639 tny_account_get_name (account),
640 tny_account_get_hostname (account));
643 password = modest_account_mgr_get_server_account_password (priv->account_mgr,
644 server_account_name);
645 if (!password || strlen(password) == 0)
646 msg = g_strdup_printf (_("emev_ni_ui_smtp_passwd_invalid"),
647 tny_account_get_name (account),
648 tny_account_get_hostname (account));
650 msg = g_strdup_printf (_("emev_ni_ui_smtp_authentication_fail_error"),
651 tny_account_get_hostname (account));
656 modest_platform_run_information_dialog (NULL, msg, TRUE);
663 if (settings_have_password) {
664 /* The password must be wrong, so show the account settings dialog so it can be corrected: */
665 show_wrong_password_dialog (account);
673 /* we don't have it yet. Get the password from the user */
674 const gchar* account_id = tny_account_get_id (account);
675 gboolean remember = FALSE;
680 gboolean username_known =
681 modest_account_mgr_get_server_account_username_has_succeeded(priv->account_mgr,
682 server_account_name);
683 /* If the login has ever succeeded then show a specific message */
685 msg = _("ecdg_ib_set_password_incorrect");
687 msg = _("mcen_ib_username_pw_incorrect");
688 show_password_warning_only (msg);
691 /* Request password */
692 g_signal_emit (G_OBJECT (self), signals[PASSWORD_REQUESTED_SIGNAL], 0,
693 account_id, /* server_account_name */
694 &username, &pwd, cancel, &remember);
698 /* The password will be returned as the result,
699 * but we need to tell tinymail about the username too: */
700 tny_account_set_user (account, username);
702 /* Do not save the password in gconf, because
703 * the UI spec says "The password will never
704 * be saved in the account": */
706 /* We need to dup the string even knowing that
707 it's already a dup of the contents of an
708 entry, because it if it's wrong, then camel
710 g_hash_table_insert (priv->password_hash, g_strdup (server_account_name), g_strdup(pwd));
712 g_hash_table_remove (priv->password_hash, server_account_name);
727 modest_tny_account_store_forget_already_asked (ModestTnyAccountStore *self, TnyAccount *account)
729 g_return_if_fail (account);
731 ModestTnyAccountStorePrivate *priv;
733 gpointer pwd_ptr = NULL;
734 gboolean already_asked = FALSE;
736 const gchar *server_account_name = tny_account_get_id (account);
738 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
740 /* This hash map stores passwords, including passwords that are not stored in gconf. */
741 pwd_ptr = (gpointer)&pwd; /* pwd_ptr so the compiler does not complained about
742 * type-punned ptrs...*/
743 already_asked = priv->password_hash &&
744 g_hash_table_lookup_extended (priv->password_hash,
747 (gpointer*)&pwd_ptr);
750 g_hash_table_remove (priv->password_hash, server_account_name);
758 /* tinymail calls this if the connection failed due to an incorrect password.
759 * And it seems to call this for any general connection failure. */
761 forget_password (TnyAccount *account)
763 ModestTnyAccountStore *self;
764 ModestTnyAccountStorePrivate *priv;
765 const TnyAccountStore *account_store;
769 account_store = TNY_ACCOUNT_STORE(g_object_get_data (G_OBJECT(account),
771 self = MODEST_TNY_ACCOUNT_STORE (account_store);
772 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
773 key = tny_account_get_id (account);
775 /* Do not remove the key, this will allow us to detect that we
776 have already asked for it at least once */
777 pwd = g_hash_table_lookup (priv->password_hash, key);
779 memset (pwd, 0, strlen (pwd));
780 g_hash_table_insert (priv->password_hash, g_strdup (key), NULL);
783 /* Remove from configuration system */
785 modest_account_mgr_unset (priv->account_mgr,
786 key, MODEST_ACCOUNT_PASSWORD, TRUE);
791 modest_tny_account_store_finalize (GObject *obj)
793 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(obj);
794 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
796 g_free (priv->cache_dir);
797 priv->cache_dir = NULL;
799 if (priv->password_hash) {
800 g_hash_table_destroy (priv->password_hash);
801 priv->password_hash = NULL;
804 if (priv->account_settings_dialog_hash) {
805 g_hash_table_destroy (priv->account_settings_dialog_hash);
806 priv->account_settings_dialog_hash = NULL;
809 if (priv->outbox_of_transport) {
810 g_hash_table_destroy (priv->outbox_of_transport);
811 priv->outbox_of_transport = NULL;
814 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
815 priv->sighandlers = NULL;
817 if (priv->account_mgr) {
818 g_object_unref (G_OBJECT(priv->account_mgr));
819 priv->account_mgr = NULL;
823 g_object_unref (G_OBJECT(priv->device));
827 /* Destroy all accounts. Disconnect all accounts before they are destroyed */
828 if (priv->store_accounts) {
829 tny_list_foreach (priv->store_accounts, (GFunc)account_disconnect, NULL);
830 tny_list_foreach (priv->store_accounts, (GFunc)account_verify_last_ref, "store");
831 g_object_unref (priv->store_accounts);
832 priv->store_accounts = NULL;
835 if (priv->transport_accounts) {
836 tny_list_foreach (priv->transport_accounts, (GFunc)account_disconnect, NULL);
837 tny_list_foreach (priv->transport_accounts, (GFunc)account_verify_last_ref, "transport");
838 g_object_unref (priv->transport_accounts);
839 priv->transport_accounts = NULL;
842 if (priv->store_accounts_outboxes) {
843 g_object_unref (priv->store_accounts_outboxes);
844 priv->store_accounts_outboxes = NULL;
848 camel_object_unref (CAMEL_OBJECT(priv->session));
849 priv->session = NULL;
854 G_OBJECT_CLASS(parent_class)->finalize (obj);
858 volume_path_is_mounted (const gchar* path)
860 g_return_val_if_fail (path, FALSE);
862 gboolean result = FALSE;
863 gchar * path_as_uri = g_filename_to_uri (path, NULL, NULL);
864 g_return_val_if_fail (path_as_uri, FALSE);
866 /* Get the monitor singleton: */
867 GnomeVFSVolumeMonitor *monitor = gnome_vfs_get_volume_monitor();
869 /* This seems like a simpler way to do this, but it returns a
870 * GnomeVFSVolume even if the drive is not mounted: */
872 GnomeVFSVolume *volume = gnome_vfs_volume_monitor_get_volume_for_path (monitor,
873 MODEST_MCC1_VOLUMEPATH);
875 gnome_vfs_volume_unref(volume);
879 /* Get the mounted volumes from the monitor: */
880 GList *list = gnome_vfs_volume_monitor_get_mounted_volumes (monitor);
882 for (iter = list; iter; iter = g_list_next (iter)) {
883 GnomeVFSVolume *volume = (GnomeVFSVolume*)iter->data;
887 gnome_vfs_volume_get_display_name (volume);
888 printf ("volume display name=%s\n", display_name);
889 g_free (display_name);
893 gnome_vfs_volume_get_activation_uri (volume);
894 /* printf (" uri=%s\n", uri); */
895 if (uri && (strcmp (uri, path_as_uri) == 0))
900 gnome_vfs_volume_unref (volume);
906 g_free (path_as_uri);
911 ModestTnyAccountStore*
912 modest_tny_account_store_new (ModestAccountMgr *account_mgr,
916 ModestTnyAccountStorePrivate *priv;
917 TnyAccount *local_account = NULL;
919 g_return_val_if_fail (account_mgr, NULL);
920 g_return_val_if_fail (device, NULL);
922 obj = G_OBJECT(g_object_new(MODEST_TYPE_TNY_ACCOUNT_STORE, NULL));
923 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
925 priv->account_mgr = g_object_ref (G_OBJECT(account_mgr));
926 priv->device = g_object_ref (device);
928 priv->session = tny_session_camel_new (TNY_ACCOUNT_STORE(obj));
929 if (!priv->session) {
930 g_warning ("failed to get TnySessionCamel");
934 /* Set the ui locker */
935 tny_session_camel_set_ui_locker (priv->session, tny_gtk_lockable_new ());
937 /* Connect signals */
938 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
939 G_OBJECT(account_mgr), "account_inserted",
940 G_CALLBACK (on_account_inserted), obj);
941 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
942 G_OBJECT(account_mgr), "account_changed",
943 G_CALLBACK (on_account_changed), obj);
944 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
945 G_OBJECT(account_mgr), "account_removed",
946 G_CALLBACK (on_account_removed), obj);
948 /* Create the lists of accounts */
949 priv->store_accounts = tny_simple_list_new ();
950 priv->transport_accounts = tny_simple_list_new ();
951 priv->store_accounts_outboxes = tny_simple_list_new ();
953 /* Create the local folders account */
955 modest_tny_account_new_for_local_folders (priv->account_mgr, priv->session, NULL);
956 tny_list_append (priv->store_accounts, G_OBJECT(local_account));
957 g_object_unref (local_account);
959 /* Add the other remote accounts. Do this after adding the
960 local account, because we need to add our outboxes to the
961 global OUTBOX hosted in the local account */
962 add_existing_accounts (MODEST_TNY_ACCOUNT_STORE (obj));
964 /* FIXME: I'm doing this (adding an "if (FALSE)"because this
965 stuff is not working properly and could cause SIGSEVs, for
966 example one send queue will be created for each connection
967 specific SMTP server, so when tinymail asks for the outbox
968 it will return NULL because there is no outbox folder for
969 this specific transport accounts, and it's a must that the
970 send queue returns an outbox */
972 /* Add connection-specific transport accounts */
973 add_connection_specific_transport_accounts (MODEST_TNY_ACCOUNT_STORE(obj));
975 /* This is a singleton, so it does not need to be unrefed. */
976 if (volume_path_is_mounted (MODEST_MCC1_VOLUMEPATH)) {
978 add_mmc_account (MODEST_TNY_ACCOUNT_STORE (obj), FALSE /* don't emit the insert signal. */);
981 return MODEST_TNY_ACCOUNT_STORE(obj);
985 modest_tny_account_store_get_accounts (TnyAccountStore *self,
987 TnyGetAccountsRequestType request_type)
989 ModestTnyAccountStorePrivate *priv;
991 g_return_if_fail (self);
992 g_return_if_fail (TNY_IS_LIST(list));
994 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
996 switch (request_type) {
997 case TNY_ACCOUNT_STORE_BOTH:
998 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
999 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
1001 case TNY_ACCOUNT_STORE_STORE_ACCOUNTS:
1002 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
1004 case TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS:
1005 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
1008 g_return_if_reached ();
1011 /* Initialize session. Why do we need this ??? */
1012 tny_session_camel_set_initialized (priv->session);
1017 modest_tny_account_store_get_cache_dir (TnyAccountStore *self)
1019 ModestTnyAccountStorePrivate *priv;
1020 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1022 if (!priv->cache_dir)
1023 priv->cache_dir = g_build_filename (g_get_home_dir(),
1024 MODEST_DIR, MODEST_CACHE_DIR, NULL);
1025 return priv->cache_dir;
1030 * callers need to unref
1033 modest_tny_account_store_get_device (TnyAccountStore *self)
1035 ModestTnyAccountStorePrivate *priv;
1037 g_return_val_if_fail (self, NULL);
1039 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1042 return g_object_ref (G_OBJECT(priv->device));
1049 modest_tny_account_store_find_account_by_url (TnyAccountStore *self, const gchar* url_string)
1051 return modest_tny_account_store_get_tny_account_by (MODEST_TNY_ACCOUNT_STORE (self),
1052 MODEST_TNY_ACCOUNT_STORE_QUERY_URL,
1059 modest_tny_account_store_alert (TnyAccountStore *self,
1060 TnyAccount *account,
1065 ModestTransportStoreProtocol proto =
1066 MODEST_PROTOCOL_TRANSPORT_STORE_UNKNOWN;
1067 const gchar* server_name = NULL;
1068 gchar *prompt = NULL;
1072 g_return_val_if_fail (account, FALSE);
1073 g_return_val_if_fail (error, FALSE);
1075 /* Get the server name: */
1076 server_name = tny_account_get_hostname (account);
1079 const gchar *proto_name = tny_account_get_proto (account);
1081 proto = modest_protocol_info_get_transport_store_protocol (proto_name);
1083 g_warning("modest: %s: account with id=%s has no proto.\n", __FUNCTION__,
1084 tny_account_get_id (account));
1089 switch (error->code) {
1090 case TNY_SYSTEM_ERROR_CANCEL:
1091 /* Don't show waste the user's time by showing him a dialog telling
1092 * him that he has just cancelled something: */
1095 case TNY_SERVICE_ERROR_PROTOCOL:
1096 /* Like a BAD from IMAP (protocol error) */
1097 case TNY_SERVICE_ERROR_LOST_CONNECTION:
1098 /* Lost the connection with the service */
1099 case TNY_SERVICE_ERROR_UNAVAILABLE:
1100 /* You must be working online for this operation */
1101 case TNY_SERVICE_ERROR_CONNECT:
1103 case MODEST_PROTOCOL_STORE_POP:
1104 prompt = g_strdup_printf (_("emev_ni_ui_pop3_msg_connect_error"),
1107 case MODEST_PROTOCOL_STORE_IMAP:
1108 prompt = g_strdup_printf (_("emev_ni_ui_imap_connect_server_error"),
1111 case MODEST_PROTOCOL_TRANSPORT_SMTP:
1112 prompt = g_strdup_printf (_("emev_ib_ui_smtp_server_invalid"),
1116 g_return_val_if_reached (FALSE);
1120 case TNY_SERVICE_ERROR_AUTHENTICATE:
1121 /* It seems that there's no better error to show with
1122 * POP and IMAP because TNY_SERVICE_ERROR_AUTHENTICATE
1123 * may appear if there's a timeout during auth */
1125 case MODEST_PROTOCOL_STORE_POP:
1126 prompt = g_strdup_printf (_("emev_ni_ui_pop3_msg_connect_error"),
1129 case MODEST_PROTOCOL_STORE_IMAP:
1130 prompt = g_strdup_printf (_("emev_ni_ui_imap_connect_server_error"),
1133 case MODEST_PROTOCOL_TRANSPORT_SMTP:
1134 prompt = g_strdup_printf (_("emev_ni_ui_smtp_authentication_fail_error"),
1138 g_return_val_if_reached (FALSE);
1142 case TNY_SERVICE_ERROR_CERTIFICATE:
1143 /* We'll show the proper dialog later */
1146 case TNY_SYSTEM_ERROR_MEMORY:
1147 /* Can't allocate memory for this operation */
1149 case TNY_SERVICE_ERROR_UNKNOWN:
1152 g_return_val_if_reached (FALSE);
1156 if (error->code == TNY_SERVICE_ERROR_CERTIFICATE)
1157 retval = modest_platform_run_certificate_confirmation_dialog (server_name,
1160 retval = modest_platform_run_alert_dialog (prompt, question);
1170 modest_tny_account_store_init (gpointer g, gpointer iface_data)
1172 TnyAccountStoreIface *klass;
1174 g_return_if_fail (g);
1176 klass = (TnyAccountStoreIface *)g;
1178 klass->get_accounts =
1179 modest_tny_account_store_get_accounts;
1180 klass->get_cache_dir =
1181 modest_tny_account_store_get_cache_dir;
1183 modest_tny_account_store_get_device;
1185 modest_tny_account_store_alert;
1186 klass->find_account =
1187 modest_tny_account_store_find_account_by_url;
1191 modest_tny_account_store_set_get_pass_func (ModestTnyAccountStore *self,
1192 ModestTnyGetPassFunc func)
1194 /* not implemented, we use signals */
1195 g_printerr ("modest: set_get_pass_func not implemented\n");
1199 modest_tny_account_store_get_session (TnyAccountStore *self)
1201 g_return_val_if_fail (self, NULL);
1202 return MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self)->session;
1206 get_tny_account_by (TnyList *accounts,
1207 ModestTnyAccountStoreQueryType type,
1210 TnyIterator *iter = NULL;
1211 gboolean found = FALSE;
1212 TnyAccount *retval = NULL;
1214 g_return_val_if_fail (TNY_IS_LIST(accounts), NULL);
1216 if (tny_list_get_length(accounts) == 0) {
1217 g_warning ("%s: account list is empty", __FUNCTION__);
1221 iter = tny_list_create_iterator (accounts);
1222 while (!tny_iterator_is_done (iter) && !found) {
1223 TnyAccount *tmp_account = NULL;
1224 const gchar *val = NULL;
1226 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1227 if (!TNY_IS_ACCOUNT(tmp_account)) {
1228 g_warning ("%s: not a valid account", __FUNCTION__);
1234 case MODEST_TNY_ACCOUNT_STORE_QUERY_ID:
1235 val = tny_account_get_id (tmp_account);
1237 case MODEST_TNY_ACCOUNT_STORE_QUERY_URL:
1238 val = tny_account_get_url_string (tmp_account);
1242 if (type == MODEST_TNY_ACCOUNT_STORE_QUERY_URL &&
1243 tny_account_matches_url_string (tmp_account, str)) {
1244 retval = g_object_ref (tmp_account);
1247 if (val && str && strcmp (val, str) == 0) {
1248 retval = g_object_ref (tmp_account);
1252 g_object_unref (tmp_account);
1253 tny_iterator_next (iter);
1255 g_object_unref (iter);
1261 modest_tny_account_store_get_tny_account_by (ModestTnyAccountStore *self,
1262 ModestTnyAccountStoreQueryType type,
1265 TnyAccount *account = NULL;
1266 ModestTnyAccountStorePrivate *priv;
1268 g_return_val_if_fail (self, NULL);
1269 g_return_val_if_fail (str, NULL);
1271 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1273 /* Search in store accounts */
1274 account = get_tny_account_by (priv->store_accounts, type, str);
1276 /* If we already found something, no need to search the transport accounts */
1278 account = get_tny_account_by (priv->transport_accounts, type, str);
1280 /* If we already found something, no need to search the
1281 per-account outbox accounts */
1283 account = get_tny_account_by (priv->store_accounts_outboxes, type, str);
1286 /* Warn if nothing was found. This is generally unusual. */
1288 g_warning("%s: Failed to find account with %s=%s\n",
1290 (type == MODEST_TNY_ACCOUNT_STORE_QUERY_ID) ? "ID" : "URL",
1294 /* Returns a new reference to the account if found */
1300 modest_tny_account_store_get_server_account (ModestTnyAccountStore *self,
1301 const gchar *account_name,
1302 TnyAccountType type)
1304 ModestTnyAccountStorePrivate *priv = NULL;
1305 TnyAccount *retval = NULL;
1306 TnyList *account_list = NULL;
1307 TnyIterator *iter = NULL;
1310 g_return_val_if_fail (self, NULL);
1311 g_return_val_if_fail (account_name, NULL);
1312 g_return_val_if_fail (type == TNY_ACCOUNT_TYPE_STORE ||
1313 type == TNY_ACCOUNT_TYPE_TRANSPORT,
1316 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1318 account_list = (type == TNY_ACCOUNT_TYPE_STORE) ?
1319 priv->store_accounts :
1320 priv->transport_accounts;
1322 if (!account_list) {
1323 g_printerr ("%s: No server accounts of type %s\n", __FUNCTION__,
1324 (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport");
1328 /* Look for the server account */
1330 iter = tny_list_create_iterator (account_list);
1331 while (!tny_iterator_is_done (iter) && !found) {
1332 const gchar *modest_acc_name;
1333 TnyAccount *tmp_account;
1335 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1337 modest_tny_account_get_parent_modest_account_name_for_server_account (tmp_account);
1339 if (account_name && modest_acc_name && !strcmp (account_name, modest_acc_name)) {
1341 retval = g_object_ref (tmp_account);
1343 /* Free and continue */
1344 g_object_unref (tmp_account);
1345 tny_iterator_next (iter);
1347 g_object_unref (iter);
1350 g_printerr ("modest: %s: could not get tny %s account for %s\n." \
1351 "Number of server accounts of this type=%d\n", __FUNCTION__,
1352 (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport",
1353 account_name, tny_list_get_length (account_list));
1356 /* Returns a new reference */
1361 modest_tny_account_store_get_smtp_specific_transport_account_for_open_connection (
1362 ModestTnyAccountStore *self, const gchar *account_name)
1366 g_return_val_if_fail (self && MODEST_IS_TNY_ACCOUNT_STORE(self), NULL);
1367 g_return_val_if_fail (account_name, NULL);
1369 /* Get the current connection: */
1370 device = modest_runtime_get_device ();
1373 g_warning ("%s: could not get device", __FUNCTION__);
1377 if (!tny_device_is_online (device))
1380 #ifdef MODEST_HAVE_CONIC
1381 g_return_val_if_fail (TNY_IS_MAEMO_CONIC_DEVICE (device), NULL);
1383 TnyMaemoConicDevice *maemo_device = TNY_MAEMO_CONIC_DEVICE (device);
1384 const gchar* iap_id = tny_maemo_conic_device_get_current_iap_id (maemo_device);
1385 /* printf ("DEBUG: %s: iap_id=%s\n", __FUNCTION__, iap_id); */
1389 ConIcIap* connection = tny_maemo_conic_device_get_iap (maemo_device, iap_id);
1393 const gchar *connection_id = con_ic_iap_get_id (connection);
1394 /* printf ("DEBUG: %s: connection_id=%s\n", __FUNCTION__, connection_id); */
1398 /* Get the connection-specific transport acccount, if any: */
1399 ModestAccountMgr *account_manager = modest_runtime_get_account_mgr ();
1401 /* Check if this account has connection-specific SMTP enabled */
1402 if (!modest_account_mgr_get_use_connection_specific_smtp (account_manager, account_name)) {
1406 gchar* server_account_name = modest_account_mgr_get_connection_specific_smtp (account_manager,
1409 /* printf ("DEBUG: %s: server_account_name=%s\n", __FUNCTION__, server_account_name); */
1410 if (!server_account_name) {
1411 return NULL; /* No connection-specific SMTP server was specified for this connection. */
1414 TnyAccount* account = modest_tny_account_store_get_tny_account_by (self,
1415 MODEST_TNY_ACCOUNT_STORE_QUERY_ID,
1416 server_account_name);
1418 /* printf ("DEBUG: %s: account=%p\n", __FUNCTION__, account); */
1419 g_free (server_account_name);
1421 /* Unref the get()ed object, as required by the tny_maemo_conic_device_get_iap() documentation. */
1422 g_object_unref (connection);
1426 return NULL; /* TODO: Implement this for GNOME, instead of just Maemo? */
1427 #endif /* MODEST_HAVE_CONIC */
1432 modest_tny_account_store_get_transport_account_for_open_connection (ModestTnyAccountStore *self,
1433 const gchar *account_name)
1435 g_return_val_if_fail (self, NULL);
1436 g_return_val_if_fail (account_name, NULL);
1438 if (!account_name || !self)
1441 /* Get the connection-specific transport acccount, if any: */
1442 /* Note: This gives us a reference: */
1443 TnyAccount *account =
1444 modest_tny_account_store_get_smtp_specific_transport_account_for_open_connection (self, account_name);
1446 /* If there is no connection-specific transport account (the common case),
1447 * just get the regular transport account: */
1449 /* The special local folders don't have transport accounts. */
1450 if (strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0)
1453 /* Note: This gives us a reference: */
1454 account = modest_tny_account_store_get_server_account (self, account_name,
1455 TNY_ACCOUNT_TYPE_TRANSPORT);
1459 /* returns a reference. */
1464 modest_tny_account_store_get_local_folders_account (ModestTnyAccountStore *self)
1466 TnyAccount *account = NULL;
1467 ModestTnyAccountStorePrivate *priv;
1471 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1473 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1476 iter = tny_list_create_iterator (priv->store_accounts);
1477 while (!tny_iterator_is_done (iter) && !found) {
1478 TnyAccount *tmp_account;
1480 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1481 if (modest_tny_account_is_virtual_local_folders (tmp_account)) {
1482 account = g_object_ref (tmp_account);
1485 g_object_unref (tmp_account);
1486 tny_iterator_next (iter);
1488 g_object_unref (iter);
1490 /* Returns a new reference to the account */
1495 modest_tny_account_store_get_mmc_folders_account (ModestTnyAccountStore *self)
1497 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1500 return modest_tny_account_store_get_tny_account_by (self, MODEST_TNY_ACCOUNT_STORE_QUERY_ID,
1501 MODEST_MMC_ACCOUNT_ID);
1505 /*********************************************************************************/
1507 add_existing_accounts (ModestTnyAccountStore *self)
1509 GSList *account_names = NULL, *iter = NULL;
1510 ModestTnyAccountStorePrivate *priv = NULL;
1512 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1514 /* These are account names, not server_account names */
1515 account_names = modest_account_mgr_account_names (priv->account_mgr, FALSE);
1517 for (iter = account_names; iter != NULL; iter = g_slist_next (iter)) {
1518 const gchar *account_name = (const gchar*) iter->data;
1520 /* Insert all enabled accounts without notifying */
1521 if (modest_account_mgr_get_enabled (priv->account_mgr, account_name))
1522 insert_account (self, account_name, FALSE);
1524 modest_account_mgr_free_account_names (account_names);
1528 connection_status_changed (TnyAccount *account,
1529 TnyConnectionStatus status,
1532 /* We do this here and not in the connection policy because we
1533 don't want to do it for every account, just for the
1534 accounts that are interactively added when modest is
1536 if (status == TNY_CONNECTION_STATUS_CONNECTED) {
1537 const gchar *account_name;
1538 ModestWindow *main_window;
1539 ModestTnyAccountStorePrivate *priv = NULL;
1541 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (data);
1543 /* Remove this handler */
1544 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
1546 "connection_status_changed");
1548 /* Perform a send receive */
1549 account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
1550 main_window = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (), FALSE);
1551 modest_ui_actions_do_send_receive (account_name, FALSE, FALSE, FALSE, main_window);
1556 create_tny_account (ModestTnyAccountStore *self,
1558 TnyAccountType type,
1561 TnyAccount *account = NULL;
1562 ModestTnyAccountStorePrivate *priv = NULL;
1564 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1566 account = modest_tny_account_new_from_account (priv->account_mgr,
1573 /* Forget any cached password for the account, so that
1574 we use a new account if any */
1575 forget_password_in_memory (self, tny_account_get_id (account));
1577 /* Install a signal handler that will refresh the
1578 account the first time it becomes online. Do this
1579 only if we're adding a new account while the
1580 program is running (we do not want to do this
1582 if (type == TNY_ACCOUNT_TYPE_STORE && notify)
1583 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
1585 "connection_status_changed",
1586 G_CALLBACK (connection_status_changed),
1589 /* Set the account store */
1590 g_object_set_data (G_OBJECT(account), "account_store", self);
1592 g_printerr ("modest: failed to create account for %s\n", name);
1600 add_outbox_from_transport_account_to_global_outbox (ModestTnyAccountStore *self,
1601 const gchar *account_name,
1602 TnyAccount *transport_account)
1604 TnyList *folders = NULL;
1605 TnyIterator *iter_folders = NULL;
1606 TnyAccount *local_account = NULL, *account_outbox = NULL;
1607 TnyFolder *per_account_outbox = NULL;
1608 ModestTnyAccountStorePrivate *priv = NULL;
1610 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1612 /* Create per account local outbox */
1614 modest_tny_account_new_for_per_account_local_outbox_folder (priv->account_mgr,
1617 tny_list_append (priv->store_accounts_outboxes, G_OBJECT (account_outbox));
1619 /* Get the outbox folder */
1620 folders = tny_simple_list_new ();
1621 tny_folder_store_get_folders (TNY_FOLDER_STORE (account_outbox), folders, NULL, NULL);
1622 if (tny_list_get_length (folders) != 1) {
1623 g_warning ("%s: > 1 outbox found (%d)?!", __FUNCTION__,
1624 tny_list_get_length (folders));
1627 iter_folders = tny_list_create_iterator (folders);
1628 per_account_outbox = TNY_FOLDER (tny_iterator_get_current (iter_folders));
1629 g_object_unref (iter_folders);
1630 g_object_unref (folders);
1631 g_object_unref (account_outbox);
1633 /* Add the outbox of the new per-account-local-outbox account
1634 to the global local merged OUTBOX of the local folders
1636 local_account = modest_tny_account_store_get_local_folders_account (self);
1637 modest_tny_local_folders_account_add_folder_to_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1638 per_account_outbox);
1639 /* Add the pair to the hash table */
1640 g_hash_table_insert (priv->outbox_of_transport,
1642 per_account_outbox);
1644 g_object_unref (local_account);
1645 g_object_unref (per_account_outbox);
1649 * This function will be used for both adding new accounts and for the
1650 * initialization. In the initialization we do not want to emit
1651 * signals so notify will be FALSE, in the case of account additions
1652 * we do want to notify the observers
1655 insert_account (ModestTnyAccountStore *self,
1656 const gchar *account,
1659 ModestTnyAccountStorePrivate *priv = NULL;
1660 TnyAccount *store_account = NULL, *transport_account = NULL;
1662 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1664 /* Get the server and the transport account */
1665 store_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_STORE, notify);
1666 if (!store_account || !TNY_IS_ACCOUNT(store_account)) {
1667 g_warning ("%s: failed to create store account", __FUNCTION__);
1671 transport_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT, notify);
1672 if (!transport_account || !TNY_IS_ACCOUNT(transport_account)) {
1673 g_warning ("%s: failed to create transport account", __FUNCTION__);
1674 g_object_unref (store_account);
1678 /* Add accounts to the lists */
1679 tny_list_append (priv->store_accounts, G_OBJECT (store_account));
1680 tny_list_append (priv->transport_accounts, G_OBJECT (transport_account));
1682 /* Create a new pseudo-account with an outbox for this
1683 transport account and add it to the global outbox
1684 in the local account */
1685 add_outbox_from_transport_account_to_global_outbox (self, account, transport_account);
1687 /* Notify the observers. We do it after everything is
1690 TnyAccount *local_account = NULL;
1692 /* Notify the observers about the new server & transport accounts */
1693 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, store_account);
1694 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, transport_account);
1696 /* Notify that the local account changed */
1697 local_account = modest_tny_account_store_get_local_folders_account (self);
1698 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1699 g_object_unref (local_account);
1703 g_object_unref (store_account);
1704 g_object_unref (transport_account);
1708 on_account_inserted (ModestAccountMgr *acc_mgr,
1709 const gchar *account,
1712 /* Insert the account and notify the observers */
1713 insert_account (MODEST_TNY_ACCOUNT_STORE (user_data), account, TRUE);
1716 /* This is the callback of the tny_camel_account_set_online called in
1717 on_account_removed to disconnect the account */
1719 on_account_disconnect_when_removing (TnyCamelAccount *account,
1724 ModestTnyAccountStore *self;
1725 ModestTnyAccountStorePrivate *priv;
1727 self = MODEST_TNY_ACCOUNT_STORE (user_data);
1728 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1730 /* Remove the connection-status-changed handler if it's still there */
1731 if (modest_signal_mgr_is_connected (priv->sighandlers,
1733 "connection_status_changed")) {
1734 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
1736 "connection_status_changed");
1739 /* Cancel all pending operations */
1740 tny_account_cancel (TNY_ACCOUNT (account));
1742 /* Unref the extra reference added by get_server_account */
1743 g_object_unref (account);
1745 /* Clear the cache if it's an store account */
1746 if (TNY_IS_STORE_ACCOUNT (account))
1747 tny_store_account_delete_cache (TNY_STORE_ACCOUNT (account));
1751 on_account_removed (ModestAccountMgr *acc_mgr,
1752 const gchar *account,
1755 TnyAccount *store_account = NULL, *transport_account = NULL;
1756 ModestTnyAccountStore *self;
1757 ModestTnyAccountStorePrivate *priv;
1759 self = MODEST_TNY_ACCOUNT_STORE (user_data);
1760 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1762 /* Get the server and the transport account */
1764 modest_tny_account_store_get_server_account (self, account, TNY_ACCOUNT_TYPE_STORE);
1766 modest_tny_account_store_get_server_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT);
1768 /* If there was any problem creating the account, for example,
1769 with the configuration system this could not exist */
1770 if (store_account) {
1771 /* Forget any cached password for the account */
1772 forget_password_in_memory (self, tny_account_get_id (store_account));
1774 /* Remove it from the list of accounts and notify the
1775 observers. Do not need to wait for account
1777 tny_list_remove (priv->store_accounts, (GObject *) store_account);
1778 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 0, store_account);
1780 /* Cancel all pending operations */
1781 tny_account_cancel (TNY_ACCOUNT (store_account));
1783 /* Disconnect before deleting the cache, because the
1784 disconnection will rewrite the cache to the
1786 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (store_account), FALSE,
1787 on_account_disconnect_when_removing, self);
1789 g_warning ("There is no store account for account %s\n", account);
1792 /* If there was any problem creating the account, for example,
1793 with the configuration system this could not exist */
1794 if (transport_account) {
1795 TnyAccount *local_account = NULL;
1796 TnyFolder *outbox = NULL;
1798 /* Forget any cached password for the account */
1799 forget_password_in_memory (self, tny_account_get_id (store_account));
1801 /* Remove it from the list of accounts and notify the
1802 observers. Do not need to wait for account
1804 tny_list_remove (priv->transport_accounts, (GObject *) transport_account);
1805 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 0, transport_account);
1807 /* Remove the OUTBOX of the account from the global outbox */
1808 outbox = g_hash_table_lookup (priv->outbox_of_transport, transport_account);
1810 if (TNY_IS_FOLDER (outbox)) {
1811 TnyAccount *outbox_account = tny_folder_get_account (outbox);
1813 if (outbox_account) {
1814 tny_list_remove (priv->store_accounts_outboxes, G_OBJECT (outbox_account));
1815 g_object_unref (outbox_account);
1818 local_account = modest_tny_account_store_get_local_folders_account (self);
1819 modest_tny_local_folders_account_remove_folder_from_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1821 g_hash_table_remove (priv->outbox_of_transport, transport_account);
1823 /* Notify the change in the local account */
1824 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1825 g_object_unref (local_account);
1827 g_warning ("Removing a transport account that has no outbox");
1830 /* Cancel all pending operations */
1831 tny_account_cancel (TNY_ACCOUNT (transport_account));
1833 /* Disconnect and notify the observers. The callback will free the reference */
1834 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (transport_account), FALSE,
1835 on_account_disconnect_when_removing, self);
1837 g_warning ("There is no transport account for account %s\n", account);
1841 TnyTransportAccount *
1842 modest_tny_account_store_new_connection_specific_transport_account (ModestTnyAccountStore *self,
1845 ModestTnyAccountStorePrivate *priv = NULL;
1846 TnyAccount * tny_account = NULL;
1848 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1850 /* Add the account: */
1852 modest_tny_account_new_from_server_account_name (priv->account_mgr,
1858 g_object_set_data (G_OBJECT(tny_account),
1862 tny_list_append (priv->transport_accounts, G_OBJECT (tny_account));
1863 add_outbox_from_transport_account_to_global_outbox (self,
1868 g_printerr ("modest: failed to create smtp-specific account for %s\n",
1871 return TNY_TRANSPORT_ACCOUNT (tny_account);
1876 add_connection_specific_transport_accounts (ModestTnyAccountStore *self)
1878 ModestTnyAccountStorePrivate *priv = NULL;
1879 GSList *list_specifics = NULL, *iter = NULL;
1881 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1883 ModestConf *conf = modest_runtime_get_conf ();
1886 list_specifics = modest_conf_get_list (conf,
1887 MODEST_CONF_CONNECTION_SPECIFIC_SMTP_LIST,
1888 MODEST_CONF_VALUE_STRING, &err);
1890 g_printerr ("modest: %s: error getting list: %s\n.", __FUNCTION__, err->message);
1895 /* Look at each connection-specific transport account for the
1896 * modest account: */
1897 iter = list_specifics;
1899 /* The list alternates between the connection name and the transport name: */
1900 iter = g_slist_next (iter);
1902 const gchar* transport_account_name = (const gchar*) (iter->data);
1903 TnyTransportAccount * account = NULL;
1904 account = modest_tny_account_store_new_connection_specific_transport_account (
1905 self, transport_account_name);
1907 g_object_unref (account);
1909 iter = g_slist_next (iter);
1914 modest_tny_account_store_find_msg_in_outboxes (ModestTnyAccountStore *self,
1916 TnyAccount **ac_out)
1918 TnyIterator *acc_iter;
1919 ModestTnyAccountStorePrivate *priv;
1921 TnyAccount *msg_account = NULL;
1923 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1924 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1926 acc_iter = tny_list_create_iterator (priv->store_accounts_outboxes);
1927 while (!msg && !tny_iterator_is_done (acc_iter)) {
1928 TnyList *folders = tny_simple_list_new ();
1929 TnyAccount *account = TNY_ACCOUNT (tny_iterator_get_current (acc_iter));
1930 TnyIterator *folders_iter = NULL;
1932 tny_folder_store_get_folders (TNY_FOLDER_STORE (account), folders, NULL, NULL);
1933 folders_iter = tny_list_create_iterator (folders);
1935 while (msg == NULL && !tny_iterator_is_done (folders_iter)) {
1936 TnyFolder *folder = TNY_FOLDER (tny_iterator_get_current (folders_iter));
1937 msg = tny_folder_find_msg (folder, uri, NULL);
1940 msg_account = g_object_ref (account);
1942 g_object_unref (folder);
1943 tny_iterator_next (folders_iter);
1945 g_object_unref (folders_iter);
1947 g_object_unref (folders);
1948 g_object_unref (account);
1949 tny_iterator_next (acc_iter);
1952 g_object_unref (acc_iter);
1955 *ac_out = msg_account;
1960 TnyTransportAccount *
1961 modest_tny_account_store_get_transport_account_from_outbox_header(ModestTnyAccountStore *self, TnyHeader *header)
1963 TnyIterator *acc_iter;
1964 ModestTnyAccountStorePrivate *priv;
1965 TnyTransportAccount *header_acc = NULL;
1966 const gchar *msg_id;
1968 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1969 g_return_val_if_fail (TNY_IS_HEADER (header), NULL);
1970 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1972 msg_id = modest_tny_send_queue_get_msg_id (header);
1973 acc_iter = tny_list_create_iterator (priv->transport_accounts);
1974 while (!header_acc && !tny_iterator_is_done (acc_iter)) {
1975 TnyTransportAccount *account = TNY_TRANSPORT_ACCOUNT (tny_iterator_get_current (acc_iter));
1976 ModestTnySendQueue *send_queue;
1977 ModestTnySendQueueStatus status;
1978 send_queue = modest_runtime_get_send_queue(TNY_TRANSPORT_ACCOUNT(account));
1979 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
1980 if (status != MODEST_TNY_SEND_QUEUE_UNKNOWN) {
1981 header_acc = g_object_ref(account);
1983 g_object_unref (account);
1984 tny_iterator_next (acc_iter);
1986 g_object_unref(acc_iter);
1993 modest_tny_account_store_show_account_settings_dialog (ModestTnyAccountStore *self,
1994 const gchar *account_name)
1996 ModestTnyAccountStorePrivate *priv;
1997 gpointer dialog_as_gpointer = NULL;
2000 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
2001 found = g_hash_table_lookup_extended (priv->account_settings_dialog_hash,
2002 account_name, NULL, (gpointer*)&dialog_as_gpointer);
2005 return (GtkWidget *) dialog_as_gpointer;
2007 ModestAccountSettings *settings;
2009 dialog = (GtkWidget *) modest_account_settings_dialog_new ();
2010 settings = modest_account_mgr_load_account_settings (priv->account_mgr, account_name);
2011 modest_account_settings_dialog_set_account (MODEST_ACCOUNT_SETTINGS_DIALOG (dialog), settings);
2012 g_object_unref (settings);
2013 modest_account_settings_dialog_switch_to_user_info (MODEST_ACCOUNT_SETTINGS_DIALOG (dialog));
2014 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (), GTK_WINDOW (dialog));
2016 g_hash_table_insert (priv->account_settings_dialog_hash, g_strdup (account_name), dialog);
2018 g_signal_connect (G_OBJECT (dialog), "hide", G_CALLBACK (on_account_settings_hide),
2019 g_strdup (account_name));
2021 /* Show it and delete it when it closes: */
2022 g_signal_connect_swapped (dialog,
2024 G_CALLBACK (gtk_widget_destroy),
2026 gtk_widget_show (GTK_WIDGET (dialog));