# HG changeset patch
# Node ID e468b55295d71e5630df2527702167afff64013e
# Parent  9e8b9ee3cfbbc3895ec98f4fd7d2193cd0c263c5
diff --git a/libpurple/meson.build b/libpurple/meson.build
--- a/libpurple/meson.build
+++ b/libpurple/meson.build
@@ -48,6 +48,7 @@
 	'purplenotification.c',
 	'purplenotificationaddcontact.c',
 	'purplenotificationauthorizationrequest.c',
+	'purplenotificationlink.c',
 	'purplenotificationmanager.c',
 	'purpleoptions.c',
 	'purplepath.c',
@@ -140,6 +141,7 @@
 	'purplenotification.h',
 	'purplenotificationaddcontact.h',
 	'purplenotificationauthorizationrequest.h',
+	'purplenotificationlink.h',
 	'purplenotificationmanager.h',
 	'purpleoptions.h',
 	'purplepath.h',
diff --git a/libpurple/purplenotificationlink.c b/libpurple/purplenotificationlink.c
new file mode 100644
--- /dev/null
+++ b/libpurple/purplenotificationlink.c
@@ -0,0 +1,206 @@
+/*
+ * 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 library 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 library 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 library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "purplenotificationlink.h"
+
+#include "util.h"
+
+struct _PurpleNotificationLink {
+	PurpleNotification parent;
+
+	char *link_text;
+	char *link_uri;
+};
+
+enum {
+	PROP_0,
+	PROP_LINK_TEXT,
+	PROP_LINK_URI,
+	N_PROPERTIES,
+};
+static GParamSpec *properties[N_PROPERTIES] = {NULL, };
+
+/******************************************************************************
+ * Helpers
+ *****************************************************************************/
+static void
+purple_notification_link_set_link_text(PurpleNotificationLink *notification,
+                                       const char *link_text)
+{
+	g_return_if_fail(PURPLE_IS_NOTIFICATION_LINK(notification));
+
+	if(g_set_str(&notification->link_text, link_text)) {
+		g_object_notify_by_pspec(G_OBJECT(notification),
+		                         properties[PROP_LINK_TEXT]);
+	}
+}
+
+static void
+purple_notification_link_set_link_uri(PurpleNotificationLink *notification,
+                                      const char *link_uri)
+{
+	g_return_if_fail(PURPLE_IS_NOTIFICATION_LINK(notification));
+	g_return_if_fail(!purple_strempty(link_uri));
+
+	if(g_set_str(&notification->link_uri, link_uri)) {
+		g_object_notify_by_pspec(G_OBJECT(notification),
+		                         properties[PROP_LINK_URI]);
+	}
+}
+
+/******************************************************************************
+ * GObject Implementation
+ *****************************************************************************/
+G_DEFINE_FINAL_TYPE(PurpleNotificationLink, purple_notification_link,
+                    PURPLE_TYPE_NOTIFICATION)
+
+static void
+purple_notification_link_finalize(GObject *obj) {
+	PurpleNotificationLink *notification = PURPLE_NOTIFICATION_LINK(obj);
+
+	g_clear_pointer(&notification->link_text, g_free);
+	g_clear_pointer(&notification->link_uri, g_free);
+
+	G_OBJECT_CLASS(purple_notification_link_parent_class)->finalize(obj);
+}
+
+static void
+purple_notification_link_get_property(GObject *obj, guint param_id,
+                                      GValue *value, GParamSpec *pspec)
+{
+	PurpleNotificationLink *notification = PURPLE_NOTIFICATION_LINK(obj);
+
+	switch(param_id) {
+	case PROP_LINK_TEXT:
+		g_value_set_string(value,
+		                   purple_notification_link_get_link_text(notification));
+		break;
+	case PROP_LINK_URI:
+		g_value_set_string(value,
+		                   purple_notification_link_get_link_uri(notification));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+		break;
+	}
+}
+
+static void
+purple_notification_link_set_property(GObject *obj, guint param_id,
+                                      const GValue *value, GParamSpec *pspec)
+{
+	PurpleNotificationLink *notification = PURPLE_NOTIFICATION_LINK(obj);
+
+	switch(param_id) {
+	case PROP_LINK_TEXT:
+		purple_notification_link_set_link_text(notification,
+		                                       g_value_get_string(value));
+		break;
+	case PROP_LINK_URI:
+		purple_notification_link_set_link_uri(notification,
+		                                      g_value_get_string(value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+		break;
+	}
+}
+
+static void
+purple_notification_link_init(G_GNUC_UNUSED PurpleNotificationLink *notification)
+{
+}
+
+static void
+purple_notification_link_class_init(PurpleNotificationLinkClass *klass) {
+	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+
+	obj_class->finalize = purple_notification_link_finalize;
+	obj_class->get_property = purple_notification_link_get_property;
+	obj_class->set_property = purple_notification_link_set_property;
+
+	/**
+	 * PurpleNotificationLink:link-text:
+	 *
+	 * The text to display instead of the URI.
+	 *
+	 * If this is not set, the value of [property@NotificationLink:link-uri]
+	 * will be returned.
+	 *
+	 * Since: 3.0
+	 */
+	properties[PROP_LINK_TEXT] = g_param_spec_string(
+		"link-text", NULL, NULL,
+		NULL,
+		G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+	/**
+	 * PurpleNotificationLink:link-uri:
+	 *
+	 * The URI for this notification.
+	 *
+	 * Since: 3.0
+	 */
+	properties[PROP_LINK_URI] = g_param_spec_string(
+		"link-uri", NULL, NULL,
+		NULL,
+		G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
+}
+
+/******************************************************************************
+ * Public API
+ *****************************************************************************/
+PurpleNotification *
+purple_notification_link_new(const char *id, const char *title,
+                             const char *link_text, const char *link_uri)
+{
+	g_return_val_if_fail(!purple_strempty(title), NULL);
+	g_return_val_if_fail(!purple_strempty(link_uri), NULL);
+
+	return g_object_new(
+		PURPLE_TYPE_NOTIFICATION_LINK,
+		"id", id,
+		"title", title,
+		"link-text", link_text,
+		"link-uri", link_uri,
+		NULL);
+}
+
+const char *
+purple_notification_link_get_link_text(PurpleNotificationLink *notification) {
+	g_return_val_if_fail(PURPLE_IS_NOTIFICATION_LINK(notification), NULL);
+
+	if(!purple_strempty(notification->link_text)) {
+		return notification->link_text;
+	}
+
+	return notification->link_uri;
+}
+
+const char *
+purple_notification_link_get_link_uri(PurpleNotificationLink *notification) {
+	g_return_val_if_fail(PURPLE_IS_NOTIFICATION_LINK(notification), NULL);
+
+	return notification->link_uri;
+}
diff --git a/libpurple/purplenotificationlink.h b/libpurple/purplenotificationlink.h
new file mode 100644
--- /dev/null
+++ b/libpurple/purplenotificationlink.h
@@ -0,0 +1,97 @@
+/*
+ * 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 library 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 library 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 library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#if !defined(PURPLE_GLOBAL_HEADER_INSIDE) && !defined(PURPLE_COMPILATION)
+# error "only <purple.h> may be included directly"
+#endif
+
+#ifndef PURPLE_NOTIFICATION_LINK_H
+#define PURPLE_NOTIFICATION_LINK_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "purplenotification.h"
+#include "purpleversion.h"
+
+G_BEGIN_DECLS
+
+/**
+ * PurpleNotificationLink:
+ *
+ * A [class@Notification] that contains a link for more information.
+ *
+ * Since: 3.0
+ */
+
+#define PURPLE_TYPE_NOTIFICATION_LINK (purple_notification_link_get_type())
+
+PURPLE_AVAILABLE_IN_3_0
+G_DECLARE_FINAL_TYPE(PurpleNotificationLink, purple_notification_link,
+                     PURPLE, NOTIFICATION_LINK, PurpleNotification)
+
+/**
+ * purple_notification_link_new:
+ * @id: (nullable): An identifier for this notification.
+ * @title: The title for the notification.
+ * @link_text: (nullable): The text to display for the link.
+ * @link_uri: The URI of the link.
+ *
+ * Creates a new [class@Notification] with a link to @link_uri.
+ *
+ * Returns: The new notification.
+ *
+ * Since: 3.0
+ */
+PURPLE_AVAILABLE_IN_3_0
+PurpleNotification *purple_notification_link_new(const char *id, const char *title, const char *link_text, const char *link_uri);
+
+/**
+ * purple_notification_link_get_link_text:
+ * @notification: The instance.
+ *
+ * The link text if set otherwise, the value of
+ * [property@NotificationLink:link-uri].
+ *
+ * Returns: The link text if set, otherwise the link URI.
+ *
+ * Since: 3.0
+ */
+PURPLE_AVAILABLE_IN_3_0
+const char *purple_notification_link_get_link_text(PurpleNotificationLink *notification);
+
+/**
+ * purple_notification_link_get_link_uri:
+ * @notification: The instance.
+ *
+ * The link URI.
+ *
+ * Returns: The link URI.
+ *
+ * Since: 3.0
+ */
+PURPLE_AVAILABLE_IN_3_0
+const char *purple_notification_link_get_link_uri(PurpleNotificationLink *notification);
+
+G_END_DECLS
+
+#endif /* PURPLE_NOTIFICATION_LINK_H */
diff --git a/libpurple/tests/meson.build b/libpurple/tests/meson.build
--- a/libpurple/tests/meson.build
+++ b/libpurple/tests/meson.build
@@ -30,6 +30,7 @@
     'notification',
     'notification_add_contact',
     'notification_authorization_request',
+    'notification_link',
     'notification_manager',
     'person',
     'presence',
diff --git a/libpurple/tests/test_notification_link.c b/libpurple/tests/test_notification_link.c
new file mode 100644
--- /dev/null
+++ b/libpurple/tests/test_notification_link.c
@@ -0,0 +1,108 @@
+/*
+ * Purple - Internet Messaging Library
+ * Copyright (C) Pidgin Developers <devel@pidgin.im>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+
+#include <purple.h>
+
+/******************************************************************************
+ * Tests
+ *****************************************************************************/
+static void
+test_purple_notification_link_new(void) {
+	PurpleNotification *notification = NULL;
+
+	notification = purple_notification_link_new(NULL, "insert title", NULL,
+	                                            "https://pidgin.im/");
+
+	g_assert_true(PURPLE_IS_NOTIFICATION(notification));
+	g_assert_true(PURPLE_IS_NOTIFICATION_LINK(notification));
+
+	g_assert_finalize_object(notification);
+}
+
+static void
+test_purple_notification_link_properties(void) {
+	PurpleNotification *notification = NULL;
+	char *id = NULL;
+	char *title = NULL;
+	char *link_text = NULL;
+	char *link_uri = NULL;
+
+	notification = g_object_new(
+		PURPLE_TYPE_NOTIFICATION_LINK,
+		"id", "notification1",
+		"title", "title1",
+		"link-text", "pidgin.im",
+		"link-uri", "https://pidgin.im/",
+		NULL);
+
+	g_object_get(
+		notification,
+		"id", &id,
+		"title", &title,
+		"link-text", &link_text,
+		"link-uri", &link_uri,
+		NULL);
+
+	g_assert_cmpstr(id, ==, "notification1");
+	g_clear_pointer(&id, g_free);
+
+	g_assert_cmpstr(title, ==, "title1");
+	g_clear_pointer(&title, g_free);
+
+	g_assert_cmpstr(link_text, ==, "pidgin.im");
+	g_clear_pointer(&link_text, g_free);
+
+	g_assert_cmpstr(link_uri, ==, "https://pidgin.im/");
+	g_clear_pointer(&link_uri, g_free);
+
+	g_assert_finalize_object(notification);
+}
+
+static void
+test_purple_notification_link_null_link_text(void) {
+	PurpleNotification *notification = NULL;
+	const char *link_text = NULL;
+
+	notification = purple_notification_link_new(NULL, "title1", NULL,
+	                                            "https://pidgin.im/");
+
+	link_text = purple_notification_link_get_link_text(PURPLE_NOTIFICATION_LINK(notification));
+	g_assert_cmpstr(link_text, ==, "https://pidgin.im/");
+
+	g_assert_finalize_object(notification);
+}
+
+/******************************************************************************
+ * Main
+ *****************************************************************************/
+int
+main(int argc, char *argv[]) {
+	g_test_init(&argc, &argv, NULL);
+	g_test_set_nonfatal_assertions();
+
+	g_test_add_func("/notification/link/new",
+	                test_purple_notification_link_new);
+	g_test_add_func("/notification/link/properties",
+	                test_purple_notification_link_properties);
+	g_test_add_func("/notification/link/null-link-text",
+	                test_purple_notification_link_null_link_text);
+
+	return g_test_run();
+}
