libpurple/purplemessage.c

changeset 40696
cf58ec89b1e4
parent 40541
9ceb8d25d4d9
child 40951
c83bf354d142
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/purplemessage.c	Mon Jan 11 01:08:47 2021 -0600
@@ -0,0 +1,573 @@
+/*
+ * 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 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, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <glib/gi18n-lib.h>
+
+#include "internal.h"
+
+#include "debug.h"
+#include "purplemessage.h"
+#include "enums.h"
+#include "purpleprivate.h"
+
+/**
+ * PurpleMessage:
+ *
+ * A message data container.
+ */
+struct _PurpleMessage {
+	GObject parent;
+
+	guint id;
+	gchar *author;
+	gchar *author_alias;
+	gchar *recipient;
+
+	gchar *contents;
+	PurpleMessageContentType content_type;
+
+	GDateTime *timestamp;
+	PurpleMessageFlags flags;
+
+	GHashTable *attachments;
+};
+
+enum {
+	PROP_0,
+	PROP_ID,
+	PROP_AUTHOR,
+	PROP_AUTHOR_ALIAS,
+	PROP_RECIPIENT,
+	PROP_CONTENTS,
+	PROP_CONTENT_TYPE,
+	PROP_TIMESTAMP,
+	PROP_FLAGS,
+	N_PROPERTIES
+};
+static GParamSpec *properties[N_PROPERTIES];
+
+G_DEFINE_TYPE(PurpleMessage, purple_message, G_TYPE_OBJECT)
+
+/******************************************************************************
+ * Helpers
+ *****************************************************************************/
+static void
+purple_message_set_id(PurpleMessage *message, guint id) {
+	message->id = id;
+
+	g_object_notify_by_pspec(G_OBJECT(message), properties[PROP_ID]);
+}
+
+static void
+purple_message_set_author(PurpleMessage *message, const gchar *author) {
+	g_free(message->author);
+	message->author = g_strdup(author);
+
+	g_object_notify_by_pspec(G_OBJECT(message), properties[PROP_AUTHOR]);
+}
+
+/******************************************************************************
+ * GObject Implementation
+ *****************************************************************************/
+static void
+purple_message_get_property(GObject *object, guint param_id, GValue *value,
+                            GParamSpec *pspec)
+{
+	PurpleMessage *message = PURPLE_MESSAGE(object);
+
+	switch(param_id) {
+		case PROP_ID:
+			g_value_set_uint(value, purple_message_get_id(message));
+			break;
+		case PROP_AUTHOR:
+			g_value_set_string(value, purple_message_get_author(message));
+			break;
+		case PROP_AUTHOR_ALIAS:
+			g_value_set_string(value, purple_message_get_author_alias(message));
+			break;
+		case PROP_RECIPIENT:
+			g_value_set_string(value, purple_message_get_recipient(message));
+			break;
+		case PROP_CONTENTS:
+			g_value_set_string(value, purple_message_get_contents(message));
+			break;
+		case PROP_CONTENT_TYPE:
+			g_value_set_enum(value, purple_message_get_content_type(message));
+			break;
+		case PROP_TIMESTAMP:
+			g_value_set_boxed(value, purple_message_get_timestamp(message));
+			break;
+		case PROP_FLAGS:
+			g_value_set_flags(value, purple_message_get_flags(message));
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
+			break;
+	}
+}
+
+static void
+purple_message_set_property(GObject *object, guint param_id,
+                            const GValue *value, GParamSpec *pspec)
+{
+	PurpleMessage *message = PURPLE_MESSAGE(object);
+
+	switch(param_id) {
+		case PROP_ID:
+			purple_message_set_id(message, g_value_get_uint(value));
+			break;
+		case PROP_AUTHOR:
+			purple_message_set_author(message, g_value_get_string(value));
+			break;
+		case PROP_AUTHOR_ALIAS:
+			purple_message_set_author_alias(message, g_value_get_string(value));
+			break;
+		case PROP_RECIPIENT:
+			purple_message_set_recipient(message, g_value_get_string(value));
+			break;
+		case PROP_CONTENTS:
+			purple_message_set_contents(message, g_value_get_string(value));
+			break;
+		case PROP_CONTENT_TYPE:
+			purple_message_set_content_type(message, g_value_get_enum(value));
+			break;
+		case PROP_TIMESTAMP:
+			purple_message_set_timestamp(message, g_value_get_boxed(value));
+			break;
+		case PROP_FLAGS:
+			purple_message_set_flags(message, g_value_get_flags(value));
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
+			break;
+	}
+}
+
+static void
+purple_message_finalize(GObject *obj) {
+	PurpleMessage *message = PURPLE_MESSAGE(obj);
+
+	g_free(message->author);
+	g_free(message->author_alias);
+	g_free(message->recipient);
+	g_free(message->contents);
+
+	if(message->timestamp != NULL) {
+		g_date_time_unref(message->timestamp);
+	}
+
+	g_hash_table_destroy(message->attachments);
+
+	G_OBJECT_CLASS(purple_message_parent_class)->finalize(obj);
+}
+
+static void
+purple_message_init(PurpleMessage *message) {
+	message->attachments = g_hash_table_new_full(g_int64_hash, g_int64_equal,
+	                                             NULL, g_object_unref);
+}
+
+static void
+purple_message_class_init(PurpleMessageClass *klass) {
+	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+
+	obj_class->get_property = purple_message_get_property;
+	obj_class->set_property = purple_message_set_property;
+	obj_class->finalize = purple_message_finalize;
+
+	/**
+	 * PurpleMessage::id:
+	 *
+	 * The account specific identifier of the message.
+	 */
+	properties[PROP_ID] = g_param_spec_uint(
+		"id", "ID",
+		"The session-unique message id",
+		0, G_MAXUINT, 0,
+		G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+	/**
+	 * PurpleMessage::author:
+	 *
+	 * The author of the message.
+	 */
+	properties[PROP_AUTHOR] = g_param_spec_string(
+		"author", "Author",
+		"The username of the person, who sent the message.",
+		NULL,
+		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+	/**
+	 * PurpleMessage::author-alias:
+	 *
+	 * The alias of the author.
+	 */
+	properties[PROP_AUTHOR_ALIAS] = g_param_spec_string(
+		"author-alias", "Author's alias",
+		"The alias of the sender",
+		NULL,
+		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+	/**
+	 * PurpleMessage::recipient:
+	 *
+	 * The recipient of the message.
+	 */
+	properties[PROP_RECIPIENT] = g_param_spec_string(
+		"recipient", "Recipient",
+		"The username of the recipient.",
+		NULL,
+		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+	/**
+	 * PurpleMessage::content:
+	 *
+	 * The contents of the message.
+	 */
+	properties[PROP_CONTENTS] = g_param_spec_string(
+		"contents", "Contents",
+		"The message text",
+		NULL,
+		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+	/**
+	 * PurpleMessage::content-type:
+	 *
+	 * The content-type of the message.
+	 */
+	properties[PROP_CONTENT_TYPE] = g_param_spec_enum(
+		"content-type", "content-type",
+		"The content-type of the message.",
+		PURPLE_TYPE_MESSAGE_CONTENT_TYPE, PURPLE_MESSAGE_CONTENT_TYPE_PLAIN,
+		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+	/**
+	 * PurpleMessage::timestamp:
+	 *
+	 * The timestamp of the message.
+	 */
+	properties[PROP_TIMESTAMP] = g_param_spec_boxed(
+		"timestamp", "timestamp",
+		"The timestamp of the message",
+		G_TYPE_DATE_TIME,
+		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+	/**
+	 * PurpleMessage::flags:
+	 *
+	 * The #PurpleMessageFlags for the message.
+	 */
+	properties[PROP_FLAGS] = g_param_spec_flags(
+		"flags", "Flags",
+		"Bitwise set of #PurpleMessageFlags flags",
+		PURPLE_TYPE_MESSAGE_FLAGS, 0,
+		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
+}
+
+/******************************************************************************
+ * Public API
+ *****************************************************************************/
+PurpleMessage *
+purple_message_new_outgoing(const gchar *author, const gchar *recipient,
+                            const gchar *contents, PurpleMessageFlags flags)
+{
+	PurpleMessage *message = NULL;
+	GDateTime *dt = NULL;
+
+	g_warn_if_fail(!(flags & PURPLE_MESSAGE_RECV));
+	g_warn_if_fail(!(flags & PURPLE_MESSAGE_SYSTEM));
+
+	flags |= PURPLE_MESSAGE_SEND;
+	dt = g_date_time_new_now_local();
+
+	/* who may be NULL for outgoing MUC messages */
+	message = PURPLE_MESSAGE(g_object_new(PURPLE_TYPE_MESSAGE,
+		"author", author,
+		"recipient", recipient,
+		"contents", contents,
+		"timestamp", dt,
+		"flags", flags,
+		NULL));
+
+	g_date_time_unref(dt);
+
+	return message;
+}
+
+PurpleMessage *
+purple_message_new_incoming(const gchar *who, const gchar *contents,
+                            PurpleMessageFlags flags, guint64 timestamp)
+{
+	PurpleMessage *message = NULL;
+	GDateTime *dt = NULL;
+
+	g_warn_if_fail(!(flags & PURPLE_MESSAGE_SEND));
+	g_warn_if_fail(!(flags & PURPLE_MESSAGE_SYSTEM));
+
+	flags |= PURPLE_MESSAGE_RECV;
+
+	if(timestamp == 0) {
+		dt = g_date_time_new_now_local();
+	} else {
+		dt = g_date_time_new_from_unix_local((gint64)timestamp);
+	}
+
+	message = PURPLE_MESSAGE(g_object_new(PURPLE_TYPE_MESSAGE,
+		"author", who,
+		"author-alias", who,
+		"contents", contents,
+		"timestamp", dt,
+		"flags", flags,
+		NULL));
+
+	g_date_time_unref(dt);
+
+	return message;
+}
+
+PurpleMessage *
+purple_message_new_system(const gchar *contents, PurpleMessageFlags flags) {
+	PurpleMessage *message = NULL;
+	GDateTime *dt = NULL;
+
+	g_warn_if_fail(!(flags & PURPLE_MESSAGE_SEND));
+	g_warn_if_fail(!(flags & PURPLE_MESSAGE_RECV));
+
+	flags |= PURPLE_MESSAGE_SYSTEM;
+	dt = g_date_time_new_now_local();
+
+	message = PURPLE_MESSAGE(g_object_new(PURPLE_TYPE_MESSAGE,
+		"contents", contents,
+		"timestamp", dt,
+		"flags", flags,
+		NULL));
+
+	g_date_time_unref(dt);
+
+	return message;
+}
+
+guint
+purple_message_get_id(PurpleMessage *message) {
+	g_return_val_if_fail(PURPLE_IS_MESSAGE(message), 0);
+
+	return message->id;
+}
+
+const gchar *
+purple_message_get_author(PurpleMessage *message) {
+	g_return_val_if_fail(PURPLE_IS_MESSAGE(message), NULL);
+
+	return message->author;
+}
+
+void
+purple_message_set_recipient(PurpleMessage *message, const gchar *recipient) {
+	g_return_if_fail(PURPLE_IS_MESSAGE(message));
+
+	g_free(message->recipient);
+	message->recipient = g_strdup(recipient);
+
+	g_object_notify_by_pspec(G_OBJECT(message), properties[PROP_RECIPIENT]);
+}
+
+const gchar *
+purple_message_get_recipient(PurpleMessage *message) {
+	g_return_val_if_fail(PURPLE_IS_MESSAGE(message), NULL);
+
+	return message->recipient;
+}
+
+void
+purple_message_set_author_alias(PurpleMessage *message,
+                                const gchar *author_alias)
+{
+	g_return_if_fail(PURPLE_IS_MESSAGE(message));
+
+	g_free(message->author_alias);
+	message->author_alias = g_strdup(author_alias);
+
+	g_object_notify_by_pspec(G_OBJECT(message), properties[PROP_AUTHOR_ALIAS]);
+}
+
+const gchar *
+purple_message_get_author_alias(PurpleMessage *message) {
+	g_return_val_if_fail(PURPLE_IS_MESSAGE(message), NULL);
+
+	if (message->author_alias == NULL)
+		return purple_message_get_author(message);
+
+	return message->author_alias;
+}
+
+void
+purple_message_set_contents(PurpleMessage *message, const gchar *contents) {
+	g_return_if_fail(PURPLE_IS_MESSAGE(message));
+
+	g_free(message->contents);
+	message->contents = g_strdup(contents);
+
+	g_object_notify_by_pspec(G_OBJECT(message), properties[PROP_CONTENTS]);
+}
+
+const gchar *
+purple_message_get_contents(PurpleMessage *message) {
+	g_return_val_if_fail(PURPLE_IS_MESSAGE(message), NULL);
+
+	return message->contents;
+}
+
+void
+purple_message_set_content_type(PurpleMessage *message,
+                                PurpleMessageContentType content_type)
+{
+	g_return_if_fail(PURPLE_IS_MESSAGE(message));
+
+	message->content_type = content_type;
+
+	g_object_notify_by_pspec(G_OBJECT(message), properties[PROP_CONTENT_TYPE]);
+}
+
+PurpleMessageContentType
+purple_message_get_content_type(PurpleMessage *message) {
+	g_return_val_if_fail(PURPLE_IS_MESSAGE(message),
+	                     PURPLE_MESSAGE_CONTENT_TYPE_PLAIN);
+
+	return message->content_type;
+}
+
+gboolean
+purple_message_is_empty(PurpleMessage *message) {
+	return (message->contents == NULL || message->contents[0] == '\0');
+}
+
+void
+purple_message_set_timestamp(PurpleMessage *message, GDateTime *timestamp) {
+	g_return_if_fail(PURPLE_IS_MESSAGE(message));
+
+	g_clear_pointer(&message->timestamp, g_date_time_unref);
+	if(timestamp != NULL) {
+		message->timestamp = g_date_time_ref(timestamp);
+	}
+
+	g_object_notify_by_pspec(G_OBJECT(message), properties[PROP_TIMESTAMP]);
+}
+
+GDateTime *
+purple_message_get_timestamp(PurpleMessage *message) {
+	g_return_val_if_fail(PURPLE_IS_MESSAGE(message), 0);
+
+	if(message->timestamp == NULL) {
+		GDateTime *dt = g_date_time_new_now_local();
+		purple_message_set_timestamp(message, dt);
+		g_date_time_unref(dt);
+	}
+
+	return message->timestamp;
+}
+
+gchar *
+purple_message_format_timestamp(PurpleMessage *message, const gchar *format) {
+	GDateTime *dt = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_MESSAGE(message), NULL);
+	g_return_val_if_fail(format != NULL, NULL);
+
+	dt = purple_message_get_timestamp(message);
+
+	return g_date_time_format(dt, format);
+}
+
+void
+purple_message_set_flags(PurpleMessage *message, PurpleMessageFlags flags) {
+	g_return_if_fail(PURPLE_IS_MESSAGE(message));
+
+	message->flags = flags;
+
+	g_object_notify_by_pspec(G_OBJECT(message), properties[PROP_FLAGS]);
+}
+
+PurpleMessageFlags
+purple_message_get_flags(PurpleMessage *message) {
+	g_return_val_if_fail(PURPLE_IS_MESSAGE(message), 0);
+
+	return message->flags;
+}
+
+gboolean
+purple_message_add_attachment(PurpleMessage *message,
+                              PurpleAttachment *attachment)
+{
+	g_return_val_if_fail(PURPLE_IS_MESSAGE(message), FALSE);
+	g_return_val_if_fail(PURPLE_IS_ATTACHMENT(attachment), FALSE);
+
+	return g_hash_table_insert(message->attachments,
+	                           purple_attachment_get_hash_key(attachment),
+	                           g_object_ref(G_OBJECT(attachment)));
+}
+
+gboolean
+purple_message_remove_attachment(PurpleMessage *message, guint64 id) {
+	g_return_val_if_fail(PURPLE_IS_MESSAGE(message), FALSE);
+
+	return g_hash_table_remove(message->attachments, &id);
+}
+
+PurpleAttachment *
+purple_message_get_attachment(PurpleMessage *message, guint64 id) {
+	PurpleAttachment *attachment = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_MESSAGE(message), NULL);
+
+	attachment = g_hash_table_lookup(message->attachments, &id);
+	if(PURPLE_IS_ATTACHMENT(attachment)) {
+		return PURPLE_ATTACHMENT(g_object_ref(G_OBJECT(attachment)));
+	}
+
+	return NULL;
+}
+
+void
+purple_message_foreach_attachment(PurpleMessage *message,
+                                  PurpleAttachmentForeachFunc func,
+                                  gpointer data)
+{
+	GHashTableIter iter;
+	gpointer value;
+
+	g_return_if_fail(PURPLE_IS_MESSAGE(message));
+	g_return_if_fail(func != NULL);
+
+	g_hash_table_iter_init(&iter, message->attachments);
+	while(g_hash_table_iter_next(&iter, NULL, &value)) {
+		func(PURPLE_ATTACHMENT(value), data);
+	}
+}
+
+void
+purple_message_clear_attachments(PurpleMessage *message) {
+	g_return_if_fail(PURPLE_IS_MESSAGE(message));
+
+	g_hash_table_remove_all(message->attachments);
+}

mercurial