pidgin/pidgin
Clone
Summary
Browse
Changes
Graph
Update the C plugin tutorial to use the gplugin macros
2021-06-07, Gary Kramlich
60f4b2a6d66a
Update the C plugin tutorial to use the gplugin macros
Testing Done:
Built and reviewed the docs.
Reviewed at https://reviews.imfreedom.org/r/686/
/* 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/gi18n-lib.h>
#include
"internal.h"
#include
"accounts.h"
#include
"core.h"
#include
"debug.h"
#include
"enums.h"
#include
"network.h"
#include
"purplecredentialmanager.h"
#include
"purpleprivate.h"
static
PurpleAccountUiOps
*
account_ui_ops
=
NULL
;
static
GList
*
accounts
=
NULL
;
static
guint
save_timer
=
0
;
static
gboolean
accounts_loaded
=
FALSE
;
static
void
purple_accounts_network_changed_cb
(
GNetworkMonitor
*
m
,
gboolean
available
,
gpointer
data
)
{
if
(
available
)
{
purple_accounts_restore_current_statuses
();
}
}
/*********************************************************************
* Writing to disk *
*********************************************************************/
static
PurpleXmlNode
*
accounts_to_xmlnode
(
void
)
{
PurpleXmlNode
*
node
,
*
child
;
GList
*
cur
;
node
=
purple_xmlnode_new
(
"account"
);
purple_xmlnode_set_attrib
(
node
,
"version"
,
"1.0"
);
for
(
cur
=
purple_accounts_get_all
();
cur
!=
NULL
;
cur
=
cur
->
next
)
{
child
=
_purple_account_to_xmlnode
(
cur
->
data
);
purple_xmlnode_insert_child
(
node
,
child
);
}
return
node
;
}
static
void
sync_accounts
(
void
)
{
PurpleXmlNode
*
node
;
char
*
data
;
if
(
!
accounts_loaded
)
{
purple_debug_error
(
"accounts"
,
"Attempted to save accounts before "
"they were read!
\n
"
);
return
;
}
node
=
accounts_to_xmlnode
();
data
=
purple_xmlnode_to_formatted_str
(
node
,
NULL
);
purple_util_write_data_to_config_file
(
"accounts.xml"
,
data
,
-1
);
g_free
(
data
);
purple_xmlnode_free
(
node
);
}
static
gboolean
save_cb
(
gpointer
data
)
{
sync_accounts
();
save_timer
=
0
;
return
FALSE
;
}
void
purple_accounts_schedule_save
(
void
)
{
if
(
save_timer
==
0
)
save_timer
=
g_timeout_add_seconds
(
5
,
save_cb
,
NULL
);
}
static
void
migrate_xmpp_encryption
(
PurpleAccount
*
account
)
{
/* When this is removed, nuke the "old_ssl" and "require_tls" settings */
if
(
g_str_equal
(
purple_account_get_protocol_id
(
account
),
"prpl-jabber"
))
{
const
char
*
sec
=
purple_account_get_string
(
account
,
"connection_security"
,
""
);
if
(
g_str_equal
(
""
,
sec
))
{
const
char
*
val
=
"require_tls"
;
if
(
purple_account_get_bool
(
account
,
"old_ssl"
,
FALSE
))
val
=
"old_ssl"
;
else
if
(
!
purple_account_get_bool
(
account
,
"require_tls"
,
TRUE
))
val
=
"opportunistic_tls"
;
purple_account_set_string
(
account
,
"connection_security"
,
val
);
}
}
}
static
void
parse_settings
(
PurpleXmlNode
*
node
,
PurpleAccount
*
account
)
{
const
char
*
ui
;
PurpleXmlNode
*
child
;
/* Get the UI string, if these are UI settings */
ui
=
purple_xmlnode_get_attrib
(
node
,
"ui"
);
/* Read settings, one by one */
for
(
child
=
purple_xmlnode_get_child
(
node
,
"setting"
);
child
!=
NULL
;
child
=
purple_xmlnode_get_next_twin
(
child
))
{
const
char
*
name
,
*
str_type
;
PurplePrefType
type
;
char
*
data
;
name
=
purple_xmlnode_get_attrib
(
child
,
"name"
);
if
(
name
==
NULL
)
/* Ignore this setting */
continue
;
str_type
=
purple_xmlnode_get_attrib
(
child
,
"type"
);
if
(
str_type
==
NULL
)
/* Ignore this setting */
continue
;
if
(
purple_strequal
(
str_type
,
"string"
))
type
=
PURPLE_PREF_STRING
;
else
if
(
purple_strequal
(
str_type
,
"int"
))
type
=
PURPLE_PREF_INT
;
else
if
(
purple_strequal
(
str_type
,
"bool"
))
type
=
PURPLE_PREF_BOOLEAN
;
else
/* Ignore this setting */
continue
;
data
=
purple_xmlnode_get_data
(
child
);
if
(
data
==
NULL
)
/* Ignore this setting */
continue
;
if
(
ui
==
NULL
)
{
if
(
type
==
PURPLE_PREF_STRING
)
purple_account_set_string
(
account
,
name
,
data
);
else
if
(
type
==
PURPLE_PREF_INT
)
purple_account_set_int
(
account
,
name
,
atoi
(
data
));
else
if
(
type
==
PURPLE_PREF_BOOLEAN
)
purple_account_set_bool
(
account
,
name
,
(
*
data
==
'0'
?
FALSE
:
TRUE
));
}
else
{
if
(
type
==
PURPLE_PREF_STRING
)
purple_account_set_ui_string
(
account
,
ui
,
name
,
data
);
else
if
(
type
==
PURPLE_PREF_INT
)
purple_account_set_ui_int
(
account
,
ui
,
name
,
atoi
(
data
));
else
if
(
type
==
PURPLE_PREF_BOOLEAN
)
purple_account_set_ui_bool
(
account
,
ui
,
name
,
(
*
data
==
'0'
?
FALSE
:
TRUE
));
}
g_free
(
data
);
}
/* we do this here because we need to do it before the user views the
* Edit Account dialog. */
migrate_xmpp_encryption
(
account
);
}
static
GHashTable
*
parse_status_attrs
(
PurpleXmlNode
*
node
,
PurpleStatus
*
status
)
{
GHashTable
*
attrs
=
g_hash_table_new
(
g_str_hash
,
g_str_equal
);
PurpleXmlNode
*
child
;
GValue
*
attr_value
;
for
(
child
=
purple_xmlnode_get_child
(
node
,
"attribute"
);
child
!=
NULL
;
child
=
purple_xmlnode_get_next_twin
(
child
))
{
const
char
*
id
=
purple_xmlnode_get_attrib
(
child
,
"id"
);
const
char
*
value
=
purple_xmlnode_get_attrib
(
child
,
"value"
);
if
(
!
id
||
!*
id
||
!
value
||
!*
value
)
continue
;
attr_value
=
purple_status_get_attr_value
(
status
,
id
);
if
(
!
attr_value
)
continue
;
switch
(
G_VALUE_TYPE
(
attr_value
))
{
case
G_TYPE_STRING
:
g_hash_table_insert
(
attrs
,
(
char
*
)
id
,
(
char
*
)
value
);
break
;
case
G_TYPE_INT
:
case
G_TYPE_BOOLEAN
:
{
int
v
;
if
(
sscanf
(
value
,
"%d"
,
&
v
)
==
1
)
{
g_hash_table_insert
(
attrs
,
(
char
*
)
id
,
GINT_TO_POINTER
(
v
));
}
break
;
}
default
:
break
;
}
}
return
attrs
;
}
static
void
parse_status
(
PurpleXmlNode
*
node
,
PurpleAccount
*
account
)
{
gboolean
active
=
FALSE
;
const
char
*
data
;
const
char
*
type
;
PurpleXmlNode
*
child
;
GHashTable
*
attrs
=
NULL
;
/* Get the active/inactive state */
data
=
purple_xmlnode_get_attrib
(
node
,
"active"
);
if
(
data
==
NULL
)
return
;
if
(
g_ascii_strcasecmp
(
data
,
"true"
)
==
0
)
active
=
TRUE
;
else
if
(
g_ascii_strcasecmp
(
data
,
"false"
)
==
0
)
active
=
FALSE
;
else
return
;
/* Get the type of the status */
type
=
purple_xmlnode_get_attrib
(
node
,
"type"
);
if
(
type
==
NULL
)
return
;
/* Read attributes into a GList */
child
=
purple_xmlnode_get_child
(
node
,
"attributes"
);
if
(
child
!=
NULL
)
{
attrs
=
parse_status_attrs
(
child
,
purple_account_get_status
(
account
,
type
));
}
purple_account_set_status_attrs
(
account
,
type
,
active
,
attrs
);
g_hash_table_destroy
(
attrs
);
}
static
void
parse_statuses
(
PurpleXmlNode
*
node
,
PurpleAccount
*
account
)
{
PurpleXmlNode
*
child
;
for
(
child
=
purple_xmlnode_get_child
(
node
,
"status"
);
child
!=
NULL
;
child
=
purple_xmlnode_get_next_twin
(
child
))
{
parse_status
(
child
,
account
);
}
}
static
void
parse_proxy_info
(
PurpleXmlNode
*
node
,
PurpleAccount
*
account
)
{
PurpleProxyInfo
*
proxy_info
;
PurpleXmlNode
*
child
;
char
*
data
;
proxy_info
=
purple_proxy_info_new
();
/* Use the global proxy settings, by default */
purple_proxy_info_set_proxy_type
(
proxy_info
,
PURPLE_PROXY_USE_GLOBAL
);
/* Read proxy type */
child
=
purple_xmlnode_get_child
(
node
,
"type"
);
if
((
child
!=
NULL
)
&&
((
data
=
purple_xmlnode_get_data
(
child
))
!=
NULL
))
{
if
(
purple_strequal
(
data
,
"global"
))
purple_proxy_info_set_proxy_type
(
proxy_info
,
PURPLE_PROXY_USE_GLOBAL
);
else
if
(
purple_strequal
(
data
,
"none"
))
purple_proxy_info_set_proxy_type
(
proxy_info
,
PURPLE_PROXY_NONE
);
else
if
(
purple_strequal
(
data
,
"http"
))
purple_proxy_info_set_proxy_type
(
proxy_info
,
PURPLE_PROXY_HTTP
);
else
if
(
purple_strequal
(
data
,
"socks4"
))
purple_proxy_info_set_proxy_type
(
proxy_info
,
PURPLE_PROXY_SOCKS4
);
else
if
(
purple_strequal
(
data
,
"socks5"
))
purple_proxy_info_set_proxy_type
(
proxy_info
,
PURPLE_PROXY_SOCKS5
);
else
if
(
purple_strequal
(
data
,
"tor"
))
purple_proxy_info_set_proxy_type
(
proxy_info
,
PURPLE_PROXY_TOR
);
else
if
(
purple_strequal
(
data
,
"envvar"
))
purple_proxy_info_set_proxy_type
(
proxy_info
,
PURPLE_PROXY_USE_ENVVAR
);
else
{
purple_debug_error
(
"accounts"
,
"Invalid proxy type found when "
"loading account information for %s
\n
"
,
purple_account_get_username
(
account
));
}
g_free
(
data
);
}
/* Read proxy host */
child
=
purple_xmlnode_get_child
(
node
,
"host"
);
if
((
child
!=
NULL
)
&&
((
data
=
purple_xmlnode_get_data
(
child
))
!=
NULL
))
{
purple_proxy_info_set_host
(
proxy_info
,
data
);
g_free
(
data
);
}
/* Read proxy port */
child
=
purple_xmlnode_get_child
(
node
,
"port"
);
if
((
child
!=
NULL
)
&&
((
data
=
purple_xmlnode_get_data
(
child
))
!=
NULL
))
{
purple_proxy_info_set_port
(
proxy_info
,
atoi
(
data
));
g_free
(
data
);
}
/* Read proxy username */
child
=
purple_xmlnode_get_child
(
node
,
"username"
);
if
((
child
!=
NULL
)
&&
((
data
=
purple_xmlnode_get_data
(
child
))
!=
NULL
))
{
purple_proxy_info_set_username
(
proxy_info
,
data
);
g_free
(
data
);
}
/* Read proxy password */
child
=
purple_xmlnode_get_child
(
node
,
"password"
);
if
((
child
!=
NULL
)
&&
((
data
=
purple_xmlnode_get_data
(
child
))
!=
NULL
))
{
purple_proxy_info_set_password
(
proxy_info
,
data
);
g_free
(
data
);
}
/* If there are no values set then proxy_info NULL */
if
((
purple_proxy_info_get_proxy_type
(
proxy_info
)
==
PURPLE_PROXY_USE_GLOBAL
)
&&
(
purple_proxy_info_get_host
(
proxy_info
)
==
NULL
)
&&
(
purple_proxy_info_get_port
(
proxy_info
)
==
0
)
&&
(
purple_proxy_info_get_username
(
proxy_info
)
==
NULL
)
&&
(
purple_proxy_info_get_password
(
proxy_info
)
==
NULL
))
{
purple_proxy_info_destroy
(
proxy_info
);
return
;
}
purple_account_set_proxy_info
(
account
,
proxy_info
);
}
static
void
parse_current_error
(
PurpleXmlNode
*
node
,
PurpleAccount
*
account
)
{
guint
type
;
char
*
type_str
=
NULL
,
*
description
=
NULL
;
PurpleXmlNode
*
child
;
PurpleConnectionErrorInfo
*
current_error
=
NULL
;
child
=
purple_xmlnode_get_child
(
node
,
"type"
);
if
(
child
==
NULL
||
(
type_str
=
purple_xmlnode_get_data
(
child
))
==
NULL
)
return
;
type
=
atoi
(
type_str
);
g_free
(
type_str
);
if
(
type
>
PURPLE_CONNECTION_ERROR_OTHER_ERROR
)
{
purple_debug_error
(
"accounts"
,
"Invalid PurpleConnectionError value %d found when "
"loading account information for %s
\n
"
,
type
,
purple_account_get_username
(
account
));
type
=
PURPLE_CONNECTION_ERROR_OTHER_ERROR
;
}
child
=
purple_xmlnode_get_child
(
node
,
"description"
);
if
(
child
)
description
=
purple_xmlnode_get_data
(
child
);
if
(
description
==
NULL
)
description
=
g_strdup
(
""
);
current_error
=
g_new0
(
PurpleConnectionErrorInfo
,
1
);
current_error
->
type
=
type
;
current_error
->
description
=
description
;
_purple_account_set_current_error
(
account
,
current_error
);
}
static
PurpleAccount
*
parse_account
(
PurpleXmlNode
*
node
)
{
PurpleAccount
*
ret
;
PurpleXmlNode
*
child
;
char
*
protocol_id
=
NULL
;
char
*
name
=
NULL
;
char
*
data
;
child
=
purple_xmlnode_get_child
(
node
,
"protocol"
);
if
(
child
!=
NULL
)
protocol_id
=
purple_xmlnode_get_data
(
child
);
child
=
purple_xmlnode_get_child
(
node
,
"name"
);
if
(
child
!=
NULL
)
name
=
purple_xmlnode_get_data
(
child
);
if
(
name
==
NULL
)
{
/* Do we really need to do this? */
child
=
purple_xmlnode_get_child
(
node
,
"username"
);
if
(
child
!=
NULL
)
name
=
purple_xmlnode_get_data
(
child
);
}
if
((
protocol_id
==
NULL
)
||
(
name
==
NULL
))
{
g_free
(
protocol_id
);
g_free
(
name
);
return
NULL
;
}
ret
=
purple_account_new
(
name
,
protocol_id
);
g_free
(
name
);
g_free
(
protocol_id
);
/* Read the alias */
child
=
purple_xmlnode_get_child
(
node
,
"alias"
);
if
((
child
!=
NULL
)
&&
((
data
=
purple_xmlnode_get_data
(
child
))
!=
NULL
))
{
if
(
*
data
!=
'\0'
)
purple_account_set_private_alias
(
ret
,
data
);
g_free
(
data
);
}
/* Read the statuses */
child
=
purple_xmlnode_get_child
(
node
,
"statuses"
);
if
(
child
!=
NULL
)
{
parse_statuses
(
child
,
ret
);
}
/* Read the userinfo */
child
=
purple_xmlnode_get_child
(
node
,
"userinfo"
);
if
((
child
!=
NULL
)
&&
((
data
=
purple_xmlnode_get_data
(
child
))
!=
NULL
))
{
purple_account_set_user_info
(
ret
,
data
);
g_free
(
data
);
}
/* Read an old buddyicon */
child
=
purple_xmlnode_get_child
(
node
,
"buddyicon"
);
if
((
child
!=
NULL
)
&&
((
data
=
purple_xmlnode_get_data
(
child
))
!=
NULL
))
{
const
char
*
dirname
=
purple_buddy_icons_get_cache_dir
();
char
*
filename
=
g_build_filename
(
dirname
,
data
,
NULL
);
gchar
*
contents
;
gsize
len
;
if
(
g_file_get_contents
(
filename
,
&
contents
,
&
len
,
NULL
))
{
purple_buddy_icons_set_account_icon
(
ret
,
(
guchar
*
)
contents
,
len
);
}
g_free
(
filename
);
g_free
(
data
);
}
/* Read settings (both core and UI) */
for
(
child
=
purple_xmlnode_get_child
(
node
,
"settings"
);
child
!=
NULL
;
child
=
purple_xmlnode_get_next_twin
(
child
))
{
parse_settings
(
child
,
ret
);
}
/* Read proxy */
child
=
purple_xmlnode_get_child
(
node
,
"proxy"
);
if
(
child
!=
NULL
)
{
parse_proxy_info
(
child
,
ret
);
}
/* Read current error */
child
=
purple_xmlnode_get_child
(
node
,
"current_error"
);
if
(
child
!=
NULL
)
{
parse_current_error
(
child
,
ret
);
}
return
ret
;
}
static
void
load_accounts
(
void
)
{
PurpleXmlNode
*
node
,
*
child
;
accounts_loaded
=
TRUE
;
node
=
purple_util_read_xml_from_config_file
(
"accounts.xml"
,
_
(
"accounts"
));
if
(
node
==
NULL
)
return
;
for
(
child
=
purple_xmlnode_get_child
(
node
,
"account"
);
child
!=
NULL
;
child
=
purple_xmlnode_get_next_twin
(
child
))
{
PurpleAccount
*
new_acct
;
new_acct
=
parse_account
(
child
);
purple_accounts_add
(
new_acct
);
}
purple_xmlnode_free
(
node
);
_purple_buddy_icons_account_loaded_cb
();
}
void
purple_accounts_add
(
PurpleAccount
*
account
)
{
g_return_if_fail
(
account
!=
NULL
);
if
(
g_list_find
(
accounts
,
account
)
!=
NULL
)
return
;
accounts
=
g_list_append
(
accounts
,
account
);
purple_accounts_schedule_save
();
purple_signal_emit
(
purple_accounts_get_handle
(),
"account-added"
,
account
);
}
void
purple_accounts_remove
(
PurpleAccount
*
account
)
{
g_return_if_fail
(
account
!=
NULL
);
accounts
=
g_list_remove
(
accounts
,
account
);
purple_accounts_schedule_save
();
/* Clearing the error ensures that account-error-changed is emitted,
* which is the end of the guarantee that the the error's pointer is
* valid.
*/
purple_account_clear_current_error
(
account
);
purple_signal_emit
(
purple_accounts_get_handle
(),
"account-removed"
,
account
);
}
static
void
purple_accounts_delete_set
(
GObject
*
obj
,
GAsyncResult
*
res
,
gpointer
d
)
{
PurpleCredentialManager
*
manager
=
PURPLE_CREDENTIAL_MANAGER
(
obj
);
PurpleAccount
*
account
=
PURPLE_ACCOUNT
(
d
);
GError
*
error
=
NULL
;
gboolean
r
=
FALSE
;
r
=
purple_credential_manager_clear_password_finish
(
manager
,
res
,
&
error
);
if
(
r
!=
TRUE
)
{
purple_debug_warning
(
"accounts"
,
"Failed to remove password for account %s: %s"
,
purple_account_get_name_for_display
(
account
),
error
->
message
);
g_clear_error
(
&
error
);
}
g_object_unref
(
G_OBJECT
(
account
));
}
void
purple_accounts_delete
(
PurpleAccount
*
account
)
{
PurpleBlistNode
*
gnode
,
*
cnode
,
*
bnode
;
PurpleCredentialManager
*
manager
=
NULL
;
GList
*
iter
;
g_return_if_fail
(
account
!=
NULL
);
/*
* Disable the account before blowing it out of the water.
* Conceptually it probably makes more sense to disable the
* account for all UIs rather than the just the current UI,
* but it doesn't really matter.
*/
purple_account_set_enabled
(
account
,
purple_core_get_ui
(),
FALSE
);
purple_notify_close_with_handle
(
account
);
purple_request_close_with_handle
(
account
);
purple_accounts_remove
(
account
);
/* Remove this account's buddies */
for
(
gnode
=
purple_blist_get_default_root
();
gnode
!=
NULL
;
gnode
=
purple_blist_node_get_sibling_next
(
gnode
))
{
if
(
!
PURPLE_IS_GROUP
(
gnode
))
continue
;
cnode
=
purple_blist_node_get_first_child
(
gnode
);
while
(
cnode
)
{
PurpleBlistNode
*
cnode_next
=
purple_blist_node_get_sibling_next
(
cnode
);
if
(
PURPLE_IS_CONTACT
(
cnode
))
{
bnode
=
purple_blist_node_get_first_child
(
cnode
);
while
(
bnode
)
{
PurpleBlistNode
*
bnode_next
=
purple_blist_node_get_sibling_next
(
bnode
);
if
(
PURPLE_IS_BUDDY
(
bnode
))
{
PurpleBuddy
*
b
=
(
PurpleBuddy
*
)
bnode
;
if
(
purple_buddy_get_account
(
b
)
==
account
)
purple_blist_remove_buddy
(
b
);
}
bnode
=
bnode_next
;
}
}
else
if
(
PURPLE_IS_CHAT
(
cnode
))
{
PurpleChat
*
c
=
(
PurpleChat
*
)
cnode
;
if
(
purple_chat_get_account
(
c
)
==
account
)
purple_blist_remove_chat
(
c
);
}
cnode
=
cnode_next
;
}
}
/* Remove any open conversation for this account */
for
(
iter
=
purple_conversations_get_all
();
iter
;
)
{
PurpleConversation
*
conv
=
iter
->
data
;
iter
=
iter
->
next
;
if
(
purple_conversation_get_account
(
conv
)
==
account
)
g_object_unref
(
conv
);
}
/* This will cause the deletion of an old buddy icon. */
purple_buddy_icons_set_account_icon
(
account
,
NULL
,
0
);
/* This is async because we do not want the
* account being overwritten before we are done.
*/
manager
=
purple_credential_manager_get_default
();
purple_credential_manager_clear_password_async
(
manager
,
account
,
NULL
,
purple_accounts_delete_set
,
NULL
);
}
void
purple_accounts_reorder
(
PurpleAccount
*
account
,
guint
new_index
)
{
gint
index
;
GList
*
l
;
g_return_if_fail
(
account
!=
NULL
);
g_return_if_fail
(
new_index
<=
g_list_length
(
accounts
));
index
=
g_list_index
(
accounts
,
account
);
if
(
index
<
0
)
{
purple_debug_error
(
"accounts"
,
"Unregistered account (%s) discovered during reorder!
\n
"
,
purple_account_get_username
(
account
));
return
;
}
l
=
g_list_nth
(
accounts
,
index
);
if
(
new_index
>
(
guint
)
index
)
new_index
--
;
/* Remove the old one. */
accounts
=
g_list_delete_link
(
accounts
,
l
);
/* Insert it where it should go. */
accounts
=
g_list_insert
(
accounts
,
account
,
new_index
);
purple_accounts_schedule_save
();
}
GList
*
purple_accounts_get_all
(
void
)
{
return
accounts
;
}
GList
*
purple_accounts_get_all_active
(
void
)
{
GList
*
list
=
NULL
;
GList
*
all
=
purple_accounts_get_all
();
while
(
all
!=
NULL
)
{
PurpleAccount
*
account
=
all
->
data
;
if
(
purple_account_get_enabled
(
account
,
purple_core_get_ui
()))
list
=
g_list_append
(
list
,
account
);
all
=
all
->
next
;
}
return
list
;
}
PurpleAccount
*
purple_accounts_find
(
const
char
*
name
,
const
char
*
protocol_id
)
{
PurpleAccount
*
account
=
NULL
;
GList
*
l
;
char
*
who
;
g_return_val_if_fail
(
name
!=
NULL
,
NULL
);
g_return_val_if_fail
(
protocol_id
!=
NULL
,
NULL
);
for
(
l
=
purple_accounts_get_all
();
l
!=
NULL
;
l
=
l
->
next
)
{
account
=
(
PurpleAccount
*
)
l
->
data
;
if
(
!
purple_strequal
(
purple_account_get_protocol_id
(
account
),
protocol_id
))
continue
;
who
=
g_strdup
(
purple_normalize
(
account
,
name
));
if
(
purple_strequal
(
purple_normalize
(
account
,
purple_account_get_username
(
account
)),
who
))
{
g_free
(
who
);
return
account
;
}
g_free
(
who
);
}
return
NULL
;
}
void
purple_accounts_restore_current_statuses
()
{
GList
*
l
;
PurpleAccount
*
account
;
/* If we're not connected to the Internet right now, we bail on this */
if
(
!
purple_network_is_available
())
{
purple_debug_warning
(
"accounts"
,
"Network not connected; skipping reconnect
\n
"
);
return
;
}
for
(
l
=
purple_accounts_get_all
();
l
!=
NULL
;
l
=
l
->
next
)
{
account
=
(
PurpleAccount
*
)
l
->
data
;
if
(
purple_account_get_enabled
(
account
,
purple_core_get_ui
())
&&
(
purple_presence_is_online
(
purple_account_get_presence
(
account
))))
{
purple_account_connect
(
account
);
}
}
}
static
PurpleAccountUiOps
*
purple_account_ui_ops_copy
(
PurpleAccountUiOps
*
ops
)
{
PurpleAccountUiOps
*
ops_new
;
g_return_val_if_fail
(
ops
!=
NULL
,
NULL
);
ops_new
=
g_new
(
PurpleAccountUiOps
,
1
);
*
ops_new
=
*
ops
;
return
ops_new
;
}
GType
purple_account_ui_ops_get_type
(
void
)
{
static
GType
type
=
0
;
if
(
type
==
0
)
{
type
=
g_boxed_type_register_static
(
"PurpleAccountUiOps"
,
(
GBoxedCopyFunc
)
purple_account_ui_ops_copy
,
(
GBoxedFreeFunc
)
g_free
);
}
return
type
;
}
void
purple_accounts_set_ui_ops
(
PurpleAccountUiOps
*
ops
)
{
account_ui_ops
=
ops
;
}
PurpleAccountUiOps
*
purple_accounts_get_ui_ops
(
void
)
{
return
account_ui_ops
;
}
void
*
purple_accounts_get_handle
(
void
)
{
static
int
handle
;
return
&
handle
;
}
static
void
signed_on_cb
(
PurpleConnection
*
gc
,
gpointer
unused
)
{
PurpleAccount
*
account
=
purple_connection_get_account
(
gc
);
purple_account_clear_current_error
(
account
);
purple_signal_emit
(
purple_accounts_get_handle
(),
"account-signed-on"
,
account
);
}
static
void
signed_off_cb
(
PurpleConnection
*
gc
,
gpointer
unused
)
{
PurpleAccount
*
account
=
purple_connection_get_account
(
gc
);
purple_signal_emit
(
purple_accounts_get_handle
(),
"account-signed-off"
,
account
);
}
static
void
connection_error_cb
(
PurpleConnection
*
gc
,
PurpleConnectionError
type
,
const
gchar
*
description
,
gpointer
unused
)
{
PurpleAccount
*
account
;
PurpleConnectionErrorInfo
*
err
;
account
=
purple_connection_get_account
(
gc
);
g_return_if_fail
(
account
!=
NULL
);
err
=
g_new0
(
PurpleConnectionErrorInfo
,
1
);
err
->
type
=
type
;
err
->
description
=
g_strdup
(
description
);
_purple_account_set_current_error
(
account
,
err
);
purple_signal_emit
(
purple_accounts_get_handle
(),
"account-connection-error"
,
account
,
type
,
description
);
}
void
purple_accounts_init
(
void
)
{
void
*
handle
=
purple_accounts_get_handle
();
void
*
conn_handle
=
purple_connections_get_handle
();
purple_signal_register
(
handle
,
"account-connecting"
,
purple_marshal_VOID__POINTER
,
G_TYPE_NONE
,
1
,
PURPLE_TYPE_ACCOUNT
);
purple_signal_register
(
handle
,
"account-disabled"
,
purple_marshal_VOID__POINTER
,
G_TYPE_NONE
,
1
,
PURPLE_TYPE_ACCOUNT
);
purple_signal_register
(
handle
,
"account-enabled"
,
purple_marshal_VOID__POINTER
,
G_TYPE_NONE
,
1
,
PURPLE_TYPE_ACCOUNT
);
purple_signal_register
(
handle
,
"account-setting-info"
,
purple_marshal_VOID__POINTER_POINTER
,
G_TYPE_NONE
,
2
,
PURPLE_TYPE_ACCOUNT
,
G_TYPE_STRING
);
purple_signal_register
(
handle
,
"account-set-info"
,
purple_marshal_VOID__POINTER_POINTER
,
G_TYPE_NONE
,
2
,
PURPLE_TYPE_ACCOUNT
,
G_TYPE_STRING
);
purple_signal_register
(
handle
,
"account-created"
,
purple_marshal_VOID__POINTER
,
G_TYPE_NONE
,
1
,
PURPLE_TYPE_ACCOUNT
);
purple_signal_register
(
handle
,
"account-destroying"
,
purple_marshal_VOID__POINTER
,
G_TYPE_NONE
,
1
,
PURPLE_TYPE_ACCOUNT
);
purple_signal_register
(
handle
,
"account-added"
,
purple_marshal_VOID__POINTER
,
G_TYPE_NONE
,
1
,
PURPLE_TYPE_ACCOUNT
);
purple_signal_register
(
handle
,
"account-removed"
,
purple_marshal_VOID__POINTER
,
G_TYPE_NONE
,
1
,
PURPLE_TYPE_ACCOUNT
);
purple_signal_register
(
handle
,
"account-status-changing"
,
purple_marshal_VOID__POINTER_POINTER_POINTER
,
G_TYPE_NONE
,
3
,
PURPLE_TYPE_ACCOUNT
,
PURPLE_TYPE_STATUS
,
PURPLE_TYPE_STATUS
);
purple_signal_register
(
handle
,
"account-status-changed"
,
purple_marshal_VOID__POINTER_POINTER_POINTER
,
G_TYPE_NONE
,
3
,
PURPLE_TYPE_ACCOUNT
,
PURPLE_TYPE_STATUS
,
PURPLE_TYPE_STATUS
);
purple_signal_register
(
handle
,
"account-actions-changed"
,
purple_marshal_VOID__POINTER
,
G_TYPE_NONE
,
1
,
PURPLE_TYPE_ACCOUNT
);
purple_signal_register
(
handle
,
"account-alias-changed"
,
purple_marshal_VOID__POINTER_POINTER
,
G_TYPE_NONE
,
2
,
PURPLE_TYPE_ACCOUNT
,
G_TYPE_STRING
);
purple_signal_register
(
handle
,
"account-authorization-requested"
,
purple_marshal_INT__POINTER_POINTER_POINTER
,
G_TYPE_INT
,
4
,
PURPLE_TYPE_ACCOUNT
,
G_TYPE_STRING
,
G_TYPE_STRING
,
G_TYPE_STRING
);
purple_signal_register
(
handle
,
"account-authorization-denied"
,
purple_marshal_VOID__POINTER_POINTER
,
G_TYPE_NONE
,
3
,
PURPLE_TYPE_ACCOUNT
,
G_TYPE_STRING
,
G_TYPE_STRING
);
purple_signal_register
(
handle
,
"account-authorization-granted"
,
purple_marshal_VOID__POINTER_POINTER
,
G_TYPE_NONE
,
3
,
PURPLE_TYPE_ACCOUNT
,
G_TYPE_STRING
,
G_TYPE_STRING
);
purple_signal_register
(
handle
,
"account-error-changed"
,
purple_marshal_VOID__POINTER_POINTER_POINTER
,
G_TYPE_NONE
,
3
,
PURPLE_TYPE_ACCOUNT
,
PURPLE_TYPE_CONNECTION_ERROR_INFO
,
PURPLE_TYPE_CONNECTION_ERROR_INFO
);
purple_signal_register
(
handle
,
"account-signed-on"
,
purple_marshal_VOID__POINTER
,
G_TYPE_NONE
,
1
,
PURPLE_TYPE_ACCOUNT
);
purple_signal_register
(
handle
,
"account-signed-off"
,
purple_marshal_VOID__POINTER
,
G_TYPE_NONE
,
1
,
PURPLE_TYPE_ACCOUNT
);
purple_signal_register
(
handle
,
"account-connection-error"
,
purple_marshal_VOID__POINTER_INT_POINTER
,
G_TYPE_NONE
,
3
,
PURPLE_TYPE_ACCOUNT
,
PURPLE_TYPE_CONNECTION_ERROR
,
G_TYPE_STRING
);
purple_signal_connect
(
conn_handle
,
"signed-on"
,
handle
,
PURPLE_CALLBACK
(
signed_on_cb
),
NULL
);
purple_signal_connect
(
conn_handle
,
"signed-off"
,
handle
,
PURPLE_CALLBACK
(
signed_off_cb
),
NULL
);
purple_signal_connect
(
conn_handle
,
"connection-error"
,
handle
,
PURPLE_CALLBACK
(
connection_error_cb
),
NULL
);
load_accounts
();
g_signal_connect
(
G_OBJECT
(
g_network_monitor_get_default
()),
"network-changed"
,
G_CALLBACK
(
purple_accounts_network_changed_cb
),
NULL
);
}
void
purple_accounts_uninit
(
void
)
{
gpointer
handle
=
purple_accounts_get_handle
();
if
(
save_timer
!=
0
)
{
g_source_remove
(
save_timer
);
save_timer
=
0
;
sync_accounts
();
}
for
(;
accounts
;
accounts
=
g_list_delete_link
(
accounts
,
accounts
))
g_object_unref
(
G_OBJECT
(
accounts
->
data
));
purple_signals_disconnect_by_handle
(
handle
);
purple_signals_unregister_by_instance
(
handle
);
}