pidgin/pidgin

7668d023ae05
Parents 7bd5bff547b4
Children 613d42be784e
Update the IRCv3 protocol plugin to the new connection setup

Testing Done:
Connected and disconnected an IRCv3 account and verified that it worked and that there were no `g_warnings`.

Reviewed at https://reviews.imfreedom.org/r/2003/
--- a/libpurple/protocols/ircv3/purpleircv3connection.c Mon Oct 31 22:52:24 2022 -0500
+++ b/libpurple/protocols/ircv3/purpleircv3connection.c Mon Oct 31 23:00:12 2022 -0500
@@ -25,7 +25,6 @@
enum {
PROP_0,
- PROP_ACCOUNT,
PROP_CANCELLABLE,
PROP_CAPABILITIES,
N_PROPERTIES,
@@ -33,10 +32,7 @@
static GParamSpec *properties[N_PROPERTIES] = {NULL, };
struct _PurpleIRCv3Connection {
- GObject parent;
-
- GError *validate_error;
- PurpleAccount *account;
+ PurpleConnection parent;
GSocketConnection *connection;
GCancellable *cancellable;
@@ -52,42 +48,32 @@
};
G_DEFINE_DYNAMIC_TYPE(PurpleIRCv3Connection, purple_ircv3_connection,
- G_TYPE_OBJECT)
+ PURPLE_TYPE_CONNECTION)
/******************************************************************************
* Helpers
*****************************************************************************/
static void
-purple_ircv3_connection_set_account(PurpleIRCv3Connection *connection,
- PurpleAccount *account)
-{
- g_return_if_fail(PURPLE_IRCV3_IS_CONNECTION(connection));
-
- if(g_set_object(&connection->account, account)) {
- g_object_notify_by_pspec(G_OBJECT(connection),
- properties[PROP_ACCOUNT]);
- }
-}
-
-static void
purple_ircv3_connection_send_user_command(PurpleIRCv3Connection *connection) {
- PurpleConnection *purple_connection = NULL;
+ PurpleAccount *account = NULL;
const char *identname = NULL;
const char *nickname = NULL;
const char *realname = NULL;
- purple_connection = purple_account_get_connection(connection->account);
- nickname = purple_connection_get_display_name(purple_connection);
+ nickname =
+ purple_connection_get_display_name(PURPLE_CONNECTION(connection));
+
+ account = purple_connection_get_account(PURPLE_CONNECTION(connection));
/* The stored value could be an empty string, so pass a default of empty
* string and then if it was empty, set our correct fallback.
*/
- identname = purple_account_get_string(connection->account, "ident", "");
+ identname = purple_account_get_string(account, "ident", "");
if(identname == NULL || *identname == '\0') {
identname = nickname;
}
- realname = purple_account_get_string(connection->account, "real-name", "");
+ realname = purple_account_get_string(account, "real-name", "");
if(realname == NULL || *realname == '\0') {
realname = nickname;
}
@@ -98,12 +84,10 @@
static void
purple_ircv3_connection_send_nick_command(PurpleIRCv3Connection *connection) {
- PurpleConnection *purple_connection = NULL;
const char *nickname = NULL;
- purple_connection = purple_account_get_connection(connection->account);
-
- nickname = purple_connection_get_display_name(purple_connection);
+ nickname =
+ purple_connection_get_display_name(PURPLE_CONNECTION(connection));
purple_ircv3_connection_writef(connection, "NICK %s", nickname);
}
@@ -115,8 +99,7 @@
purple_ircv3_connection_read_cb(GObject *source, GAsyncResult *result,
gpointer data)
{
- PurpleIRCv3Connection *connection = NULL;
- PurpleConnection *purple_connection = data;
+ PurpleIRCv3Connection *connection = data;
GDataInputStream *istream = G_DATA_INPUT_STREAM(source);
GError *error = NULL;
gchar *line = NULL;
@@ -125,24 +108,24 @@
line = g_data_input_stream_read_line_finish(istream, result, &length,
&error);
if(line == NULL || error != NULL) {
- if(error == NULL) {
- g_set_error_literal(&error, PURPLE_CONNECTION_ERROR,
- PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
- _("Server closed the connection"));
- } else {
- g_prefix_error(&error, "%s", _("Lost connection with server: "));
+ if(PURPLE_IS_CONNECTION(connection)) {
+ if(error == NULL) {
+ g_set_error_literal(&error, PURPLE_CONNECTION_ERROR,
+ PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+ _("Server closed the connection"));
+ } else {
+ g_prefix_error(&error, "%s", _("Lost connection with server: "));
+ }
+
+ purple_connection_take_error(PURPLE_CONNECTION(connection), error);
}
- purple_connection_take_error(purple_connection, error);
-
/* In the off chance that line was returned, make sure we free it. */
g_free(line);
return;
}
- connection = g_object_get_data(G_OBJECT(purple_connection),
- PURPLE_IRCV3_CONNECTION_KEY);
purple_ircv3_parser_parse(connection->parser, line, &error, connection);
g_free(line);
@@ -152,7 +135,7 @@
G_PRIORITY_DEFAULT,
connection->cancellable,
purple_ircv3_connection_read_cb,
- purple_connection);
+ connection);
}
static void
@@ -168,14 +151,11 @@
&error);
if(!success) {
- PurpleConnection *purple_connection = NULL;
- purple_connection = purple_account_get_connection(connection->account);
-
purple_queued_output_stream_clear_queue(stream);
g_prefix_error(&error, "%s", _("Lost connection with server: "));
- purple_connection_take_error(purple_connection, error);
+ purple_connection_take_error(PURPLE_CONNECTION(connection), error);
return;
}
@@ -185,8 +165,7 @@
purple_ircv3_connection_connected_cb(GObject *source, GAsyncResult *result,
gpointer data)
{
- PurpleIRCv3Connection *connection = NULL;
- PurpleConnection *purple_connection = data;
+ PurpleIRCv3Connection *connection = data;
GError *error = NULL;
GInputStream *istream = NULL;
GOutputStream *ostream = NULL;
@@ -198,15 +177,12 @@
if(conn == NULL || error != NULL) {
g_prefix_error(&error, "%s", _("Unable to connect: "));
- purple_connection_take_error(purple_connection, error);
+ purple_connection_take_error(PURPLE_CONNECTION(connection), error);
return;
}
- connection = g_object_get_data(G_OBJECT(purple_connection),
- PURPLE_IRCV3_CONNECTION_KEY);
-
- purple_connection_set_state(purple_connection,
+ purple_connection_set_state(PURPLE_CONNECTION(connection),
PURPLE_CONNECTION_STATE_CONNECTED);
g_message("Successfully connected to %s", connection->server_name);
@@ -231,7 +207,7 @@
G_PRIORITY_DEFAULT,
connection->cancellable,
purple_ircv3_connection_read_cb,
- purple_connection);
+ connection);
/* Send our registration commands. */
purple_ircv3_connection_writef(connection, "CAP LS %s",
@@ -241,6 +217,89 @@
}
/******************************************************************************
+ * PurpleConnection Implementation
+ *****************************************************************************/
+static gboolean
+purple_ircv3_connection_connect(PurpleConnection *purple_connection,
+ GError **error)
+{
+ PurpleIRCv3Connection *connection = NULL;
+ PurpleAccount *account = NULL;
+ GSocketClient *client = NULL;
+ gint default_port = PURPLE_IRCV3_DEFAULT_TLS_PORT;
+ gint port = 0;
+ gboolean use_tls = TRUE;
+
+ g_return_val_if_fail(PURPLE_IRCV3_IS_CONNECTION(purple_connection), FALSE);
+
+ connection = PURPLE_IRCV3_CONNECTION(purple_connection);
+ account = purple_connection_get_account(purple_connection);
+
+ client = purple_gio_socket_client_new(account, error);
+ if(!G_IS_SOCKET_CLIENT(client)) {
+ if(error != NULL && *error != NULL) {
+ purple_connection_take_error(purple_connection, *error);
+ }
+
+ return FALSE;
+ }
+
+ /* Turn on TLS if requested. */
+ use_tls = purple_account_get_bool(account, "use-tls", TRUE);
+ g_socket_client_set_tls(client, use_tls);
+
+ /* If TLS is not being used, set the default port to the plain port. */
+ if(!use_tls) {
+ default_port = PURPLE_IRCV3_DEFAULT_PLAIN_PORT;
+ }
+ port = purple_account_get_int(account, "port", default_port);
+
+ /* Finally start the async connection. */
+ g_socket_client_connect_to_host_async(client, connection->server_name,
+ port, connection->cancellable,
+ purple_ircv3_connection_connected_cb,
+ connection);
+
+ g_clear_object(&client);
+
+ return TRUE;
+}
+
+static gboolean
+purple_ircv3_connection_disconnect(PurpleConnection *purple_connection,
+ GError **error)
+{
+ PurpleIRCv3Connection *connection = NULL;
+
+ g_return_val_if_fail(PURPLE_IRCV3_IS_CONNECTION(purple_connection), FALSE);
+
+ connection = PURPLE_IRCV3_CONNECTION(purple_connection);
+
+ /* TODO: send QUIT command. */
+
+ /* Cancel the cancellable to tell everyone we're shutting down. */
+ if(G_IS_CANCELLABLE(connection->cancellable)) {
+ g_cancellable_cancel(connection->cancellable);
+
+ g_clear_object(&connection->cancellable);
+ }
+
+ if(G_IS_SOCKET_CONNECTION(connection->connection)) {
+ GInputStream *istream = G_INPUT_STREAM(connection->input);
+ GOutputStream *ostream = G_OUTPUT_STREAM(connection->output);
+
+ purple_gio_graceful_close(G_IO_STREAM(connection->connection),
+ istream, ostream);
+ }
+
+ g_clear_object(&connection->input);
+ g_clear_object(&connection->output);
+ g_clear_object(&connection->connection);
+
+ return TRUE;
+}
+
+/******************************************************************************
* GObject Implementation
*****************************************************************************/
static void
@@ -250,10 +309,6 @@
PurpleIRCv3Connection *connection = PURPLE_IRCV3_CONNECTION(obj);
switch(param_id) {
- case PROP_ACCOUNT:
- g_value_set_object(value,
- purple_ircv3_connection_get_account(connection));
- break;
case PROP_CANCELLABLE:
g_value_set_object(value,
purple_ircv3_connection_get_cancellable(connection));
@@ -272,13 +327,9 @@
purple_ircv3_connection_set_property(GObject *obj, guint param_id,
const GValue *value, GParamSpec *pspec)
{
- PurpleIRCv3Connection *connection = PURPLE_IRCV3_CONNECTION(obj);
+ // PurpleIRCv3Connection *connection = PURPLE_IRCV3_CONNECTION(obj);
switch(param_id) {
- case PROP_ACCOUNT:
- purple_ircv3_connection_set_account(connection,
- g_value_get_object(value));
- break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
break;
@@ -289,7 +340,6 @@
purple_ircv3_connection_dispose(GObject *obj) {
PurpleIRCv3Connection *connection = PURPLE_IRCV3_CONNECTION(obj);
- g_clear_object(&connection->account);
g_clear_object(&connection->cancellable);
g_clear_object(&connection->input);
@@ -305,7 +355,6 @@
purple_ircv3_connection_finalize(GObject *obj) {
PurpleIRCv3Connection *connection = PURPLE_IRCV3_CONNECTION(obj);
- g_clear_error(&connection->validate_error);
g_clear_pointer(&connection->server_name, g_free);
g_clear_pointer(&connection->capabilities, g_free);
@@ -316,30 +365,19 @@
static void
purple_ircv3_connection_constructed(GObject *obj) {
PurpleIRCv3Connection *connection = PURPLE_IRCV3_CONNECTION(obj);
- PurpleConnection *purple_connection = NULL;
+ PurpleAccount *account = NULL;
gchar **userparts = NULL;
const gchar *username = NULL;
G_OBJECT_CLASS(purple_ircv3_connection_parent_class)->constructed(obj);
- purple_connection = purple_account_get_connection(connection->account);
-
- /* Make sure the username (which includes the servername via usersplits),
- * does not contain any whitespace.
- */
- username = purple_account_get_username(connection->account);
- if(strpbrk(username, " \t\v\r\n") != NULL) {
- g_set_error(&connection->validate_error,
- PURPLE_CONNECTION_ERROR,
- PURPLE_CONNECTION_ERROR_INVALID_SETTINGS,
- _("IRC nick and server may not contain whitespace"));
-
- return;
- }
+ account = purple_connection_get_account(PURPLE_CONNECTION(connection));
/* Split the username into nick and server and store the values. */
+ username = purple_account_get_username(account);
userparts = g_strsplit(username, "@", 2);
- purple_connection_set_display_name(purple_connection, userparts[0]);
+ purple_connection_set_display_name(PURPLE_CONNECTION(connection),
+ userparts[0]);
connection->server_name = g_strdup(userparts[1]);
g_strfreev(userparts);
@@ -358,6 +396,7 @@
static void
purple_ircv3_connection_class_init(PurpleIRCv3ConnectionClass *klass) {
GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+ PurpleConnectionClass *connection_class = PURPLE_CONNECTION_CLASS(klass);
obj_class->get_property = purple_ircv3_connection_get_property;
obj_class->set_property = purple_ircv3_connection_set_property;
@@ -365,18 +404,8 @@
obj_class->dispose = purple_ircv3_connection_dispose;
obj_class->finalize = purple_ircv3_connection_finalize;
- /**
- * PurpleIRCv3Connection:account:
- *
- * The [class@Purple.Account] that this connection is for.
- *
- * Since: 3.0.0
- */
- properties[PROP_ACCOUNT] = g_param_spec_object(
- "account", "account",
- "The account for this connection",
- PURPLE_TYPE_ACCOUNT,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+ connection_class->connect = purple_ircv3_connection_connect;
+ connection_class->disconnect = purple_ircv3_connection_disconnect;
/**
* PurpleIRCv3Connection:cancellable:
@@ -418,21 +447,6 @@
purple_ircv3_connection_register_type(G_TYPE_MODULE(plugin));
}
-PurpleIRCv3Connection *
-purple_ircv3_connection_new(PurpleAccount *account) {
- return g_object_new(
- PURPLE_IRCV3_TYPE_CONNECTION,
- "account", account,
- NULL);
-}
-
-PurpleAccount *
-purple_ircv3_connection_get_account(PurpleIRCv3Connection *connection) {
- g_return_val_if_fail(PURPLE_IRCV3_IS_CONNECTION(connection), NULL);
-
- return connection->account;
-}
-
GCancellable *
purple_ircv3_connection_get_cancellable(PurpleIRCv3Connection *connection) {
g_return_val_if_fail(PURPLE_IRCV3_IS_CONNECTION(connection), NULL);
@@ -440,87 +454,6 @@
return connection->cancellable;
}
-gboolean
-purple_ircv3_connection_valid(PurpleIRCv3Connection *connection,
- GError **error)
-{
- g_return_val_if_fail(PURPLE_IRCV3_IS_CONNECTION(connection), FALSE);
-
- if(connection->validate_error != NULL) {
- g_propagate_error(error, connection->validate_error);
- connection->validate_error = NULL;
-
- return FALSE;
- }
-
- return TRUE;
-}
-
-void
-purple_ircv3_connection_connect(PurpleIRCv3Connection *connection) {
- PurpleConnection *purple_connection = NULL;
- GError *error = NULL;
- GSocketClient *client = NULL;
- gint default_port = PURPLE_IRCV3_DEFAULT_TLS_PORT;
- gint port = 0;
- gboolean use_tls = TRUE;
-
- g_return_if_fail(PURPLE_IRCV3_IS_CONNECTION(connection));
- g_return_if_fail(connection->connection == NULL);
-
- purple_connection = purple_account_get_connection(connection->account);
- client = purple_gio_socket_client_new(connection->account, &error);
- if(!G_IS_SOCKET_CLIENT(client)) {
- purple_connection_take_error(purple_connection, error);
-
- return;
- }
-
- /* Turn on TLS if requested. */
- use_tls = purple_account_get_bool(connection->account, "use-tls", TRUE);
- g_socket_client_set_tls(client, use_tls);
-
- /* If TLS is not being used, set the default port to the plain port. */
- if(!use_tls) {
- default_port = PURPLE_IRCV3_DEFAULT_PLAIN_PORT;
- }
- port = purple_account_get_int(connection->account, "port", default_port);
-
- /* Finally start the async connection. */
- g_socket_client_connect_to_host_async(client, connection->server_name,
- port, connection->cancellable,
- purple_ircv3_connection_connected_cb,
- purple_connection);
-
- g_clear_object(&client);
-}
-
-void
-purple_ircv3_connection_close(PurpleIRCv3Connection *connection) {
- g_return_if_fail(PURPLE_IRCV3_IS_CONNECTION(connection));
-
- /* TODO: send QUIT command. */
-
- /* Cancel the cancellable to tell everyone we're shutting down. */
- if(G_IS_CANCELLABLE(connection->cancellable)) {
- g_cancellable_cancel(connection->cancellable);
-
- g_clear_object(&connection->cancellable);
- }
-
- if(G_IS_SOCKET_CONNECTION(connection->connection)) {
- GInputStream *istream = G_INPUT_STREAM(connection->input);
- GOutputStream *ostream = G_OUTPUT_STREAM(connection->output);
-
- purple_gio_graceful_close(G_IO_STREAM(connection->connection),
- istream, ostream);
- }
-
- g_clear_object(&connection->input);
- g_clear_object(&connection->output);
- g_clear_object(&connection->connection);
-}
-
void
purple_ircv3_connection_writef(PurpleIRCv3Connection *connection,
const char *format, ...)
--- a/libpurple/protocols/ircv3/purpleircv3connection.h Mon Oct 31 22:52:24 2022 -0500
+++ b/libpurple/protocols/ircv3/purpleircv3connection.h Mon Oct 31 23:00:12 2022 -0500
@@ -31,22 +31,14 @@
#define PURPLE_IRCV3_TYPE_CONNECTION (purple_ircv3_connection_get_type())
G_DECLARE_FINAL_TYPE(PurpleIRCv3Connection, purple_ircv3_connection,
- PURPLE_IRCV3, CONNECTION, GObject)
+ PURPLE_IRCV3, CONNECTION, PurpleConnection)
G_GNUC_INTERNAL void purple_ircv3_connection_register(GPluginNativePlugin *plugin);
-G_GNUC_INTERNAL PurpleIRCv3Connection *purple_ircv3_connection_new(PurpleAccount *account);
-
G_GNUC_INTERNAL PurpleAccount *purple_ircv3_connection_get_account(PurpleIRCv3Connection *connection);
G_GNUC_INTERNAL GCancellable *purple_ircv3_connection_get_cancellable(PurpleIRCv3Connection *connection);
-G_GNUC_INTERNAL gboolean purple_ircv3_connection_valid(PurpleIRCv3Connection *connection, GError **error);
-
-G_GNUC_INTERNAL void purple_ircv3_connection_connect(PurpleIRCv3Connection *connection);
-
-G_GNUC_INTERNAL void purple_ircv3_connection_close(PurpleIRCv3Connection *connection);
-
G_GNUC_INTERNAL void purple_ircv3_connection_writef(PurpleIRCv3Connection *connection, const char *format, ...) G_GNUC_PRINTF(2, 3);
/**
--- a/libpurple/protocols/ircv3/purpleircv3core.h Mon Oct 31 22:52:24 2022 -0500
+++ b/libpurple/protocols/ircv3/purpleircv3core.h Mon Oct 31 23:00:12 2022 -0500
@@ -27,8 +27,6 @@
#define PURPLE_IRCV3_DOMAIN (g_quark_from_static_string("ircv3-plugin"))
-#define PURPLE_IRCV3_CONNECTION_KEY "ircv3-connection"
-
#define PURPLE_IRCV3_CONNECTION_CAP_VERSION "302"
#endif /* PURPLE_IRCV3_CORE_H */
--- a/libpurple/protocols/ircv3/purpleircv3messagehandlers.c Mon Oct 31 22:52:24 2022 -0500
+++ b/libpurple/protocols/ircv3/purpleircv3messagehandlers.c Mon Oct 31 23:00:12 2022 -0500
@@ -160,7 +160,7 @@
return FALSE;
}
- account = purple_ircv3_connection_get_account(connection);
+ account = purple_connection_get_account(PURPLE_CONNECTION(connection));
contact_manager = purple_contact_manager_get_default();
contact = purple_contact_manager_find_with_username(contact_manager,
--- a/libpurple/protocols/ircv3/purpleircv3protocol.c Mon Oct 31 22:52:24 2022 -0500
+++ b/libpurple/protocols/ircv3/purpleircv3protocol.c Mon Oct 31 23:00:12 2022 -0500
@@ -23,10 +23,6 @@
#include "purpleircv3connection.h"
#include "purpleircv3core.h"
-typedef struct {
- gboolean dummy;
-} PurpleIRCv3ProtocolPrivate;
-
/******************************************************************************
* PurpleProtocol Implementation
*****************************************************************************/
@@ -84,44 +80,36 @@
return options;
}
-static void
-purple_ircv3_protocol_login(G_GNUC_UNUSED PurpleProtocol *protocol,
- PurpleAccount *account)
+static PurpleConnection *
+purple_ircv3_protocol_create_connection(PurpleProtocol *protocol,
+ PurpleAccount *account,
+ const char *password,
+ GError **error)
{
- PurpleIRCv3Connection *connection = NULL;
- PurpleConnection *purple_connection = NULL;
- GError *error = NULL;
+ const char *username = NULL;
+
+ g_return_val_if_fail(PURPLE_IS_PROTOCOL(protocol), NULL);
+ g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
- purple_connection = purple_account_get_connection(account);
+ /* Make sure the username (which includes the servername via usersplits),
+ * does not contain any whitespace.
+ */
+ username = purple_account_get_username(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"));
- connection = purple_ircv3_connection_new(account);
- if(!purple_ircv3_connection_valid(connection, &error)) {
- purple_connection_take_error(purple_connection, error);
-
- return;
+ return NULL;
}
- g_object_set_data_full(G_OBJECT(purple_connection),
- PURPLE_IRCV3_CONNECTION_KEY,
- connection, g_object_unref);
-
- purple_ircv3_connection_connect(connection);
-}
-
-static void
-purple_ircv3_protocol_close(G_GNUC_UNUSED PurpleProtocol *protocol,
- PurpleConnection *purple_connection)
-{
- PurpleIRCv3Connection *connection = NULL;
-
- connection = g_object_get_data(G_OBJECT(purple_connection),
- PURPLE_IRCV3_CONNECTION_KEY);
-
- purple_ircv3_connection_close(connection);
-
- /* Set our connection data to NULL which will remove the last reference. */
- g_object_set_data(G_OBJECT(purple_connection), PURPLE_IRCV3_CONNECTION_KEY,
- NULL);
+ return g_object_new(
+ PURPLE_IRCV3_TYPE_CONNECTION,
+ "protocol", protocol,
+ "account", account,
+ "password", password,
+ NULL);
}
static GList *
@@ -149,9 +137,8 @@
/******************************************************************************
* GObject Implementation
*****************************************************************************/
-G_DEFINE_DYNAMIC_TYPE_EXTENDED(
- PurpleIRCv3Protocol, purple_ircv3_protocol, PURPLE_TYPE_PROTOCOL, 0,
- G_ADD_PRIVATE_DYNAMIC(PurpleIRCv3Protocol))
+G_DEFINE_DYNAMIC_TYPE(PurpleIRCv3Protocol, purple_ircv3_protocol,
+ PURPLE_TYPE_PROTOCOL)
static void
purple_ircv3_protocol_init(PurpleIRCv3Protocol *protocol) {
@@ -168,8 +155,8 @@
protocol_class->get_user_splits = purple_ircv3_protocol_get_user_splits;
protocol_class->get_account_options =
purple_ircv3_protocol_get_account_options;
- protocol_class->login = purple_ircv3_protocol_login;
- protocol_class->close = purple_ircv3_protocol_close;
+ protocol_class->create_connection =
+ purple_ircv3_protocol_create_connection;
protocol_class->status_types = purple_ircv3_protocol_status_types;
}