accounts-qt  1.13
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  * Copyright (C) 2012-2013 Canonical Ltd.
00007  *
00008  * Contact: Alberto Mardegan <alberto.mardegan@canonical.com>
00009  *
00010  * This library is free software; you can redistribute it and/or
00011  * modify it under the terms of the GNU Lesser General Public License
00012  * version 2.1 as published by the Free Software Foundation.
00013  *
00014  * This library is distributed in the hope that it will be useful, but
00015  * WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00017  * Lesser General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU Lesser General Public
00020  * License along with this library; if not, write to the Free Software
00021  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
00022  * 02110-1301 USA
00023  */
00024 
00025 #include "account.h"
00026 #include "manager.h"
00027 #include "manager_p.h"
00028 #include "utils.h"
00029 
00030 #include <QPointer>
00031 #include <libaccounts-glib/ag-account.h>
00032 
00033 namespace Accounts {
00034 
00075 class Account::Private
00076 {
00077 public:
00078     Private(Manager *manager, const QString &providerName, Account *account);
00079     Private(Manager *manager, AgAccount *agAccount);
00080 
00081     ~Private()
00082     {
00083         g_cancellable_cancel(m_cancellable);
00084         g_object_unref(m_cancellable);
00085         m_cancellable = NULL;
00086     }
00087 
00088     void init(Account *account);
00089 
00090     QPointer<Manager> m_manager;
00091     AgAccount *m_account;  //real account
00092     GCancellable *m_cancellable;
00093     QString prefix;
00094 
00095     static void on_display_name_changed(Account *self);
00096     static void on_enabled(Account *self, const gchar *service_name,
00097                            gboolean enabled);
00098     static void account_store_cb(AgAccount *account,
00099                                  GAsyncResult *res,
00100                                  Account *self);
00101     static void on_deleted(Account *self);
00102 };
00103 
00104 class Watch::Private
00105 {
00106 public:
00107     static void account_notify_cb(AgAccount *account, const gchar *key,
00108                                   Watch *self);
00109 };
00110 } //namespace Accounts
00111 
00112 
00113 using namespace Accounts;
00114 
00115 static QChar slash = QChar::fromLatin1('/');
00116 
00126 Watch::Watch(QObject *parent):
00127     QObject(parent)
00128 {
00129 }
00130 
00131 Watch::~Watch()
00132 {
00133     Account *account = qobject_cast<Account *>(QObject::parent());
00134     /* The destructor of Account deletes the child Watches before detaching
00135      * them, so here account should always be not NULL */
00136     Q_ASSERT(account != NULL);
00137     ag_account_remove_watch(account->d->m_account, watch);
00138 }
00139 
00140 Account::Private::Private(Manager *manager, const QString &providerName,
00141                           Account *account):
00142     m_manager(manager),
00143     m_cancellable(g_cancellable_new())
00144 {
00145     m_account = ag_manager_create_account(manager->d->m_manager,
00146                                           providerName.toUtf8().constData());
00147     init(account);
00148 }
00149 
00150 Account::Private::Private(Manager *manager, AgAccount *agAccount):
00151     m_manager(manager),
00152     m_account(agAccount),
00153     m_cancellable(g_cancellable_new())
00154 {
00155 }
00156 
00157 void Account::Private::init(Account *account)
00158 {
00159     if (m_account == 0) return;
00160     g_signal_connect_swapped(m_account, "display-name-changed",
00161                              G_CALLBACK(&Private::on_display_name_changed),
00162                              account);
00163     g_signal_connect_swapped(m_account, "enabled",
00164                              G_CALLBACK(&Private::on_enabled), account);
00165     g_signal_connect_swapped(m_account, "deleted",
00166                              G_CALLBACK(&Private::on_deleted), account);
00167 }
00168 
00169 void Account::Private::on_display_name_changed(Account *self)
00170 {
00171     const gchar *name = ag_account_get_display_name(self->d->m_account);
00172 
00173     Q_EMIT self->displayNameChanged(UTF8(name));
00174 }
00175 
00176 void Account::Private::on_enabled(Account *self, const gchar *service_name,
00177                                   gboolean enabled)
00178 {
00179     Q_EMIT self->enabledChanged(UTF8(service_name), enabled);
00180 }
00181 
00182 void Account::Private::on_deleted(Account *self)
00183 {
00184     TRACE();
00185 
00186     Q_EMIT self->removed();
00187 }
00188 
00204 Account::Account(Manager *manager, const QString &providerName,
00205                  QObject *parent):
00206     QObject(parent),
00207     d(new Private(manager, providerName, this))
00208 {
00209 }
00210 
00211 Account::Account(Private *d, QObject *parent):
00212     QObject(parent),
00213     d(d)
00214 {
00215     d->init(this);
00216 }
00217 
00227 Account *Account::fromId(Manager *manager, AccountId id, QObject *parent)
00228 {
00229     GError *error = 0;
00230     AgAccount *account = ag_manager_load_account(manager->d->m_manager, id,
00231                                                  &error);
00232     if (account == 0) {
00233         Q_ASSERT(error != 0);
00234         manager->d->lastError = Error(error);
00235         g_error_free(error);
00236         return 0;
00237     }
00238     Q_ASSERT(error == 0);
00239     return new Account(new Private(manager, account), parent);
00240 }
00241 
00245 Account::~Account()
00246 {
00247     QObjectList list = children();
00248     for (int i = 0; i < list.count(); i++)
00249     {
00250         QObject *o = list.at(i);
00251         if (qobject_cast<Watch *>(o))
00252             delete o;
00253     }
00254 
00255     g_signal_handlers_disconnect_by_func
00256         (d->m_account, (void *)&Private::on_display_name_changed, this);
00257     g_signal_handlers_disconnect_by_func
00258         (d->m_account, (void *)&Private::on_enabled, this);
00259     g_signal_handlers_disconnect_by_func
00260         (d->m_account, (void *)&Private::on_deleted, this);
00261     g_object_unref(d->m_account);
00262     delete d;
00263     d = 0;
00264 }
00265 
00270 AccountId Account::id() const
00271 {
00272     return d->m_account ? d->m_account->id : 0;
00273 }
00274 
00278 Manager *Account::manager() const
00279 {
00280     return d->m_manager;
00281 }
00282 
00286 bool Account::supportsService(const QString &serviceType) const
00287 {
00288     return ag_account_supports_service(d->m_account,
00289                                        serviceType.toUtf8().constData());
00290 }
00291 
00300 ServiceList Account::services(const QString &serviceType) const
00301 {
00302     GList *list;
00303     if (serviceType.isEmpty()) {
00304         list = ag_account_list_services(d->m_account);
00305     } else {
00306         list = ag_account_list_services_by_type(d->m_account,
00307             serviceType.toUtf8().constData());
00308     }
00309 
00310     /* convert glist -> ServiceList */
00311     ServiceList servList;
00312     GList *iter;
00313     for (iter = list; iter; iter = iter->next)
00314     {
00315         AgService *service = (AgService*)iter->data;
00316         servList.append(Service(service, StealReference));
00317     }
00318 
00319     g_list_free(list);
00320 
00321     return servList;
00322 }
00323 
00329 ServiceList Account::enabledServices() const
00330 {
00331     GList *list;
00332     list = ag_account_list_enabled_services(d->m_account);
00333 
00334     /* convert glist -> ServiceList */
00335     ServiceList servList;
00336     GList *iter;
00337     for (iter = list; iter; iter = g_list_next(iter))
00338     {
00339         AgService *service = (AgService*)iter->data;
00340         servList.append(Service(service, StealReference));
00341     }
00342 
00343     g_list_free(list);
00344 
00345     return servList;
00346 }
00347 
00358 bool Account::enabled() const
00359 {
00360     return isEnabled();
00361 }
00362 
00369 bool Account::isEnabled() const
00370 {
00371     return ag_account_get_enabled(d->m_account);
00372 }
00373 
00381 void Account::setEnabled(bool enabled)
00382 {
00383     ag_account_set_enabled(d->m_account, enabled);
00384 }
00385 
00391 QString Account::displayName() const
00392 {
00393     return UTF8(ag_account_get_display_name(d->m_account));
00394 }
00395 
00400 void Account::setDisplayName(const QString &displayName)
00401 {
00402     ag_account_set_display_name(d->m_account,
00403                                 displayName.toUtf8().constData());
00404 }
00405 
00409 QString Account::providerName() const
00410 {
00411     return UTF8(ag_account_get_provider_name(d->m_account));
00412 }
00413 
00417 Provider Account::provider() const
00418 {
00419     return manager()->provider(providerName());
00420 }
00421 
00427 void Account::selectService(const Service &service)
00428 {
00429     AgService *agService = NULL;
00430 
00431     if (service.isValid())
00432         agService = service.service();
00433 
00434     ag_account_select_service(d->m_account, agService);
00435     d->prefix = QString();
00436 }
00437 
00441 Service Account::selectedService() const
00442 {
00443     AgService *agService = ag_account_get_selected_service(d->m_account);
00444     return Service(agService);
00445 }
00446 
00452 QStringList Account::allKeys() const
00453 {
00454     QStringList allKeys;
00455     AgAccountSettingIter iter;
00456     const gchar *key;
00457     GVariant *val;
00458 
00459     /* iterate the settings */
00460     QByteArray tmp = d->prefix.toLatin1();
00461     ag_account_settings_iter_init(d->m_account, &iter, tmp.constData());
00462     while (ag_account_settings_iter_get_next(&iter, &key, &val))
00463     {
00464         allKeys.append(QString(ASCII(key)));
00465     }
00466     return allKeys;
00467 }
00468 
00475 void Account::beginGroup(const QString &prefix)
00476 {
00477     d->prefix += prefix + slash;
00478 }
00479 
00485 QStringList Account::childGroups() const
00486 {
00487     QStringList groups, all_keys;
00488 
00489     all_keys = allKeys();
00490     Q_FOREACH (QString key, all_keys)
00491     {
00492         if (key.contains(slash)) {
00493             QString group = key.section(slash, 0, 0);
00494             if (!groups.contains(group))
00495                 groups.append(group);
00496         }
00497     }
00498     return groups;
00499 }
00500 
00506 QStringList Account::childKeys() const
00507 {
00508     QStringList keys, all_keys;
00509 
00510     all_keys = allKeys();
00511     Q_FOREACH (QString key, all_keys)
00512     {
00513         if (!key.contains(slash))
00514             keys.append(key);
00515     }
00516     return keys;
00517 }
00518 
00523 void Account::clear()
00524 {
00525     /* clear() must ignore the group: so, temporarily reset it and call
00526      * remove("") */
00527     QString saved_prefix = d->prefix;
00528     d->prefix = QString();
00529     remove(QString());
00530     d->prefix = saved_prefix;
00531 }
00532 
00539 bool Account::contains(const QString &key) const
00540 {
00541     return childKeys().contains(key);
00542 }
00543 
00549 void Account::endGroup()
00550 {
00551     d->prefix = d->prefix.section(slash, 0, -3,
00552                                   QString::SectionIncludeTrailingSep);
00553     if (d->prefix[0] == slash) d->prefix.remove(0, 1);
00554 }
00555 
00561 QString Account::group() const
00562 {
00563     if (d->prefix.endsWith(slash))
00564         return d->prefix.left(d->prefix.size() - 1);
00565     return d->prefix;
00566 }
00567 
00571 bool Account::isWritable() const
00572 {
00573     return true;
00574 }
00575 
00583 void Account::remove(const QString &key)
00584 {
00585     if (key.isEmpty())
00586     {
00587         /* delete all keys in the group */
00588         QStringList keys = allKeys();
00589         Q_FOREACH (QString key, keys)
00590         {
00591             if (!key.isEmpty())
00592                 remove(key);
00593         }
00594     }
00595     else
00596     {
00597         QString full_key = d->prefix + key;
00598         QByteArray tmpkey = full_key.toLatin1();
00599         ag_account_set_variant(d->m_account, tmpkey.constData(), NULL);
00600     }
00601 }
00602 
00610 void Account::setValue(const QString &key, const QVariant &value)
00611 {
00612     GVariant *variant = qVariantToGVariant(value);
00613     if (variant == 0) {
00614         return;
00615     }
00616 
00617     QString full_key = d->prefix + key;
00618     QByteArray tmpkey = full_key.toLatin1();
00619     ag_account_set_variant(d->m_account, tmpkey.constData(), variant);
00620 }
00621 
00622 void Account::Private::account_store_cb(AgAccount *account,
00623                                         GAsyncResult *res,
00624                                         Account *self)
00625 {
00626     TRACE() << "Saved accunt ID:" << account->id;
00627 
00628     GError *error = NULL;
00629     ag_account_store_finish(account, res, &error);
00630     if (error) {
00631         if (error->domain == G_IO_ERROR &&
00632             error->code == G_IO_ERROR_CANCELLED) {
00633             TRACE() << "Account destroyed, operation cancelled";
00634         } else {
00635             Q_EMIT self->error(Error(error));
00636         }
00637         g_error_free(error);
00638     } else {
00639         Q_EMIT self->synced();
00640     }
00641 }
00642 
00657 QVariant Account::value(const QString &key, const QVariant &defaultValue,
00658                         SettingSource *source) const
00659 {
00660     QString full_key = d->prefix + key;
00661     QByteArray ba = full_key.toLatin1();
00662     AgSettingSource settingSource;
00663     GVariant *variant =
00664         ag_account_get_variant(d->m_account, ba.constData(), &settingSource);
00665     if (source != 0) {
00666         switch (settingSource) {
00667         case AG_SETTING_SOURCE_ACCOUNT: *source = ACCOUNT; break;
00668         case AG_SETTING_SOURCE_PROFILE: *source = TEMPLATE; break;
00669         default: *source = NONE; break;
00670         }
00671     }
00672 
00673     return (variant != 0) ? gVariantToQVariant(variant) : defaultValue;
00674 }
00675 
00691 SettingSource Account::value(const QString &key, QVariant &value) const
00692 {
00693     SettingSource source;
00694     QVariant variant = this->value(key, QVariant(), &source);
00695     if (variant.isValid()) {
00696         if (value.type() != variant.type()) {
00697             if (!variant.convert(value.type())) source = NONE;
00698         }
00699         value = variant;
00700     }
00701 
00702     return source;
00703 }
00704 
00714 QString Account::valueAsString(const QString &key,
00715                                QString default_value,
00716                                SettingSource *source) const
00717 {
00718     QVariant var = default_value;
00719     SettingSource src = value(key, var);
00720     if (source)
00721         *source = src;
00722     return var.toString();
00723 }
00724 
00734 int Account::valueAsInt(const QString &key,
00735                         int default_value,
00736                         SettingSource *source) const
00737 {
00738     QVariant var = default_value;
00739     SettingSource src = value(key, var);
00740     if (source)
00741         *source = src;
00742     return var.toInt();
00743 }
00744 
00754 quint64 Account::valueAsUInt64(const QString &key,
00755                         quint64 default_value,
00756                         SettingSource *source) const
00757 {
00758     QVariant var = default_value;
00759     SettingSource src = value(key, var);
00760     if (source)
00761         *source = src;
00762     return var.toULongLong();
00763 }
00764 
00774 bool Account::valueAsBool(const QString &key,
00775                           bool default_value,
00776                           SettingSource *source) const
00777 {
00778     QVariant var = default_value;
00779     SettingSource src = value(key, var);
00780     if (source)
00781         *source = src;
00782     return var.toBool();
00783 }
00784 
00785 void Watch::Private::account_notify_cb(AgAccount *account, const gchar *key,
00786                                        Watch *watch)
00787 {
00788     Q_EMIT watch->notify(key);
00789 
00790     Q_UNUSED(account);
00791 }
00792 
00803 Watch *Account::watchKey(const QString &key)
00804 {
00805     AgAccountWatch ag_watch;
00806     Watch *watch = new Watch(this);
00807 
00808     if (!key.isEmpty())
00809     {
00810         QString full_key = d->prefix + key;
00811         ag_watch = ag_account_watch_key
00812             (d->m_account, full_key.toLatin1().constData(),
00813              (AgAccountNotifyCb)&Watch::Private::account_notify_cb, watch);
00814     }
00815     else
00816     {
00817         ag_watch = ag_account_watch_dir
00818             (d->m_account, d->prefix.toLatin1().constData(),
00819              (AgAccountNotifyCb)&Watch::Private::account_notify_cb, watch);
00820     }
00821 
00822     if (!ag_watch)
00823     {
00824         delete watch;
00825         return NULL;
00826     }
00827 
00828     watch->setWatch(ag_watch);
00829     return watch;
00830 }
00831 
00844 void Account::sync()
00845 {
00846     ag_account_store_async(d->m_account,
00847                            d->m_cancellable,
00848                            (GAsyncReadyCallback)&Private::account_store_cb,
00849                            this);
00850 }
00851 
00859 bool Account::syncAndBlock()
00860 {
00861     GError *error = NULL;
00862     bool ret;
00863 
00864     ret = ag_account_store_blocking(d->m_account, &error);
00865     if (error)
00866     {
00867         qWarning() << "Store operation failed: " << error->message;
00868         g_error_free(error);
00869     }
00870 
00871     return ret;
00872 }
00873 
00878 void Account::remove()
00879 {
00880     ag_account_delete(d->m_account);
00881 }
00882 
00892 void Account::sign(const QString &key, const char *token)
00893 {
00894     ag_account_sign (d->m_account, key.toUtf8().constData(), token);
00895 }
00896 
00908 bool Account::verify(const QString &key, const char **token)
00909 {
00910     return ag_account_verify(d->m_account, key.toUtf8().constData(), token);
00911 }
00912 
00925 bool Account::verifyWithTokens(const QString &key, QList<const char*> tokens)
00926 {
00927     int tokensCount = tokens.count();
00928 
00929     const char *tmp[tokensCount + 1];
00930 
00931     for (int i = 0; i < tokensCount; ++i)
00932     {
00933         tmp[i] = tokens.at(i);
00934     }
00935     tmp[tokensCount] = NULL;
00936 
00937     return ag_account_verify_with_tokens(d->m_account, key.toUtf8().constData(), tmp);
00938 }
00939 
00940 uint Account::credentialsId()
00941 {
00942     QString key = ACCOUNTS_KEY_CREDENTIALS_ID;
00943     QVariant val(QVariant::Int);
00944 
00945     if (value(key, val) != NONE)
00946         return val.toUInt();
00947 
00948     uint id = 0;
00949     Service service = selectedService();
00950     if (service.isValid()) {
00951         selectService();
00952         if (value(key, val) != NONE)
00953             id = val.toUInt();
00954         selectService(service);
00955     }
00956     return id;
00957 }
00958 
00959 AgAccount *Account::account()
00960 {
00961     return d->m_account;
00962 }