pidgin/pidgin
Clone
Summary
Browse
Changes
Graph
Make PurpleIRCv3Connection Derivable
15 months ago, Gary Kramlich
7af8ab97086d
Make PurpleIRCv3Connection Derivable
This is going to be necessary for the protocol plugin to be subclassed.
Testing Done:
Compiled and connected to my local ergo instance.
Reviewed at https://reviews.imfreedom.org/r/2187/
/* 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
"accounts.h"
#include
"core.h"
#include
"debug.h"
#include
"network.h"
#include
"notify.h"
#include
"prefs.h"
#include
"purpleaccountmanager.h"
#include
"purpleaccountpresence.h"
#include
"purpleaddcontactrequest.h"
#include
"purpleconversationmanager.h"
#include
"purplecredentialmanager.h"
#include
"purplenotification.h"
#include
"purplenotificationmanager.h"
#include
"purpleprivate.h"
#include
"purpleprotocolclient.h"
#include
"purpleprotocolmanager.h"
#include
"purpleprotocolserver.h"
#include
"request.h"
#include
"server.h"
#include
"signals.h"
#include
"util.h"
typedef
struct
{
GSList
*
names
;
guint
ref_count
;
}
PurpleAccountSettingFreezeQueue
;
G_LOCK_DEFINE_STATIC
(
setting_notify_lock
);
struct
_PurpleAccount
{
PurpleContactInfo
parent
;
gboolean
require_password
;
char
*
user_info
;
/* User information. */
char
*
buddy_icon_path
;
/* The buddy icon's non-cached path. */
gboolean
enabled
;
gboolean
remember_pass
;
/* Remember the password. */
/*
* TODO: After a GObject representing a protocol is ready, use it
* here instead of the protocol ID.
*/
char
*
protocol_id
;
/* The ID of the protocol. */
PurpleConnection
*
gc
;
/* The connection handle. */
gboolean
disconnecting
;
/* The account is currently disconnecting */
GHashTable
*
settings
;
/* Protocol-specific settings. */
PurpleAccountSettingFreezeQueue
*
freeze_queue
;
PurpleProxyInfo
*
proxy_info
;
/* Proxy information. This will be set */
/* to NULL when the account inherits */
/* proxy settings from global prefs. */
GList
*
status_types
;
/* Status types. */
PurplePresence
*
presence
;
/* Presence. */
PurpleConnectionErrorInfo
*
current_error
;
/* Errors */
PurpleNotification
*
error_notification
;
}
PurpleAccountPrivate
;
typedef
struct
{
char
*
ui
;
GValue
value
;
}
PurpleAccountSetting
;
enum
{
PROP_0
,
PROP_REQUIRE_PASSWORD
,
PROP_ENABLED
,
PROP_CONNECTION
,
PROP_PROTOCOL_ID
,
PROP_USER_INFO
,
PROP_BUDDY_ICON_PATH
,
PROP_REMEMBER_PASSWORD
,
PROP_PROXY_INFO
,
PROP_ERROR
,
PROP_LAST
};
static
GParamSpec
*
properties
[
PROP_LAST
];
enum
{
SIG_SETTING_CHANGED
,
N_SIGNALS
};
static
guint
signals
[
N_SIGNALS
]
=
{
0
,
};
G_DEFINE_TYPE
(
PurpleAccount
,
purple_account
,
PURPLE_TYPE_CONTACT_INFO
);
/******************************************************************************
* Helpers
*****************************************************************************/
static
void
purple_account_free_notify_settings
(
PurpleAccount
*
account
)
{
g_return_if_fail
(
PURPLE_IS_ACCOUNT
(
account
));
if
(
account
->
freeze_queue
!=
NULL
)
{
g_slist_free_full
(
account
->
freeze_queue
->
names
,
g_free
);
g_slice_free
(
PurpleAccountSettingFreezeQueue
,
account
->
freeze_queue
);
account
->
freeze_queue
=
NULL
;
}
}
static
void
purple_account_setting_changed_emit
(
PurpleAccount
*
account
,
const
char
*
name
)
{
g_return_if_fail
(
PURPLE_IS_ACCOUNT
(
account
));
g_return_if_fail
(
name
!=
NULL
);
G_LOCK
(
setting_notify_lock
);
if
(
account
->
freeze_queue
!=
NULL
)
{
GSList
*
names
=
account
->
freeze_queue
->
names
;
if
(
g_slist_find_custom
(
names
,
name
,
(
GCompareFunc
)
g_strcmp0
)
==
NULL
)
{
names
=
g_slist_prepend
(
names
,
g_strdup
(
name
));
account
->
freeze_queue
->
names
=
names
;
}
}
else
{
g_signal_emit
(
account
,
signals
[
SIG_SETTING_CHANGED
],
g_quark_from_string
(
name
),
name
);
}
G_UNLOCK
(
setting_notify_lock
);
}
static
void
purple_account_real_connect
(
PurpleAccount
*
account
,
const
char
*
password
)
{
PurpleConnection
*
connection
=
NULL
;
PurpleProtocol
*
protocol
=
NULL
;
GError
*
error
=
NULL
;
protocol
=
purple_account_get_protocol
(
account
);
connection
=
purple_protocol_create_connection
(
protocol
,
account
,
password
,
&
error
);
if
(
error
!=
NULL
)
{
PurpleContactInfo
*
info
=
PURPLE_CONTACT_INFO
(
account
);
purple_debug_warning
(
"failed to create connection for %s: %s"
,
purple_contact_info_get_username
(
info
),
error
->
message
);
g_clear_error
(
&
error
);
return
;
}
g_return_if_fail
(
PURPLE_IS_CONNECTION
(
connection
));
purple_account_set_connection
(
account
,
connection
);
if
(
!
purple_connection_connect
(
connection
,
&
error
))
{
const
char
*
message
=
"unknown error"
;
if
(
error
!=
NULL
&&
error
->
message
!=
NULL
)
{
message
=
error
->
message
;
}
purple_connection_error
(
connection
,
PURPLE_CONNECTION_ERROR_OTHER_ERROR
,
message
);
g_clear_error
(
&
error
);
}
/* Finally remove our reference to the connection. */
g_object_unref
(
connection
);
}
static
void
request_password_write_cb
(
GObject
*
obj
,
GAsyncResult
*
res
,
gpointer
data
)
{
PurpleCredentialManager
*
manager
=
PURPLE_CREDENTIAL_MANAGER
(
obj
);
PurpleAccount
*
account
=
PURPLE_ACCOUNT
(
data
);
GError
*
error
=
NULL
;
gchar
*
password
=
NULL
;
/* We stash the password on the account to get it to this call back... It's
* kind of gross but shouldn't be a big deal because any plugin has access
* to the credential store, so it's not really a security leak.
*/
password
=
(
gchar
*
)
g_object_get_data
(
G_OBJECT
(
account
),
"_tmp_password"
);
g_object_set_data
(
G_OBJECT
(
account
),
"_tmp_password"
,
NULL
);
if
(
!
purple_credential_manager_write_password_finish
(
manager
,
res
,
&
error
))
{
PurpleContactInfo
*
info
=
PURPLE_CONTACT_INFO
(
account
);
const
gchar
*
name
=
purple_contact_info_get_name_for_display
(
info
);
/* we can't error an account without a connection, so we just drop a
* debug message for now and continue to connect the account.
*/
purple_debug_info
(
"account"
,
"failed to save password for account
\"
%s
\"
: %s"
,
name
,
error
!=
NULL
?
error
->
message
:
"unknown error"
);
}
purple_account_real_connect
(
account
,
password
);
g_free
(
password
);
}
static
void
request_password_ok_cb
(
PurpleAccount
*
account
,
PurpleRequestFields
*
fields
)
{
const
char
*
entry
;
gboolean
remember
;
entry
=
purple_request_fields_get_string
(
fields
,
"password"
);
remember
=
purple_request_fields_get_bool
(
fields
,
"remember"
);
if
(
!
entry
||
!*
entry
)
{
purple_notify_error
(
account
,
NULL
,
_
(
"Password is required to sign on."
),
NULL
,
purple_request_cpar_from_account
(
account
));
return
;
}
purple_account_set_remember_password
(
account
,
remember
);
if
(
remember
)
{
PurpleCredentialManager
*
manager
=
NULL
;
manager
=
purple_credential_manager_get_default
();
/* The requests field can be invalidated by the time we write the
* password and we want to use it in the write callback, so we need to
* duplicate it for that callback.
*/
g_object_set_data
(
G_OBJECT
(
account
),
"_tmp_password"
,
g_strdup
(
entry
));
purple_credential_manager_write_password_async
(
manager
,
account
,
entry
,
NULL
,
request_password_write_cb
,
account
);
}
else
{
purple_account_real_connect
(
account
,
entry
);
}
}
static
void
request_password_cancel_cb
(
PurpleAccount
*
account
,
G_GNUC_UNUSED
PurpleRequestFields
*
fields
)
{
/* Disable the account as the user has cancelled connecting */
purple_account_set_enabled
(
account
,
FALSE
);
}
static
void
purple_account_connect_got_password_cb
(
GObject
*
obj
,
GAsyncResult
*
res
,
gpointer
data
)
{
PurpleCredentialManager
*
manager
=
PURPLE_CREDENTIAL_MANAGER
(
obj
);
PurpleAccount
*
account
=
PURPLE_ACCOUNT
(
data
);
PurpleProtocol
*
protocol
=
NULL
;
PurpleProtocolOptions
options
;
GError
*
error
=
NULL
;
gchar
*
password
=
NULL
;
gboolean
require_password
=
TRUE
;
password
=
purple_credential_manager_read_password_finish
(
manager
,
res
,
&
error
);
if
(
error
!=
NULL
)
{
purple_debug_warning
(
"account"
,
"failed to read password %s"
,
error
->
message
);
g_error_free
(
error
);
}
protocol
=
purple_account_get_protocol
(
account
);
options
=
purple_protocol_get_options
(
protocol
);
if
(
options
&
OPT_PROTO_PASSWORD_OPTIONAL
)
{
require_password
=
purple_account_get_require_password
(
account
);
}
else
if
(
options
&
OPT_PROTO_NO_PASSWORD
)
{
require_password
=
FALSE
;
}
if
((
password
==
NULL
||
*
password
==
'\0'
)
&&
require_password
)
{
purple_account_request_password
(
account
,
G_CALLBACK
(
request_password_ok_cb
),
G_CALLBACK
(
request_password_cancel_cb
),
account
);
}
else
{
purple_account_real_connect
(
account
,
password
);
}
g_free
(
password
);
}
static
void
change_password_cb
(
PurpleAccount
*
account
,
PurpleRequestFields
*
fields
)
{
const
char
*
orig_pass
,
*
new_pass_1
,
*
new_pass_2
;
orig_pass
=
purple_request_fields_get_string
(
fields
,
"password"
);
new_pass_1
=
purple_request_fields_get_string
(
fields
,
"new_password_1"
);
new_pass_2
=
purple_request_fields_get_string
(
fields
,
"new_password_2"
);
if
(
g_utf8_collate
(
new_pass_1
,
new_pass_2
))
{
purple_notify_error
(
account
,
NULL
,
_
(
"New passwords do not match."
),
NULL
,
purple_request_cpar_from_account
(
account
));
return
;
}
if
((
purple_request_fields_is_field_required
(
fields
,
"password"
)
&&
(
orig_pass
==
NULL
||
*
orig_pass
==
'\0'
))
||
(
purple_request_fields_is_field_required
(
fields
,
"new_password_1"
)
&&
(
new_pass_1
==
NULL
||
*
new_pass_1
==
'\0'
))
||
(
purple_request_fields_is_field_required
(
fields
,
"new_password_2"
)
&&
(
new_pass_2
==
NULL
||
*
new_pass_2
==
'\0'
)))
{
purple_notify_error
(
account
,
NULL
,
_
(
"Fill out all fields completely."
),
NULL
,
purple_request_cpar_from_account
(
account
));
return
;
}
purple_account_change_password
(
account
,
orig_pass
,
new_pass_1
);
}
static
gboolean
no_password_cb
(
gpointer
data
)
{
PurpleAccount
*
account
=
data
;
purple_account_real_connect
(
account
,
NULL
);
return
G_SOURCE_REMOVE
;
}
static
void
set_user_info_cb
(
PurpleAccount
*
account
,
const
char
*
user_info
)
{
PurpleProtocol
*
protocol
=
NULL
;
purple_account_set_user_info
(
account
,
user_info
);
protocol
=
purple_account_get_protocol
(
account
);
if
(
PURPLE_PROTOCOL_IMPLEMENTS
(
protocol
,
SERVER
,
set_info
))
{
PurpleConnection
*
connection
=
purple_account_get_connection
(
account
);
purple_protocol_server_set_info
(
PURPLE_PROTOCOL_SERVER
(
protocol
),
connection
,
user_info
);
}
}
static
void
delete_setting
(
void
*
data
)
{
PurpleAccountSetting
*
setting
=
(
PurpleAccountSetting
*
)
data
;
g_free
(
setting
->
ui
);
g_value_unset
(
&
setting
->
value
);
g_free
(
setting
);
}
static
PurpleConnectionState
purple_account_get_state
(
PurpleAccount
*
account
)
{
PurpleConnection
*
gc
;
g_return_val_if_fail
(
PURPLE_IS_ACCOUNT
(
account
),
PURPLE_CONNECTION_STATE_DISCONNECTED
);
gc
=
purple_account_get_connection
(
account
);
if
(
!
gc
)
{
return
PURPLE_CONNECTION_STATE_DISCONNECTED
;
}
return
purple_connection_get_state
(
gc
);
}
void
_purple_account_set_current_error
(
PurpleAccount
*
account
,
PurpleConnectionErrorInfo
*
new_err
)
{
PurpleNotificationManager
*
manager
=
NULL
;
g_return_if_fail
(
PURPLE_IS_ACCOUNT
(
account
));
if
(
new_err
==
account
->
current_error
)
{
return
;
}
g_clear_pointer
(
&
account
->
current_error
,
purple_connection_error_info_free
);
account
->
current_error
=
new_err
;
manager
=
purple_notification_manager_get_default
();
if
(
PURPLE_IS_NOTIFICATION
(
account
->
error_notification
))
{
purple_notification_manager_remove
(
manager
,
account
->
error_notification
);
g_clear_object
(
&
account
->
error_notification
);
}
if
(
new_err
!=
NULL
)
{
account
->
error_notification
=
purple_notification_new_from_connection_error
(
account
,
new_err
);
purple_notification_manager_add
(
manager
,
account
->
error_notification
);
}
g_object_notify_by_pspec
(
G_OBJECT
(
account
),
properties
[
PROP_ERROR
]);
purple_accounts_schedule_save
();
}
static
void
purple_account_changed_cb
(
GObject
*
obj
,
GParamSpec
*
pspec
,
G_GNUC_UNUSED
gpointer
data
)
{
const
char
*
name
=
NULL
;
purple_accounts_schedule_save
();
name
=
g_param_spec_get_name
(
pspec
);
if
(
purple_strequal
(
name
,
"username"
))
{
/* if the username changes, we should re-write the buddy list to disk
* with the new name.
*/
purple_blist_save_account
(
purple_blist_get_default
(),
PURPLE_ACCOUNT
(
obj
));
}
}
/******************************************************************************
* XmlNode Helpers
*****************************************************************************/
static
PurpleXmlNode
*
proxy_settings_to_xmlnode
(
PurpleProxyInfo
*
proxy_info
)
{
PurpleXmlNode
*
node
,
*
child
;
PurpleProxyType
proxy_type
;
const
char
*
value
;
int
int_value
;
char
buf
[
21
];
proxy_type
=
purple_proxy_info_get_proxy_type
(
proxy_info
);
node
=
purple_xmlnode_new
(
"proxy"
);
child
=
purple_xmlnode_new_child
(
node
,
"type"
);
purple_xmlnode_insert_data
(
child
,
(
proxy_type
==
PURPLE_PROXY_TYPE_USE_GLOBAL
?
"global"
:
proxy_type
==
PURPLE_PROXY_TYPE_NONE
?
"none"
:
proxy_type
==
PURPLE_PROXY_TYPE_HTTP
?
"http"
:
proxy_type
==
PURPLE_PROXY_TYPE_SOCKS4
?
"socks4"
:
proxy_type
==
PURPLE_PROXY_TYPE_SOCKS5
?
"socks5"
:
proxy_type
==
PURPLE_PROXY_TYPE_TOR
?
"tor"
:
proxy_type
==
PURPLE_PROXY_TYPE_USE_ENVVAR
?
"envvar"
:
"unknown"
),
-1
);
if
((
value
=
purple_proxy_info_get_hostname
(
proxy_info
))
!=
NULL
)
{
child
=
purple_xmlnode_new_child
(
node
,
"host"
);
purple_xmlnode_insert_data
(
child
,
value
,
-1
);
}
if
((
int_value
=
purple_proxy_info_get_port
(
proxy_info
))
!=
0
)
{
g_snprintf
(
buf
,
sizeof
(
buf
),
"%d"
,
int_value
);
child
=
purple_xmlnode_new_child
(
node
,
"port"
);
purple_xmlnode_insert_data
(
child
,
buf
,
-1
);
}
if
((
value
=
purple_proxy_info_get_username
(
proxy_info
))
!=
NULL
)
{
child
=
purple_xmlnode_new_child
(
node
,
"username"
);
purple_xmlnode_insert_data
(
child
,
value
,
-1
);
}
if
((
value
=
purple_proxy_info_get_password
(
proxy_info
))
!=
NULL
)
{
child
=
purple_xmlnode_new_child
(
node
,
"password"
);
purple_xmlnode_insert_data
(
child
,
value
,
-1
);
}
return
node
;
}
static
PurpleXmlNode
*
current_error_to_xmlnode
(
PurpleConnectionErrorInfo
*
err
)
{
PurpleXmlNode
*
node
,
*
child
;
char
type_str
[
3
];
node
=
purple_xmlnode_new
(
"current_error"
);
if
(
err
==
NULL
)
return
node
;
/* It doesn't make sense to have transient errors persist across a
* restart.
*/
if
(
!
purple_connection_error_is_fatal
(
err
->
type
))
return
node
;
child
=
purple_xmlnode_new_child
(
node
,
"type"
);
g_snprintf
(
type_str
,
sizeof
(
type_str
),
"%u"
,
err
->
type
);
purple_xmlnode_insert_data
(
child
,
type_str
,
-1
);
child
=
purple_xmlnode_new_child
(
node
,
"description"
);
if
(
err
->
description
)
{
char
*
utf8ized
=
purple_utf8_try_convert
(
err
->
description
);
if
(
utf8ized
==
NULL
)
{
utf8ized
=
g_utf8_make_valid
(
err
->
description
,
-1
);
}
purple_xmlnode_insert_data
(
child
,
utf8ized
,
-1
);
g_free
(
utf8ized
);
}
return
node
;
}
static
void
setting_to_xmlnode
(
gpointer
key
,
gpointer
value
,
gpointer
user_data
)
{
const
char
*
name
;
PurpleAccountSetting
*
setting
;
PurpleXmlNode
*
node
,
*
child
;
char
buf
[
21
];
name
=
(
const
char
*
)
key
;
setting
=
(
PurpleAccountSetting
*
)
value
;
node
=
(
PurpleXmlNode
*
)
user_data
;
child
=
purple_xmlnode_new_child
(
node
,
"setting"
);
purple_xmlnode_set_attrib
(
child
,
"name"
,
name
);
if
(
G_VALUE_HOLDS_INT
(
&
setting
->
value
))
{
purple_xmlnode_set_attrib
(
child
,
"type"
,
"int"
);
g_snprintf
(
buf
,
sizeof
(
buf
),
"%d"
,
g_value_get_int
(
&
setting
->
value
));
purple_xmlnode_insert_data
(
child
,
buf
,
-1
);
}
else
if
(
G_VALUE_HOLDS_STRING
(
&
setting
->
value
)
&&
g_value_get_string
(
&
setting
->
value
)
!=
NULL
)
{
purple_xmlnode_set_attrib
(
child
,
"type"
,
"string"
);
purple_xmlnode_insert_data
(
child
,
g_value_get_string
(
&
setting
->
value
),
-1
);
}
else
if
(
G_VALUE_HOLDS_BOOLEAN
(
&
setting
->
value
))
{
purple_xmlnode_set_attrib
(
child
,
"type"
,
"bool"
);
g_snprintf
(
buf
,
sizeof
(
buf
),
"%d"
,
g_value_get_boolean
(
&
setting
->
value
));
purple_xmlnode_insert_data
(
child
,
buf
,
-1
);
}
}
PurpleXmlNode
*
_purple_account_to_xmlnode
(
PurpleAccount
*
account
)
{
PurpleContactInfo
*
info
=
PURPLE_CONTACT_INFO
(
account
);
PurpleXmlNode
*
node
,
*
child
;
gchar
*
data
=
NULL
;
const
char
*
tmp
;
PurpleProxyInfo
*
proxy_info
;
node
=
purple_xmlnode_new
(
"account"
);
tmp
=
purple_contact_info_get_id
(
info
);
if
(
tmp
!=
NULL
)
{
child
=
purple_xmlnode_new_child
(
node
,
"id"
);
purple_xmlnode_insert_data
(
child
,
tmp
,
-1
);
}
child
=
purple_xmlnode_new_child
(
node
,
"protocol"
);
purple_xmlnode_insert_data
(
child
,
purple_account_get_protocol_id
(
account
),
-1
);
child
=
purple_xmlnode_new_child
(
node
,
"name"
);
purple_xmlnode_insert_data
(
child
,
purple_contact_info_get_username
(
info
),
-1
);
child
=
purple_xmlnode_new_child
(
node
,
"require_password"
);
data
=
g_strdup_printf
(
"%d"
,
account
->
require_password
);
purple_xmlnode_insert_data
(
child
,
data
,
-1
);
g_clear_pointer
(
&
data
,
g_free
);
child
=
purple_xmlnode_new_child
(
node
,
"enabled"
);
data
=
g_strdup_printf
(
"%d"
,
account
->
enabled
);
purple_xmlnode_insert_data
(
child
,
data
,
-1
);
g_clear_pointer
(
&
data
,
g_free
);
tmp
=
purple_contact_info_get_alias
(
info
);
if
(
tmp
!=
NULL
)
{
child
=
purple_xmlnode_new_child
(
node
,
"alias"
);
purple_xmlnode_insert_data
(
child
,
tmp
,
-1
);
}
if
((
tmp
=
purple_account_get_user_info
(
account
))
!=
NULL
)
{
/* TODO: Do we need to call purple_str_strip_char(tmp, '\r') here? */
child
=
purple_xmlnode_new_child
(
node
,
"user-info"
);
purple_xmlnode_insert_data
(
child
,
tmp
,
-1
);
}
if
(
g_hash_table_size
(
account
->
settings
)
>
0
)
{
child
=
purple_xmlnode_new_child
(
node
,
"settings"
);
g_hash_table_foreach
(
account
->
settings
,
setting_to_xmlnode
,
child
);
}
if
((
proxy_info
=
purple_account_get_proxy_info
(
account
))
!=
NULL
)
{
child
=
proxy_settings_to_xmlnode
(
proxy_info
);
purple_xmlnode_insert_child
(
node
,
child
);
}
child
=
current_error_to_xmlnode
(
account
->
current_error
);
purple_xmlnode_insert_child
(
node
,
child
);
return
node
;
}
/******************************************************************************
* GObject Implementation
*****************************************************************************/
static
void
purple_account_set_property
(
GObject
*
obj
,
guint
param_id
,
const
GValue
*
value
,
GParamSpec
*
pspec
)
{
PurpleAccount
*
account
=
PURPLE_ACCOUNT
(
obj
);
switch
(
param_id
)
{
case
PROP_REQUIRE_PASSWORD
:
purple_account_set_require_password
(
account
,
g_value_get_boolean
(
value
));
break
;
case
PROP_ENABLED
:
purple_account_set_enabled
(
account
,
g_value_get_boolean
(
value
));
break
;
case
PROP_CONNECTION
:
purple_account_set_connection
(
account
,
g_value_get_object
(
value
));
break
;
case
PROP_PROTOCOL_ID
:
purple_account_set_protocol_id
(
account
,
g_value_get_string
(
value
));
break
;
case
PROP_USER_INFO
:
purple_account_set_user_info
(
account
,
g_value_get_string
(
value
));
break
;
case
PROP_BUDDY_ICON_PATH
:
purple_account_set_buddy_icon_path
(
account
,
g_value_get_string
(
value
));
break
;
case
PROP_REMEMBER_PASSWORD
:
purple_account_set_remember_password
(
account
,
g_value_get_boolean
(
value
));
break
;
case
PROP_PROXY_INFO
:
purple_account_set_proxy_info
(
account
,
g_value_get_object
(
value
));
break
;
default
:
G_OBJECT_WARN_INVALID_PROPERTY_ID
(
obj
,
param_id
,
pspec
);
break
;
}
}
static
void
purple_account_get_property
(
GObject
*
obj
,
guint
param_id
,
GValue
*
value
,
GParamSpec
*
pspec
)
{
PurpleAccount
*
account
=
PURPLE_ACCOUNT
(
obj
);
switch
(
param_id
)
{
case
PROP_REQUIRE_PASSWORD
:
g_value_set_boolean
(
value
,
purple_account_get_require_password
(
account
));
break
;
case
PROP_ENABLED
:
g_value_set_boolean
(
value
,
purple_account_get_enabled
(
account
));
break
;
case
PROP_CONNECTION
:
g_value_set_object
(
value
,
purple_account_get_connection
(
account
));
break
;
case
PROP_PROTOCOL_ID
:
g_value_set_string
(
value
,
purple_account_get_protocol_id
(
account
));
break
;
case
PROP_USER_INFO
:
g_value_set_string
(
value
,
purple_account_get_user_info
(
account
));
break
;
case
PROP_BUDDY_ICON_PATH
:
g_value_set_string
(
value
,
purple_account_get_buddy_icon_path
(
account
));
break
;
case
PROP_REMEMBER_PASSWORD
:
g_value_set_boolean
(
value
,
purple_account_get_remember_password
(
account
));
break
;
case
PROP_PROXY_INFO
:
g_value_set_object
(
value
,
purple_account_get_proxy_info
(
account
));
break
;
default
:
G_OBJECT_WARN_INVALID_PROPERTY_ID
(
obj
,
param_id
,
pspec
);
break
;
}
}
static
void
purple_account_init
(
PurpleAccount
*
account
)
{
account
->
settings
=
g_hash_table_new_full
(
g_str_hash
,
g_str_equal
,
g_free
,
delete_setting
);
}
static
void
purple_account_constructed
(
GObject
*
object
)
{
PurpleAccount
*
account
=
PURPLE_ACCOUNT
(
object
);
gchar
*
username
,
*
protocol_id
;
const
char
*
id
=
NULL
;
PurpleProtocol
*
protocol
=
NULL
;
PurpleProtocolManager
*
manager
=
NULL
;
PurpleStatusType
*
status_type
;
G_OBJECT_CLASS
(
purple_account_parent_class
)
->
constructed
(
object
);
/* If we didn't get an id, checksum the protocol id and the username. */
id
=
purple_contact_info_get_id
(
PURPLE_CONTACT_INFO
(
object
));
if
(
id
==
NULL
)
{
PurpleContactInfo
*
info
=
PURPLE_CONTACT_INFO
(
account
);
GChecksum
*
checksum
=
NULL
;
const
char
*
username
=
NULL
;
checksum
=
g_checksum_new
(
G_CHECKSUM_SHA256
);
username
=
purple_contact_info_get_username
(
info
);
g_checksum_update
(
checksum
,
(
const
guchar
*
)
account
->
protocol_id
,
-1
);
g_checksum_update
(
checksum
,
(
const
guchar
*
)
username
,
-1
);
purple_contact_info_set_id
(
info
,
g_checksum_get_string
(
checksum
));
g_checksum_free
(
checksum
);
}
g_object_get
(
object
,
"username"
,
&
username
,
"protocol-id"
,
&
protocol_id
,
NULL
);
manager
=
purple_protocol_manager_get_default
();
protocol
=
purple_protocol_manager_find
(
manager
,
protocol_id
);
if
(
protocol
==
NULL
)
{
g_free
(
username
);
g_free
(
protocol_id
);
return
;
}
purple_account_set_status_types
(
account
,
purple_protocol_get_status_types
(
protocol
,
account
));
account
->
presence
=
PURPLE_PRESENCE
(
purple_account_presence_new
(
account
));
status_type
=
purple_account_get_status_type_with_primitive
(
account
,
PURPLE_STATUS_AVAILABLE
);
if
(
status_type
!=
NULL
)
purple_presence_set_status_active
(
account
->
presence
,
purple_status_type_get_id
(
status_type
),
TRUE
);
else
purple_presence_set_status_active
(
account
->
presence
,
"offline"
,
TRUE
);
g_free
(
username
);
g_free
(
protocol_id
);
/* Connect to our own notify signal so we can update accounts.xml. */
g_signal_connect
(
object
,
"notify"
,
G_CALLBACK
(
purple_account_changed_cb
),
NULL
);
}
static
void
purple_account_dispose
(
GObject
*
object
)
{
PurpleAccount
*
account
=
PURPLE_ACCOUNT
(
object
);
if
(
!
purple_account_is_disconnected
(
account
))
{
purple_account_disconnect
(
account
);
}
g_clear_object
(
&
account
->
gc
);
g_clear_object
(
&
account
->
presence
);
G_OBJECT_CLASS
(
purple_account_parent_class
)
->
dispose
(
object
);
}
static
void
purple_account_finalize
(
GObject
*
object
)
{
GList
*
l
;
PurpleAccount
*
account
=
PURPLE_ACCOUNT
(
object
);
PurpleConversationManager
*
manager
=
NULL
;
purple_debug_info
(
"account"
,
"Destroying account %p"
,
account
);
purple_account_free_notify_settings
(
account
);
manager
=
purple_conversation_manager_get_default
();
l
=
purple_conversation_manager_get_all
(
manager
);
while
(
l
!=
NULL
)
{
PurpleConversation
*
conv
=
PURPLE_CONVERSATION
(
l
->
data
);
if
(
purple_conversation_get_account
(
conv
)
==
account
)
{
purple_conversation_set_account
(
conv
,
NULL
);
}
l
=
g_list_delete_link
(
l
,
l
);
}
purple_account_set_status_types
(
account
,
NULL
);
g_clear_object
(
&
account
->
proxy_info
);
g_clear_pointer
(
&
account
->
current_error
,
purple_connection_error_info_free
);
g_clear_object
(
&
account
->
error_notification
);
g_free
(
account
->
user_info
);
g_free
(
account
->
buddy_icon_path
);
g_free
(
account
->
protocol_id
);
g_hash_table_destroy
(
account
->
settings
);
G_OBJECT_CLASS
(
purple_account_parent_class
)
->
finalize
(
object
);
}
static
void
purple_account_class_init
(
PurpleAccountClass
*
klass
)
{
GObjectClass
*
obj_class
=
G_OBJECT_CLASS
(
klass
);
obj_class
->
constructed
=
purple_account_constructed
;
obj_class
->
dispose
=
purple_account_dispose
;
obj_class
->
finalize
=
purple_account_finalize
;
obj_class
->
get_property
=
purple_account_get_property
;
obj_class
->
set_property
=
purple_account_set_property
;
/**
* PurpleAccount:require-password:
*
* Whether or not this account should require a password. This is only used
* if the [class@Purple.Protocol] that this account is for allows optional
* passwords.
*
* Since: 3.0.0
*/
properties
[
PROP_REQUIRE_PASSWORD
]
=
g_param_spec_boolean
(
"require-password"
,
"Require password"
,
"Whether or not to require a password for this account"
,
FALSE
,
G_PARAM_READWRITE
|
G_PARAM_STATIC_STRINGS
);
properties
[
PROP_USER_INFO
]
=
g_param_spec_string
(
"user-info"
,
"User information"
,
"Detailed user information for the account."
,
NULL
,
G_PARAM_READWRITE
|
G_PARAM_STATIC_STRINGS
);
properties
[
PROP_BUDDY_ICON_PATH
]
=
g_param_spec_string
(
"buddy-icon-path"
,
"Buddy icon path"
,
"Path to the buddyicon for the account."
,
NULL
,
G_PARAM_READWRITE
|
G_PARAM_STATIC_STRINGS
);
properties
[
PROP_ENABLED
]
=
g_param_spec_boolean
(
"enabled"
,
"Enabled"
,
"Whether the account is enabled or not."
,
FALSE
,
G_PARAM_READWRITE
|
G_PARAM_STATIC_STRINGS
);
properties
[
PROP_REMEMBER_PASSWORD
]
=
g_param_spec_boolean
(
"remember-password"
,
"Remember password"
,
"Whether to remember and store the password for this account."
,
FALSE
,
G_PARAM_READWRITE
|
G_PARAM_STATIC_STRINGS
);
properties
[
PROP_CONNECTION
]
=
g_param_spec_object
(
"connection"
,
"Connection"
,
"The connection for the account."
,
PURPLE_TYPE_CONNECTION
,
G_PARAM_READWRITE
|
G_PARAM_STATIC_STRINGS
);
properties
[
PROP_PROTOCOL_ID
]
=
g_param_spec_string
(
"protocol-id"
,
"Protocol ID"
,
"ID of the protocol that is responsible for the account."
,
NULL
,
G_PARAM_READWRITE
|
G_PARAM_CONSTRUCT_ONLY
|
G_PARAM_STATIC_STRINGS
);
properties
[
PROP_PROXY_INFO
]
=
g_param_spec_object
(
"proxy-info"
,
"proxy-info"
,
"The PurpleProxyInfo for this account."
,
PURPLE_TYPE_PROXY_INFO
,
G_PARAM_READWRITE
|
G_PARAM_STATIC_STRINGS
);
/**
* PurpleAccount:error:
*
* The [type@GLib.Error] of the account. This is set when an account enters
* an error state and is cleared when a connection attempt is made.
*
* Since: 3.0.0
*/
properties
[
PROP_ERROR
]
=
g_param_spec_boxed
(
"error"
,
"error"
,
"The connection error info of the account"
,
PURPLE_TYPE_CONNECTION_ERROR_INFO
,
G_PARAM_READWRITE
|
G_PARAM_STATIC_STRINGS
);
g_object_class_install_properties
(
obj_class
,
PROP_LAST
,
properties
);
/**
* PurpleAccount::setting-changed:
* @account: The account whose setting changed.
* @name: The name of the setting that changed.
*
* The ::setting-changed signal is emitted whenever an account setting is
* changed.
*
* This signal supports details, so you can be notified when a single
* setting changes. For example, say there's a setting named `foo`,
* connecting to `setting-changed::foo` will only be called when the `foo`
* setting is changed.
*
* Since: 3.0.0
*/
signals
[
SIG_SETTING_CHANGED
]
=
g_signal_new_class_handler
(
"setting-changed"
,
G_OBJECT_CLASS_TYPE
(
klass
),
G_SIGNAL_RUN_LAST
|
G_SIGNAL_DETAILED
,
NULL
,
NULL
,
NULL
,
NULL
,
G_TYPE_NONE
,
1
,
G_TYPE_STRING
);
}
/******************************************************************************
* Private API
*****************************************************************************/
/* This is a temporary method that the deserializer can call to set the
* enabled property without bringing the account online.
*/
void
purple_account_set_enabled_plain
(
PurpleAccount
*
account
,
gboolean
enabled
)
{
g_return_if_fail
(
PURPLE_IS_ACCOUNT
(
account
));
account
->
enabled
=
enabled
;
}
/******************************************************************************
* Public API
*****************************************************************************/
PurpleAccount
*
purple_account_new
(
const
gchar
*
username
,
const
gchar
*
protocol_id
)
{
PurpleAccount
*
account
;
PurpleAccountManager
*
manager
=
NULL
;
g_return_val_if_fail
(
username
!=
NULL
,
NULL
);
g_return_val_if_fail
(
protocol_id
!=
NULL
,
NULL
);
manager
=
purple_account_manager_get_default
();
account
=
purple_account_manager_find
(
manager
,
username
,
protocol_id
);
if
(
account
!=
NULL
)
{
return
account
;
}
account
=
g_object_new
(
PURPLE_TYPE_ACCOUNT
,
"username"
,
username
,
"protocol-id"
,
protocol_id
,
"enabled"
,
FALSE
,
NULL
);
return
account
;
}
void
purple_account_connect
(
PurpleAccount
*
account
)
{
PurpleCredentialManager
*
manager
=
NULL
;
PurpleProtocol
*
protocol
=
NULL
;
PurpleProtocolOptions
options
;
const
char
*
username
=
NULL
;
gboolean
require_password
=
TRUE
;
g_return_if_fail
(
PURPLE_IS_ACCOUNT
(
account
));
purple_account_clear_current_error
(
account
);
username
=
purple_contact_info_get_username
(
PURPLE_CONTACT_INFO
(
account
));
if
(
!
purple_account_get_enabled
(
account
))
{
purple_debug_info
(
"account"
,
"Account %s not enabled, not connecting.
\n
"
,
username
);
return
;
}
protocol
=
purple_account_get_protocol
(
account
);
if
(
protocol
==
NULL
)
{
gchar
*
message
;
message
=
g_strdup_printf
(
_
(
"Missing protocol for %s"
),
username
);
purple_notify_error
(
account
,
_
(
"Connection Error"
),
message
,
NULL
,
purple_request_cpar_from_account
(
account
));
g_free
(
message
);
return
;
}
purple_debug_info
(
"account"
,
"Connecting to account %s.
\n
"
,
username
);
options
=
purple_protocol_get_options
(
protocol
);
if
(
options
&
OPT_PROTO_PASSWORD_OPTIONAL
)
{
require_password
=
purple_account_get_require_password
(
account
);
}
else
if
(
options
&
OPT_PROTO_NO_PASSWORD
)
{
require_password
=
FALSE
;
}
if
(
require_password
)
{
manager
=
purple_credential_manager_get_default
();
purple_credential_manager_read_password_async
(
manager
,
account
,
NULL
,
purple_account_connect_got_password_cb
,
account
);
}
else
{
g_timeout_add_seconds
(
0
,
no_password_cb
,
account
);
}
}
void
purple_account_disconnect
(
PurpleAccount
*
account
)
{
GError
*
error
=
NULL
;
const
char
*
username
;
g_return_if_fail
(
PURPLE_IS_ACCOUNT
(
account
));
g_return_if_fail
(
!
purple_account_is_disconnecting
(
account
));
g_return_if_fail
(
!
purple_account_is_disconnected
(
account
));
username
=
purple_contact_info_get_username
(
PURPLE_CONTACT_INFO
(
account
));
purple_debug_info
(
"account"
,
"Disconnecting account %s (%p)
\n
"
,
username
?
username
:
"(null)"
,
account
);
account
->
disconnecting
=
TRUE
;
if
(
!
purple_connection_disconnect
(
account
->
gc
,
&
error
))
{
g_warning
(
"error while disconnecting account %s (%s): %s"
,
username
,
purple_account_get_protocol_id
(
account
),
(
error
!=
NULL
)
?
error
->
message
:
"unknown error"
);
g_clear_error
(
&
error
);
}
purple_account_set_connection
(
account
,
NULL
);
account
->
disconnecting
=
FALSE
;
}
gboolean
purple_account_is_disconnecting
(
PurpleAccount
*
account
)
{
g_return_val_if_fail
(
PURPLE_IS_ACCOUNT
(
account
),
TRUE
);
return
account
->
disconnecting
;
}
void
purple_account_request_close_with_account
(
PurpleAccount
*
account
)
{
PurpleNotificationManager
*
manager
=
NULL
;
g_return_if_fail
(
PURPLE_IS_ACCOUNT
(
account
));
manager
=
purple_notification_manager_get_default
();
purple_notification_manager_remove_with_account
(
manager
,
account
,
FALSE
);
}
void
purple_account_request_password
(
PurpleAccount
*
account
,
GCallback
ok_cb
,
GCallback
cancel_cb
,
void
*
user_data
)
{
gchar
*
primary
;
const
gchar
*
username
;
PurpleRequestFieldGroup
*
group
;
PurpleRequestField
*
field
;
PurpleRequestFields
*
fields
;
/* Close any previous password request windows */
purple_request_close_with_handle
(
account
);
username
=
purple_contact_info_get_username
(
PURPLE_CONTACT_INFO
(
account
));
primary
=
g_strdup_printf
(
_
(
"Enter password for %s (%s)"
),
username
,
purple_account_get_protocol_name
(
account
));
fields
=
purple_request_fields_new
();
group
=
purple_request_field_group_new
(
NULL
);
purple_request_fields_add_group
(
fields
,
group
);
field
=
purple_request_field_string_new
(
"password"
,
_
(
"Enter Password"
),
NULL
,
FALSE
);
purple_request_field_string_set_masked
(
field
,
TRUE
);
purple_request_field_set_required
(
field
,
TRUE
);
purple_request_field_group_add_field
(
group
,
field
);
field
=
purple_request_field_bool_new
(
"remember"
,
_
(
"Save password"
),
FALSE
);
purple_request_field_group_add_field
(
group
,
field
);
purple_request_fields
(
account
,
NULL
,
primary
,
NULL
,
fields
,
_
(
"OK"
),
ok_cb
,
_
(
"Cancel"
),
cancel_cb
,
purple_request_cpar_from_account
(
account
),
user_data
);
g_free
(
primary
);
}
void
purple_account_request_change_password
(
PurpleAccount
*
account
)
{
PurpleRequestFields
*
fields
;
PurpleRequestFieldGroup
*
group
;
PurpleRequestField
*
field
;
PurpleConnection
*
gc
;
PurpleProtocol
*
protocol
=
NULL
;
char
primary
[
256
];
g_return_if_fail
(
PURPLE_IS_ACCOUNT
(
account
));
g_return_if_fail
(
purple_account_is_connected
(
account
));
gc
=
purple_account_get_connection
(
account
);
if
(
gc
!=
NULL
)
protocol
=
purple_connection_get_protocol
(
gc
);
fields
=
purple_request_fields_new
();
group
=
purple_request_field_group_new
(
NULL
);
purple_request_fields_add_group
(
fields
,
group
);
field
=
purple_request_field_string_new
(
"password"
,
_
(
"Original password"
),
NULL
,
FALSE
);
purple_request_field_string_set_masked
(
field
,
TRUE
);
if
(
!
protocol
||
!
(
purple_protocol_get_options
(
protocol
)
&
OPT_PROTO_PASSWORD_OPTIONAL
))
purple_request_field_set_required
(
field
,
TRUE
);
purple_request_field_group_add_field
(
group
,
field
);
field
=
purple_request_field_string_new
(
"new_password_1"
,
_
(
"New password"
),
NULL
,
FALSE
);
purple_request_field_string_set_masked
(
field
,
TRUE
);
if
(
!
protocol
||
!
(
purple_protocol_get_options
(
protocol
)
&
OPT_PROTO_PASSWORD_OPTIONAL
))
purple_request_field_set_required
(
field
,
TRUE
);
purple_request_field_group_add_field
(
group
,
field
);
field
=
purple_request_field_string_new
(
"new_password_2"
,
_
(
"New password (again)"
),
NULL
,
FALSE
);
purple_request_field_string_set_masked
(
field
,
TRUE
);
if
(
!
protocol
||
!
(
purple_protocol_get_options
(
protocol
)
&
OPT_PROTO_PASSWORD_OPTIONAL
))
purple_request_field_set_required
(
field
,
TRUE
);
purple_request_field_group_add_field
(
group
,
field
);
g_snprintf
(
primary
,
sizeof
(
primary
),
_
(
"Change password for %s"
),
purple_contact_info_get_username
(
PURPLE_CONTACT_INFO
(
account
)));
/* I'm sticking this somewhere in the code: bologna */
purple_request_fields
(
purple_account_get_connection
(
account
),
NULL
,
primary
,
_
(
"Please enter your current password and your new "
"password."
),
fields
,
_
(
"OK"
),
G_CALLBACK
(
change_password_cb
),
_
(
"Cancel"
),
NULL
,
purple_request_cpar_from_account
(
account
),
account
);
}
void
purple_account_request_change_user_info
(
PurpleAccount
*
account
)
{
PurpleConnection
*
gc
;
char
primary
[
256
];
g_return_if_fail
(
PURPLE_IS_ACCOUNT
(
account
));
g_return_if_fail
(
purple_account_is_connected
(
account
));
gc
=
purple_account_get_connection
(
account
);
g_snprintf
(
primary
,
sizeof
(
primary
),
_
(
"Change user information for %s"
),
purple_contact_info_get_username
(
PURPLE_CONTACT_INFO
(
account
)));
purple_request_input
(
gc
,
_
(
"Set User Info"
),
primary
,
NULL
,
purple_account_get_user_info
(
account
),
TRUE
,
FALSE
,
((
gc
!=
NULL
)
&&
(
purple_connection_get_flags
(
gc
)
&
PURPLE_CONNECTION_FLAG_HTML
)
?
"html"
:
NULL
),
_
(
"Save"
),
G_CALLBACK
(
set_user_info_cb
),
_
(
"Cancel"
),
NULL
,
purple_request_cpar_from_account
(
account
),
account
);
}
void
purple_account_set_user_info
(
PurpleAccount
*
account
,
const
char
*
user_info
)
{
g_return_if_fail
(
PURPLE_IS_ACCOUNT
(
account
));
g_free
(
account
->
user_info
);
account
->
user_info
=
g_strdup
(
user_info
);
g_object_notify_by_pspec
(
G_OBJECT
(
account
),
properties
[
PROP_USER_INFO
]);
purple_accounts_schedule_save
();
}
void
purple_account_set_buddy_icon_path
(
PurpleAccount
*
account
,
const
char
*
path
)
{
g_return_if_fail
(
PURPLE_IS_ACCOUNT
(
account
));
g_free
(
account
->
buddy_icon_path
);
account
->
buddy_icon_path
=
g_strdup
(
path
);
g_object_notify_by_pspec
(
G_OBJECT
(
account
),
properties
[
PROP_BUDDY_ICON_PATH
]);
purple_accounts_schedule_save
();
}
void
purple_account_set_protocol_id
(
PurpleAccount
*
account
,
const
char
*
protocol_id
)
{
g_return_if_fail
(
PURPLE_IS_ACCOUNT
(
account
));
g_return_if_fail
(
protocol_id
!=
NULL
);
g_free
(
account
->
protocol_id
);
account
->
protocol_id
=
g_strdup
(
protocol_id
);
g_object_notify_by_pspec
(
G_OBJECT
(
account
),
properties
[
PROP_PROTOCOL_ID
]);
purple_accounts_schedule_save
();
}
void
purple_account_set_connection
(
PurpleAccount
*
account
,
PurpleConnection
*
gc
)
{
g_return_if_fail
(
PURPLE_IS_ACCOUNT
(
account
));
if
(
g_set_object
(
&
account
->
gc
,
gc
))
{
g_object_notify_by_pspec
(
G_OBJECT
(
account
),
properties
[
PROP_CONNECTION
]);
}
}
void
purple_account_set_remember_password
(
PurpleAccount
*
account
,
gboolean
value
)
{
g_return_if_fail
(
PURPLE_IS_ACCOUNT
(
account
));
account
->
remember_pass
=
value
;
g_object_notify_by_pspec
(
G_OBJECT
(
account
),
properties
[
PROP_REMEMBER_PASSWORD
]);
purple_accounts_schedule_save
();
}
void
purple_account_set_enabled
(
PurpleAccount
*
account
,
gboolean
value
)
{
PurpleConnection
*
gc
;
gboolean
was_enabled
=
FALSE
;
g_return_if_fail
(
PURPLE_IS_ACCOUNT
(
account
));
was_enabled
=
account
->
enabled
;
account
->
enabled
=
value
;
if
(
was_enabled
!=
value
)
{
g_object_notify_by_pspec
(
G_OBJECT
(
account
),
properties
[
PROP_ENABLED
]);
}
gc
=
purple_account_get_connection
(
account
);
if
((
gc
!=
NULL
)
&&
(
_purple_connection_wants_to_die
(
gc
)))
return
;
if
(
value
&&
purple_presence_is_online
(
account
->
presence
))
purple_account_connect
(
account
);
else
if
(
!
value
&&
!
purple_account_is_disconnected
(
account
))
purple_account_disconnect
(
account
);
purple_accounts_schedule_save
();
}
void
purple_account_set_proxy_info
(
PurpleAccount
*
account
,
PurpleProxyInfo
*
info
)
{
g_return_if_fail
(
PURPLE_IS_ACCOUNT
(
account
));
if
(
g_set_object
(
&
account
->
proxy_info
,
info
))
{
g_object_notify_by_pspec
(
G_OBJECT
(
account
),
properties
[
PROP_PROXY_INFO
]);
purple_accounts_schedule_save
();
}
}
void
purple_account_set_status_types
(
PurpleAccount
*
account
,
GList
*
status_types
)
{
g_return_if_fail
(
PURPLE_IS_ACCOUNT
(
account
));
/* Out with the old... */
g_list_free_full
(
account
->
status_types
,
(
GDestroyNotify
)
purple_status_type_destroy
);
/* In with the new... */
account
->
status_types
=
status_types
;
}
void
purple_account_set_status
(
PurpleAccount
*
account
,
const
char
*
status_id
,
gboolean
active
,
...)
{
GHashTable
*
attrs
;
va_list
args
;
va_start
(
args
,
active
);
attrs
=
purple_attrs_from_vargs
(
args
);
purple_account_set_status_attrs
(
account
,
status_id
,
active
,
attrs
);
g_hash_table_destroy
(
attrs
);
va_end
(
args
);
}
void
purple_account_set_status_attrs
(
PurpleAccount
*
account
,
const
char
*
status_id
,
gboolean
active
,
GHashTable
*
attrs
)
{
PurpleStatus
*
status
;
g_return_if_fail
(
PURPLE_IS_ACCOUNT
(
account
));
g_return_if_fail
(
status_id
!=
NULL
);
status
=
purple_account_get_status
(
account
,
status_id
);
if
(
status
==
NULL
)
{
PurpleContactInfo
*
info
=
PURPLE_CONTACT_INFO
(
account
);
purple_debug_error
(
"account"
,
"Invalid status ID '%s' for account %s (%s)
\n
"
,
status_id
,
purple_contact_info_get_username
(
info
),
purple_account_get_protocol_id
(
account
));
return
;
}
if
(
active
||
purple_status_is_independent
(
status
))
{
purple_status_set_active_with_attributes
(
status
,
active
,
attrs
);
}
/*
* Our current statuses are saved to accounts.xml (so that when we
* reconnect, we go back to the previous status).
*/
purple_accounts_schedule_save
();
}
void
purple_account_clear_settings
(
PurpleAccount
*
account
)
{
g_return_if_fail
(
PURPLE_IS_ACCOUNT
(
account
));
g_hash_table_destroy
(
account
->
settings
);
account
->
settings
=
g_hash_table_new_full
(
g_str_hash
,
g_str_equal
,
g_free
,
delete_setting
);
}
void
purple_account_set_int
(
PurpleAccount
*
account
,
const
char
*
name
,
int
value
)
{
PurpleAccountSetting
*
setting
;
g_return_if_fail
(
PURPLE_IS_ACCOUNT
(
account
));
g_return_if_fail
(
name
!=
NULL
);
setting
=
g_new0
(
PurpleAccountSetting
,
1
);
g_value_init
(
&
setting
->
value
,
G_TYPE_INT
);
g_value_set_int
(
&
setting
->
value
,
value
);
g_hash_table_insert
(
account
->
settings
,
g_strdup
(
name
),
setting
);
purple_account_setting_changed_emit
(
account
,
name
);
purple_accounts_schedule_save
();
}
void
purple_account_set_string
(
PurpleAccount
*
account
,
const
char
*
name
,
const
char
*
value
)
{
PurpleAccountSetting
*
setting
;
g_return_if_fail
(
PURPLE_IS_ACCOUNT
(
account
));
g_return_if_fail
(
name
!=
NULL
);
setting
=
g_new0
(
PurpleAccountSetting
,
1
);
g_value_init
(
&
setting
->
value
,
G_TYPE_STRING
);
g_value_set_string
(
&
setting
->
value
,
value
);
g_hash_table_insert
(
account
->
settings
,
g_strdup
(
name
),
setting
);
purple_account_setting_changed_emit
(
account
,
name
);
purple_accounts_schedule_save
();
}
void
purple_account_set_bool
(
PurpleAccount
*
account
,
const
char
*
name
,
gboolean
value
)
{
PurpleAccountSetting
*
setting
;
g_return_if_fail
(
PURPLE_IS_ACCOUNT
(
account
));
g_return_if_fail
(
name
!=
NULL
);
setting
=
g_new0
(
PurpleAccountSetting
,
1
);
g_value_init
(
&
setting
->
value
,
G_TYPE_BOOLEAN
);
g_value_set_boolean
(
&
setting
->
value
,
value
);
g_hash_table_insert
(
account
->
settings
,
g_strdup
(
name
),
setting
);
purple_account_setting_changed_emit
(
account
,
name
);
purple_accounts_schedule_save
();
}
gboolean
purple_account_is_connected
(
PurpleAccount
*
account
)
{
return
(
purple_account_get_state
(
account
)
==
PURPLE_CONNECTION_STATE_CONNECTED
);
}
gboolean
purple_account_is_connecting
(
PurpleAccount
*
account
)
{
return
(
purple_account_get_state
(
account
)
==
PURPLE_CONNECTION_STATE_CONNECTING
);
}
gboolean
purple_account_is_disconnected
(
PurpleAccount
*
account
)
{
return
(
purple_account_get_state
(
account
)
==
PURPLE_CONNECTION_STATE_DISCONNECTED
);
}
const
char
*
purple_account_get_user_info
(
PurpleAccount
*
account
)
{
g_return_val_if_fail
(
PURPLE_IS_ACCOUNT
(
account
),
NULL
);
return
account
->
user_info
;
}
const
char
*
purple_account_get_buddy_icon_path
(
PurpleAccount
*
account
)
{
g_return_val_if_fail
(
PURPLE_IS_ACCOUNT
(
account
),
NULL
);
return
account
->
buddy_icon_path
;
}
const
char
*
purple_account_get_protocol_id
(
PurpleAccount
*
account
)
{
g_return_val_if_fail
(
PURPLE_IS_ACCOUNT
(
account
),
NULL
);
return
account
->
protocol_id
;
}
PurpleProtocol
*
purple_account_get_protocol
(
PurpleAccount
*
account
)
{
PurpleProtocolManager
*
manager
=
NULL
;
g_return_val_if_fail
(
PURPLE_IS_ACCOUNT
(
account
),
NULL
);
manager
=
purple_protocol_manager_get_default
();
return
purple_protocol_manager_find
(
manager
,
account
->
protocol_id
);
}
const
char
*
purple_account_get_protocol_name
(
PurpleAccount
*
account
)
{
PurpleProtocol
*
p
;
g_return_val_if_fail
(
PURPLE_IS_ACCOUNT
(
account
),
NULL
);
p
=
purple_account_get_protocol
(
account
);
return
(
p
&&
purple_protocol_get_name
(
p
)
?
_
(
purple_protocol_get_name
(
p
))
:
_
(
"Unknown"
));
}
PurpleConnection
*
purple_account_get_connection
(
PurpleAccount
*
account
)
{
g_return_val_if_fail
(
PURPLE_IS_ACCOUNT
(
account
),
NULL
);
return
account
->
gc
;
}
gboolean
purple_account_get_remember_password
(
PurpleAccount
*
account
)
{
g_return_val_if_fail
(
PURPLE_IS_ACCOUNT
(
account
),
FALSE
);
return
account
->
remember_pass
;
}
gboolean
purple_account_get_enabled
(
PurpleAccount
*
account
)
{
g_return_val_if_fail
(
PURPLE_IS_ACCOUNT
(
account
),
FALSE
);
return
account
->
enabled
;
}
PurpleProxyInfo
*
purple_account_get_proxy_info
(
PurpleAccount
*
account
)
{
g_return_val_if_fail
(
PURPLE_IS_ACCOUNT
(
account
),
NULL
);
return
account
->
proxy_info
;
}
PurpleStatus
*
purple_account_get_active_status
(
PurpleAccount
*
account
)
{
g_return_val_if_fail
(
PURPLE_IS_ACCOUNT
(
account
),
NULL
);
return
purple_presence_get_active_status
(
account
->
presence
);
}
PurpleStatus
*
purple_account_get_status
(
PurpleAccount
*
account
,
const
char
*
status_id
)
{
g_return_val_if_fail
(
PURPLE_IS_ACCOUNT
(
account
),
NULL
);
g_return_val_if_fail
(
status_id
!=
NULL
,
NULL
);
return
purple_presence_get_status
(
account
->
presence
,
status_id
);
}
PurpleStatusType
*
purple_account_get_status_type
(
PurpleAccount
*
account
,
const
char
*
id
)
{
GList
*
l
;
g_return_val_if_fail
(
PURPLE_IS_ACCOUNT
(
account
),
NULL
);
g_return_val_if_fail
(
id
!=
NULL
,
NULL
);
for
(
l
=
purple_account_get_status_types
(
account
);
l
!=
NULL
;
l
=
l
->
next
)
{
PurpleStatusType
*
status_type
=
(
PurpleStatusType
*
)
l
->
data
;
if
(
purple_strequal
(
purple_status_type_get_id
(
status_type
),
id
))
return
status_type
;
}
return
NULL
;
}
PurpleStatusType
*
purple_account_get_status_type_with_primitive
(
PurpleAccount
*
account
,
PurpleStatusPrimitive
primitive
)
{
GList
*
l
;
g_return_val_if_fail
(
PURPLE_IS_ACCOUNT
(
account
),
NULL
);
for
(
l
=
purple_account_get_status_types
(
account
);
l
!=
NULL
;
l
=
l
->
next
)
{
PurpleStatusType
*
status_type
=
(
PurpleStatusType
*
)
l
->
data
;
if
(
purple_status_type_get_primitive
(
status_type
)
==
primitive
)
return
status_type
;
}
return
NULL
;
}
PurplePresence
*
purple_account_get_presence
(
PurpleAccount
*
account
)
{
g_return_val_if_fail
(
PURPLE_IS_ACCOUNT
(
account
),
NULL
);
return
account
->
presence
;
}
gboolean
purple_account_is_status_active
(
PurpleAccount
*
account
,
const
char
*
status_id
)
{
g_return_val_if_fail
(
PURPLE_IS_ACCOUNT
(
account
),
FALSE
);
g_return_val_if_fail
(
status_id
!=
NULL
,
FALSE
);
return
purple_presence_is_status_active
(
account
->
presence
,
status_id
);
}
GList
*
purple_account_get_status_types
(
PurpleAccount
*
account
)
{
g_return_val_if_fail
(
PURPLE_IS_ACCOUNT
(
account
),
NULL
);
return
account
->
status_types
;
}
int
purple_account_get_int
(
PurpleAccount
*
account
,
const
char
*
name
,
int
default_value
)
{
PurpleAccountSetting
*
setting
;
g_return_val_if_fail
(
PURPLE_IS_ACCOUNT
(
account
),
default_value
);
g_return_val_if_fail
(
name
!=
NULL
,
default_value
);
setting
=
g_hash_table_lookup
(
account
->
settings
,
name
);
if
(
setting
==
NULL
)
return
default_value
;
g_return_val_if_fail
(
G_VALUE_HOLDS_INT
(
&
setting
->
value
),
default_value
);
return
g_value_get_int
(
&
setting
->
value
);
}
const
char
*
purple_account_get_string
(
PurpleAccount
*
account
,
const
char
*
name
,
const
char
*
default_value
)
{
PurpleAccountSetting
*
setting
;
g_return_val_if_fail
(
PURPLE_IS_ACCOUNT
(
account
),
default_value
);
g_return_val_if_fail
(
name
!=
NULL
,
default_value
);
setting
=
g_hash_table_lookup
(
account
->
settings
,
name
);
if
(
setting
==
NULL
)
return
default_value
;
g_return_val_if_fail
(
G_VALUE_HOLDS_STRING
(
&
setting
->
value
),
default_value
);
return
g_value_get_string
(
&
setting
->
value
);
}
gboolean
purple_account_get_bool
(
PurpleAccount
*
account
,
const
char
*
name
,
gboolean
default_value
)
{
PurpleAccountSetting
*
setting
;
g_return_val_if_fail
(
PURPLE_IS_ACCOUNT
(
account
),
default_value
);
g_return_val_if_fail
(
name
!=
NULL
,
default_value
);
setting
=
g_hash_table_lookup
(
account
->
settings
,
name
);
if
(
setting
==
NULL
)
return
default_value
;
g_return_val_if_fail
(
G_VALUE_HOLDS_BOOLEAN
(
&
setting
->
value
),
default_value
);
return
g_value_get_boolean
(
&
setting
->
value
);
}
void
purple_account_add_buddy
(
PurpleAccount
*
account
,
PurpleBuddy
*
buddy
,
const
char
*
message
)
{
PurpleProtocol
*
protocol
=
NULL
;
PurpleConnection
*
gc
;
g_return_if_fail
(
PURPLE_IS_ACCOUNT
(
account
));
g_return_if_fail
(
PURPLE_IS_BUDDY
(
buddy
));
gc
=
purple_account_get_connection
(
account
);
if
(
gc
!=
NULL
)
protocol
=
purple_connection_get_protocol
(
gc
);
if
(
PURPLE_IS_PROTOCOL_SERVER
(
protocol
))
{
PurpleGroup
*
group
=
purple_buddy_get_group
(
buddy
);
purple_protocol_server_add_buddy
(
PURPLE_PROTOCOL_SERVER
(
protocol
),
gc
,
buddy
,
group
,
message
);
}
}
void
purple_account_add_buddies
(
PurpleAccount
*
account
,
GList
*
buddies
,
const
char
*
message
)
{
PurpleProtocol
*
protocol
=
NULL
;
PurpleConnection
*
gc
=
purple_account_get_connection
(
account
);
if
(
gc
!=
NULL
)
protocol
=
purple_connection_get_protocol
(
gc
);
if
(
protocol
)
{
GList
*
groups
;
/* Make a list of what group each buddy is in */
groups
=
g_list_copy_deep
(
buddies
,
(
GCopyFunc
)(
GCallback
)
purple_buddy_get_group
,
NULL
);
if
(
PURPLE_IS_PROTOCOL_SERVER
(
protocol
))
{
purple_protocol_server_add_buddies
(
PURPLE_PROTOCOL_SERVER
(
protocol
),
gc
,
buddies
,
groups
,
message
);
}
g_list_free
(
groups
);
}
}
void
purple_account_remove_buddy
(
PurpleAccount
*
account
,
PurpleBuddy
*
buddy
,
PurpleGroup
*
group
)
{
PurpleProtocol
*
protocol
=
NULL
;
PurpleConnection
*
gc
=
purple_account_get_connection
(
account
);
if
(
gc
!=
NULL
)
protocol
=
purple_connection_get_protocol
(
gc
);
if
(
PURPLE_IS_PROTOCOL_SERVER
(
protocol
))
{
purple_protocol_server_remove_buddy
(
PURPLE_PROTOCOL_SERVER
(
protocol
),
gc
,
buddy
,
group
);
}
}
void
purple_account_remove_buddies
(
PurpleAccount
*
account
,
GList
*
buddies
,
GList
*
groups
)
{
PurpleProtocol
*
protocol
=
NULL
;
PurpleConnection
*
gc
=
purple_account_get_connection
(
account
);
if
(
gc
!=
NULL
)
protocol
=
purple_connection_get_protocol
(
gc
);
if
(
PURPLE_IS_PROTOCOL_SERVER
(
protocol
))
{
purple_protocol_server_remove_buddies
(
PURPLE_PROTOCOL_SERVER
(
protocol
),
gc
,
buddies
,
groups
);
}
}
void
purple_account_remove_group
(
PurpleAccount
*
account
,
PurpleGroup
*
group
)
{
PurpleProtocol
*
protocol
=
NULL
;
PurpleConnection
*
gc
=
purple_account_get_connection
(
account
);
if
(
gc
!=
NULL
)
protocol
=
purple_connection_get_protocol
(
gc
);
if
(
PURPLE_IS_PROTOCOL_SERVER
(
protocol
))
{
purple_protocol_server_remove_group
(
PURPLE_PROTOCOL_SERVER
(
protocol
),
gc
,
group
);
}
}
void
purple_account_change_password
(
PurpleAccount
*
account
,
const
char
*
orig_pw
,
const
char
*
new_pw
)
{
PurpleCredentialManager
*
manager
=
NULL
;
PurpleProtocol
*
protocol
=
NULL
;
PurpleConnection
*
gc
=
purple_account_get_connection
(
account
);
/* just going to fire and forget this for now as not many protocols even
* implement the change password stuff.
*/
manager
=
purple_credential_manager_get_default
();
purple_credential_manager_write_password_async
(
manager
,
account
,
new_pw
,
NULL
,
NULL
,
NULL
);
if
(
gc
!=
NULL
)
protocol
=
purple_connection_get_protocol
(
gc
);
if
(
PURPLE_IS_PROTOCOL_SERVER
(
protocol
))
{
purple_protocol_server_change_passwd
(
PURPLE_PROTOCOL_SERVER
(
protocol
),
gc
,
orig_pw
,
new_pw
);
}
}
gboolean
purple_account_supports_offline_message
(
PurpleAccount
*
account
,
PurpleBuddy
*
buddy
)
{
PurpleConnection
*
gc
;
PurpleProtocol
*
protocol
=
NULL
;
g_return_val_if_fail
(
PURPLE_IS_ACCOUNT
(
account
),
FALSE
);
g_return_val_if_fail
(
PURPLE_IS_BUDDY
(
buddy
),
FALSE
);
gc
=
purple_account_get_connection
(
account
);
if
(
gc
==
NULL
)
{
return
FALSE
;
}
protocol
=
purple_connection_get_protocol
(
gc
);
if
(
!
protocol
)
{
return
FALSE
;
}
return
purple_protocol_client_offline_message
(
PURPLE_PROTOCOL_CLIENT
(
protocol
),
buddy
);
}
const
PurpleConnectionErrorInfo
*
purple_account_get_current_error
(
PurpleAccount
*
account
)
{
g_return_val_if_fail
(
PURPLE_IS_ACCOUNT
(
account
),
NULL
);
return
account
->
current_error
;
}
void
purple_account_clear_current_error
(
PurpleAccount
*
account
)
{
_purple_account_set_current_error
(
account
,
NULL
);
}
void
purple_account_set_require_password
(
PurpleAccount
*
account
,
gboolean
require_password
)
{
gboolean
old
=
FALSE
;
g_return_if_fail
(
PURPLE_IS_ACCOUNT
(
account
));
old
=
account
->
require_password
;
account
->
require_password
=
require_password
;
if
(
old
!=
require_password
)
{
g_object_notify_by_pspec
(
G_OBJECT
(
account
),
properties
[
PROP_REQUIRE_PASSWORD
]);
}
}
gboolean
purple_account_get_require_password
(
PurpleAccount
*
account
)
{
g_return_val_if_fail
(
PURPLE_IS_ACCOUNT
(
account
),
FALSE
);
return
account
->
require_password
;
}
void
purple_account_freeze_notify_settings
(
PurpleAccount
*
account
)
{
g_return_if_fail
(
PURPLE_IS_ACCOUNT
(
account
));
G_LOCK
(
setting_notify_lock
);
if
(
account
->
freeze_queue
==
NULL
)
{
account
->
freeze_queue
=
g_slice_new0
(
PurpleAccountSettingFreezeQueue
);
}
account
->
freeze_queue
->
ref_count
++
;
G_UNLOCK
(
setting_notify_lock
);
}
void
purple_account_thaw_notify_settings
(
PurpleAccount
*
account
)
{
GSList
*
names
=
NULL
;
g_return_if_fail
(
PURPLE_IS_ACCOUNT
(
account
));
G_LOCK
(
setting_notify_lock
);
if
(
G_UNLIKELY
(
account
->
freeze_queue
->
ref_count
==
0
))
{
G_UNLOCK
(
setting_notify_lock
);
g_critical
(
"purple_account_settings_thaw_notify called for account %s "
"(%s) when not frozen"
,
purple_contact_info_get_username
(
PURPLE_CONTACT_INFO
(
account
)),
purple_account_get_protocol_id
(
account
));
return
;
}
account
->
freeze_queue
->
ref_count
--
;
if
(
account
->
freeze_queue
->
ref_count
>
0
)
{
G_UNLOCK
(
setting_notify_lock
);
return
;
}
/* This was the last ref, so fire off the signals. */
names
=
account
->
freeze_queue
->
names
;
while
(
names
!=
NULL
)
{
char
*
name
=
names
->
data
;
g_signal_emit
(
account
,
signals
[
SIG_SETTING_CHANGED
],
g_quark_from_string
(
name
),
name
);
names
=
g_slist_delete_link
(
names
,
names
);
g_free
(
name
);
}
account
->
freeze_queue
->
names
=
names
;
purple_account_free_notify_settings
(
account
);
G_UNLOCK
(
setting_notify_lock
);
}