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 /* modest-tny-account-store.c */
35 #include <tny-account-iface.h>
36 #include <tny-account-store-iface.h>
37 #include <tny-store-account-iface.h>
38 #include <tny-transport-account-iface.h>
39 #include <tny-device-iface.h>
40 #include <tny-device.h>
41 #include <tny-account-store.h>
43 #include <tny-store-account.h>
44 #include <tny-transport-account.h>
46 #include "modest-account-mgr.h"
47 #include "modest-tny-account-store.h"
49 /* 'private'/'protected' functions */
50 static void modest_tny_account_store_class_init (ModestTnyAccountStoreClass *klass);
51 static void modest_tny_account_store_init (ModestTnyAccountStore *obj);
52 static void modest_tny_account_store_finalize (GObject *obj);
54 /* implementations for tny-account-store-iface */
55 static void modest_tny_account_store_iface_init (gpointer g_iface, gpointer iface_data);
57 static void modest_tny_account_store_add_store_account (TnyAccountStoreIface *self,
58 TnyStoreAccountIface *account);
59 static void modest_tny_account_store_add_transport_account (TnyAccountStoreIface *self,
60 TnyTransportAccountIface *account);
61 static const GList* modest_tny_account_store_get_store_accounts (TnyAccountStoreIface *iface);
62 static const GList* modest_tny_account_store_get_transport_accounts (TnyAccountStoreIface *iface);
66 PASSWORD_REQUESTED_SIGNAL,
76 static const gchar *transport_protocols[] = { "smtp", NULL };
78 typedef struct _ModestTnyAccountStorePrivate ModestTnyAccountStorePrivate;
79 struct _ModestTnyAccountStorePrivate {
82 GMutex *transport_lock;
83 GList *store_accounts;
84 GList *transport_accounts;
87 TnySessionCamel *tny_session_camel;
88 TnyDeviceIface *device;
90 ModestAccountMgr *modest_acc_mgr;
92 ModestTnyGetPassFunc get_pass_func;
94 #define MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
95 MODEST_TYPE_TNY_ACCOUNT_STORE, \
96 ModestTnyAccountStorePrivate))
98 static GObjectClass *parent_class = NULL;
100 static guint signals[LAST_SIGNAL] = {0};
103 modest_tny_account_store_get_type (void)
105 static GType my_type = 0;
107 static const GTypeInfo my_info = {
108 sizeof(ModestTnyAccountStoreClass),
109 NULL, /* base init */
110 NULL, /* base finalize */
111 (GClassInitFunc) modest_tny_account_store_class_init,
112 NULL, /* class finalize */
113 NULL, /* class data */
114 sizeof(ModestTnyAccountStore),
116 (GInstanceInitFunc) modest_tny_account_store_init,
119 static const GInterfaceInfo iface_info = {
120 (GInterfaceInitFunc) modest_tny_account_store_iface_init,
121 NULL, /* interface_finalize */
122 NULL /* interface_data */
125 my_type = g_type_register_static (TNY_TYPE_ACCOUNT_STORE,
126 "ModestTnyAccountStore", &my_info, 0);
128 g_type_add_interface_static (my_type, TNY_TYPE_ACCOUNT_STORE_IFACE,
135 modest_tny_account_store_class_init (ModestTnyAccountStoreClass *klass)
137 GObjectClass *gobject_class;
138 gobject_class = (GObjectClass*) klass;
140 parent_class = g_type_class_peek_parent (klass);
141 gobject_class->finalize = modest_tny_account_store_finalize;
143 g_type_class_add_private (gobject_class,
144 sizeof(ModestTnyAccountStorePrivate));
146 signals[PASSWORD_REQUESTED_SIGNAL] =
147 g_signal_new ("password_requested",
148 G_TYPE_FROM_CLASS (gobject_class),
150 G_STRUCT_OFFSET(ModestTnyAccountStoreClass, password_requested),
152 g_cclosure_marshal_VOID__POINTER,
153 G_TYPE_NONE, 1, G_TYPE_POINTER);
157 modest_tny_account_store_init (ModestTnyAccountStore *obj)
159 ModestTnyAccountStorePrivate *priv =
160 MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
162 priv->modest_acc_mgr = NULL;
165 priv->store_lock = NULL;
166 priv->transport_lock = NULL;
167 priv->store_accounts = NULL;
168 priv->transport_accounts = NULL;
169 priv->cache_dir = NULL;
171 priv->tny_session_camel = NULL;
172 /* Meaning: if not indicated otherwise, we have valid password data */
173 priv->pw_invalid = PW_NOT_INVALID;
174 priv->get_pass_func = NULL;
179 free_gobject (GObject *obj, gpointer user_data)
182 g_object_unref (obj);
187 free_gobject_list (GList *list)
190 g_list_foreach (list, (GFunc)free_gobject, NULL);
197 get_password (TnyAccountIface *account,
202 const TnyAccountStoreIface *account_store;
203 ModestTnyAccountStore *self;
204 ModestTnyAccountStorePrivate *priv;
207 g_return_val_if_fail (account, NULL);
209 key = tny_account_iface_get_id (account);
210 account_store = tny_account_iface_get_account_store(account);
212 self = MODEST_TNY_ACCOUNT_STORE (account_store);
213 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
215 if (priv->pw_invalid==PW_NOT_INVALID) {
216 retval = modest_account_mgr_get_server_account_string (priv->modest_acc_mgr,
218 MODEST_ACCOUNT_PASSWORD,
221 retval = priv->get_pass_func(account, prompt, cancel);
224 priv->pw_invalid=PW_NOT_INVALID;
225 modest_account_mgr_set_server_account_string(priv->modest_acc_mgr,
227 MODEST_ACCOUNT_PASSWORD,
237 forget_password (TnyAccountIface *account) {
239 ModestTnyAccountStore *self;
240 ModestTnyAccountStorePrivate *priv;
241 const TnyAccountStoreIface *account_store;
243 account_store = tny_account_iface_get_account_store(account);
244 self = MODEST_TNY_ACCOUNT_STORE (account_store);
245 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
247 priv->pw_invalid=PW_INVALID;
251 static TnyAccountIface*
252 tny_account_from_key (ModestTnyAccountStore *self, const gchar *key,
255 TnyAccountIface *tny_account;
256 ModestTnyAccountStorePrivate *priv;
259 g_return_val_if_fail (self, NULL);
260 g_return_val_if_fail (key, NULL);
262 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
264 /* is it a store or a transport? */
266 tny_account = TNY_ACCOUNT_IFACE(tny_store_account_new ());
268 tny_account = TNY_ACCOUNT_IFACE(tny_transport_account_new ());
271 g_warning ("failed to create new tny %s account",
272 is_store ? "store" : "transport");
276 tny_account_iface_set_account_store (TNY_ACCOUNT_IFACE(tny_account),
277 TNY_ACCOUNT_STORE_IFACE(self));
279 tny_account_iface_set_id (tny_account, key);
280 tny_account_iface_set_name (tny_account, key);
283 val = modest_account_mgr_get_server_account_string (priv->modest_acc_mgr, key,
284 MODEST_ACCOUNT_PROTO, NULL);
286 tny_account_iface_set_proto (tny_account, val);
289 g_warning ("protocol not defined for %s", key);
290 g_object_unref (G_OBJECT(tny_account));
295 val = modest_account_mgr_get_server_account_string (priv->modest_acc_mgr, key,
296 MODEST_ACCOUNT_HOSTNAME,
299 tny_account_iface_set_hostname (tny_account, val);
305 val = modest_account_mgr_get_server_account_string (priv->modest_acc_mgr, key,
306 MODEST_ACCOUNT_USERNAME,
309 tny_account_iface_set_user (tny_account, val);
313 tny_account_iface_set_pass_func (tny_account, get_password);
314 tny_account_iface_set_forget_pass_func (tny_account, forget_password);
321 tny_accounts_from_server_accounts (ModestTnyAccountStore *self, GSList *accounts,
324 GSList *cursor = accounts;
325 GList *tny_accounts = NULL;
327 g_return_val_if_fail (self, NULL);
330 TnyAccountIface *tny_account;
331 tny_account = tny_account_from_key (self, (gchar*)cursor->data,
334 g_warning ("could not create tnyaccount for %s",
335 (gchar*)cursor->data);
338 g_list_append (tny_accounts, tny_account);
340 cursor = cursor->next;
348 manager_new_account (ModestAccountMgr *modest_acc_mgr, gchar *name, gpointer data)
350 ModestTnyAccountStore *self = data;
351 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
352 TnyAccountIface *new_account;
355 gboolean is_store = TRUE;
357 g_print ("new account signal %s\n", name);
359 proto = modest_account_mgr_get_server_account_string (priv->modest_acc_mgr, name,
360 MODEST_ACCOUNT_PROTO, NULL);
362 g_printerr ("Cannot add account: unknown type.");
366 while (transport_protocols [i]) {
367 if (!strcmp (transport_protocols [i], proto)) {
374 /* fill account lists */
375 if (!priv->store_accounts)
376 modest_tny_account_store_get_store_accounts (TNY_ACCOUNT_STORE_IFACE(self));
377 if (!priv->transport_accounts)
378 modest_tny_account_store_get_transport_accounts (TNY_ACCOUNT_STORE_IFACE(self));
382 new_account = tny_account_from_key (self, name, is_store);
383 g_mutex_lock (priv->store_lock);
384 priv->store_accounts = g_list_append (priv->store_accounts, new_account);
385 g_mutex_unlock (priv->store_lock);
387 new_account = tny_account_from_key (self, name, is_store);
388 g_mutex_lock (priv->transport_lock);
389 priv->transport_accounts = g_list_append (priv->transport_accounts, new_account);
390 g_mutex_unlock (priv->transport_lock);
393 tny_account_store_iface_signals [TNY_ACCOUNT_STORE_IFACE_ACCOUNT_INSERTED], 0, new_account);
398 manager_remove_account (ModestAccountMgr *modest_acc_mgr, gchar *name, gpointer data)
400 g_print ("remove account signal %s\n", name);
405 manager_change_account (ModestAccountMgr *modest_acc_mgr, gchar *accountname,
406 gchar *key, gchar* value, gpointer data)
408 ModestTnyAccountStore *self = data;
409 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
411 TnyAccountIface *account = NULL;
413 g_print ("account change signal: account: %s key: %s value: %s\n", accountname, key, value);
415 /* fill account lists */
416 if (!priv->store_accounts)
417 modest_tny_account_store_get_store_accounts (TNY_ACCOUNT_STORE_IFACE(self));
418 if (!priv->transport_accounts)
419 modest_tny_account_store_get_transport_accounts (TNY_ACCOUNT_STORE_IFACE(self));
421 for (iter = priv->store_accounts; iter; iter = iter->next) {
422 TnyAccountIface *acc = iter->data;
423 if (!strcmp (tny_account_iface_get_name (acc), accountname)) {
430 for (iter = priv->transport_accounts; iter; iter = iter->next) {
431 TnyAccountIface *acc = iter->data;
432 if (!strcmp (tny_account_iface_get_name (acc), accountname)) {
439 g_printerr ("Couldn't find account - returning without applying changes.");
443 g_mutex_lock (priv->store_lock);
444 g_mutex_lock (priv->transport_lock);
446 if (!strcmp (key, MODEST_ACCOUNT_HOSTNAME))
447 tny_account_iface_set_hostname (account, value);
448 if (!strcmp (key, MODEST_ACCOUNT_USERNAME))
449 tny_account_iface_set_user (account, value);
451 g_mutex_unlock (priv->transport_lock);
452 g_mutex_unlock (priv->store_lock);
454 /* TODO: handle protocol and password changes */
456 tny_account_store_iface_signals [TNY_ACCOUNT_STORE_IFACE_ACCOUNTS_RELOADED], 0);
461 modest_tny_account_store_finalize (GObject *obj)
463 ModestTnyAccountStore *self = MODEST_TNY_ACCOUNT_STORE(obj);
464 ModestTnyAccountStorePrivate *priv =
465 MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
467 g_signal_handlers_disconnect_by_func (G_OBJECT (priv->modest_acc_mgr),
468 G_CALLBACK(manager_new_account), NULL);
469 g_signal_handlers_disconnect_by_func (G_OBJECT (priv->modest_acc_mgr),
470 G_CALLBACK(manager_remove_account), NULL);
471 g_signal_handlers_disconnect_by_func (G_OBJECT (priv->modest_acc_mgr),
472 G_CALLBACK(manager_change_account), NULL);
474 if (priv->modest_acc_mgr) {
475 g_object_unref (G_OBJECT(priv->modest_acc_mgr));
476 priv->modest_acc_mgr = NULL;
479 if (priv->tny_session_camel) {
480 g_object_unref (G_OBJECT(priv->tny_session_camel));
481 priv->tny_session_camel = NULL;
485 g_object_unref (G_OBJECT(priv->device));
489 g_mutex_lock (priv->store_lock);
490 priv->store_accounts = free_gobject_list (priv->store_accounts);
491 g_mutex_unlock (priv->store_lock);
493 g_mutex_lock (priv->transport_lock);
494 priv->transport_accounts = free_gobject_list (priv->store_accounts);
495 g_mutex_unlock (priv->transport_lock);
498 g_mutex_free (priv->store_lock);
499 g_mutex_free (priv->transport_lock);
501 g_free (priv->cache_dir);
502 priv->cache_dir = NULL;
508 modest_tny_account_store_new (ModestAccountMgr *modest_acc_mgr) {
511 ModestTnyAccountStorePrivate *priv;
513 g_return_val_if_fail (modest_acc_mgr, NULL);
515 obj = G_OBJECT(g_object_new(MODEST_TYPE_TNY_ACCOUNT_STORE, NULL));
517 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(obj);
519 g_object_ref(G_OBJECT(modest_acc_mgr));
520 priv->modest_acc_mgr = modest_acc_mgr;
522 priv->store_lock = g_mutex_new ();
523 priv->transport_lock = g_mutex_new ();
525 priv->device = (TnyDeviceIface*)tny_device_new();
527 g_warning ("Cannot create Device instance");
528 g_object_unref (obj);
531 priv->tny_session_camel = tny_session_camel_new
532 (TNY_ACCOUNT_STORE_IFACE(obj));
533 if (!priv->tny_session_camel) {
534 g_warning ("Cannot create TnySessionCamel instance");
535 g_object_unref (obj);
539 g_signal_connect (G_OBJECT (modest_acc_mgr), "account-add",
540 G_CALLBACK(manager_new_account), obj);
541 g_signal_connect (G_OBJECT (modest_acc_mgr), "account-remove",
542 G_CALLBACK(manager_remove_account), obj);
543 g_signal_connect (G_OBJECT (modest_acc_mgr), "account-change",
544 G_CALLBACK(manager_change_account), obj);
551 add_account (TnyAccountStoreIface *self, TnyAccountIface *account) {
553 TnyAccountIface *account_iface;
554 ModestTnyAccountStore *account_store;
555 ModestTnyAccountStorePrivate *priv;
557 const gchar *account_name;
558 const gchar *hostname, *username, *proto;
560 g_return_val_if_fail (self, FALSE);
561 g_return_val_if_fail (account, FALSE);
563 account_iface = TNY_ACCOUNT_IFACE(account);
564 account_store = MODEST_TNY_ACCOUNT_STORE(self);
565 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
567 account_name = tny_account_iface_get_id(account_iface);
569 g_warning ("failed to retrieve account name");
573 hostname = tny_account_iface_get_hostname(account_iface);
574 username = tny_account_iface_get_user(account_iface);
575 proto = tny_account_iface_get_proto(account_iface);
577 return modest_account_mgr_add_server_account (priv->modest_acc_mgr,
579 hostname, username, NULL,
585 modest_tny_account_store_add_store_account (TnyAccountStoreIface *self,
586 TnyStoreAccountIface *account)
588 if (!add_account (self, TNY_ACCOUNT_IFACE(account)))
589 g_warning ("failed to add store account");
594 modest_tny_account_store_add_transport_account (TnyAccountStoreIface *self,
595 TnyTransportAccountIface *account)
597 if (!add_account (self, TNY_ACCOUNT_IFACE(account)))
598 g_warning ("failed to add transport account");
603 modest_tny_account_store_get_store_accounts (TnyAccountStoreIface *iface)
605 ModestTnyAccountStore *self;
606 ModestTnyAccountStorePrivate *priv;
609 g_return_val_if_fail (iface, NULL);
611 self = MODEST_TNY_ACCOUNT_STORE(iface);
612 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
614 if (!priv->store_accounts) {
616 modest_account_mgr_server_account_names (priv->modest_acc_mgr,
618 MODEST_PROTO_TYPE_STORE,
621 g_mutex_lock (priv->store_lock);
622 priv->store_accounts = tny_accounts_from_server_accounts (self, accounts, TRUE);
623 g_mutex_unlock (priv->store_lock);
624 g_slist_free (accounts);
627 return priv->store_accounts;
632 modest_tny_account_store_get_transport_accounts (TnyAccountStoreIface *iface)
634 ModestTnyAccountStore *self;
635 ModestTnyAccountStorePrivate *priv;
638 g_return_val_if_fail (iface, NULL);
640 self = MODEST_TNY_ACCOUNT_STORE(iface);
641 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
644 if (!priv->transport_accounts) {
646 modest_account_mgr_server_account_names (priv->modest_acc_mgr,
648 MODEST_PROTO_TYPE_TRANSPORT,
650 g_mutex_lock (priv->transport_lock);
651 priv->transport_accounts = tny_accounts_from_server_accounts (self, accounts, FALSE);
652 g_mutex_unlock (priv->transport_lock);
653 g_slist_free (accounts);
657 return priv->transport_accounts;
662 *modest_tny_account_store_get_accout_mgr(ModestTnyAccountStore *self)
664 ModestTnyAccountStorePrivate *priv;
665 g_return_val_if_fail (self, NULL);
667 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
669 return priv->modest_acc_mgr;
674 tny_account_store_get_session (TnyAccountStore *self)
676 ModestTnyAccountStorePrivate *priv;
677 g_return_val_if_fail (self, NULL);
679 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
681 return priv->tny_session_camel;
686 * modest_tny_account_store_get_cache_dir:
687 * @self: self a TnyAccountStoreIface instance
689 * returns the pathname of the cache directory
691 * Returns: a string with the value of the pathname
692 * to the cache directory or NULL if the environment variable $HOME is
693 * not set. string should _not_ be freed by caller
696 modest_tny_account_store_get_cache_dir (TnyAccountStoreIface *self)
698 ModestTnyAccountStorePrivate *priv;
699 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
701 if (!priv->cache_dir) {
702 if (g_getenv("HOME") != NULL)
703 priv->cache_dir = g_strconcat(g_getenv("HOME"),
704 "/.modest/cache/", NULL);
706 return priv->cache_dir;
710 static const TnyDeviceIface*
711 modest_tny_account_store_get_device (TnyAccountStoreIface *self)
713 ModestTnyAccountStorePrivate *priv;
715 priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE (self);
722 modest_tny_account_store_iface_init (gpointer g_iface, gpointer iface_data)
724 TnyAccountStoreIfaceClass *klass;
726 g_return_if_fail (g_iface);
728 klass = (TnyAccountStoreIfaceClass *)g_iface;
730 klass->add_store_account_func =
731 modest_tny_account_store_add_store_account;
732 klass->get_store_accounts_func =
733 modest_tny_account_store_get_store_accounts;
734 klass->add_transport_account_func =
735 modest_tny_account_store_add_transport_account;
736 klass->get_transport_accounts_func =
737 modest_tny_account_store_get_transport_accounts;
738 klass->get_cache_dir_func =
739 modest_tny_account_store_get_cache_dir;
740 klass->get_device_func =
741 modest_tny_account_store_get_device;
745 modest_tny_account_store_set_get_pass_func (ModestTnyAccountStore *self, ModestTnyGetPassFunc func) {
747 ModestTnyAccountStorePrivate *priv = MODEST_TNY_ACCOUNT_STORE_GET_PRIVATE(self);
749 priv->get_pass_func=func;