2 * @file kwallet.cpp KWallet password storage
8 * Purple is the legal property of its developers, whose names are too numerous
9 * to list here. Please refer to the COPYRIGHT file distributed with this
10 * source distribution.
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program ; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
36 #include <QCoreApplication>
39 #define KWALLET_NAME N_("KWallet")
40 #define KWALLET_DESCRIPTION N_("This plugin will store passwords in KWallet.")
41 #define KWALLET_AUTHORS { "QuLogic (qulogic[at]pidgin.im)", NULL }
42 #define KWALLET_ID "keyring-kwallet"
43 #define KWALLET_DOMAIN (g_quark_from_static_string(KWALLET_ID))
45 #define KWALLET_WALLET_NAME KWallet::Wallet::NetworkWallet()
46 #define KWALLET_APP_NAME "Libpurple"
47 #define KWALLET_FOLDER_NAME "libpurple"
49 PurpleKeyring
*keyring_handler
= NULL
;
50 QCoreApplication
*qCoreApp
= NULL
;
52 namespace KWalletPlugin
{
58 virtual void detailedAbort(enum PurpleKeyringError error
) = 0;
60 virtual void execute(KWallet::Wallet
*wallet
) = 0;
64 PurpleAccount
*account
;
69 class engine
: private QObject
, private QQueue
<request
*>
76 void queue(request
*req
);
78 static engine
*instance(bool create
);
79 static void closeInstance(void);
82 void walletOpened(bool opened
);
86 static engine
*pinstance
;
91 bool externallyClosed
;
95 KWallet::Wallet
*wallet
;
98 void executeRequests();
101 class save_request
: public request
104 save_request(PurpleAccount
*account
, const char *password
,
105 PurpleKeyringSaveCallback cb
, void *data
);
106 void detailedAbort(enum PurpleKeyringError error
);
107 void execute(KWallet::Wallet
*wallet
);
110 PurpleKeyringSaveCallback callback
;
113 class read_request
: public request
116 read_request(PurpleAccount
*account
,
117 PurpleKeyringReadCallback cb
, void *data
);
118 void detailedAbort(enum PurpleKeyringError error
);
119 void execute(KWallet::Wallet
*wallet
);
122 PurpleKeyringReadCallback callback
;
128 kwallet_is_enabled(void)
130 return KWallet::Wallet::isEnabled() ? TRUE
: FALSE
;
133 KWalletPlugin::engine
*KWalletPlugin::engine::pinstance
= NULL
;
135 KWalletPlugin::request::~request()
140 KWalletPlugin::request::abort()
142 detailedAbort(PURPLE_KEYRING_ERROR_CANCELLED
);
145 KWalletPlugin::engine::engine()
150 externallyClosed
= false;
153 closeAfterBusy
= false;
159 KWalletPlugin::engine::reopenWallet()
162 purple_debug_error("keyring-kwallet",
163 "wallet is closing right now\n");
170 externallyClosed
= false;
172 wallet
= KWallet::Wallet::openWallet(KWALLET_WALLET_NAME
, 0,
173 KWallet::Wallet::Asynchronous
);
174 if (wallet
== NULL
) {
176 purple_debug_error("keyring-kwallet",
177 "failed opening a wallet\n");
181 failed
|= !connect(wallet
, SIGNAL(walletClosed()),
182 SLOT(walletClosed()));
183 failed
|= !connect(wallet
, SIGNAL(walletOpened(bool)),
184 SLOT(walletOpened(bool)));
186 purple_debug_error("keyring-kwallet",
187 "failed connecting to wallet signal\n");
191 KWalletPlugin::engine::~engine()
199 if (pinstance
== this)
204 KWalletPlugin::engine::abortAll()
206 int abortedCount
= 0;
209 request
*req
= dequeue();
215 if (abortedCount
> 0) {
216 purple_debug_info("keyring-kwallet", "aborted requests: %d\n",
221 KWalletPlugin::engine
*
222 KWalletPlugin::engine::instance(bool create
)
224 if (pinstance
== NULL
&& create
)
225 pinstance
= new engine
;
230 KWalletPlugin::engine::closeInstance(void)
232 if (pinstance
== NULL
)
234 if (pinstance
->closing
)
236 if (pinstance
->busy
) {
237 purple_debug_misc("keyring-kwallet",
238 "current instance is busy, will be freed later\n");
239 pinstance
->closeAfterBusy
= true;
246 KWalletPlugin::engine::walletOpened(bool opened
)
251 purple_debug_warning("keyring-kwallet",
252 "failed to open a wallet\n");
257 if (!wallet
->hasFolder(KWALLET_FOLDER_NAME
)) {
258 if (!wallet
->createFolder(KWALLET_FOLDER_NAME
)) {
259 purple_debug_error("keyring-kwallet",
260 "couldn't create \"" KWALLET_FOLDER_NAME
261 "\" folder in wallet\n");
266 wallet
->setFolder(KWALLET_FOLDER_NAME
);
272 KWalletPlugin::engine::walletClosed()
275 purple_debug_info("keyring-kwallet",
276 "wallet was externally closed\n");
277 externallyClosed
= true;
284 KWalletPlugin::engine::queue(request
*req
)
291 KWalletPlugin::engine::executeRequests()
296 if (externallyClosed
) {
298 } else if (connected
|| failed
) {
300 request
*req
= dequeue();
302 req
->execute(wallet
);
307 } else if (purple_debug_is_verbose()) {
308 purple_debug_misc("keyring-kwallet", "not yet connected\n");
311 if (closeAfterBusy
) {
312 purple_debug_misc("keyring-kwallet",
313 "instance freed after being busy\n");
318 KWalletPlugin::save_request::save_request(PurpleAccount
*acc
, const char *pw
,
319 PurpleKeyringSaveCallback cb
, void *userdata
)
324 password
= QString(pw
);
325 noPassword
= (pw
== NULL
);
328 KWalletPlugin::read_request::read_request(PurpleAccount
*acc
,
329 PurpleKeyringReadCallback cb
, void *userdata
)
334 password
= QString();
338 KWalletPlugin::save_request::detailedAbort(enum PurpleKeyringError error
)
341 if (callback
== NULL
)
344 gerror
= g_error_new(PURPLE_KEYRING_ERROR
, error
,
345 _("Failed to save password."));
346 callback(account
, gerror
, data
);
347 g_error_free(gerror
);
351 KWalletPlugin::read_request::detailedAbort(enum PurpleKeyringError error
)
354 if (callback
== NULL
)
357 gerror
= g_error_new(PURPLE_KEYRING_ERROR
, error
,
358 _("Failed to read password."));
359 callback(account
, NULL
, gerror
, data
);
360 g_error_free(gerror
);
364 kwallet_account_key(PurpleAccount
*account
)
366 return QString(purple_account_get_protocol_id(account
)) + ":" +
367 purple_account_get_username(account
);
371 KWalletPlugin::read_request::execute(KWallet::Wallet
*wallet
)
375 g_return_if_fail(wallet
!= NULL
);
377 result
= wallet
->readPassword(kwallet_account_key(account
), password
);
380 purple_debug_warning("keyring-kwallet",
381 "failed to read password, result was %d\n", result
);
386 purple_debug_misc("keyring-kwallet",
387 "Got password for account %s (%s).\n",
388 purple_account_get_username(account
),
389 purple_account_get_protocol_id(account
));
391 if (callback
!= NULL
)
392 callback(account
, password
.toUtf8().constData(), NULL
, data
);
396 KWalletPlugin::save_request::execute(KWallet::Wallet
*wallet
)
400 g_return_if_fail(wallet
!= NULL
);
403 result
= wallet
->removeEntry(kwallet_account_key(account
));
405 result
= wallet
->writePassword(kwallet_account_key(account
),
410 purple_debug_warning("keyring-kwallet",
411 "failed to write password, result was %d\n", result
);
416 purple_debug_misc("keyring-kwallet",
417 "Password %s for account %s (%s).\n",
418 (noPassword
? "removed" : "saved"),
419 purple_account_get_username(account
),
420 purple_account_get_protocol_id(account
));
422 if (callback
!= NULL
)
423 callback(account
, NULL
, data
);
430 kwallet_read(PurpleAccount
*account
, PurpleKeyringReadCallback cb
,
433 KWalletPlugin::read_request
*req
=
434 new KWalletPlugin::read_request(account
, cb
, data
);
436 if (KWallet::Wallet::keyDoesNotExist(KWALLET_WALLET_NAME
,
437 KWALLET_FOLDER_NAME
, kwallet_account_key(account
)))
439 req
->detailedAbort(PURPLE_KEYRING_ERROR_NOPASSWORD
);
443 KWalletPlugin::engine::instance(true)->queue(req
);
447 kwallet_save(PurpleAccount
*account
, const char *password
,
448 PurpleKeyringSaveCallback cb
, gpointer data
)
450 if (password
== NULL
&& KWallet::Wallet::keyDoesNotExist(
451 KWALLET_WALLET_NAME
, KWALLET_FOLDER_NAME
,
452 kwallet_account_key(account
)))
455 cb(account
, NULL
, data
);
458 KWalletPlugin::engine::instance(true)->queue(
459 new KWalletPlugin::save_request(account
, password
, cb
,
466 KWalletPlugin::engine
*instance
=
467 KWalletPlugin::engine::instance(false);
469 instance
->abortAll();
473 kwallet_get_handle(void)
480 static const char *kwallet_get_ui_name(void)
483 const char *ui_name
= NULL
;
485 ui_info
= purple_core_get_ui_info();
487 ui_name
= (const char*)g_hash_table_lookup(ui_info
, "name");
489 ui_name
= KWALLET_APP_NAME
;
494 static PurplePluginInfo
*
495 plugin_query(GError
**error
)
497 const gchar
* const authors
[] = KWALLET_AUTHORS
;
499 return purple_plugin_info_new(
501 "name", KWALLET_NAME
,
502 "version", DISPLAY_VERSION
,
503 "category", N_("Keyring"),
504 "summary", "KWallet Keyring Plugin",
505 "description", KWALLET_DESCRIPTION
,
507 "website", PURPLE_WEBSITE
,
508 "abi-version", PURPLE_ABI_VERSION
,
509 "flags", PURPLE_PLUGIN_INFO_FLAGS_INTERNAL
,
515 plugin_load(PurplePlugin
*plugin
, GError
**error
)
519 qCoreApp
= new QCoreApplication(argc
, NULL
);
520 qCoreApp
->setApplicationName(kwallet_get_ui_name());
523 if (!kwallet_is_enabled()) {
524 g_set_error(error
, KWALLET_DOMAIN
, 0, "KWallet service is disabled.");
525 purple_debug_info("keyring-kwallet",
526 "KWallet service is disabled\n");
530 keyring_handler
= purple_keyring_new();
532 purple_keyring_set_name(keyring_handler
, _(KWALLET_NAME
));
533 purple_keyring_set_id(keyring_handler
, KWALLET_ID
);
534 purple_keyring_set_read_password(keyring_handler
, kwallet_read
);
535 purple_keyring_set_save_password(keyring_handler
, kwallet_save
);
536 purple_keyring_set_cancel_requests(keyring_handler
, kwallet_cancel
);
537 purple_keyring_set_close_keyring(keyring_handler
,
538 KWalletPlugin::engine::closeInstance
);
540 purple_keyring_register(keyring_handler
);
546 plugin_unload(PurplePlugin
*plugin
, GError
**error
)
548 if (purple_keyring_get_inuse() == keyring_handler
) {
549 g_set_error(error
, KWALLET_DOMAIN
, 0, "The keyring is currently "
551 purple_debug_warning("keyring-kwallet",
552 "keyring in use, cannot unload\n");
556 purple_signals_disconnect_by_handle(kwallet_get_handle());
558 KWalletPlugin::engine::closeInstance();
560 purple_keyring_unregister(keyring_handler
);
561 purple_keyring_free(keyring_handler
);
562 keyring_handler
= NULL
;
572 PURPLE_PLUGIN_INIT(kwallet_keyring
, plugin_query
, plugin_load
, plugin_unload
);
576 #include "kwallet.moc"