accounts-qt 1.17
account.cpp
1/* vi: set et sw=4 ts=4 cino=t0,(0: */
2/*
3 * This file is part of libaccounts-qt
4 *
5 * Copyright (C) 2009-2011 Nokia Corporation.
6 * Copyright (C) 2012-2016 Canonical Ltd.
7 *
8 * Contact: Alberto Mardegan <alberto.mardegan@canonical.com>
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public License
12 * version 2.1 as published by the Free Software Foundation.
13 *
14 * This library is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22 * 02110-1301 USA
23 */
24
25#include "account.h"
26#include "manager.h"
27#include "manager_p.h"
28#include "utils.h"
29
30#include <QPointer>
31#include <libaccounts-glib.h>
32
33namespace Accounts {
34
75class Account::Private
76{
77public:
78 Private(Manager *manager, const QString &providerName, Account *account);
79 Private(Manager *manager, AgAccount *agAccount);
80
81 ~Private()
82 {
83 g_cancellable_cancel(m_cancellable);
84 g_object_unref(m_cancellable);
85 m_cancellable = NULL;
86 }
87
88 void init(Account *account);
89
90 QPointer<Manager> m_manager;
91 AgAccount *m_account; //real account
92 GCancellable *m_cancellable;
93 QString prefix;
94
95 static void on_display_name_changed(Account *self);
96 static void on_enabled(Account *self, const gchar *service_name,
97 gboolean enabled);
98 static void account_store_cb(AgAccount *account,
99 GAsyncResult *res,
100 Account *self);
101 static void on_deleted(Account *self);
102};
103
104class Watch::Private
105{
106public:
107 static void account_notify_cb(AgAccount *account, const gchar *key,
108 Watch *self);
109};
110} //namespace Accounts
111
112
113using namespace Accounts;
114
115static QChar slash = QChar::fromLatin1('/');
116
126Watch::Watch(QObject *parent):
127 QObject(parent)
128{
129}
130
131Watch::~Watch()
132{
133 Account *account = qobject_cast<Account *>(QObject::parent());
134 /* The destructor of Account deletes the child Watches before detaching
135 * them, so here account should always be not NULL */
136 Q_ASSERT(account != NULL);
137 ag_account_remove_watch(account->d->m_account, watch);
138}
139
140Account::Private::Private(Manager *manager, const QString &providerName,
141 Account *account):
142 m_manager(manager),
143 m_cancellable(g_cancellable_new())
144{
145 m_account = ag_manager_create_account(manager->d->m_manager,
146 providerName.toUtf8().constData());
147 init(account);
148}
149
150Account::Private::Private(Manager *manager, AgAccount *agAccount):
151 m_manager(manager),
152 m_account(agAccount),
153 m_cancellable(g_cancellable_new())
154{
155}
156
157void Account::Private::init(Account *account)
158{
159 if (m_account == nullptr) return;
160 g_signal_connect_swapped(m_account, "display-name-changed",
161 G_CALLBACK(&Private::on_display_name_changed),
162 account);
163 g_signal_connect_swapped(m_account, "enabled",
164 G_CALLBACK(&Private::on_enabled), account);
165 g_signal_connect_swapped(m_account, "deleted",
166 G_CALLBACK(&Private::on_deleted), account);
167}
168
169void Account::Private::on_display_name_changed(Account *self)
170{
171 const gchar *name = ag_account_get_display_name(self->d->m_account);
172
173 Q_EMIT self->displayNameChanged(UTF8(name));
174}
175
176void Account::Private::on_enabled(Account *self, const gchar *service_name,
177 gboolean enabled)
178{
179 Q_EMIT self->enabledChanged(UTF8(service_name), enabled);
180}
181
182void Account::Private::on_deleted(Account *self)
183{
184 Q_EMIT self->removed();
185}
186
202Account::Account(Manager *manager, const QString &providerName,
203 QObject *parent):
204 QObject(parent),
205 d(new Private(manager, providerName, this))
206{
207}
208
209Account::Account(Private *d, QObject *parent):
210 QObject(parent),
211 d(d)
212{
213 d->init(this);
214}
215
225Account *Account::fromId(Manager *manager, AccountId id, QObject *parent)
226{
227 GError *error = nullptr;
228 AgAccount *account = ag_manager_load_account(manager->d->m_manager, id,
229 &error);
230 if (account == nullptr) {
231 Q_ASSERT(error != nullptr);
232 manager->d->lastError = Error(error);
233 g_error_free(error);
234 return 0;
235 }
236 Q_ASSERT(error == nullptr);
237 return new Account(new Private(manager, account), parent);
238}
239
243Account::~Account()
244{
245 QObjectList list = children();
246 for (int i = 0; i < list.count(); i++)
247 {
248 QObject *o = list.at(i);
249 if (qobject_cast<Watch *>(o))
250 delete o;
251 }
252
253 g_signal_handlers_disconnect_by_func
254 (d->m_account, (void *)&Private::on_display_name_changed, this);
255 g_signal_handlers_disconnect_by_func
256 (d->m_account, (void *)&Private::on_enabled, this);
257 g_signal_handlers_disconnect_by_func
258 (d->m_account, (void *)&Private::on_deleted, this);
259 g_object_unref(d->m_account);
260 delete d;
261 d = nullptr;
262}
263
268AccountId Account::id() const
269{
270 return d->m_account ? d->m_account->id : 0;
271}
272
276Manager *Account::manager() const
277{
278 return d->m_manager;
279}
280
284bool Account::supportsService(const QString &serviceType) const
285{
286 return ag_account_supports_service(d->m_account,
287 serviceType.toUtf8().constData());
288}
289
298ServiceList Account::services(const QString &serviceType) const
299{
300 GList *list;
301 if (serviceType.isEmpty()) {
302 list = ag_account_list_services(d->m_account);
303 } else {
304 list = ag_account_list_services_by_type(d->m_account,
305 serviceType.toUtf8().constData());
306 }
307
308 /* convert glist -> ServiceList */
309 ServiceList servList;
310 GList *iter;
311 for (iter = list; iter; iter = iter->next)
312 {
313 AgService *service = (AgService*)iter->data;
314 servList.append(Service(service, StealReference));
315 }
316
317 g_list_free(list);
318
319 return servList;
320}
321
327ServiceList Account::enabledServices() const
328{
329 GList *list;
330 list = ag_account_list_enabled_services(d->m_account);
331
332 /* convert glist -> ServiceList */
333 ServiceList servList;
334 GList *iter;
335 for (iter = list; iter; iter = g_list_next(iter))
336 {
337 AgService *service = (AgService*)iter->data;
338 servList.append(Service(service, StealReference));
339 }
340
341 g_list_free(list);
342
343 return servList;
344}
345
356bool Account::enabled() const
357{
358 return isEnabled();
359}
360
367bool Account::isEnabled() const
368{
369 return ag_account_get_enabled(d->m_account);
370}
371
379void Account::setEnabled(bool enabled)
380{
381 ag_account_set_enabled(d->m_account, enabled);
382}
383
389QString Account::displayName() const
390{
391 return UTF8(ag_account_get_display_name(d->m_account));
392}
393
398void Account::setDisplayName(const QString &displayName)
399{
400 ag_account_set_display_name(d->m_account,
401 displayName.toUtf8().constData());
402}
403
407QString Account::providerName() const
408{
409 return UTF8(ag_account_get_provider_name(d->m_account));
410}
411
415Provider Account::provider() const
416{
417 return manager()->provider(providerName());
418}
419
425void Account::selectService(const Service &service)
426{
427 AgService *agService = NULL;
428
429 if (service.isValid())
430 agService = service.service();
431
432 ag_account_select_service(d->m_account, agService);
433 d->prefix = QString();
434}
435
439Service Account::selectedService() const
440{
441 AgService *agService = ag_account_get_selected_service(d->m_account);
442 return Service(agService);
443}
444
450QStringList Account::allKeys() const
451{
452 QStringList allKeys;
453 AgAccountSettingIter iter;
454 const gchar *key;
455 GVariant *val;
456
457 /* iterate the settings */
458 QByteArray tmp = d->prefix.toLatin1();
459 ag_account_settings_iter_init(d->m_account, &iter, tmp.constData());
460 while (ag_account_settings_iter_get_next(&iter, &key, &val))
461 {
462 allKeys.append(QString(ASCII(key)));
463 }
464 return allKeys;
465}
466
473void Account::beginGroup(const QString &prefix)
474{
475 d->prefix += prefix + slash;
476}
477
483QStringList Account::childGroups() const
484{
485 QStringList groups, all_keys;
486
487 all_keys = allKeys();
488 Q_FOREACH (const QString &key, all_keys)
489 {
490 if (key.contains(slash)) {
491 QString group = key.section(slash, 0, 0);
492 if (!groups.contains(group))
493 groups.append(group);
494 }
495 }
496 return groups;
497}
498
504QStringList Account::childKeys() const
505{
506 QStringList keys, all_keys;
507
508 all_keys = allKeys();
509 Q_FOREACH (const QString &key, all_keys)
510 {
511 if (!key.contains(slash))
512 keys.append(key);
513 }
514 return keys;
515}
516
521void Account::clear()
522{
523 /* clear() must ignore the group: so, temporarily reset it and call
524 * remove("") */
525 QString saved_prefix = d->prefix;
526 d->prefix = QString();
527 remove(QString());
528 d->prefix = saved_prefix;
529}
530
537bool Account::contains(const QString &key) const
538{
539 return childKeys().contains(key);
540}
541
547void Account::endGroup()
548{
549 d->prefix = d->prefix.section(slash, 0, -3,
550 QString::SectionIncludeTrailingSep);
551 if (!d->prefix.isEmpty() && d->prefix[0] == slash) d->prefix.remove(0, 1);
552}
553
559QString Account::group() const
560{
561 if (d->prefix.endsWith(slash))
562 return d->prefix.left(d->prefix.size() - 1);
563 return d->prefix;
564}
565
569bool Account::isWritable() const
570{
571 return true;
572}
573
581void Account::remove(const QString &key)
582{
583 if (key.isEmpty())
584 {
585 /* delete all keys in the group */
586 QStringList keys = allKeys();
587 Q_FOREACH (const QString &key, keys)
588 {
589 if (!key.isEmpty())
590 remove(key);
591 }
592 }
593 else
594 {
595 QString full_key = d->prefix + key;
596 QByteArray tmpkey = full_key.toLatin1();
597 ag_account_set_variant(d->m_account, tmpkey.constData(), NULL);
598 }
599}
600
608void Account::setValue(const QString &key, const QVariant &value)
609{
610 GVariant *variant = qVariantToGVariant(value);
611 if (variant == nullptr) {
612 return;
613 }
614
615 QString full_key = d->prefix + key;
616 QByteArray tmpkey = full_key.toLatin1();
617 ag_account_set_variant(d->m_account, tmpkey.constData(), variant);
618}
619
620void Account::Private::account_store_cb(AgAccount *account,
621 GAsyncResult *res,
622 Account *self)
623{
624 GError *error = NULL;
625 ag_account_store_finish(account, res, &error);
626 if (error) {
627 if (error->domain == G_IO_ERROR &&
628 error->code == G_IO_ERROR_CANCELLED) {
629 } else {
630 Q_EMIT self->error(Error(error));
631 }
632 g_error_free(error);
633 } else {
634 Q_EMIT self->synced();
635 }
636}
637
652QVariant Account::value(const QString &key, const QVariant &defaultValue,
653 SettingSource *source) const
654{
655 QString full_key = d->prefix + key;
656 QByteArray ba = full_key.toLatin1();
657 AgSettingSource settingSource;
658 GVariant *variant =
659 ag_account_get_variant(d->m_account, ba.constData(), &settingSource);
660 if (source != nullptr) {
661 switch (settingSource) {
662 case AG_SETTING_SOURCE_ACCOUNT: *source = ACCOUNT; break;
663 case AG_SETTING_SOURCE_PROFILE: *source = TEMPLATE; break;
664 default: *source = NONE; break;
665 }
666 }
667
668 return (variant != nullptr) ? gVariantToQVariant(variant) : defaultValue;
669}
670
686SettingSource Account::value(const QString &key, QVariant &value) const
687{
688 SettingSource source;
689 QVariant variant = this->value(key, QVariant(), &source);
690 if (variant.isValid()) {
691 if (value.type() != variant.type()) {
692 if (!variant.convert(value.type())) source = NONE;
693 }
694 value = variant;
695 }
696
697 return source;
698}
699
709QString Account::valueAsString(const QString &key,
710 QString default_value,
711 SettingSource *source) const
712{
713 QVariant var = default_value;
714 SettingSource src = value(key, var);
715 if (source)
716 *source = src;
717 return var.toString();
718}
719
729int Account::valueAsInt(const QString &key,
730 int default_value,
731 SettingSource *source) const
732{
733 QVariant var = default_value;
734 SettingSource src = value(key, var);
735 if (source)
736 *source = src;
737 return var.toInt();
738}
739
749quint64 Account::valueAsUInt64(const QString &key,
750 quint64 default_value,
751 SettingSource *source) const
752{
753 QVariant var = default_value;
754 SettingSource src = value(key, var);
755 if (source)
756 *source = src;
757 return var.toULongLong();
758}
759
769bool Account::valueAsBool(const QString &key,
770 bool default_value,
771 SettingSource *source) const
772{
773 QVariant var = default_value;
774 SettingSource src = value(key, var);
775 if (source)
776 *source = src;
777 return var.toBool();
778}
779
780void Watch::Private::account_notify_cb(AgAccount *account, const gchar *key,
781 Watch *watch)
782{
783 Q_EMIT watch->notify(key);
784
785 Q_UNUSED(account);
786}
787
798Watch *Account::watchKey(const QString &key)
799{
800 AgAccountWatch ag_watch;
801 Watch *watch = new Watch(this);
802
803 if (!key.isEmpty())
804 {
805 QString full_key = d->prefix + key;
806 ag_watch = ag_account_watch_key
807 (d->m_account, full_key.toLatin1().constData(),
808 (AgAccountNotifyCb)&Watch::Private::account_notify_cb, watch);
809 }
810 else
811 {
812 ag_watch = ag_account_watch_dir
813 (d->m_account, d->prefix.toLatin1().constData(),
814 (AgAccountNotifyCb)&Watch::Private::account_notify_cb, watch);
815 }
816
817 if (!ag_watch)
818 {
819 delete watch;
820 return NULL;
821 }
822
823 watch->setWatch(ag_watch);
824 return watch;
825}
826
839void Account::sync()
840{
841 ag_account_store_async(d->m_account,
842 d->m_cancellable,
843 (GAsyncReadyCallback)&Private::account_store_cb,
844 this);
845}
846
854bool Account::syncAndBlock()
855{
856 GError *error = NULL;
857 bool ret;
858
859 ret = ag_account_store_blocking(d->m_account, &error);
860 if (error)
861 {
862 qWarning() << "Store operation failed: " << error->message;
863 g_error_free(error);
864 }
865
866 return ret;
867}
868
873void Account::remove()
874{
875 ag_account_delete(d->m_account);
876}
877
887void Account::sign(const QString &key, const char *token)
888{
889 ag_account_sign (d->m_account, key.toUtf8().constData(), token);
890}
891
903bool Account::verify(const QString &key, const char **token)
904{
905 return ag_account_verify(d->m_account, key.toUtf8().constData(), token);
906}
907
920bool Account::verifyWithTokens(const QString &key, QList<const char*> tokens)
921{
922 int tokensCount = tokens.count();
923
924 const char *tmp[tokensCount + 1];
925
926 for (int i = 0; i < tokensCount; ++i)
927 {
928 tmp[i] = tokens.at(i);
929 }
930 tmp[tokensCount] = NULL;
931
932 return ag_account_verify_with_tokens(d->m_account, key.toUtf8().constData(), tmp);
933}
934
935uint Account::credentialsId()
936{
937 QString key = ACCOUNTS_KEY_CREDENTIALS_ID;
938 QVariant val(QVariant::Int);
939
940 if (value(key, val) != NONE)
941 return val.toUInt();
942
943 uint id = 0;
944 Service service = selectedService();
945 if (service.isValid()) {
946 selectService();
947 if (value(key, val) != NONE)
948 id = val.toUInt();
949 selectService(service);
950 }
951 return id;
952}
953
954AgAccount *Account::account()
955{
956 return d->m_account;
957}
Base object definition for accounts error handling.
Definition: error.h:44
Manager of accounts, services and providers.
Definition: manager.h:52
Provider provider(const QString &providerName) const
Gets an object representing a provider.
Definition: manager.cpp:421
Error lastError() const
Gets the last error.
Definition: manager.cpp:583
Representation of an account provider.
Definition: provider.h:49
Representation of an account service.
Definition: service.h:49
bool isValid() const
Check whether this object represents a Service.
Definition: service.cpp:104