# HG changeset patch
# Node ID adbcfceea77ef0b4ada2aa2630ba5dfd90ce4fc3
# Parent  28a4480fe7463e4db57daa17a4aa81534678883b
diff --git a/libpurple/meson.build b/libpurple/meson.build
--- a/libpurple/meson.build
+++ b/libpurple/meson.build
@@ -45,6 +45,7 @@
 	'purplemessages.c',
 	'purplenoopcredentialprovider.c',
 	'purplenotification.c',
+	'purplenotificationaddcontact.c',
 	'purplenotificationauthorizationrequest.c',
 	'purplenotificationmanager.c',
 	'purpleoptions.c',
@@ -135,6 +136,7 @@
 	'purplemessages.h',
 	'purplenoopcredentialprovider.h',
 	'purplenotification.h',
+	'purplenotificationaddcontact.h',
 	'purplenotificationauthorizationrequest.h',
 	'purplenotificationmanager.h',
 	'purpleoptions.h',
diff --git a/libpurple/purplenotification.c b/libpurple/purplenotification.c
--- a/libpurple/purplenotification.c
+++ b/libpurple/purplenotification.c
@@ -27,6 +27,7 @@
 #include "purplenotification.h"
 
 #include "purpleenums.h"
+#include "purplenotificationaddcontact.h"
 #include "util.h"
 
 typedef struct {
@@ -504,28 +505,9 @@
 PurpleNotification *
 purple_notification_new_from_add_contact_request(PurpleAddContactRequest *request)
 {
-	PurpleAccount *account = NULL;
-	PurpleContact *remote = NULL;
-	PurpleContactInfo *info = NULL;
-	PurpleNotification *notification = NULL;
-	char *title = NULL;
-
 	g_return_val_if_fail(PURPLE_IS_ADD_CONTACT_REQUEST(request), NULL);
 
-	remote = purple_add_contact_request_get_contact(request);
-	account = purple_contact_get_account(remote);
-	info = purple_account_get_contact_info(account);
-
-	notification = purple_notification_new(PURPLE_NOTIFICATION_TYPE_ADD_CONTACT,
-	                                       account, request, g_object_unref);
-
-	title = g_strdup_printf(_("%s added %s to their contact_list"),
-	                        purple_contact_info_get_name_for_display(PURPLE_CONTACT_INFO(remote)),
-	                        purple_contact_info_get_name_for_display(info));
-	purple_notification_set_title(notification, title);
-	g_free(title);
-
-	return notification;
+	return purple_notification_add_contact_new(request);
 }
 
 PurpleNotification *
diff --git a/libpurple/purplenotification.h b/libpurple/purplenotification.h
--- a/libpurple/purplenotification.h
+++ b/libpurple/purplenotification.h
@@ -127,8 +127,10 @@
  * Returns: (transfer full): The new notification.
  *
  * Since: 3.0
+ *
+ * Deprecated: 3.0
  */
-PURPLE_AVAILABLE_IN_3_0
+PURPLE_DEPRECATED_FOR(purple_notification_add_contact_new)
 PurpleNotification *purple_notification_new_from_add_contact_request(PurpleAddContactRequest *request);
 
 /**
diff --git a/libpurple/purplenotificationaddcontact.c b/libpurple/purplenotificationaddcontact.c
new file mode 100644
--- /dev/null
+++ b/libpurple/purplenotificationaddcontact.c
@@ -0,0 +1,227 @@
+/*
+ * 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 <glib/gi18n-lib.h>
+
+#include "purplenotificationaddcontact.h"
+
+struct _PurpleNotificationAddContact {
+	PurpleNotification parent;
+
+	PurpleAddContactRequest *request;
+};
+
+enum {
+	PROP_0,
+	PROP_REQUEST,
+	N_PROPERTIES,
+};
+static GParamSpec *properties[N_PROPERTIES] = {NULL, };
+
+static void
+purple_notification_add_contact_contact_notify_cb(GObject *obj,
+                                                  GParamSpec *pspec,
+                                                  gpointer data);
+static void
+purple_notification_add_contact_request_notify_cb(GObject *obj,
+                                                  GParamSpec *pspec,
+                                                  gpointer data);
+
+/******************************************************************************
+ * Helpers
+ *****************************************************************************/
+static void
+purple_notification_add_contact_update(PurpleNotificationAddContact *notification)
+{
+	PurpleAccount *account = NULL;
+	PurpleContact *remote = NULL;
+	PurpleContactInfo *info = NULL;
+	char *title = NULL;
+
+	g_return_if_fail(PURPLE_IS_NOTIFICATION_ADD_CONTACT(notification));
+
+	remote = purple_add_contact_request_get_contact(notification->request);
+	account = purple_contact_get_account(remote);
+	info = purple_account_get_contact_info(account);
+
+	title = g_strdup_printf(_("%s added %s to their contact_list"),
+	                        purple_contact_info_get_name_for_display(PURPLE_CONTACT_INFO(remote)),
+	                        purple_contact_info_get_name_for_display(info));
+	purple_notification_set_title(PURPLE_NOTIFICATION(notification), title);
+	g_free(title);
+}
+
+static void
+purple_notification_add_contact_set_request(PurpleNotificationAddContact *notification,
+                                            PurpleAddContactRequest *request)
+{
+	g_return_if_fail(PURPLE_IS_NOTIFICATION_ADD_CONTACT(notification));
+
+	if(g_set_object(&notification->request, request)) {
+		if(PURPLE_IS_ADD_CONTACT_REQUEST(request)) {
+			PurpleContact *contact = NULL;
+
+			contact = purple_add_contact_request_get_contact(request);
+			g_signal_connect_object(contact, "notify",
+			                        G_CALLBACK(purple_notification_add_contact_contact_notify_cb),
+			                        notification, G_CONNECT_DEFAULT);
+
+			/* We need to know when the contact or the message changes. */
+			g_signal_connect_object(request, "notify",
+			                        G_CALLBACK(purple_notification_add_contact_request_notify_cb),
+			                        notification, G_CONNECT_DEFAULT);
+		}
+
+		g_object_notify_by_pspec(G_OBJECT(notification),
+		                         properties[PROP_REQUEST]);
+
+		purple_notification_add_contact_update(notification);
+	}
+}
+
+/******************************************************************************
+ * Callbacks
+ *****************************************************************************/
+static void
+purple_notification_add_contact_contact_notify_cb(G_GNUC_UNUSED GObject *obj,
+                                                  G_GNUC_UNUSED GParamSpec *pspec,
+                                                  gpointer data)
+{
+	purple_notification_add_contact_update(data);
+}
+
+static void
+purple_notification_add_contact_request_notify_cb(G_GNUC_UNUSED GObject *obj,
+                                                  G_GNUC_UNUSED GParamSpec *pspec,
+                                                  gpointer data)
+{
+	purple_notification_add_contact_update(data);
+}
+
+/******************************************************************************
+ * GObject Implementation
+ *****************************************************************************/
+G_DEFINE_FINAL_TYPE(PurpleNotificationAddContact,
+                    purple_notification_add_contact, PURPLE_TYPE_NOTIFICATION)
+
+static void
+purple_notification_add_contact_finalize(GObject *obj) {
+	PurpleNotificationAddContact *notification = NULL;
+
+	notification = PURPLE_NOTIFICATION_ADD_CONTACT(obj);
+
+	g_clear_object(&notification->request);
+
+	G_OBJECT_CLASS(purple_notification_add_contact_parent_class)->finalize(obj);
+}
+
+static void
+purple_notification_add_contact_get_property(GObject *obj, guint param_id,
+                                             GValue *value, GParamSpec *pspec)
+{
+	PurpleNotificationAddContact *notification = NULL;
+
+	notification = PURPLE_NOTIFICATION_ADD_CONTACT(obj);
+
+	switch(param_id) {
+	case PROP_REQUEST:
+		g_value_set_object(value,
+		                   purple_notification_add_contact_get_request(notification));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+		break;
+	}
+}
+
+static void
+purple_notification_add_contact_set_property(GObject *obj, guint param_id,
+                                             const GValue *value,
+                                             GParamSpec *pspec)
+{
+	PurpleNotificationAddContact *notification = NULL;
+
+	notification = PURPLE_NOTIFICATION_ADD_CONTACT(obj);
+
+	switch(param_id) {
+	case PROP_REQUEST:
+		purple_notification_add_contact_set_request(notification,
+		                                            g_value_get_object(value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+		break;
+	}
+}
+
+static void
+purple_notification_add_contact_init(PurpleNotificationAddContact *notification)
+{
+	purple_notification_set_icon_name(PURPLE_NOTIFICATION(notification),
+	                                  "contact-new-symbolic");
+}
+
+static void
+purple_notification_add_contact_class_init(PurpleNotificationAddContactClass *klass)
+{
+	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+
+	obj_class->finalize = purple_notification_add_contact_finalize;
+	obj_class->get_property = purple_notification_add_contact_get_property;
+	obj_class->set_property = purple_notification_add_contact_set_property;
+
+	/**
+	 * PurpleNotificationAddContact:request:
+	 *
+	 * The [class@AddContactRequest] that this notification is for.
+	 *
+	 * Since: 3.0
+	 */
+	properties[PROP_REQUEST] = g_param_spec_object(
+		"request", NULL, NULL,
+		PURPLE_TYPE_ADD_CONTACT_REQUEST,
+		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_add_contact_new(PurpleAddContactRequest *request) {
+	g_return_val_if_fail(PURPLE_IS_ADD_CONTACT_REQUEST(request), NULL);
+
+	return g_object_new(
+		PURPLE_TYPE_NOTIFICATION_ADD_CONTACT,
+		"request", request,
+		NULL);
+}
+
+PurpleAddContactRequest *
+purple_notification_add_contact_get_request(PurpleNotificationAddContact *notification)
+{
+	g_return_val_if_fail(PURPLE_IS_NOTIFICATION_ADD_CONTACT(notification),
+	                     NULL);
+
+	return notification->request;
+}
diff --git a/libpurple/purplenotificationaddcontact.h b/libpurple/purplenotificationaddcontact.h
new file mode 100644
--- /dev/null
+++ b/libpurple/purplenotificationaddcontact.h
@@ -0,0 +1,83 @@
+/*
+ * 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_ADD_CONTACT_H
+#define PURPLE_NOTIFICATION_ADD_CONTACT_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "purpleaddcontactrequest.h"
+#include "purplenotification.h"
+#include "purpleversion.h"
+
+G_BEGIN_DECLS
+
+/**
+ * PurpleNotificationAddContact:
+ *
+ * A [class@Notification] for [class@AddContactRequest]s.
+ *
+ * Since: 3.0
+ */
+
+#define PURPLE_TYPE_NOTIFICATION_ADD_CONTACT (purple_notification_add_contact_get_type())
+
+PURPLE_AVAILABLE_IN_3_0
+G_DECLARE_FINAL_TYPE(PurpleNotificationAddContact,
+                     purple_notification_add_contact,
+                     PURPLE, NOTIFICATION_ADD_CONTACT,
+                     PurpleNotification)
+
+/**
+ * purple_notification_add_contact_new:
+ * @request: The add contact request.
+ *
+ * Creates a new [class@Notification] for @request.
+ *
+ * Returns: The new notification.
+ *
+ * Since: 3.0
+ */
+PURPLE_AVAILABLE_IN_3_0
+PurpleNotification *purple_notification_add_contact_new(PurpleAddContactRequest *request);
+
+/**
+ * purple_notification_add_contact_get_request:
+ * @notification: The instance.
+ *
+ * Gets the [class@AddContactRequest] for @notification.
+ *
+ * Returns: (transfer none): The add contact request.
+ *
+ * Since: 3.0
+ */
+PURPLE_AVAILABLE_IN_3_0
+PurpleAddContactRequest *purple_notification_add_contact_get_request(PurpleNotificationAddContact *notification);
+
+G_END_DECLS
+
+#endif /* PURPLE_NOTIFICATION_ADD_CONTACT_H */
diff --git a/libpurple/tests/meson.build b/libpurple/tests/meson.build
--- a/libpurple/tests/meson.build
+++ b/libpurple/tests/meson.build
@@ -27,6 +27,7 @@
     'message',
     'messages',
     'notification',
+    'notification_add_contact',
     'notification_authorization_request',
     'notification_manager',
     'person',
diff --git a/libpurple/tests/test_notification_add_contact.c b/libpurple/tests/test_notification_add_contact.c
new file mode 100644
--- /dev/null
+++ b/libpurple/tests/test_notification_add_contact.c
@@ -0,0 +1,149 @@
+/*
+ * 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>
+
+/******************************************************************************
+ * Callbacks
+ *****************************************************************************/
+static void
+test_purple_notification_add_contact_notify_cb(GObject *obj,
+                                               G_GNUC_UNUSED GParamSpec *pspec,
+                                               gpointer data)
+{
+	guint *counter = data;
+
+	g_assert_true(PURPLE_IS_NOTIFICATION(obj));
+	g_assert_true(PURPLE_IS_NOTIFICATION_ADD_CONTACT(obj));
+
+	*counter = *counter + 1;
+}
+
+/******************************************************************************
+ * Tests
+ *****************************************************************************/
+static void
+test_purple_notification_add_contact_new(void) {
+	PurpleAccount *account = NULL;
+	PurpleAddContactRequest *request = NULL;
+	PurpleContact *contact = NULL;
+	PurpleNotification *notification = NULL;
+
+	account = purple_account_new("test", "test");
+	contact = purple_contact_new(account, "remote");
+	request = purple_add_contact_request_new(contact);
+	notification = purple_notification_add_contact_new(request);
+
+	g_assert_true(PURPLE_IS_NOTIFICATION(notification));
+	g_assert_true(PURPLE_IS_NOTIFICATION_ADD_CONTACT(notification));
+
+	g_assert_finalize_object(notification);
+
+	g_clear_object(&request);
+	g_clear_object(&contact);
+	g_clear_object(&account);
+}
+
+static void
+test_purple_notification_add_contact_properties(void) {
+	PurpleAccount *account = NULL;
+	PurpleAddContactRequest *request = NULL;
+	PurpleAddContactRequest *request1 = NULL;
+	PurpleContact *contact = NULL;
+	PurpleNotification *notification = NULL;
+
+	account = purple_account_new("test", "test");
+	contact = purple_contact_new(account, "username");
+	request = purple_add_contact_request_new(contact);
+
+	notification = g_object_new(
+		PURPLE_TYPE_NOTIFICATION_ADD_CONTACT,
+		"request", request,
+		NULL);
+
+	g_object_get(
+		notification,
+		"request", &request1,
+		NULL);
+
+	g_assert_true(request1 == request);
+	g_clear_object(&request1);
+
+	g_assert_finalize_object(notification);
+	g_assert_finalize_object(request);
+	g_assert_finalize_object(contact);
+
+	g_clear_object(&account);
+}
+
+static void
+test_purple_notification_add_contact_updates_title(void) {
+	PurpleAccount *account = NULL;
+	PurpleAddContactRequest *request = NULL;
+	PurpleContact *contact = NULL;
+	PurpleNotification *notification = NULL;
+	const char *title = NULL;
+	guint counter = 0;
+
+	account = purple_account_new("test", "test");
+	contact = purple_contact_new(account, "remote-username");
+	request = purple_add_contact_request_new(contact);
+
+	notification = purple_notification_add_contact_new(request);
+	g_signal_connect(notification, "notify::title",
+	                 G_CALLBACK(test_purple_notification_add_contact_notify_cb),
+	                 &counter);
+
+	/* Make sure the id is in the title after construction. */
+	title = purple_notification_get_title(notification);
+	g_assert_true(g_pattern_match_simple("*remote-username*", title));
+
+	/* Set the alias and make sure the title gets updated. */
+	g_assert_cmpuint(counter, ==, 0);
+	purple_contact_info_set_alias(PURPLE_CONTACT_INFO(contact), "test-alias");
+	g_assert_cmpuint(counter, ==, 1);
+
+	title = purple_notification_get_title(notification);
+	g_assert_true(g_pattern_match_simple("*test-alias*", title));
+
+	g_assert_finalize_object(notification);
+	g_assert_finalize_object(request);
+	g_assert_finalize_object(contact);
+
+	g_clear_object(&account);
+}
+
+/******************************************************************************
+ * Main
+ *****************************************************************************/
+int
+main(int argc, char *argv[]) {
+	g_test_init(&argc, &argv, NULL);
+	g_test_set_nonfatal_assertions();
+
+	g_test_add_func("/notification/add-contact/new",
+	                test_purple_notification_add_contact_new);
+	g_test_add_func("/notification/add-contact/properties",
+	                test_purple_notification_add_contact_properties);
+	g_test_add_func("/notification/add-contact/updates-title",
+	                test_purple_notification_add_contact_updates_title);
+
+	return g_test_run();
+}
