accounts-qt  1.15
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-2016 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     Q_EMIT self->removed();
00185 }
00186 
00202 Account::Account(Manager *manager, const QString &providerName,
00203                  QObject *parent):
00204     QObject(parent),
00205     d(new Private(manager, providerName, this))
00206 {
00207 }
00208 
00209 Account::Account(Private *d, QObject *parent):
00210     QObject(parent),
00211     d(d)
00212 {
00213     d->init(this);
00214 }
00215 
00225 Account *Account::fromId(Manager *manager, AccountId id, QObject *parent)
00226 {
00227     GError *error = 0;
00228     AgAccount *account = ag_manager_load_account(manager->d->m_manager, id,
00229                                                  &error);
00230     if (account == 0) {
00231         Q_ASSERT(error != 0);
00232         manager->d->lastError = Error(error);
00233         g_error_free(error);
00234         return 0;
00235     }
00236     Q_ASSERT(error == 0);
00237     return new Account(new Private(manager, account), parent);
00238 }
00239 
00243 Account::~Account()
00244 {
00245     QObjectList list = children();
00246     for (int i = 0; i < list.count(); i++)
00247     {
00248         QObject *o = list.at(i);
00249         if (qobject_cast<Watch *>(o))
00250             delete o;
00251     }
00252 
00253     g_signal_handlers_disconnect_by_func
00254         (d->m_account, (void *)&Private::on_display_name_changed, this);
00255     g_signal_handlers_disconnect_by_func
00256         (d->m_account, (void *)&Private::on_enabled, this);
00257     g_signal_handlers_disconnect_by_func
00258         (d->m_account, (void *)&Private::on_deleted, this);
00259     g_object_unref(d->m_account);
00260     delete d;
00261     d = 0;
00262 }
00263 
00268 AccountId Account::id() const
00269 {
00270     return d->m_account ? d->m_account->id : 0;
00271 }
00272 
00276 Manager *Account::manager() const
00277 {
00278     return d->m_manager;
00279 }
00280 
00284 bool Account::supportsService(const QString &serviceType) const
00285 {
00286     return ag_account_supports_service(d->m_account,
00287                                        serviceType.toUtf8().constData());
00288 }
00289 
00298 ServiceList Account::services(const QString &serviceType) const
00299 {
00300     GList *list;
00301     if (serviceType.isEmpty()) {
00302         list = ag_account_list_services(d->m_account);
00303     } else {
00304         list = ag_account_list_services_by_type(d->m_account,
00305             serviceType.toUtf8().constData());
00306     }
00307 
00308     /* convert glist -> ServiceList */
00309     ServiceList servList;
00310     GList *iter;
00311     for (iter = list; iter; iter = iter->next)
00312     {
00313         AgService *service = (AgService*)iter->data;
00314         servList.append(Service(service, StealReference));
00315     }
00316 
00317     g_list_free(list);
00318 
00319     return servList;
00320 }
00321 
00327 ServiceList Account::enabledServices() const
00328 {
00329     GList *list;
00330     list = ag_account_list_enabled_services(d->m_account);
00331 
00332     /* convert glist -> ServiceList */
00333     ServiceList servList;
00334     GList *iter;
00335     for (iter = list; iter; iter = g_list_next(iter))
00336     {
00337         AgService *service = (AgService*)iter->data;
00338         servList.append(Service(service, StealReference));
00339     }
00340 
00341     g_list_free(list);
00342 
00343     return servList;
00344 }
00345 
00356 bool Account::enabled() const
00357 {
00358     return isEnabled();
00359 }
00360 
00367 bool Account::isEnabled() const
00368 {
00369     return ag_account_get_enabled(d->m_account);
00370 }
00371 
00379 void Account::setEnabled(bool enabled)
00380 {
00381     ag_account_set_enabled(d->m_account, enabled);
00382 }
00383 
00389 QString Account::displayName() const
00390 {
00391     return UTF8(ag_account_get_display_name(d->m_account));
00392 }
00393 
00398 void Account::setDisplayName(const QString &displayName)
00399 {
00400     ag_account_set_display_name(d->m_account,
00401                                 displayName.toUtf8().constData());
00402 }
00403 
00407 QString Account::providerName() const
00408 {
00409     return UTF8(ag_account_get_provider_name(d->m_account));
00410 }
00411 
00415 Provider Account::provider() const
00416 {
00417     return manager()->provider(providerName());
00418 }
00419 
00425 void Account::selectService(const Service &service)
00426 {
00427     AgService *agService = NULL;
00428 
00429     if (service.isValid())
00430         agService = service.service();
00431 
00432     ag_account_select_service(d->m_account, agService);
00433     d->prefix = QString();
00434 }
00435 
00439 Service Account::selectedService() const
00440 {
00441     AgService *agService = ag_account_get_selected_service(d->m_account);
00442     return Service(agService);
00443 }
00444 
00450 QStringList Account::allKeys() const
00451 {
00452     QStringList allKeys;
00453     AgAccountSettingIter iter;
00454     const gchar *key;
00455     GVariant *val;
00456 
00457     /* iterate the settings */
00458     QByteArray tmp = d->prefix.toLatin1();
00459     ag_account_settings_iter_init(d->m_account, &iter, tmp.constData());
00460     while (ag_account_settings_iter_get_next(&iter, &key, &val))
00461     {
00462         allKeys.append(QString(ASCII(key)));
00463     }
00464     return allKeys;
00465 }
00466 
00473 void Account::beginGroup(const QString &prefix)
00474 {
00475     d->prefix += prefix + slash;
00476 }
00477 
00483 QStringList Account::childGroups() const
00484 {
00485     QStringList groups, all_keys;
00486 
00487     all_keys = allKeys();
00488     Q_FOREACH (const QString &key, all_keys)
00489     {
00490         if (key.contains(slash)) {
00491             QString group = key.section(slash, 0, 0);
00492             if (!groups.contains(group))
00493                 groups.append(group);
00494         }
00495     }
00496     return groups;
00497 }
00498 
00504 QStringList Account::childKeys() const
00505 {
00506     QStringList keys, all_keys;
00507 
00508     all_keys = allKeys();
00509     Q_FOREACH (const QString &key, all_keys)
00510     {
00511         if (!key.contains(slash))
00512             keys.append(key);
00513     }
00514     return keys;
00515 }
00516 
00521 void Account::clear()
00522 {
00523     /* clear() must ignore the group: so, temporarily reset it and call
00524      * remove("") */
00525     QString saved_prefix = d->prefix;
00526     d->prefix = QString();
00527     remove(QString());
00528     d->prefix = saved_prefix;
00529 }
00530 
00537 bool Account::contains(const QString &key) const
00538 {
00539     return childKeys().contains(key);
00540 }
00541 
00547 void Account::endGroup()
00548 {
00549     d->prefix = d->prefix.section(slash, 0, -3,
00550                                   QString::SectionIncludeTrailingSep);
00551     if (d->prefix[0] == slash) d->prefix.remove(0, 1);
00552 }
00553 
00559 QString Account::group() const
00560 {
00561     if (d->prefix.endsWith(slash))
00562         return d->prefix.left(d->prefix.size() - 1);
00563     return d->prefix;
00564 }
00565 
00569 bool Account::isWritable() const
00570 {
00571     return true;
00572 }
00573 
00581 void Account::remove(const QString &key)
00582 {
00583     if (key.isEmpty())
00584     {
00585         /* delete all keys in the group */
00586         QStringList keys = allKeys();
00587         Q_FOREACH (const QString &key, keys)
00588         {
00589             if (!key.isEmpty())
00590                 remove(key);
00591         }
00592     }
00593     else
00594     {
00595         QString full_key = d->prefix + key;
00596         QByteArray tmpkey = full_key.toLatin1();
00597         ag_account_set_variant(d->m_account, tmpkey.constData(), NULL);
00598     }
00599 }
00600 
00608 void Account::setValue(const QString &key, const QVariant &value)
00609 {
00610     GVariant *variant = qVariantToGVariant(value);
00611     if (variant == 0) {
00612         return;
00613     }
00614 
00615     QString full_key = d->prefix + key;
00616     QByteArray tmpkey = full_key.toLatin1();
00617     ag_account_set_variant(d->m_account, tmpkey.constData(), variant);
00618 }
00619 
00620 void Account::Private::account_store_cb(AgAccount *account,
00621                                         GAsyncResult *res,
00622                                         Account *self)
00623 {
00624     GError *error = NULL;
00625     ag_account_store_finish(account, res, &error);
00626     if (error) {
00627         if (error->domain == G_IO_ERROR &&
00628             error->code == G_IO_ERROR_CANCELLED) {
00629         } else {
00630             Q_EMIT self->error(Error(error));
00631         }
00632         g_error_free(error);
00633     } else {
00634         Q_EMIT self->synced();
00635     }
00636 }
00637 
00652 QVariant Account::value(const QString &key, const QVariant &defaultValue,
00653                         SettingSource *source) const
00654 {
00655     QString full_key = d->prefix + key;
00656     QByteArray ba = full_key.toLatin1();
00657     AgSettingSource settingSource;
00658     GVariant *variant =
00659         ag_account_get_variant(d->m_account, ba.constData(), &settingSource);
00660     if (source != 0) {
00661         switch (settingSource) {
00662         case AG_SETTING_SOURCE_ACCOUNT: *source = ACCOUNT; break;
00663         case AG_SETTING_SOURCE_PROFILE: *source = TEMPLATE; break;
00664         default: *source = NONE; break;
00665         }
00666     }
00667 
00668     return (variant != 0) ? gVariantToQVariant(variant) : defaultValue;
00669 }
00670 
00686 SettingSource Account::value(const QString &key, QVariant &value) const
00687 {
00688     SettingSource source;
00689     QVariant variant = this->value(key, QVariant(), &source);
00690     if (variant.isValid()) {
00691         if (value.type() != variant.type()) {
00692             if (!variant.convert(value.type())) source = NONE;
00693         }
00694         value = variant;
00695     }
00696 
00697     return source;
00698 }
00699 
00709 QString Account::valueAsString(const QString &key,
00710                                QString default_value,
00711                                SettingSource *source) const
00712 {
00713     QVariant var = default_value;
00714     SettingSource src = value(key, var);
00715     if (source)
00716         *source = src;
00717     return var.toString();
00718 }
00719 
00729 int Account::valueAsInt(const QString &key,
00730                         int default_value,
00731                         SettingSource *source) const
00732 {
00733     QVariant var = default_value;
00734     SettingSource src = value(key, var);
00735     if (source)
00736         *source = src;
00737     return var.toInt();
00738 }
00739 
00749 quint64 Account::valueAsUInt64(const QString &key,
00750                         quint64 default_value,
00751                         SettingSource *source) const
00752 {
00753     QVariant var = default_value;
00754     SettingSource src = value(key, var);
00755     if (source)
00756         *source = src;
00757     return var.toULongLong();
00758 }
00759 
00769 bool Account::valueAsBool(const QString &key,
00770                           bool default_value,
00771                           SettingSource *source) const
00772 {
00773     QVariant var = default_value;
00774     SettingSource src = value(key, var);
00775     if (source)
00776         *source = src;
00777     return var.toBool();
00778 }
00779 
00780 void Watch::Private::account_notify_cb(AgAccount *account, const gchar *key,
00781                                        Watch *watch)
00782 {
00783     Q_EMIT watch->notify(key);
00784 
00785     Q_UNUSED(account);
00786 }
00787 
00798 Watch *Account::watchKey(const QString &key)
00799 {
00800     AgAccountWatch ag_watch;
00801     Watch *watch = new Watch(this);
00802 
00803     if (!key.isEmpty())
00804     {
00805         QString full_key = d->prefix + key;
00806         ag_watch = ag_account_watch_key
00807             (d->m_account, full_key.toLatin1().constData(),
00808              (AgAccountNotifyCb)&Watch::Private::account_notify_cb, watch);
00809     }
00810     else
00811     {
00812         ag_watch = ag_account_watch_dir
00813             (d->m_account, d->prefix.toLatin1().constData(),
00814              (AgAccountNotifyCb)&Watch::Private::account_notify_cb, watch);
00815     }
00816 
00817     if (!ag_watch)
00818     {
00819         delete watch;
00820         return NULL;
00821     }
00822 
00823     watch->setWatch(ag_watch);
00824     return watch;
00825 }
00826 
00839 void Account::sync()
00840 {
00841     ag_account_store_async(d->m_account,
00842                            d->m_cancellable,
00843                            (GAsyncReadyCallback)&Private::account_store_cb,
00844                            this);
00845 }
00846 
00854 bool Account::syncAndBlock()
00855 {
00856     GError *error = NULL;
00857     bool ret;
00858 
00859     ret = ag_account_store_blocking(d->m_account, &error);
00860     if (error)
00861     {
00862         qWarning() << "Store operation failed: " << error->message;
00863         g_error_free(error);
00864     }
00865 
00866     return ret;
00867 }
00868 
00873 void Account::remove()
00874 {
00875     ag_account_delete(d->m_account);
00876 }
00877 
00887 void Account::sign(const QString &key, const char *token)
00888 {
00889     ag_account_sign (d->m_account, key.toUtf8().constData(), token);
00890 }
00891 
00903 bool Account::verify(const QString &key, const char **token)
00904 {
00905     return ag_account_verify(d->m_account, key.toUtf8().constData(), token);
00906 }
00907 
00920 bool Account::verifyWithTokens(const QString &key, QList<const char*> tokens)
00921 {
00922     int tokensCount = tokens.count();
00923 
00924     const char *tmp[tokensCount + 1];
00925 
00926     for (int i = 0; i < tokensCount; ++i)
00927     {
00928         tmp[i] = tokens.at(i);
00929     }
00930     tmp[tokensCount] = NULL;
00931 
00932     return ag_account_verify_with_tokens(d->m_account, key.toUtf8().constData(), tmp);
00933 }
00934 
00935 uint Account::credentialsId()
00936 {
00937     QString key = ACCOUNTS_KEY_CREDENTIALS_ID;
00938     QVariant val(QVariant::Int);
00939 
00940     if (value(key, val) != NONE)
00941         return val.toUInt();
00942 
00943     uint id = 0;
00944     Service service = selectedService();
00945     if (service.isValid()) {
00946         selectService();
00947         if (value(key, val) != NONE)
00948             id = val.toUInt();
00949         selectService(service);
00950     }
00951     return id;
00952 }
00953 
00954 AgAccount *Account::account()
00955 {
00956     return d->m_account;
00957 }