pidgin/pidgin

bcc726c6c61a
Parents 44125b8e3b27
Children 258b96f56580
Add purple_conversation_send_message_async and _finish

Also make purple_message_set_error not take ownership of the error as that will
complicate things and it wasn't implemented properly anyways.

Testing Done:
Just had the turtles do their thing. There are no unit tests for sending messages right now due to complexity.

Reviewed at https://reviews.imfreedom.org/r/3139/
--- a/libpurple/purpleconversation.c Wed Apr 24 01:02:13 2024 -0500
+++ b/libpurple/purpleconversation.c Thu Apr 25 21:07:46 2024 -0500
@@ -184,9 +184,9 @@
}
static void
-purple_conversation_send_message_async_cb(GObject *protocol,
- GAsyncResult *result,
- gpointer data)
+purple_conversation_send_message_async_old_cb(GObject *protocol,
+ GAsyncResult *result,
+ gpointer data)
{
PurpleProtocolConversation *protocol_conversation = NULL;
PurpleMessage *message = data;
@@ -206,6 +206,54 @@
}
static void
+purple_conversation_send_message_async_cb(GObject *source,
+ GAsyncResult *result,
+ gpointer data)
+{
+ PurpleMessage *message = NULL;
+ PurpleProtocolConversation *protocol = NULL;
+ GError *error = NULL;
+ GTask *task = data;
+ gboolean success = FALSE;
+
+ /* task and result share a cancellable, so we just need to clear task to
+ * make sure its callback gets called.
+ */
+ if(g_task_return_error_if_cancelled(G_TASK(task))) {
+ g_clear_object(&task);
+
+ return;
+ }
+
+ protocol = PURPLE_PROTOCOL_CONVERSATION(source);
+ message = g_task_get_task_data(G_TASK(task));
+
+ success = purple_protocol_conversation_send_message_finish(protocol,
+ result, &error);
+
+ if(!success) {
+ if(error == NULL) {
+ error = g_error_new(PURPLE_CONVERSATION_DOMAIN, 0,
+ "unknown error");
+ }
+
+ purple_message_set_error(message, error);
+ g_task_return_error(task, error);
+
+ g_clear_error(&error);
+ } else {
+ /* If the protocol didn't set delivered, set it now. */
+ if(!purple_message_get_delivered(message)) {
+ purple_message_set_delivered(message, TRUE);
+ }
+
+ g_task_return_boolean(task, TRUE);
+ }
+
+ g_clear_object(&task);
+}
+
+static void
common_send(PurpleConversation *conversation, const char *message,
PurpleMessageFlags msgflags)
{
@@ -260,7 +308,7 @@
purple_protocol_conversation_send_message_async(protocol_conversation,
conversation, msg,
NULL,
- purple_conversation_send_message_async_cb,
+ purple_conversation_send_message_async_old_cb,
msg);
g_clear_pointer(&displayed, g_free);
@@ -1181,6 +1229,59 @@
}
void
+purple_conversation_send_message_async(PurpleConversation *conversation,
+ PurpleMessage *message,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer data)
+{
+ PurpleAccount *account = NULL;
+ PurpleProtocol *protocol = NULL;
+ GTask *task = NULL;
+
+ g_return_if_fail(PURPLE_IS_CONVERSATION(conversation));
+ g_return_if_fail(PURPLE_IS_MESSAGE(message));
+
+ task = g_task_new(conversation, cancellable, callback, data);
+ g_task_set_source_tag(task, purple_conversation_send_message_async);
+ g_task_set_task_data(task, g_object_ref(message), g_object_unref);
+
+ account = purple_conversation_get_account(conversation);
+ protocol = purple_account_get_protocol(account);
+
+ if(!PURPLE_IS_PROTOCOL_CONVERSATION(protocol)) {
+ g_task_return_new_error(task, PURPLE_CONVERSATION_DOMAIN, 0,
+ "protocol does not implement "
+ "PurpleProtocolConversation");
+
+ g_clear_object(&task);
+
+ return;
+ }
+
+ purple_protocol_conversation_send_message_async(PURPLE_PROTOCOL_CONVERSATION(protocol),
+ conversation,
+ message,
+ cancellable,
+ purple_conversation_send_message_async_cb,
+ task);
+}
+
+gboolean
+purple_conversation_send_message_finish(PurpleConversation *conversation,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail(PURPLE_IS_CONVERSATION(conversation), FALSE);
+ g_return_val_if_fail(G_IS_ASYNC_RESULT(result), FALSE);
+
+ g_return_val_if_fail(g_task_get_source_tag(G_TASK(result)) !=
+ purple_conversation_send_message_async, FALSE);
+
+ return g_task_propagate_boolean(G_TASK(result), error);
+}
+
+void
purple_conversation_send(PurpleConversation *conversation,
const char *message)
{
--- a/libpurple/purpleconversation.h Wed Apr 24 01:02:13 2024 -0500
+++ b/libpurple/purpleconversation.h Thu Apr 25 21:07:46 2024 -0500
@@ -32,6 +32,17 @@
#include "purpleversion.h"
+/**
+ * PURPLE_CONVERSATION_DOMAIN:
+ *
+ * A GError domain for PurpleConversation.
+ *
+ * Since: 3.0
+ */
+#define PURPLE_CONVERSATION_DOMAIN \
+ (g_quark_from_static_string("purple-conversatin")) \
+ PURPLE_AVAILABLE_MACRO_IN_3_0
+
#define PURPLE_TYPE_CONVERSATION (purple_conversation_get_type())
PURPLE_AVAILABLE_IN_ALL
@@ -326,6 +337,42 @@
void purple_conversation_write_system_message(PurpleConversation *conversation, const char *message, PurpleMessageFlags flags);
/**
+ * purple_conversation_send_message_async:
+ * @conversation: The conversation.
+ * @message: The message to send.
+ * @cancellable: (nullable): optional GCancellable object, %NULL to ignore.
+ * @callback: (nullable) (scope async): The callback to call after the
+ * conversation has been created.
+ * @data: (nullable): Optional user data to pass to @callback.
+ *
+ * Sends @message to @conversation.
+ *
+ * This will lookup the account and protocol plugin that @conversation belongs
+ * to and call [method@ProtocolConversation.send_message_async] for @message.
+ *
+ * You will need to call [method@Conversation.send_message_finish] from
+ * @callback.
+ *
+ * Since: 3.0
+ */
+PURPLE_AVAILABLE_IN_3_0
+void purple_conversation_send_message_async(PurpleConversation *conversation, PurpleMessage *message, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer data);
+
+/**
+ * purple_conversation_send_message_finish:
+ * @conversation: The instance.
+ * @result: The result.
+ * @error: Return address for a #GError, or %NULL.
+ *
+ * Finishes a previous call to [method@Conversation.send_message_async].
+ *
+ * Returns: %TRUE on success, otherwise %FALSE with error set.
+ *
+ * Since: 3.0
+ */
+gboolean purple_conversation_send_message_finish(PurpleConversation *conversation, GAsyncResult *result, GError **error);
+
+/**
* purple_conversation_send:
* @conversation: The conversation.
* @message: The message to send.
--- a/libpurple/purplemessage.c Wed Apr 24 01:02:13 2024 -0500
+++ b/libpurple/purplemessage.c Thu Apr 25 21:07:46 2024 -0500
@@ -683,7 +683,7 @@
g_clear_error(&message->error);
if(error != NULL) {
- g_propagate_error(&message->error, error);
+ message->error = g_error_copy(error);
}
g_object_notify_by_pspec(G_OBJECT(message), properties[PROP_ERROR]);
--- a/libpurple/purplemessage.h Wed Apr 24 01:02:13 2024 -0500
+++ b/libpurple/purplemessage.h Thu Apr 25 21:07:46 2024 -0500
@@ -369,7 +369,7 @@
/**
* purple_message_set_error:
* @message: The instance.
- * @error: (nullable) (transfer full): The error to set.
+ * @error: (nullable) (transfer none): The error to set.
*
* Sets the error of @message to @error. Primarily this will be used for
* delivery failure.