accounts-qt  1.2
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  {
80  m_account = 0;
81  }
82 
83  ~Private() {}
84 
85  AgAccount *m_account; //real account
86  QString prefix;
87 
88  static void on_display_name_changed(Account *self);
89  static void on_enabled(Account *self, const gchar *service_name,
90  gboolean enabled);
91  static void account_store_cb(AgAccount *account, const GError *error,
92  Account *self);
93  static void on_deleted(Account *self);
94 };
95 
96 class Watch::Private
97 {
98 public:
99  static void account_notify_cb(AgAccount *account, const gchar *key,
100  Watch *self);
101 };
102 } //namespace Accounts
103 
104 
105 using namespace Accounts;
106 
107 static QChar slash = QChar::fromLatin1('/');
108 
118 Watch::Watch(QObject *parent):
119  QObject(parent)
120 {
121 }
122 
123 Watch::~Watch()
124 {
125  TRACE();
126  Account *account = qobject_cast<Account *>(QObject::parent());
127  /* The destructor of Account deletes the child Watches before detaching
128  * them, so here account should always be not NULL */
129  Q_ASSERT(account != NULL);
130  ag_account_remove_watch(account->d->m_account, watch);
131 }
132 
133 void Account::Private::on_display_name_changed(Account *self)
134 {
135  TRACE();
136  const gchar *name = ag_account_get_display_name(self->d->m_account);
137 
138  emit self->displayNameChanged(UTF8(name));
139 }
140 
141 void Account::Private::on_enabled(Account *self, const gchar *service_name,
142  gboolean enabled)
143 {
144  TRACE();
145 
146  emit self->enabledChanged(UTF8(service_name), enabled);
147 }
148 
149 void Account::Private::on_deleted(Account *self)
150 {
151  TRACE();
152 
153  emit self->removed();
154 }
155 
162 Account::Account(AgAccount *account, QObject *parent):
163  QObject(parent),
164  d(new Private)
165 {
166  TRACE();
167  d->m_account = account;
168  g_object_ref(account);
169 
170  g_signal_connect_swapped(account, "display-name-changed",
171  G_CALLBACK(&Private::on_display_name_changed),
172  this);
173  g_signal_connect_swapped(account, "enabled",
174  G_CALLBACK(&Private::on_enabled), this);
175  g_signal_connect_swapped(account, "deleted",
176  G_CALLBACK(&Private::on_deleted), this);
177 }
178 
183 {
184  TRACE();
185 
186  QObjectList list = children();
187  for (int i = 0; i < list.count(); i++)
188  {
189  QObject *o = list.at(i);
190  if (qobject_cast<Watch *>(o))
191  delete o;
192  }
193 
194  g_signal_handlers_disconnect_by_func
195  (d->m_account, (void *)&Private::on_display_name_changed, this);
196  g_signal_handlers_disconnect_by_func
197  (d->m_account, (void *)&Private::on_enabled, this);
198  g_signal_handlers_disconnect_by_func
199  (d->m_account, (void *)&Private::on_deleted, this);
200  g_object_unref(d->m_account);
201  delete d;
202  d = 0;
203 }
204 
209 AccountId Account::id() const
210 {
211  return d->m_account ? d->m_account->id : 0;
212 }
213 
218 {
219  return qobject_cast<Manager *>(QObject::parent());
220 }
221 
225 bool Account::supportsService(const QString &serviceType) const
226 {
227  TRACE() << serviceType;
228 
229  return ag_account_supports_service(d->m_account,
230  serviceType.toUtf8().constData());
231 }
232 
241 ServiceList Account::services(const QString &serviceType) const
242 {
243  TRACE() << serviceType;
244 
245  GList *list;
246  if (serviceType.isEmpty()) {
247  list = ag_account_list_services(d->m_account);
248  } else {
249  list = ag_account_list_services_by_type(d->m_account,
250  serviceType.toUtf8().constData());
251  }
252 
253  /* convert glist -> ServiceList */
254  ServiceList servList;
255  GList *iter;
256  for (iter = list; iter; iter = iter->next)
257  {
258  AgService *service = (AgService*)iter->data;
259  servList.append(Service(service, StealReference));
260  }
261 
262  g_list_free(list);
263 
264  return servList;
265 }
266 
272 ServiceList Account::enabledServices() const
273 {
274  GList *list;
275  list = ag_account_list_enabled_services(d->m_account);
276 
277  /* convert glist -> ServiceList */
278  ServiceList servList;
279  GList *iter;
280  for (iter = list; iter; iter = g_list_next(iter))
281  {
282  AgService *service = (AgService*)iter->data;
283  servList.append(Service(service, StealReference));
284  }
285 
286  g_list_free(list);
287 
288  return servList;
289 }
290 
297 bool Account::enabled() const
298 {
299  return ag_account_get_enabled(d->m_account);
300 }
301 
309 void Account::setEnabled(bool enabled)
310 {
311  ag_account_set_enabled(d->m_account, enabled);
312 }
313 
319 QString Account::displayName() const
320 {
321  return UTF8(ag_account_get_display_name(d->m_account));
322 }
323 
328 void Account::setDisplayName(const QString &displayName)
329 {
330  ag_account_set_display_name(d->m_account,
331  displayName.toUtf8().constData());
332 }
333 
337 QString Account::providerName() const
338 {
339  return UTF8(ag_account_get_provider_name(d->m_account));
340 }
341 
347 void Account::selectService(const Service &service)
348 {
349  AgService *agService = NULL;
350 
351  if (service.isValid())
352  agService = service.service();
353 
354  ag_account_select_service(d->m_account, agService);
355  d->prefix = QString();
356 }
357 
362 {
363  AgService *agService = ag_account_get_selected_service(d->m_account);
364  return Service(agService);
365 }
366 
372 QStringList Account::allKeys() const
373 {
374  QStringList allKeys;
375  AgAccountSettingIter iter;
376  const gchar *key;
377  const GValue *val;
378 
379  /* iterate the settings */
380  QByteArray tmp = d->prefix.toLatin1();
381  ag_account_settings_iter_init(d->m_account, &iter, tmp.constData());
382  while (ag_account_settings_iter_next(&iter, &key, &val))
383  {
384  allKeys.append(QString(ASCII(key)));
385  }
386  return allKeys;
387 }
388 
395 void Account::beginGroup(const QString &prefix)
396 {
397  d->prefix += prefix + slash;
398 }
399 
405 QStringList Account::childGroups() const
406 {
407  QStringList groups, all_keys;
408 
409  all_keys = allKeys();
410  foreach (QString key, all_keys)
411  {
412  if (key.contains(slash)) {
413  QString group = key.section(slash, 0, 0);
414  if (!groups.contains(group))
415  groups.append(group);
416  }
417  }
418  return groups;
419 }
420 
426 QStringList Account::childKeys() const
427 {
428  QStringList keys, all_keys;
429 
430  all_keys = allKeys();
431  foreach (QString key, all_keys)
432  {
433  if (!key.contains(slash))
434  keys.append(key);
435  }
436  return keys;
437 }
438 
444 {
445  /* clear() must ignore the group: so, temporarily reset it and call
446  * remove("") */
447  QString saved_prefix = d->prefix;
448  d->prefix = QString();
449  remove(QString());
450  d->prefix = saved_prefix;
451 }
452 
459 bool Account::contains(const QString &key) const
460 {
461  return childKeys().contains(key);
462 }
463 
470 {
471  d->prefix = d->prefix.section(slash, 0, -3,
472  QString::SectionIncludeTrailingSep);
473  if (d->prefix[0] == slash) d->prefix.remove(0, 1);
474 }
475 
481 QString Account::group() const
482 {
483  if (d->prefix.endsWith(slash))
484  return d->prefix.left(d->prefix.size() - 1);
485  return d->prefix;
486 }
487 
492 {
493  return true;
494 }
495 
503 void Account::remove(const QString &key)
504 {
505  if (key.isEmpty())
506  {
507  /* delete all keys in the group */
508  QStringList keys = allKeys();
509  foreach (QString key, keys)
510  {
511  if (!key.isEmpty())
512  remove(key);
513  }
514  }
515  else
516  {
517  QString full_key = d->prefix + key;
518  QByteArray tmpkey = full_key.toLatin1();
519  ag_account_set_value(d->m_account, tmpkey.constData(), NULL);
520  }
521 }
522 
530 void Account::setValue(const QString &key, const QVariant &value)
531 {
532  TRACE();
533  GValue val= {0, {{0}}};
534 
535  if (!variantToGValue(value, &val)) {
536  return;
537  }
538 
539  QString full_key = d->prefix + key;
540  QByteArray tmpkey = full_key.toLatin1();
541  ag_account_set_value(d->m_account, tmpkey.constData(), &val);
542  g_value_unset(&val);
543 }
544 
545 void Account::Private::account_store_cb(AgAccount *account, const GError *err,
546  Account *self)
547 {
548  TRACE() << "Saved accunt ID:" << account->id;
549 
550  if (err) {
551  emit self->error(Error(err));
552  } else {
553  emit self->synced();
554  }
555 
556  Q_UNUSED(account);
557 }
558 
572 SettingSource Account::value(const QString &key, QVariant &value) const
573 {
574  GType type;
575 
576  switch (value.type())
577  {
578  case QVariant::String:
579  type = G_TYPE_STRING;
580  break;
581  case QVariant::Int:
582  type = G_TYPE_INT;
583  break;
584  case QVariant::UInt:
585  type = G_TYPE_UINT;
586  break;
587  case QVariant::LongLong:
588  type = G_TYPE_INT64;
589  break;
590  case QVariant::ULongLong:
591  type = G_TYPE_UINT64;
592  break;
593  case QVariant::Bool:
594  type = G_TYPE_BOOLEAN;
595  break;
596  default:
597  qWarning("Unsupported type %s", value.typeName());
598  return NONE;
599  }
600 
601  GValue val= {0, {{0}}};
602  g_value_init(&val, type);
603  QString full_key = d->prefix + key;
604  AgSettingSource source =
605  ag_account_get_value(d->m_account,
606  full_key.toLatin1().constData(), &val);
607  if (source == AG_SETTING_SOURCE_NONE)
608  return NONE;
609 
610  value = gvalueToVariant(&val);
611  g_value_unset(&val);
612 
613  return (source == AG_SETTING_SOURCE_ACCOUNT) ? ACCOUNT : TEMPLATE;
614 }
615 
625 QString Account::valueAsString(const QString &key,
626  QString default_value,
627  SettingSource *source) const
628 {
629  QVariant var = default_value;
630  SettingSource src = value(key, var);
631  if (source)
632  *source = src;
633  return var.toString();
634 }
635 
645 int Account::valueAsInt(const QString &key,
646  int default_value,
647  SettingSource *source) const
648 {
649  QVariant var = default_value;
650  SettingSource src = value(key, var);
651  if (source)
652  *source = src;
653  return var.toInt();
654 }
655 
665 quint64 Account::valueAsUInt64(const QString &key,
666  quint64 default_value,
667  SettingSource *source) const
668 {
669  QVariant var = default_value;
670  SettingSource src = value(key, var);
671  if (source)
672  *source = src;
673  return var.toULongLong();
674 }
675 
685 bool Account::valueAsBool(const QString &key,
686  bool default_value,
687  SettingSource *source) const
688 {
689  QVariant var = default_value;
690  SettingSource src = value(key, var);
691  if (source)
692  *source = src;
693  return var.toBool();
694 }
695 
696 void Watch::Private::account_notify_cb(AgAccount *account, const gchar *key,
697  Watch *watch)
698 {
699  emit watch->notify(key);
700 
701  Q_UNUSED(account);
702 }
703 
714 Watch *Account::watchKey(const QString &key)
715 {
716  AgAccountWatch ag_watch;
717  Watch *watch = new Watch(this);
718 
719  if (!key.isEmpty())
720  {
721  QString full_key = d->prefix + key;
722  ag_watch = ag_account_watch_key
723  (d->m_account, full_key.toLatin1().constData(),
724  (AgAccountNotifyCb)&Watch::Private::account_notify_cb, watch);
725  }
726  else
727  {
728  ag_watch = ag_account_watch_dir
729  (d->m_account, d->prefix.toLatin1().constData(),
730  (AgAccountNotifyCb)&Watch::Private::account_notify_cb, watch);
731  }
732 
733  if (!ag_watch)
734  {
735  delete watch;
736  return NULL;
737  }
738 
739  watch->setWatch(ag_watch);
740  return watch;
741 }
742 
756 {
757  TRACE();
758 
759  ag_account_store(d->m_account,
760  (AgAccountStoreCb)&Private::account_store_cb,
761  this);
762 }
763 
772 {
773  TRACE();
774 
775  GError *error = NULL;
776  bool ret;
777 
778  ret = ag_account_store_blocking(d->m_account, &error);
779  if (error)
780  {
781  qWarning() << "Store operation failed: " << error->message;
782  g_error_free(error);
783  }
784 
785  return ret;
786 }
787 
793 {
794  TRACE();
795  ag_account_delete(d->m_account);
796 }
797 
807 void Account::sign(const QString &key, const char *token)
808 {
809  ag_account_sign (d->m_account, key.toUtf8().constData(), token);
810 }
811 
823 bool Account::verify(const QString &key, const char **token)
824 {
825  return ag_account_verify(d->m_account, key.toUtf8().constData(), token);
826 }
827 
840 bool Account::verifyWithTokens(const QString &key, QList<const char*> tokens)
841 {
842  int tokensCount = tokens.count();
843 
844  const char *tmp[tokensCount + 1];
845 
846  for (int i = 0; i < tokensCount; ++i)
847  {
848  tmp[i] = tokens.at(i);
849  }
850  tmp[tokensCount] = NULL;
851 
852  return ag_account_verify_with_tokens(d->m_account, key.toUtf8().constData(), tmp);
853 }
854 
856 {
857  QString key = ACCOUNTS_KEY_CREDENTIALS_ID;
858  QVariant val(QVariant::Int);
859 
860  if (value(key, val) != NONE)
861  return val.toUInt();
862 
863  uint id = 0;
864  Service service = selectedService();
865  if (service.isValid()) {
866  selectService();
867  if (value(key, val) != NONE)
868  id = val.toUInt();
869  selectService(service);
870  }
871  return id;
872 }
873 
874 AgAccount *Account::account()
875 {
876  return d->m_account;
877 }