pidgin/pidgin
Clone
Summary
Browse
Changes
Graph
closing merged branch
jingle-reply-with-senders-both
2019-11-11, Gary Kramlich
2f28c8df6574
closing merged branch
/**
* @file kwallet.cpp KWallet password storage
* @ingroup plugins
*/
/* purple
*
* Purple is the legal property of its developers, whose names are too numerous
* to list here. Please refer to the COPYRIGHT file distributed with this
* source distribution.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
*/
#include
"internal.h"
#include
<purple.h>
#include
<QQueue>
#include
<QCoreApplication>
#include
"purplekwallet.h"
#define KWALLET_NAME N_("KWallet")
#define KWALLET_DESCRIPTION N_("This plugin will store passwords in KWallet.")
#define KWALLET_AUTHORS { "QuLogic (qulogic[at]pidgin.im)", NULL }
#define KWALLET_ID "keyring-kwallet"
#define KWALLET_DOMAIN (g_quark_from_static_string(KWALLET_ID))
#define KWALLET_WALLET_NAME KWallet::Wallet::NetworkWallet()
#define KWALLET_APP_NAME "Libpurple"
#define KWALLET_FOLDER_NAME "libpurple"
PurpleKeyring
*
keyring_handler
=
NULL
;
QCoreApplication
*
qCoreApp
=
NULL
;
static
gboolean
kwallet_is_enabled
(
void
)
{
return
KWallet
::
Wallet
::
isEnabled
()
?
TRUE
:
FALSE
;
}
KWalletPlugin
::
engine
*
KWalletPlugin
::
engine
::
pinstance
=
NULL
;
KWalletPlugin
::
request
::~
request
()
{
}
void
KWalletPlugin
::
request
::
abort
()
{
detailedAbort
(
PURPLE_KEYRING_ERROR_CANCELLED
);
}
KWalletPlugin
::
engine
::
engine
()
{
connected
=
false
;
failed
=
false
;
closing
=
false
;
externallyClosed
=
false
;
wallet
=
NULL
;
busy
=
false
;
closeAfterBusy
=
false
;
reopenWallet
();
}
void
KWalletPlugin
::
engine
::
reopenWallet
()
{
if
(
closing
)
{
purple_debug_error
(
"keyring-kwallet"
,
"wallet is closing right now
\n
"
);
failed
=
true
;
return
;
}
connected
=
false
;
failed
=
false
;
externallyClosed
=
false
;
wallet
=
KWallet
::
Wallet
::
openWallet
(
KWALLET_WALLET_NAME
,
0
,
KWallet
::
Wallet
::
Asynchronous
);
if
(
wallet
==
NULL
)
{
failed
=
true
;
purple_debug_error
(
"keyring-kwallet"
,
"failed opening a wallet
\n
"
);
return
;
}
failed
|=
!
connect
(
wallet
,
SIGNAL
(
walletClosed
()),
SLOT
(
walletClosed
()));
failed
|=
!
connect
(
wallet
,
SIGNAL
(
walletOpened
(
bool
)),
SLOT
(
walletOpened
(
bool
)));
if
(
failed
)
{
purple_debug_error
(
"keyring-kwallet"
,
"failed connecting to wallet signal
\n
"
);
}
}
KWalletPlugin
::
engine
::~
engine
()
{
closing
=
true
;
abortAll
();
delete
wallet
;
if
(
pinstance
==
this
)
pinstance
=
NULL
;
}
void
KWalletPlugin
::
engine
::
abortAll
()
{
int
abortedCount
=
0
;
while
(
!
isEmpty
())
{
request
*
req
=
dequeue
();
req
->
abort
();
delete
req
;
abortedCount
++
;
}
if
(
abortedCount
>
0
)
{
purple_debug_info
(
"keyring-kwallet"
,
"aborted requests: %d
\n
"
,
abortedCount
);
}
}
KWalletPlugin
::
engine
*
KWalletPlugin
::
engine
::
instance
(
bool
create
)
{
if
(
pinstance
==
NULL
&&
create
)
pinstance
=
new
engine
;
return
pinstance
;
}
void
KWalletPlugin
::
engine
::
closeInstance
(
void
)
{
if
(
pinstance
==
NULL
)
return
;
if
(
pinstance
->
closing
)
return
;
if
(
pinstance
->
busy
)
{
purple_debug_misc
(
"keyring-kwallet"
,
"current instance is busy, will be freed later
\n
"
);
pinstance
->
closeAfterBusy
=
true
;
}
else
delete
pinstance
;
pinstance
=
NULL
;
}
void
KWalletPlugin
::
engine
::
walletOpened
(
bool
opened
)
{
connected
=
opened
;
if
(
!
opened
)
{
purple_debug_warning
(
"keyring-kwallet"
,
"failed to open a wallet
\n
"
);
delete
this
;
return
;
}
if
(
!
wallet
->
hasFolder
(
KWALLET_FOLDER_NAME
))
{
if
(
!
wallet
->
createFolder
(
KWALLET_FOLDER_NAME
))
{
purple_debug_error
(
"keyring-kwallet"
,
"couldn't create
\"
"
KWALLET_FOLDER_NAME
"
\"
folder in wallet
\n
"
);
failed
=
true
;
}
}
if
(
!
failed
)
wallet
->
setFolder
(
KWALLET_FOLDER_NAME
);
executeRequests
();
}
void
KWalletPlugin
::
engine
::
walletClosed
()
{
if
(
!
closing
)
{
purple_debug_info
(
"keyring-kwallet"
,
"wallet was externally closed
\n
"
);
externallyClosed
=
true
;
delete
wallet
;
wallet
=
NULL
;
}
}
void
KWalletPlugin
::
engine
::
queue
(
request
*
req
)
{
enqueue
(
req
);
executeRequests
();
}
void
KWalletPlugin
::
engine
::
executeRequests
()
{
if
(
closing
||
busy
)
return
;
busy
=
true
;
if
(
externallyClosed
)
{
reopenWallet
();
}
else
if
(
connected
||
failed
)
{
while
(
!
isEmpty
())
{
request
*
req
=
dequeue
();
if
(
connected
)
req
->
execute
(
wallet
);
else
req
->
abort
();
delete
req
;
}
}
else
if
(
purple_debug_is_verbose
())
{
purple_debug_misc
(
"keyring-kwallet"
,
"not yet connected
\n
"
);
}
busy
=
false
;
if
(
closeAfterBusy
)
{
purple_debug_misc
(
"keyring-kwallet"
,
"instance freed after being busy
\n
"
);
delete
this
;
}
}
KWalletPlugin
::
save_request
::
save_request
(
PurpleAccount
*
acc
,
const
char
*
pw
,
PurpleKeyringSaveCallback
cb
,
void
*
userdata
)
{
account
=
acc
;
data
=
userdata
;
callback
=
cb
;
password
=
QString
(
pw
);
noPassword
=
(
pw
==
NULL
);
}
KWalletPlugin
::
read_request
::
read_request
(
PurpleAccount
*
acc
,
PurpleKeyringReadCallback
cb
,
void
*
userdata
)
{
account
=
acc
;
data
=
userdata
;
callback
=
cb
;
password
=
QString
();
}
void
KWalletPlugin
::
save_request
::
detailedAbort
(
enum
PurpleKeyringError
error
)
{
GError
*
gerror
;
if
(
callback
==
NULL
)
return
;
gerror
=
g_error_new
(
PURPLE_KEYRING_ERROR
,
error
,
_
(
"Failed to save password."
));
callback
(
account
,
gerror
,
data
);
g_error_free
(
gerror
);
}
void
KWalletPlugin
::
read_request
::
detailedAbort
(
enum
PurpleKeyringError
error
)
{
GError
*
gerror
;
if
(
callback
==
NULL
)
return
;
gerror
=
g_error_new
(
PURPLE_KEYRING_ERROR
,
error
,
_
(
"Failed to read password."
));
callback
(
account
,
NULL
,
gerror
,
data
);
g_error_free
(
gerror
);
}
static
QString
kwallet_account_key
(
PurpleAccount
*
account
)
{
return
QString
(
purple_account_get_protocol_id
(
account
))
+
":"
+
purple_account_get_username
(
account
);
}
void
KWalletPlugin
::
read_request
::
execute
(
KWallet
::
Wallet
*
wallet
)
{
int
result
;
g_return_if_fail
(
wallet
!=
NULL
);
result
=
wallet
->
readPassword
(
kwallet_account_key
(
account
),
password
);
if
(
result
!=
0
)
{
purple_debug_warning
(
"keyring-kwallet"
,
"failed to read password, result was %d
\n
"
,
result
);
abort
();
return
;
}
purple_debug_misc
(
"keyring-kwallet"
,
"Got password for account %s (%s).
\n
"
,
purple_account_get_username
(
account
),
purple_account_get_protocol_id
(
account
));
if
(
callback
!=
NULL
)
callback
(
account
,
password
.
toUtf8
().
constData
(),
NULL
,
data
);
}
void
KWalletPlugin
::
save_request
::
execute
(
KWallet
::
Wallet
*
wallet
)
{
int
result
;
g_return_if_fail
(
wallet
!=
NULL
);
if
(
noPassword
)
result
=
wallet
->
removeEntry
(
kwallet_account_key
(
account
));
else
{
result
=
wallet
->
writePassword
(
kwallet_account_key
(
account
),
password
);
}
if
(
result
!=
0
)
{
purple_debug_warning
(
"keyring-kwallet"
,
"failed to write password, result was %d
\n
"
,
result
);
abort
();
return
;
}
purple_debug_misc
(
"keyring-kwallet"
,
"Password %s for account %s (%s).
\n
"
,
(
noPassword
?
"removed"
:
"saved"
),
purple_account_get_username
(
account
),
purple_account_get_protocol_id
(
account
));
if
(
callback
!=
NULL
)
callback
(
account
,
NULL
,
data
);
}
extern
"C"
{
static
void
kwallet_read
(
PurpleAccount
*
account
,
PurpleKeyringReadCallback
cb
,
gpointer
data
)
{
KWalletPlugin
::
read_request
*
req
=
new
KWalletPlugin
::
read_request
(
account
,
cb
,
data
);
if
(
KWallet
::
Wallet
::
keyDoesNotExist
(
KWALLET_WALLET_NAME
,
KWALLET_FOLDER_NAME
,
kwallet_account_key
(
account
)))
{
req
->
detailedAbort
(
PURPLE_KEYRING_ERROR_NOPASSWORD
);
delete
req
;
}
else
KWalletPlugin
::
engine
::
instance
(
true
)
->
queue
(
req
);
}
static
void
kwallet_save
(
PurpleAccount
*
account
,
const
char
*
password
,
PurpleKeyringSaveCallback
cb
,
gpointer
data
)
{
if
(
password
==
NULL
&&
KWallet
::
Wallet
::
keyDoesNotExist
(
KWALLET_WALLET_NAME
,
KWALLET_FOLDER_NAME
,
kwallet_account_key
(
account
)))
{
if
(
cb
!=
NULL
)
cb
(
account
,
NULL
,
data
);
}
else
KWalletPlugin
::
engine
::
instance
(
true
)
->
queue
(
new
KWalletPlugin
::
save_request
(
account
,
password
,
cb
,
data
));
}
static
void
kwallet_cancel
(
void
)
{
KWalletPlugin
::
engine
*
instance
=
KWalletPlugin
::
engine
::
instance
(
false
);
if
(
instance
)
instance
->
abortAll
();
}
static
void
*
kwallet_get_handle
(
void
)
{
static
int
handle
;
return
&
handle
;
}
static
const
char
*
kwallet_get_ui_name
(
void
)
{
GHashTable
*
ui_info
;
const
char
*
ui_name
=
NULL
;
ui_info
=
purple_core_get_ui_info
();
if
(
ui_info
!=
NULL
)
ui_name
=
(
const
char
*
)
g_hash_table_lookup
(
ui_info
,
"name"
);
if
(
ui_name
==
NULL
)
ui_name
=
KWALLET_APP_NAME
;
return
ui_name
;
}
static
PurplePluginInfo
*
plugin_query
(
GError
**
error
)
{
const
gchar
*
const
authors
[]
=
KWALLET_AUTHORS
;
return
purple_plugin_info_new
(
"id"
,
KWALLET_ID
,
"name"
,
KWALLET_NAME
,
"version"
,
DISPLAY_VERSION
,
"category"
,
N_
(
"Keyring"
),
"summary"
,
"KWallet Keyring Plugin"
,
"description"
,
KWALLET_DESCRIPTION
,
"authors"
,
authors
,
"website"
,
PURPLE_WEBSITE
,
"abi-version"
,
PURPLE_ABI_VERSION
,
"flags"
,
PURPLE_PLUGIN_INFO_FLAGS_INTERNAL
,
NULL
);
}
static
gboolean
plugin_load
(
PurplePlugin
*
plugin
,
GError
**
error
)
{
if
(
!
qCoreApp
)
{
int
argc
=
0
;
qCoreApp
=
new
QCoreApplication
(
argc
,
NULL
);
qCoreApp
->
setApplicationName
(
kwallet_get_ui_name
());
}
if
(
!
kwallet_is_enabled
())
{
g_set_error
(
error
,
KWALLET_DOMAIN
,
0
,
"KWallet service is disabled."
);
purple_debug_info
(
"keyring-kwallet"
,
"KWallet service is disabled
\n
"
);
return
FALSE
;
}
keyring_handler
=
purple_keyring_new
();
purple_keyring_set_name
(
keyring_handler
,
_
(
KWALLET_NAME
));
purple_keyring_set_id
(
keyring_handler
,
KWALLET_ID
);
purple_keyring_set_read_password
(
keyring_handler
,
kwallet_read
);
purple_keyring_set_save_password
(
keyring_handler
,
kwallet_save
);
purple_keyring_set_cancel_requests
(
keyring_handler
,
kwallet_cancel
);
purple_keyring_set_close_keyring
(
keyring_handler
,
KWalletPlugin
::
engine
::
closeInstance
);
purple_keyring_register
(
keyring_handler
);
return
TRUE
;
}
static
gboolean
plugin_unload
(
PurplePlugin
*
plugin
,
GError
**
error
)
{
if
(
purple_keyring_get_inuse
()
==
keyring_handler
)
{
g_set_error
(
error
,
KWALLET_DOMAIN
,
0
,
"The keyring is currently "
"in use."
);
purple_debug_warning
(
"keyring-kwallet"
,
"keyring in use, cannot unload
\n
"
);
return
FALSE
;
}
purple_signals_disconnect_by_handle
(
kwallet_get_handle
());
KWalletPlugin
::
engine
::
closeInstance
();
purple_keyring_unregister
(
keyring_handler
);
purple_keyring_free
(
keyring_handler
);
keyring_handler
=
NULL
;
if
(
qCoreApp
)
{
delete
qCoreApp
;
qCoreApp
=
NULL
;
}
return
TRUE
;
}
PURPLE_PLUGIN_INIT
(
kwallet_keyring
,
plugin_query
,
plugin_load
,
plugin_unload
);
}
/* extern "C" */