libaccounts-qt  1.1
account.cpp
00001 /* vi: set et sw=4 ts=4 cino=t0,(0: */
00002 /*
00003  * This file is part of libaccounts-qt
00004  *
00005  * Copyright (C) 2009-2011 Nokia Corporation.
00006  *
00007  * Contact: Alberto Mardegan <alberto.mardegan@nokia.com>
00008  *
00009  * This library is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public License
00011  * version 2.1 as published by the Free Software Foundation.
00012  *
00013  * This library is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with this library; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
00021  * 02110-1301 USA
00022  */
00023 
00024 #include "account.h"
00025 #include "manager.h"
00026 #include "utils.h"
00027 
00028 #undef signals
00029 #include <libaccounts-glib/ag-manager.h>
00030 #include <libaccounts-glib/ag-account.h>
00031 
00032 namespace Accounts {
00033 
00074 class Account::Private
00075 {
00076 public:
00077     Private()
00078     {
00079         m_account = 0;
00080     }
00081 
00082     ~Private() {}
00083 
00084     AgAccount *m_account;  //real account
00085     QString prefix;
00086 
00087     static void on_display_name_changed(Account *self);
00088     static void on_enabled(Account *self, const gchar *service_name,
00089                            gboolean enabled);
00090     static void account_store_cb(AgAccount *account, const GError *error,
00091                                  Account *self);
00092     static void on_deleted(Account *self);
00093 };
00094 
00095 class Watch::Private
00096 {
00097 public:
00098     static void account_notify_cb(AgAccount *account, const gchar *key,
00099                                   Watch *self);
00100 };
00101 } //namespace Accounts
00102 
00103 
00104 using namespace Accounts;
00105 
00106 static QChar slash = QChar::fromLatin1('/');
00107 
00117 Watch::Watch(QObject *parent)
00118     : QObject(parent)
00119 {
00120 }
00121 
00122 Watch::~Watch()
00123 {
00124     TRACE();
00125     Account *account = qobject_cast<Account *>(QObject::parent());
00126     /* The destructor of Account deletes the child Watches before detaching
00127      * them, so here account should always be not NULL */
00128     Q_ASSERT(account != NULL);
00129     ag_account_remove_watch(account->d->m_account, watch);
00130 }
00131 
00132 void Account::Private::on_display_name_changed(Account *self)
00133 {
00134     TRACE();
00135     const gchar *name = ag_account_get_display_name(self->d->m_account);
00136 
00137     emit self->displayNameChanged(UTF8(name));
00138 }
00139 
00140 void Account::Private::on_enabled(Account *self, const gchar *service_name,
00141                                   gboolean enabled)
00142 {
00143     TRACE();
00144 
00145     emit self->enabledChanged(UTF8(service_name), enabled);
00146 }
00147 
00148 void Account::Private::on_deleted(Account *self)
00149 {
00150     TRACE();
00151 
00152     emit self->removed();
00153 }
00154 
00161 Account::Account(AgAccount *account, QObject *parent)
00162     : QObject(parent), d(new Private)
00163 {
00164     TRACE();
00165     d->m_account = account;
00166     g_object_ref(account);
00167 
00168     g_signal_connect_swapped(account, "display-name-changed",
00169                              G_CALLBACK(&Private::on_display_name_changed),
00170                              this);
00171     g_signal_connect_swapped(account, "enabled",
00172                              G_CALLBACK(&Private::on_enabled), this);
00173     g_signal_connect_swapped(account, "deleted",
00174                              G_CALLBACK(&Private::on_deleted), this);
00175 }
00176 
00180 Account::~Account()
00181 {
00182     TRACE();
00183 
00184     QObjectList list = children();
00185     for (int i = 0; i < list.count(); i++)
00186     {
00187         QObject *o = list.at(i);
00188         if (qobject_cast<Watch *>(o))
00189             delete o;
00190     }
00191 
00192     g_signal_handlers_disconnect_by_func
00193         (d->m_account, (void *)&Private::on_display_name_changed, this);
00194     g_signal_handlers_disconnect_by_func
00195         (d->m_account, (void *)&Private::on_enabled, this);
00196     g_signal_handlers_disconnect_by_func
00197         (d->m_account, (void *)&Private::on_deleted, this);
00198     g_object_unref(d->m_account);
00199     delete d;
00200     d = 0;
00201 }
00202 
00207 AccountId Account::id() const
00208 {
00209     return d->m_account ? d->m_account->id : 0;
00210 }
00211 
00215 Manager *Account::manager() const
00216 {
00217     return qobject_cast<Manager *>(QObject::parent());
00218 }
00219 
00223 bool Account::supportsService(const QString &serviceType) const
00224 {
00225     TRACE() << serviceType;
00226 
00227     return ag_account_supports_service(d->m_account,
00228                                        serviceType.toUtf8().constData());
00229 }
00230 
00239 ServiceList Account::services(const QString &serviceType) const
00240 {
00241     TRACE() << serviceType;
00242 
00243     GList *list;
00244     if (serviceType.isEmpty()) {
00245         list = ag_account_list_services(d->m_account);
00246     } else {
00247         list = ag_account_list_services_by_type(d->m_account,
00248             serviceType.toUtf8().constData());
00249     }
00250 
00251     /* convert glist -> ServiceList */
00252     ServiceList servList;
00253     GList *iter;
00254     Manager *mgr = manager();
00255     Q_ASSERT(mgr != 0);
00256     for (iter = list; iter; iter = g_list_next(iter))
00257     {
00258         Service *serv = mgr->serviceInstance((AgService*)(iter->data));
00259         servList.append(serv);
00260     }
00261 
00262     ag_service_list_free(list);
00263 
00264     return servList;
00265 }
00266 
00272 ServiceList Account::enabledServices() const
00273 {
00274     GList *list;
00275     list = ag_account_list_enabled_services(d->m_account);
00276 
00277     /* convert glist -> ServiceList */
00278     ServiceList servList;
00279     GList *iter;
00280     Manager *mgr = manager();
00281     Q_ASSERT(mgr != 0);
00282     for (iter = list; iter; iter = g_list_next(iter))
00283     {
00284         Service *serv = mgr->serviceInstance((AgService*)(iter->data));
00285         servList.append(serv);
00286     }
00287 
00288     ag_service_list_free(list);
00289 
00290     return servList;
00291 }
00292 
00299 bool Account::enabled() const
00300 {
00301     return ag_account_get_enabled(d->m_account);
00302 }
00303 
00311 void Account::setEnabled(bool enabled)
00312 {
00313     ag_account_set_enabled(d->m_account, enabled);
00314 }
00315 
00321 QString Account::displayName() const
00322 {
00323     return UTF8(ag_account_get_display_name(d->m_account));
00324 }
00325 
00330 void Account::setDisplayName(const QString &displayName)
00331 {
00332     ag_account_set_display_name(d->m_account,
00333                                 displayName.toUtf8().constData());
00334 }
00335 
00339 QString Account::providerName() const
00340 {
00341     return UTF8(ag_account_get_provider_name(d->m_account));
00342 }
00343 
00349 void Account::selectService(const Service *service)
00350 {
00351     AgService *agService = NULL;
00352 
00353     if (service != NULL)
00354         agService = service->service();
00355 
00356     ag_account_select_service(d->m_account, agService);
00357     d->prefix = QString();
00358 }
00359 
00363 Service* Account::selectedService() const
00364 {
00365     AgService *agService = ag_account_get_selected_service(d->m_account);
00366     if (agService == NULL)
00367         return NULL;
00368 
00369     Manager *mgr = manager();
00370     Q_ASSERT(mgr != 0);
00371     Service *service = mgr->serviceInstance(agService);
00372 
00373     return service;
00374 }
00375 
00381 QStringList Account::allKeys() const
00382 {
00383     QStringList allKeys;
00384     AgAccountSettingIter iter;
00385     const gchar *key;
00386     const GValue *val;
00387 
00388     /* iterate the settings */
00389     QByteArray tmp = d->prefix.toLatin1();
00390     ag_account_settings_iter_init(d->m_account, &iter, tmp.constData());
00391     while (ag_account_settings_iter_next(&iter, &key, &val))
00392     {
00393         allKeys.append(QString(ASCII(key)));
00394     }
00395     return allKeys;
00396 }
00397 
00404 void Account::beginGroup(const QString &prefix)
00405 {
00406     d->prefix += prefix + slash;
00407 }
00408 
00414 QStringList Account::childGroups() const
00415 {
00416     QStringList groups, all_keys;
00417 
00418     all_keys = allKeys();
00419     foreach (QString key, all_keys)
00420     {
00421         if (key.contains(slash)) {
00422             QString group = key.section(slash, 0, 0);
00423             if (!groups.contains(group))
00424                 groups.append(group);
00425         }
00426     }
00427     return groups;
00428 }
00429 
00435 QStringList Account::childKeys() const
00436 {
00437     QStringList keys, all_keys;
00438 
00439     all_keys = allKeys();
00440     foreach (QString key, all_keys)
00441     {
00442         if (!key.contains(slash))
00443             keys.append(key);
00444     }
00445     return keys;
00446 }
00447 
00452 void Account::clear()
00453 {
00454     /* clear() must ignore the group: so, temporarily reset it and call
00455      * remove("") */
00456     QString saved_prefix = d->prefix;
00457     d->prefix = QString();
00458     remove(QString());
00459     d->prefix = saved_prefix;
00460 }
00461 
00468 bool Account::contains(const QString &key) const
00469 {
00470     return childKeys().contains(key);
00471 }
00472 
00478 void Account::endGroup()
00479 {
00480     d->prefix = d->prefix.section(slash, 0, -3,
00481                                   QString::SectionIncludeTrailingSep);
00482     if (d->prefix[0] == slash) d->prefix.remove(0, 1);
00483 }
00484 
00490 QString Account::group() const
00491 {
00492     if (d->prefix.endsWith(slash))
00493         return d->prefix.left(d->prefix.size() - 1);
00494     return d->prefix;
00495 }
00496 
00500 bool Account::isWritable() const
00501 {
00502     return true;
00503 }
00504 
00512 void Account::remove(const QString &key)
00513 {
00514     if (key.isEmpty())
00515     {
00516         /* delete all keys in the group */
00517         QStringList keys = allKeys();
00518         foreach (QString key, keys)
00519         {
00520             if (!key.isEmpty())
00521                 remove(key);
00522         }
00523     }
00524     else
00525     {
00526         QString full_key = d->prefix + key;
00527         QByteArray tmpkey = full_key.toLatin1();
00528         ag_account_set_value(d->m_account, tmpkey.constData(), NULL);
00529     }
00530 }
00531 
00539 void Account::setValue(const QString &key, const QVariant &value)
00540 {
00541     TRACE();
00542     GValue val= {0, {{0}}};
00543 
00544     if (!variantToGValue(value, &val)) {
00545         return;
00546     }
00547 
00548     QString full_key = d->prefix + key;
00549     QByteArray tmpkey = full_key.toLatin1();
00550     ag_account_set_value(d->m_account, tmpkey.constData(), &val);
00551     g_value_unset(&val);
00552 }
00553 
00554 void Account::Private::account_store_cb(AgAccount *account, const GError *err,
00555                                         Account *self)
00556 {
00557     TRACE() << "Saved accunt ID:" << account->id;
00558 
00559     if (err) {
00560         emit self->error(Error(err));
00561     } else {
00562         emit self->synced();
00563     }
00564 
00565     Q_UNUSED(account);
00566 }
00567 
00580 void Account::sync()
00581 {
00582     TRACE();
00583 
00584     ag_account_store(d->m_account,
00585                      (AgAccountStoreCb)&Private::account_store_cb,
00586                      this);
00587 }
00588 
00596 bool Account::syncAndBlock()
00597 {
00598     TRACE();
00599 
00600     GError *error = NULL;
00601     bool ret;
00602 
00603     ret = ag_account_store_blocking(d->m_account, &error);
00604     if (error)
00605     {
00606         qWarning() << "Store operation failed: " << error->message;
00607         g_error_free(error);
00608     }
00609 
00610     return ret;
00611 }
00612 
00626 SettingSource Account::value(const QString &key, QVariant &value) const
00627 {
00628     GType type;
00629 
00630     switch (value.type())
00631     {
00632     case QVariant::String:
00633         type = G_TYPE_STRING;
00634         break;
00635     case QVariant::Int:
00636         type = G_TYPE_INT;
00637         break;
00638     case QVariant::UInt:
00639         type = G_TYPE_UINT;
00640         break;
00641     case QVariant::LongLong:
00642         type = G_TYPE_INT64;
00643         break;
00644     case QVariant::ULongLong:
00645         type = G_TYPE_UINT64;
00646         break;
00647     case QVariant::Bool:
00648         type = G_TYPE_BOOLEAN;
00649         break;
00650     default:
00651         qWarning("Unsupported type %s", value.typeName());
00652         return NONE;
00653     }
00654 
00655     GValue val= {0, {{0}}};
00656     g_value_init(&val, type);
00657     QString full_key = d->prefix + key;
00658     AgSettingSource source =
00659         ag_account_get_value(d->m_account,
00660                              full_key.toLatin1().constData(), &val);
00661     if (source == AG_SETTING_SOURCE_NONE)
00662         return NONE;
00663 
00664     value = gvalueToVariant(&val);
00665     g_value_unset(&val);
00666 
00667     return (source == AG_SETTING_SOURCE_ACCOUNT) ? ACCOUNT : TEMPLATE;
00668 }
00669 
00679 QString Account::valueAsString(const QString &key,
00680                                QString default_value,
00681                                SettingSource *source) const
00682 {
00683     QVariant var = default_value;
00684     SettingSource src = value(key, var);
00685     if (source)
00686         *source = src;
00687     return var.toString();
00688 }
00689 
00699 int Account::valueAsInt(const QString &key,
00700                         int default_value,
00701                         SettingSource *source) const
00702 {
00703     QVariant var = default_value;
00704     SettingSource src = value(key, var);
00705     if (source)
00706         *source = src;
00707     return var.toInt();
00708 }
00709 
00719 quint64 Account::valueAsUInt64(const QString &key,
00720                         quint64 default_value,
00721                         SettingSource *source) const
00722 {
00723     QVariant var = default_value;
00724     SettingSource src = value(key, var);
00725     if (source)
00726         *source = src;
00727     return var.toULongLong();
00728 }
00729 
00739 bool Account::valueAsBool(const QString &key,
00740                           bool default_value,
00741                           SettingSource *source) const
00742 {
00743     QVariant var = default_value;
00744     SettingSource src = value(key, var);
00745     if (source)
00746         *source = src;
00747     return var.toBool();
00748 }
00749 
00750 void Watch::Private::account_notify_cb(AgAccount *account, const gchar *key,
00751                                        Watch *watch)
00752 {
00753     emit watch->notify(key);
00754 
00755     Q_UNUSED(account);
00756 }
00757 
00768 Watch *Account::watchKey(const QString &key)
00769 {
00770     AgAccountWatch ag_watch;
00771     Watch *watch = new Watch(this);
00772 
00773     if (!key.isEmpty())
00774     {
00775         QString full_key = d->prefix + key;
00776         ag_watch = ag_account_watch_key
00777             (d->m_account, full_key.toLatin1().constData(),
00778              (AgAccountNotifyCb)&Watch::Private::account_notify_cb, watch);
00779     }
00780     else
00781     {
00782         ag_watch = ag_account_watch_dir
00783             (d->m_account, d->prefix.toLatin1().constData(),
00784              (AgAccountNotifyCb)&Watch::Private::account_notify_cb, watch);
00785     }
00786 
00787     if (!ag_watch)
00788     {
00789         delete watch;
00790         return NULL;
00791     }
00792 
00793     watch->setWatch(ag_watch);
00794     return watch;
00795 }
00796 
00801 void Account::remove()
00802 {
00803     TRACE();
00804     ag_account_delete(d->m_account);
00805 }
00806 
00816 void Account::sign(const QString &key, const char *token)
00817 {
00818     ag_account_sign (d->m_account, key.toUtf8().constData(), token);
00819 }
00820 
00832 bool Account::verify(const QString &key, const char **token)
00833 {
00834     return ag_account_verify(d->m_account, key.toUtf8().constData(), token);
00835 }
00836 
00849 bool Account::verifyWithTokens(const QString &key, QList<const char*> tokens)
00850 {
00851     int tokensCount = tokens.count();
00852 
00853     const char *tmp[tokensCount + 1];
00854 
00855     for (int i = 0; i < tokensCount; ++i)
00856     {
00857         tmp[i] = tokens.at(i);
00858     }
00859     tmp[tokensCount] = NULL;
00860 
00861     return ag_account_verify_with_tokens(d->m_account, key.toUtf8().constData(), tmp);
00862 }
00863 
00864 qint32 Account::credentialsId()
00865 {
00866     QString key = ACCOUNTS_KEY_CREDENTIALS_ID;
00867     QVariant val(QVariant::Int);
00868 
00869     if (value(key, val) != NONE)
00870         return val.toInt();
00871 
00872     qint32 id = 0;
00873     Service *service = selectedService();
00874     if (service) {
00875         selectService(NULL);
00876         if (value(key, val) != NONE)
00877             id = val.toInt();
00878         selectService(service);
00879     }
00880     return id;
00881 }
00882 
00883 AgAccount *Account::account()
00884 {
00885     return d->m_account;
00886 }