accounts-qt  1.13
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-2013 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 == 0) 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  TRACE();
185 
186  Q_EMIT self->removed();
187 }
188 
204 Account::Account(Manager *manager, const QString &providerName,
205  QObject *parent):
206  QObject(parent),
207  d(new Private(manager, providerName, this))
208 {
209 }
210 
211 Account::Account(Private *d, QObject *parent):
212  QObject(parent),
213  d(d)
214 {
215  d->init(this);
216 }
217 
227 Account *Account::fromId(Manager *manager, AccountId id, QObject *parent)
228 {
229  GError *error = 0;
230  AgAccount *account = ag_manager_load_account(manager->d->m_manager, id,
231  &error);
232  if (account == 0) {
233  Q_ASSERT(error != 0);
234  manager->d->lastError = Error(error);
235  g_error_free(error);
236  return 0;
237  }
238  Q_ASSERT(error == 0);
239  return new Account(new Private(manager, account), parent);
240 }
241 
245 Account::~Account()
246 {
247  QObjectList list = children();
248  for (int i = 0; i < list.count(); i++)
249  {
250  QObject *o = list.at(i);
251  if (qobject_cast<Watch *>(o))
252  delete o;
253  }
254 
255  g_signal_handlers_disconnect_by_func
256  (d->m_account, (void *)&Private::on_display_name_changed, this);
257  g_signal_handlers_disconnect_by_func
258  (d->m_account, (void *)&Private::on_enabled, this);
259  g_signal_handlers_disconnect_by_func
260  (d->m_account, (void *)&Private::on_deleted, this);
261  g_object_unref(d->m_account);
262  delete d;
263  d = 0;
264 }
265 
270 AccountId Account::id() const
271 {
272  return d->m_account ? d->m_account->id : 0;
273 }
274 
278 Manager *Account::manager() const
279 {
280  return d->m_manager;
281 }
282 
286 bool Account::supportsService(const QString &serviceType) const
287 {
288  return ag_account_supports_service(d->m_account,
289  serviceType.toUtf8().constData());
290 }
291 
300 ServiceList Account::services(const QString &serviceType) const
301 {
302  GList *list;
303  if (serviceType.isEmpty()) {
304  list = ag_account_list_services(d->m_account);
305  } else {
306  list = ag_account_list_services_by_type(d->m_account,
307  serviceType.toUtf8().constData());
308  }
309 
310  /* convert glist -> ServiceList */
311  ServiceList servList;
312  GList *iter;
313  for (iter = list; iter; iter = iter->next)
314  {
315  AgService *service = (AgService*)iter->data;
316  servList.append(Service(service, StealReference));
317  }
318 
319  g_list_free(list);
320 
321  return servList;
322 }
323 
329 ServiceList Account::enabledServices() const
330 {
331  GList *list;
332  list = ag_account_list_enabled_services(d->m_account);
333 
334  /* convert glist -> ServiceList */
335  ServiceList servList;
336  GList *iter;
337  for (iter = list; iter; iter = g_list_next(iter))
338  {
339  AgService *service = (AgService*)iter->data;
340  servList.append(Service(service, StealReference));
341  }
342 
343  g_list_free(list);
344 
345  return servList;
346 }
347 
358 bool Account::enabled() const
359 {
360  return isEnabled();
361 }
362 
369 bool Account::isEnabled() const
370 {
371  return ag_account_get_enabled(d->m_account);
372 }
373 
381 void Account::setEnabled(bool enabled)
382 {
383  ag_account_set_enabled(d->m_account, enabled);
384 }
385 
391 QString Account::displayName() const
392 {
393  return UTF8(ag_account_get_display_name(d->m_account));
394 }
395 
400 void Account::setDisplayName(const QString &displayName)
401 {
402  ag_account_set_display_name(d->m_account,
403  displayName.toUtf8().constData());
404 }
405 
409 QString Account::providerName() const
410 {
411  return UTF8(ag_account_get_provider_name(d->m_account));
412 }
413 
417 Provider Account::provider() const
418 {
419  return manager()->provider(providerName());
420 }
421 
427 void Account::selectService(const Service &service)
428 {
429  AgService *agService = NULL;
430 
431  if (service.isValid())
432  agService = service.service();
433 
434  ag_account_select_service(d->m_account, agService);
435  d->prefix = QString();
436 }
437 
441 Service Account::selectedService() const
442 {
443  AgService *agService = ag_account_get_selected_service(d->m_account);
444  return Service(agService);
445 }
446 
452 QStringList Account::allKeys() const
453 {
454  QStringList allKeys;
455  AgAccountSettingIter iter;
456  const gchar *key;
457  GVariant *val;
458 
459  /* iterate the settings */
460  QByteArray tmp = d->prefix.toLatin1();
461  ag_account_settings_iter_init(d->m_account, &iter, tmp.constData());
462  while (ag_account_settings_iter_get_next(&iter, &key, &val))
463  {
464  allKeys.append(QString(ASCII(key)));
465  }
466  return allKeys;
467 }
468 
475 void Account::beginGroup(const QString &prefix)
476 {
477  d->prefix += prefix + slash;
478 }
479 
485 QStringList Account::childGroups() const
486 {
487  QStringList groups, all_keys;
488 
489  all_keys = allKeys();
490  Q_FOREACH (QString key, all_keys)
491  {
492  if (key.contains(slash)) {
493  QString group = key.section(slash, 0, 0);
494  if (!groups.contains(group))
495  groups.append(group);
496  }
497  }
498  return groups;
499 }
500 
506 QStringList Account::childKeys() const
507 {
508  QStringList keys, all_keys;
509 
510  all_keys = allKeys();
511  Q_FOREACH (QString key, all_keys)
512  {
513  if (!key.contains(slash))
514  keys.append(key);
515  }
516  return keys;
517 }
518 
523 void Account::clear()
524 {
525  /* clear() must ignore the group: so, temporarily reset it and call
526  * remove("") */
527  QString saved_prefix = d->prefix;
528  d->prefix = QString();
529  remove(QString());
530  d->prefix = saved_prefix;
531 }
532 
539 bool Account::contains(const QString &key) const
540 {
541  return childKeys().contains(key);
542 }
543 
549 void Account::endGroup()
550 {
551  d->prefix = d->prefix.section(slash, 0, -3,
552  QString::SectionIncludeTrailingSep);
553  if (d->prefix[0] == slash) d->prefix.remove(0, 1);
554 }
555 
561 QString Account::group() const
562 {
563  if (d->prefix.endsWith(slash))
564  return d->prefix.left(d->prefix.size() - 1);
565  return d->prefix;
566 }
567 
571 bool Account::isWritable() const
572 {
573  return true;
574 }
575 
583 void Account::remove(const QString &key)
584 {
585  if (key.isEmpty())
586  {
587  /* delete all keys in the group */
588  QStringList keys = allKeys();
589  Q_FOREACH (QString key, keys)
590  {
591  if (!key.isEmpty())
592  remove(key);
593  }
594  }
595  else
596  {
597  QString full_key = d->prefix + key;
598  QByteArray tmpkey = full_key.toLatin1();
599  ag_account_set_variant(d->m_account, tmpkey.constData(), NULL);
600  }
601 }
602 
610 void Account::setValue(const QString &key, const QVariant &value)
611 {
612  GVariant *variant = qVariantToGVariant(value);
613  if (variant == 0) {
614  return;
615  }
616 
617  QString full_key = d->prefix + key;
618  QByteArray tmpkey = full_key.toLatin1();
619  ag_account_set_variant(d->m_account, tmpkey.constData(), variant);
620 }
621 
622 void Account::Private::account_store_cb(AgAccount *account,
623  GAsyncResult *res,
624  Account *self)
625 {
626  TRACE() << "Saved accunt ID:" << account->id;
627 
628  GError *error = NULL;
629  ag_account_store_finish(account, res, &error);
630  if (error) {
631  if (error->domain == G_IO_ERROR &&
632  error->code == G_IO_ERROR_CANCELLED) {
633  TRACE() << "Account destroyed, operation cancelled";
634  } else {
635  Q_EMIT self->error(Error(error));
636  }
637  g_error_free(error);
638  } else {
639  Q_EMIT self->synced();
640  }
641 }
642 
657 QVariant Account::value(const QString &key, const QVariant &defaultValue,
658  SettingSource *source) const
659 {
660  QString full_key = d->prefix + key;
661  QByteArray ba = full_key.toLatin1();
662  AgSettingSource settingSource;
663  GVariant *variant =
664  ag_account_get_variant(d->m_account, ba.constData(), &settingSource);
665  if (source != 0) {
666  switch (settingSource) {
667  case AG_SETTING_SOURCE_ACCOUNT: *source = ACCOUNT; break;
668  case AG_SETTING_SOURCE_PROFILE: *source = TEMPLATE; break;
669  default: *source = NONE; break;
670  }
671  }
672 
673  return (variant != 0) ? gVariantToQVariant(variant) : defaultValue;
674 }
675 
691 SettingSource Account::value(const QString &key, QVariant &value) const
692 {
693  SettingSource source;
694  QVariant variant = this->value(key, QVariant(), &source);
695  if (variant.isValid()) {
696  if (value.type() != variant.type()) {
697  if (!variant.convert(value.type())) source = NONE;
698  }
699  value = variant;
700  }
701 
702  return source;
703 }
704 
714 QString Account::valueAsString(const QString &key,
715  QString default_value,
716  SettingSource *source) const
717 {
718  QVariant var = default_value;
719  SettingSource src = value(key, var);
720  if (source)
721  *source = src;
722  return var.toString();
723 }
724 
734 int Account::valueAsInt(const QString &key,
735  int default_value,
736  SettingSource *source) const
737 {
738  QVariant var = default_value;
739  SettingSource src = value(key, var);
740  if (source)
741  *source = src;
742  return var.toInt();
743 }
744 
754 quint64 Account::valueAsUInt64(const QString &key,
755  quint64 default_value,
756  SettingSource *source) const
757 {
758  QVariant var = default_value;
759  SettingSource src = value(key, var);
760  if (source)
761  *source = src;
762  return var.toULongLong();
763 }
764 
774 bool Account::valueAsBool(const QString &key,
775  bool default_value,
776  SettingSource *source) const
777 {
778  QVariant var = default_value;
779  SettingSource src = value(key, var);
780  if (source)
781  *source = src;
782  return var.toBool();
783 }
784 
785 void Watch::Private::account_notify_cb(AgAccount *account, const gchar *key,
786  Watch *watch)
787 {
788  Q_EMIT watch->notify(key);
789 
790  Q_UNUSED(account);
791 }
792 
803 Watch *Account::watchKey(const QString &key)
804 {
805  AgAccountWatch ag_watch;
806  Watch *watch = new Watch(this);
807 
808  if (!key.isEmpty())
809  {
810  QString full_key = d->prefix + key;
811  ag_watch = ag_account_watch_key
812  (d->m_account, full_key.toLatin1().constData(),
813  (AgAccountNotifyCb)&Watch::Private::account_notify_cb, watch);
814  }
815  else
816  {
817  ag_watch = ag_account_watch_dir
818  (d->m_account, d->prefix.toLatin1().constData(),
819  (AgAccountNotifyCb)&Watch::Private::account_notify_cb, watch);
820  }
821 
822  if (!ag_watch)
823  {
824  delete watch;
825  return NULL;
826  }
827 
828  watch->setWatch(ag_watch);
829  return watch;
830 }
831 
844 void Account::sync()
845 {
846  ag_account_store_async(d->m_account,
847  d->m_cancellable,
848  (GAsyncReadyCallback)&Private::account_store_cb,
849  this);
850 }
851 
859 bool Account::syncAndBlock()
860 {
861  GError *error = NULL;
862  bool ret;
863 
864  ret = ag_account_store_blocking(d->m_account, &error);
865  if (error)
866  {
867  qWarning() << "Store operation failed: " << error->message;
868  g_error_free(error);
869  }
870 
871  return ret;
872 }
873 
878 void Account::remove()
879 {
880  ag_account_delete(d->m_account);
881 }
882 
892 void Account::sign(const QString &key, const char *token)
893 {
894  ag_account_sign (d->m_account, key.toUtf8().constData(), token);
895 }
896 
908 bool Account::verify(const QString &key, const char **token)
909 {
910  return ag_account_verify(d->m_account, key.toUtf8().constData(), token);
911 }
912 
925 bool Account::verifyWithTokens(const QString &key, QList<const char*> tokens)
926 {
927  int tokensCount = tokens.count();
928 
929  const char *tmp[tokensCount + 1];
930 
931  for (int i = 0; i < tokensCount; ++i)
932  {
933  tmp[i] = tokens.at(i);
934  }
935  tmp[tokensCount] = NULL;
936 
937  return ag_account_verify_with_tokens(d->m_account, key.toUtf8().constData(), tmp);
938 }
939 
940 uint Account::credentialsId()
941 {
942  QString key = ACCOUNTS_KEY_CREDENTIALS_ID;
943  QVariant val(QVariant::Int);
944 
945  if (value(key, val) != NONE)
946  return val.toUInt();
947 
948  uint id = 0;
949  Service service = selectedService();
950  if (service.isValid()) {
951  selectService();
952  if (value(key, val) != NONE)
953  id = val.toUInt();
954  selectService(service);
955  }
956  return id;
957 }
958 
959 AgAccount *Account::account()
960 {
961  return d->m_account;
962 }
bool isValid() const
Check whether this object represents a Service.
Definition: service.cpp:104
QString group() const
Return the name of the current group.
Manager of accounts, services and providers.
Definition: manager.h:51
bool enabled() const
Check whether the account service is enabled.
Monitors an account key or group of keys.
Definition: account.h:70
bool isEnabled() const
Check whether the account service is enabled.
Representation of an account provider.
Definition: provider.h:48
QVariant value(const QString &key, const QVariant &defaultValue, SettingSource *source=0) const
Retrieves the value of an account setting, as a QVariant.
Representation of an account service.
Definition: service.h:48
QStringList allKeys() const
Return all the keys in the current group.
Base object definition for accounts error handling.
Definition: error.h:42
QStringList childKeys() const
Return all the keys which are direct children of the current group.
Provider provider(const QString &providerName) const
Gets an object representing a provider.
Definition: manager.cpp:392
Error lastError() const
Gets the last error.
Definition: manager.cpp:554
Account * account() const
Return the Account.
Service service() const
Return the Service.