qulogic/pidgin
Clone
Summary
Browse
Changes
Graph
Update a bunch of gettext stuff
8 months ago, Gary Kramlich
c2cb3f628555
Update a bunch of gettext stuff
Add support for a PURPLE_LOCALE_DIR environment variable so we can set the
locale directory in a dev environment.
Added purple_get_locale_dir() which will check the environment variable or
fallback to PURPLE_LOCALE_DIR.
Removed the old PACKAGE and PACKAGE_NAME constants and replaced them with
GETTEXT_PACKAGE which is much more self explanatory.
Testing Done:
Compiled with finch enabled and verified no issues.
Reviewed at https://reviews.imfreedom.org/r/2759/
/*
* 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
<purpleconfig.h>
#include
<string.h>
#include
<stdio.h>
#include
<stdlib.h>
#include
<sys/types.h>
#include
<glib.h>
#include
"prefs.h"
#include
"debug.h"
#include
"purplepath.h"
#include
"util.h"
#ifdef _WIN32
#include
"win32/win32dep.h"
#endif
struct
_PurplePrefCallbackData
{
PurplePrefCallback
func
;
gpointer
data
;
guint
id
;
void
*
handle
;
void
*
ui_data
;
char
*
name
;
};
struct
pref_cb
{
PurplePrefCallback
func
;
gpointer
data
;
guint
id
;
void
*
handle
;
void
*
ui_data
;
char
*
name
;
};
/* TODO: This should use PurpleValues? */
struct
purple_pref
{
PurplePrefType
type
;
char
*
name
;
union
{
/* 'generic' is kind of ugly. We use it as an elegant way to refer to
the value of this pref when calling callback functions. We could
use 'boolean' or 'integer' or any other field... but it feels
mildly cleaner to use a gpointer. Maybe it would be best to use a
GValue? */
gpointer
generic
;
gboolean
boolean
;
int
integer
;
char
*
string
;
GList
*
stringlist
;
}
value
;
GSList
*
callbacks
;
struct
purple_pref
*
parent
;
struct
purple_pref
*
sibling
;
struct
purple_pref
*
first_child
;
};
static
struct
purple_pref
prefs
=
{
PURPLE_PREF_NONE
,
NULL
,
{
NULL
},
NULL
,
NULL
,
NULL
,
NULL
};
static
GHashTable
*
prefs_hash
=
NULL
;
static
guint
save_timer
=
0
;
static
gboolean
prefs_loaded
=
FALSE
;
/*********************************************************************
* Private utility functions *
*********************************************************************/
static
struct
purple_pref
*
find_pref
(
const
char
*
name
)
{
g_return_val_if_fail
(
name
!=
NULL
&&
name
[
0
]
==
'/'
,
NULL
);
if
(
name
[
1
]
==
'\0'
)
return
&
prefs
;
else
{
/* When we're initializing, the debug system is
* initialized before the prefs system, but debug
* calls will end up calling prefs functions, so we
* need to deal cleanly here. */
if
(
prefs_hash
)
return
g_hash_table_lookup
(
prefs_hash
,
name
);
else
return
NULL
;
}
}
/*********************************************************************
* Writing to disk *
*********************************************************************/
/*
* This function recursively creates the PurpleXmlNode tree from the prefs
* tree structure. Yay recursion!
*/
static
void
pref_to_xmlnode
(
PurpleXmlNode
*
parent
,
struct
purple_pref
*
pref
)
{
PurpleXmlNode
*
node
,
*
childnode
;
struct
purple_pref
*
child
;
char
buf
[
21
];
GList
*
cur
;
/* Create a new node */
node
=
purple_xmlnode_new_child
(
parent
,
"pref"
);
purple_xmlnode_set_attrib
(
node
,
"name"
,
pref
->
name
);
/* Set the type of this node (if type == PURPLE_PREF_NONE then do nothing) */
if
(
pref
->
type
==
PURPLE_PREF_INT
)
{
purple_xmlnode_set_attrib
(
node
,
"type"
,
"int"
);
g_snprintf
(
buf
,
sizeof
(
buf
),
"%d"
,
pref
->
value
.
integer
);
purple_xmlnode_set_attrib
(
node
,
"value"
,
buf
);
}
else
if
(
pref
->
type
==
PURPLE_PREF_STRING
)
{
purple_xmlnode_set_attrib
(
node
,
"type"
,
"string"
);
purple_xmlnode_set_attrib
(
node
,
"value"
,
pref
->
value
.
string
?
pref
->
value
.
string
:
""
);
}
else
if
(
pref
->
type
==
PURPLE_PREF_STRING_LIST
)
{
purple_xmlnode_set_attrib
(
node
,
"type"
,
"stringlist"
);
for
(
cur
=
pref
->
value
.
stringlist
;
cur
!=
NULL
;
cur
=
cur
->
next
)
{
childnode
=
purple_xmlnode_new_child
(
node
,
"item"
);
purple_xmlnode_set_attrib
(
childnode
,
"value"
,
cur
->
data
?
cur
->
data
:
""
);
}
}
else
if
(
pref
->
type
==
PURPLE_PREF_PATH
)
{
char
*
encoded
=
g_filename_to_utf8
(
pref
->
value
.
string
?
pref
->
value
.
string
:
""
,
-1
,
NULL
,
NULL
,
NULL
);
purple_xmlnode_set_attrib
(
node
,
"type"
,
"path"
);
purple_xmlnode_set_attrib
(
node
,
"value"
,
encoded
);
g_free
(
encoded
);
}
else
if
(
pref
->
type
==
PURPLE_PREF_PATH_LIST
)
{
purple_xmlnode_set_attrib
(
node
,
"type"
,
"pathlist"
);
for
(
cur
=
pref
->
value
.
stringlist
;
cur
!=
NULL
;
cur
=
cur
->
next
)
{
char
*
encoded
=
g_filename_to_utf8
(
cur
->
data
?
cur
->
data
:
""
,
-1
,
NULL
,
NULL
,
NULL
);
childnode
=
purple_xmlnode_new_child
(
node
,
"item"
);
purple_xmlnode_set_attrib
(
childnode
,
"value"
,
encoded
);
g_free
(
encoded
);
}
}
else
if
(
pref
->
type
==
PURPLE_PREF_BOOLEAN
)
{
purple_xmlnode_set_attrib
(
node
,
"type"
,
"bool"
);
g_snprintf
(
buf
,
sizeof
(
buf
),
"%d"
,
pref
->
value
.
boolean
);
purple_xmlnode_set_attrib
(
node
,
"value"
,
buf
);
}
/* All My Children */
for
(
child
=
pref
->
first_child
;
child
!=
NULL
;
child
=
child
->
sibling
)
pref_to_xmlnode
(
node
,
child
);
}
static
PurpleXmlNode
*
prefs_to_xmlnode
(
void
)
{
PurpleXmlNode
*
node
;
struct
purple_pref
*
pref
,
*
child
;
pref
=
&
prefs
;
/* Create the root preference node */
node
=
purple_xmlnode_new
(
"pref"
);
purple_xmlnode_set_attrib
(
node
,
"version"
,
"1"
);
purple_xmlnode_set_attrib
(
node
,
"name"
,
"/"
);
/* All My Children */
for
(
child
=
pref
->
first_child
;
child
!=
NULL
;
child
=
child
->
sibling
)
pref_to_xmlnode
(
node
,
child
);
return
node
;
}
static
void
sync_prefs
(
void
)
{
PurpleXmlNode
*
node
;
char
*
data
;
if
(
!
prefs_loaded
)
{
/*
* TODO: Call schedule_prefs_save()? Ideally we wouldn't need to.
* (prefs.xml should be loaded when purple_prefs_init is called)
*/
purple_debug_error
(
"prefs"
,
"Attempted to save prefs before "
"they were read!
\n
"
);
return
;
}
node
=
prefs_to_xmlnode
();
data
=
purple_xmlnode_to_formatted_str
(
node
,
NULL
);
purple_util_write_data_to_config_file
(
"prefs.xml"
,
data
,
-1
);
g_free
(
data
);
purple_xmlnode_free
(
node
);
}
static
gboolean
save_cb
(
G_GNUC_UNUSED
gpointer
data
)
{
sync_prefs
();
save_timer
=
0
;
return
FALSE
;
}
static
void
schedule_prefs_save
(
void
)
{
if
(
save_timer
==
0
)
save_timer
=
g_timeout_add_seconds
(
5
,
save_cb
,
NULL
);
}
/*********************************************************************
* Reading from disk *
*********************************************************************/
static
GList
*
prefs_stack
=
NULL
;
static
void
prefs_start_element_handler
(
G_GNUC_UNUSED
GMarkupParseContext
*
context
,
const
char
*
element_name
,
const
char
**
attribute_names
,
const
char
**
attribute_values
,
G_GNUC_UNUSED
gpointer
user_data
,
G_GNUC_UNUSED
GError
**
error
)
{
PurplePrefType
pref_type
=
PURPLE_PREF_NONE
;
int
i
;
const
char
*
pref_name
=
NULL
,
*
pref_value
=
NULL
;
GString
*
pref_name_full
;
GList
*
tmp
;
if
(
!
purple_strequal
(
element_name
,
"pref"
)
&&
!
purple_strequal
(
element_name
,
"item"
))
return
;
for
(
i
=
0
;
attribute_names
[
i
];
i
++
)
{
if
(
purple_strequal
(
attribute_names
[
i
],
"name"
))
{
pref_name
=
attribute_values
[
i
];
}
else
if
(
purple_strequal
(
attribute_names
[
i
],
"type"
))
{
if
(
purple_strequal
(
attribute_values
[
i
],
"bool"
))
pref_type
=
PURPLE_PREF_BOOLEAN
;
else
if
(
purple_strequal
(
attribute_values
[
i
],
"int"
))
pref_type
=
PURPLE_PREF_INT
;
else
if
(
purple_strequal
(
attribute_values
[
i
],
"string"
))
pref_type
=
PURPLE_PREF_STRING
;
else
if
(
purple_strequal
(
attribute_values
[
i
],
"stringlist"
))
pref_type
=
PURPLE_PREF_STRING_LIST
;
else
if
(
purple_strequal
(
attribute_values
[
i
],
"path"
))
pref_type
=
PURPLE_PREF_PATH
;
else
if
(
purple_strequal
(
attribute_values
[
i
],
"pathlist"
))
pref_type
=
PURPLE_PREF_PATH_LIST
;
else
return
;
}
else
if
(
purple_strequal
(
attribute_names
[
i
],
"value"
))
{
pref_value
=
attribute_values
[
i
];
}
}
if
((
pref_type
==
PURPLE_PREF_BOOLEAN
||
pref_type
==
PURPLE_PREF_INT
)
&&
pref_value
==
NULL
)
{
/* Missing a value attribute */
return
;
}
if
(
purple_strequal
(
element_name
,
"item"
))
{
struct
purple_pref
*
pref
;
pref_name_full
=
g_string_new
(
""
);
for
(
tmp
=
prefs_stack
;
tmp
;
tmp
=
tmp
->
next
)
{
pref_name_full
=
g_string_prepend
(
pref_name_full
,
tmp
->
data
);
pref_name_full
=
g_string_prepend_c
(
pref_name_full
,
'/'
);
}
pref
=
find_pref
(
pref_name_full
->
str
);
if
(
pref
)
{
if
(
pref
->
type
==
PURPLE_PREF_STRING_LIST
)
{
pref
->
value
.
stringlist
=
g_list_append
(
pref
->
value
.
stringlist
,
g_strdup
(
pref_value
));
}
else
if
(
pref
->
type
==
PURPLE_PREF_PATH_LIST
)
{
pref
->
value
.
stringlist
=
g_list_append
(
pref
->
value
.
stringlist
,
g_filename_from_utf8
(
pref_value
,
-1
,
NULL
,
NULL
,
NULL
));
}
}
g_string_free
(
pref_name_full
,
TRUE
);
}
else
{
char
*
decoded
;
if
(
!
pref_name
||
purple_strequal
(
pref_name
,
"/"
))
return
;
pref_name_full
=
g_string_new
(
pref_name
);
for
(
tmp
=
prefs_stack
;
tmp
;
tmp
=
tmp
->
next
)
{
pref_name_full
=
g_string_prepend_c
(
pref_name_full
,
'/'
);
pref_name_full
=
g_string_prepend
(
pref_name_full
,
tmp
->
data
);
}
pref_name_full
=
g_string_prepend_c
(
pref_name_full
,
'/'
);
switch
(
pref_type
)
{
case
PURPLE_PREF_NONE
:
purple_prefs_add_none
(
pref_name_full
->
str
);
break
;
case
PURPLE_PREF_BOOLEAN
:
purple_prefs_set_bool
(
pref_name_full
->
str
,
atoi
(
pref_value
));
break
;
case
PURPLE_PREF_INT
:
purple_prefs_set_int
(
pref_name_full
->
str
,
atoi
(
pref_value
));
break
;
case
PURPLE_PREF_STRING
:
purple_prefs_set_string
(
pref_name_full
->
str
,
pref_value
);
break
;
case
PURPLE_PREF_STRING_LIST
:
purple_prefs_set_string_list
(
pref_name_full
->
str
,
NULL
);
break
;
case
PURPLE_PREF_PATH
:
if
(
pref_value
)
{
decoded
=
g_filename_from_utf8
(
pref_value
,
-1
,
NULL
,
NULL
,
NULL
);
purple_prefs_set_path
(
pref_name_full
->
str
,
decoded
);
g_free
(
decoded
);
}
else
{
purple_prefs_set_path
(
pref_name_full
->
str
,
NULL
);
}
break
;
case
PURPLE_PREF_PATH_LIST
:
purple_prefs_set_path_list
(
pref_name_full
->
str
,
NULL
);
break
;
}
prefs_stack
=
g_list_prepend
(
prefs_stack
,
g_strdup
(
pref_name
));
g_string_free
(
pref_name_full
,
TRUE
);
}
}
static
void
prefs_end_element_handler
(
G_GNUC_UNUSED
GMarkupParseContext
*
context
,
const
gchar
*
element_name
,
G_GNUC_UNUSED
gpointer
user_data
,
G_GNUC_UNUSED
GError
**
error
)
{
if
(
prefs_stack
&&
purple_strequal
(
element_name
,
"pref"
))
{
g_free
(
prefs_stack
->
data
);
prefs_stack
=
g_list_delete_link
(
prefs_stack
,
prefs_stack
);
}
}
static
GMarkupParser
prefs_parser
=
{
prefs_start_element_handler
,
prefs_end_element_handler
,
NULL
,
NULL
,
NULL
};
gboolean
purple_prefs_load
(
void
)
{
gchar
*
filename
;
gchar
*
contents
=
NULL
;
gsize
length
;
GMarkupParseContext
*
context
;
GError
*
error
=
NULL
;
filename
=
g_build_filename
(
purple_config_dir
(),
"prefs.xml"
,
NULL
);
if
(
!
filename
)
{
prefs_loaded
=
TRUE
;
return
FALSE
;
}
purple_debug_misc
(
"prefs"
,
"Reading %s"
,
filename
);
if
(
!
g_file_get_contents
(
filename
,
&
contents
,
&
length
,
&
error
))
{
const
gchar
*
sysconfdir
=
PURPLE_SYSCONFDIR
;
g_free
(
filename
);
g_clear_error
(
&
error
);
if
(
sysconfdir
==
NULL
)
sysconfdir
=
""
;
filename
=
g_build_filename
(
sysconfdir
,
"purple"
,
"prefs.xml"
,
NULL
);
purple_debug_info
(
"prefs"
,
"Reading %s
\n
"
,
filename
);
if
(
!
g_file_get_contents
(
filename
,
&
contents
,
&
length
,
&
error
))
{
purple_debug_info
(
"prefs"
,
"Error reading prefs: %s
\n
"
,
error
->
message
);
g_error_free
(
error
);
g_free
(
filename
);
prefs_loaded
=
TRUE
;
return
FALSE
;
}
}
context
=
g_markup_parse_context_new
(
&
prefs_parser
,
0
,
NULL
,
NULL
);
if
(
!
g_markup_parse_context_parse
(
context
,
contents
,
length
,
NULL
))
{
g_markup_parse_context_free
(
context
);
g_free
(
contents
);
g_free
(
filename
);
prefs_loaded
=
TRUE
;
return
FALSE
;
}
if
(
!
g_markup_parse_context_end_parse
(
context
,
NULL
))
{
purple_debug_error
(
"prefs"
,
"Error parsing %s
\n
"
,
filename
);
g_markup_parse_context_free
(
context
);
g_free
(
contents
);
g_free
(
filename
);
prefs_loaded
=
TRUE
;
return
FALSE
;
}
if
(
purple_debug_is_verbose
())
purple_debug_misc
(
"prefs"
,
"Finished reading %s"
,
filename
);
g_markup_parse_context_free
(
context
);
g_free
(
contents
);
g_free
(
filename
);
prefs_loaded
=
TRUE
;
return
TRUE
;
}
static
void
prefs_save_cb
(
const
char
*
name
,
G_GNUC_UNUSED
PurplePrefType
type
,
G_GNUC_UNUSED
gconstpointer
val
,
G_GNUC_UNUSED
gpointer
user_data
)
{
if
(
!
prefs_loaded
)
return
;
purple_debug_misc
(
"prefs"
,
"%s changed, scheduling save.
\n
"
,
name
);
schedule_prefs_save
();
}
static
char
*
get_path_dirname
(
const
char
*
name
)
{
char
*
c
,
*
str
;
str
=
g_strdup
(
name
);
if
((
c
=
strrchr
(
str
,
'/'
))
!=
NULL
)
{
*
c
=
'\0'
;
if
(
*
str
==
'\0'
)
{
g_free
(
str
);
str
=
g_strdup
(
"/"
);
}
}
else
{
g_free
(
str
);
str
=
g_strdup
(
"."
);
}
return
str
;
}
static
char
*
get_path_basename
(
const
char
*
name
)
{
const
char
*
c
;
if
((
c
=
strrchr
(
name
,
'/'
))
!=
NULL
)
return
g_strdup
(
c
+
1
);
return
g_strdup
(
name
);
}
static
char
*
pref_full_name
(
struct
purple_pref
*
pref
)
{
GString
*
name
;
struct
purple_pref
*
parent
;
if
(
!
pref
)
return
NULL
;
if
(
pref
==
&
prefs
)
return
g_strdup
(
"/"
);
name
=
g_string_new
(
pref
->
name
);
for
(
parent
=
pref
->
parent
;
parent
&&
parent
->
name
;
parent
=
parent
->
parent
)
{
name
=
g_string_prepend_c
(
name
,
'/'
);
name
=
g_string_prepend
(
name
,
parent
->
name
);
}
name
=
g_string_prepend_c
(
name
,
'/'
);
return
g_string_free
(
name
,
FALSE
);
}
static
struct
purple_pref
*
find_pref_parent
(
const
char
*
name
)
{
char
*
parent_name
=
get_path_dirname
(
name
);
struct
purple_pref
*
ret
=
&
prefs
;
if
(
!
purple_strequal
(
parent_name
,
"/"
))
{
ret
=
find_pref
(
parent_name
);
}
g_free
(
parent_name
);
return
ret
;
}
static
void
free_pref_value
(
struct
purple_pref
*
pref
)
{
switch
(
pref
->
type
)
{
case
PURPLE_PREF_BOOLEAN
:
pref
->
value
.
boolean
=
FALSE
;
break
;
case
PURPLE_PREF_INT
:
pref
->
value
.
integer
=
0
;
break
;
case
PURPLE_PREF_STRING
:
case
PURPLE_PREF_PATH
:
g_free
(
pref
->
value
.
string
);
pref
->
value
.
string
=
NULL
;
break
;
case
PURPLE_PREF_STRING_LIST
:
case
PURPLE_PREF_PATH_LIST
:
g_list_free_full
(
pref
->
value
.
stringlist
,
g_free
);
break
;
case
PURPLE_PREF_NONE
:
break
;
}
}
static
struct
purple_pref
*
add_pref
(
PurplePrefType
type
,
const
char
*
name
)
{
struct
purple_pref
*
parent
;
struct
purple_pref
*
me
;
struct
purple_pref
*
sibling
;
char
*
my_name
;
parent
=
find_pref_parent
(
name
);
g_return_val_if_fail
(
parent
,
NULL
);
my_name
=
get_path_basename
(
name
);
for
(
sibling
=
parent
->
first_child
;
sibling
;
sibling
=
sibling
->
sibling
)
{
if
(
purple_strequal
(
sibling
->
name
,
my_name
))
{
g_free
(
my_name
);
return
NULL
;
}
}
me
=
g_new0
(
struct
purple_pref
,
1
);
me
->
type
=
type
;
me
->
name
=
my_name
;
me
->
parent
=
parent
;
if
(
parent
->
first_child
)
{
/* blatant abuse of a for loop */
for
(
sibling
=
parent
->
first_child
;
sibling
->
sibling
;
sibling
=
sibling
->
sibling
);
sibling
->
sibling
=
me
;
}
else
{
parent
->
first_child
=
me
;
}
g_hash_table_insert
(
prefs_hash
,
g_strdup
(
name
),
(
gpointer
)
me
);
return
me
;
}
void
purple_prefs_add_none
(
const
char
*
name
)
{
add_pref
(
PURPLE_PREF_NONE
,
name
);
}
void
purple_prefs_add_bool
(
const
char
*
name
,
gboolean
value
)
{
struct
purple_pref
*
pref
;
pref
=
add_pref
(
PURPLE_PREF_BOOLEAN
,
name
);
if
(
!
pref
)
return
;
pref
->
value
.
boolean
=
value
;
}
void
purple_prefs_add_int
(
const
char
*
name
,
int
value
)
{
struct
purple_pref
*
pref
;
pref
=
add_pref
(
PURPLE_PREF_INT
,
name
);
if
(
!
pref
)
return
;
pref
->
value
.
integer
=
value
;
}
void
purple_prefs_add_string
(
const
char
*
name
,
const
char
*
value
)
{
struct
purple_pref
*
pref
;
if
(
value
!=
NULL
&&
!
g_utf8_validate
(
value
,
-1
,
NULL
))
{
purple_debug_error
(
"prefs"
,
"purple_prefs_add_string: Cannot store invalid UTF8 for string pref %s
\n
"
,
name
);
return
;
}
pref
=
add_pref
(
PURPLE_PREF_STRING
,
name
);
if
(
!
pref
)
return
;
pref
->
value
.
string
=
g_strdup
(
value
);
}
void
purple_prefs_add_string_list
(
const
char
*
name
,
GList
*
value
)
{
struct
purple_pref
*
pref
;
GList
*
tmp
;
pref
=
add_pref
(
PURPLE_PREF_STRING_LIST
,
name
);
if
(
!
pref
)
return
;
for
(
tmp
=
value
;
tmp
;
tmp
=
tmp
->
next
)
{
if
(
tmp
->
data
!=
NULL
&&
!
g_utf8_validate
(
tmp
->
data
,
-1
,
NULL
))
{
purple_debug_error
(
"prefs"
,
"purple_prefs_add_string_list: Skipping invalid UTF8 for string list pref %s
\n
"
,
name
);
continue
;
}
pref
->
value
.
stringlist
=
g_list_append
(
pref
->
value
.
stringlist
,
g_strdup
(
tmp
->
data
));
}
}
void
purple_prefs_add_path
(
const
char
*
name
,
const
char
*
value
)
{
struct
purple_pref
*
pref
;
pref
=
add_pref
(
PURPLE_PREF_PATH
,
name
);
if
(
!
pref
)
return
;
pref
->
value
.
string
=
g_strdup
(
value
);
}
void
purple_prefs_add_path_list
(
const
char
*
name
,
GList
*
value
)
{
struct
purple_pref
*
pref
;
GList
*
copy
=
NULL
;
pref
=
add_pref
(
PURPLE_PREF_PATH_LIST
,
name
);
if
(
!
pref
)
return
;
copy
=
g_list_copy_deep
(
value
,
(
GCopyFunc
)(
GCallback
)
g_strdup
,
NULL
);
pref
->
value
.
stringlist
=
g_list_concat
(
pref
->
value
.
stringlist
,
copy
);
}
static
void
free_pref
(
struct
purple_pref
*
pref
)
{
char
*
name
;
name
=
pref_full_name
(
pref
);
if
(
prefs_loaded
)
{
purple_debug_info
(
"prefs"
,
"removing pref %s
\n
"
,
name
);
}
g_hash_table_remove
(
prefs_hash
,
name
);
g_free
(
name
);
free_pref_value
(
pref
);
g_slist_free_full
(
pref
->
callbacks
,
g_free
);
g_free
(
pref
->
name
);
g_free
(
pref
);
}
static
void
remove_pref
(
struct
purple_pref
*
pref
)
{
struct
purple_pref
*
child
;
if
(
!
pref
)
{
return
;
}
child
=
pref
->
first_child
;
pref
->
first_child
=
NULL
;
while
(
child
)
{
struct
purple_pref
*
next
;
if
(
child
->
first_child
)
{
next
=
child
->
first_child
;
child
->
first_child
=
NULL
;
}
else
if
(
child
->
sibling
)
{
next
=
child
->
sibling
;
child
->
sibling
=
NULL
;
free_pref
(
child
);
}
else
{
if
(
child
->
parent
!=
pref
)
{
next
=
child
->
parent
;
}
else
{
next
=
NULL
;
}
free_pref
(
child
);
}
child
=
next
;
}
if
(
pref
==
&
prefs
)
{
return
;
}
if
(
pref
->
parent
->
first_child
==
pref
)
{
pref
->
parent
->
first_child
=
pref
->
sibling
;
}
else
{
child
=
pref
->
parent
->
first_child
;
while
(
child
&&
child
->
sibling
!=
pref
)
{
child
=
child
->
sibling
;
}
if
(
child
)
{
child
->
sibling
=
pref
->
sibling
;
}
}
free_pref
(
pref
);
}
void
purple_prefs_remove
(
const
char
*
name
)
{
struct
purple_pref
*
pref
;
pref
=
find_pref
(
name
);
if
(
!
pref
)
return
;
remove_pref
(
pref
);
}
void
purple_prefs_destroy
(
void
)
{
purple_prefs_remove
(
"/"
);
}
static
void
do_callbacks
(
const
char
*
name
,
struct
purple_pref
*
pref
)
{
GSList
*
cbs
;
struct
purple_pref
*
cb_pref
;
for
(
cb_pref
=
pref
;
cb_pref
;
cb_pref
=
cb_pref
->
parent
)
{
for
(
cbs
=
cb_pref
->
callbacks
;
cbs
;
cbs
=
cbs
->
next
)
{
PurplePrefCallbackData
*
cb
=
cbs
->
data
;
cb
->
func
(
name
,
pref
->
type
,
pref
->
value
.
generic
,
cb
->
data
);
}
}
}
void
purple_prefs_trigger_callback
(
const
char
*
name
)
{
struct
purple_pref
*
pref
;
pref
=
find_pref
(
name
);
if
(
!
pref
)
{
purple_debug_error
(
"prefs"
,
"purple_prefs_trigger_callback: Unknown pref %s
\n
"
,
name
);
return
;
}
do_callbacks
(
name
,
pref
);
}
/* this function is deprecated, so it doesn't get the new UI ops */
void
purple_prefs_set_bool
(
const
char
*
name
,
gboolean
value
)
{
struct
purple_pref
*
pref
;
pref
=
find_pref
(
name
);
if
(
pref
)
{
if
(
pref
->
type
!=
PURPLE_PREF_BOOLEAN
)
{
purple_debug_error
(
"prefs"
,
"purple_prefs_set_bool: %s not a boolean pref
\n
"
,
name
);
return
;
}
if
(
pref
->
value
.
boolean
!=
value
)
{
pref
->
value
.
boolean
=
value
;
do_callbacks
(
name
,
pref
);
}
}
else
{
purple_prefs_add_bool
(
name
,
value
);
}
}
void
purple_prefs_set_int
(
const
char
*
name
,
int
value
)
{
struct
purple_pref
*
pref
;
pref
=
find_pref
(
name
);
if
(
pref
)
{
if
(
pref
->
type
!=
PURPLE_PREF_INT
)
{
purple_debug_error
(
"prefs"
,
"purple_prefs_set_int: %s not an integer pref
\n
"
,
name
);
return
;
}
if
(
pref
->
value
.
integer
!=
value
)
{
pref
->
value
.
integer
=
value
;
do_callbacks
(
name
,
pref
);
}
}
else
{
purple_prefs_add_int
(
name
,
value
);
}
}
void
purple_prefs_set_string
(
const
char
*
name
,
const
char
*
value
)
{
struct
purple_pref
*
pref
;
if
(
value
!=
NULL
&&
!
g_utf8_validate
(
value
,
-1
,
NULL
))
{
purple_debug_error
(
"prefs"
,
"purple_prefs_set_string: Cannot store invalid UTF8 for string pref %s
\n
"
,
name
);
return
;
}
pref
=
find_pref
(
name
);
if
(
pref
)
{
if
(
pref
->
type
!=
PURPLE_PREF_STRING
&&
pref
->
type
!=
PURPLE_PREF_PATH
)
{
purple_debug_error
(
"prefs"
,
"purple_prefs_set_string: %s not a string pref
\n
"
,
name
);
return
;
}
if
(
!
purple_strequal
(
pref
->
value
.
string
,
value
))
{
g_free
(
pref
->
value
.
string
);
pref
->
value
.
string
=
g_strdup
(
value
);
do_callbacks
(
name
,
pref
);
}
}
else
{
purple_prefs_add_string
(
name
,
value
);
}
}
void
purple_prefs_set_string_list
(
const
char
*
name
,
GList
*
value
)
{
struct
purple_pref
*
pref
;
pref
=
find_pref
(
name
);
if
(
pref
)
{
GList
*
tmp
;
if
(
pref
->
type
!=
PURPLE_PREF_STRING_LIST
)
{
purple_debug_error
(
"prefs"
,
"purple_prefs_set_string_list: %s not a string list pref
\n
"
,
name
);
return
;
}
g_clear_list
(
&
pref
->
value
.
stringlist
,
g_free
);
for
(
tmp
=
value
;
tmp
;
tmp
=
tmp
->
next
)
{
if
(
tmp
->
data
!=
NULL
&&
!
g_utf8_validate
(
tmp
->
data
,
-1
,
NULL
))
{
purple_debug_error
(
"prefs"
,
"purple_prefs_set_string_list: Skipping invalid UTF8 for string list pref %s
\n
"
,
name
);
continue
;
}
pref
->
value
.
stringlist
=
g_list_prepend
(
pref
->
value
.
stringlist
,
g_strdup
(
tmp
->
data
));
}
pref
->
value
.
stringlist
=
g_list_reverse
(
pref
->
value
.
stringlist
);
do_callbacks
(
name
,
pref
);
}
else
{
purple_prefs_add_string_list
(
name
,
value
);
}
}
void
purple_prefs_set_path
(
const
char
*
name
,
const
char
*
value
)
{
struct
purple_pref
*
pref
;
pref
=
find_pref
(
name
);
if
(
pref
)
{
if
(
pref
->
type
!=
PURPLE_PREF_PATH
)
{
purple_debug_error
(
"prefs"
,
"purple_prefs_set_path: %s not a path pref
\n
"
,
name
);
return
;
}
if
(
!
purple_strequal
(
pref
->
value
.
string
,
value
))
{
g_free
(
pref
->
value
.
string
);
pref
->
value
.
string
=
g_strdup
(
value
);
do_callbacks
(
name
,
pref
);
}
}
else
{
purple_prefs_add_path
(
name
,
value
);
}
}
void
purple_prefs_set_path_list
(
const
char
*
name
,
GList
*
value
)
{
struct
purple_pref
*
pref
;
pref
=
find_pref
(
name
);
if
(
pref
)
{
if
(
pref
->
type
!=
PURPLE_PREF_PATH_LIST
)
{
purple_debug_error
(
"prefs"
,
"purple_prefs_set_path_list: %s not a path list pref
\n
"
,
name
);
return
;
}
g_list_free_full
(
pref
->
value
.
stringlist
,
g_free
);
pref
->
value
.
stringlist
=
g_list_copy_deep
(
value
,
(
GCopyFunc
)(
GCallback
)
g_strdup
,
NULL
);
do_callbacks
(
name
,
pref
);
}
else
{
purple_prefs_add_path_list
(
name
,
value
);
}
}
gboolean
purple_prefs_exists
(
const
char
*
name
)
{
struct
purple_pref
*
pref
;
pref
=
find_pref
(
name
);
if
(
pref
!=
NULL
)
return
TRUE
;
return
FALSE
;
}
PurplePrefType
purple_prefs_get_pref_type
(
const
char
*
name
)
{
struct
purple_pref
*
pref
;
pref
=
find_pref
(
name
);
if
(
pref
==
NULL
)
return
PURPLE_PREF_NONE
;
return
(
pref
->
type
);
}
gboolean
purple_prefs_get_bool
(
const
char
*
name
)
{
struct
purple_pref
*
pref
;
pref
=
find_pref
(
name
);
if
(
!
pref
)
{
purple_debug_error
(
"prefs"
,
"purple_prefs_get_bool: Unknown pref %s
\n
"
,
name
);
return
FALSE
;
}
else
if
(
pref
->
type
!=
PURPLE_PREF_BOOLEAN
)
{
purple_debug_error
(
"prefs"
,
"purple_prefs_get_bool: %s not a boolean pref
\n
"
,
name
);
return
FALSE
;
}
return
pref
->
value
.
boolean
;
}
int
purple_prefs_get_int
(
const
char
*
name
)
{
struct
purple_pref
*
pref
;
pref
=
find_pref
(
name
);
if
(
!
pref
)
{
purple_debug_error
(
"prefs"
,
"purple_prefs_get_int: Unknown pref %s
\n
"
,
name
);
return
0
;
}
else
if
(
pref
->
type
!=
PURPLE_PREF_INT
)
{
purple_debug_error
(
"prefs"
,
"purple_prefs_get_int: %s not an integer pref
\n
"
,
name
);
return
0
;
}
return
pref
->
value
.
integer
;
}
const
char
*
purple_prefs_get_string
(
const
char
*
name
)
{
struct
purple_pref
*
pref
;
pref
=
find_pref
(
name
);
if
(
!
pref
)
{
purple_debug_error
(
"prefs"
,
"purple_prefs_get_string: Unknown pref %s
\n
"
,
name
);
return
NULL
;
}
else
if
(
pref
->
type
!=
PURPLE_PREF_STRING
)
{
purple_debug_error
(
"prefs"
,
"purple_prefs_get_string: %s not a string pref
\n
"
,
name
);
return
NULL
;
}
return
pref
->
value
.
string
;
}
GList
*
purple_prefs_get_string_list
(
const
char
*
name
)
{
struct
purple_pref
*
pref
;
pref
=
find_pref
(
name
);
if
(
!
pref
)
{
purple_debug_error
(
"prefs"
,
"purple_prefs_get_string_list: Unknown pref %s
\n
"
,
name
);
return
NULL
;
}
else
if
(
pref
->
type
!=
PURPLE_PREF_STRING_LIST
)
{
purple_debug_error
(
"prefs"
,
"purple_prefs_get_string_list: %s not a string list pref
\n
"
,
name
);
return
NULL
;
}
return
g_list_copy_deep
(
pref
->
value
.
stringlist
,
(
GCopyFunc
)(
GCallback
)
g_strdup
,
NULL
);
}
const
char
*
purple_prefs_get_path
(
const
char
*
name
)
{
struct
purple_pref
*
pref
;
pref
=
find_pref
(
name
);
if
(
!
pref
)
{
purple_debug_error
(
"prefs"
,
"purple_prefs_get_path: Unknown pref %s
\n
"
,
name
);
return
NULL
;
}
else
if
(
pref
->
type
!=
PURPLE_PREF_PATH
)
{
purple_debug_error
(
"prefs"
,
"purple_prefs_get_path: %s not a path pref
\n
"
,
name
);
return
NULL
;
}
return
pref
->
value
.
string
;
}
GList
*
purple_prefs_get_path_list
(
const
char
*
name
)
{
struct
purple_pref
*
pref
;
pref
=
find_pref
(
name
);
if
(
!
pref
)
{
purple_debug_error
(
"prefs"
,
"purple_prefs_get_path_list: Unknown pref %s
\n
"
,
name
);
return
NULL
;
}
else
if
(
pref
->
type
!=
PURPLE_PREF_PATH_LIST
)
{
purple_debug_error
(
"prefs"
,
"purple_prefs_get_path_list: %s not a path list pref
\n
"
,
name
);
return
NULL
;
}
return
g_list_copy_deep
(
pref
->
value
.
stringlist
,
(
GCopyFunc
)(
GCallback
)
g_strdup
,
NULL
);
}
static
void
purple_prefs_rename_node
(
struct
purple_pref
*
oldpref
,
struct
purple_pref
*
newpref
)
{
struct
purple_pref
*
child
,
*
next
;
char
*
oldname
,
*
newname
;
/* if we're a parent, rename the kids first */
for
(
child
=
oldpref
->
first_child
;
child
!=
NULL
;
child
=
next
)
{
struct
purple_pref
*
newchild
;
next
=
child
->
sibling
;
for
(
newchild
=
newpref
->
first_child
;
newchild
!=
NULL
;
newchild
=
newchild
->
sibling
)
{
if
(
purple_strequal
(
child
->
name
,
newchild
->
name
))
{
purple_prefs_rename_node
(
child
,
newchild
);
break
;
}
}
if
(
newchild
==
NULL
)
{
/* no rename happened, we weren't able to find the new pref */
char
*
tmpname
=
pref_full_name
(
child
);
purple_debug_error
(
"prefs"
,
"Unable to find rename pref for %s
\n
"
,
tmpname
);
g_free
(
tmpname
);
}
}
oldname
=
pref_full_name
(
oldpref
);
newname
=
pref_full_name
(
newpref
);
if
(
oldpref
->
type
!=
newpref
->
type
)
{
purple_debug_error
(
"prefs"
,
"Unable to rename %s to %s: differing types
\n
"
,
oldname
,
newname
);
g_free
(
oldname
);
g_free
(
newname
);
return
;
}
purple_debug_info
(
"prefs"
,
"Renaming %s to %s
\n
"
,
oldname
,
newname
);
g_free
(
oldname
);
switch
(
oldpref
->
type
)
{
case
PURPLE_PREF_NONE
:
break
;
case
PURPLE_PREF_BOOLEAN
:
purple_prefs_set_bool
(
newname
,
oldpref
->
value
.
boolean
);
break
;
case
PURPLE_PREF_INT
:
purple_prefs_set_int
(
newname
,
oldpref
->
value
.
integer
);
break
;
case
PURPLE_PREF_STRING
:
purple_prefs_set_string
(
newname
,
oldpref
->
value
.
string
);
break
;
case
PURPLE_PREF_STRING_LIST
:
purple_prefs_set_string_list
(
newname
,
oldpref
->
value
.
stringlist
);
break
;
case
PURPLE_PREF_PATH
:
purple_prefs_set_path
(
newname
,
oldpref
->
value
.
string
);
break
;
case
PURPLE_PREF_PATH_LIST
:
purple_prefs_set_path_list
(
newname
,
oldpref
->
value
.
stringlist
);
break
;
}
g_free
(
newname
);
remove_pref
(
oldpref
);
}
void
purple_prefs_rename
(
const
char
*
oldname
,
const
char
*
newname
)
{
struct
purple_pref
*
oldpref
,
*
newpref
;
oldpref
=
find_pref
(
oldname
);
/* it's already been renamed, call off the dogs */
if
(
!
oldpref
)
return
;
newpref
=
find_pref
(
newname
);
if
(
newpref
==
NULL
)
{
purple_debug_error
(
"prefs"
,
"Unable to rename %s to %s: new pref not created
\n
"
,
oldname
,
newname
);
return
;
}
purple_prefs_rename_node
(
oldpref
,
newpref
);
}
void
purple_prefs_rename_boolean_toggle
(
const
char
*
oldname
,
const
char
*
newname
)
{
struct
purple_pref
*
oldpref
,
*
newpref
;
oldpref
=
find_pref
(
oldname
);
/* it's already been renamed, call off the cats */
if
(
!
oldpref
)
return
;
if
(
oldpref
->
type
!=
PURPLE_PREF_BOOLEAN
)
{
purple_debug_error
(
"prefs"
,
"Unable to rename %s to %s: old pref not a boolean
\n
"
,
oldname
,
newname
);
return
;
}
if
(
oldpref
->
first_child
!=
NULL
)
/* can't rename parents */
{
purple_debug_error
(
"prefs"
,
"Unable to rename %s to %s: can't rename parents
\n
"
,
oldname
,
newname
);
return
;
}
newpref
=
find_pref
(
newname
);
if
(
newpref
==
NULL
)
{
purple_debug_error
(
"prefs"
,
"Unable to rename %s to %s: new pref not created
\n
"
,
oldname
,
newname
);
return
;
}
if
(
oldpref
->
type
!=
newpref
->
type
)
{
purple_debug_error
(
"prefs"
,
"Unable to rename %s to %s: differing types
\n
"
,
oldname
,
newname
);
return
;
}
purple_debug_info
(
"prefs"
,
"Renaming and toggling %s to %s
\n
"
,
oldname
,
newname
);
purple_prefs_set_bool
(
newname
,
!
(
oldpref
->
value
.
boolean
));
remove_pref
(
oldpref
);
}
guint
purple_prefs_connect_callback
(
void
*
handle
,
const
char
*
name
,
PurplePrefCallback
func
,
gpointer
data
)
{
struct
purple_pref
*
pref
=
NULL
;
PurplePrefCallbackData
*
cb
;
static
guint
cb_id
=
0
;
g_return_val_if_fail
(
name
!=
NULL
,
0
);
g_return_val_if_fail
(
func
!=
NULL
,
0
);
pref
=
find_pref
(
name
);
if
(
pref
==
NULL
)
{
purple_debug_error
(
"prefs"
,
"purple_prefs_connect_callback: Unknown pref %s
\n
"
,
name
);
return
0
;
}
cb
=
g_new0
(
PurplePrefCallbackData
,
1
);
cb
->
func
=
func
;
cb
->
data
=
data
;
cb
->
id
=
++
cb_id
;
cb
->
handle
=
handle
;
cb
->
name
=
g_strdup
(
name
);
pref
->
callbacks
=
g_slist_append
(
pref
->
callbacks
,
cb
);
return
cb
->
id
;
}
void
purple_prefs_trigger_callback_object
(
PurplePrefCallbackData
*
cb
)
{
purple_prefs_trigger_callback
(
cb
->
name
);
}
static
gboolean
disco_callback_helper
(
struct
purple_pref
*
pref
,
guint
callback_id
)
{
GSList
*
cbs
;
struct
purple_pref
*
child
;
if
(
!
pref
)
return
FALSE
;
for
(
cbs
=
pref
->
callbacks
;
cbs
;
cbs
=
cbs
->
next
)
{
PurplePrefCallbackData
*
cb
=
cbs
->
data
;
if
(
cb
->
id
==
callback_id
)
{
pref
->
callbacks
=
g_slist_delete_link
(
pref
->
callbacks
,
cbs
);
g_free
(
cb
->
name
);
g_free
(
cb
);
return
TRUE
;
}
}
for
(
child
=
pref
->
first_child
;
child
;
child
=
child
->
sibling
)
{
if
(
disco_callback_helper
(
child
,
callback_id
))
return
TRUE
;
}
return
FALSE
;
}
void
purple_prefs_disconnect_callback
(
guint
callback_id
)
{
disco_callback_helper
(
&
prefs
,
callback_id
);
}
static
void
disco_callback_helper_handle
(
struct
purple_pref
*
pref
,
void
*
handle
)
{
GSList
*
cbs
;
struct
purple_pref
*
child
;
if
(
!
pref
)
return
;
cbs
=
pref
->
callbacks
;
while
(
cbs
!=
NULL
)
{
PurplePrefCallbackData
*
cb
=
cbs
->
data
;
if
(
cb
->
handle
==
handle
)
{
pref
->
callbacks
=
g_slist_delete_link
(
pref
->
callbacks
,
cbs
);
g_free
(
cb
->
name
);
g_free
(
cb
);
cbs
=
pref
->
callbacks
;
}
else
cbs
=
cbs
->
next
;
}
for
(
child
=
pref
->
first_child
;
child
;
child
=
child
->
sibling
)
disco_callback_helper_handle
(
child
,
handle
);
}
void
purple_prefs_disconnect_by_handle
(
void
*
handle
)
{
g_return_if_fail
(
handle
!=
NULL
);
disco_callback_helper_handle
(
&
prefs
,
handle
);
}
GList
*
purple_prefs_get_children_names
(
const
char
*
name
)
{
GList
*
list
=
NULL
;
struct
purple_pref
*
pref
,
*
child
;
char
sep
[
2
]
=
"
\0\0
"
;;
pref
=
find_pref
(
name
);
if
(
pref
==
NULL
)
return
NULL
;
if
(
name
[
strlen
(
name
)
-
1
]
!=
'/'
)
sep
[
0
]
=
'/'
;
for
(
child
=
pref
->
first_child
;
child
;
child
=
child
->
sibling
)
{
list
=
g_list_append
(
list
,
g_strdup_printf
(
"%s%s%s"
,
name
,
sep
,
child
->
name
));
}
return
list
;
}
static
void
prefs_update_old
(
void
)
{
purple_prefs_rename
(
"/core"
,
"/purple"
);
/* Remove some no-longer-used prefs */
purple_prefs_remove
(
"/purple/away/auto_response/enabled"
);
purple_prefs_remove
(
"/purple/away/auto_response/idle_only"
);
purple_prefs_remove
(
"/purple/away/auto_response/in_active_conv"
);
purple_prefs_remove
(
"/purple/away/auto_response/sec_before_resend"
);
purple_prefs_remove
(
"/purple/away/auto_response"
);
purple_prefs_remove
(
"/purple/away/default_message"
);
purple_prefs_remove
(
"/purple/buddies/use_server_alias"
);
purple_prefs_remove
(
"/purple/conversations/away_back_on_send"
);
purple_prefs_remove
(
"/purple/conversations/send_urls_as_links"
);
purple_prefs_remove
(
"/purple/conversations/im/show_login"
);
purple_prefs_remove
(
"/purple/conversations/chat/show_join"
);
purple_prefs_remove
(
"/purple/conversations/chat/show_leave"
);
purple_prefs_remove
(
"/purple/conversations/combine_chat_im"
);
purple_prefs_remove
(
"/purple/conversations/use_alias_for_title"
);
purple_prefs_remove
(
"/purple/debug/timestamps"
);
purple_prefs_remove
(
"/purple/logging/log_signon_signoff"
);
purple_prefs_remove
(
"/purple/logging/log_idle_state"
);
purple_prefs_remove
(
"/purple/logging/log_away_state"
);
purple_prefs_remove
(
"/purple/logging/log_own_states"
);
purple_prefs_remove
(
"/purple/sound/while_away"
);
purple_prefs_remove
(
"/purple/sound/while_status"
);
purple_prefs_remove
(
"/purple/sound"
);
purple_prefs_remove
(
"/purple/status/scores/hidden"
);
purple_prefs_remove
(
"/plugins/core/autorecon/hide_connected_error"
);
purple_prefs_remove
(
"/plugins/core/autorecon/hide_connecting_error"
);
purple_prefs_remove
(
"/plugins/core/autorecon/hide_reconnecting_dialog"
);
purple_prefs_remove
(
"/plugins/core/autorecon/restore_state"
);
purple_prefs_remove
(
"/plugins/core/autorecon"
);
purple_prefs_remove
(
"/plugins/lopl"
);
}
void
*
purple_prefs_get_handle
(
void
)
{
static
int
handle
;
return
&
handle
;
}
void
purple_prefs_init
(
void
)
{
void
*
handle
=
purple_prefs_get_handle
();
prefs_hash
=
g_hash_table_new_full
(
g_str_hash
,
g_str_equal
,
g_free
,
NULL
);
purple_prefs_connect_callback
(
handle
,
"/"
,
prefs_save_cb
,
NULL
);
purple_prefs_add_none
(
"/purple"
);
purple_prefs_add_none
(
"/plugins"
);
purple_prefs_add_none
(
"/plugins/core"
);
purple_prefs_add_none
(
"/plugins/prpl"
);
/* Away */
purple_prefs_add_none
(
"/purple/away"
);
purple_prefs_add_string
(
"/purple/away/idle_reporting"
,
"system"
);
purple_prefs_add_bool
(
"/purple/away/away_when_idle"
,
TRUE
);
purple_prefs_add_int
(
"/purple/away/mins_before_away"
,
5
);
/* Buddies */
purple_prefs_add_none
(
"/purple/buddies"
);
/* Contact Priority Settings */
purple_prefs_add_none
(
"/purple/contact"
);
purple_prefs_add_bool
(
"/purple/contact/last_match"
,
FALSE
);
purple_prefs_remove
(
"/purple/contact/offline_score"
);
purple_prefs_remove
(
"/purple/contact/away_score"
);
purple_prefs_remove
(
"/purple/contact/idle_score"
);
purple_prefs_load
();
prefs_update_old
();
}
void
purple_prefs_uninit
(
void
)
{
if
(
save_timer
!=
0
)
{
g_clear_handle_id
(
&
save_timer
,
g_source_remove
);
save_cb
(
NULL
);
}
purple_prefs_disconnect_by_handle
(
purple_prefs_get_handle
());
prefs_loaded
=
FALSE
;
purple_prefs_destroy
();
g_clear_pointer
(
&
prefs_hash
,
g_hash_table_destroy
);
}