accounts-qt  1.6
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 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 "utils.h"
28 
29 #undef signals
30 #include <libaccounts-glib/ag-manager.h>
31 #include <libaccounts-glib/ag-account.h>
32 
33 namespace Accounts {
34 
75 class Account::Private
76 {
77 public:
78  Private():
79  m_account(0),
80  m_cancellable(g_cancellable_new())
81  {
82  }
83 
84  ~Private()
85  {
86  g_cancellable_cancel(m_cancellable);
87  g_object_unref(m_cancellable);
88  m_cancellable = NULL;
89  }
90 
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 void Account::Private::on_display_name_changed(Account *self)
141 {
142  const gchar *name = ag_account_get_display_name(self->d->m_account);
143 
144  Q_EMIT self->displayNameChanged(UTF8(name));
145 }
146 
147 void Account::Private::on_enabled(Account *self, const gchar *service_name,
148  gboolean enabled)
149 {
150  Q_EMIT self->enabledChanged(UTF8(service_name), enabled);
151 }
152 
153 void Account::Private::on_deleted(Account *self)
154 {
155  TRACE();
156 
157  Q_EMIT self->removed();
158 }
159 
166 Account::Account(AgAccount *account, QObject *parent):
167  QObject(parent),
168  d(new Private)
169 {
170  d->m_account = account;
171  g_object_ref(account);
172 
173  g_signal_connect_swapped(account, "display-name-changed",
174  G_CALLBACK(&Private::on_display_name_changed),
175  this);
176  g_signal_connect_swapped(account, "enabled",
177  G_CALLBACK(&Private::on_enabled), this);
178  g_signal_connect_swapped(account, "deleted",
179  G_CALLBACK(&Private::on_deleted), this);
180 }
181 
185 Account::~Account()
186 {
187  QObjectList list = children();
188  for (int i = 0; i < list.count(); i++)
189  {
190  QObject *o = list.at(i);
191  if (qobject_cast<Watch *>(o))
192  delete o;
193  }
194 
195  g_signal_handlers_disconnect_by_func
196  (d->m_account, (void *)&Private::on_display_name_changed, this);
197  g_signal_handlers_disconnect_by_func
198  (d->m_account, (void *)&Private::on_enabled, this);
199  g_signal_handlers_disconnect_by_func
200  (d->m_account, (void *)&Private::on_deleted, this);
201  g_object_unref(d->m_account);
202  delete d;
203  d = 0;
204 }
205 
210 AccountId Account::id() const
211 {
212  return d->m_account ? d->m_account->id : 0;
213 }
214 
218 Manager *Account::manager() const
219 {
220  return qobject_cast<Manager *>(QObject::parent());
221 }
222 
226 bool Account::supportsService(const QString &serviceType) const
227 {
228  return ag_account_supports_service(d->m_account,
229  serviceType.toUtf8().constData());
230 }
231 
240 ServiceList Account::services(const QString &serviceType) const
241 {
242  GList *list;
243  if (serviceType.isEmpty()) {
244  list = ag_account_list_services(d->m_account);
245  } else {
246  list = ag_account_list_services_by_type(d->m_account,
247  serviceType.toUtf8().constData());
248  }
249 
250  /* convert glist -> ServiceList */
251  ServiceList servList;
252  GList *iter;
253  for (iter = list; iter; iter = iter->next)
254  {
255  AgService *service = (AgService*)iter->data;
256  servList.append(Service(service, StealReference));
257  }
258 
259  g_list_free(list);
260 
261  return servList;
262 }
263 
269 ServiceList Account::enabledServices() const
270 {
271  GList *list;
272  list = ag_account_list_enabled_services(d->m_account);
273 
274  /* convert glist -> ServiceList */
275  ServiceList servList;
276  GList *iter;
277  for (iter = list; iter; iter = g_list_next(iter))
278  {
279  AgService *service = (AgService*)iter->data;
280  servList.append(Service(service, StealReference));
281  }
282 
283  g_list_free(list);
284 
285  return servList;
286 }
287 
294 bool Account::enabled() const
295 {
296  return ag_account_get_enabled(d->m_account);
297 }
298 
306 void Account::setEnabled(bool enabled)
307 {
308  ag_account_set_enabled(d->m_account, enabled);
309 }
310 
316 QString Account::displayName() const
317 {
318  return UTF8(ag_account_get_display_name(d->m_account));
319 }
320 
325 void Account::setDisplayName(const QString &displayName)
326 {
327  ag_account_set_display_name(d->m_account,
328  displayName.toUtf8().constData());
329 }
330 
334 QString Account::providerName() const
335 {
336  return UTF8(ag_account_get_provider_name(d->m_account));
337 }
338 
342 Provider Account::provider() const
343 {
344  return manager()->provider(providerName());
345 }
346 
352 void Account::selectService(const Service &service)
353 {
354  AgService *agService = NULL;
355 
356  if (service.isValid())
357  agService = service.service();
358 
359  ag_account_select_service(d->m_account, agService);
360  d->prefix = QString();
361 }
362 
366 Service Account::selectedService() const
367 {
368  AgService *agService = ag_account_get_selected_service(d->m_account);
369  return Service(agService);
370 }
371 
377 QStringList Account::allKeys() const
378 {
379  QStringList allKeys;
380  AgAccountSettingIter iter;
381  const gchar *key;
382  GVariant *val;
383 
384  /* iterate the settings */
385  QByteArray tmp = d->prefix.toLatin1();
386  ag_account_settings_iter_init(d->m_account, &iter, tmp.constData());
387  while (ag_account_settings_iter_get_next(&iter, &key, &val))
388  {
389  allKeys.append(QString(ASCII(key)));
390  }
391  return allKeys;
392 }
393 
400 void Account::beginGroup(const QString &prefix)
401 {
402  d->prefix += prefix + slash;
403 }
404 
410 QStringList Account::childGroups() const
411 {
412  QStringList groups, all_keys;
413 
414  all_keys = allKeys();
415  Q_FOREACH (QString key, all_keys)
416  {
417  if (key.contains(slash)) {
418  QString group = key.section(slash, 0, 0);
419  if (!groups.contains(group))
420  groups.append(group);
421  }
422  }
423  return groups;
424 }
425 
431 QStringList Account::childKeys() const
432 {
433  QStringList keys, all_keys;
434 
435  all_keys = allKeys();
436  Q_FOREACH (QString key, all_keys)
437  {
438  if (!key.contains(slash))
439  keys.append(key);
440  }
441  return keys;
442 }
443 
448 void Account::clear()
449 {
450  /* clear() must ignore the group: so, temporarily reset it and call
451  * remove("") */
452  QString saved_prefix = d->prefix;
453  d->prefix = QString();
454  remove(QString());
455  d->prefix = saved_prefix;
456 }
457 
464 bool Account::contains(const QString &key) const
465 {
466  return childKeys().contains(key);
467 }
468 
474 void Account::endGroup()
475 {
476  d->prefix = d->prefix.section(slash, 0, -3,
477  QString::SectionIncludeTrailingSep);
478  if (d->prefix[0] == slash) d->prefix.remove(0, 1);
479 }
480 
486 QString Account::group() const
487 {
488  if (d->prefix.endsWith(slash))
489  return d->prefix.left(d->prefix.size() - 1);
490  return d->prefix;
491 }
492 
496 bool Account::isWritable() const
497 {
498  return true;
499 }
500 
508 void Account::remove(const QString &key)
509 {
510  if (key.isEmpty())
511  {
512  /* delete all keys in the group */
513  QStringList keys = allKeys();
514  Q_FOREACH (QString key, keys)
515  {
516  if (!key.isEmpty())
517  remove(key);
518  }
519  }
520  else
521  {
522  QString full_key = d->prefix + key;
523  QByteArray tmpkey = full_key.toLatin1();
524  ag_account_set_variant(d->m_account, tmpkey.constData(), NULL);
525  }
526 }
527 
535 void Account::setValue(const QString &key, const QVariant &value)
536 {
537  GVariant *variant = qVariantToGVariant(value);
538  if (variant == 0) {
539  return;
540  }
541 
542  QString full_key = d->prefix + key;
543  QByteArray tmpkey = full_key.toLatin1();
544  ag_account_set_variant(d->m_account, tmpkey.constData(), variant);
545 }
546 
547 void Account::Private::account_store_cb(AgAccount *account,
548  GAsyncResult *res,
549  Account *self)
550 {
551  TRACE() << "Saved accunt ID:" << account->id;
552 
553  GError *error = NULL;
554  ag_account_store_finish(account, res, &error);
555  if (error) {
556  if (error->domain == G_IO_ERROR &&
557  error->code == G_IO_ERROR_CANCELLED) {
558  TRACE() << "Account destroyed, operation cancelled";
559  } else {
560  Q_EMIT self->error(Error(error));
561  }
562  g_error_free(error);
563  } else {
564  Q_EMIT self->synced();
565  }
566 }
567 
582 QVariant Account::value(const QString &key, const QVariant &defaultValue,
583  SettingSource *source) const
584 {
585  QString full_key = d->prefix + key;
586  QByteArray ba = full_key.toLatin1();
587  AgSettingSource settingSource;
588  GVariant *variant =
589  ag_account_get_variant(d->m_account, ba.constData(), &settingSource);
590  if (source != 0) {
591  switch (settingSource) {
592  case AG_SETTING_SOURCE_ACCOUNT: *source = ACCOUNT; break;
593  case AG_SETTING_SOURCE_PROFILE: *source = TEMPLATE; break;
594  default: *source = NONE; break;
595  }
596  }
597 
598  return (variant != 0) ? gVariantToQVariant(variant) : defaultValue;
599 }
600 
616 SettingSource Account::value(const QString &key, QVariant &value) const
617 {
618  SettingSource source;
619  QVariant variant = this->value(key, QVariant(), &source);
620  if (variant.isValid()) {
621  if (value.type() != variant.type()) {
622  if (!variant.convert(value.type())) source = NONE;
623  }
624  value = variant;
625  }
626 
627  return source;
628 }
629 
639 QString Account::valueAsString(const QString &key,
640  QString default_value,
641  SettingSource *source) const
642 {
643  QVariant var = default_value;
644  SettingSource src = value(key, var);
645  if (source)
646  *source = src;
647  return var.toString();
648 }
649 
659 int Account::valueAsInt(const QString &key,
660  int default_value,
661  SettingSource *source) const
662 {
663  QVariant var = default_value;
664  SettingSource src = value(key, var);
665  if (source)
666  *source = src;
667  return var.toInt();
668 }
669 
679 quint64 Account::valueAsUInt64(const QString &key,
680  quint64 default_value,
681  SettingSource *source) const
682 {
683  QVariant var = default_value;
684  SettingSource src = value(key, var);
685  if (source)
686  *source = src;
687  return var.toULongLong();
688 }
689 
699 bool Account::valueAsBool(const QString &key,
700  bool default_value,
701  SettingSource *source) const
702 {
703  QVariant var = default_value;
704  SettingSource src = value(key, var);
705  if (source)
706  *source = src;
707  return var.toBool();
708 }
709 
710 void Watch::Private::account_notify_cb(AgAccount *account, const gchar *key,
711  Watch *watch)
712 {
713  Q_EMIT watch->notify(key);
714 
715  Q_UNUSED(account);
716 }
717 
728 Watch *Account::watchKey(const QString &key)
729 {
730  AgAccountWatch ag_watch;
731  Watch *watch = new Watch(this);
732 
733  if (!key.isEmpty())
734  {
735  QString full_key = d->prefix + key;
736  ag_watch = ag_account_watch_key
737  (d->m_account, full_key.toLatin1().constData(),
738  (AgAccountNotifyCb)&Watch::Private::account_notify_cb, watch);
739  }
740  else
741  {
742  ag_watch = ag_account_watch_dir
743  (d->m_account, d->prefix.toLatin1().constData(),
744  (AgAccountNotifyCb)&Watch::Private::account_notify_cb, watch);
745  }
746 
747  if (!ag_watch)
748  {
749  delete watch;
750  return NULL;
751  }
752 
753  watch->setWatch(ag_watch);
754  return watch;
755 }
756 
769 void Account::sync()
770 {
771  ag_account_store_async(d->m_account,
772  d->m_cancellable,
773  (GAsyncReadyCallback)&Private::account_store_cb,
774  this);
775 }
776 
784 bool Account::syncAndBlock()
785 {
786  GError *error = NULL;
787  bool ret;
788 
789  ret = ag_account_store_blocking(d->m_account, &error);
790  if (error)
791  {
792  qWarning() << "Store operation failed: " << error->message;
793  g_error_free(error);
794  }
795 
796  return ret;
797 }
798 
803 void Account::remove()
804 {
805  ag_account_delete(d->m_account);
806 }
807 
817 void Account::sign(const QString &key, const char *token)
818 {
819  ag_account_sign (d->m_account, key.toUtf8().constData(), token);
820 }
821 
833 bool Account::verify(const QString &key, const char **token)
834 {
835  return ag_account_verify(d->m_account, key.toUtf8().constData(), token);
836 }
837 
850 bool Account::verifyWithTokens(const QString &key, QList<const char*> tokens)
851 {
852  int tokensCount = tokens.count();
853 
854  const char *tmp[tokensCount + 1];
855 
856  for (int i = 0; i < tokensCount; ++i)
857  {
858  tmp[i] = tokens.at(i);
859  }
860  tmp[tokensCount] = NULL;
861 
862  return ag_account_verify_with_tokens(d->m_account, key.toUtf8().constData(), tmp);
863 }
864 
865 uint Account::credentialsId()
866 {
867  QString key = ACCOUNTS_KEY_CREDENTIALS_ID;
868  QVariant val(QVariant::Int);
869 
870  if (value(key, val) != NONE)
871  return val.toUInt();
872 
873  uint id = 0;
874  Service service = selectedService();
875  if (service.isValid()) {
876  selectService();
877  if (value(key, val) != NONE)
878  id = val.toUInt();
879  selectService(service);
880  }
881  return id;
882 }
883 
884 AgAccount *Account::account()
885 {
886  return d->m_account;
887 }