libpurple/purplemessage.c

Thu, 25 Aug 2022 22:45:58 -0500

author
Elliott Sales de Andrade <quantum.analyst@gmail.com>
date
Thu, 25 Aug 2022 22:45:58 -0500
branch
gtk4
changeset 41596
2f0fec76cfbc
parent 41479
3d2e114380f6
child 41685
ca22b00972d4
permissions
-rw-r--r--

Handle delete event in more dialogs (probably all, but can't be too sure.)

Testing Done:
Compile only.

Reviewed at https://reviews.imfreedom.org/r/1652/

/*
 * 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 "purpleenums.h"
#include "purplemessage.h"
#include "purpleprivate.h"

struct _PurpleMessage {
	GObject parent;

	gchar *id;
	gchar *author;
	gchar *author_name_color;
	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_AUTHOR_NAME_COLOR,
	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, const gchar *id) {
	g_free(message->id);
	message->id = g_strdup(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_string(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_AUTHOR_NAME_COLOR:
			g_value_set_string(value,
			                   purple_message_get_author_name_color(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_string(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_AUTHOR_NAME_COLOR:
			purple_message_set_author_name_color(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->id);
	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.
	 *
	 * Since: 3.0.0
	 */
	properties[PROP_ID] = g_param_spec_string(
		"id", "ID",
		"The session-unique message id",
		NULL,
		G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);

	/**
	 * PurpleMessage::author:
	 *
	 * The author of the message.
	 *
	 * Since: 3.0.0
	 */
	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-name-color:
	 *
	 * The hex color for the author's name.
	 *
	 * Since: 3.0.0
	 */
	properties[PROP_AUTHOR_NAME_COLOR] = g_param_spec_string(
		"author-name-color", "author-name-color",
		"The hex color to display the author's name with",
		NULL,
		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);

	/**
	 * PurpleMessage::author-alias:
	 *
	 * The alias of the author.
	 *
	 * Since: 3.0.0
	 */
	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.
	 *
	 * Since: 3.0.0
	 */
	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.
	 *
	 * Since: 3.0.0
	 */
	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.
	 *
	 * Since: 3.0.0
	 */
	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.
	 *
	 * Since: 3.0.0
	 */
	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.
	 *
	 * Since: 3.0.0
	 */
	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;
}

const gchar *
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_author_name_color(PurpleMessage *message,
                                     const gchar *color)
{
	g_return_if_fail(PURPLE_IS_MESSAGE(message));

	g_free(message->author_name_color);
	message->author_name_color = g_strdup(color);

	g_object_notify_by_pspec(G_OBJECT(message),
	                         properties[PROP_AUTHOR_NAME_COLOR]);
}

const gchar *
purple_message_get_author_name_color(PurpleMessage *message) {
	g_return_val_if_fail(PURPLE_IS_MESSAGE(message), NULL);

	return message->author_name_color;
}

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