Branch data Line data Source code
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-service.h"
25 : : #include "manager.h"
26 : : #include "utils.h"
27 : : #include <QPointer>
28 : : #include <libaccounts-glib/ag-account.h>
29 : : #include <libaccounts-glib/ag-account-service.h>
30 : : #include <libaccounts-glib/ag-auth-data.h>
31 : :
32 : : namespace Accounts
33 : : {
34 : :
35 : : /*!
36 : : * @class AccountService
37 : : * @headerfile account-service.h Accounts/AccountService
38 : : *
39 : : * @brief Account settings for a specific service
40 : : *
41 : : * @details The AccountService class provides access to the account settings
42 : : * for a specific service type. It is meant to be easier to use than the
43 : : * Account class because it hides the complexity of the account structure and
44 : : * gives access to only the limited subset of account settings which are
45 : : * relevant to a service.
46 : : *
47 : : * To get an AccountService one can use the Manager methods accountServices()
48 : : * or enabledAccountServices(), which both return a QList of account services.
49 : : * Note that if the Manager was instantiated for a specific service type, these
50 : : * lists will contain only those account services matching that service type.
51 : : * The AccountService can also be instantiated with its AccountService(Account
52 : : * *account, Service *service) constructor: this is useful if one already has
53 : : * an Account instance.
54 : : *
55 : : * This is intended to be a convenient wrapper over the accounts settings
56 : : * specific for a service; as such, it doesn't offer all the editing
57 : : * possibilities offered by the Account class, such as enabling the service
58 : : * itself: these operations should ideally not be performed by consumer
59 : : * applications, but by the account editing UI only.
60 : : *
61 : : * Example code:
62 : : * @code
63 : : * // Instantiate an account manager interested in e-mail services only.
64 : : * Accounts::Manager *manager = new Accounts::Manager("e-mail");
65 : : *
66 : : * // Get the list of enabled AccountService objects of type e-mail.
67 : : * Accounts::AccountServiceList services = manager->enabledAccountServices();
68 : : *
69 : : * // Loop through the account services and do something useful with them.
70 : : * foreach (Accounts::AccountService service, services) {
71 : : * QString server = service.value("pop3/hostname").toString();
72 : : * int port = service.value("pop3/port").toInt();
73 : : *
74 : : * // Suppose that the e-mail address is stored in the global account
75 : : * // settings; let's get it from there:
76 : : * QString fromAddress = service.account()->valueAsString("username");
77 : : *
78 : : * ...
79 : : * }
80 : : * @endcode
81 : : *
82 : : * @note User applications (with the notable exception of the accounts editing
83 : : * application) should never use account services which are not enabled, and
84 : : * should stop using an account when the account service becomes disabled. The
85 : : * latter can be done by connecting to the changed() signal and checking if
86 : : * enabled() still returns true.
87 : : * @note Note that if the account gets deleted, it will always get disabled
88 : : * first; so, there is no need to connect to the Account::removed() signal; one
89 : : * can just monitor the changed() signal from the AccountService objects.
90 : : */
91 : :
92 : : /*!
93 : : * @fn AccountService::enabled(bool isEnabled)
94 : : *
95 : : * Emitted when the enabledness state of the account service has changed.
96 : : */
97 : :
98 : :
99 : : /*!
100 : : * @fn AccountService::changed()
101 : : * Emitted when some setting has changed on the account service.
102 : : * You can use the changedFields() method to retrieve the list of the
103 : : * settings which have changed.
104 : : */
105 : :
106 : : class AccountServicePrivate
107 : : {
108 : : Q_DECLARE_PUBLIC(AccountService)
109 : :
110 : : public:
111 : : AccountServicePrivate(Account *account,
112 : : const Service &service,
113 : : AccountService *accountService);
114 : : ~AccountServicePrivate();
115 : :
116 : : private:
117 : : static void onEnabled(AccountService *accountService, gboolean isEnabled);
118 : : static void onChanged(AccountService *accountService);
119 : :
120 : : ServiceList m_serviceList;
121 : : AgAccountService *m_accountService;
122 : : QPointer<Account> m_account;
123 : : QString prefix;
124 : : mutable AccountService *q_ptr;
125 : : };
126 : :
127 : : } // namespace
128 : :
129 : : using namespace Accounts;
130 : :
131 : 1 : static QChar slash = QChar::fromLatin1('/');
132 : :
133 : 4 : AccountServicePrivate::AccountServicePrivate(Account *account,
134 : : const Service &service,
135 : : AccountService *accountService):
136 : : m_account(account),
137 : 4 : q_ptr(accountService)
138 : : {
139 : : m_accountService = ag_account_service_new(account->account(),
140 : 4 : service.service());
141 : : g_signal_connect_swapped(m_accountService, "enabled",
142 : 4 : G_CALLBACK(&onEnabled), accountService);
143 : 4 : g_signal_connect_swapped(m_accountService, "changed",
144 : 4 : G_CALLBACK(&onChanged), accountService);
145 : 4 : }
146 : :
147 : 4 : AccountServicePrivate::~AccountServicePrivate()
148 : : {
149 : : Q_Q(AccountService);
150 : 4 : g_signal_handlers_disconnect_by_func(m_accountService,
151 : 4 : (void *)&onEnabled, q);
152 : 4 : g_signal_handlers_disconnect_by_func(m_accountService,
153 : 4 : (void *)&onChanged, q);
154 : 4 : g_object_unref(m_accountService);
155 : 4 : m_accountService = 0;
156 : 4 : }
157 : :
158 : 4 : void AccountServicePrivate::onEnabled(AccountService *accountService,
159 : : gboolean isEnabled)
160 : : {
161 : 4 : TRACE();
162 : :
163 : 4 : Q_EMIT accountService->enabled(isEnabled);
164 : 4 : }
165 : :
166 : 5 : void AccountServicePrivate::onChanged(AccountService *accountService)
167 : : {
168 : 5 : TRACE();
169 : :
170 : 5 : Q_EMIT accountService->changed();
171 : 5 : }
172 : :
173 : : /*!
174 : : * Constructor.
175 : : * @param account An Account.
176 : : * @param service A Service supported by the account.
177 : : */
178 : 3 : AccountService::AccountService(Account *account, const Service &service):
179 : : QObject(0),
180 : 3 : d_ptr(new AccountServicePrivate(account, service, this))
181 : : {
182 : 3 : }
183 : :
184 : : /*!
185 : : * Constructor.
186 : : * @param account An Account.
187 : : * @param service A Service supported by the account.
188 : : * @param parent The parent object.
189 : : */
190 : 1 : AccountService::AccountService(Account *account, const Service &service,
191 : : QObject *parent):
192 : : QObject(parent),
193 : 1 : d_ptr(new AccountServicePrivate(account, service, this))
194 : : {
195 : 1 : }
196 : :
197 : : /*!
198 : : * Destructor.
199 : : */
200 : 4 : AccountService::~AccountService()
201 : : {
202 [ + - ]: 4 : delete d_ptr;
203 : 8 : }
204 : :
205 : : /*!
206 : : * Return the Account.
207 : : */
208 : 2 : Account *AccountService::account() const
209 : : {
210 : : Q_D(const AccountService);
211 : 2 : return d->m_account;
212 : : }
213 : :
214 : : /*!
215 : : * Return the Service. Do not delete this object explicitly.
216 : : */
217 : 1 : Service AccountService::service() const
218 : : {
219 : : Q_D(const AccountService);
220 : 1 : AgService *service = ag_account_service_get_service(d->m_accountService);
221 : 1 : return Service(service);
222 : : }
223 : :
224 : : /*!
225 : : * Check whether the account service is enabled.
226 : : */
227 : 6 : bool AccountService::enabled() const
228 : : {
229 : : Q_D(const AccountService);
230 : 6 : return ag_account_service_get_enabled(d->m_accountService);
231 : : }
232 : :
233 : : /*!
234 : : * Return all the keys in the current group.
235 : : */
236 : 5 : QStringList AccountService::allKeys() const
237 : : {
238 : : Q_D(const AccountService);
239 : : QStringList allKeys;
240 : : AgAccountSettingIter iter;
241 : : const gchar *key;
242 : : GVariant *val;
243 : :
244 : : /* iterate the settings */
245 : 5 : QByteArray tmp = d->prefix.toLatin1();
246 : : ag_account_service_settings_iter_init(d->m_accountService,
247 : 5 : &iter, tmp.constData());
248 [ + + ]: 27 : while (ag_account_settings_iter_get_next(&iter, &key, &val))
249 : : {
250 : 22 : allKeys.append(ASCII(key));
251 : : }
252 : 5 : return allKeys;
253 : : }
254 : :
255 : : /*!
256 : : * Enter a group. This method never fails.
257 : : * @param prefix
258 : : */
259 : 1 : void AccountService::beginGroup(const QString &prefix)
260 : : {
261 : : Q_D(AccountService);
262 : 1 : d->prefix += prefix + slash;
263 : 1 : }
264 : :
265 : : /*!
266 : : * Return all the groups which are direct children of the current group.
267 : : */
268 : 2 : QStringList AccountService::childGroups() const
269 : : {
270 : : QStringList groups, all_keys;
271 : :
272 : 2 : all_keys = allKeys();
273 [ + - ][ + + ]: 11 : Q_FOREACH (QString key, all_keys)
[ + + ]
274 : : {
275 [ + + ]: 9 : if (key.contains(slash)) {
276 : 4 : QString group = key.section(slash, 0, 0);
277 [ + + ]: 4 : if (!groups.contains(group))
278 : 4 : groups.append(group);
279 : : }
280 : 11 : }
281 : 2 : return groups;
282 : : }
283 : :
284 : : /*!
285 : : * Return all the keys which are direct children of the current group.
286 : : */
287 : 2 : QStringList AccountService::childKeys() const
288 : : {
289 : : QStringList keys, all_keys;
290 : :
291 : 2 : all_keys = allKeys();
292 [ + - ][ + + ]: 10 : Q_FOREACH (QString key, all_keys)
[ + + ]
293 : : {
294 [ + - ]: 8 : if (!key.contains(slash))
295 : 8 : keys.append(key);
296 : 10 : }
297 : 2 : return keys;
298 : : }
299 : :
300 : : /*!
301 : : * Remove all the keys.
302 : : * @see remove(const QString &key)
303 : : */
304 : 1 : void AccountService::clear()
305 : : {
306 : : Q_D(AccountService);
307 : : /* clear() must ignore the group: so, temporarily reset it and call
308 : : * remove("") */
309 : : QString saved_prefix = d->prefix;
310 : 1 : d->prefix = QString();
311 : 1 : remove(QString());
312 : 1 : d->prefix = saved_prefix;
313 : 1 : }
314 : :
315 : : /*!
316 : : * Check whether the given key is in the current group.
317 : : * @param key The key name of the setting.
318 : : */
319 : 1 : bool AccountService::contains(const QString &key) const
320 : : {
321 : 2 : return childKeys().contains(key);
322 : : }
323 : :
324 : : /*!
325 : : * Exit a group.
326 : : */
327 : 1 : void AccountService::endGroup()
328 : : {
329 : : Q_D(AccountService);
330 : : d->prefix = d->prefix.section(slash, 0, -3,
331 : 1 : QString::SectionIncludeTrailingSep);
332 [ + - ]: 1 : if (d->prefix[0] == slash) d->prefix.remove(0, 1);
333 : 1 : }
334 : :
335 : : /*!
336 : : * Return the name of the current group.
337 : : */
338 : 1 : QString AccountService::group() const
339 : : {
340 : : Q_D(const AccountService);
341 [ + - ]: 1 : if (d->prefix.endsWith(slash))
342 : 1 : return d->prefix.left(d->prefix.size() - 1);
343 : : return d->prefix;
344 : : }
345 : :
346 : : /*!
347 : : * Remove the given key. If the key is the empty string, all keys in the
348 : : * current group are removed.
349 : : * @param key The key name of the setting.
350 : : */
351 : 7 : void AccountService::remove(const QString &key)
352 : : {
353 : : Q_D(AccountService);
354 [ + + ]: 7 : if (key.isEmpty())
355 : : {
356 : : /* delete all keys in the group */
357 : 1 : QStringList keys = allKeys();
358 [ + - ][ + + ]: 6 : Q_FOREACH (QString key, keys)
[ + + ]
359 : : {
360 [ + - ]: 5 : if (!key.isEmpty())
361 : 5 : remove(key);
362 : 6 : }
363 : : }
364 : : else
365 : : {
366 : 6 : QString full_key = d->prefix + key;
367 : 6 : QByteArray tmpkey = full_key.toLatin1();
368 : : ag_account_service_set_variant(d->m_accountService,
369 : : tmpkey.constData(),
370 : 6 : NULL);
371 : : }
372 : 7 : }
373 : :
374 : : /*!
375 : : * Change the value of an account setting.
376 : : * @param key The name of the setting.
377 : : * @param value The new value of the setting.
378 : : */
379 : 1 : void AccountService::setValue(const QString &key, const QVariant &value)
380 : : {
381 : : Q_D(AccountService);
382 : :
383 : 1 : GVariant *variant = qVariantToGVariant(value);
384 [ + - ]: 1 : if (variant == 0) {
385 : 1 : return;
386 : : }
387 : :
388 : 1 : QString full_key = d->prefix + key;
389 : 1 : QByteArray tmpkey = full_key.toLatin1();
390 : : ag_account_service_set_variant(d->m_accountService,
391 : : tmpkey.constData(),
392 : 1 : variant);
393 : : }
394 : :
395 : 1 : void AccountService::setValue(const char *key, const QVariant &value)
396 : : {
397 : 1 : setValue(ASCII(key), value);
398 : 1 : }
399 : :
400 : : /*!
401 : : * Retrieves the value of an account setting, as a QVariant.
402 : : * @param key The key whose value must be retrieved.
403 : : * @param defaultValue Value returned if the key is unset.
404 : : * @param source Indicates whether the value comes from the account, the
405 : : * service template or was unset.
406 : : *
407 : : * @return The value associated to \a key.
408 : : *
409 : : * This method operates on the currently selected service.
410 : : */
411 : 4 : QVariant AccountService::value(const QString &key,
412 : : const QVariant &defaultValue,
413 : : SettingSource *source) const
414 : : {
415 : : Q_D(const AccountService);
416 : 4 : QString full_key = d->prefix + key;
417 : 4 : QByteArray ba = full_key.toLatin1();
418 : : AgSettingSource settingSource;
419 : : GVariant *variant =
420 : : ag_account_service_get_variant(d->m_accountService,
421 : : ba.constData(),
422 : 4 : &settingSource);
423 [ - + ]: 4 : if (source != 0) {
424 [ # # # ]: 0 : switch (settingSource) {
425 : 0 : case AG_SETTING_SOURCE_ACCOUNT: *source = ACCOUNT; break;
426 : 0 : case AG_SETTING_SOURCE_PROFILE: *source = TEMPLATE; break;
427 : 0 : default: *source = NONE; break;
428 : : }
429 : : }
430 : :
431 [ + - ]: 4 : return (variant != 0) ? gVariantToQVariant(variant) : defaultValue;
432 : : }
433 : :
434 : : /*!
435 : : * Retrieves the value of an account setting.
436 : : * @param key The key whose value must be retrieved
437 : : * @param source Indicates whether the value comes from the account, the
438 : : * service template or was unset.
439 : : *
440 : : * Returns the value of the setting, or an invalid QVariant if unset.
441 : : */
442 : 4 : QVariant AccountService::value(const QString &key, SettingSource *source) const
443 : : {
444 : 4 : return value(key, QVariant(), source);
445 : : }
446 : :
447 : 4 : QVariant AccountService::value(const char *key, SettingSource *source) const
448 : : {
449 : 4 : return value(ASCII(key), source);
450 : : }
451 : :
452 : : /*!
453 : : * This method should be called only in the context of a handler of the
454 : : * AccountService::changed() signal, and can be used to retrieve the set of
455 : : * changes.
456 : : *
457 : : * @return a QStringList of the keys which have changed.
458 : : */
459 : 5 : QStringList AccountService::changedFields() const
460 : : {
461 : : Q_D(const AccountService);
462 : :
463 : : gchar **changedFields =
464 : 5 : ag_account_service_get_changed_fields(d->m_accountService);
465 : :
466 : : QStringList keyList;
467 [ + - ]: 5 : if (changedFields == 0)
468 : : return keyList;
469 : :
470 : : gchar **keys = changedFields;
471 [ + + ]: 15 : while (*keys != 0) {
472 : 10 : keyList.append(QString(ASCII(*keys)));
473 : 10 : keys++;
474 : : }
475 : :
476 : 5 : g_strfreev(changedFields);
477 : 5 : return keyList;
478 : : }
479 : :
480 : : /*!
481 : : * Read the authentication data stored in the account (merging the
482 : : * service-specific settings with the global account settings).
483 : : * The method and mechanism are read from the "auth/method" and
484 : : * "auth/mechanism" keys, respectively. The authentication parameters are
485 : : * found under the "auth/<method>/<mechanism>/" group.
486 : : *
487 : : * @return an AuthData object, describing the authentication settings.
488 : : */
489 : 2 : AuthData AccountService::authData() const
490 : : {
491 : : Q_D(const AccountService);
492 : :
493 : : AgAuthData *agAuthData =
494 : 2 : ag_account_service_get_auth_data(d->m_accountService);
495 : 2 : return AuthData(agAuthData);
496 : 1 : }
|