pidgin/pidgin
Clone
Summary
Browse
Changes
Graph
Fix memory leak when creating an IRCv3 account
default
tip
16 hours ago, Markus Fischer
96d1ed6df91c
Fix memory leak when creating an IRCv3 account
Testing Done:
Created a new IRCv3 account while running in valgrind.
Reviewed at https://reviews.imfreedom.org/r/3262/
/*
* Purple - Internet Messaging Library
* Copyright (C) Pidgin Developers <devel@pidgin.im>
*
* 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 library 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 library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this library; if not, see <https://www.gnu.org/licenses/>.
*/
#include
<glib/gi18n-lib.h>
#include
"purpleircv3protocol.h"
#include
"purpleircv3connection.h"
#include
"purpleircv3core.h"
#include
"purpleircv3protocolconversation.h"
/******************************************************************************
* Callbacks
*****************************************************************************/
static
void
purple_ircv3_protocol_can_reach_cb
(
GObject
*
self
,
GAsyncResult
*
result
,
gpointer
data
)
{
GError
*
error
=
NULL
;
GTask
*
task
=
data
;
gboolean
can_reach
=
FALSE
;
/* task and result share a cancellable, so either can be used here. */
if
(
g_task_return_error_if_cancelled
(
task
))
{
g_clear_object
(
&
task
);
return
;
}
can_reach
=
g_network_monitor_can_reach_finish
(
G_NETWORK_MONITOR
(
self
),
result
,
&
error
);
if
(
error
!=
NULL
)
{
g_task_return_error
(
task
,
error
);
}
else
if
(
!
can_reach
)
{
g_task_return_new_error
(
task
,
PURPLE_IRCV3_DOMAIN
,
0
,
_
(
"Unknown network error."
));
}
else
{
g_task_return_boolean
(
task
,
TRUE
);
}
g_clear_object
(
&
task
);
}
/******************************************************************************
* PurpleProtocol Implementation
*****************************************************************************/
static
GList
*
purple_ircv3_protocol_get_user_splits
(
G_GNUC_UNUSED
PurpleProtocol
*
protocol
)
{
PurpleAccountUserSplit
*
split
=
NULL
;
GList
*
splits
=
NULL
;
split
=
purple_account_user_split_new
(
_
(
"Server"
),
PURPLE_IRCV3_DEFAULT_SERVER
,
'@'
);
splits
=
g_list_append
(
splits
,
split
);
return
splits
;
}
static
GList
*
purple_ircv3_protocol_get_account_options
(
G_GNUC_UNUSED
PurpleProtocol
*
protocol
)
{
PurpleAccountOption
*
option
;
GList
*
options
=
NULL
;
option
=
purple_account_option_int_new
(
_
(
"Port"
),
"port"
,
PURPLE_IRCV3_DEFAULT_TLS_PORT
);
options
=
g_list_append
(
options
,
option
);
option
=
purple_account_option_bool_new
(
_
(
"Use TLS"
),
"use-tls"
,
TRUE
);
options
=
g_list_append
(
options
,
option
);
option
=
purple_account_option_string_new
(
_
(
"Server password"
),
"server-password"
,
""
);
purple_account_option_string_set_masked
(
option
,
TRUE
);
options
=
g_list_append
(
options
,
option
);
option
=
purple_account_option_string_new
(
_
(
"Ident name"
),
"ident"
,
""
);
options
=
g_list_append
(
options
,
option
);
option
=
purple_account_option_string_new
(
_
(
"Real name"
),
"real-name"
,
""
);
options
=
g_list_append
(
options
,
option
);
option
=
purple_account_option_string_new
(
_
(
"SASL login name"
),
"sasl-login-name"
,
""
);
options
=
g_list_append
(
options
,
option
);
option
=
purple_account_option_string_new
(
_
(
"SASL mechanisms"
),
"sasl-mechanisms"
,
""
);
options
=
g_list_append
(
options
,
option
);
option
=
purple_account_option_bool_new
(
_
(
"Allow plaintext SASL auth over "
"unencrypted connection"
),
"plain-sasl-in-clear"
,
FALSE
);
options
=
g_list_append
(
options
,
option
);
option
=
purple_account_option_int_new
(
_
(
"Seconds between sending "
"messages"
),
"rate-limit-interval"
,
2
);
options
=
g_list_append
(
options
,
option
);
option
=
purple_account_option_int_new
(
_
(
"Maximum messages to send at "
"once"
),
"rate-limit-burst"
,
5
);
options
=
g_list_append
(
options
,
option
);
return
options
;
}
static
PurpleConnection
*
purple_ircv3_protocol_create_connection
(
PurpleProtocol
*
protocol
,
PurpleAccount
*
account
,
const
char
*
password
,
GError
**
error
)
{
const
char
*
username
=
NULL
;
g_return_val_if_fail
(
PURPLE_IS_PROTOCOL
(
protocol
),
NULL
);
g_return_val_if_fail
(
PURPLE_IS_ACCOUNT
(
account
),
NULL
);
/* Make sure the username (which includes the servername via usersplits),
* does not contain any whitespace.
*/
username
=
purple_contact_info_get_username
(
PURPLE_CONTACT_INFO
(
account
));
if
(
strpbrk
(
username
,
"
\t\v\r\n
"
)
!=
NULL
)
{
g_set_error
(
error
,
PURPLE_CONNECTION_ERROR
,
PURPLE_CONNECTION_ERROR_INVALID_SETTINGS
,
_
(
"IRC nick and server may not contain whitespace"
));
return
NULL
;
}
return
g_object_new
(
PURPLE_IRCV3_TYPE_CONNECTION
,
"protocol"
,
protocol
,
"account"
,
account
,
"password"
,
password
,
NULL
);
}
static
void
purple_ircv3_protocol_can_connect_async
(
PurpleProtocol
*
protocol
,
PurpleAccount
*
account
,
GCancellable
*
cancellable
,
GAsyncReadyCallback
callback
,
gpointer
data
)
{
GNetworkMonitor
*
monitor
=
NULL
;
GSocketConnectable
*
connectable
=
NULL
;
GStrv
parts
=
NULL
;
GTask
*
task
=
NULL
;
const
char
*
username
=
NULL
;
gint
port
=
0
;
task
=
g_task_new
(
protocol
,
cancellable
,
callback
,
data
);
monitor
=
g_network_monitor_get_default
();
username
=
purple_contact_info_get_username
(
PURPLE_CONTACT_INFO
(
account
));
parts
=
g_strsplit
(
username
,
"@"
,
2
);
port
=
purple_account_get_int
(
account
,
"port"
,
PURPLE_IRCV3_DEFAULT_TLS_PORT
);
connectable
=
g_network_address_new
(
parts
[
1
],
(
guint16
)
port
);
g_strfreev
(
parts
);
g_network_monitor_can_reach_async
(
monitor
,
connectable
,
cancellable
,
purple_ircv3_protocol_can_reach_cb
,
task
);
g_clear_object
(
&
connectable
);
}
static
gboolean
purple_ircv3_protocol_can_connect_finish
(
G_GNUC_UNUSED
PurpleProtocol
*
protocol
,
GAsyncResult
*
result
,
GError
**
error
)
{
return
g_task_propagate_boolean
(
G_TASK
(
result
),
error
);
}
/******************************************************************************
* GObject Implementation
*****************************************************************************/
G_DEFINE_DYNAMIC_TYPE_EXTENDED
(
PurpleIRCv3Protocol
,
purple_ircv3_protocol
,
PURPLE_TYPE_PROTOCOL
,
0
,
G_IMPLEMENT_INTERFACE_DYNAMIC
(
PURPLE_TYPE_PROTOCOL_CONVERSATION
,
purple_ircv3_protocol_conversation_init
))
static
void
purple_ircv3_protocol_init
(
G_GNUC_UNUSED
PurpleIRCv3Protocol
*
protocol
)
{
}
static
void
purple_ircv3_protocol_class_finalize
(
G_GNUC_UNUSED
PurpleIRCv3ProtocolClass
*
klass
)
{
}
static
void
purple_ircv3_protocol_class_init
(
PurpleIRCv3ProtocolClass
*
klass
)
{
PurpleProtocolClass
*
protocol_class
=
PURPLE_PROTOCOL_CLASS
(
klass
);
protocol_class
->
get_user_splits
=
purple_ircv3_protocol_get_user_splits
;
protocol_class
->
get_account_options
=
purple_ircv3_protocol_get_account_options
;
protocol_class
->
create_connection
=
purple_ircv3_protocol_create_connection
;
protocol_class
->
can_connect_async
=
purple_ircv3_protocol_can_connect_async
;
protocol_class
->
can_connect_finish
=
purple_ircv3_protocol_can_connect_finish
;
}
/******************************************************************************
* GObject Implementation
*****************************************************************************/
void
purple_ircv3_protocol_register
(
GPluginNativePlugin
*
plugin
)
{
purple_ircv3_protocol_register_type
(
G_TYPE_MODULE
(
plugin
));
}
PurpleProtocol
*
purple_ircv3_protocol_new
(
void
)
{
return
g_object_new
(
PURPLE_IRCV3_TYPE_PROTOCOL
,
"id"
,
"prpl-ircv3"
,
"name"
,
"IRCv3"
,
"description"
,
_
(
"Version 3 of Internet Relay Chat (IRC)."
),
"icon-name"
,
"im-ircv3"
,
"icon-resource-path"
,
"/im/pidgin/libpurple/ircv3/icons"
,
"options"
,
OPT_PROTO_CHAT_TOPIC
|
OPT_PROTO_PASSWORD_OPTIONAL
|
OPT_PROTO_SLASH_COMMANDS_NATIVE
,
NULL
);
}