--- a/libpurple/protocols/ircv3/purpleircv3protocol.c Tue Mar 19 00:38:22 2024 -0500
+++ b/libpurple/protocols/ircv3/purpleircv3protocol.c Tue Mar 19 00:53:11 2024 -0500
@@ -29,6 +29,39 @@
#include "purpleircv3protocolconversation.h"
/******************************************************************************
+ *****************************************************************************/ +purple_ircv3_protocol_can_reach_cb(GObject *self, GAsyncResult *result, + gboolean can_reach = FALSE; + /* task and result share a cancellable, so either can be used here. */ + if(g_task_return_error_if_cancelled(task)) { + can_reach = g_network_monitor_can_reach_finish(G_NETWORK_MONITOR(self), result, + g_task_return_error(task, error); + } else if(!can_reach) { + g_task_return_new_error(task, PURPLE_IRCV3_DOMAIN, 0, + _("Unknown network error.")); + g_task_return_boolean(task, TRUE); +/****************************************************************************** * PurpleProtocol Implementation
*****************************************************************************/
@@ -148,6 +181,46 @@
+purple_ircv3_protocol_can_connect_async(PurpleProtocol *protocol, + PurpleAccount *account, + GCancellable *cancellable, + GAsyncReadyCallback callback, + GNetworkMonitor *monitor = NULL; + GSocketConnectable *connectable = NULL; + const char *username = NULL; + 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_network_monitor_can_reach_async(monitor, connectable, cancellable, + purple_ircv3_protocol_can_reach_cb, + g_clear_object(&connectable); +purple_ircv3_protocol_can_connect_finish(G_GNUC_UNUSED PurpleProtocol *protocol, + return g_task_propagate_boolean(G_TASK(result), error); /******************************************************************************
*****************************************************************************/
@@ -177,6 +250,10 @@
protocol_class->create_connection =
purple_ircv3_protocol_create_connection;
protocol_class->status_types = purple_ircv3_protocol_status_types;
+ protocol_class->can_connect_async = + purple_ircv3_protocol_can_connect_async; + protocol_class->can_connect_finish = + purple_ircv3_protocol_can_connect_finish; /******************************************************************************
--- a/libpurple/purpleaccount.c Tue Mar 19 00:38:22 2024 -0500
+++ b/libpurple/purpleaccount.c Tue Mar 19 00:53:11 2024 -0500
@@ -429,6 +429,54 @@
+purple_account_can_connect_cb(GObject *source, GAsyncResult *result, + PurpleAccount *account = data; + PurpleProtocol *protocol = PURPLE_PROTOCOL(source); + PurpleProtocolOptions options; + gboolean can_connect = FALSE; + gboolean require_password = TRUE; + can_connect = purple_protocol_can_connect_finish(protocol, result, &error); + if(!can_connect || error != NULL) { + PurpleConnectionErrorInfo *info = NULL; + const char *error_message = _("unknown error"); + error_message = error->message; + info = purple_connection_error_info_new(PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + purple_account_set_error(account, info); + 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; + PurpleCredentialManager *manager = NULL; + manager = purple_credential_manager_get_default(); + purple_credential_manager_read_password_async(manager, account, NULL, + purple_account_connect_got_password_cb, + g_timeout_add_seconds(0, no_password_cb, account); /******************************************************************************
*****************************************************************************/
@@ -1065,11 +1113,8 @@
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));
@@ -1095,23 +1140,8 @@
- 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;
- manager = purple_credential_manager_get_default();
- purple_credential_manager_read_password_async(manager, account, NULL,
- purple_account_connect_got_password_cb,
- g_timeout_add_seconds(0, no_password_cb, account);
+ purple_protocol_can_connect_async(protocol, account, NULL, + purple_account_can_connect_cb, account); --- a/libpurple/purpleprotocol.c Tue Mar 19 00:38:22 2024 -0500
+++ b/libpurple/purpleprotocol.c Tue Mar 19 00:53:11 2024 -0500
@@ -561,6 +561,13 @@
if(klass != NULL && klass->can_connect_async != NULL) {
klass->can_connect_async(protocol, account, cancellable, callback,
+ GTask *task = g_task_new(protocol, cancellable, callback, data); + g_task_return_boolean(task, TRUE); + g_task_set_source_tag(task, purple_protocol_can_connect_async); @@ -569,13 +576,19 @@
- PurpleProtocolClass *klass = NULL;
g_return_val_if_fail(PURPLE_IS_PROTOCOL(protocol), FALSE);
- klass = PURPLE_PROTOCOL_GET_CLASS(protocol);
- if(klass != NULL && klass->can_connect_finish != NULL) {
- return klass->can_connect_finish(protocol, result, error);
+ tag = g_task_get_source_tag(G_TASK(result)); + if(tag == purple_protocol_can_connect_async) { + return g_task_propagate_boolean(G_TASK(result), error); + PurpleProtocolClass *klass = PURPLE_PROTOCOL_GET_CLASS(protocol); + if(klass != NULL && klass->can_connect_finish != NULL) { + return klass->can_connect_finish(protocol, result, error); --- a/libpurple/purpleprotocol.h Tue Mar 19 00:38:22 2024 -0500
+++ b/libpurple/purpleprotocol.h Tue Mar 19 00:53:11 2024 -0500
@@ -317,6 +317,9 @@
* Most protocol plugins will call [method@Gio.NetworkMonitor.can_reach_async]
* to determine if a connection is possible.
+ * If [vfunc@Protocol.can_connect_async] is not implemented, this function will + * create a [type@Gio.Task] that returns %TRUE. --- a/protocols/bonjour/purplebonjourprotocol.c Tue Mar 19 00:38:22 2024 -0500
+++ b/protocols/bonjour/purplebonjourprotocol.c Tue Mar 19 00:53:11 2024 -0500
@@ -22,6 +22,7 @@
#include "purplebonjourconnection.h"
#include "purplebonjourconstants.h"
+#include "purplebonjourcore.h" struct _PurpleBonjourProtocol {
@@ -60,6 +61,41 @@
+purple_bonjour_protocol_can_connect_async(PurpleProtocol *protocol, + G_GNUC_UNUSED PurpleAccount *account, + GCancellable *cancellable, + GAsyncReadyCallback callback, + GNetworkMonitor *monitor = NULL; + GNetworkConnectivity connectivity = 0; + task = g_task_new(protocol, cancellable, callback, data); + /* Bonjour runs on LANs so we just need local connectivity. */ + monitor = g_network_monitor_get_default(); + connectivity = g_network_monitor_get_connectivity(monitor); + if(connectivity >= G_NETWORK_CONNECTIVITY_LOCAL) { + g_task_return_boolean(task, TRUE); + g_task_return_new_error(task, PURPLE_BONJOUR_DOMAIN, 0, + _("Network connection not detected.")); +purple_bonjour_protocol_can_connect_finish(G_GNUC_UNUSED PurpleProtocol *protocol, + return g_task_propagate_boolean(G_TASK(result), error); static PurpleConnection *
purple_bonjour_protocol_create_connection(PurpleProtocol *protocol,
@@ -99,7 +135,8 @@
protocol_class->get_account_options = purple_bonjour_protocol_get_account_options;
protocol_class->status_types = purple_bonjour_protocol_status_types;
+ protocol_class->can_connect_async = purple_bonjour_protocol_can_connect_async; + protocol_class->can_connect_finish = purple_bonjour_protocol_can_connect_finish; protocol_class->create_connection = purple_bonjour_protocol_create_connection;
--- a/protocols/xmpp/purplexmppprotocol.c Tue Mar 19 00:38:22 2024 -0500
+++ b/protocols/xmpp/purplexmppprotocol.c Tue Mar 19 00:53:11 2024 -0500
@@ -22,6 +22,7 @@
#include "purplexmppconnection.h"
#include "purplexmppconstants.h"
+#include "purplexmppcore.h" struct _PurpleXmppProtocol {
@@ -110,6 +111,43 @@
+purple_xmpp_protocol_can_connect_async(PurpleProtocol *protocol, + G_GNUC_UNUSED PurpleAccount *account, + GCancellable *cancellable, + GAsyncReadyCallback callback, + GNetworkMonitor *monitor = NULL; + GNetworkConnectivity connectivity = 0; + task = g_task_new(protocol, cancellable, callback, data); + /* Since we could be connecting to localhost, we only need to verify that + * our connectivity is at least G_NETWORK_CONNECTIVITY_LOCAL. + monitor = g_network_monitor_get_default(); + connectivity = g_network_monitor_get_connectivity(monitor); + if(connectivity >= G_NETWORK_CONNECTIVITY_LOCAL) { + g_task_return_boolean(task, TRUE); + g_task_return_new_error(task, PURPLE_XMPP_DOMAIN, 0, + _("Network connection not detected.")); +purple_xmpp_protocol_can_connect_finish(G_GNUC_UNUSED PurpleProtocol *protocol, + return g_task_propagate_boolean(G_TASK(result), error); static PurpleConnection *
purple_xmpp_protocol_create_connection(PurpleProtocol *protocol,
@@ -149,7 +187,8 @@
protocol_class->get_user_splits = purple_xmpp_protocol_get_user_splits;
protocol_class->get_account_options = purple_xmpp_protocol_get_account_options;
protocol_class->status_types = purple_xmpp_protocol_status_types;
+ protocol_class->can_connect_async = purple_xmpp_protocol_can_connect_async; + protocol_class->can_connect_finish = purple_xmpp_protocol_can_connect_finish; protocol_class->create_connection = purple_xmpp_protocol_create_connection;