pidgin/pidgin
Clone
Summary
Browse
Changes
Graph
A handful of random cleanups in PidginConversation and PidginConvWindow
2021-01-08, Gary Kramlich
8aadc4b6a592
A handful of random cleanups in PidginConversation and PidginConvWindow
Testing Done:
Built and ran locally.
Reviewed at https://reviews.imfreedom.org/r/411/
/* 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
<glib.h>
#include
<glib/gi18n-lib.h>
#include
<string.h>
#include
"account.h"
#include
"keyring.h"
#include
"signals.h"
#include
"core.h"
#include
"debug.h"
#include
"internal.h"
#include
"plugins.h"
struct
_PurpleKeyring
{
gchar
*
name
;
gchar
*
id
;
PurpleKeyringRead
read_password
;
PurpleKeyringSave
save_password
;
PurpleKeyringCancelRequests
cancel_requests
;
PurpleKeyringClose
close_keyring
;
PurpleKeyringImportPassword
import_password
;
PurpleKeyringExportPassword
export_password
;
PurpleKeyringReadSettings
read_settings
;
PurpleKeyringApplySettings
apply_settings
;
gboolean
is_closing
;
gboolean
is_cancelling
;
gboolean
close_after_cancel
;
};
typedef
struct
{
GError
*
error
;
PurpleKeyringSetInUseCallback
cb
;
gpointer
cb_data
;
PurpleKeyring
*
new_kr
;
PurpleKeyring
*
old_kr
;
/*
* We are done when finished is positive and read_outstanding is zero.
*/
gboolean
finished
;
int
read_outstanding
;
gboolean
abort
;
gboolean
force
;
gboolean
succeeded
;
}
PurpleKeyringChangeTracker
;
typedef
void
(
*
PurpleKeyringDropCallback
)(
gpointer
data
);
typedef
struct
{
PurpleKeyringDropCallback
cb
;
gpointer
cb_data
;
gboolean
finished
;
int
drop_outstanding
;
}
PurpleKeyringDropTracker
;
typedef
struct
{
PurpleKeyringSaveCallback
cb
;
gpointer
cb_data
;
}
PurpleKeyringSetPasswordData
;
typedef
struct
{
gchar
*
keyring_id
;
gchar
*
mode
;
gchar
*
data
;
}
PurpleKeyringFailedImport
;
static
void
purple_keyring_change_tracker_free
(
PurpleKeyringChangeTracker
*
tracker
)
{
if
(
tracker
->
error
)
g_error_free
(
tracker
->
error
);
g_free
(
tracker
);
}
static
void
purple_keyring_failed_import_free
(
PurpleKeyringFailedImport
*
import
)
{
g_return_if_fail
(
import
!=
NULL
);
g_free
(
import
->
keyring_id
);
g_free
(
import
->
mode
);
purple_str_wipe
(
import
->
data
);
g_free
(
import
);
}
static
void
purple_keyring_close
(
PurpleKeyring
*
keyring
);
static
void
purple_keyring_drop_passwords
(
PurpleKeyring
*
keyring
,
PurpleKeyringDropCallback
cb
,
gpointer
data
);
/* A list of available keyrings */
static
GList
*
purple_keyring_keyrings
=
NULL
;
/* Keyring being used. */
static
PurpleKeyring
*
purple_keyring_inuse
=
NULL
;
/* Keyring id marked to use (may not be loadable). */
static
gchar
*
purple_keyring_to_use
=
NULL
;
static
guint
purple_keyring_pref_cbid
=
0
;
static
GList
*
purple_keyring_loaded_plugins
=
NULL
;
static
PurpleKeyringChangeTracker
*
current_change_tracker
=
NULL
;
static
gboolean
purple_keyring_is_quitting
=
FALSE
;
static
GHashTable
*
purple_keyring_failed_imports
=
NULL
;
static
const
gchar
*
purple_keyring_print_account
(
PurpleAccount
*
account
)
{
static
gchar
print_buff
[
100
];
if
(
account
==
NULL
)
{
g_snprintf
(
print_buff
,
100
,
"(null)"
);
return
print_buff
;
}
g_snprintf
(
print_buff
,
100
,
"%s:%s"
,
purple_account_get_protocol_id
(
account
),
purple_account_get_username
(
account
));
return
print_buff
;
}
/**************************************************************************/
/* Setting used keyrings */
/**************************************************************************/
PurpleKeyring
*
purple_keyring_find_keyring_by_id
(
const
gchar
*
id
)
{
GList
*
it
;
for
(
it
=
purple_keyring_keyrings
;
it
!=
NULL
;
it
=
it
->
next
)
{
PurpleKeyring
*
keyring
=
it
->
data
;
const
gchar
*
curr_id
=
purple_keyring_get_id
(
keyring
);
if
(
g_strcmp0
(
id
,
curr_id
)
==
0
)
return
keyring
;
}
return
NULL
;
}
static
void
purple_keyring_pref_callback
(
const
gchar
*
pref
,
PurplePrefType
type
,
gconstpointer
id
,
gpointer
data
)
{
PurpleKeyring
*
new_keyring
;
g_return_if_fail
(
g_strcmp0
(
pref
,
"/purple/keyring/active"
)
==
0
);
g_return_if_fail
(
type
==
PURPLE_PREF_STRING
);
g_return_if_fail
(
id
!=
NULL
);
new_keyring
=
purple_keyring_find_keyring_by_id
(
id
);
g_return_if_fail
(
new_keyring
!=
NULL
);
purple_keyring_set_inuse
(
new_keyring
,
FALSE
,
NULL
,
NULL
);
}
static
void
purple_keyring_pref_connect
(
void
)
{
g_return_if_fail
(
purple_keyring_pref_cbid
==
0
);
purple_keyring_pref_cbid
=
purple_prefs_connect_callback
(
NULL
,
"/purple/keyring/active"
,
purple_keyring_pref_callback
,
NULL
);
}
static
void
purple_keyring_pref_disconnect
(
void
)
{
g_return_if_fail
(
purple_keyring_pref_cbid
!=
0
);
purple_prefs_disconnect_callback
(
purple_keyring_pref_cbid
);
purple_keyring_pref_cbid
=
0
;
}
PurpleKeyring
*
purple_keyring_get_inuse
(
void
)
{
return
purple_keyring_inuse
;
}
static
void
purple_keyring_set_inuse_drop_cb
(
gpointer
_tracker
)
{
PurpleKeyringChangeTracker
*
tracker
=
_tracker
;
g_return_if_fail
(
tracker
!=
NULL
);
if
(
tracker
->
succeeded
)
{
purple_keyring_close
(
tracker
->
old_kr
);
purple_debug_info
(
"keyring"
,
"Successfully changed keyring.
\n
"
);
purple_keyring_inuse
=
tracker
->
new_kr
;
current_change_tracker
=
NULL
;
if
(
tracker
->
cb
!=
NULL
)
tracker
->
cb
(
NULL
,
tracker
->
cb_data
);
purple_keyring_change_tracker_free
(
tracker
);
return
;
}
purple_debug_error
(
"keyring"
,
"Failed to change keyring, aborting.
\n
"
);
purple_keyring_close
(
tracker
->
new_kr
);
purple_keyring_pref_disconnect
();
purple_prefs_set_string
(
"/purple/keyring/active"
,
purple_keyring_get_id
(
tracker
->
old_kr
));
purple_keyring_pref_connect
();
current_change_tracker
=
NULL
;
if
(
tracker
->
error
==
NULL
)
{
tracker
->
error
=
g_error_new_literal
(
PURPLE_KEYRING_ERROR
,
PURPLE_KEYRING_ERROR_UNKNOWN
,
_
(
"An unknown error has occured."
));
}
if
(
tracker
->
cb
!=
NULL
)
tracker
->
cb
(
tracker
->
error
,
tracker
->
cb_data
);
purple_keyring_change_tracker_free
(
tracker
);
}
static
void
purple_keyring_set_inuse_save_cb
(
PurpleAccount
*
account
,
GError
*
error
,
gpointer
_tracker
)
{
PurpleKeyringChangeTracker
*
tracker
=
_tracker
;
g_return_if_fail
(
account
!=
NULL
);
g_return_if_fail
(
tracker
!=
NULL
);
tracker
->
read_outstanding
--
;
if
(
error
==
NULL
)
{
/* no error */
}
else
if
(
g_error_matches
(
error
,
PURPLE_KEYRING_ERROR
,
PURPLE_KEYRING_ERROR_NOPASSWORD
))
{
if
(
purple_debug_is_verbose
())
{
purple_debug_misc
(
"keyring"
,
"No password found while "
"changing keyring for account %s: %s.
\n
"
,
purple_keyring_print_account
(
account
),
error
->
message
);
}
}
else
if
(
g_error_matches
(
error
,
PURPLE_KEYRING_ERROR
,
PURPLE_KEYRING_ERROR_ACCESSDENIED
))
{
purple_debug_info
(
"keyring"
,
"Access denied while changing "
"keyring for account %s: %s.
\n
"
,
purple_keyring_print_account
(
account
),
error
->
message
);
tracker
->
abort
=
TRUE
;
if
(
tracker
->
error
!=
NULL
)
g_error_free
(
tracker
->
error
);
tracker
->
error
=
g_error_copy
(
error
);
}
else
if
(
g_error_matches
(
error
,
PURPLE_KEYRING_ERROR
,
PURPLE_KEYRING_ERROR_CANCELLED
))
{
purple_debug_info
(
"keyring"
,
"Operation cancelled while "
"changing keyring for account %s: %s.
\n
"
,
purple_keyring_print_account
(
account
),
error
->
message
);
tracker
->
abort
=
TRUE
;
if
(
tracker
->
error
==
NULL
)
tracker
->
error
=
g_error_copy
(
error
);
}
else
if
(
g_error_matches
(
error
,
PURPLE_KEYRING_ERROR
,
PURPLE_KEYRING_ERROR_BACKENDFAIL
))
{
purple_debug_error
(
"keyring"
,
"Failed to communicate with "
"backend while changing keyring for account %s: %s. "
"Aborting changes.
\n
"
,
purple_keyring_print_account
(
account
),
error
->
message
);
tracker
->
abort
=
TRUE
;
if
(
tracker
->
error
!=
NULL
)
g_error_free
(
tracker
->
error
);
tracker
->
error
=
g_error_copy
(
error
);
}
else
{
purple_debug_error
(
"keyring"
,
"Unknown error while changing "
"keyring for account %s: %s. Aborting changes.
\n
"
,
purple_keyring_print_account
(
account
),
error
->
message
);
tracker
->
abort
=
TRUE
;
if
(
tracker
->
error
==
NULL
)
tracker
->
error
=
g_error_copy
(
error
);
}
purple_signal_emit
(
purple_keyring_get_handle
(),
"password-migration"
,
account
);
if
(
!
tracker
->
finished
||
tracker
->
read_outstanding
>
0
)
return
;
/* This was the last one. */
if
(
tracker
->
abort
&&
!
tracker
->
force
)
{
tracker
->
succeeded
=
FALSE
;
purple_keyring_drop_passwords
(
tracker
->
new_kr
,
purple_keyring_set_inuse_drop_cb
,
tracker
);
}
else
{
tracker
->
succeeded
=
TRUE
;
purple_keyring_drop_passwords
(
tracker
->
old_kr
,
purple_keyring_set_inuse_drop_cb
,
tracker
);
}
}
static
void
purple_keyring_set_inuse_read_cb
(
PurpleAccount
*
account
,
const
gchar
*
password
,
GError
*
error
,
gpointer
_tracker
)
{
PurpleKeyringChangeTracker
*
tracker
=
_tracker
;
PurpleKeyringSave
save_cb
;
g_return_if_fail
(
account
!=
NULL
);
g_return_if_fail
(
tracker
!=
NULL
);
if
(
tracker
->
abort
)
{
purple_keyring_set_inuse_save_cb
(
account
,
NULL
,
tracker
);
return
;
}
if
(
error
!=
NULL
)
{
if
(
tracker
->
force
==
TRUE
||
g_error_matches
(
error
,
PURPLE_KEYRING_ERROR
,
PURPLE_KEYRING_ERROR_NOPASSWORD
))
{
/* Don't save password, and ignore it. */
}
else
{
tracker
->
abort
=
TRUE
;
}
purple_keyring_set_inuse_save_cb
(
account
,
error
,
tracker
);
return
;
}
save_cb
=
purple_keyring_get_save_password
(
tracker
->
new_kr
);
g_assert
(
save_cb
!=
NULL
);
save_cb
(
account
,
password
,
purple_keyring_set_inuse_save_cb
,
tracker
);
}
void
purple_keyring_set_inuse
(
PurpleKeyring
*
newkeyring
,
gboolean
force
,
PurpleKeyringSetInUseCallback
cb
,
gpointer
data
)
{
PurpleKeyring
*
oldkeyring
;
PurpleKeyringChangeTracker
*
tracker
;
GList
*
it
;
PurpleKeyringRead
read_cb
;
if
(
current_change_tracker
!=
NULL
)
{
GError
*
error
;
purple_debug_error
(
"keyring"
,
"There is password migration "
"session already running.
\n
"
);
if
(
cb
==
NULL
)
return
;
error
=
g_error_new_literal
(
PURPLE_KEYRING_ERROR
,
PURPLE_KEYRING_ERROR_INTERNAL
,
_
(
"There is a password migration session already "
"running."
));
cb
(
error
,
data
);
g_error_free
(
error
);
return
;
}
oldkeyring
=
purple_keyring_get_inuse
();
if
(
oldkeyring
==
newkeyring
)
{
if
(
purple_debug_is_verbose
())
{
purple_debug_misc
(
"keyring"
,
"Old and new keyring are the same: %s.
\n
"
,
(
newkeyring
!=
NULL
)
?
newkeyring
->
id
:
"(null)"
);
}
if
(
cb
!=
NULL
)
cb
(
NULL
,
data
);
return
;
}
purple_debug_info
(
"keyring"
,
"Attempting to set new keyring: %s.
\n
"
,
(
newkeyring
!=
NULL
)
?
newkeyring
->
id
:
"(null)"
);
if
(
oldkeyring
==
NULL
)
{
/* No keyring was set before. */
if
(
purple_debug_is_verbose
())
{
purple_debug_misc
(
"keyring"
,
"Setting keyring for the first time: %s.
\n
"
,
(
newkeyring
!=
NULL
)
?
newkeyring
->
id
:
"(null)"
);
}
purple_keyring_inuse
=
newkeyring
;
g_assert
(
current_change_tracker
==
NULL
);
if
(
cb
!=
NULL
)
cb
(
NULL
,
data
);
return
;
}
/* Starting a migration. */
read_cb
=
purple_keyring_get_read_password
(
oldkeyring
);
g_assert
(
read_cb
!=
NULL
);
purple_debug_misc
(
"keyring"
,
"Starting migration from: %s.
\n
"
,
oldkeyring
->
id
);
tracker
=
g_new0
(
PurpleKeyringChangeTracker
,
1
);
current_change_tracker
=
tracker
;
tracker
->
cb
=
cb
;
tracker
->
cb_data
=
data
;
tracker
->
new_kr
=
newkeyring
;
tracker
->
old_kr
=
oldkeyring
;
tracker
->
force
=
force
;
for
(
it
=
purple_accounts_get_all
();
it
!=
NULL
;
it
=
it
->
next
)
{
if
(
tracker
->
abort
)
{
tracker
->
finished
=
TRUE
;
break
;
}
tracker
->
read_outstanding
++
;
if
(
it
->
next
==
NULL
)
tracker
->
finished
=
TRUE
;
read_cb
(
it
->
data
,
purple_keyring_set_inuse_read_cb
,
tracker
);
}
}
void
purple_keyring_register
(
PurpleKeyring
*
keyring
)
{
const
gchar
*
keyring_id
;
g_return_if_fail
(
keyring
!=
NULL
);
keyring_id
=
purple_keyring_get_id
(
keyring
);
purple_debug_info
(
"keyring"
,
"Registering keyring: %s
\n
"
,
keyring_id
?
keyring_id
:
"(null)"
);
if
(
purple_keyring_get_id
(
keyring
)
==
NULL
||
purple_keyring_get_name
(
keyring
)
==
NULL
||
purple_keyring_get_read_password
(
keyring
)
==
NULL
||
purple_keyring_get_save_password
(
keyring
)
==
NULL
)
{
purple_debug_error
(
"keyring"
,
"Cannot register %s, some "
"required fields are missing.
\n
"
,
keyring_id
?
keyring_id
:
"(null)"
);
return
;
}
if
(
purple_keyring_find_keyring_by_id
(
keyring_id
)
!=
NULL
)
{
purple_debug_error
(
"keyring"
,
"Keyring is already registered.
\n
"
);
return
;
}
/* If this is the configured keyring, use it. */
if
(
purple_keyring_inuse
==
NULL
&&
g_strcmp0
(
keyring_id
,
purple_keyring_to_use
)
==
0
)
{
purple_debug_misc
(
"keyring"
,
"Keyring %s matches keyring to "
"use, using it."
,
keyring_id
);
purple_keyring_set_inuse
(
keyring
,
TRUE
,
NULL
,
NULL
);
}
purple_signal_emit
(
purple_keyring_get_handle
(),
"keyring-register"
,
keyring_id
,
keyring
);
if
(
purple_debug_is_verbose
())
{
purple_debug_info
(
"keyring"
,
"Registered keyring: %s.
\n
"
,
keyring_id
);
}
purple_keyring_keyrings
=
g_list_prepend
(
purple_keyring_keyrings
,
keyring
);
}
void
purple_keyring_unregister
(
PurpleKeyring
*
keyring
)
{
PurpleKeyring
*
inuse
;
PurpleKeyring
*
fallback
;
const
gchar
*
keyring_id
;
g_return_if_fail
(
keyring
!=
NULL
);
keyring_id
=
purple_keyring_get_id
(
keyring
);
purple_debug_info
(
"keyring"
,
"Unregistering keyring: %s.
\n
"
,
keyring_id
);
purple_signal_emit
(
purple_keyring_get_handle
(),
"keyring-unregister"
,
keyring_id
,
keyring
);
inuse
=
purple_keyring_get_inuse
();
fallback
=
purple_keyring_find_keyring_by_id
(
PURPLE_DEFAULT_KEYRING
);
if
(
inuse
==
keyring
)
{
if
(
inuse
!=
fallback
)
{
purple_keyring_set_inuse
(
fallback
,
TRUE
,
NULL
,
NULL
);
}
else
{
fallback
=
NULL
;
purple_keyring_set_inuse
(
NULL
,
TRUE
,
NULL
,
NULL
);
}
}
purple_keyring_keyrings
=
g_list_remove
(
purple_keyring_keyrings
,
keyring
);
}
GList
*
purple_keyring_get_options
(
void
)
{
GList
*
options
=
NULL
;
GList
*
it
;
static
gchar
currentDisabledName
[
40
];
if
(
purple_keyring_get_inuse
()
==
NULL
&&
purple_keyring_to_use
!=
NULL
&&
purple_keyring_to_use
[
0
]
!=
'\0'
)
{
g_snprintf
(
currentDisabledName
,
sizeof
(
currentDisabledName
),
_
(
"%s (disabled)"
),
purple_keyring_to_use
);
options
=
g_list_append
(
options
,
currentDisabledName
);
options
=
g_list_append
(
options
,
purple_keyring_to_use
);
}
for
(
it
=
purple_keyring_keyrings
;
it
!=
NULL
;
it
=
it
->
next
)
{
PurpleKeyring
*
keyring
=
it
->
data
;
options
=
g_list_append
(
options
,
(
gpointer
)
purple_keyring_get_name
(
keyring
));
options
=
g_list_append
(
options
,
(
gpointer
)
purple_keyring_get_id
(
keyring
));
}
return
options
;
}
/**************************************************************************/
/* Keyring plugin wrappers */
/**************************************************************************/
static
void
purple_keyring_close
(
PurpleKeyring
*
keyring
)
{
PurpleKeyringClose
close_cb
;
g_return_if_fail
(
keyring
!=
NULL
);
if
(
keyring
->
is_cancelling
)
{
keyring
->
close_after_cancel
=
TRUE
;
return
;
}
if
(
keyring
->
is_closing
)
return
;
keyring
->
is_closing
=
TRUE
;
close_cb
=
purple_keyring_get_close_keyring
(
keyring
);
if
(
close_cb
!=
NULL
)
close_cb
();
keyring
->
is_closing
=
FALSE
;
}
static
void
purple_keyring_cancel_requests
(
PurpleKeyring
*
keyring
)
{
PurpleKeyringCancelRequests
cancel_cb
;
g_return_if_fail
(
keyring
!=
NULL
);
if
(
keyring
->
is_cancelling
)
return
;
keyring
->
is_cancelling
=
TRUE
;
cancel_cb
=
purple_keyring_get_cancel_requests
(
keyring
);
if
(
cancel_cb
!=
NULL
)
cancel_cb
();
keyring
->
is_cancelling
=
FALSE
;
if
(
keyring
->
close_after_cancel
)
{
keyring
->
close_after_cancel
=
FALSE
;
purple_keyring_close
(
keyring
);
}
}
static
void
purple_keyring_drop_passwords_save_cb
(
PurpleAccount
*
account
,
GError
*
error
,
gpointer
_tracker
)
{
PurpleKeyringDropTracker
*
tracker
=
_tracker
;
tracker
->
drop_outstanding
--
;
if
(
!
tracker
->
finished
||
tracker
->
drop_outstanding
>
0
)
return
;
if
(
tracker
->
cb
)
tracker
->
cb
(
tracker
->
cb_data
);
g_free
(
tracker
);
}
static
void
purple_keyring_drop_passwords
(
PurpleKeyring
*
keyring
,
PurpleKeyringDropCallback
cb
,
gpointer
data
)
{
GList
*
it
;
PurpleKeyringSave
save_cb
;
PurpleKeyringDropTracker
*
tracker
;
g_return_if_fail
(
keyring
!=
NULL
);
save_cb
=
purple_keyring_get_save_password
(
keyring
);
g_assert
(
save_cb
!=
NULL
);
it
=
purple_accounts_get_all
();
if
(
it
==
NULL
)
return
;
tracker
=
g_new0
(
PurpleKeyringDropTracker
,
1
);
tracker
->
cb
=
cb
;
tracker
->
cb_data
=
data
;
for
(;
it
!=
NULL
;
it
=
it
->
next
)
{
PurpleAccount
*
account
=
it
->
data
;
tracker
->
drop_outstanding
++
;
if
(
it
->
next
==
NULL
)
tracker
->
finished
=
TRUE
;
save_cb
(
account
,
NULL
,
purple_keyring_drop_passwords_save_cb
,
tracker
);
}
}
gboolean
purple_keyring_import_password
(
PurpleAccount
*
account
,
const
gchar
*
keyring_id
,
const
gchar
*
mode
,
const
gchar
*
data
,
GError
**
error
)
{
PurpleKeyring
*
keyring
;
PurpleKeyring
*
inuse
;
PurpleKeyringImportPassword
import
;
g_return_val_if_fail
(
account
!=
NULL
,
FALSE
);
if
(
keyring_id
==
NULL
)
keyring_id
=
PURPLE_DEFAULT_KEYRING
;
purple_debug_misc
(
"keyring"
,
"Importing password for account %s to "
"keyring %s.
\n
"
,
purple_keyring_print_account
(
account
),
keyring_id
);
keyring
=
purple_keyring_find_keyring_by_id
(
keyring_id
);
if
(
keyring
==
NULL
)
{
g_set_error_literal
(
error
,
PURPLE_KEYRING_ERROR
,
PURPLE_KEYRING_ERROR_BACKENDFAIL
,
_
(
"Specified keyring is not registered."
));
purple_debug_warning
(
"Keyring"
,
"Specified keyring is not "
"registered, cannot import password info for account "
"%s.
\n
"
,
purple_keyring_print_account
(
account
));
return
FALSE
;
}
inuse
=
purple_keyring_get_inuse
();
if
(
inuse
==
NULL
)
{
PurpleKeyringFailedImport
*
import
;
g_set_error_literal
(
error
,
PURPLE_KEYRING_ERROR
,
PURPLE_KEYRING_ERROR_NOKEYRING
,
_
(
"No keyring loaded, cannot import password info."
));
purple_debug_warning
(
"Keyring"
,
"No keyring loaded, cannot import password info for "
"account %s.
\n
"
,
purple_keyring_print_account
(
account
));
import
=
g_new0
(
PurpleKeyringFailedImport
,
1
);
import
->
keyring_id
=
g_strdup
(
keyring_id
);
import
->
mode
=
g_strdup
(
mode
);
import
->
data
=
g_strdup
(
data
);
g_hash_table_insert
(
purple_keyring_failed_imports
,
account
,
import
);
return
FALSE
;
}
if
(
inuse
!=
keyring
)
{
g_set_error_literal
(
error
,
PURPLE_KEYRING_ERROR
,
PURPLE_KEYRING_ERROR_INTERNAL
,
_
(
"Specified keyring ID does not match the loaded one."
));
purple_debug_error
(
"keyring"
,
"Specified keyring %s is not currently used (%s). "
"Data will be lost.
\n
"
,
keyring_id
,
purple_keyring_get_id
(
inuse
));
return
FALSE
;
}
import
=
purple_keyring_get_import_password
(
inuse
);
if
(
import
==
NULL
)
{
if
(
purple_debug_is_verbose
())
{
purple_debug_misc
(
"Keyring"
,
"Configured keyring "
"cannot import password info. This might be "
"normal.
\n
"
);
}
return
TRUE
;
}
return
import
(
account
,
mode
,
data
,
error
);
}
gboolean
purple_keyring_export_password
(
PurpleAccount
*
account
,
const
gchar
**
keyring_id
,
const
gchar
**
mode
,
gchar
**
data
,
GError
**
error
,
GDestroyNotify
*
destroy
)
{
PurpleKeyring
*
inuse
;
PurpleKeyringExportPassword
export
;
g_return_val_if_fail
(
account
!=
NULL
,
FALSE
);
g_return_val_if_fail
(
keyring_id
!=
NULL
,
FALSE
);
g_return_val_if_fail
(
mode
!=
NULL
,
FALSE
);
g_return_val_if_fail
(
data
!=
NULL
,
FALSE
);
g_return_val_if_fail
(
error
!=
NULL
,
FALSE
);
inuse
=
purple_keyring_get_inuse
();
if
(
inuse
==
NULL
)
{
PurpleKeyringFailedImport
*
import
=
g_hash_table_lookup
(
purple_keyring_failed_imports
,
account
);
if
(
import
==
NULL
)
{
g_set_error_literal
(
error
,
PURPLE_KEYRING_ERROR
,
PURPLE_KEYRING_ERROR_NOKEYRING
,
_
(
"No keyring configured, cannot export password info."
));
purple_debug_warning
(
"keyring"
,
"No keyring configured, cannot export password "
"info.
\n
"
);
return
FALSE
;
}
else
{
purple_debug_info
(
"keyring"
,
"No keyring configured, "
"getting fallback export data for %s.
\n
"
,
purple_keyring_print_account
(
account
));
*
keyring_id
=
import
->
keyring_id
;
*
mode
=
import
->
mode
;
*
data
=
g_strdup
(
import
->
data
);
*
destroy
=
(
GDestroyNotify
)
purple_str_wipe
;
return
TRUE
;
}
}
if
(
purple_debug_is_verbose
())
{
purple_debug_misc
(
"keyring"
,
"Exporting password for account %s from keyring %s
\n
"
,
purple_keyring_print_account
(
account
),
purple_keyring_get_id
(
inuse
));
}
*
keyring_id
=
purple_keyring_get_id
(
inuse
);
export
=
purple_keyring_get_export_password
(
inuse
);
if
(
export
==
NULL
)
{
if
(
purple_debug_is_verbose
())
{
purple_debug_misc
(
"Keyring"
,
"Configured keyring "
"cannot export password info. This might be "
"normal.
\n
"
);
}
*
mode
=
NULL
;
*
data
=
NULL
;
*
destroy
=
NULL
;
return
TRUE
;
}
return
export
(
account
,
mode
,
data
,
error
,
destroy
);
}
/**************************************************************************/
/* PurpleKeyring accessors */
/**************************************************************************/
PurpleKeyring
*
purple_keyring_new
(
void
)
{
return
g_new0
(
PurpleKeyring
,
1
);
}
void
purple_keyring_free
(
PurpleKeyring
*
keyring
)
{
g_return_if_fail
(
keyring
!=
NULL
);
g_free
(
keyring
->
name
);
g_free
(
keyring
->
id
);
g_free
(
keyring
);
}
const
gchar
*
purple_keyring_get_name
(
const
PurpleKeyring
*
keyring
)
{
g_return_val_if_fail
(
keyring
!=
NULL
,
NULL
);
return
keyring
->
name
;
}
const
gchar
*
purple_keyring_get_id
(
const
PurpleKeyring
*
keyring
)
{
g_return_val_if_fail
(
keyring
!=
NULL
,
NULL
);
return
keyring
->
id
;
}
PurpleKeyringRead
purple_keyring_get_read_password
(
const
PurpleKeyring
*
keyring
)
{
g_return_val_if_fail
(
keyring
!=
NULL
,
NULL
);
return
keyring
->
read_password
;
}
PurpleKeyringSave
purple_keyring_get_save_password
(
const
PurpleKeyring
*
keyring
)
{
g_return_val_if_fail
(
keyring
!=
NULL
,
NULL
);
return
keyring
->
save_password
;
}
PurpleKeyringCancelRequests
purple_keyring_get_cancel_requests
(
const
PurpleKeyring
*
keyring
)
{
g_return_val_if_fail
(
keyring
!=
NULL
,
NULL
);
return
keyring
->
cancel_requests
;
}
PurpleKeyringClose
purple_keyring_get_close_keyring
(
const
PurpleKeyring
*
keyring
)
{
g_return_val_if_fail
(
keyring
!=
NULL
,
NULL
);
return
keyring
->
close_keyring
;
}
PurpleKeyringImportPassword
purple_keyring_get_import_password
(
const
PurpleKeyring
*
keyring
)
{
g_return_val_if_fail
(
keyring
!=
NULL
,
NULL
);
return
keyring
->
import_password
;
}
PurpleKeyringExportPassword
purple_keyring_get_export_password
(
const
PurpleKeyring
*
keyring
)
{
g_return_val_if_fail
(
keyring
!=
NULL
,
NULL
);
return
keyring
->
export_password
;
}
PurpleKeyringReadSettings
purple_keyring_get_read_settings
(
const
PurpleKeyring
*
keyring
)
{
g_return_val_if_fail
(
keyring
!=
NULL
,
NULL
);
return
keyring
->
read_settings
;
}
PurpleKeyringApplySettings
purple_keyring_get_apply_settings
(
const
PurpleKeyring
*
keyring
)
{
g_return_val_if_fail
(
keyring
!=
NULL
,
NULL
);
return
keyring
->
apply_settings
;
}
void
purple_keyring_set_name
(
PurpleKeyring
*
keyring
,
const
gchar
*
name
)
{
g_return_if_fail
(
keyring
!=
NULL
);
g_return_if_fail
(
name
!=
NULL
);
g_free
(
keyring
->
name
);
keyring
->
name
=
g_strdup
(
name
);
}
void
purple_keyring_set_id
(
PurpleKeyring
*
keyring
,
const
gchar
*
id
)
{
g_return_if_fail
(
keyring
!=
NULL
);
g_return_if_fail
(
id
!=
NULL
);
g_free
(
keyring
->
id
);
keyring
->
id
=
g_strdup
(
id
);
}
void
purple_keyring_set_read_password
(
PurpleKeyring
*
keyring
,
PurpleKeyringRead
read_cb
)
{
g_return_if_fail
(
keyring
!=
NULL
);
g_return_if_fail
(
read_cb
!=
NULL
);
keyring
->
read_password
=
read_cb
;
}
void
purple_keyring_set_save_password
(
PurpleKeyring
*
keyring
,
PurpleKeyringSave
save_cb
)
{
g_return_if_fail
(
keyring
!=
NULL
);
g_return_if_fail
(
save_cb
!=
NULL
);
keyring
->
save_password
=
save_cb
;
}
void
purple_keyring_set_cancel_requests
(
PurpleKeyring
*
keyring
,
PurpleKeyringCancelRequests
cancel_requests
)
{
g_return_if_fail
(
keyring
!=
NULL
);
keyring
->
cancel_requests
=
cancel_requests
;
}
void
purple_keyring_set_close_keyring
(
PurpleKeyring
*
keyring
,
PurpleKeyringClose
close_cb
)
{
g_return_if_fail
(
keyring
!=
NULL
);
keyring
->
close_keyring
=
close_cb
;
}
void
purple_keyring_set_import_password
(
PurpleKeyring
*
keyring
,
PurpleKeyringImportPassword
import_password
)
{
g_return_if_fail
(
keyring
!=
NULL
);
keyring
->
import_password
=
import_password
;
}
void
purple_keyring_set_export_password
(
PurpleKeyring
*
keyring
,
PurpleKeyringExportPassword
export_password
)
{
g_return_if_fail
(
keyring
!=
NULL
);
keyring
->
export_password
=
export_password
;
}
void
purple_keyring_set_read_settings
(
PurpleKeyring
*
keyring
,
PurpleKeyringReadSettings
read_settings
)
{
g_return_if_fail
(
keyring
!=
NULL
);
keyring
->
read_settings
=
read_settings
;
}
void
purple_keyring_set_apply_settings
(
PurpleKeyring
*
keyring
,
PurpleKeyringApplySettings
apply_settings
)
{
g_return_if_fail
(
keyring
!=
NULL
);
keyring
->
apply_settings
=
apply_settings
;
}
/**************************************************************************/
/* Error Codes */
/**************************************************************************/
GQuark
purple_keyring_error_domain
(
void
)
{
return
g_quark_from_static_string
(
"libpurple keyring"
);
}
/**************************************************************************/
/* Keyring Subsystem */
/**************************************************************************/
static
void
purple_keyring_core_initialized_cb
(
void
)
{
if
(
purple_keyring_inuse
==
NULL
)
{
purple_notify_error
(
NULL
,
_
(
"Keyrings"
),
_
(
"Failed to load selected keyring."
),
_
(
"Check your system configuration or select another "
"one in Preferences dialog."
),
NULL
);
}
}
static
void
purple_keyring_core_quitting_cb
()
{
if
(
current_change_tracker
!=
NULL
)
{
PurpleKeyringChangeTracker
*
tracker
=
current_change_tracker
;
tracker
->
abort
=
TRUE
;
if
(
tracker
->
old_kr
)
purple_keyring_cancel_requests
(
tracker
->
old_kr
);
if
(
current_change_tracker
==
tracker
&&
tracker
->
new_kr
)
purple_keyring_cancel_requests
(
tracker
->
new_kr
);
}
purple_keyring_is_quitting
=
TRUE
;
if
(
purple_keyring_inuse
!=
NULL
)
purple_keyring_cancel_requests
(
purple_keyring_inuse
);
}
void
purple_keyring_init
(
void
)
{
const
gchar
*
touse
;
GList
*
plugins
,
*
it
;
purple_keyring_keyrings
=
NULL
;
purple_keyring_inuse
=
NULL
;
purple_keyring_failed_imports
=
g_hash_table_new_full
(
g_direct_hash
,
g_direct_equal
,
NULL
,
(
GDestroyNotify
)
purple_keyring_failed_import_free
);
/* void keyring_register(const char *keyring_id,
* PurpleKeyring * keyring);
*
* A signal called when keyring is registered.
*
* @param keyring_id The keyring ID.
* @param keyring The keyring.
*/
purple_signal_register
(
purple_keyring_get_handle
(),
"keyring-register"
,
purple_marshal_VOID__POINTER_POINTER
,
G_TYPE_NONE
,
2
,
G_TYPE_STRING
,
PURPLE_TYPE_KEYRING
);
/* void keyring_unregister(const char *keyring_id,
* PurpleKeyring * keyring);
*
* A signal called when keyring is unregistered.
*
* @param keyring_id The keyring ID.
* @param keyring The keyring.
*/
purple_signal_register
(
purple_keyring_get_handle
(),
"keyring-unregister"
,
purple_marshal_VOID__POINTER_POINTER
,
G_TYPE_NONE
,
2
,
G_TYPE_STRING
,
PURPLE_TYPE_KEYRING
);
/* void password_migration(PurpleAccount* account);
*
* A signal called, when a password for the account was moved to another
* keyring.
*
* @param account The account.
*/
purple_signal_register
(
purple_keyring_get_handle
(),
"password-migration"
,
purple_marshal_VOID__POINTER
,
G_TYPE_NONE
,
1
,
PURPLE_TYPE_ACCOUNT
);
touse
=
purple_prefs_get_string
(
"/purple/keyring/active"
);
if
(
touse
==
NULL
)
{
purple_prefs_add_none
(
"/purple/keyring"
);
purple_prefs_add_string
(
"/purple/keyring/active"
,
PURPLE_DEFAULT_KEYRING
);
purple_keyring_to_use
=
g_strdup
(
PURPLE_DEFAULT_KEYRING
);
}
else
purple_keyring_to_use
=
g_strdup
(
touse
);
purple_keyring_pref_connect
();
plugins
=
purple_plugins_find_all
();
for
(
it
=
plugins
;
it
!=
NULL
;
it
=
it
->
next
)
{
PurplePlugin
*
plugin
=
PURPLE_PLUGIN
(
it
->
data
);
GPluginPluginInfo
*
info
=
GPLUGIN_PLUGIN_INFO
(
purple_plugin_get_info
(
plugin
));
if
(
!
g_str_has_prefix
(
gplugin_plugin_info_get_id
(
info
),
"keyring-"
))
{
continue
;
}
if
(
purple_plugin_is_loaded
(
plugin
))
continue
;
if
(
purple_plugin_load
(
plugin
,
NULL
))
{
purple_keyring_loaded_plugins
=
g_list_append
(
purple_keyring_loaded_plugins
,
plugin
);
}
}
g_list_free
(
plugins
);
if
(
purple_keyring_inuse
==
NULL
)
purple_debug_error
(
"keyring"
,
"Selected keyring failed to load
\n
"
);
purple_signal_connect
(
purple_get_core
(),
"core-initialized"
,
purple_keyring_get_handle
(),
PURPLE_CALLBACK
(
purple_keyring_core_initialized_cb
),
NULL
);
purple_signal_connect
(
purple_get_core
(),
"quitting"
,
purple_keyring_get_handle
(),
PURPLE_CALLBACK
(
purple_keyring_core_quitting_cb
),
NULL
);
}
void
purple_keyring_uninit
(
void
)
{
GList
*
it
;
purple_keyring_pref_disconnect
();
g_free
(
purple_keyring_to_use
);
purple_keyring_inuse
=
NULL
;
g_hash_table_destroy
(
purple_keyring_failed_imports
);
purple_keyring_failed_imports
=
NULL
;
for
(
it
=
g_list_first
(
purple_keyring_loaded_plugins
);
it
!=
NULL
;
it
=
g_list_next
(
it
))
{
PurplePlugin
*
plugin
=
PURPLE_PLUGIN
(
it
->
data
);
if
(
g_list_find
(
purple_plugins_get_loaded
(),
plugin
)
==
NULL
)
continue
;
purple_plugin_unload
(
plugin
,
NULL
);
}
g_list_free
(
purple_keyring_loaded_plugins
);
purple_keyring_loaded_plugins
=
NULL
;
purple_signals_unregister_by_instance
(
purple_keyring_get_handle
());
purple_signals_disconnect_by_handle
(
purple_keyring_get_handle
());
}
void
*
purple_keyring_get_handle
(
void
)
{
static
int
handle
;
return
&
handle
;
}
static
PurpleKeyring
*
purple_keyring_copy
(
PurpleKeyring
*
keyring
)
{
PurpleKeyring
*
keyring_copy
;
g_return_val_if_fail
(
keyring
!=
NULL
,
NULL
);
keyring_copy
=
purple_keyring_new
();
*
keyring_copy
=
*
keyring
;
keyring_copy
->
name
=
g_strdup
(
keyring
->
name
);
keyring_copy
->
id
=
g_strdup
(
keyring
->
id
);
return
keyring_copy
;
}
GType
purple_keyring_get_type
(
void
)
{
static
GType
type
=
0
;
if
(
type
==
0
)
{
type
=
g_boxed_type_register_static
(
"PurpleKeyring"
,
(
GBoxedCopyFunc
)
purple_keyring_copy
,
(
GBoxedFreeFunc
)
purple_keyring_free
);
}
return
type
;
}