accounts-qt  1.16
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/ag-account.h>
32 
33 namespace Accounts {
34 
75 class Account::Private
76 {
77 public:
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 
104 class Watch::Private
105 {
106 public:
107  static void account_notify_cb(AgAccount *account, const gchar *key,
108  Watch *self);
109 };
110 } //namespace Accounts
111 
112 
113 using namespace Accounts;
114 
115 static QChar slash = QChar::fromLatin1('/');
116 
126 Watch::Watch(QObject *parent):
127  QObject(parent)
128 {
129 }
130 
131 Watch::~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 
140 Account::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 
150 Account::Private::Private(Manager *manager, AgAccount *agAccount):
151  m_manager(manager),
152  m_account(agAccount),
153  m_cancellable(g_cancellable_new())
154 {
155 }
156 
157 void 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 
169 void 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 
176 void 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 
182 void Account::Private::on_deleted(Account *self)
183 {
184  Q_EMIT self->removed();
185 }
186 
202 Account::Account(Manager *manager, const QString &providerName,
203  QObject *parent):
204  QObject(parent),
205  d(new Private(manager, providerName, this))
206 {
207 }
208 
209 Account::Account(Private *d, QObject *parent):
210  QObject(parent),
211  d(d)
212 {
213  d->init(this);
214 }
215 
225 Account *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 
243 Account::~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 
268 AccountId Account::id() const
269 {
270  return d->m_account ? d->m_account->id : 0;
271 }
272 
276 Manager *Account::manager() const
277 {
278  return d->m_manager;
279 }
280 
284 bool Account::supportsService(const QString &serviceType) const
285 {
286  return ag_account_supports_service(d->m_account,
287  serviceType.toUtf8().constData());
288 }
289 
298 ServiceList 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 
327 ServiceList 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 
356 bool Account::enabled() const
357 {
358  return isEnabled();
359 }
360 
367 bool Account::isEnabled() const
368 {
369  return ag_account_get_enabled(d->m_account);
370 }
371 
379 void Account::setEnabled(bool enabled)
380 {
381  ag_account_set_enabled(d->m_account, enabled);
382 }
383 
389 QString Account::displayName() const
390 {
391  return UTF8(ag_account_get_display_name(d->m_account));
392 }
393 
398 void Account::setDisplayName(const QString &displayName)
399 {
400  ag_account_set_display_name(d->m_account,
401  displayName.toUtf8().constData());
402 }
403 
407 QString Account::providerName() const
408 {
409  return UTF8(ag_account_get_provider_name(d->m_account));
410 }
411 
415 Provider Account::provider() const
416 {
417  return manager()->provider(providerName());
418 }
419 
425 void 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 
439 Service Account::selectedService() const
440 {
441  AgService *agService = ag_account_get_selected_service(d->m_account);
442  return Service(agService);
443 }
444 
450 QStringList 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 
473 void Account::beginGroup(const QString &prefix)
474 {
475  d->prefix += prefix + slash;
476 }
477 
483 QStringList 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 
504 QStringList 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 
521 void 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 
537 bool Account::contains(const QString &key) const
538 {
539  return childKeys().contains(key);
540 }
541 
547 void Account::endGroup()
548 {
549  d->prefix = d->prefix.section(slash, 0, -3,
550  QString::SectionIncludeTrailingSep);
551  if (d->prefix[0] == slash) d->prefix.remove(0, 1);
552 }
553 
559 QString 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 
569 bool Account::isWritable() const
570 {
571  return true;
572 }
573 
581 void 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 
608 void 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 
620 void 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 
652 QVariant 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 
686 SettingSource 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 
709 QString 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 
729 int 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 
749 quint64 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 
769 bool 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 
780 void 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 
798 Watch *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 
839 void 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 
854 bool 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 
873 void Account::remove()
874 {
875  ag_account_delete(d->m_account);
876 }
877 
887 void Account::sign(const QString &key, const char *token)
888 {
889  ag_account_sign (d->m_account, key.toUtf8().constData(), token);
890 }
891 
903 bool Account::verify(const QString &key, const char **token)
904 {
905  return ag_account_verify(d->m_account, key.toUtf8().constData(), token);
906 }
907 
920 bool 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 
935 uint 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 
954 AgAccount *Account::account()
955 {
956  return d->m_account;
957 }
Accounts::Manager::lastError
Error lastError() const
Gets the last error.
Definition: manager.cpp:583
Accounts::Manager
Manager of accounts, services and providers.
Definition: manager.h:52
Accounts::AccountService::account
Account * account() const
Return the Account.
Definition: account-service.cpp:205
Accounts::Error
Base object definition for accounts error handling.
Definition: error.h:44
Accounts::Manager::provider
Provider provider(const QString &providerName) const
Gets an object representing a provider.
Definition: manager.cpp:421
Accounts::Service
Representation of an account service.
Definition: service.h:49
Accounts::Provider
Representation of an account provider.
Definition: provider.h:49
Accounts::Service::isValid
bool isValid() const
Check whether this object represents a Service.
Definition: service.cpp:104