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>
66 #ifdef MODEST_PLATFORM_MAEMO
67 #include <tny-maemo-conic-device.h>
70 #include <libgnomevfs/gnome-vfs-volume-monitor.h>
72 /* 'private'/'protected' functions */
73 static void modest_tny_account_store_class_init (ModestTnyAccountStoreClass *klass);
74 static void modest_tny_account_store_finalize (GObject *obj);
75 static void modest_tny_account_store_instance_init (ModestTnyAccountStore *obj);
76 static void modest_tny_account_store_init (gpointer g, gpointer iface_data);
77 static void modest_tny_account_store_base_init (gpointer g_class);
79 static void on_account_inserted (ModestAccountMgr *acc_mgr,
83 static void add_existing_accounts (ModestTnyAccountStore *self);
85 static void insert_account (ModestTnyAccountStore *self,
89 static void on_account_removed (ModestAccountMgr *acc_mgr,
93 static gchar* get_password (TnyAccount *account,
94 const gchar * prompt_not_used,
97 static void forget_password (TnyAccount *account);
99 static void on_vfs_volume_mounted (GnomeVFSVolumeMonitor *volume_monitor,
100 GnomeVFSVolume *volume,
103 static void on_vfs_volume_unmounted (GnomeVFSVolumeMonitor *volume_monitor,
104 GnomeVFSVolume *volume,
107 static void forget_password_in_memory (ModestTnyAccountStore *self,
108 const gchar *server_account_name);
110 static void add_connection_specific_transport_accounts (ModestTnyAccountStore *self);
112 static void remove_connection_specific_transport_accounts (ModestTnyAccountStore *self);
114 static inline gboolean only_local_accounts (ModestTnyAccountStore *self);
116 /* list my signals */
118 ACCOUNT_CHANGED_SIGNAL,
119 ACCOUNT_INSERTED_SIGNAL,
120 ACCOUNT_REMOVED_SIGNAL,
122 PASSWORD_REQUESTED_SIGNAL,
126 typedef struct _ModestTnyAccountStorePrivate ModestTnyAccountStorePrivate;
127 struct _ModestTnyAccountStorePrivate {
129 GHashTable *password_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;
144 /* is sending mail blocked? */
145 gboolean send_mail_blocked;
148 #define MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
149 MODEST_TYPE_TNY_ACCOUNT_STORE, \
150 ModestTnyAccountStorePrivate))
152 #define RETRY_ATTEMPTS 3
154 typedef struct _PwdAttempt {
160 static GObjectClass *parent_class = NULL;
162 static guint signals[LAST_SIGNAL] = {0};
165 modest_tny_account_store_get_type (void)
167 static GType my_type = 0;
170 static const GTypeInfo my_info = {
171 sizeof(ModestTnyAccountStoreClass),
172 modest_tny_account_store_base_init, /* base init */
173 NULL, /* base finalize */
174 (GClassInitFunc) modest_tny_account_store_class_init,
175 NULL, /* class finalize */
176 NULL, /* class data */
177 sizeof(ModestTnyAccountStore),
179 (GInstanceInitFunc) modest_tny_account_store_instance_init,
183 static const GInterfaceInfo iface_info = {
184 (GInterfaceInitFunc) modest_tny_account_store_init,
185 NULL, /* interface_finalize */
186 NULL /* interface_data */
189 my_type = g_type_register_static (G_TYPE_OBJECT,
190 "ModestTnyAccountStore",
192 g_type_add_interface_static (my_type, TNY_TYPE_ACCOUNT_STORE,
200 modest_tny_account_store_base_init (gpointer g_class)
202 static gboolean tny_account_store_initialized = FALSE;
204 if (!tny_account_store_initialized) {
206 signals[ACCOUNT_CHANGED_SIGNAL] =
207 g_signal_new ("account_changed",
208 MODEST_TYPE_TNY_ACCOUNT_STORE,
210 G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_changed),
212 g_cclosure_marshal_VOID__OBJECT,
213 G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
215 signals[ACCOUNT_INSERTED_SIGNAL] =
216 g_signal_new ("account_inserted",
217 MODEST_TYPE_TNY_ACCOUNT_STORE,
219 G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_inserted),
221 g_cclosure_marshal_VOID__OBJECT,
222 G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
224 signals[ACCOUNT_REMOVED_SIGNAL] =
225 g_signal_new ("account_removed",
226 MODEST_TYPE_TNY_ACCOUNT_STORE,
228 G_STRUCT_OFFSET (ModestTnyAccountStoreClass, account_removed),
230 g_cclosure_marshal_VOID__OBJECT,
231 G_TYPE_NONE, 1, TNY_TYPE_ACCOUNT);
233 signals[PASSWORD_REQUESTED_SIGNAL] =
234 g_signal_new ("password_requested",
235 MODEST_TYPE_TNY_ACCOUNT_STORE,
237 G_STRUCT_OFFSET(ModestTnyAccountStoreClass, password_requested),
239 modest_marshal_VOID__STRING_POINTER_POINTER_POINTER_POINTER,
240 G_TYPE_NONE, 5, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER,
243 tny_account_store_initialized = TRUE;
249 modest_tny_account_store_class_init (ModestTnyAccountStoreClass *klass)
251 GObjectClass *gobject_class;
252 gobject_class = (GObjectClass*) klass;
254 parent_class = g_type_class_peek_parent (klass);
255 gobject_class->finalize = modest_tny_account_store_finalize;
257 g_type_class_add_private (gobject_class,
258 sizeof(ModestTnyAccountStorePrivate));
262 free_pwd_attempt (gpointer data)
264 PwdAttempt *attempt = (PwdAttempt *) data;
266 /* Note that we sometimes insert NULL */
271 g_free (attempt->pwd);
272 g_slice_free (PwdAttempt, attempt);
276 modest_tny_account_store_instance_init (ModestTnyAccountStore *obj)
278 ModestTnyAccountStorePrivate *priv;
280 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
282 priv->cache_dir = NULL;
283 priv->account_mgr = NULL;
284 priv->session = NULL;
286 priv->sighandlers = NULL;
287 priv->send_mail_blocked = FALSE;
289 priv->outbox_of_transport = g_hash_table_new_full (g_direct_hash,
294 /* An in-memory store of passwords,
295 * for passwords that are not remembered in the configuration,
296 * so they need to be asked for from the user once in each session:
298 priv->password_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
299 g_free, free_pwd_attempt);
302 /* disconnect the list of TnyAccounts */
304 account_verify_last_ref (TnyAccount *account, const gchar *str)
308 g_return_if_fail (account && TNY_IS_ACCOUNT(account));
310 txt = g_strdup_printf ("%s: %s", str ? str : "?", tny_account_get_name(account));
311 MODEST_DEBUG_VERIFY_OBJECT_LAST_REF(G_OBJECT(account),txt);
316 foreach_account_append_to_list (gpointer data,
321 list = TNY_LIST (user_data);
322 tny_list_append (list, G_OBJECT (data));
325 /********************************************************************/
326 /* Control the state of the MMC local account */
327 /********************************************************************/
329 /** Only call this if the memory card is really mounted.
332 add_mmc_account(ModestTnyAccountStore *self, gboolean emit_insert_signal)
334 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
335 g_return_if_fail (priv->session);
337 TnyAccount *mmc_account = modest_tny_account_new_for_local_folders (priv->account_mgr,
339 g_getenv (MODEST_MMC1_VOLUMEPATH_ENV));
341 /* Add to the list of store accounts */
342 tny_list_append (priv->store_accounts, G_OBJECT (mmc_account));
344 if (emit_insert_signal) {
345 g_signal_emit (G_OBJECT (self),
346 signals [ACCOUNT_INSERTED_SIGNAL],
351 g_object_unref (mmc_account);
355 on_vfs_volume_mounted(GnomeVFSVolumeMonitor *volume_monitor,
356 GnomeVFSVolume *volume,
359 ModestTnyAccountStore *self;
360 ModestTnyAccountStorePrivate *priv;
361 gchar *volume_path_uri;
365 self = MODEST_TNY_ACCOUNT_STORE(user_data);
366 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
368 /* Check whether this was the external MMC1 card: */
369 uri = gnome_vfs_volume_get_activation_uri (volume);
371 volume_path_uri = g_strconcat (MODEST_MMC1_VOLUMEPATH_URI_PREFIX,
372 g_getenv (MODEST_MMC1_VOLUMEPATH_ENV),
374 if (uri && (!strcmp (uri, volume_path_uri))) {
375 add_mmc_account (self, TRUE /* emit the insert signal. */);
378 g_free (volume_path_uri);
383 on_vfs_volume_unmounted(GnomeVFSVolumeMonitor *volume_monitor,
384 GnomeVFSVolume *volume,
387 ModestTnyAccountStore *self;
388 ModestTnyAccountStorePrivate *priv;
390 gchar *volume_path_uri;
392 self = MODEST_TNY_ACCOUNT_STORE(user_data);
393 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
395 /* Check whether this was the external MMC1 card: */
396 uri = gnome_vfs_volume_get_activation_uri (volume);
397 volume_path_uri = g_strconcat (MODEST_MMC1_VOLUMEPATH_URI_PREFIX,
398 g_getenv (MODEST_MMC1_VOLUMEPATH_ENV),
400 if (uri && (strcmp (uri, volume_path_uri) == 0)) {
401 TnyAccount *mmc_account = NULL;
402 gboolean found = FALSE;
403 TnyIterator *iter = NULL;
405 iter = tny_list_create_iterator (priv->store_accounts);
406 while (!tny_iterator_is_done (iter) && !found) {
409 account = TNY_ACCOUNT (tny_iterator_get_current (iter));
410 if (modest_tny_account_is_memory_card_account (account)) {
412 mmc_account = g_object_ref (account);
414 g_object_unref (account);
415 tny_iterator_next (iter);
417 g_object_unref (iter);
420 /* Remove from the list */
421 tny_list_remove (priv->store_accounts, G_OBJECT (mmc_account));
423 /* Notify observers */
424 g_signal_emit (G_OBJECT (self),
425 signals [ACCOUNT_REMOVED_SIGNAL],
428 g_object_unref (mmc_account);
430 g_debug ("%s: there was no store account for the unmounted MMC",
434 g_free (volume_path_uri);
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);
488 g_object_unref (iter);
492 show_wrong_password_dialog (TnyAccount *account,
493 gboolean show_banner)
495 g_debug ("%s: %s", __FUNCTION__, tny_account_get_id (account));
497 if (g_object_get_data (G_OBJECT (account), "connection_specific") != NULL) {
498 modest_ui_actions_on_smtp_servers (NULL, NULL);
500 ModestAccountProtocol *proto;
501 ModestProtocolType proto_type;
502 const gchar *modest_account_name;
503 modest_account_name = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
506 proto_type = modest_account_mgr_get_store_protocol (modest_runtime_get_account_mgr (),
507 modest_account_name);
508 proto = (ModestAccountProtocol *)
509 modest_protocol_registry_get_protocol_by_type (modest_runtime_get_protocol_registry (),
512 /* Create and show the dialog */
513 if (proto && MODEST_IS_ACCOUNT_PROTOCOL (proto)) {
515 ModestWindowMgr *mgr = modest_runtime_get_window_mgr ();
516 ModestAccountSettingsDialog *dialog =
517 modest_account_protocol_get_account_settings_dialog (proto, modest_account_name);
519 parent = modest_window_mgr_get_modal (mgr);
521 parent = (GtkWindow *) modest_window_mgr_get_current_top (mgr);
523 modest_window_mgr_set_modal (mgr, GTK_WINDOW (dialog), parent);
524 gtk_widget_show (GTK_WIDGET (dialog));
527 /* Show an explanatory temporary banner: */
529 modest_platform_information_banner (NULL, NULL, _("mcen_ib_username_pw_incorrect"));
532 /* This callback will be called by Tinymail when it needs the password
533 * from the user or the account settings.
534 * It can also call forget_password() before calling this,
535 * so that we clear wrong passwords out of our account settings.
536 * Note that TnyAccount here will be the server account. */
538 get_password (TnyAccount *account, const gchar * prompt_not_used, gboolean *cancel)
540 ModestTnyAccountStore *self = NULL;
541 ModestTnyAccountStorePrivate *priv;
542 gchar *username = NULL;
544 gboolean already_asked = FALSE;
545 const gchar *server_account_name;
547 PwdAttempt *attempt = NULL;
548 gpointer attempt_ptr = NULL;
550 g_return_val_if_fail (account, NULL);
552 g_debug ("%s: %s", __FUNCTION__, prompt_not_used);
554 /* Get a reference to myself */
555 self = MODEST_TNY_ACCOUNT_STORE (g_object_get_data (G_OBJECT(account), "account_store"));
556 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
558 /* Ensure that we still have this account. It could happen
559 that a set_online was requested *before* removing an
560 account, and due to tinymail emits the get_password
561 function using a g_idle the account could be actually
562 removed *before* this function was really called */
563 url_string = tny_account_get_url_string (account);
565 TnyAccount *tmp_account;
567 tmp_account = tny_account_store_find_account (TNY_ACCOUNT_STORE (self),
575 g_object_unref (tmp_account);
578 server_account_name = tny_account_get_id (account);
579 if (!server_account_name || !self) {
580 g_warning ("%s: could not retrieve account_store for account %s",
581 __FUNCTION__, server_account_name ? server_account_name : "<NULL>");
588 /* We need to do this to avoid "dereferencing type-punned pointer will break strict-aliasing rules" */
589 attempt_ptr = (gpointer) &attempt;
591 /* This hash map stores passwords, including passwords that are not stored in gconf. */
592 /* Is it in the hash? if it's already there, it must be wrong... */
593 already_asked = priv->password_hash && g_hash_table_lookup_extended (priv->password_hash,
598 /* If the password is not already there, try ModestConf */
599 if (!already_asked) {
600 pwd = modest_account_mgr_get_server_account_password (priv->account_mgr,
601 server_account_name);
602 PwdAttempt *new_attempt = g_slice_new0 (PwdAttempt);
603 new_attempt->count = RETRY_ATTEMPTS;
604 new_attempt->pwd = g_strdup (pwd);
605 g_hash_table_insert (priv->password_hash, g_strdup (server_account_name), new_attempt);
606 } else if (attempt) {
607 pwd = g_strdup (attempt->pwd);
610 /* This is horrible but we need it until we don't get a proper
611 fix into tinymail. Thing is that tinymail incorrectly asks
612 for password when the connection to the server failed due a
613 timeout (slow network connection, firewalls...). In those
614 cases it makes no sense to ask the user. It's better just
616 if (g_strstr_len (prompt_not_used, -1, "Connection timed out")) {
617 g_debug ("%s, Incorrect get_password with connection issue %s",
618 __FUNCTION__, (attempt && (attempt->count > 0)) ? "retrying" : "canceling");
620 if (attempt->count == 0) {
621 modest_tny_account_store_reset_attempt_count (self, account);
635 /* If it was already asked, it must have been wrong, so ask again */
636 if (already_asked || !pwd || strlen(pwd) == 0) {
637 gboolean settings_have_password;
638 ModestProtocolType protocol_type;
640 /* As per the UI spec, if no password was set in the account settings,
641 * ask for it now. But if the password is wrong in the account settings,
642 * then show a banner and the account settings dialog so it can be corrected:
644 settings_have_password =
645 modest_account_mgr_get_server_account_has_password (priv->account_mgr, server_account_name);
647 protocol_type = modest_tny_account_get_protocol_type (account);
649 /* Show an error and after that ask for a password */
650 if (modest_protocol_registry_protocol_type_has_tag(modest_runtime_get_protocol_registry (),
651 protocol_type, MODEST_PROTOCOL_REGISTRY_TRANSPORT_PROTOCOLS)) {
652 gchar *username = NULL, *msg = NULL;
653 username = modest_account_mgr_get_server_account_username (priv->account_mgr,
654 server_account_name);
655 if (!username || strlen(username) == 0) {
656 msg = g_strdup_printf (_("emev_ni_ui_smtp_userid_invalid"),
657 tny_account_get_name (account),
658 tny_account_get_hostname (account));
661 password = modest_account_mgr_get_server_account_password (priv->account_mgr,
662 server_account_name);
664 if (!password || strlen(password) == 0) {
665 msg = g_strdup_printf (_("emev_ni_ui_smtp_passwd_invalid"),
666 tny_account_get_name (account),
667 tny_account_get_hostname (account));
669 msg = g_strdup_printf (_("emev_ni_ui_smtp_authentication_fail_error"),
670 tny_account_get_hostname (account));
676 modest_platform_run_information_dialog (NULL, msg, TRUE);
684 gboolean username_known =
685 modest_account_mgr_get_server_account_username_has_succeeded(priv->account_mgr,
686 server_account_name);
687 /* If the login has ever succeeded then show a specific message */
689 msg = _CS ("ecdg_ib_set_password_incorrect");
691 msg = _("mcen_ib_username_pw_incorrect");
692 if (modest_window_mgr_get_num_windows (modest_runtime_get_window_mgr ()))
693 modest_platform_information_banner (NULL, NULL, msg);
697 if (settings_have_password) {
698 /* The password must be wrong, so show the account settings dialog so it can be corrected: */
699 show_wrong_password_dialog (account, TRUE);
707 /* we don't have it yet. Get the password from the user */
709 const gchar* account_id = tny_account_get_id (account);
710 gboolean remember = FALSE;
711 g_signal_emit (G_OBJECT (self), signals[PASSWORD_REQUESTED_SIGNAL], 0,
712 account_id, /* server_account_name */
713 &username, &pwd, cancel, &remember);
716 g_hash_table_remove (priv->password_hash, server_account_name);
731 modest_tny_account_store_forget_already_asked (ModestTnyAccountStore *self, TnyAccount *account)
733 g_return_if_fail (account);
735 ModestTnyAccountStorePrivate *priv;
737 gpointer pwd_ptr = NULL;
738 gboolean already_asked = FALSE;
740 const gchar *server_account_name = tny_account_get_id (account);
742 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
744 /* This hash map stores passwords, including passwords that are not stored in gconf. */
745 pwd_ptr = (gpointer)&pwd; /* pwd_ptr so the compiler does not complained about
746 * type-punned ptrs...*/
747 already_asked = priv->password_hash &&
748 g_hash_table_lookup_extended (priv->password_hash,
751 (gpointer*)&pwd_ptr);
754 g_hash_table_remove (priv->password_hash, server_account_name);
762 /* tinymail calls this if the connection failed due to an incorrect password.
763 * And it seems to call this for any general connection failure. */
765 forget_password (TnyAccount *account)
767 ModestTnyAccountStore *self;
768 ModestTnyAccountStorePrivate *priv;
769 const TnyAccountStore *account_store;
773 account_store = TNY_ACCOUNT_STORE(g_object_get_data (G_OBJECT(account),
775 self = MODEST_TNY_ACCOUNT_STORE (account_store);
776 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
777 key = tny_account_get_id (account);
779 /* Do not remove the key, this will allow us to detect that we
780 have already asked for it at least once */
781 attempt = g_hash_table_lookup (priv->password_hash, key);
784 g_debug ("%s, remaining %d for account %s", __FUNCTION__, attempt->count, key);
785 if (attempt->count == 0) {
787 memset (attempt->pwd, 0, strlen (attempt->pwd));
788 g_hash_table_insert (priv->password_hash, g_strdup (key), NULL);
794 modest_tny_account_store_finalize (GObject *obj)
796 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(obj);
797 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
799 g_free (priv->cache_dir);
800 priv->cache_dir = NULL;
802 if (priv->password_hash) {
803 g_hash_table_destroy (priv->password_hash);
804 priv->password_hash = NULL;
807 if (priv->outbox_of_transport) {
808 g_hash_table_destroy (priv->outbox_of_transport);
809 priv->outbox_of_transport = NULL;
812 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
813 priv->sighandlers = NULL;
815 if (priv->account_mgr) {
816 g_object_unref (G_OBJECT(priv->account_mgr));
817 priv->account_mgr = NULL;
821 g_object_unref (G_OBJECT(priv->device));
825 /* Destroy all accounts. Disconnect all accounts before they are destroyed */
826 if (priv->store_accounts) {
827 tny_list_foreach (priv->store_accounts, (GFunc)account_verify_last_ref, "store");
828 g_object_unref (priv->store_accounts);
829 priv->store_accounts = NULL;
832 if (priv->transport_accounts) {
833 tny_list_foreach (priv->transport_accounts, (GFunc)account_verify_last_ref, "transport");
834 g_object_unref (priv->transport_accounts);
835 priv->transport_accounts = NULL;
838 if (priv->store_accounts_outboxes) {
839 g_object_unref (priv->store_accounts_outboxes);
840 priv->store_accounts_outboxes = NULL;
844 camel_object_unref (CAMEL_OBJECT(priv->session));
845 priv->session = NULL;
848 G_OBJECT_CLASS(parent_class)->finalize (obj);
852 volume_path_is_mounted (const gchar* path)
854 g_return_val_if_fail (path, FALSE);
856 gboolean result = FALSE;
857 gchar * path_as_uri = g_filename_to_uri (path, NULL, NULL);
858 g_return_val_if_fail (path_as_uri, FALSE);
860 /* Get the monitor singleton: */
861 GnomeVFSVolumeMonitor *monitor = gnome_vfs_get_volume_monitor();
863 /* This seems like a simpler way to do this, but it returns a
864 * GnomeVFSVolume even if the drive is not mounted: */
866 GnomeVFSVolume *volume = gnome_vfs_volume_monitor_get_volume_for_path (monitor,
867 g_getenv (MODEST_MMC1_VOLUMEPATH_ENV));
869 gnome_vfs_volume_unref(volume);
873 /* Get the mounted volumes from the monitor: */
874 GList *list = gnome_vfs_volume_monitor_get_mounted_volumes (monitor);
876 for (iter = list; iter; iter = g_list_next (iter)) {
877 GnomeVFSVolume *volume = (GnomeVFSVolume*)iter->data;
881 gnome_vfs_volume_get_display_name (volume);
882 printf ("volume display name=%s\n", display_name);
883 g_free (display_name);
887 gnome_vfs_volume_get_activation_uri (volume);
888 /* printf (" uri=%s\n", uri); */
889 if (uri && (strcmp (uri, path_as_uri) == 0))
894 gnome_vfs_volume_unref (volume);
900 g_free (path_as_uri);
905 ModestTnyAccountStore*
906 modest_tny_account_store_new (ModestAccountMgr *account_mgr,
910 ModestTnyAccountStorePrivate *priv;
911 TnyAccount *local_account = NULL;
912 TnyLockable *lockable;
913 GnomeVFSVolumeMonitor* monitor = NULL;
914 gboolean auto_update;
916 g_return_val_if_fail (account_mgr, NULL);
917 g_return_val_if_fail (device, NULL);
919 obj = G_OBJECT(g_object_new(MODEST_TYPE_TNY_ACCOUNT_STORE, NULL));
920 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
922 priv->account_mgr = g_object_ref (G_OBJECT(account_mgr));
923 priv->device = g_object_ref (device);
925 /* If autoupdate is off then we don't try to connect to the
926 accounts when they're added to the account store*/
927 auto_update = modest_conf_get_bool (modest_runtime_get_conf (),
928 MODEST_CONF_AUTO_UPDATE, NULL);
930 tny_device_force_offline (priv->device);
932 priv->session = tny_session_camel_new (TNY_ACCOUNT_STORE(obj));
933 if (!priv->session) {
934 g_warning ("failed to get TnySessionCamel");
938 /* Set the ui locker */
939 lockable = tny_gtk_lockable_new ();
940 tny_session_camel_set_ui_locker (priv->session, lockable);
941 g_object_unref (lockable);
943 /* Connect signals */
944 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
945 G_OBJECT(account_mgr), "account_inserted",
946 G_CALLBACK (on_account_inserted), obj);
947 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
948 G_OBJECT(account_mgr), "account_changed",
949 G_CALLBACK (on_account_changed), obj);
950 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
951 G_OBJECT(account_mgr), "account_removed",
952 G_CALLBACK (on_account_removed), obj);
954 /* Respond to volume mounts and unmounts, such as the
955 insertion/removal of the memory card. This is a singleton,
956 so it does not need to be unrefed */
957 monitor = gnome_vfs_get_volume_monitor();
958 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
961 G_CALLBACK(on_vfs_volume_mounted),
963 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
964 G_OBJECT(monitor), "volume-unmounted",
965 G_CALLBACK(on_vfs_volume_unmounted),
968 /* Create the lists of accounts */
969 priv->store_accounts = tny_simple_list_new ();
970 priv->transport_accounts = tny_simple_list_new ();
971 priv->store_accounts_outboxes = tny_simple_list_new ();
973 /* Create the local folders account */
975 modest_tny_account_new_for_local_folders (priv->account_mgr, priv->session, NULL);
976 tny_list_append (priv->store_accounts, G_OBJECT(local_account));
977 g_object_unref (local_account);
979 /* Add the other remote accounts. Do this after adding the
980 local account, because we need to add our outboxes to the
981 global OUTBOX hosted in the local account */
982 add_existing_accounts (MODEST_TNY_ACCOUNT_STORE (obj));
984 /* Add connection-specific transport accounts if there are any
985 accounts available */
986 if (!only_local_accounts (MODEST_TNY_ACCOUNT_STORE(obj)))
987 add_connection_specific_transport_accounts (MODEST_TNY_ACCOUNT_STORE(obj));
989 /* This is a singleton, so it does not need to be unrefed. */
990 if (volume_path_is_mounted (g_getenv (MODEST_MMC1_VOLUMEPATH_ENV))) {
992 add_mmc_account (MODEST_TNY_ACCOUNT_STORE (obj), FALSE /* don't emit the insert signal. */);
995 /* Initialize session */
996 tny_session_camel_set_initialized (priv->session);
998 return MODEST_TNY_ACCOUNT_STORE(obj);
1002 modest_tny_account_store_get_accounts (TnyAccountStore *self,
1004 TnyGetAccountsRequestType request_type)
1006 ModestTnyAccountStorePrivate *priv;
1008 g_return_if_fail (self);
1009 g_return_if_fail (TNY_IS_LIST(list));
1011 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1013 switch (request_type) {
1014 case TNY_ACCOUNT_STORE_BOTH:
1015 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
1016 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
1018 case TNY_ACCOUNT_STORE_STORE_ACCOUNTS:
1019 tny_list_foreach (priv->store_accounts, foreach_account_append_to_list, list);
1021 case TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS:
1022 tny_list_foreach (priv->transport_accounts, foreach_account_append_to_list, list);
1025 g_return_if_reached ();
1031 modest_tny_account_store_get_cache_dir (TnyAccountStore *self)
1033 ModestTnyAccountStorePrivate *priv;
1034 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1036 if (!priv->cache_dir)
1037 priv->cache_dir = g_build_filename (g_get_home_dir(),
1038 MODEST_DIR, MODEST_CACHE_DIR, NULL);
1039 return priv->cache_dir;
1044 * callers need to unref
1047 modest_tny_account_store_get_device (TnyAccountStore *self)
1049 ModestTnyAccountStorePrivate *priv;
1051 g_return_val_if_fail (self, NULL);
1053 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1056 return g_object_ref (G_OBJECT(priv->device));
1063 modest_tny_account_store_find_account_by_url (TnyAccountStore *self, const gchar* url_string)
1065 return modest_tny_account_store_get_tny_account_by (MODEST_TNY_ACCOUNT_STORE (self),
1066 MODEST_TNY_ACCOUNT_STORE_QUERY_URL,
1073 modest_tny_account_store_alert (TnyAccountStore *self,
1074 TnyAccount *account,
1079 ModestProtocolType protocol_type = MODEST_PROTOCOL_REGISTRY_TYPE_INVALID;
1080 ModestProtocol *protocol = NULL;
1081 const gchar* server_name = "";
1082 gchar *prompt = NULL;
1083 gboolean retval = TRUE;
1085 /* NOTE: account may be NULL in some cases */
1089 /* Get the server name: */
1091 server_name = tny_account_get_hostname (account);
1092 protocol_type = modest_tny_account_get_protocol_type (account);
1093 if (protocol_type == MODEST_PROTOCOL_REGISTRY_TYPE_INVALID){
1094 g_warning("%s: account with id=%s has no proto.\n", __FUNCTION__,
1095 tny_account_get_id (account));
1098 protocol = modest_protocol_registry_get_protocol_by_type (modest_runtime_get_protocol_registry (),
1102 switch (error->code) {
1103 case TNY_SYSTEM_ERROR_CANCEL:
1104 /* Don't show waste the user's time by showing him a dialog telling
1105 * him that he has just cancelled something: */
1108 case TNY_SERVICE_ERROR_PROTOCOL:
1109 /* Like a BAD from IMAP (protocol error) */
1110 case TNY_SERVICE_ERROR_LOST_CONNECTION:
1111 /* Lost the connection with the service */
1112 case TNY_SERVICE_ERROR_UNAVAILABLE:
1113 /* You must be working online for this operation */
1114 case TNY_SERVICE_ERROR_CONNECT:
1116 prompt = modest_protocol_get_translation (protocol, MODEST_PROTOCOL_TRANSLATION_CONNECT_ERROR, server_name);
1119 g_return_val_if_reached (FALSE);
1122 case TNY_SERVICE_ERROR_AUTHENTICATE:
1123 /* It seems that there's no better error to show with
1124 * POP and IMAP because TNY_SERVICE_ERROR_AUTHENTICATE
1125 * may appear if there's a timeout during auth */
1127 prompt = modest_protocol_get_translation (protocol, MODEST_PROTOCOL_TRANSLATION_AUTH_ERROR, server_name);
1130 g_return_val_if_reached (FALSE);
1133 case TNY_SERVICE_ERROR_CERTIFICATE:
1134 /* We'll show the proper dialog later */
1137 case TNY_SYSTEM_ERROR_MEMORY:
1138 /* Can't allocate memory for this operation */
1139 if (modest_tny_account_store_check_disk_full_error ((ModestTnyAccountStore*)self,
1140 NULL, error, account, NULL))
1143 case TNY_SERVICE_ERROR_UNKNOWN:
1146 /* We don't treat this as an error, but as a not handled message. Then,
1147 * debug message, and return false */
1148 g_debug ("Unexpected error %d (%s)", error->code, error->message);
1153 if (error->code == TNY_SERVICE_ERROR_CERTIFICATE)
1154 retval = modest_platform_run_certificate_confirmation_dialog (server_name,
1156 else if (error->code == TNY_SERVICE_ERROR_AUTHENTICATE ||
1157 error->code == TNY_SERVICE_ERROR_CONNECT) {
1158 TnyDevice *device = modest_runtime_get_device ();
1161 /* If we get the connection error after establishing a
1162 proper connection then do not show the dialog as we
1163 are probably behind a firewall, or in a network
1164 with connection issues. We just keep this code to
1165 detect situations were the user does not enter the
1166 server info properly */
1167 success = modest_account_mgr_get_server_account_username_has_succeeded (modest_runtime_get_account_mgr (),
1168 tny_account_get_id (account));
1171 g_debug ("%s: %s alert received (%s)", __FUNCTION__,
1172 (error->code == TNY_SERVICE_ERROR_CONNECT) ? "connect" : "aunthenticate",
1175 modest_platform_run_information_dialog (NULL, prompt, TRUE);
1177 /* Show the account dialog. Checking the online status
1178 allows us to minimize the number of times that we
1179 incorrectly show the dialog */
1180 if (tny_device_is_online (device))
1181 show_wrong_password_dialog (account,
1182 (error->code == TNY_SERVICE_ERROR_CONNECT) ? FALSE : TRUE);
1187 g_debug ("%s: error code %d (%s", __FUNCTION__, error->code, error->message);
1197 modest_tny_account_store_init (gpointer g, gpointer iface_data)
1199 TnyAccountStoreIface *klass;
1201 g_return_if_fail (g);
1203 klass = (TnyAccountStoreIface *)g;
1205 klass->get_accounts =
1206 modest_tny_account_store_get_accounts;
1207 klass->get_cache_dir =
1208 modest_tny_account_store_get_cache_dir;
1210 modest_tny_account_store_get_device;
1212 modest_tny_account_store_alert;
1213 klass->find_account =
1214 modest_tny_account_store_find_account_by_url;
1218 modest_tny_account_store_set_get_pass_func (ModestTnyAccountStore *self,
1219 ModestTnyGetPassFunc func)
1221 /* not implemented, we use signals */
1222 g_printerr ("modest: set_get_pass_func not implemented\n");
1226 modest_tny_account_store_get_session (TnyAccountStore *self)
1228 g_return_val_if_fail (self, NULL);
1229 return MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self)->session;
1233 get_tny_account_by (TnyList *accounts,
1234 ModestTnyAccountStoreQueryType type,
1237 TnyIterator *iter = NULL;
1238 gboolean found = FALSE;
1239 TnyAccount *retval = NULL;
1241 g_return_val_if_fail (TNY_IS_LIST(accounts), NULL);
1243 if (tny_list_get_length(accounts) == 0) {
1244 g_warning ("%s: account list is empty", __FUNCTION__);
1248 iter = tny_list_create_iterator (accounts);
1249 while (!tny_iterator_is_done (iter) && !found) {
1250 TnyAccount *tmp_account = NULL;
1251 const gchar *val = NULL;
1253 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1254 if (!TNY_IS_ACCOUNT(tmp_account)) {
1255 g_warning ("%s: not a valid account", __FUNCTION__);
1261 case MODEST_TNY_ACCOUNT_STORE_QUERY_ID:
1262 val = tny_account_get_id (tmp_account);
1264 case MODEST_TNY_ACCOUNT_STORE_QUERY_URL:
1265 val = tny_account_get_url_string (tmp_account);
1269 if (type == MODEST_TNY_ACCOUNT_STORE_QUERY_URL &&
1270 tny_account_matches_url_string (tmp_account, str)) {
1271 retval = g_object_ref (tmp_account);
1274 if (val && str && strcmp (val, str) == 0) {
1275 retval = g_object_ref (tmp_account);
1279 g_object_unref (tmp_account);
1280 tny_iterator_next (iter);
1282 g_object_unref (iter);
1288 modest_tny_account_store_get_tny_account_by (ModestTnyAccountStore *self,
1289 ModestTnyAccountStoreQueryType type,
1292 TnyAccount *account = NULL;
1293 ModestTnyAccountStorePrivate *priv;
1295 g_return_val_if_fail (self, NULL);
1296 g_return_val_if_fail (str, NULL);
1298 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1300 /* Search in store accounts */
1301 account = get_tny_account_by (priv->store_accounts, type, str);
1303 /* If we already found something, no need to search the transport accounts */
1305 account = get_tny_account_by (priv->transport_accounts, type, str);
1307 /* If we already found something, no need to search the
1308 per-account outbox accounts */
1310 account = get_tny_account_by (priv->store_accounts_outboxes, type, str);
1313 /* Warn if nothing was found. This is generally unusual. */
1315 g_warning("%s: Failed to find account with %s=%s\n",
1317 (type == MODEST_TNY_ACCOUNT_STORE_QUERY_ID) ? "ID" : "URL",
1321 /* Returns a new reference to the account if found */
1327 modest_tny_account_store_get_server_account (ModestTnyAccountStore *self,
1328 const gchar *account_name,
1329 TnyAccountType type)
1331 ModestTnyAccountStorePrivate *priv = NULL;
1332 TnyAccount *retval = NULL;
1333 TnyList *account_list = NULL;
1334 TnyIterator *iter = NULL;
1337 g_return_val_if_fail (self, NULL);
1338 g_return_val_if_fail (account_name, NULL);
1339 g_return_val_if_fail (type == TNY_ACCOUNT_TYPE_STORE ||
1340 type == TNY_ACCOUNT_TYPE_TRANSPORT,
1343 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1345 account_list = (type == TNY_ACCOUNT_TYPE_STORE) ?
1346 priv->store_accounts :
1347 priv->transport_accounts;
1349 if (!account_list) {
1350 g_printerr ("%s: No server accounts of type %s\n", __FUNCTION__,
1351 (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport");
1355 /* Look for the server account */
1357 iter = tny_list_create_iterator (account_list);
1358 while (!tny_iterator_is_done (iter) && !found) {
1359 const gchar *modest_acc_name;
1360 TnyAccount *tmp_account;
1362 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1364 modest_tny_account_get_parent_modest_account_name_for_server_account (tmp_account);
1366 if (account_name && modest_acc_name && !strcmp (account_name, modest_acc_name)) {
1368 retval = g_object_ref (tmp_account);
1370 /* Free and continue */
1371 g_object_unref (tmp_account);
1372 tny_iterator_next (iter);
1374 g_object_unref (iter);
1377 g_printerr ("modest: %s: could not get tny %s account for %s\n." \
1378 "Number of server accounts of this type=%d\n", __FUNCTION__,
1379 (type == TNY_ACCOUNT_TYPE_STORE) ? "store" : "transport",
1380 account_name, tny_list_get_length (account_list));
1383 /* Returns a new reference */
1388 modest_tny_account_store_get_smtp_specific_transport_account_for_open_connection (
1389 ModestTnyAccountStore *self, const gchar *account_name)
1393 g_return_val_if_fail (self && MODEST_IS_TNY_ACCOUNT_STORE(self), NULL);
1394 g_return_val_if_fail (account_name, NULL);
1396 /* Get the current connection: */
1397 device = modest_runtime_get_device ();
1400 g_warning ("%s: could not get device", __FUNCTION__);
1404 if (!tny_device_is_online (device))
1407 #ifdef MODEST_HAVE_CONIC
1408 g_return_val_if_fail (TNY_IS_MAEMO_CONIC_DEVICE (device), NULL);
1410 TnyMaemoConicDevice *maemo_device = TNY_MAEMO_CONIC_DEVICE (device);
1411 const gchar* iap_id = tny_maemo_conic_device_get_current_iap_id (maemo_device);
1412 /* printf ("DEBUG: %s: iap_id=%s\n", __FUNCTION__, iap_id); */
1416 ConIcIap* connection = tny_maemo_conic_device_get_iap (maemo_device, iap_id);
1420 const gchar *connection_id = con_ic_iap_get_id (connection);
1421 /* printf ("DEBUG: %s: connection_id=%s\n", __FUNCTION__, connection_id); */
1425 /* Get the connection-specific transport acccount, if any: */
1426 ModestAccountMgr *account_manager = modest_runtime_get_account_mgr ();
1428 /* Check if this account has connection-specific SMTP enabled */
1429 if (!modest_account_mgr_get_use_connection_specific_smtp (account_manager, account_name)) {
1433 gchar* server_account_name = modest_account_mgr_get_connection_specific_smtp (account_manager,
1436 /* printf ("DEBUG: %s: server_account_name=%s\n", __FUNCTION__, server_account_name); */
1437 if (!server_account_name) {
1438 return NULL; /* No connection-specific SMTP server was specified for this connection. */
1441 TnyAccount* account = modest_tny_account_store_get_tny_account_by (self,
1442 MODEST_TNY_ACCOUNT_STORE_QUERY_ID,
1443 server_account_name);
1445 /* printf ("DEBUG: %s: account=%p\n", __FUNCTION__, account); */
1446 g_free (server_account_name);
1448 /* Unref the get()ed object, as required by the tny_maemo_conic_device_get_iap() documentation. */
1449 g_object_unref (connection);
1453 return NULL; /* TODO: Implement this for GNOME, instead of just Maemo? */
1454 #endif /* MODEST_HAVE_CONIC */
1459 modest_tny_account_store_get_transport_account_for_open_connection (ModestTnyAccountStore *self,
1460 const gchar *account_name)
1462 g_return_val_if_fail (self, NULL);
1463 g_return_val_if_fail (account_name, NULL);
1465 if (!account_name || !self)
1468 /* Get the connection-specific transport acccount, if any: */
1469 /* Note: This gives us a reference: */
1470 TnyAccount *account =
1471 modest_tny_account_store_get_smtp_specific_transport_account_for_open_connection (self, account_name);
1473 /* If there is no connection-specific transport account (the common case),
1474 * just get the regular transport account: */
1476 /* The special local folders don't have transport accounts. */
1477 if (strcmp (account_name, MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0)
1480 /* Note: This gives us a reference: */
1481 account = modest_tny_account_store_get_server_account (self, account_name,
1482 TNY_ACCOUNT_TYPE_TRANSPORT);
1486 /* returns a reference. */
1491 modest_tny_account_store_get_local_folders_account (ModestTnyAccountStore *self)
1493 TnyAccount *account = NULL;
1494 ModestTnyAccountStorePrivate *priv;
1498 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1500 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1503 iter = tny_list_create_iterator (priv->store_accounts);
1504 while (!tny_iterator_is_done (iter) && !found) {
1505 TnyAccount *tmp_account;
1507 tmp_account = TNY_ACCOUNT (tny_iterator_get_current (iter));
1508 if (modest_tny_account_is_virtual_local_folders (tmp_account)) {
1509 account = g_object_ref (tmp_account);
1512 g_object_unref (tmp_account);
1513 tny_iterator_next (iter);
1515 g_object_unref (iter);
1517 /* Returns a new reference to the account */
1522 modest_tny_account_store_get_mmc_folders_account (ModestTnyAccountStore *self)
1524 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
1527 return modest_tny_account_store_get_tny_account_by (self, MODEST_TNY_ACCOUNT_STORE_QUERY_ID,
1528 MODEST_MMC_ACCOUNT_ID);
1532 /*********************************************************************************/
1534 add_existing_accounts (ModestTnyAccountStore *self)
1536 GSList *account_names = NULL, *iter = NULL;
1537 ModestTnyAccountStorePrivate *priv = NULL;
1539 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1541 /* These are account names, not server_account names */
1542 account_names = modest_account_mgr_account_names (priv->account_mgr, FALSE);
1544 for (iter = account_names; iter != NULL; iter = g_slist_next (iter)) {
1545 const gchar *account_name = (const gchar*) iter->data;
1547 /* Insert all enabled accounts without notifying */
1548 if (modest_account_mgr_get_enabled (priv->account_mgr, account_name))
1549 insert_account (self, account_name, FALSE);
1551 modest_account_mgr_free_account_names (account_names);
1555 create_tny_account (ModestTnyAccountStore *self,
1557 TnyAccountType type,
1560 TnyAccount *account = NULL;
1561 ModestTnyAccountStorePrivate *priv = NULL;
1563 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1565 account = modest_tny_account_new_from_account (priv->account_mgr,
1572 /* Forget any cached password for the account, so that
1573 we use a new account if any */
1574 forget_password_in_memory (self, tny_account_get_id (account));
1576 /* Set the account store */
1577 g_object_set_data (G_OBJECT(account), "account_store", self);
1579 g_printerr ("modest: failed to create account for %s\n", name);
1585 typedef struct _AddOutboxInfo {
1586 ModestTnyAccountStore *account_store;
1587 TnyAccount *transport_account;
1591 add_outbox_from_transport_account_to_global_outbox_get_folders_cb (TnyFolderStore *folder_store,
1597 TnyIterator *iter_folders;
1598 TnyFolder *per_account_outbox;
1599 TnyAccount *local_account = NULL;
1600 AddOutboxInfo *info = (AddOutboxInfo *) userdata;
1601 ModestTnyAccountStorePrivate *priv = NULL;
1602 ModestTnyAccountStore *self;
1604 self = MODEST_TNY_ACCOUNT_STORE (info->account_store);
1605 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1607 /* Note that this could happen if there is not enough space
1608 available on disk, then the outbox folder could not be
1610 if (tny_list_get_length (list) != 1) {
1611 g_warning ("%s: could not create outbox folder (%d folders found)", __FUNCTION__,
1612 tny_list_get_length (list));
1616 iter_folders = tny_list_create_iterator (list);
1617 per_account_outbox = TNY_FOLDER (tny_iterator_get_current (iter_folders));
1618 g_object_unref (iter_folders);
1619 g_object_unref (list);
1621 /* Add the outbox of the new per-account-local-outbox account
1622 to the global local merged OUTBOX of the local folders
1624 local_account = modest_tny_account_store_get_local_folders_account (info->account_store);
1625 modest_tny_local_folders_account_add_folder_to_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1626 per_account_outbox);
1627 /* Add the pair to the hash table */
1628 g_hash_table_insert (priv->outbox_of_transport,
1629 info->transport_account,
1630 per_account_outbox);
1632 /* Notify that the local account changed */
1633 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1634 g_object_unref (local_account);
1635 g_object_unref (per_account_outbox);
1638 g_object_unref (info->transport_account);
1639 g_slice_free (AddOutboxInfo, info);
1644 add_outbox_from_transport_account_to_global_outbox (ModestTnyAccountStore *self,
1645 const gchar *account_name,
1646 TnyAccount *transport_account)
1648 TnyList *folders = NULL;
1649 TnyAccount *account_outbox = NULL;
1650 ModestTnyAccountStorePrivate *priv = NULL;
1651 AddOutboxInfo *info;
1653 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1655 /* Create per account local outbox */
1657 modest_tny_account_new_for_per_account_local_outbox_folder (priv->account_mgr,
1661 if (!G_IS_OBJECT (account_outbox)) {
1662 g_warning ("%s: could not create per account local outbox folder", __FUNCTION__);
1666 tny_list_append (priv->store_accounts_outboxes, G_OBJECT (account_outbox));
1668 /* Get the outbox folder */
1669 folders = tny_simple_list_new ();
1670 info = g_slice_new0 (AddOutboxInfo);
1671 info->account_store = self;
1672 info->transport_account = g_object_ref (transport_account);
1673 tny_folder_store_get_folders_async (TNY_FOLDER_STORE (account_outbox), folders, NULL, FALSE,
1674 add_outbox_from_transport_account_to_global_outbox_get_folders_cb, NULL, (gpointer) info);
1675 g_object_unref (account_outbox);
1679 * This function will be used for both adding new accounts and for the
1680 * initialization. In the initialization we do not want to emit
1681 * signals so notify will be FALSE, in the case of account additions
1682 * we do want to notify the observers
1685 insert_account (ModestTnyAccountStore *self,
1686 const gchar *account,
1689 ModestTnyAccountStorePrivate *priv = NULL;
1690 TnyAccount *store_account = NULL, *transport_account = NULL;
1692 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1694 /* Get the server and the transport account */
1695 store_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_STORE, is_new);
1696 if (!store_account || !TNY_IS_ACCOUNT(store_account)) {
1697 g_warning ("%s: failed to create store account", __FUNCTION__);
1701 transport_account = create_tny_account (self, account, TNY_ACCOUNT_TYPE_TRANSPORT, is_new);
1702 if (!transport_account || !TNY_IS_ACCOUNT(transport_account)) {
1703 g_warning ("%s: failed to create transport account", __FUNCTION__);
1704 g_object_unref (store_account);
1708 /* Add accounts to the lists */
1709 tny_list_append (priv->store_accounts, G_OBJECT (store_account));
1710 tny_list_append (priv->transport_accounts, G_OBJECT (transport_account));
1712 /* Create a new pseudo-account with an outbox for this
1713 transport account and add it to the global outbox
1714 in the local account */
1715 add_outbox_from_transport_account_to_global_outbox (self, account, transport_account);
1717 /* Force the creation of the send queue, this way send queues
1718 will automatically send missing emails when the connections
1720 /* Notify the observers. We do it after everything is
1723 /* We only have to do this for new accounts, already
1724 existing accounts at boot time are instantiated by
1725 modest_tny_account_store_start_send_queues */
1726 modest_runtime_get_send_queue ((TnyTransportAccount *) transport_account, TRUE);
1728 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, store_account);
1729 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_INSERTED_SIGNAL], 0, transport_account);
1733 g_object_unref (store_account);
1734 g_object_unref (transport_account);
1737 static inline gboolean
1738 only_local_accounts (ModestTnyAccountStore *self)
1740 return (modest_tny_account_store_get_num_remote_accounts (self) > 0) ? FALSE : TRUE;
1744 on_account_inserted (ModestAccountMgr *acc_mgr,
1745 const gchar *account,
1748 gboolean add_specific;
1750 add_specific = only_local_accounts (MODEST_TNY_ACCOUNT_STORE (user_data));
1752 /* Insert the account and notify the observers */
1753 insert_account (MODEST_TNY_ACCOUNT_STORE (user_data), account, TRUE);
1755 /* If it's the first remote account then add the connection
1756 specific SMTP servers as well */
1758 add_connection_specific_transport_accounts (MODEST_TNY_ACCOUNT_STORE (user_data));
1762 /* This is the callback of the tny_camel_account_set_online called in
1763 on_account_removed to disconnect the account */
1765 on_account_disconnect_when_removing (TnyCamelAccount *account,
1770 ModestTnyAccountStore *self;
1771 ModestTnyAccountStorePrivate *priv;
1773 self = MODEST_TNY_ACCOUNT_STORE (user_data);
1774 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1776 /* Cancel all pending operations */
1777 tny_account_cancel (TNY_ACCOUNT (account));
1779 /* Unref the extra reference added by get_server_account */
1780 g_object_unref (account);
1782 /* Clear the cache if it's an store account */
1783 if (TNY_IS_STORE_ACCOUNT (account)) {
1784 tny_store_account_delete_cache (TNY_STORE_ACCOUNT (account));
1785 } else if (TNY_IS_TRANSPORT_ACCOUNT (account)) {
1786 ModestTnySendQueue* send_queue;
1787 send_queue = modest_runtime_get_send_queue (TNY_TRANSPORT_ACCOUNT (account), FALSE);
1788 if (TNY_IS_SEND_QUEUE (send_queue)) {
1789 if (modest_tny_send_queue_sending_in_progress (send_queue))
1790 tny_send_queue_cancel (TNY_SEND_QUEUE (send_queue),
1791 TNY_SEND_QUEUE_CANCEL_ACTION_REMOVE,
1793 modest_runtime_remove_send_queue (TNY_TRANSPORT_ACCOUNT (account));
1799 * We use this one for both removing "normal" and "connection
1800 * specific" transport accounts
1803 remove_transport_account (ModestTnyAccountStore *self,
1804 TnyTransportAccount *transport_account)
1806 ModestTnyAccountStorePrivate *priv;
1807 TnyFolder *outbox = NULL;
1809 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1811 /* Remove it from the list of accounts and notify the
1812 observers. Do not need to wait for account
1814 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 0, transport_account);
1815 tny_list_remove (priv->transport_accounts, (GObject *) transport_account);
1817 /* Remove the OUTBOX of the account from the global outbox */
1818 outbox = g_hash_table_lookup (priv->outbox_of_transport, transport_account);
1820 if (TNY_IS_FOLDER (outbox)) {
1821 TnyAccount *local_account = NULL;
1822 TnyAccount *outbox_account = tny_folder_get_account (outbox);
1824 if (outbox_account) {
1825 tny_list_remove (priv->store_accounts_outboxes, G_OBJECT (outbox_account));
1826 /* Remove existing emails to send */
1827 tny_store_account_delete_cache (TNY_STORE_ACCOUNT (outbox_account));
1828 g_object_unref (outbox_account);
1831 local_account = modest_tny_account_store_get_local_folders_account (self);
1832 modest_tny_local_folders_account_remove_folder_from_outbox (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (local_account),
1835 g_hash_table_remove (priv->outbox_of_transport, transport_account);
1837 /* Notify the change in the local account */
1838 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_CHANGED_SIGNAL], 0, local_account);
1839 g_object_unref (local_account);
1841 g_warning ("Removing a transport account that has no outbox");
1844 /* Cancel all pending operations */
1845 tny_account_cancel (TNY_ACCOUNT (transport_account));
1847 /* Disconnect and notify the observers. The callback will free the reference */
1848 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (transport_account), FALSE,
1849 on_account_disconnect_when_removing, self);
1853 images_cache_remove_filter (TnyStreamCache *self, const gchar *id, const gchar *account_name)
1855 gchar *account_name_with_separator;
1857 if (account_name == NULL || account_name[0] == '\0')
1860 if (id == NULL || id[0] == '\0')
1863 account_name_with_separator = g_strconcat (account_name, "__", NULL);
1865 result = (g_str_has_prefix (id, account_name));
1866 g_free (account_name_with_separator);
1872 on_account_removed (ModestAccountMgr *acc_mgr,
1873 const gchar *account,
1876 TnyAccount *store_account = NULL, *transport_account = NULL;
1877 ModestTnyAccountStore *self;
1878 ModestTnyAccountStorePrivate *priv;
1879 TnyStreamCache *stream_cache;
1881 self = MODEST_TNY_ACCOUNT_STORE (user_data);
1882 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
1884 /* Get the server and the transport account */
1886 modest_tny_account_store_get_server_account (self, account,
1887 TNY_ACCOUNT_TYPE_STORE);
1889 modest_tny_account_store_get_server_account (self, account,
1890 TNY_ACCOUNT_TYPE_TRANSPORT);
1892 /* If there was any problem creating the account, for example,
1893 with the configuration system this could not exist */
1894 if (TNY_IS_STORE_ACCOUNT(store_account)) {
1895 /* Forget any cached password for the account */
1896 forget_password_in_memory (self, tny_account_get_id (store_account));
1898 /* Remove it from the list of accounts and notify the
1899 observers. Do not need to wait for account
1901 tny_list_remove (priv->store_accounts, (GObject *) store_account);
1902 g_signal_emit (G_OBJECT (self), signals [ACCOUNT_REMOVED_SIGNAL], 0, store_account);
1904 /* Cancel all pending operations */
1905 tny_account_cancel (TNY_ACCOUNT (store_account));
1907 /* Disconnect before deleting the cache, because the
1908 disconnection will rewrite the cache to the
1910 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (store_account), FALSE,
1911 on_account_disconnect_when_removing, self);
1913 g_warning ("%s: no store account for account %s\n",
1914 __FUNCTION__, account);
1917 /* If there was any problem creating the account, for example,
1918 with the configuration system this could not exist */
1919 if (TNY_IS_TRANSPORT_ACCOUNT(transport_account)) {
1921 /* Forget any cached password for the account */
1922 forget_password_in_memory (self, tny_account_get_id (transport_account));
1924 /* Remove transport account. It'll free the reference
1925 added by get_server_account */
1926 remove_transport_account (self, TNY_TRANSPORT_ACCOUNT (transport_account));
1928 g_warning ("%s: no transport account for account %s\n",
1929 __FUNCTION__, account);
1932 /* Remove cached images */
1933 stream_cache = modest_runtime_get_images_cache ();
1934 tny_stream_cache_remove (stream_cache, (TnyStreamCacheRemoveFilter) images_cache_remove_filter, (gpointer) account);
1936 /* If there are no more user accounts then delete the
1937 transport specific SMTP servers */
1938 if (only_local_accounts (self))
1939 remove_connection_specific_transport_accounts (self);
1942 TnyTransportAccount *
1943 modest_tny_account_store_new_connection_specific_transport_account (ModestTnyAccountStore *self,
1946 ModestTnyAccountStorePrivate *priv = NULL;
1947 TnyAccount * tny_account = NULL;
1949 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1951 /* Add the account: */
1953 modest_tny_account_new_from_server_account_name (priv->account_mgr,
1959 g_object_set_data (G_OBJECT(tny_account),
1962 g_object_set_data (G_OBJECT(tny_account),
1963 "connection_specific",
1964 GINT_TO_POINTER (TRUE));
1966 tny_list_append (priv->transport_accounts, G_OBJECT (tny_account));
1967 add_outbox_from_transport_account_to_global_outbox (self,
1972 g_printerr ("modest: failed to create smtp-specific account for %s\n",
1975 return TNY_TRANSPORT_ACCOUNT (tny_account);
1979 foreach_free_string(gpointer data,
1986 add_connection_specific_transport_accounts (ModestTnyAccountStore *self)
1988 ModestTnyAccountStorePrivate *priv = NULL;
1989 GSList *list_specifics = NULL, *iter = NULL;
1992 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
1994 list_specifics = modest_conf_get_list (modest_runtime_get_conf (),
1995 MODEST_CONF_CONNECTION_SPECIFIC_SMTP_LIST,
1996 MODEST_CONF_VALUE_STRING, &err);
1999 g_return_if_reached ();
2003 /* Look at each connection-specific transport account for the
2004 * modest account: */
2005 iter = list_specifics;
2007 /* The list alternates between the connection name and the transport name: */
2008 iter = g_slist_next (iter);
2010 const gchar* transport_account_name = (const gchar*) (iter->data);
2011 TnyTransportAccount * account = NULL;
2012 account = modest_tny_account_store_new_connection_specific_transport_account (
2013 self, transport_account_name);
2015 g_object_unref (account);
2017 iter = g_slist_next (iter);
2021 g_slist_foreach (list_specifics, foreach_free_string, NULL);
2022 g_slist_free (list_specifics);
2026 remove_connection_specific_transport_accounts (ModestTnyAccountStore *self)
2028 ModestTnyAccountStorePrivate *priv = NULL;
2029 GSList *list_specifics = NULL, *iter = NULL;
2032 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
2035 list_specifics = modest_conf_get_list (modest_runtime_get_conf (),
2036 MODEST_CONF_CONNECTION_SPECIFIC_SMTP_LIST,
2037 MODEST_CONF_VALUE_STRING, &err);
2040 g_return_if_reached ();
2044 /* Look at each connection-specific transport account for the
2045 * modest account: */
2046 iter = list_specifics;
2048 /* The list alternates between the connection name and the transport name: */
2049 iter = g_slist_next (iter);
2051 const gchar* transport_account_name = (const gchar*) (iter->data);
2052 TnyAccount * account;
2053 account = modest_tny_account_store_get_server_account (self,
2054 transport_account_name,
2055 TNY_ACCOUNT_TYPE_TRANSPORT);
2057 /* the call will free the reference */
2059 remove_transport_account (self, TNY_TRANSPORT_ACCOUNT (account));
2061 iter = g_slist_next (iter);
2065 g_slist_foreach (list_specifics, foreach_free_string, NULL);
2066 g_slist_free (list_specifics);
2071 modest_tny_account_store_find_msg_in_outboxes (ModestTnyAccountStore *self,
2073 TnyAccount **ac_out)
2075 TnyIterator *acc_iter;
2076 ModestTnyAccountStorePrivate *priv;
2078 TnyAccount *msg_account = NULL;
2080 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
2081 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2083 acc_iter = tny_list_create_iterator (priv->store_accounts_outboxes);
2084 while (!msg && !tny_iterator_is_done (acc_iter)) {
2085 TnyList *folders = tny_simple_list_new ();
2086 TnyAccount *account = TNY_ACCOUNT (tny_iterator_get_current (acc_iter));
2087 TnyIterator *folders_iter = NULL;
2089 tny_folder_store_get_folders (TNY_FOLDER_STORE (account), folders, NULL, FALSE, NULL);
2090 folders_iter = tny_list_create_iterator (folders);
2092 while (msg == NULL && !tny_iterator_is_done (folders_iter)) {
2093 TnyFolder *folder = TNY_FOLDER (tny_iterator_get_current (folders_iter));
2094 msg = tny_folder_find_msg (folder, uri, NULL);
2097 msg_account = g_object_ref (account);
2099 g_object_unref (folder);
2100 tny_iterator_next (folders_iter);
2102 g_object_unref (folders_iter);
2104 g_object_unref (folders);
2105 g_object_unref (account);
2106 tny_iterator_next (acc_iter);
2109 g_object_unref (acc_iter);
2112 *ac_out = msg_account;
2117 TnyTransportAccount *
2118 modest_tny_account_store_get_transport_account_from_outbox_header(ModestTnyAccountStore *self, TnyHeader *header)
2120 TnyIterator *acc_iter;
2121 ModestTnyAccountStorePrivate *priv;
2122 TnyTransportAccount *header_acc = NULL;
2125 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), NULL);
2126 g_return_val_if_fail (TNY_IS_HEADER (header), NULL);
2127 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2128 msg_id = modest_tny_send_queue_get_msg_id (header);
2129 acc_iter = tny_list_create_iterator (priv->transport_accounts);
2130 while (!header_acc && !tny_iterator_is_done (acc_iter)) {
2131 TnyTransportAccount *account = TNY_TRANSPORT_ACCOUNT (tny_iterator_get_current (acc_iter));
2132 ModestTnySendQueue *send_queue;
2133 ModestTnySendQueueStatus status;
2134 send_queue = modest_runtime_get_send_queue(TNY_TRANSPORT_ACCOUNT(account), TRUE);
2135 if (TNY_IS_SEND_QUEUE (send_queue)) {
2136 status = modest_tny_send_queue_get_msg_status(send_queue, msg_id);
2137 if (status != MODEST_TNY_SEND_QUEUE_UNKNOWN)
2138 header_acc = g_object_ref(account);
2140 g_object_unref (account);
2141 tny_iterator_next (acc_iter);
2143 g_object_unref(acc_iter);
2151 ModestTnyAccountStore *account_store;
2152 ModestTnyAccountStoreShutdownCallback callback;
2158 account_shutdown_callback (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer userdata)
2160 ShutdownOpData *op_data = (ShutdownOpData *) userdata;
2162 if (op_data->pending == 0) {
2163 if (op_data->callback)
2164 op_data->callback (op_data->account_store, op_data->userdata);
2165 g_object_unref (op_data->account_store);
2171 account_shutdown (TnyAccount *account, ShutdownOpData *op_data)
2173 g_return_if_fail (account && TNY_IS_ACCOUNT(account));
2175 if (TNY_IS_STORE_ACCOUNT (account) &&
2176 !modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
2181 /* Disconnect account */
2182 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT(account), FALSE,
2183 account_shutdown_callback, op_data);
2189 modest_tny_account_store_shutdown (ModestTnyAccountStore *self,
2190 ModestTnyAccountStoreShutdownCallback callback,
2194 ShutdownOpData *op_data;
2195 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2197 /* Get references */
2199 if (priv->store_accounts)
2200 num_accounts += tny_list_get_length (priv->store_accounts);
2201 if (priv->transport_accounts)
2202 num_accounts += tny_list_get_length (priv->transport_accounts);
2204 /* Create the helper object */
2205 op_data = g_new0 (ShutdownOpData, 1);
2206 op_data->callback = callback;
2207 op_data->userdata = userdata;
2208 op_data->pending = num_accounts;
2209 op_data->account_store = g_object_ref (self);
2211 /* Force the TnyDevice to be offline. This way new
2212 undesired connections won't be initiated */
2213 tny_device_force_offline (priv->device);
2215 /* Destroy all accounts. Disconnect all accounts before they are destroyed */
2216 if (priv->store_accounts) {
2217 tny_list_foreach (priv->store_accounts, (GFunc)account_shutdown, op_data);
2220 if (priv->transport_accounts) {
2221 tny_list_foreach (priv->transport_accounts, (GFunc)account_shutdown, op_data);
2224 if (op_data->pending == 0) {
2225 if (op_data->callback)
2226 op_data->callback (op_data->account_store, op_data->userdata);
2227 g_object_unref (op_data->account_store);
2233 modest_tny_account_store_is_shutdown (ModestTnyAccountStore *self)
2235 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2241 for (iter = tny_list_create_iterator (priv->store_accounts);
2242 !found && !tny_iterator_is_done (iter);
2243 tny_iterator_next (iter)) {
2244 TnyAccount *account;
2246 account = (TnyAccount *) tny_iterator_get_current (iter);
2247 if (TNY_IS_ACCOUNT (account)) {
2248 found = (tny_account_get_connection_status (account) == TNY_CONNECTION_STATUS_CONNECTED) ||
2249 (tny_account_get_connection_status (account) == TNY_CONNECTION_STATUS_RECONNECTING);
2251 g_object_unref (account);
2253 g_object_unref (iter);
2258 for (iter = tny_list_create_iterator (priv->transport_accounts);
2259 !found && !tny_iterator_is_done (iter);
2260 tny_iterator_next (iter)) {
2261 TnyAccount *account;
2263 account = (TnyAccount *) tny_iterator_get_current (iter);
2264 if (TNY_IS_ACCOUNT (account)) {
2265 found = (tny_account_get_connection_status (account) == TNY_CONNECTION_STATUS_CONNECTED) ||
2266 (tny_account_get_connection_status (account) == TNY_CONNECTION_STATUS_RECONNECTING);
2268 g_object_unref (account);
2270 g_object_unref (iter);
2278 modest_tny_account_store_is_send_mail_blocked (ModestTnyAccountStore *self)
2280 ModestTnyAccountStorePrivate *priv;
2282 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
2284 return priv->send_mail_blocked;
2288 modest_tny_account_store_set_send_mail_blocked (ModestTnyAccountStore *self,
2291 ModestTnyAccountStorePrivate *priv;
2293 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
2295 priv->send_mail_blocked = blocked;
2299 count_remote_accounts (gpointer data, gpointer user_data)
2301 TnyFolderStore *account = TNY_FOLDER_STORE (data);
2302 gint *count = (gint *) user_data;
2304 if (modest_tny_folder_store_is_remote (account))
2309 modest_tny_account_store_get_num_remote_accounts (ModestTnyAccountStore *self)
2311 ModestTnyAccountStorePrivate *priv;
2314 g_return_val_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self), 0);
2316 /* Count remote accounts */
2317 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2318 tny_list_foreach (priv->store_accounts, (GFunc) count_remote_accounts, &count);
2324 init_send_queue (TnyAccount *account, gpointer user_data)
2326 modest_runtime_get_send_queue ((TnyTransportAccount *) account, TRUE);
2330 modest_tny_account_store_start_send_queues (ModestTnyAccountStore *self)
2332 ModestTnyAccountStorePrivate *priv;
2335 g_return_if_fail (MODEST_IS_TNY_ACCOUNT_STORE (self));
2337 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
2339 /* We need to create a copy of the list because if the send
2340 queues are created they'll directly access to the TnyList
2341 of transport accounts, and thus we'll end up blocked in the
2342 mutex the TnyList uses to synchronize accesses */
2343 tmp = tny_list_copy (priv->transport_accounts);
2345 /* Just instantiate them. They'll begin to listen for
2346 connection changes to send messages ASAP */
2347 tny_list_foreach (tmp, (GFunc) init_send_queue, NULL);
2348 g_object_unref (tmp);
2353 modest_tny_account_store_check_disk_full_error (ModestTnyAccountStore *self,
2354 GtkWidget *parent_window,
2356 TnyAccount *account,
2357 const gchar *alternate)
2362 if (modest_tny_account_store_is_disk_full_error (self, err, account)) {
2363 gboolean is_mcc = modest_tny_account_is_memory_card_account (account);
2364 if (is_mcc && alternate) {
2365 modest_platform_information_banner (parent_window, NULL, alternate);
2367 gchar *msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
2368 modest_platform_information_banner (parent_window, NULL, msg);
2371 } else if (err->code == TNY_SYSTEM_ERROR_MEMORY)
2372 /* If the account was created in memory full
2373 conditions then tinymail won't be able to
2374 connect so it'll return this error code */
2375 modest_platform_information_banner (parent_window,
2376 NULL, _("emev_ui_imap_inbox_select_error"));
2384 modest_tny_account_store_is_disk_full_error (ModestTnyAccountStore *self,
2386 TnyAccount *account)
2388 gboolean enough_free_space = TRUE;
2389 GnomeVFSURI *cache_dir_uri;
2390 const gchar *cache_dir = NULL;
2391 GnomeVFSFileSize free_space;
2393 /* Cache dir is different in case we're using an external storage (like MMC account) */
2394 if (account && modest_tny_account_is_memory_card_account (account))
2395 cache_dir = g_getenv (MODEST_MMC1_VOLUMEPATH_ENV);
2397 /* Get the default local cache dir */
2399 cache_dir = tny_account_store_get_cache_dir ((TnyAccountStore *) self);
2401 cache_dir_uri = gnome_vfs_uri_new (cache_dir);
2402 if (cache_dir_uri) {
2403 if (gnome_vfs_get_volume_free_space (cache_dir_uri, &free_space) == GNOME_VFS_OK) {
2404 if (free_space < MODEST_TNY_ACCOUNT_STORE_MIN_FREE_SPACE)
2405 enough_free_space = FALSE;
2407 gnome_vfs_uri_unref (cache_dir_uri);
2410 if ((error->code == TNY_SYSTEM_ERROR_MEMORY ||
2411 /* When asking for a mail and no space left on device
2412 tinymail returns this error */
2413 error->code == TNY_SERVICE_ERROR_MESSAGE_NOT_AVAILABLE ||
2414 /* When the folder summary could not be read or
2416 error->code == TNY_IO_ERROR_WRITE ||
2417 error->code == TNY_IO_ERROR_READ) &&
2418 !enough_free_space) {
2426 modest_tny_account_store_reset_attempt_count (ModestTnyAccountStore *self,
2427 TnyAccount *account)
2429 ModestTnyAccountStorePrivate *priv;
2430 PwdAttempt *attempt;
2432 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
2434 /* Reset the count */
2435 attempt = g_hash_table_lookup (priv->password_hash, tny_account_get_id (account));
2437 attempt->count = RETRY_ATTEMPTS;
2438 g_debug ("%s, reseting the attempt count for account %s", __FUNCTION__, tny_account_get_id (account));