accounts-qt 0.31
account.cpp
Go to the documentation of this file.
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-2010 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 
00027 #include <libaccounts-glib/ag-manager.h>
00028 #include <libaccounts-glib/ag-account.h>
00029 
00030 namespace Accounts {
00031 
00032 class Account::Private
00033 {
00034 public:
00035     Private()
00036     {
00037         m_account = 0;
00038     }
00039 
00040     ~Private() {}
00041 
00042     AgAccount *m_account;  //real account
00043     QString prefix;
00044 
00045     static void on_display_name_changed(Account *self);
00046     static void on_enabled(Account *self, const gchar *service_name,
00047                            gboolean enabled);
00048     static void account_store_cb(AgAccount *account, const GError *error,
00049                                  Account *self);
00050     static void on_deleted(Account *self);
00051 };
00052 
00053 class Watch::Private
00054 {
00055 public:
00056     static void account_notify_cb(AgAccount *account, const gchar *key,
00057                                   Watch *self);
00058 };
00059 } //namespace Accounts
00060 
00061 
00062 using namespace Accounts;
00063 
00064 static QChar slash = QChar::fromLatin1('/');
00065 
00066 Watch::Watch(QObject *parent)
00067     : QObject(parent)
00068 {
00069 }
00070 
00071 Watch::~Watch()
00072 {
00073     TRACE();
00074     Account *account = qobject_cast<Account *>(QObject::parent());
00075     /* The destructor of Account deletes the child Watches before detaching
00076      * them, so here account should always be not NULL */
00077     Q_ASSERT(account != NULL);
00078     ag_account_remove_watch(account->d->m_account, watch);
00079 }
00080 
00081 void Account::Private::on_display_name_changed(Account *self)
00082 {
00083     TRACE();
00084     const gchar *name = ag_account_get_display_name(self->d->m_account);
00085 
00086     emit self->displayNameChanged(UTF8(name));
00087 }
00088 
00089 void Account::Private::on_enabled(Account *self, const gchar *service_name,
00090                                   gboolean enabled)
00091 {
00092     TRACE();
00093 
00094     emit self->enabledChanged(UTF8(service_name), enabled);
00095 }
00096 
00097 void Account::Private::on_deleted(Account *self)
00098 {
00099     TRACE();
00100 
00101     emit self->removed();
00102 }
00103 
00104 Account::Account(AgAccount *account, QObject *parent)
00105     : QObject(parent), d(new Private)
00106 {
00107     TRACE();
00108     d->m_account = account;
00109     g_object_ref(account);
00110 
00111     g_signal_connect_swapped(account, "display-name-changed",
00112                              G_CALLBACK(&Private::on_display_name_changed),
00113                              this);
00114     g_signal_connect_swapped(account, "enabled",
00115                              G_CALLBACK(&Private::on_enabled), this);
00116     g_signal_connect_swapped(account, "deleted",
00117                              G_CALLBACK(&Private::on_deleted), this);
00118 }
00119 
00120 Account::~Account()
00121 {
00122     TRACE();
00123 
00124     QObjectList list = children();
00125     for (int i = 0; i < list.count(); i++)
00126     {
00127         QObject *o = list.at(i);
00128         if (qobject_cast<Watch *>(o))
00129             delete o;
00130     }
00131 
00132     g_signal_handlers_disconnect_by_func
00133         (d->m_account, (void *)&Private::on_display_name_changed, this);
00134     g_signal_handlers_disconnect_by_func
00135         (d->m_account, (void *)&Private::on_enabled, this);
00136     g_signal_handlers_disconnect_by_func
00137         (d->m_account, (void *)&Private::on_deleted, this);
00138     g_object_unref(d->m_account);
00139     delete d;
00140     d = 0;
00141 }
00142 
00143 AccountId Account::id() const
00144 {
00145     return d->m_account ? d->m_account->id : 0;
00146 }
00147 
00148 Manager *Account::manager() const
00149 {
00150     return qobject_cast<Manager *>(QObject::parent());
00151 }
00152 
00153 bool Account::supportsService(const QString &serviceType) const
00154 {
00155     TRACE() << serviceType;
00156 
00157     return ag_account_supports_service(d->m_account,
00158                                        serviceType.toUtf8().constData());
00159 }
00160 
00161 ServiceList Account::services(const QString &serviceType) const
00162 {
00163     TRACE() << serviceType;
00164 
00165     GList *list;
00166     if (serviceType.isEmpty()) {
00167         list = ag_account_list_services(d->m_account);
00168     } else {
00169         list = ag_account_list_services_by_type(d->m_account,
00170             serviceType.toUtf8().constData());
00171     }
00172 
00173     /* convert glist -> ServiceList */
00174     ServiceList servList;
00175     GList *iter;
00176     Manager *mgr = manager();
00177     Q_ASSERT(mgr != 0);
00178     for (iter = list; iter; iter = g_list_next(iter))
00179     {
00180         Service *serv = mgr->serviceInstance((AgService*)(iter->data));
00181         servList.append(serv);
00182     }
00183 
00184     ag_service_list_free(list);
00185 
00186     return servList;
00187 }
00188 
00189 ServiceList Account::enabledServices() const
00190 {
00191     GList *list;
00192     list = ag_account_list_enabled_services(d->m_account);
00193 
00194     /* convert glist -> ServiceList */
00195     ServiceList servList;
00196     GList *iter;
00197     Manager *mgr = manager();
00198     Q_ASSERT(mgr != 0);
00199     for (iter = list; iter; iter = g_list_next(iter))
00200     {
00201         Service *serv = mgr->serviceInstance((AgService*)(iter->data));
00202         servList.append(serv);
00203     }
00204 
00205     ag_service_list_free(list);
00206 
00207     return servList;
00208 }
00209 
00210 bool Account::enabled() const
00211 {
00212     return ag_account_get_enabled(d->m_account);
00213 }
00214 
00215 void Account::setEnabled(bool enabled)
00216 {
00217     ag_account_set_enabled(d->m_account, enabled);
00218 }
00219 
00220 QString Account::displayName() const
00221 {
00222     return UTF8(ag_account_get_display_name(d->m_account));
00223 }
00224 
00225 void Account::setDisplayName(const QString &displayName)
00226 {
00227     ag_account_set_display_name(d->m_account,
00228                                 displayName.toUtf8().constData());
00229 }
00230 
00231 QString Account::providerName() const
00232 {
00233     return UTF8(ag_account_get_provider_name(d->m_account));
00234 }
00235 
00236 void Account::selectService(const Service *service)
00237 {
00238     AgService *agService = NULL;
00239 
00240     if (service != NULL)
00241         agService = service->service();
00242 
00243     ag_account_select_service(d->m_account, agService);
00244     d->prefix = QString();
00245 }
00246 
00247 Service* Account::selectedService() const
00248 {
00249     AgService *agService = ag_account_get_selected_service(d->m_account);
00250     if (agService == NULL)
00251         return NULL;
00252 
00253     Manager *mgr = manager();
00254     Q_ASSERT(mgr != 0);
00255     Service *service = mgr->serviceInstance(agService);
00256 
00257     return service;
00258 }
00259 
00260 QStringList Account::allKeys() const
00261 {
00262     QStringList allKeys;
00263     AgAccountSettingIter iter;
00264     const gchar *key;
00265     const GValue *val;
00266 
00267     /* iterate the settings */
00268     QByteArray tmp = d->prefix.toLatin1();
00269     ag_account_settings_iter_init(d->m_account, &iter, tmp.constData());
00270     while (ag_account_settings_iter_next(&iter, &key, &val))
00271     {
00272         allKeys.append(QString(ASCII(key)).mid(d->prefix.size()));
00273     }
00274     return allKeys;
00275 }
00276 
00277 void Account::beginGroup(const QString &prefix)
00278 {
00279     d->prefix += prefix + slash;
00280 }
00281 
00282 QStringList Account::childGroups() const
00283 {
00284     QStringList groups, all_keys;
00285 
00286     all_keys = allKeys();
00287     foreach (QString key, all_keys)
00288     {
00289         if (key.contains(slash)) {
00290             QString group = key.section(slash, 0, 0);
00291             if (!groups.contains(group))
00292                 groups.append(group);
00293         }
00294     }
00295     return groups;
00296 }
00297 
00298 QStringList Account::childKeys() const
00299 {
00300     QStringList keys, all_keys;
00301 
00302     all_keys = allKeys();
00303     foreach (QString key, all_keys)
00304     {
00305         if (!key.contains(slash))
00306             keys.append(key);
00307     }
00308     return keys;
00309 }
00310 
00311 void Account::clear()
00312 {
00313     /* clear() must ignore the group: so, temporarily reset it and call
00314      * remove("") */
00315     QString saved_prefix = d->prefix;
00316     d->prefix = QString();
00317     remove(QString());
00318     d->prefix = saved_prefix;
00319 }
00320 
00321 bool Account::contains(const QString &key) const
00322 {
00323     return childKeys().contains(key);
00324 }
00325 
00326 void Account::endGroup()
00327 {
00328     d->prefix = d->prefix.section(slash, 0, -3,
00329                                   QString::SectionIncludeTrailingSep);
00330     if (d->prefix[0] == slash) d->prefix.remove(0, 1);
00331 }
00332 
00333 QString Account::group() const
00334 {
00335     if (d->prefix.endsWith(slash))
00336         return d->prefix.left(d->prefix.size() - 1);
00337     return d->prefix;
00338 }
00339 
00340 bool Account::isWritable() const
00341 {
00342     return true;
00343 }
00344 
00345 void Account::remove(const QString &key)
00346 {
00347     if (key.isEmpty())
00348     {
00349         /* delete all keys in the group */
00350         QStringList keys = allKeys();
00351         foreach (QString key, keys)
00352         {
00353             if (!key.isEmpty())
00354                 remove(key);
00355         }
00356     }
00357     else
00358     {
00359         QString full_key = d->prefix + key;
00360         QByteArray tmpkey = full_key.toLatin1();
00361         ag_account_set_value(d->m_account, tmpkey.constData(), NULL);
00362     }
00363 }
00364 
00365 void Account::setValue(const QString &key, const QVariant &value)
00366 {
00367     TRACE();
00368     GValue val= {0, {{0}}};
00369     QByteArray tmpvalue;
00370 
00371     switch (value.type())
00372     {
00373     case QVariant::String:
00374         g_value_init(&val, G_TYPE_STRING);
00375         tmpvalue = value.toString().toUtf8();
00376         g_value_set_static_string(&val, tmpvalue.constData());
00377         break;
00378     case QVariant::Int:
00379         g_value_init(&val, G_TYPE_INT);
00380         g_value_set_int(&val, value.toInt());
00381         break;
00382     case QVariant::UInt:
00383         g_value_init(&val, G_TYPE_UINT);
00384         g_value_set_uint(&val, value.toUInt());
00385         break;
00386     case QVariant::LongLong:
00387         g_value_init(&val, G_TYPE_INT64);
00388         g_value_set_int64(&val, value.toLongLong());
00389         break;
00390     case QVariant::ULongLong:
00391         g_value_init(&val, G_TYPE_UINT64);
00392         g_value_set_uint64(&val, value.toULongLong());
00393         break;
00394     case QVariant::Bool:
00395         g_value_init(&val, G_TYPE_BOOLEAN);
00396         g_value_set_boolean(&val, value.toBool());
00397         break;
00398     default:
00399         qWarning("unsupproted datatype %s", value.typeName());
00400         return;
00401     }
00402 
00403     QString full_key = d->prefix + key;
00404     QByteArray tmpkey = full_key.toLatin1();
00405     ag_account_set_value(d->m_account, tmpkey.constData(), &val);
00406     g_value_unset(&val);
00407 }
00408 
00409 void Account::Private::account_store_cb(AgAccount *account, const GError *err,
00410                                         Account *self)
00411 {
00412     TRACE() << "Saved accunt ID:" << account->id;
00413 
00414     if (err) {
00415         emit self->error((ErrorCode)err->code);
00416     } else {
00417         emit self->synced();
00418     }
00419 
00420     Q_UNUSED(account);
00421 }
00422 
00423 void Account::sync()
00424 {
00425     TRACE();
00426 
00427     ag_account_store(d->m_account,
00428                      (AgAccountStoreCb)&Private::account_store_cb,
00429                      this);
00430 }
00431 
00432 bool Account::syncAndBlock()
00433 {
00434     TRACE();
00435 
00436     GError *error = NULL;
00437     bool ret;
00438 
00439     ret = ag_account_store_blocking(d->m_account, &error);
00440     if (error)
00441     {
00442         qWarning() << "Store operation failed: " << error->message;
00443         g_error_free(error);
00444     }
00445 
00446     return ret;
00447 }
00448 
00449 SettingSource Account::value(const QString &key, QVariant &value) const
00450 {
00451     GType type;
00452 
00453     switch (value.type())
00454     {
00455     case QVariant::String:
00456         type = G_TYPE_STRING;
00457         break;
00458     case QVariant::Int:
00459         type = G_TYPE_INT;
00460         break;
00461     case QVariant::UInt:
00462         type = G_TYPE_UINT;
00463         break;
00464     case QVariant::LongLong:
00465         type = G_TYPE_INT64;
00466         break;
00467     case QVariant::ULongLong:
00468         type = G_TYPE_UINT64;
00469         break;
00470     case QVariant::Bool:
00471         type = G_TYPE_BOOLEAN;
00472         break;
00473     default:
00474         qWarning("Unsupported type %s", value.typeName());
00475         return NONE;
00476     }
00477 
00478     GValue val= {0, {{0}}};
00479     g_value_init(&val, type);
00480     QString full_key = d->prefix + key;
00481     AgSettingSource source =
00482         ag_account_get_value(d->m_account,
00483                              full_key.toLatin1().constData(), &val);
00484     if (source == AG_SETTING_SOURCE_NONE)
00485         return NONE;
00486 
00487     switch (type)
00488     {
00489     case G_TYPE_STRING:
00490         value = UTF8(g_value_get_string(&val));
00491         break;
00492     case G_TYPE_INT:
00493         value = g_value_get_int(&val);
00494         break;
00495     case G_TYPE_UINT:
00496         value = g_value_get_uint(&val);
00497         break;
00498     case G_TYPE_INT64:
00499         value = qint64(g_value_get_int64(&val));
00500         break;
00501     case G_TYPE_UINT64:
00502         value = quint64(g_value_get_uint64(&val));
00503         break;
00504     case G_TYPE_BOOLEAN:
00505         value = g_value_get_boolean(&val);
00506         break;
00507     default:
00508         /* This can never be reached */
00509         Q_ASSERT(false);
00510         break;
00511     }
00512     g_value_unset(&val);
00513 
00514     return (source == AG_SETTING_SOURCE_ACCOUNT) ? ACCOUNT : TEMPLATE;
00515 }
00516 
00517 QString Account::valueAsString(const QString &key,
00518                                QString default_value,
00519                                SettingSource *source) const
00520 {
00521     QVariant var = default_value;
00522     SettingSource src = value(key, var);
00523     if (source)
00524         *source = src;
00525     return var.toString();
00526 }
00527 
00528 int Account::valueAsInt(const QString &key,
00529                         int default_value,
00530                         SettingSource *source) const
00531 {
00532     QVariant var = default_value;
00533     SettingSource src = value(key, var);
00534     if (source)
00535         *source = src;
00536     return var.toInt();
00537 }
00538 
00539 quint64 Account::valueAsUInt64(const QString &key,
00540                         quint64 default_value,
00541                         SettingSource *source) const
00542 {
00543     QVariant var = default_value;
00544     SettingSource src = value(key, var);
00545     if (source)
00546         *source = src;
00547     return var.toULongLong();
00548 }
00549 
00550 bool Account::valueAsBool(const QString &key,
00551                           bool default_value,
00552                           SettingSource *source) const
00553 {
00554     QVariant var = default_value;
00555     SettingSource src = value(key, var);
00556     if (source)
00557         *source = src;
00558     return var.toBool();
00559 }
00560 
00561 void Watch::Private::account_notify_cb(AgAccount *account, const gchar *key,
00562                                        Watch *watch)
00563 {
00564     emit watch->notify(key);
00565 
00566     Q_UNUSED(account);
00567 }
00568 
00569 Watch *Account::watchKey(const QString &key)
00570 {
00571     AgAccountWatch ag_watch;
00572     Watch *watch = new Watch(this);
00573 
00574     if (!key.isEmpty())
00575     {
00576         QString full_key = d->prefix + key;
00577         ag_watch = ag_account_watch_key
00578             (d->m_account, full_key.toLatin1().constData(),
00579              (AgAccountNotifyCb)&Watch::Private::account_notify_cb, watch);
00580     }
00581     else
00582     {
00583         ag_watch = ag_account_watch_dir
00584             (d->m_account, d->prefix.toLatin1().constData(),
00585              (AgAccountNotifyCb)&Watch::Private::account_notify_cb, watch);
00586     }
00587 
00588     if (!ag_watch)
00589     {
00590         delete watch;
00591         return NULL;
00592     }
00593 
00594     watch->setWatch(ag_watch);
00595     return watch;
00596 }
00597 
00598 void Account::remove()
00599 {
00600     TRACE();
00601     ag_account_delete(d->m_account);
00602 }
00603 
00604 void Account::sign(const QString &key, const char *token)
00605 {
00606     ag_account_sign (d->m_account, key.toUtf8().constData(), token);
00607 }
00608 
00609 bool Account::verify(const QString &key, const char **token)
00610 {
00611     return ag_account_verify(d->m_account, key.toUtf8().constData(), token);
00612 }
00613 
00614 bool Account::verifyWithTokens(const QString &key, QList<const char*> tokens)
00615 {
00616     int tokensCount = tokens.count();
00617 
00618     const char *tmp[tokensCount + 1];
00619 
00620     for (int i = 0; i < tokensCount; ++i)
00621     {
00622         tmp[i] = tokens.at(i);
00623     }
00624     tmp[tokensCount] = NULL;
00625 
00626     return ag_account_verify_with_tokens(d->m_account, key.toUtf8().constData(), tmp);
00627 }
00628 
00629 qint32 Account::credentialsId()
00630 {
00631     QString key = ACCOUNTS_KEY_CREDENTIALS_ID;
00632     QVariant val(QVariant::Int);
00633 
00634     if (value(key, val) != NONE)
00635         return val.toInt();
00636 
00637     qint32 id = 0;
00638     Service *service = selectedService();
00639     if (service) {
00640         selectService(NULL);
00641         if (value(key, val) != NONE)
00642             id = val.toInt();
00643         selectService(service);
00644     }
00645     return id;
00646 }