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