accounts-qt  0.31
account.cpp
Go to the documentation of this file.
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-2010 Nokia Corporation.
6  *
7  * Contact: Alberto Mardegan <alberto.mardegan@nokia.com>
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * version 2.1 as published by the Free Software Foundation.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  */
23 
24 #include "account.h"
25 #include "manager.h"
26 
27 #include <libaccounts-glib/ag-manager.h>
28 #include <libaccounts-glib/ag-account.h>
29 
30 namespace Accounts {
31 
32 class Account::Private
33 {
34 public:
35  Private()
36  {
37  m_account = 0;
38  }
39 
40  ~Private() {}
41 
42  AgAccount *m_account; //real account
43  QString prefix;
44 
45  static void on_display_name_changed(Account *self);
46  static void on_enabled(Account *self, const gchar *service_name,
47  gboolean enabled);
48  static void account_store_cb(AgAccount *account, const GError *error,
49  Account *self);
50  static void on_deleted(Account *self);
51 };
52 
53 class Watch::Private
54 {
55 public:
56  static void account_notify_cb(AgAccount *account, const gchar *key,
57  Watch *self);
58 };
59 } //namespace Accounts
60 
61 
62 using namespace Accounts;
63 
64 static QChar slash = QChar::fromLatin1('/');
65 
66 Watch::Watch(QObject *parent)
67  : QObject(parent)
68 {
69 }
70 
71 Watch::~Watch()
72 {
73  TRACE();
74  Account *account = qobject_cast<Account *>(QObject::parent());
75  /* The destructor of Account deletes the child Watches before detaching
76  * them, so here account should always be not NULL */
77  Q_ASSERT(account != NULL);
78  ag_account_remove_watch(account->d->m_account, watch);
79 }
80 
81 void Account::Private::on_display_name_changed(Account *self)
82 {
83  TRACE();
84  const gchar *name = ag_account_get_display_name(self->d->m_account);
85 
86  emit self->displayNameChanged(UTF8(name));
87 }
88 
89 void Account::Private::on_enabled(Account *self, const gchar *service_name,
90  gboolean enabled)
91 {
92  TRACE();
93 
94  emit self->enabledChanged(UTF8(service_name), enabled);
95 }
96 
97 void Account::Private::on_deleted(Account *self)
98 {
99  TRACE();
100 
101  emit self->removed();
102 }
103 
104 Account::Account(AgAccount *account, QObject *parent)
105  : QObject(parent), d(new Private)
106 {
107  TRACE();
108  d->m_account = account;
109  g_object_ref(account);
110 
111  g_signal_connect_swapped(account, "display-name-changed",
112  G_CALLBACK(&Private::on_display_name_changed),
113  this);
114  g_signal_connect_swapped(account, "enabled",
115  G_CALLBACK(&Private::on_enabled), this);
116  g_signal_connect_swapped(account, "deleted",
117  G_CALLBACK(&Private::on_deleted), this);
118 }
119 
120 Account::~Account()
121 {
122  TRACE();
123 
124  QObjectList list = children();
125  for (int i = 0; i < list.count(); i++)
126  {
127  QObject *o = list.at(i);
128  if (qobject_cast<Watch *>(o))
129  delete o;
130  }
131 
132  g_signal_handlers_disconnect_by_func
133  (d->m_account, (void *)&Private::on_display_name_changed, this);
134  g_signal_handlers_disconnect_by_func
135  (d->m_account, (void *)&Private::on_enabled, this);
136  g_signal_handlers_disconnect_by_func
137  (d->m_account, (void *)&Private::on_deleted, this);
138  g_object_unref(d->m_account);
139  delete d;
140  d = 0;
141 }
142 
144 {
145  return d->m_account ? d->m_account->id : 0;
146 }
147 
149 {
150  return qobject_cast<Manager *>(QObject::parent());
151 }
152 
153 bool Account::supportsService(const QString &serviceType) const
154 {
155  TRACE() << serviceType;
156 
157  return ag_account_supports_service(d->m_account,
158  serviceType.toUtf8().constData());
159 }
160 
161 ServiceList Account::services(const QString &serviceType) const
162 {
163  TRACE() << serviceType;
164 
165  GList *list;
166  if (serviceType.isEmpty()) {
167  list = ag_account_list_services(d->m_account);
168  } else {
169  list = ag_account_list_services_by_type(d->m_account,
170  serviceType.toUtf8().constData());
171  }
172 
173  /* convert glist -> ServiceList */
174  ServiceList servList;
175  GList *iter;
176  Manager *mgr = manager();
177  Q_ASSERT(mgr != 0);
178  for (iter = list; iter; iter = g_list_next(iter))
179  {
180  Service *serv = mgr->serviceInstance((AgService*)(iter->data));
181  servList.append(serv);
182  }
183 
184  ag_service_list_free(list);
185 
186  return servList;
187 }
188 
190 {
191  GList *list;
192  list = ag_account_list_enabled_services(d->m_account);
193 
194  /* convert glist -> ServiceList */
195  ServiceList servList;
196  GList *iter;
197  Manager *mgr = manager();
198  Q_ASSERT(mgr != 0);
199  for (iter = list; iter; iter = g_list_next(iter))
200  {
201  Service *serv = mgr->serviceInstance((AgService*)(iter->data));
202  servList.append(serv);
203  }
204 
205  ag_service_list_free(list);
206 
207  return servList;
208 }
209 
210 bool Account::enabled() const
211 {
212  return ag_account_get_enabled(d->m_account);
213 }
214 
215 void Account::setEnabled(bool enabled)
216 {
217  ag_account_set_enabled(d->m_account, enabled);
218 }
219 
220 QString Account::displayName() const
221 {
222  return UTF8(ag_account_get_display_name(d->m_account));
223 }
224 
225 void Account::setDisplayName(const QString &displayName)
226 {
227  ag_account_set_display_name(d->m_account,
228  displayName.toUtf8().constData());
229 }
230 
231 QString Account::providerName() const
232 {
233  return UTF8(ag_account_get_provider_name(d->m_account));
234 }
235 
236 void Account::selectService(const Service *service)
237 {
238  AgService *agService = NULL;
239 
240  if (service != NULL)
241  agService = service->service();
242 
243  ag_account_select_service(d->m_account, agService);
244  d->prefix = QString();
245 }
246 
248 {
249  AgService *agService = ag_account_get_selected_service(d->m_account);
250  if (agService == NULL)
251  return NULL;
252 
253  Manager *mgr = manager();
254  Q_ASSERT(mgr != 0);
255  Service *service = mgr->serviceInstance(agService);
256 
257  return service;
258 }
259 
260 QStringList Account::allKeys() const
261 {
262  QStringList allKeys;
263  AgAccountSettingIter iter;
264  const gchar *key;
265  const GValue *val;
266 
267  /* iterate the settings */
268  QByteArray tmp = d->prefix.toLatin1();
269  ag_account_settings_iter_init(d->m_account, &iter, tmp.constData());
270  while (ag_account_settings_iter_next(&iter, &key, &val))
271  {
272  allKeys.append(QString(ASCII(key)).mid(d->prefix.size()));
273  }
274  return allKeys;
275 }
276 
277 void Account::beginGroup(const QString &prefix)
278 {
279  d->prefix += prefix + slash;
280 }
281 
282 QStringList Account::childGroups() const
283 {
284  QStringList groups, all_keys;
285 
286  all_keys = allKeys();
287  foreach (QString key, all_keys)
288  {
289  if (key.contains(slash)) {
290  QString group = key.section(slash, 0, 0);
291  if (!groups.contains(group))
292  groups.append(group);
293  }
294  }
295  return groups;
296 }
297 
298 QStringList Account::childKeys() const
299 {
300  QStringList keys, all_keys;
301 
302  all_keys = allKeys();
303  foreach (QString key, all_keys)
304  {
305  if (!key.contains(slash))
306  keys.append(key);
307  }
308  return keys;
309 }
310 
312 {
313  /* clear() must ignore the group: so, temporarily reset it and call
314  * remove("") */
315  QString saved_prefix = d->prefix;
316  d->prefix = QString();
317  remove(QString());
318  d->prefix = saved_prefix;
319 }
320 
321 bool Account::contains(const QString &key) const
322 {
323  return childKeys().contains(key);
324 }
325 
327 {
328  d->prefix = d->prefix.section(slash, 0, -3,
329  QString::SectionIncludeTrailingSep);
330  if (d->prefix[0] == slash) d->prefix.remove(0, 1);
331 }
332 
333 QString Account::group() const
334 {
335  if (d->prefix.endsWith(slash))
336  return d->prefix.left(d->prefix.size() - 1);
337  return d->prefix;
338 }
339 
341 {
342  return true;
343 }
344 
345 void Account::remove(const QString &key)
346 {
347  if (key.isEmpty())
348  {
349  /* delete all keys in the group */
350  QStringList keys = allKeys();
351  foreach (QString key, keys)
352  {
353  if (!key.isEmpty())
354  remove(key);
355  }
356  }
357  else
358  {
359  QString full_key = d->prefix + key;
360  QByteArray tmpkey = full_key.toLatin1();
361  ag_account_set_value(d->m_account, tmpkey.constData(), NULL);
362  }
363 }
364 
365 void Account::setValue(const QString &key, const QVariant &value)
366 {
367  TRACE();
368  GValue val= {0, {{0}}};
369  QByteArray tmpvalue;
370 
371  switch (value.type())
372  {
373  case QVariant::String:
374  g_value_init(&val, G_TYPE_STRING);
375  tmpvalue = value.toString().toUtf8();
376  g_value_set_static_string(&val, tmpvalue.constData());
377  break;
378  case QVariant::Int:
379  g_value_init(&val, G_TYPE_INT);
380  g_value_set_int(&val, value.toInt());
381  break;
382  case QVariant::UInt:
383  g_value_init(&val, G_TYPE_UINT);
384  g_value_set_uint(&val, value.toUInt());
385  break;
386  case QVariant::LongLong:
387  g_value_init(&val, G_TYPE_INT64);
388  g_value_set_int64(&val, value.toLongLong());
389  break;
390  case QVariant::ULongLong:
391  g_value_init(&val, G_TYPE_UINT64);
392  g_value_set_uint64(&val, value.toULongLong());
393  break;
394  case QVariant::Bool:
395  g_value_init(&val, G_TYPE_BOOLEAN);
396  g_value_set_boolean(&val, value.toBool());
397  break;
398  default:
399  qWarning("unsupproted datatype %s", value.typeName());
400  return;
401  }
402 
403  QString full_key = d->prefix + key;
404  QByteArray tmpkey = full_key.toLatin1();
405  ag_account_set_value(d->m_account, tmpkey.constData(), &val);
406  g_value_unset(&val);
407 }
408 
409 void Account::Private::account_store_cb(AgAccount *account, const GError *err,
410  Account *self)
411 {
412  TRACE() << "Saved accunt ID:" << account->id;
413 
414  if (err) {
415  emit self->error((ErrorCode)err->code);
416  } else {
417  emit self->synced();
418  }
419 
420  Q_UNUSED(account);
421 }
422 
424 {
425  TRACE();
426 
427  ag_account_store(d->m_account,
428  (AgAccountStoreCb)&Private::account_store_cb,
429  this);
430 }
431 
433 {
434  TRACE();
435 
436  GError *error = NULL;
437  bool ret;
438 
439  ret = ag_account_store_blocking(d->m_account, &error);
440  if (error)
441  {
442  qWarning() << "Store operation failed: " << error->message;
443  g_error_free(error);
444  }
445 
446  return ret;
447 }
448 
449 SettingSource Account::value(const QString &key, QVariant &value) const
450 {
451  GType type;
452 
453  switch (value.type())
454  {
455  case QVariant::String:
456  type = G_TYPE_STRING;
457  break;
458  case QVariant::Int:
459  type = G_TYPE_INT;
460  break;
461  case QVariant::UInt:
462  type = G_TYPE_UINT;
463  break;
464  case QVariant::LongLong:
465  type = G_TYPE_INT64;
466  break;
467  case QVariant::ULongLong:
468  type = G_TYPE_UINT64;
469  break;
470  case QVariant::Bool:
471  type = G_TYPE_BOOLEAN;
472  break;
473  default:
474  qWarning("Unsupported type %s", value.typeName());
475  return NONE;
476  }
477 
478  GValue val= {0, {{0}}};
479  g_value_init(&val, type);
480  QString full_key = d->prefix + key;
481  AgSettingSource source =
482  ag_account_get_value(d->m_account,
483  full_key.toLatin1().constData(), &val);
484  if (source == AG_SETTING_SOURCE_NONE)
485  return NONE;
486 
487  switch (type)
488  {
489  case G_TYPE_STRING:
490  value = UTF8(g_value_get_string(&val));
491  break;
492  case G_TYPE_INT:
493  value = g_value_get_int(&val);
494  break;
495  case G_TYPE_UINT:
496  value = g_value_get_uint(&val);
497  break;
498  case G_TYPE_INT64:
499  value = qint64(g_value_get_int64(&val));
500  break;
501  case G_TYPE_UINT64:
502  value = quint64(g_value_get_uint64(&val));
503  break;
504  case G_TYPE_BOOLEAN:
505  value = g_value_get_boolean(&val);
506  break;
507  default:
508  /* This can never be reached */
509  Q_ASSERT(false);
510  break;
511  }
512  g_value_unset(&val);
513 
514  return (source == AG_SETTING_SOURCE_ACCOUNT) ? ACCOUNT : TEMPLATE;
515 }
516 
517 QString Account::valueAsString(const QString &key,
518  QString default_value,
519  SettingSource *source) const
520 {
521  QVariant var = default_value;
522  SettingSource src = value(key, var);
523  if (source)
524  *source = src;
525  return var.toString();
526 }
527 
528 int Account::valueAsInt(const QString &key,
529  int default_value,
530  SettingSource *source) const
531 {
532  QVariant var = default_value;
533  SettingSource src = value(key, var);
534  if (source)
535  *source = src;
536  return var.toInt();
537 }
538 
539 quint64 Account::valueAsUInt64(const QString &key,
540  quint64 default_value,
541  SettingSource *source) const
542 {
543  QVariant var = default_value;
544  SettingSource src = value(key, var);
545  if (source)
546  *source = src;
547  return var.toULongLong();
548 }
549 
550 bool Account::valueAsBool(const QString &key,
551  bool default_value,
552  SettingSource *source) const
553 {
554  QVariant var = default_value;
555  SettingSource src = value(key, var);
556  if (source)
557  *source = src;
558  return var.toBool();
559 }
560 
561 void Watch::Private::account_notify_cb(AgAccount *account, const gchar *key,
562  Watch *watch)
563 {
564  emit watch->notify(key);
565 
566  Q_UNUSED(account);
567 }
568 
569 Watch *Account::watchKey(const QString &key)
570 {
571  AgAccountWatch ag_watch;
572  Watch *watch = new Watch(this);
573 
574  if (!key.isEmpty())
575  {
576  QString full_key = d->prefix + key;
577  ag_watch = ag_account_watch_key
578  (d->m_account, full_key.toLatin1().constData(),
579  (AgAccountNotifyCb)&Watch::Private::account_notify_cb, watch);
580  }
581  else
582  {
583  ag_watch = ag_account_watch_dir
584  (d->m_account, d->prefix.toLatin1().constData(),
585  (AgAccountNotifyCb)&Watch::Private::account_notify_cb, watch);
586  }
587 
588  if (!ag_watch)
589  {
590  delete watch;
591  return NULL;
592  }
593 
594  watch->setWatch(ag_watch);
595  return watch;
596 }
597 
599 {
600  TRACE();
601  ag_account_delete(d->m_account);
602 }
603 
604 void Account::sign(const QString &key, const char *token)
605 {
606  ag_account_sign (d->m_account, key.toUtf8().constData(), token);
607 }
608 
609 bool Account::verify(const QString &key, const char **token)
610 {
611  return ag_account_verify(d->m_account, key.toUtf8().constData(), token);
612 }
613 
614 bool Account::verifyWithTokens(const QString &key, QList<const char*> tokens)
615 {
616  int tokensCount = tokens.count();
617 
618  const char *tmp[tokensCount + 1];
619 
620  for (int i = 0; i < tokensCount; ++i)
621  {
622  tmp[i] = tokens.at(i);
623  }
624  tmp[tokensCount] = NULL;
625 
626  return ag_account_verify_with_tokens(d->m_account, key.toUtf8().constData(), tmp);
627 }
628 
630 {
631  QString key = ACCOUNTS_KEY_CREDENTIALS_ID;
632  QVariant val(QVariant::Int);
633 
634  if (value(key, val) != NONE)
635  return val.toInt();
636 
637  qint32 id = 0;
638  Service *service = selectedService();
639  if (service) {
640  selectService(NULL);
641  if (value(key, val) != NONE)
642  id = val.toInt();
643  selectService(service);
644  }
645  return id;
646 }