pidgin/pidgin
Clone
Summary
Browse
Changes
Graph
Fix some GWarnings during finch's startup
21 months ago, Gary Kramlich
01b94846bb60
Fix some GWarnings during finch's startup
Testing Done:
Ran via `G_DEBUG=fatal-warnings gdb --ex run finch3` and verified I was able to make it to the contact list.
Reviewed at https://reviews.imfreedom.org/r/1592/
/*
* 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 library; if not, see <https://www.gnu.org/licenses/>.
*/
#include
<glib.h>
#include
<glib/gi18n-lib.h>
#include
<purple.h>
#include
<QCoreApplication>
#include
<kwallet.h>
#include
"purplekwallet.h"
/******************************************************************************
* Globals
*****************************************************************************/
static
QCoreApplication
*
qCoreApp
=
NULL
;
static
PurpleCredentialProvider
*
instance
=
NULL
;
#define PURPLE_KWALLET_DOMAIN (g_quark_from_static_string("purple-kwallet"))
#define PURPLE_KWALLET_WALLET_NAME (KWallet::Wallet::NetworkWallet())
struct
_PurpleKWalletProvider
{
PurpleCredentialProvider
parent
;
PurpleKWalletPlugin
::
Engine
*
engine
;
};
G_DEFINE_DYNAMIC_TYPE
(
PurpleKWalletProvider
,
purple_kwallet_provider
,
PURPLE_TYPE_CREDENTIAL_PROVIDER
)
/******************************************************************************
* Helpers
*****************************************************************************/
static
QString
purple_kwallet_get_ui_name
(
void
)
{
PurpleUiInfo
*
ui_info
=
NULL
;
QString
ui_name
=
NULL
;
ui_info
=
purple_core_get_ui_info
();
if
(
PURPLE_IS_UI_INFO
(
ui_info
))
{
ui_name
=
purple_ui_info_get_name
(
ui_info
);
}
if
(
ui_name
.
isEmpty
())
{
ui_name
=
"libpurple"
;
}
return
ui_name
;
}
static
QString
purple_kwallet_provider_account_key
(
PurpleAccount
*
account
)
{
return
QString
(
purple_account_get_protocol_id
(
account
))
+
":"
+
purple_account_get_username
(
account
);
}
/******************************************************************************
* Request Implementation
*****************************************************************************/
PurpleKWalletPlugin
::
Request
::
Request
(
QString
key
,
GTask
*
task
)
{
this
->
key
=
key
;
this
->
task
=
G_TASK
(
g_object_ref
(
G_OBJECT
(
task
)));
}
PurpleKWalletPlugin
::
Request
::~
Request
(
void
)
{
g_clear_object
(
&
this
->
task
);
}
/******************************************************************************
* ReadRequest Implementation
*****************************************************************************/
PurpleKWalletPlugin
::
ReadRequest
::
ReadRequest
(
QString
key
,
GTask
*
task
)
:
PurpleKWalletPlugin
::
Request
(
key
,
task
)
{
}
void
PurpleKWalletPlugin
::
ReadRequest
::
execute
(
KWallet
::
Wallet
*
wallet
)
{
QString
password
;
int
result
=
0
;
bool
missing
;
missing
=
KWallet
::
Wallet
::
keyDoesNotExist
(
PURPLE_KWALLET_WALLET_NAME
,
purple_kwallet_get_ui_name
(),
key
);
if
(
missing
)
{
g_task_return_new_error
(
this
->
task
,
PURPLE_KWALLET_DOMAIN
,
0
,
"no password stored"
);
g_clear_object
(
&
this
->
task
);
return
;
}
result
=
wallet
->
readPassword
(
this
->
key
,
password
);
if
(
result
!=
0
)
{
g_task_return_new_error
(
this
->
task
,
PURPLE_KWALLET_DOMAIN
,
result
,
_
(
"failed to read password, kwallet responded "
"with error code %d"
),
result
);
}
else
{
gchar
*
c_password
=
g_strdup
(
password
.
toUtf8
().
constData
());
g_task_return_pointer
(
this
->
task
,
c_password
,
g_free
);
}
g_clear_object
(
&
this
->
task
);
}
void
PurpleKWalletPlugin
::
ReadRequest
::
cancel
(
QString
reason
)
{
g_task_return_new_error
(
this
->
task
,
PURPLE_KWALLET_DOMAIN
,
0
,
_
(
"failed to read password: %s"
),
reason
.
toUtf8
().
constData
());
g_clear_object
(
&
this
->
task
);
}
/******************************************************************************
* WriteRequest Implementation
*****************************************************************************/
PurpleKWalletPlugin
::
WriteRequest
::
WriteRequest
(
QString
key
,
GTask
*
task
,
QString
password
)
:
PurpleKWalletPlugin
::
Request
(
key
,
task
)
{
this
->
password
=
password
;
}
void
PurpleKWalletPlugin
::
WriteRequest
::
execute
(
KWallet
::
Wallet
*
wallet
)
{
int
result
;
result
=
wallet
->
writePassword
(
this
->
key
,
this
->
password
);
if
(
result
!=
0
)
{
g_task_return_new_error
(
this
->
task
,
PURPLE_KWALLET_DOMAIN
,
result
,
_
(
"failed to write password, kwallet "
"responded with error code %d"
),
result
);
}
else
{
g_task_return_boolean
(
this
->
task
,
TRUE
);
}
g_clear_object
(
&
this
->
task
);
}
void
PurpleKWalletPlugin
::
WriteRequest
::
cancel
(
QString
reason
)
{
g_task_return_new_error
(
this
->
task
,
PURPLE_KWALLET_DOMAIN
,
0
,
_
(
"failed to write password: %s"
),
reason
.
toUtf8
().
constData
());
g_clear_object
(
&
this
->
task
);
}
/******************************************************************************
* ClearRequest Implementation
*****************************************************************************/
PurpleKWalletPlugin
::
ClearRequest
::
ClearRequest
(
QString
key
,
GTask
*
task
)
:
PurpleKWalletPlugin
::
Request
(
key
,
task
)
{
}
void
PurpleKWalletPlugin
::
ClearRequest
::
execute
(
KWallet
::
Wallet
*
wallet
)
{
int
result
;
result
=
wallet
->
removeEntry
(
this
->
key
);
if
(
result
!=
0
)
{
g_task_return_new_error
(
this
->
task
,
PURPLE_KWALLET_DOMAIN
,
result
,
_
(
"failed to clear password, kwallet "
"responded with error code %d"
),
result
);
}
else
{
g_task_return_boolean
(
this
->
task
,
TRUE
);
}
g_clear_object
(
&
this
->
task
);
}
void
PurpleKWalletPlugin
::
ClearRequest
::
cancel
(
QString
reason
)
{
g_task_return_new_error
(
this
->
task
,
PURPLE_KWALLET_DOMAIN
,
0
,
_
(
"failed to clear password: %s"
),
reason
.
toUtf8
().
constData
());
g_clear_object
(
&
this
->
task
);
}
/******************************************************************************
* Engine Implementation
*****************************************************************************/
PurpleKWalletPlugin
::
Engine
::
Engine
(
void
)
{
this
->
queue
=
QQueue
<
PurpleKWalletPlugin
::
Request
*>
();
this
->
wallet
=
NULL
;
this
->
connected
=
false
;
this
->
failed
=
false
;
this
->
externallyClosed
=
false
;
}
PurpleKWalletPlugin
::
Engine
::~
Engine
(
void
)
{
this
->
close
();
}
void
PurpleKWalletPlugin
::
Engine
::
open
(
void
)
{
purple_debug_misc
(
"kwallet-provider"
,
"attempting to open wallet"
);
if
(
this
->
connected
)
{
purple_debug_misc
(
"kwallet-provider"
,
"wallet already opened"
);
return
;
}
// Reset our externallyClosed and failed states.
this
->
externallyClosed
=
false
;
this
->
failed
=
false
;
// No need to check this pointer as an async open always returns non-null.
this
->
wallet
=
KWallet
::
Wallet
::
openWallet
(
PURPLE_KWALLET_WALLET_NAME
,
0
,
KWallet
::
Wallet
::
Asynchronous
);
this
->
failed
|=
!
QObject
::
connect
(
this
->
wallet
,
SIGNAL
(
walletOpened
(
bool
)),
SLOT
(
opened
(
bool
)));
this
->
failed
|=
!
QObject
::
connect
(
this
->
wallet
,
SIGNAL
(
walletClosed
(
void
)),
SLOT
(
closed
()));
if
(
this
->
failed
)
{
purple_debug_error
(
"kwallet-provider"
,
"Failed to connect KWallet signals"
);
}
}
void
PurpleKWalletPlugin
::
Engine
::
close
(
void
)
{
while
(
!
this
->
queue
.
isEmpty
())
{
PurpleKWalletPlugin
::
Request
*
request
=
this
->
queue
.
dequeue
();
request
->
cancel
(
"wallet is closing"
);
delete
request
;
}
if
(
this
->
wallet
!=
NULL
)
{
delete
this
->
wallet
;
this
->
wallet
=
NULL
;
}
this
->
connected
=
false
;
this
->
failed
=
false
;
}
void
PurpleKWalletPlugin
::
Engine
::
enqueue
(
PurpleKWalletPlugin
::
Request
*
request
)
{
this
->
queue
.
enqueue
(
request
);
processQueue
();
}
void
PurpleKWalletPlugin
::
Engine
::
opened
(
bool
opened
)
{
QString
folder_name
;
if
(
!
opened
)
{
purple_debug_error
(
"kwallet-provider"
,
"failed to open wallet"
);
delete
this
->
wallet
;
this
->
wallet
=
NULL
;
this
->
connected
=
false
;
this
->
failed
=
true
;
return
;
}
// Handle the case where the wallet opened signal connected, but the wallet
// closed signal failed to connect.
if
(
this
->
failed
)
{
purple_debug_error
(
"kwallet-provider"
,
"wallet opened, but failed to connect the wallet "
"closed signal"
);
return
;
}
this
->
connected
=
true
;
// setup our folder
folder_name
=
purple_kwallet_get_ui_name
();
if
(
!
this
->
wallet
->
hasFolder
(
folder_name
))
{
if
(
!
this
->
wallet
->
createFolder
(
folder_name
))
{
purple_debug_error
(
"kwallet-provider"
,
"failed to create folder %s in wallet."
,
folder_name
.
toUtf8
().
constData
());
this
->
failed
=
true
;
}
}
if
(
!
this
->
failed
&&
!
this
->
wallet
->
setFolder
(
folder_name
))
{
purple_debug_error
(
"kwallet-provider"
,
"failed to set folder to %s"
,
folder_name
.
toUtf8
().
constData
());
this
->
failed
=
true
;
}
purple_debug_misc
(
"kwallet-provider"
,
"successfully opened the wallet"
);
processQueue
();
}
void
PurpleKWalletPlugin
::
Engine
::
closed
(
void
)
{
purple_debug_misc
(
"kwallet-provider"
,
"the wallet was closed externally"
);
this
->
externallyClosed
=
true
;
this
->
close
();
}
void
PurpleKWalletPlugin
::
Engine
::
processQueue
()
{
if
(
this
->
externallyClosed
&&
this
->
queue
.
isEmpty
()
==
false
)
{
this
->
open
();
}
else
if
(
this
->
connected
||
this
->
failed
)
{
while
(
!
this
->
queue
.
isEmpty
())
{
PurpleKWalletPlugin
::
Request
*
request
=
this
->
queue
.
dequeue
();
if
(
this
->
failed
)
{
request
->
cancel
(
_
(
"failed to open kwallet"
));
}
else
{
request
->
execute
(
this
->
wallet
);
}
delete
request
;
}
}
}
/******************************************************************************
* PurpleCredentialProvider Implementation
*****************************************************************************/
static
void
purple_kwallet_provider_activate
(
PurpleCredentialProvider
*
provider
)
{
PurpleKWalletProvider
*
kwallet_provider
=
NULL
;
kwallet_provider
=
PURPLE_KWALLET_PROVIDER
(
provider
);
kwallet_provider
->
engine
->
open
();
}
static
void
purple_kwallet_provider_deactivate
(
PurpleCredentialProvider
*
provider
)
{
PurpleKWalletProvider
*
kwallet_provider
=
NULL
;
kwallet_provider
=
PURPLE_KWALLET_PROVIDER
(
provider
);
kwallet_provider
->
engine
->
close
();
}
static
void
purple_kwallet_read_password_async
(
PurpleCredentialProvider
*
provider
,
PurpleAccount
*
account
,
GCancellable
*
cancellable
,
GAsyncReadyCallback
callback
,
gpointer
data
)
{
PurpleKWalletProvider
*
kwallet_provider
=
NULL
;
PurpleKWalletPlugin
::
ReadRequest
*
request
=
NULL
;
GTask
*
task
=
NULL
;
QString
key
;
key
=
purple_kwallet_provider_account_key
(
account
);
task
=
g_task_new
(
G_OBJECT
(
provider
),
cancellable
,
callback
,
data
);
request
=
new
PurpleKWalletPlugin
::
ReadRequest
(
key
,
task
);
kwallet_provider
=
PURPLE_KWALLET_PROVIDER
(
provider
);
kwallet_provider
->
engine
->
enqueue
(
request
);
g_clear_object
(
&
task
);
}
static
gchar
*
purple_kwallet_read_password_finish
(
PurpleCredentialProvider
*
provider
,
GAsyncResult
*
result
,
GError
**
error
)
{
return
(
gchar
*
)
g_task_propagate_pointer
(
G_TASK
(
result
),
error
);
}
static
void
purple_kwallet_write_password_async
(
PurpleCredentialProvider
*
provider
,
PurpleAccount
*
account
,
const
gchar
*
password
,
GCancellable
*
cancellable
,
GAsyncReadyCallback
callback
,
gpointer
data
)
{
PurpleKWalletProvider
*
kwallet_provider
=
NULL
;
PurpleKWalletPlugin
::
WriteRequest
*
request
=
NULL
;
GTask
*
task
=
NULL
;
QString
key
;
task
=
g_task_new
(
G_OBJECT
(
provider
),
cancellable
,
callback
,
data
);
key
=
purple_kwallet_provider_account_key
(
account
);
request
=
new
PurpleKWalletPlugin
::
WriteRequest
(
key
,
task
,
password
);
kwallet_provider
=
PURPLE_KWALLET_PROVIDER
(
provider
);
kwallet_provider
->
engine
->
enqueue
(
request
);
g_clear_object
(
&
task
);
}
static
gboolean
purple_kwallet_write_password_finish
(
PurpleCredentialProvider
*
provider
,
GAsyncResult
*
result
,
GError
**
error
)
{
return
g_task_propagate_boolean
(
G_TASK
(
result
),
error
);
}
static
void
purple_kwallet_clear_password_async
(
PurpleCredentialProvider
*
provider
,
PurpleAccount
*
account
,
GCancellable
*
cancellable
,
GAsyncReadyCallback
callback
,
gpointer
data
)
{
PurpleKWalletProvider
*
kwallet_provider
=
NULL
;
PurpleKWalletPlugin
::
ClearRequest
*
request
=
NULL
;
GTask
*
task
=
NULL
;
QString
key
;
task
=
g_task_new
(
G_OBJECT
(
provider
),
cancellable
,
callback
,
data
);
key
=
purple_kwallet_provider_account_key
(
account
);
request
=
new
PurpleKWalletPlugin
::
ClearRequest
(
key
,
task
);
kwallet_provider
=
PURPLE_KWALLET_PROVIDER
(
provider
);
kwallet_provider
->
engine
->
enqueue
(
request
);
g_clear_object
(
&
task
);
}
static
gboolean
purple_kwallet_clear_password_finish
(
PurpleCredentialProvider
*
provider
,
GAsyncResult
*
result
,
GError
**
error
)
{
return
g_task_propagate_boolean
(
G_TASK
(
result
),
error
);
}
/******************************************************************************
* GObject Implementation
*****************************************************************************/
static
void
purple_kwallet_provider_dispose
(
GObject
*
obj
)
{
PurpleKWalletProvider
*
provider
=
PURPLE_KWALLET_PROVIDER
(
obj
);
if
(
provider
->
engine
!=
NULL
)
{
provider
->
engine
->
close
();
}
G_OBJECT_CLASS
(
purple_kwallet_provider_parent_class
)
->
dispose
(
obj
);
}
static
void
purple_kwallet_provider_finalize
(
GObject
*
obj
)
{
PurpleKWalletProvider
*
provider
=
PURPLE_KWALLET_PROVIDER
(
obj
);
if
(
provider
->
engine
!=
NULL
)
{
delete
provider
->
engine
;
provider
->
engine
=
NULL
;
}
G_OBJECT_CLASS
(
purple_kwallet_provider_parent_class
)
->
finalize
(
obj
);
}
static
void
purple_kwallet_provider_init
(
PurpleKWalletProvider
*
provider
)
{
provider
->
engine
=
new
PurpleKWalletPlugin
::
Engine
();
}
static
void
purple_kwallet_provider_class_init
(
PurpleKWalletProviderClass
*
klass
)
{
GObjectClass
*
obj_class
=
G_OBJECT_CLASS
(
klass
);
PurpleCredentialProviderClass
*
provider_class
=
NULL
;
provider_class
=
PURPLE_CREDENTIAL_PROVIDER_CLASS
(
klass
);
obj_class
->
dispose
=
purple_kwallet_provider_dispose
;
obj_class
->
finalize
=
purple_kwallet_provider_finalize
;
provider_class
->
activate
=
purple_kwallet_provider_activate
;
provider_class
->
deactivate
=
purple_kwallet_provider_deactivate
;
provider_class
->
read_password_async
=
purple_kwallet_read_password_async
;
provider_class
->
read_password_finish
=
purple_kwallet_read_password_finish
;
provider_class
->
write_password_async
=
purple_kwallet_write_password_async
;
provider_class
->
write_password_finish
=
purple_kwallet_write_password_finish
;
provider_class
->
clear_password_async
=
purple_kwallet_clear_password_async
;
provider_class
->
clear_password_finish
=
purple_kwallet_clear_password_finish
;
}
static
void
purple_kwallet_provider_class_finalize
(
PurpleKWalletProviderClass
*
klass
)
{
}
/******************************************************************************
* API
*****************************************************************************/
static
PurpleCredentialProvider
*
purple_kwallet_provider_new
(
void
)
{
return
PURPLE_CREDENTIAL_PROVIDER
(
g_object_new
(
PURPLE_KWALLET_TYPE_PROVIDER
,
"id"
,
"kwallet"
,
"name"
,
_
(
"KWallet"
),
"description"
,
_
(
"A credentials management application for the KDE "
"Software Compilation desktop environment"
),
NULL
));
}
/******************************************************************************
* Plugin Exports
*****************************************************************************/
static
GPluginPluginInfo
*
kwallet_query
(
G_GNUC_UNUSED
GError
**
error
)
{
const
gchar
*
const
authors
[]
=
{
"Pidgin Developers <devel@pidgin.im>"
,
NULL
};
return
GPLUGIN_PLUGIN_INFO
(
purple_plugin_info_new
(
"id"
,
"keyring-kwallet"
,
"name"
,
N_
(
"KWallet"
),
"version"
,
DISPLAY_VERSION
,
"category"
,
N_
(
"Keyring"
),
"summary"
,
"KWallet Keyring Plugin"
,
"description"
,
N_
(
"This plugin will store passwords in KWallet."
),
"authors"
,
authors
,
"website"
,
PURPLE_WEBSITE
,
"abi-version"
,
PURPLE_ABI_VERSION
,
"flags"
,
PURPLE_PLUGIN_INFO_FLAGS_INTERNAL
|
PURPLE_PLUGIN_INFO_FLAGS_AUTO_LOAD
,
NULL
));
}
static
gboolean
kwallet_load
(
GPluginPlugin
*
plugin
,
GError
**
error
)
{
PurpleCredentialManager
*
manager
=
NULL
;
purple_kwallet_provider_register_type
(
G_TYPE_MODULE
(
plugin
));
if
(
qCoreApp
==
NULL
)
{
int
argc
=
0
;
qCoreApp
=
new
QCoreApplication
(
argc
,
NULL
);
qCoreApp
->
setApplicationName
(
purple_kwallet_get_ui_name
());
}
if
(
!
KWallet
::
Wallet
::
isEnabled
())
{
g_set_error
(
error
,
PURPLE_KWALLET_DOMAIN
,
0
,
"KWallet service is disabled."
);
return
FALSE
;
}
manager
=
purple_credential_manager_get_default
();
instance
=
purple_kwallet_provider_new
();
return
purple_credential_manager_register
(
manager
,
instance
,
error
);
}
static
gboolean
kwallet_unload
(
G_GNUC_UNUSED
GPluginPlugin
*
plugin
,
G_GNUC_UNUSED
gboolean
shutdown
,
GError
**
error
)
{
PurpleCredentialManager
*
manager
=
NULL
;
gboolean
ret
=
FALSE
;
manager
=
purple_credential_manager_get_default
();
ret
=
purple_credential_manager_unregister
(
manager
,
instance
,
error
);
if
(
!
ret
)
{
return
ret
;
}
if
(
qCoreApp
!=
NULL
)
{
delete
qCoreApp
;
qCoreApp
=
NULL
;
}
g_clear_object
(
&
instance
);
return
TRUE
;
}
G_BEGIN_DECLS
GPLUGIN_NATIVE_PLUGIN_DECLARE
(
kwallet
)
G_END_DECLS