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>
43 #include "modest-text-utils.h"
44 #include <modest-runtime.h>
45 #include <modest-marshal.h>
46 #include <modest-protocol-registry.h>
47 #include <modest-local-folder-info.h>
48 #include "modest-account-protocol.h"
49 #include <modest-tny-account.h>
50 #include <modest-tny-local-folders-account.h>
51 #include <modest-account-mgr.h>
52 #include <modest-account-mgr-helpers.h>
53 #include <widgets/modest-window-mgr.h>
54 #include <modest-signal-mgr.h>
55 #include <modest-debug.h>
56 #include "modest-utils.h"
57 #include <modest-defs.h>
58 #include "modest-tny-account-store.h"
59 #include "modest-tny-platform-factory.h"
60 #include <tny-gtk-lockable.h>
61 #include <camel/camel.h>
62 #include <modest-platform.h>
63 #include "modest-ui-actions.h"
64 #include <widgets/modest-account-settings-dialog.h>
65 #include <tny-camel-bs-msg-receive-strategy.h>
66 #include <modest-tny-msg.h>
68 #ifdef MODEST_PLATFORM_MAEMO
69 #include <tny-maemo-conic-device.h>
72 #include <libgnomevfs/gnome-vfs-volume-monitor.h>
74 /* 'private'/'protected' functions */
75 static void modest_tny_account_store_class_init (ModestTnyAccountStoreClass *klass);
76 static void modest_tny_account_store_finalize (GObject *obj);
77 static void modest_tny_account_store_instance_init (ModestTnyAccountStore *obj);
78 static void modest_tny_account_store_init (gpointer g, gpointer iface_data);
79 static void modest_tny_account_store_base_init (gpointer g_class);
81 static void on_account_inserted (ModestAccountMgr *acc_mgr,
85 static void add_existing_accounts (ModestTnyAccountStore *self);
87 static void insert_account (ModestTnyAccountStore *self,
91 static void on_account_removed (ModestAccountMgr *acc_mgr,
95 static gchar* get_password (TnyAccount *account,
96 const gchar * prompt_not_used,
99 static void forget_password (TnyAccount *account);
101 static void on_vfs_volume_mounted (GnomeVFSVolumeMonitor *volume_monitor,
102 GnomeVFSVolume *volume,
105 static void on_vfs_volume_unmounted (GnomeVFSVolumeMonitor *volume_monitor,
106 GnomeVFSVolume *volume,
109 static void add_connection_specific_transport_accounts (ModestTnyAccountStore *self);
111 static void remove_connection_specific_transport_accounts (ModestTnyAccountStore *self);
113 static inline gboolean only_local_accounts (ModestTnyAccountStore *self);
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 ModestAccountMgr *account_mgr;
130 TnySessionCamel *session;
135 /* We cache the lists of accounts here */
136 TnyList *store_accounts;
137 TnyList *transport_accounts;
138 TnyList *store_accounts_outboxes;
140 /* Matches transport accounts and outbox folder */
141 GHashTable *outbox_of_transport;
143 /* is sending mail blocked? */
144 gboolean send_mail_blocked;
147 #define MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
148 MODEST_TYPE_TNY_ACCOUNT_STORE, \
149 ModestTnyAccountStorePrivate))
152 static GObjectClass *parent_class = NULL;
154 static guint signals[LAST_SIGNAL] = {0};
157 modest_tny_account_store_get_type (void)
159 static GType my_type = 0;
162 static const GTypeInfo my_info = {
163 sizeof(ModestTnyAccountStoreClass),
164 modest_tny_account_store_base_init, /* base init */
165 NULL, /* base finalize */
166 (GClassInitFunc) modest_tny_account_store_class_init,
167 NULL, /* class finalize */
168 NULL, /* class data */
169 sizeof(ModestTnyAccountStore),
171 (GInstanceInitFunc) modest_tny_account_store_instance_init,
175 static const GInterfaceInfo iface_info = {
176 (GInterfaceInitFunc) modest_tny_account_store_init,
177 NULL, /* interface_finalize */
178 NULL /* interface_data */
181 my_type = g_type_register_static (G_TYPE_OBJECT,
182 "ModestTnyAccountStore",
184 g_type_add_interface_static (my_type, TNY_TYPE_ACCOUNT_STORE,
192 modest_tny_account_store_base_init (gpointer g_class)
194 static gboolean tny_account_store_initialized = FALSE;
196 if (!tny_account_store_initialized) {
198 signals[ACCOUNT_CHANGED_SIGNAL] =
199 g_signal_new ("account_changed",
200 MODEST_TYPE_TNY_ACCOUNT_STORE,
202 G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_changed),
204 g_cclosure_marshal_VOID__OBJECT,
205 G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
207 signals[ACCOUNT_INSERTED_SIGNAL] =
208 g_signal_new ("account_inserted",
209 MODEST_TYPE_TNY_ACCOUNT_STORE,
211 G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_inserted),
213 g_cclosure_marshal_VOID__OBJECT,
214 G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
216 signals[ACCOUNT_REMOVED_SIGNAL] =
217 g_signal_new ("account_removed",
218 MODEST_TYPE_TNY_ACCOUNT_STORE,
220 G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_removed),
222 g_cclosure_marshal_VOID__OBJECT,
223 G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
225 signals[PASSWORD_REQUESTED_SIGNAL] =
226 g_signal_new ("password_requested",
227 MODEST_TYPE_TNY_ACCOUNT_STORE,
229 G_STRUCT_OFFSET(ModestTnyAccountStoreClass, password_requested),
231 modest_marshal_VOID__STRING_POINTER_POINTER_POINTER_POINTER,
232 G_TYPE_NONE, 5, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER,
235 tny_account_store_initialized = TRUE;
241 modest_tny_account_store_class_init (ModestTnyAccountStoreClass *klass)
243 GObjectClass *gobject_class;
244 gobject_class = (GObjectClass*) klass;
246 parent_class = g_type_class_peek_parent (klass);
247 gobject_class->finalize = modest_tny_account_store_finalize;
249 g_type_class_add_private (gobject_class,
250 sizeof(ModestTnyAccountStorePrivate));
254 modest_tny_account_store_instance_init (ModestTnyAccountStore *obj)
256 ModestTnyAccountStorePrivate *priv;
258 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
260 priv->cache_dir = NULL;
261 priv->account_mgr = NULL;
262 priv->session = NULL;
264 priv->sighandlers = NULL;
265 priv->send_mail_blocked = FALSE;
267 priv->outbox_of_transport = g_hash_table_new_full (g_direct_hash,
272 /* An in-memory store of passwords,
273 * for passwords that are not remembered in the configuration,
274 * so they need to be asked for from the user once in each session:
276 priv->password_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
280 /* disconnect the list of TnyAccounts */
282 account_verify_last_ref (TnyAccount *account, const gchar *str)
286 g_return_if_fail (account && TNY_IS_ACCOUNT(account));
288 txt = g_strdup_printf ("%s: %s", str ? str : "?", tny_account_get_name(account));
289 MODEST_DEBUG_VERIFY_OBJECT_LAST_REF(G_OBJECT(account),txt);
294 foreach_account_append_to_list (gpointer data,
299 list = TNY_LIST (user_data);
300 tny_list_append (list, G_OBJECT (data));
303 /********************************************************************/
304 /* Control the state of the MMC local account */
305 /********************************************************************/
307 /** Only call this if the memory card is really mounted.
310 add_mmc_account(ModestTnyAccountStore *self, gboolean emit_insert_signal)
312 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
313 g_return_if_fail (priv->session);
315 TnyAccount *mmc_account = modest_tny_account_new_for_local_folders (priv->account_mgr,
317 g_getenv (MODEST_MMC1_VOLUMEPATH_ENV));
319 /* Add to the list of store accounts */
320 tny_list_append (priv->store_accounts, G_OBJECT (mmc_account));
322 if (emit_insert_signal) {
323 g_signal_emit (G_OBJECT (self),
324 signals [ACCOUNT_INSERTED_SIGNAL],
329 g_object_unref (mmc_account);
333 on_vfs_volume_mounted(GnomeVFSVolumeMonitor *volume_monitor,
334 GnomeVFSVolume *volume,
337 ModestTnyAccountStore *self;
338 ModestTnyAccountStorePrivate *priv;
339 gchar *volume_path_uri;
343 self = MODEST_TNY_ACCOUNT_STORE(user_data);
344 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
346 /* Check whether this was the external MMC1 card: */
347 uri = gnome_vfs_volume_get_activation_uri (volume);
349 volume_path_uri = g_strconcat (MODEST_MMC1_VOLUMEPATH_URI_PREFIX,
350 g_getenv (MODEST_MMC1_VOLUMEPATH_ENV),
352 if (uri && (!strcmp (uri, volume_path_uri))) {
353 add_mmc_account (self, TRUE /* emit the insert signal. */);
356 g_free (volume_path_uri);
361 on_vfs_volume_unmounted(GnomeVFSVolumeMonitor *volume_monitor,
362 GnomeVFSVolume *volume,
365 ModestTnyAccountStore *self;
366 ModestTnyAccountStorePrivate *priv;
368 gchar *volume_path_uri;
370 self = MODEST_TNY_ACCOUNT_STORE(user_data);
371 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
373 /* Check whether this was the external MMC1 card: */
374 uri = gnome_vfs_volume_get_activation_uri (volume);
375 volume_path_uri = g_strconcat (MODEST_MMC1_VOLUMEPATH_URI_PREFIX,
376 g_getenv (MODEST_MMC1_VOLUMEPATH_ENV),
378 if (uri && (strcmp (uri, volume_path_uri) == 0)) {
379 TnyAccount *mmc_account = NULL;
380 gboolean found = FALSE;
381 TnyIterator *iter = NULL;
383 iter = tny_list_create_iterator (priv->store_accounts);
384 while (!tny_iterator_is_done (iter) && !found) {
387 account = TNY_ACCOUNT (tny_iterator_get_current (iter));
388 if (modest_tny_account_is_memory_card_account (account)) {
390 mmc_account = g_object_ref (account);
392 g_object_unref (account);
393 tny_iterator_next (iter);
395 g_object_unref (iter);
398 /* Remove from the list */
399 tny_list_remove (priv->store_accounts, G_OBJECT (mmc_account));
401 /* Notify observers */
402 g_signal_emit (G_OBJECT (self),
403 signals [ACCOUNT_REMOVED_SIGNAL],
406 g_object_unref (mmc_account);
408 g_debug ("%s: there was no store account for the unmounted MMC",
412 g_free (volume_path_uri);
417 modest_tny_account_store_forget_password_in_memory (ModestTnyAccountStore *self,
418 const gchar * server_account_name)
420 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
422 if (server_account_name && priv->password_hash)
423 g_hash_table_remove (priv->password_hash, server_account_name);
427 on_account_changed (ModestAccountMgr *acc_mgr,
428 const gchar *account_name,
429 TnyAccountType account_type,
432 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(user_data);
433 ModestTnyAccountStorePrivate *priv;
434 TnyList* account_list;
435 gboolean found = FALSE;
436 TnyIterator *iter = NULL;
438 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
439 account_list = (account_type == TNY_ACCOUNT_TYPE_STORE ?
440 priv->store_accounts :
441 priv->transport_accounts);
443 iter = tny_list_create_iterator (account_list);
444 while (!tny_iterator_is_done (iter) && !found) {
445 TnyAccount *tny_account;
446 tny_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
448 if (!strcmp (tny_account_get_id (tny_account), account_name)) {
450 modest_tny_account_update_from_account (tny_account, get_password, forget_password);
451 g_signal_emit (G_OBJECT(self), signals[ACCOUNT_CHANGED_SIGNAL], 0, tny_account);
453 g_object_unref (tny_account);
455 tny_iterator_next (iter);
457 g_object_unref (iter);
461 show_wrong_password_dialog (TnyAccountStore *self,
463 gboolean show_banner)
468 g_debug ("%s: %s", __FUNCTION__, tny_account_get_id (account));
470 device = tny_account_store_get_device (self);
471 is_online = tny_device_is_online (device);
472 g_object_unref (device);
475 g_debug ("%s: not showing the acc settings dialog. Device OFFLINE", __FUNCTION__);
479 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()) == 0) {
480 g_debug ("%s: not showing the account settings dialog. NO windows", __FUNCTION__);
484 if (g_object_get_data (G_OBJECT (account), "connection_specific") != NULL) {
485 modest_ui_actions_on_smtp_servers (NULL, NULL);
487 ModestAccountProtocol *proto;
488 ModestProtocolType proto_type;
489 const gchar *modest_account_name;
490 modest_account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
493 proto_type = modest_account_mgr_get_store_protocol (modest_runtime_get_account_mgr (),
494 modest_account_name);
495 proto = (ModestAccountProtocol *)
496 modest_protocol_registry_get_protocol_by_type (modest_runtime_get_protocol_registry (),
499 /* Create and show the dialog */
500 if (proto && MODEST_IS_ACCOUNT_PROTOCOL (proto)) {
501 ModestAccountSettingsDialog *dialog =
502 modest_account_protocol_get_account_settings_dialog (proto, modest_account_name);
505 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
506 GtkWindow *parent = modest_window_mgr_get_modal (mgr);
508 parent = (GtkWindow *) modest_window_mgr_get_current_top (mgr);
510 modest_window_mgr_set_modal (mgr, GTK_WINDOW (dialog), parent);
511 gtk_widget_show (GTK_WIDGET (dialog));
515 /* Show an explanatory temporary banner: */
517 modest_platform_information_banner (NULL, NULL, _("mcen_ib_username_pw_incorrect"));
520 /* This callback will be called by Tinymail when it needs the password
521 * from the user or the account settings.
522 * It can also call forget_password() before calling this,
523 * so that we clear wrong passwords out of our account settings.
524 * Note that TnyAccount here will be the server account. */
526 get_password (TnyAccount *account, const gchar * prompt_not_used, gboolean *cancel)
528 ModestTnyAccountStore *self = NULL;
529 ModestTnyAccountStorePrivate *priv;
530 gchar *username = NULL;
533 gboolean already_asked = FALSE;
534 const gchar *server_account_name;
537 g_return_val_if_fail (account, NULL);
539 g_debug ("%s: %s", __FUNCTION__, prompt_not_used);
541 /* Get a reference to myself */
542 self = MODEST_TNY_ACCOUNT_STORE (g_object_get_data (G_OBJECT(account), "account_store"));
543 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
545 /* Ensure that we still have this account. It could happen
546 that a set_online was requested *before* removing an
547 account, and due to tinymail emits the get_password
548 function using a g_idle the account could be actually
549 removed *before* this function was really called */
550 url_string = tny_account_get_url_string (account);
552 TnyAccount *tmp_account;
554 tmp_account = tny_account_store_find_account (TNY_ACCOUNT_STORE (self),
562 g_object_unref (tmp_account);
565 server_account_name = tny_account_get_id (account);
566 if (!server_account_name || !self) {
567 g_warning ("%s: could not retrieve account_store for account %s",
568 __FUNCTION__, server_account_name ? server_account_name : "<NULL>");
575 /* We need to do this to avoid "dereferencing type-punned pointer will break strict-aliasing rules" */
576 pwd_ptr = (gpointer) &pwd;
578 /* This hash map stores passwords, including passwords that are not stored in gconf. */
579 /* Is it in the hash? if it's already there, it must be wrong... */
580 already_asked = priv->password_hash && g_hash_table_lookup_extended (priv->password_hash,
585 /* If the password is not already there, try ModestConf */
586 if (!already_asked) {
587 pwd = modest_account_mgr_get_server_account_password (priv->account_mgr,
588 server_account_name);
589 g_hash_table_insert (priv->password_hash, g_strdup (server_account_name), g_strdup (pwd));
591 /* We need to get it again because forget_password has cleared it */
592 pwd = modest_account_mgr_get_server_account_password (priv->account_mgr, server_account_name);
595 /* This is horrible but we need it until we don't get a proper
596 fix into tinymail. Thing is that tinymail incorrectly asks
597 for password when the connection to the server failed due a
598 timeout (slow network connection, firewalls...). In those
599 cases it makes no sense to ask the user. It's better just
601 if (g_strstr_len (prompt_not_used, -1, "Connection timed out")) {
602 g_debug ("%s, Incorrect get_password with connection issue", __FUNCTION__);
603 modest_tny_account_store_forget_password_in_memory (self, tny_account_get_id (account));
609 /* If it was already asked, it must have been wrong, so ask again */
610 if (already_asked || !pwd || strlen(pwd) == 0) {
611 gboolean settings_have_password;
612 ModestProtocolType protocol_type;
614 /* As per the UI spec, if no password was set in the account settings,
615 * ask for it now. But if the password is wrong in the account settings,
616 * then show a banner and the account settings dialog so it can be corrected:
618 settings_have_password =
619 modest_account_mgr_get_server_account_has_password (priv->account_mgr, server_account_name);
621 protocol_type = modest_tny_account_get_protocol_type (account);
623 /* Show an error and after that ask for a password */
624 if (modest_protocol_registry_protocol_type_has_tag(modest_runtime_get_protocol_registry (),
625 protocol_type, MODEST_PROTOCOL_REGISTRY_TRANSPORT_PROTOCOLS)) {
626 gchar *username = NULL, *msg = NULL;
627 username = modest_account_mgr_get_server_account_username (priv->account_mgr,
628 server_account_name);
629 if (!username || strlen(username) == 0) {
630 msg = g_strdup_printf (_("emev_ni_ui_smtp_userid_invalid"),
631 tny_account_get_name (account),
632 tny_account_get_hostname (account));
635 password = modest_account_mgr_get_server_account_password (priv->account_mgr,
636 server_account_name);
638 if (!password || strlen(password) == 0) {
639 msg = g_strdup_printf (_("emev_ni_ui_smtp_passwd_invalid"),
640 tny_account_get_name (account),
641 tny_account_get_hostname (account));
643 msg = g_strdup_printf (_("emev_ni_ui_smtp_authentication_fail_error"),
644 tny_account_get_hostname (account));
650 modest_platform_run_information_dialog (NULL, msg, TRUE);
658 gboolean username_known =
659 modest_account_mgr_get_server_account_username_has_succeeded(priv->account_mgr,
660 server_account_name);
661 /* If the login has ever succeeded then show a specific message */
663 msg = _CS_SET_PASSWORD_INCORRECT;
665 msg = _("mcen_ib_username_pw_incorrect");
666 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()))
667 modest_platform_information_banner (NULL, NULL, msg);
671 if (settings_have_password) {
673 /* The password must be wrong, so show
674 the account settings dialog so it
676 g_debug ("%s: going to show the settings dialog", __FUNCTION__);
677 show_wrong_password_dialog ((TnyAccountStore *) self, account, TRUE);
684 /* Get the password from the account settings */
685 return modest_account_mgr_get_server_account_password (priv->account_mgr,
686 server_account_name);
690 /* we don't have it yet. Get the password from the user */
692 const gchar* account_id = tny_account_get_id (account);
693 gboolean remember = FALSE;
694 g_signal_emit (G_OBJECT (self), signals[PASSWORD_REQUESTED_SIGNAL], 0,
695 account_id, /* server_account_name */
696 &username, &pwd, cancel, &remember);
699 g_hash_table_remove (priv->password_hash, server_account_name);
714 modest_tny_account_store_forget_already_asked (ModestTnyAccountStore *self, TnyAccount *account)
716 g_return_if_fail (account);
718 ModestTnyAccountStorePrivate *priv;
720 gpointer pwd_ptr = NULL;
721 gboolean already_asked = FALSE;
723 const gchar *server_account_name = tny_account_get_id (account);
725 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
727 /* This hash map stores passwords, including passwords that are not stored in gconf. */
728 pwd_ptr = (gpointer)&pwd; /* pwd_ptr so the compiler does not complained about
729 * type-punned ptrs...*/
730 already_asked = priv->password_hash &&
731 g_hash_table_lookup_extended (priv->password_hash,
734 (gpointer*)&pwd_ptr);
737 g_hash_table_remove (priv->password_hash, server_account_name);
745 /* tinymail calls this if the connection failed due to an incorrect password.
746 * And it seems to call this for any general connection failure. */
748 forget_password (TnyAccount *account)
750 ModestTnyAccountStore *self;
751 ModestTnyAccountStorePrivate *priv;
752 const TnyAccountStore *account_store;
756 account_store = TNY_ACCOUNT_STORE(g_object_get_data (G_OBJECT(account),
758 self = MODEST_TNY_ACCOUNT_STORE (account_store);
759 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
760 key = tny_account_get_id (account);
762 /* Do not remove the key, this will allow us to detect that we
763 have already asked for it at least once */
764 pwd = g_hash_table_lookup (priv->password_hash, key);
766 g_debug ("%s, forgetting %s for account %s", __FUNCTION__, pwd, key);
767 memset (pwd, 0, strlen (pwd));
768 g_hash_table_insert (priv->password_hash, g_strdup (key), NULL);
773 modest_tny_account_store_finalize (GObject *obj)
775 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(obj);
776 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
778 g_free (priv->cache_dir);
779 priv->cache_dir = NULL;
781 if (priv->password_hash) {
782 g_hash_table_destroy (priv->password_hash);
783 priv->password_hash = NULL;
786 if (priv->outbox_of_transport) {
787 g_hash_table_destroy (priv->outbox_of_transport);
788 priv->outbox_of_transport = NULL;
791 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
792 priv->sighandlers = NULL;
794 if (priv->account_mgr) {
795 g_object_unref (G_OBJECT(priv->account_mgr));
796 priv->account_mgr = NULL;
800 g_object_unref (G_OBJECT(priv->device));
804 /* Destroy all accounts. Disconnect all accounts before they are destroyed */
805 if (priv->store_accounts) {
806 tny_list_foreach (priv->store_accounts, (GFunc)account_verify_last_ref, "store");
807 g_object_unref (priv->store_accounts);
808 priv->store_accounts = NULL;
811 if (priv->transport_accounts) {
812 tny_list_foreach (priv->transport_accounts, (GFunc)account_verify_last_ref, "transport");
813 g_object_unref (priv->transport_accounts);
814 priv->transport_accounts = NULL;
817 if (priv->store_accounts_outboxes) {
818 g_object_unref (priv->store_accounts_outboxes);
819 priv->store_accounts_outboxes = NULL;
823 camel_object_unref (CAMEL_OBJECT(priv->session));
824 priv->session = NULL;
827 G_OBJECT_CLASS(parent_class)->finalize (obj);
831 volume_path_is_mounted (const gchar* path)
833 g_return_val_if_fail (path, FALSE);
835 gboolean result = FALSE;
836 gchar * path_as_uri = g_filename_to_uri (path, NULL, NULL);
837 g_return_val_if_fail (path_as_uri, FALSE);
839 /* Get the monitor singleton: */
840 GnomeVFSVolumeMonitor *monitor = gnome_vfs_get_volume_monitor();
842 /* This seems like a simpler way to do this, but it returns a
843 * GnomeVFSVolume even if the drive is not mounted: */
845 GnomeVFSVolume *volume = gnome_vfs_volume_monitor_get_volume_for_path (monitor,
846 g_getenv (MODEST_MMC1_VOLUMEPATH_ENV));
848 gnome_vfs_volume_unref(volume);
852 /* Get the mounted volumes from the monitor: */
853 GList *list = gnome_vfs_volume_monitor_get_mounted_volumes (monitor);
855 for (iter = list; iter; iter = g_list_next (iter)) {
856 GnomeVFSVolume *volume = (GnomeVFSVolume*)iter->data;
860 gnome_vfs_volume_get_display_name (volume);
861 printf ("volume display name=%s\n", display_name);
862 g_free (display_name);
866 gnome_vfs_volume_get_activation_uri (volume);
867 /* printf (" uri=%s\n", uri); */
868 if (uri && (strcmp (uri, path_as_uri) == 0))
873 gnome_vfs_volume_unref (volume);
879 g_free (path_as_uri);
884 static void _bodies_filter (TnyMsg *msg, TnyList *list)
886 TnyMimePart *html_part, *text_part;
888 html_part = modest_tny_msg_find_body_part (msg, TRUE);
889 text_part = modest_tny_msg_find_body_part (msg, FALSE);
891 if (text_part && TNY_IS_MIME_PART (text_part) && html_part == text_part) {
892 g_object_unref (text_part);
896 if (html_part && TNY_IS_MIME_PART (html_part)) {
897 tny_list_prepend (list, G_OBJECT (html_part));
898 g_object_unref (html_part);
901 if (text_part && TNY_IS_MIME_PART (text_part)) {
902 tny_list_prepend (list, G_OBJECT (text_part));
903 g_object_unref (text_part);
908 ModestTnyAccountStore*
909 modest_tny_account_store_new (ModestAccountMgr *account_mgr,
913 ModestTnyAccountStorePrivate *priv;
914 TnyAccount *local_account = NULL;
915 TnyLockable *lockable;
916 GnomeVFSVolumeMonitor* monitor = NULL;
917 gboolean auto_update;
918 const gchar *mmc_path = NULL;
920 g_return_val_if_fail (account_mgr, NULL);
921 g_return_val_if_fail (device, NULL);
923 tny_camel_bs_msg_receive_strategy_set_global_bodies_filter (
924 (TnyCamelBsMsgReceiveStrategyBodiesFilter) _bodies_filter);
926 obj = G_OBJECT(g_object_new(MODEST_TYPE_TNY_ACCOUNT_STORE, NULL));
927 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
929 priv->account_mgr = g_object_ref (G_OBJECT(account_mgr));
930 priv->device = g_object_ref (device);
932 /* If autoupdate is off then we don't try to connect to the
933 accounts when they're added to the account store*/
934 auto_update = modest_conf_get_bool (modest_runtime_get_conf (),
935 MODEST_CONF_AUTO_UPDATE, NULL);
937 tny_device_force_offline (priv->device);
939 priv->session = tny_session_camel_new (TNY_ACCOUNT_STORE(obj));
940 if (!priv->session) {
941 g_warning ("failed to get TnySessionCamel");
945 /* Set the ui locker */
946 lockable = tny_gtk_lockable_new ();
947 tny_session_camel_set_ui_locker (priv->session, lockable);
948 g_object_unref (lockable);
950 /* Connect signals */
951 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
952 G_OBJECT(account_mgr), "account_inserted",
953 G_CALLBACK (on_account_inserted), obj);
954 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
955 G_OBJECT(account_mgr), "account_changed",
956 G_CALLBACK (on_account_changed), obj);
957 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
958 G_OBJECT(account_mgr), "account_removed",
959 G_CALLBACK (on_account_removed), obj);
961 /* Respond to volume mounts and unmounts, such as the
962 insertion/removal of the memory card. This is a singleton,
963 so it does not need to be unrefed */
964 monitor = gnome_vfs_get_volume_monitor();
965 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
968 G_CALLBACK(on_vfs_volume_mounted),
970 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
971 G_OBJECT(monitor), "volume-unmounted",
972 G_CALLBACK(on_vfs_volume_unmounted),
975 /* Create the lists of accounts */
976 priv->store_accounts = tny_simple_list_new ();
977 priv->transport_accounts = tny_simple_list_new ();
978 priv->store_accounts_outboxes = tny_simple_list_new ();
980 /* Create the local folders account */
982 modest_tny_account_new_for_local_folders (priv->account_mgr, priv->session, NULL);
983 tny_list_append (priv->store_accounts, G_OBJECT(local_account));
984 g_object_unref (local_account);
986 /* Add the other remote accounts. Do this after adding the
987 local account, because we need to add our outboxes to the
988 global OUTBOX hosted in the local account */
989 add_existing_accounts (MODEST_TNY_ACCOUNT_STORE (obj));
991 /* Add connection-specific transport accounts if there are any
992 accounts available */
993 if (!only_local_accounts (MODEST_TNY_ACCOUNT_STORE(obj)))
994 add_connection_specific_transport_accounts (MODEST_TNY_ACCOUNT_STORE(obj));
996 /* This is a singleton, so it does not need to be unrefed. */
997 mmc_path = g_getenv (MODEST_MMC1_VOLUMEPATH_ENV);
998 if (mmc_path && volume_path_is_mounted (mmc_path)) {
1000 add_mmc_account (MODEST_TNY_ACCOUNT_STORE (obj), FALSE /* don't emit the insert signal. */);
1003 /* Initialize session */
1004 tny_session_camel_set_initialized (priv->session);
1006 return MODEST_TNY_ACCOUNT_STORE(obj);
1010 modest_tny_account_store_get_accounts (TnyAccountStore *self,
1012 TnyGetAccountsRequestType request_type)
1014 ModestTnyAccountStorePrivate *priv;
1016 g_return_if_fail (self);
1017 g_return_if_fail (TNY_IS_LIST(list));
1019 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1021 switch (request_type) {
1022 case TNY_ACCOUNT_STORE_BOTH:
1023 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
1024 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
1026 case TNY_ACCOUNT_STORE_STORE_ACCOUNTS:
1027 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
1029 case TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS:
1030 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
1033 g_return_if_reached ();
1039 modest_tny_account_store_get_cache_dir (TnyAccountStore *self)
1041 ModestTnyAccountStorePrivate *priv;
1042 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1044 if (!priv->cache_dir)
1045 priv->cache_dir = g_build_filename (g_get_home_dir(),
1046 MODEST_DIR, MODEST_CACHE_DIR, NULL);
1047 return priv->cache_dir;
1052 * callers need to unref
1055 modest_tny_account_store_get_device (TnyAccountStore *self)
1057 ModestTnyAccountStorePrivate *priv;
1059 g_return_val_if_fail (self, NULL);
1061 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1064 return g_object_ref (G_OBJECT(priv->device));
1071 modest_tny_account_store_find_account_by_url (TnyAccountStore *self, const gchar* url_string)
1073 return modest_tny_account_store_get_tny_account_by (MODEST_TNY_ACCOUNT_STORE (self),
1074 MODEST_TNY_ACCOUNT_STORE_QUERY_URL,
1081 modest_tny_account_store_alert (TnyAccountStore *self,
1082 TnyAccount *account,
1087 ModestProtocolType protocol_type = MODEST_PROTOCOL_REGISTRY_TYPE_INVALID;
1088 ModestProtocol *protocol = NULL;
1089 const gchar* server_name = "";
1090 gchar *prompt = NULL;
1091 gboolean retval = TRUE;
1093 /* NOTE: account may be NULL in some cases */
1097 /* Get the server name: */
1099 server_name = tny_account_get_hostname (account);
1100 protocol_type = modest_tny_account_get_protocol_type (account);
1101 if (protocol_type == MODEST_PROTOCOL_REGISTRY_TYPE_INVALID){
1102 g_warning("%s: account with id=%s has no proto.\n", __FUNCTION__,
1103 tny_account_get_id (account));
1106 protocol = modest_protocol_registry_get_protocol_by_type (modest_runtime_get_protocol_registry (),
1110 switch (error->code) {
1111 case TNY_SYSTEM_ERROR_CANCEL:
1112 /* Don't show waste the user's time by showing him a dialog telling
1113 * him that he has just cancelled something: */
1116 case TNY_SERVICE_ERROR_PROTOCOL:
1117 /* Like a BAD from IMAP (protocol error) */
1118 case TNY_SERVICE_ERROR_LOST_CONNECTION:
1119 /* Lost the connection with the service */
1120 case TNY_SERVICE_ERROR_UNAVAILABLE:
1121 /* You must be working online for this operation */
1122 case TNY_SERVICE_ERROR_CONNECT:
1124 prompt = modest_protocol_get_translation (protocol, MODEST_PROTOCOL_TRANSLATION_CONNECT_ERROR, server_name);
1127 g_return_val_if_reached (FALSE);
1130 case TNY_SERVICE_ERROR_AUTHENTICATE:
1131 /* It seems that there's no better error to show with
1132 * POP and IMAP because TNY_SERVICE_ERROR_AUTHENTICATE
1133 * may appear if there's a timeout during auth */
1135 prompt = modest_protocol_get_translation (protocol, MODEST_PROTOCOL_TRANSLATION_AUTH_ERROR, server_name);
1138 g_return_val_if_reached (FALSE);
1141 case TNY_SERVICE_ERROR_CERTIFICATE:
1142 /* We'll show the proper dialog later */
1145 case TNY_SYSTEM_ERROR_MEMORY:
1146 /* Can't allocate memory for this operation */
1147 if (modest_tny_account_store_check_disk_full_error ((ModestTnyAccountStore*)self,
1148 NULL, error, account, NULL))
1151 case TNY_SERVICE_ERROR_UNKNOWN:
1154 /* We don't treat this as an error, but as a not handled message. Then,
1155 * debug message, and return false */
1156 g_debug ("Unexpected error %d (%s)", error->code, error->message);
1161 if (error->code == TNY_SERVICE_ERROR_CERTIFICATE)
1162 retval = modest_platform_run_certificate_confirmation_dialog (server_name,
1164 else if (error->code == TNY_SERVICE_ERROR_AUTHENTICATE ||
1165 error->code == TNY_SERVICE_ERROR_CONNECT) {
1166 TnyDevice *device = modest_runtime_get_device ();
1169 /* If we get the connection error after establishing a
1170 proper connection then do not show the dialog as we
1171 are probably behind a firewall, or in a network
1172 with connection issues. We just keep this code to
1173 detect situations were the user does not enter the
1174 server info properly */
1175 success = modest_account_mgr_get_server_account_username_has_succeeded (modest_runtime_get_account_mgr (),
1176 tny_account_get_id (account));
1179 gboolean show_banner;
1181 g_debug ("%s: %s alert received (%s)", __FUNCTION__,
1182 (error->code == TNY_SERVICE_ERROR_CONNECT) ? "connect" : "aunthenticate",
1185 if (tny_device_is_online (device) &&
1186 modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()))
1187 modest_platform_run_information_dialog (NULL, prompt, TRUE);
1189 /* Show the account dialog */
1190 show_banner = (error->code == TNY_SERVICE_ERROR_CONNECT) ? FALSE : TRUE;
1191 g_debug ("%s: going to show settings dialog", __FUNCTION__);
1192 show_wrong_password_dialog (self, account, show_banner);
1197 g_debug ("%s: error code %d (%s", __FUNCTION__, error->code, error->message);
1207 modest_tny_account_store_init (gpointer g, gpointer iface_data)
1209 TnyAccountStoreIface *klass;
1211 g_return_if_fail (g);
1213 klass = (TnyAccountStoreIface *)g;
1215 klass->get_accounts =
1216 modest_tny_account_store_get_accounts;
1217 klass->get_cache_dir =
1218 modest_tny_account_store_get_cache_dir;
1220 modest_tny_account_store_get_device;
1222 modest_tny_account_store_alert;
1223 klass->find_account =
1224 modest_tny_account_store_find_account_by_url;
1228 modest_tny_account_store_set_get_pass_func (ModestTnyAccountStore *self,
1229 ModestTnyGetPassFunc func)
1231 /* not implemented, we use signals */
1232 g_printerr ("modest: set_get_pass_func not implemented\n");
1236 modest_tny_account_store_get_session (TnyAccountStore *self)
1238 g_return_val_if_fail (self, NULL);
1239 return MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self)->session;
1243 get_tny_account_by (TnyList *accounts,
1244 ModestTnyAccountStoreQueryType type,
1247 TnyIterator *iter = NULL;
1248 gboolean found = FALSE;
1249 TnyAccount *retval = NULL;
1251 g_return_val_if_fail (TNY_IS_LIST(accounts), NULL);
1253 if (tny_list_get_length(accounts) == 0) {
1254 g_warning ("%s: account list is empty", __FUNCTION__);
1258 iter = tny_list_create_iterator (accounts);
1259 while (!tny_iterator_is_done (iter) && !found) {
1260 TnyAccount *tmp_account = NULL;
1261 const gchar *val = NULL;
1263 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1264 if (!TNY_IS_ACCOUNT(tmp_account)) {
1265 g_warning ("%s: not a valid account", __FUNCTION__);
1271 case MODEST_TNY_ACCOUNT_STORE_QUERY_ID:
1272 val = tny_account_get_id (tmp_account);
1274 case MODEST_TNY_ACCOUNT_STORE_QUERY_URL:
1275 val = tny_account_get_url_string (tmp_account);
1279 if (type == MODEST_TNY_ACCOUNT_STORE_QUERY_URL &&
1280 tny_account_matches_url_string (tmp_account, str)) {
1281 retval = g_object_ref (tmp_account);
1284 if (val && str && strcmp (val, str) == 0) {
1285 retval = g_object_ref (tmp_account);
1289 g_object_unref (tmp_account);
1290 tny_iterator_next (iter);
1292 g_object_unref (iter);
1298 modest_tny_account_store_get_tny_account_by (ModestTnyAccountStore *self,
1299 ModestTnyAccountStoreQueryType type,
1302 TnyAccount *account = NULL;
1303 ModestTnyAccountStorePrivate *priv;
1305 g_return_val_if_fail (self, NULL);
1306 g_return_val_if_fail (str, NULL);
1308 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1310 /* Search in store accounts */
1311 account = get_tny_account_by (priv->store_accounts, type, str);
1313 /* If we already found something, no need to search the transport accounts */
1315 account = get_tny_account_by (priv->transport_accounts, type, str);
1317 /* If we already found something, no need to search the
1318 per-account outbox accounts */
1320 account = get_tny_account_by (priv->store_accounts_outboxes, type, str);
1323 /* Warn if nothing was found. This is generally unusual. */
1325 g_warning("%s: Failed to find account with %s=%s\n",
1327 (type == MODEST_TNY_ACCOUNT_STORE_QUERY_ID) ? "ID" : "URL",
1331 /* Returns a new reference to the account if found */
1337 modest_tny_account_store_get_server_account (ModestTnyAccountStore *self,
1338 const gchar *account_name,
1339 TnyAccountType type)
1341 ModestTnyAccountStorePrivate *priv = NULL;
1342 TnyAccount *retval = NULL;
1343 TnyList *account_list = NULL;
1344 TnyIterator *iter = NULL;
1347 g_return_val_if_fail (self, NULL);
1348 g_return_val_if_fail (account_name, NULL);
1349 g_return_val_if_fail (type == TNY_ACCOUNT_TYPE_STORE ||
1350 type == TNY_ACCOUNT_TYPE_TRANSPORT,
1353 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1355 account_list = (type == TNY_ACCOUNT_TYPE_STORE) ?
1356 priv->store_accounts :
1357 priv->transport_accounts;
1359 if (!account_list) {
1360 g_printerr ("%s: No server accounts of type %s\n", __FUNCTION__,
1361 (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport");
1365 /* Look for the server account */
1367 iter = tny_list_create_iterator (account_list);
1368 while (!tny_iterator_is_done (iter) && !found) {
1369 const gchar *modest_acc_name;
1370 TnyAccount *tmp_account;
1372 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1374 modest_tny_account_get_parent_modest_account_name_for_server_account (tmp_account);
1376 if (account_name && modest_acc_name && !strcmp (account_name, modest_acc_name)) {
1378 retval = g_object_ref (tmp_account);
1380 /* Free and continue */
1381 g_object_unref (tmp_account);
1382 tny_iterator_next (iter);
1384 g_object_unref (iter);
1387 g_printerr ("modest: %s: could not get tny %s account for %s\n." \
1388 "Number of server accounts of this type=%d\n", __FUNCTION__,
1389 (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport",
1390 account_name, tny_list_get_length (account_list));
1393 /* Returns a new reference */
1398 modest_tny_account_store_get_smtp_specific_transport_account_for_open_connection (
1399 ModestTnyAccountStore *self, const gchar *account_name)
1403 g_return_val_if_fail (self && MODEST_IS_TNY_ACCOUNT_STORE(self), NULL);
1404 g_return_val_if_fail (account_name, NULL);
1406 /* Get the current connection: */
1407 device = modest_runtime_get_device ();
1410 g_warning ("%s: could not get device", __FUNCTION__);
1414 if (!tny_device_is_online (device))
1417 #ifdef MODEST_HAVE_CONIC
1418 g_return_val_if_fail (TNY_IS_MAEMO_CONIC_DEVICE (device), NULL);
1420 TnyMaemoConicDevice *maemo_device = TNY_MAEMO_CONIC_DEVICE (device);
1421 const gchar* iap_id = tny_maemo_conic_device_get_current_iap_id (maemo_device);
1422 /* printf ("DEBUG: %s: iap_id=%s\n", __FUNCTION__, iap_id); */
1426 ConIcIap* connection = tny_maemo_conic_device_get_iap (maemo_device, iap_id);
1430 const gchar *connection_id = con_ic_iap_get_id (connection);
1431 /* printf ("DEBUG: %s: connection_id=%s\n", __FUNCTION__, connection_id); */
1435 /* Get the connection-specific transport acccount, if any: */
1436 ModestAccountMgr *account_manager = modest_runtime_get_account_mgr ();
1438 /* Check if this account has connection-specific SMTP enabled */
1439 if (!modest_account_mgr_get_use_connection_specific_smtp (account_manager, account_name)) {
1443 gchar* server_account_name = modest_account_mgr_get_connection_specific_smtp (account_manager,
1446 /* printf ("DEBUG: %s: server_account_name=%s\n", __FUNCTION__, server_account_name); */
1447 if (!server_account_name) {
1448 return NULL; /* No connection-specific SMTP server was specified for this connection. */
1451 TnyAccount* account = modest_tny_account_store_get_tny_account_by (self,
1452 MODEST_TNY_ACCOUNT_STORE_QUERY_ID,
1453 server_account_name);
1455 /* printf ("DEBUG: %s: account=%p\n", __FUNCTION__, account); */
1456 g_free (server_account_name);
1458 /* Unref the get()ed object, as required by the tny_maemo_conic_device_get_iap() documentation. */
1459 g_object_unref (connection);
1463 return NULL; /* TODO: Implement this for GNOME, instead of just Maemo? */
1464 #endif /* MODEST_HAVE_CONIC */
1469 modest_tny_account_store_get_transport_account_for_open_connection (ModestTnyAccountStore *self,
1470 const gchar *account_name)
1472 g_return_val_if_fail (self, NULL);
1473 g_return_val_if_fail (account_name, NULL);
1475 if (!account_name || !self)
1478 /* Get the connection-specific transport acccount, if any: */
1479 /* Note: This gives us a reference: */
1480 TnyAccount *account =
1481 modest_tny_account_store_get_smtp_specific_transport_account_for_open_connection (self, account_name);
1483 /* If there is no connection-specific transport account (the common case),
1484 * just get the regular transport account: */
1486 /* The special local folders don't have transport accounts. */
1487 if (strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0)
1490 /* Note: This gives us a reference: */
1491 account = modest_tny_account_store_get_server_account (self, account_name,
1492 TNY_ACCOUNT_TYPE_TRANSPORT);
1496 /* returns a reference. */
1501 modest_tny_account_store_get_local_folders_account (ModestTnyAccountStore *self)
1503 TnyAccount *account = NULL;
1504 ModestTnyAccountStorePrivate *priv;
1508 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1510 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1513 iter = tny_list_create_iterator (priv->store_accounts);
1514 while (!tny_iterator_is_done (iter) && !found) {
1515 TnyAccount *tmp_account;
1517 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1518 if (modest_tny_account_is_virtual_local_folders (tmp_account)) {
1519 account = g_object_ref (tmp_account);
1522 g_object_unref (tmp_account);
1523 tny_iterator_next (iter);
1525 g_object_unref (iter);
1527 /* Returns a new reference to the account */
1532 modest_tny_account_store_get_mmc_folders_account (ModestTnyAccountStore *self)
1534 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1537 return modest_tny_account_store_get_tny_account_by (self, MODEST_TNY_ACCOUNT_STORE_QUERY_ID,
1538 MODEST_MMC_ACCOUNT_ID);
1542 /*********************************************************************************/
1544 add_existing_accounts (ModestTnyAccountStore *self)
1546 GSList *account_names = NULL, *iter = NULL;
1547 ModestTnyAccountStorePrivate *priv = NULL;
1549 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1551 /* These are account names, not server_account names */
1552 account_names = modest_account_mgr_account_names (priv->account_mgr, FALSE);
1554 for (iter = account_names; iter != NULL; iter = g_slist_next (iter)) {
1555 const gchar *account_name = (const gchar*) iter->data;
1557 /* Insert all enabled accounts without notifying */
1558 if (modest_account_mgr_get_enabled (priv->account_mgr, account_name))
1559 insert_account (self, account_name, FALSE);
1561 modest_account_mgr_free_account_names (account_names);
1565 create_tny_account (ModestTnyAccountStore *self,
1567 TnyAccountType type,
1570 TnyAccount *account = NULL;
1571 ModestTnyAccountStorePrivate *priv = NULL;
1573 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1575 account = modest_tny_account_new_from_account (priv->account_mgr,
1582 /* Forget any cached password for the account, so that
1583 we use a new account if any */
1584 modest_tny_account_store_forget_password_in_memory (self, tny_account_get_id (account));
1586 /* Set the account store */
1587 g_object_set_data (G_OBJECT(account), "account_store", self);
1589 g_printerr ("modest: failed to create account for %s\n", name);
1595 typedef struct _AddOutboxInfo {
1596 ModestTnyAccountStore *account_store;
1597 TnyAccount *transport_account;
1601 add_outbox_from_transport_account_to_global_outbox_get_folders_cb (TnyFolderStore *folder_store,
1607 TnyIterator *iter_folders;
1608 TnyFolder *per_account_outbox;
1609 TnyAccount *local_account = NULL;
1610 AddOutboxInfo *info = (AddOutboxInfo *) userdata;
1611 ModestTnyAccountStorePrivate *priv = NULL;
1612 ModestTnyAccountStore *self;
1614 self = MODEST_TNY_ACCOUNT_STORE (info->account_store);
1615 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1617 /* Note that this could happen if there is not enough space
1618 available on disk, then the outbox folder could not be
1620 if (tny_list_get_length (list) != 1) {
1621 g_warning ("%s: could not create outbox folder (%d folders found)", __FUNCTION__,
1622 tny_list_get_length (list));
1626 iter_folders = tny_list_create_iterator (list);
1627 per_account_outbox = TNY_FOLDER (tny_iterator_get_current (iter_folders));
1628 g_object_unref (iter_folders);
1629 g_object_unref (list);
1631 /* Add the outbox of the new per-account-local-outbox account
1632 to the global local merged OUTBOX of the local folders
1634 local_account = modest_tny_account_store_get_local_folders_account (info->account_store);
1635 modest_tny_local_folders_account_add_folder_to_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1636 per_account_outbox);
1637 /* Add the pair to the hash table */
1638 g_hash_table_insert (priv->outbox_of_transport,
1639 info->transport_account,
1640 per_account_outbox);
1642 /* Notify that the local account changed */
1643 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1644 g_object_unref (local_account);
1645 g_object_unref (per_account_outbox);
1648 g_object_unref (info->transport_account);
1649 g_slice_free (AddOutboxInfo, info);
1654 add_outbox_from_transport_account_to_global_outbox (ModestTnyAccountStore *self,
1655 const gchar *account_name,
1656 TnyAccount *transport_account)
1658 TnyList *folders = NULL;
1659 TnyAccount *account_outbox = NULL;
1660 ModestTnyAccountStorePrivate *priv = NULL;
1661 AddOutboxInfo *info;
1663 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1665 /* Create per account local outbox */
1667 modest_tny_account_new_for_per_account_local_outbox_folder (priv->account_mgr,
1671 if (!G_IS_OBJECT (account_outbox)) {
1672 g_warning ("%s: could not create per account local outbox folder", __FUNCTION__);
1676 tny_list_append (priv->store_accounts_outboxes, G_OBJECT (account_outbox));
1678 /* Get the outbox folder */
1679 folders = tny_simple_list_new ();
1680 info = g_slice_new0 (AddOutboxInfo);
1681 info->account_store = self;
1682 info->transport_account = g_object_ref (transport_account);
1683 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (account_outbox), folders, NULL, FALSE,
1684 add_outbox_from_transport_account_to_global_outbox_get_folders_cb, NULL, (gpointer) info);
1685 g_object_unref (account_outbox);
1689 * This function will be used for both adding new accounts and for the
1690 * initialization. In the initialization we do not want to emit
1691 * signals so notify will be FALSE, in the case of account additions
1692 * we do want to notify the observers
1695 insert_account (ModestTnyAccountStore *self,
1696 const gchar *account,
1699 ModestTnyAccountStorePrivate *priv = NULL;
1700 TnyAccount *store_account = NULL, *transport_account = NULL;
1702 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1704 /* Get the server and the transport account */
1705 store_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_STORE, is_new);
1706 if (!store_account || !TNY_IS_ACCOUNT(store_account)) {
1707 g_warning ("%s: failed to create store account", __FUNCTION__);
1711 transport_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT, is_new);
1712 if (!transport_account || !TNY_IS_ACCOUNT(transport_account)) {
1713 g_warning ("%s: failed to create transport account", __FUNCTION__);
1714 g_object_unref (store_account);
1718 /* Add accounts to the lists */
1719 tny_list_append (priv->store_accounts, G_OBJECT (store_account));
1720 tny_list_append (priv->transport_accounts, G_OBJECT (transport_account));
1722 /* Create a new pseudo-account with an outbox for this
1723 transport account and add it to the global outbox
1724 in the local account */
1725 add_outbox_from_transport_account_to_global_outbox (self, account, transport_account);
1727 /* Force the creation of the send queue, this way send queues
1728 will automatically send missing emails when the connections
1730 /* Notify the observers. We do it after everything is
1733 /* We only have to do this for new accounts, already
1734 existing accounts at boot time are instantiated by
1735 modest_tny_account_store_start_send_queues */
1736 modest_runtime_get_send_queue ((TnyTransportAccount *) transport_account, TRUE);
1738 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, store_account);
1739 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, transport_account);
1743 g_object_unref (store_account);
1744 g_object_unref (transport_account);
1747 static inline gboolean
1748 only_local_accounts (ModestTnyAccountStore *self)
1750 return (modest_tny_account_store_get_num_remote_accounts (self) > 0) ? FALSE : TRUE;
1754 on_account_inserted (ModestAccountMgr *acc_mgr,
1755 const gchar *account,
1758 gboolean add_specific;
1760 add_specific = only_local_accounts (MODEST_TNY_ACCOUNT_STORE (user_data));
1762 /* Insert the account and notify the observers */
1763 insert_account (MODEST_TNY_ACCOUNT_STORE (user_data), account, TRUE);
1765 /* If it's the first remote account then add the connection
1766 specific SMTP servers as well */
1768 add_connection_specific_transport_accounts (MODEST_TNY_ACCOUNT_STORE (user_data));
1772 /* This is the callback of the tny_camel_account_set_online called in
1773 on_account_removed to disconnect the account */
1775 on_account_disconnect_when_removing (TnyCamelAccount *account,
1780 ModestTnyAccountStore *self;
1781 ModestTnyAccountStorePrivate *priv;
1783 self = MODEST_TNY_ACCOUNT_STORE (user_data);
1784 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1786 /* Cancel all pending operations */
1787 tny_account_cancel (TNY_ACCOUNT (account));
1789 /* Unref the extra reference added by get_server_account */
1790 g_object_unref (account);
1792 /* Clear the cache if it's an store account */
1793 if (TNY_IS_STORE_ACCOUNT (account)) {
1794 tny_store_account_delete_cache (TNY_STORE_ACCOUNT (account));
1795 } else if (TNY_IS_TRANSPORT_ACCOUNT (account)) {
1796 ModestTnySendQueue* send_queue;
1797 send_queue = modest_runtime_get_send_queue (TNY_TRANSPORT_ACCOUNT (account), FALSE);
1798 if (TNY_IS_SEND_QUEUE (send_queue)) {
1799 if (modest_tny_send_queue_sending_in_progress (send_queue))
1800 tny_send_queue_cancel (TNY_SEND_QUEUE (send_queue),
1801 TNY_SEND_QUEUE_CANCEL_ACTION_REMOVE,
1803 modest_runtime_remove_send_queue (TNY_TRANSPORT_ACCOUNT (account));
1809 * We use this one for both removing "normal" and "connection
1810 * specific" transport accounts
1813 remove_transport_account (ModestTnyAccountStore *self,
1814 TnyTransportAccount *transport_account)
1816 ModestTnyAccountStorePrivate *priv;
1817 TnyFolder *outbox = NULL;
1819 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1821 /* Remove it from the list of accounts and notify the
1822 observers. Do not need to wait for account
1824 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 0, transport_account);
1825 tny_list_remove (priv->transport_accounts, (GObject *) transport_account);
1827 /* Remove the OUTBOX of the account from the global outbox */
1828 outbox = g_hash_table_lookup (priv->outbox_of_transport, transport_account);
1830 if (TNY_IS_FOLDER (outbox)) {
1831 TnyAccount *local_account = NULL;
1832 TnyAccount *outbox_account = tny_folder_get_account (outbox);
1834 if (outbox_account) {
1835 tny_list_remove (priv->store_accounts_outboxes, G_OBJECT (outbox_account));
1836 /* Remove existing emails to send */
1837 tny_store_account_delete_cache (TNY_STORE_ACCOUNT (outbox_account));
1838 g_object_unref (outbox_account);
1841 local_account = modest_tny_account_store_get_local_folders_account (self);
1842 modest_tny_local_folders_account_remove_folder_from_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1845 g_hash_table_remove (priv->outbox_of_transport, transport_account);
1847 /* Notify the change in the local account */
1848 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1849 g_object_unref (local_account);
1851 g_warning ("Removing a transport account that has no outbox");
1854 /* Cancel all pending operations */
1855 tny_account_cancel (TNY_ACCOUNT (transport_account));
1857 /* Disconnect and notify the observers. The callback will free the reference */
1858 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (transport_account), FALSE,
1859 on_account_disconnect_when_removing, self);
1863 images_cache_remove_filter (TnyStreamCache *self, const gchar *id, const gchar *account_name)
1865 gchar *account_name_with_separator;
1867 if (account_name == NULL || account_name[0] == '\0')
1870 if (id == NULL || id[0] == '\0')
1873 account_name_with_separator = g_strconcat (account_name, "__", NULL);
1875 result = (g_str_has_prefix (id, account_name));
1876 g_free (account_name_with_separator);
1882 on_account_removed (ModestAccountMgr *acc_mgr,
1883 const gchar *account,
1886 TnyAccount *store_account = NULL, *transport_account = NULL;
1887 ModestTnyAccountStore *self;
1888 ModestTnyAccountStorePrivate *priv;
1889 TnyStreamCache *stream_cache;
1891 self = MODEST_TNY_ACCOUNT_STORE (user_data);
1892 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1894 /* Get the server and the transport account */
1896 modest_tny_account_store_get_server_account (self, account,
1897 TNY_ACCOUNT_TYPE_STORE);
1899 modest_tny_account_store_get_server_account (self, account,
1900 TNY_ACCOUNT_TYPE_TRANSPORT);
1902 /* If there was any problem creating the account, for example,
1903 with the configuration system this could not exist */
1904 if (TNY_IS_STORE_ACCOUNT(store_account)) {
1905 /* Forget any cached password for the account */
1906 modest_tny_account_store_forget_password_in_memory (self, tny_account_get_id (store_account));
1908 /* Remove it from the list of accounts and notify the
1909 observers. Do not need to wait for account
1911 tny_list_remove (priv->store_accounts, (GObject *) store_account);
1912 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 0, store_account);
1914 /* Cancel all pending operations */
1915 tny_account_cancel (TNY_ACCOUNT (store_account));
1917 /* Disconnect before deleting the cache, because the
1918 disconnection will rewrite the cache to the
1920 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (store_account), FALSE,
1921 on_account_disconnect_when_removing, self);
1923 g_warning ("%s: no store account for account %s\n",
1924 __FUNCTION__, account);
1927 /* If there was any problem creating the account, for example,
1928 with the configuration system this could not exist */
1929 if (TNY_IS_TRANSPORT_ACCOUNT(transport_account)) {
1931 /* Forget any cached password for the account */
1932 modest_tny_account_store_forget_password_in_memory (self, tny_account_get_id (transport_account));
1934 /* Remove transport account. It'll free the reference
1935 added by get_server_account */
1936 remove_transport_account (self, TNY_TRANSPORT_ACCOUNT (transport_account));
1938 g_warning ("%s: no transport account for account %s\n",
1939 __FUNCTION__, account);
1942 /* Remove cached images */
1943 stream_cache = modest_runtime_get_images_cache ();
1944 tny_stream_cache_remove (stream_cache, (TnyStreamCacheRemoveFilter) images_cache_remove_filter, (gpointer) account);
1946 /* If there are no more user accounts then delete the
1947 transport specific SMTP servers */
1948 if (only_local_accounts (self))
1949 remove_connection_specific_transport_accounts (self);
1952 TnyTransportAccount *
1953 modest_tny_account_store_new_connection_specific_transport_account (ModestTnyAccountStore *self,
1956 ModestTnyAccountStorePrivate *priv = NULL;
1957 TnyAccount * tny_account = NULL;
1959 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1961 /* Add the account: */
1963 modest_tny_account_new_from_server_account_name (priv->account_mgr,
1969 g_object_set_data (G_OBJECT(tny_account),
1972 g_object_set_data (G_OBJECT(tny_account),
1973 "connection_specific",
1974 GINT_TO_POINTER (TRUE));
1976 tny_list_append (priv->transport_accounts, G_OBJECT (tny_account));
1977 add_outbox_from_transport_account_to_global_outbox (self,
1982 g_printerr ("modest: failed to create smtp-specific account for %s\n",
1985 return TNY_TRANSPORT_ACCOUNT (tny_account);
1989 foreach_free_string(gpointer data,
1996 add_connection_specific_transport_accounts (ModestTnyAccountStore *self)
1998 ModestTnyAccountStorePrivate *priv = NULL;
1999 GSList *list_specifics = NULL, *iter = NULL;
2002 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
2004 list_specifics = modest_conf_get_list (modest_runtime_get_conf (),
2005 MODEST_CONF_CONNECTION_SPECIFIC_SMTP_LIST,
2006 MODEST_CONF_VALUE_STRING, &err);
2009 g_return_if_reached ();
2013 /* Look at each connection-specific transport account for the
2014 * modest account: */
2015 iter = list_specifics;
2017 /* The list alternates between the connection name and the transport name: */
2018 iter = g_slist_next (iter);
2020 const gchar* transport_account_name = (const gchar*) (iter->data);
2021 TnyTransportAccount * account = NULL;
2022 account = modest_tny_account_store_new_connection_specific_transport_account (
2023 self, transport_account_name);
2025 g_object_unref (account);
2027 iter = g_slist_next (iter);
2031 g_slist_foreach (list_specifics, foreach_free_string, NULL);
2032 g_slist_free (list_specifics);
2036 remove_connection_specific_transport_accounts (ModestTnyAccountStore *self)
2038 ModestTnyAccountStorePrivate *priv = NULL;
2039 GSList *list_specifics = NULL, *iter = NULL;
2042 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
2045 list_specifics = modest_conf_get_list (modest_runtime_get_conf (),
2046 MODEST_CONF_CONNECTION_SPECIFIC_SMTP_LIST,
2047 MODEST_CONF_VALUE_STRING, &err);
2050 g_return_if_reached ();
2054 /* Look at each connection-specific transport account for the
2055 * modest account: */
2056 iter = list_specifics;
2058 /* The list alternates between the connection name and the transport name: */
2059 iter = g_slist_next (iter);
2061 const gchar* transport_account_name = (const gchar*) (iter->data);
2062 TnyAccount * account;
2063 account = modest_tny_account_store_get_server_account (self,
2064 transport_account_name,
2065 TNY_ACCOUNT_TYPE_TRANSPORT);
2067 /* the call will free the reference */
2069 remove_transport_account (self, TNY_TRANSPORT_ACCOUNT (account));
2071 iter = g_slist_next (iter);
2075 g_slist_foreach (list_specifics, foreach_free_string, NULL);
2076 g_slist_free (list_specifics);
2081 modest_tny_account_store_find_msg_in_outboxes (ModestTnyAccountStore *self,
2083 TnyAccount **ac_out)
2085 TnyIterator *acc_iter;
2086 ModestTnyAccountStorePrivate *priv;
2088 TnyAccount *msg_account = NULL;
2090 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
2091 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2093 acc_iter = tny_list_create_iterator (priv->store_accounts_outboxes);
2094 while (!msg && !tny_iterator_is_done (acc_iter)) {
2095 TnyList *folders = tny_simple_list_new ();
2096 TnyAccount *account = TNY_ACCOUNT (tny_iterator_get_current (acc_iter));
2097 TnyIterator *folders_iter = NULL;
2099 tny_folder_store_get_folders (TNY_FOLDER_STORE (account), folders, NULL, FALSE, NULL);
2100 folders_iter = tny_list_create_iterator (folders);
2102 while (msg == NULL && !tny_iterator_is_done (folders_iter)) {
2103 TnyFolder *folder = TNY_FOLDER (tny_iterator_get_current (folders_iter));
2104 msg = tny_folder_find_msg (folder, uri, NULL);
2107 msg_account = g_object_ref (account);
2109 g_object_unref (folder);
2110 tny_iterator_next (folders_iter);
2112 g_object_unref (folders_iter);
2114 g_object_unref (folders);
2115 g_object_unref (account);
2116 tny_iterator_next (acc_iter);
2119 g_object_unref (acc_iter);
2122 *ac_out = msg_account;
2127 TnyTransportAccount *
2128 modest_tny_account_store_get_transport_account_from_outbox_header(ModestTnyAccountStore *self, TnyHeader *header)
2130 TnyIterator *acc_iter;
2131 ModestTnyAccountStorePrivate *priv;
2132 TnyTransportAccount *header_acc = NULL;
2135 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
2136 g_return_val_if_fail (TNY_IS_HEADER (header), NULL);
2137 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2138 msg_id = modest_tny_send_queue_get_msg_id (header);
2139 acc_iter = tny_list_create_iterator (priv->transport_accounts);
2140 while (!header_acc && !tny_iterator_is_done (acc_iter)) {
2141 TnyTransportAccount *account = TNY_TRANSPORT_ACCOUNT (tny_iterator_get_current (acc_iter));
2142 ModestTnySendQueue *send_queue;
2143 ModestTnySendQueueStatus status;
2144 send_queue = modest_runtime_get_send_queue(TNY_TRANSPORT_ACCOUNT(account), TRUE);
2145 if (TNY_IS_SEND_QUEUE (send_queue)) {
2146 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2147 if (status != MODEST_TNY_SEND_QUEUE_UNKNOWN)
2148 header_acc = g_object_ref(account);
2150 g_object_unref (account);
2151 tny_iterator_next (acc_iter);
2153 g_object_unref(acc_iter);
2161 ModestTnyAccountStore *account_store;
2162 ModestTnyAccountStoreShutdownCallback callback;
2168 account_shutdown_callback (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer userdata)
2170 ShutdownOpData *op_data = (ShutdownOpData *) userdata;
2172 if (op_data->pending == 0) {
2173 if (op_data->callback)
2174 op_data->callback (op_data->account_store, op_data->userdata);
2175 g_object_unref (op_data->account_store);
2181 account_shutdown (TnyAccount *account, ShutdownOpData *op_data)
2183 g_return_if_fail (account && TNY_IS_ACCOUNT(account));
2185 if (TNY_IS_STORE_ACCOUNT (account) &&
2186 !modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
2191 /* Disconnect account */
2192 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT(account), FALSE,
2193 account_shutdown_callback, op_data);
2199 modest_tny_account_store_shutdown (ModestTnyAccountStore *self,
2200 ModestTnyAccountStoreShutdownCallback callback,
2204 ShutdownOpData *op_data;
2205 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2207 /* Get references */
2209 if (priv->store_accounts)
2210 num_accounts += tny_list_get_length (priv->store_accounts);
2211 if (priv->transport_accounts)
2212 num_accounts += tny_list_get_length (priv->transport_accounts);
2214 /* Create the helper object */
2215 op_data = g_new0 (ShutdownOpData, 1);
2216 op_data->callback = callback;
2217 op_data->userdata = userdata;
2218 op_data->pending = num_accounts;
2219 op_data->account_store = g_object_ref (self);
2221 /* Force the TnyDevice to be offline. This way new
2222 undesired connections won't be initiated */
2223 tny_device_force_offline (priv->device);
2225 /* Destroy all accounts. Disconnect all accounts before they are destroyed */
2226 if (priv->store_accounts) {
2227 tny_list_foreach (priv->store_accounts, (GFunc)account_shutdown, op_data);
2230 if (priv->transport_accounts) {
2231 tny_list_foreach (priv->transport_accounts, (GFunc)account_shutdown, op_data);
2234 if (op_data->pending == 0) {
2235 if (op_data->callback)
2236 op_data->callback (op_data->account_store, op_data->userdata);
2237 g_object_unref (op_data->account_store);
2243 modest_tny_account_store_is_shutdown (ModestTnyAccountStore *self)
2245 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2251 for (iter = tny_list_create_iterator (priv->store_accounts);
2252 !found && !tny_iterator_is_done (iter);
2253 tny_iterator_next (iter)) {
2254 TnyAccount *account;
2256 account = (TnyAccount *) tny_iterator_get_current (iter);
2257 if (TNY_IS_ACCOUNT (account)) {
2258 found = (tny_account_get_connection_status (account) == TNY_CONNECTION_STATUS_CONNECTED) ||
2259 (tny_account_get_connection_status (account) == TNY_CONNECTION_STATUS_RECONNECTING);
2261 g_object_unref (account);
2263 g_object_unref (iter);
2268 for (iter = tny_list_create_iterator (priv->transport_accounts);
2269 !found && !tny_iterator_is_done (iter);
2270 tny_iterator_next (iter)) {
2271 TnyAccount *account;
2273 account = (TnyAccount *) tny_iterator_get_current (iter);
2274 if (TNY_IS_ACCOUNT (account)) {
2275 found = (tny_account_get_connection_status (account) == TNY_CONNECTION_STATUS_CONNECTED) ||
2276 (tny_account_get_connection_status (account) == TNY_CONNECTION_STATUS_RECONNECTING);
2278 g_object_unref (account);
2280 g_object_unref (iter);
2288 modest_tny_account_store_is_send_mail_blocked (ModestTnyAccountStore *self)
2290 ModestTnyAccountStorePrivate *priv;
2292 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
2294 return priv->send_mail_blocked;
2298 modest_tny_account_store_set_send_mail_blocked (ModestTnyAccountStore *self,
2301 ModestTnyAccountStorePrivate *priv;
2303 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
2305 priv->send_mail_blocked = blocked;
2309 count_remote_accounts (gpointer data, gpointer user_data)
2311 TnyFolderStore *account = TNY_FOLDER_STORE (data);
2312 gint *count = (gint *) user_data;
2314 if (modest_tny_folder_store_is_remote (account))
2319 modest_tny_account_store_get_num_remote_accounts (ModestTnyAccountStore *self)
2321 ModestTnyAccountStorePrivate *priv;
2324 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), 0);
2326 /* Count remote accounts */
2327 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2328 tny_list_foreach (priv->store_accounts, (GFunc) count_remote_accounts, &count);
2334 init_send_queue (TnyAccount *account, gpointer user_data)
2336 modest_runtime_get_send_queue ((TnyTransportAccount *) account, TRUE);
2340 modest_tny_account_store_start_send_queues (ModestTnyAccountStore *self)
2342 ModestTnyAccountStorePrivate *priv;
2345 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self));
2347 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2349 /* We need to create a copy of the list because if the send
2350 queues are created they'll directly access to the TnyList
2351 of transport accounts, and thus we'll end up blocked in the
2352 mutex the TnyList uses to synchronize accesses */
2353 tmp = tny_list_copy (priv->transport_accounts);
2355 /* Just instantiate them. They'll begin to listen for
2356 connection changes to send messages ASAP */
2357 tny_list_foreach (tmp, (GFunc) init_send_queue, NULL);
2358 g_object_unref (tmp);
2363 modest_tny_account_store_check_disk_full_error (ModestTnyAccountStore *self,
2364 GtkWidget *parent_window,
2366 TnyAccount *account,
2367 const gchar *alternate)
2372 if (modest_tny_account_store_is_disk_full_error (self, err, account)) {
2373 gboolean is_mcc = modest_tny_account_is_memory_card_account (account);
2374 if (is_mcc && alternate) {
2375 modest_platform_information_banner (parent_window, NULL, alternate);
2377 gchar *msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
2378 modest_platform_information_banner (parent_window, NULL, msg);
2381 } else if (err->code == TNY_SYSTEM_ERROR_MEMORY)
2382 /* If the account was created in memory full
2383 conditions then tinymail won't be able to
2384 connect so it'll return this error code */
2385 modest_platform_information_banner (parent_window,
2386 NULL, _("emev_ui_imap_inbox_select_error"));
2394 modest_tny_account_store_is_disk_full_error (ModestTnyAccountStore *self,
2396 TnyAccount *account)
2398 gboolean enough_free_space = TRUE;
2399 GnomeVFSURI *cache_dir_uri;
2400 const gchar *cache_dir = NULL;
2401 GnomeVFSFileSize free_space;
2403 /* Cache dir is different in case we're using an external storage (like MMC account) */
2404 if (account && modest_tny_account_is_memory_card_account (account))
2405 cache_dir = g_getenv (MODEST_MMC1_VOLUMEPATH_ENV);
2407 /* Get the default local cache dir */
2409 cache_dir = tny_account_store_get_cache_dir ((TnyAccountStore *) self);
2411 cache_dir_uri = gnome_vfs_uri_new (cache_dir);
2412 if (cache_dir_uri) {
2413 if (gnome_vfs_get_volume_free_space (cache_dir_uri, &free_space) == GNOME_VFS_OK) {
2414 if (free_space < MODEST_TNY_ACCOUNT_STORE_MIN_FREE_SPACE)
2415 enough_free_space = FALSE;
2417 gnome_vfs_uri_unref (cache_dir_uri);
2420 if ((error->code == TNY_SYSTEM_ERROR_MEMORY ||
2421 /* When asking for a mail and no space left on device
2422 tinymail returns this error */
2423 error->code == TNY_SERVICE_ERROR_MESSAGE_NOT_AVAILABLE ||
2424 /* When the folder summary could not be read or
2426 error->code == TNY_IO_ERROR_WRITE ||
2427 error->code == TNY_IO_ERROR_READ) &&
2428 !enough_free_space) {