diff --git a/libpurple/purplepresence.h b/libpurple/purplepresence.h
--- a/libpurple/purplepresence.h
+++ b/libpurple/purplepresence.h
@@ -27,6 +27,9 @@
 #ifndef PURPLE_PRESENCE_H
 #define PURPLE_PRESENCE_H
 
+#include <glib.h>
+#include <glib-object.h>
+
 /**
  * PurplePresence:
  *
@@ -73,6 +76,17 @@
                          GObject)
 
 /**
+ * purple_presence_new:
+ *
+ * Creates a new presence instance.
+ *
+ * Returns: (transfer full): The new instance.
+ *
+ * Since: 3.0.0
+ */
+PurplePresence *purple_presence_new(void);
+
+/**
  * purple_presence_set_status_active:
  * @presence: The #PurplePresence instance.
  * @status_id: The ID of the status.
@@ -246,6 +260,30 @@
  */
 gint purple_presence_compare(PurplePresence *presence1, PurplePresence *presence2);
 
+/**
+ * purple_presence_get_primitive:
+ * @presence: The instance.
+ *
+ * Gets the [enum@Purple.StatusPrimitive] for @presence.
+ *
+ * Returns: The current primitive.
+ *
+ * Since: 3.0.0
+ */
+PurpleStatusPrimitive purple_presence_get_primitive(PurplePresence *presence);
+
+/**
+ * purple_presence_get_message:
+ * @presence: The instance.
+ *
+ * Gets the status message for @presence if one is set.
+ *
+ * Returns: (nullable): The status message of @presence.
+ *
+ * Since: 3.0.0
+ */
+const char *purple_presence_get_message(PurplePresence *presence);
+
 G_END_DECLS
 
 #endif /* PURPLE_PRESENCE_H */
# HG changeset patch
# Node ID eccc250b7351
# Parent  16d2e16bd24f
diff --git a/libpurple/purplepresence.c b/libpurple/purplepresence.c
--- a/libpurple/purplepresence.c
+++ b/libpurple/purplepresence.c
@@ -22,9 +22,11 @@
 
 #include <glib/gi18n-lib.h>
 
+#include "purplepresence.h"
+
 #include "internal.h"
 #include "debug.h"
-#include "purplepresence.h"
+#include "purpleenums.h"
 #include "purpleprivate.h"
 
 typedef struct {
@@ -43,6 +45,8 @@
 	PROP_IDLE_TIME,
 	PROP_LOGIN_TIME,
 	PROP_ACTIVE_STATUS,
+	PROP_PRIMITIVE,
+	PROP_MESSAGE,
 	N_PROPERTIES
 };
 static GParamSpec *properties[N_PROPERTIES];
@@ -61,8 +65,13 @@
 	priv = purple_presence_get_instance_private(presence);
 
 	if(g_set_object(&priv->active_status, status)) {
-		g_object_notify_by_pspec(G_OBJECT(presence),
-		                         properties[PROP_ACTIVE_STATUS]);
+		GObject *obj = G_OBJECT(presence);
+
+		g_object_freeze_notify(obj);
+		g_object_notify_by_pspec(obj, properties[PROP_ACTIVE_STATUS]);
+		g_object_notify_by_pspec(obj, properties[PROP_PRIMITIVE]);
+		g_object_notify_by_pspec(obj, properties[PROP_MESSAGE]);
+		g_object_thaw_notify(obj);
 	}
 }
 
@@ -126,6 +135,12 @@
 		case PROP_ACTIVE_STATUS:
 			g_value_set_object(value, purple_presence_get_active_status(presence));
 			break;
+		case PROP_PRIMITIVE:
+			g_value_set_enum(value, purple_presence_get_primitive(presence));
+			break;
+		case PROP_MESSAGE:
+			g_value_set_string(value, purple_presence_get_message(presence));
+			break;
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
 			break;
@@ -216,12 +231,44 @@
 				"The active status for the presence.", PURPLE_TYPE_STATUS,
 				G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 
+	/**
+	 * PurplePresence:primitive:
+	 *
+	 * The [enum@Purple.StatusPrimitive] for this presence.
+	 *
+	 * Since: 3.0.0
+	 */
+	properties[PROP_PRIMITIVE] = g_param_spec_enum(
+		"primitive", "primitive",
+		"The primitive for the presence",
+		PURPLE_TYPE_STATUS_PRIMITIVE,
+		PURPLE_STATUS_UNSET,
+		G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+	/**
+	 * PurplePresence:message:
+	 *
+	 * The status message of the presence.
+	 *
+	 * Since: 3.0.0
+	 */
+	properties[PROP_MESSAGE] = g_param_spec_string(
+		"message", "message",
+		"The status message",
+		NULL,
+		G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
 	g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
 }
 
 /******************************************************************************
  * Public API
  *****************************************************************************/
+PurplePresence *
+purple_presence_new(void) {
+	return g_object_new(PURPLE_TYPE_PRESENCE, NULL);
+}
+
 void
 purple_presence_set_status_active(PurplePresence *presence,
                                   const gchar *status_id, gboolean active)
@@ -511,3 +558,31 @@
 
 	return 0;
 }
+
+PurpleStatusPrimitive
+purple_presence_get_primitive(PurplePresence *presence) {
+	PurplePresencePrivate *priv = NULL;
+	PurpleStatusType *type = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), PURPLE_STATUS_UNSET);
+
+	priv = purple_presence_get_instance_private(presence);
+
+	type = purple_status_get_status_type(priv->active_status);
+	if(type != NULL) {
+		return purple_status_type_get_primitive(type);
+	}
+
+	return PURPLE_STATUS_UNSET;
+}
+
+const char *
+purple_presence_get_message(PurplePresence *presence) {
+	PurplePresencePrivate *priv = NULL;
+
+	g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), NULL);
+
+	priv = purple_presence_get_instance_private(presence);
+
+	return purple_status_get_attr_string(priv->active_status, "message");
+}
diff --git a/libpurple/tests/meson.build b/libpurple/tests/meson.build
--- a/libpurple/tests/meson.build
+++ b/libpurple/tests/meson.build
@@ -17,6 +17,7 @@
     'notification',
     'notification_manager',
     'person',
+    'presence',
     'protocol',
     'protocol_action',
     'protocol_xfer',
diff --git a/libpurple/tests/test_presence.c b/libpurple/tests/test_presence.c
new file mode 100644
--- /dev/null
+++ b/libpurple/tests/test_presence.c
@@ -0,0 +1,105 @@
+/*
+ * 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>
+
+/******************************************************************************
+ * Main
+ *****************************************************************************/
+static void
+test_purple_presence_migrate_online_without_message(void) {
+	PurplePresence *presence = NULL;
+	PurpleStatus *status = NULL;
+	PurpleStatusType *type = NULL;
+
+	type = purple_status_type_new(PURPLE_STATUS_AVAILABLE,
+	                              "online", "online", TRUE);
+	presence = purple_presence_new();
+	status = purple_status_new(type, presence);
+
+	purple_status_set_active(status, TRUE);
+
+	/* Now verify that the presence returns the correct values for the
+	 * properties.
+	 */
+	g_assert_cmpint(purple_presence_get_primitive(presence), ==,
+	                PURPLE_STATUS_AVAILABLE);
+	g_assert_null(purple_presence_get_message(presence));
+
+	/* Cleanup. */
+	g_clear_object(&presence);
+	g_clear_object(&status);
+	g_clear_pointer(&type, purple_status_type_destroy);
+}
+
+static void
+test_purple_presence_migrate_online_with_message(void) {
+	PurplePresence *presence = NULL;
+	PurpleStatus *status = NULL;
+	PurpleStatusType *type = NULL;
+	GHashTable *attrs =  NULL;
+
+	type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE,
+	                                         "online", "online",
+	                                         FALSE, TRUE, TRUE,
+	                                         "message", "message",
+	                                         purple_value_new(G_TYPE_STRING),
+	                                         NULL);
+	presence = purple_presence_new();
+
+	status = purple_status_new(type, presence);
+
+	attrs = g_hash_table_new(g_str_hash, g_str_equal);
+	g_hash_table_insert(attrs, "message", "Greetings Programs!");
+	purple_status_set_active_with_attributes(status, TRUE, attrs);
+	g_hash_table_destroy(attrs);
+
+	/* Now verify that the presence returns the correct values for the
+	 * properties.
+	 */
+	g_assert_cmpint(purple_presence_get_primitive(presence), ==,
+	                PURPLE_STATUS_AVAILABLE);
+	g_assert_cmpstr(purple_presence_get_message(presence), ==,
+	                "Greetings Programs!");
+
+	/* Cleanup. */
+	g_clear_object(&presence);
+	g_clear_object(&status);
+	g_clear_pointer(&type, purple_status_type_destroy);
+}
+
+/******************************************************************************
+ * Main
+ *****************************************************************************/
+gint
+main(gint argc, gchar *argv[]) {
+	g_test_init(&argc, &argv, NULL);
+
+	/* This tests verify that PurplePresence is properly notifying of property
+	 * changes with the 2.x.y and earlier status back end. When PurplePresence
+	 * has replaced that back end, these tests should be removed as well.
+	 */
+	g_test_add_func("/presence/migrate/online-without-message",
+	                test_purple_presence_migrate_online_without_message);
+	g_test_add_func("/presence/migrate/online-with-message",
+	                test_purple_presence_migrate_online_with_message);
+
+	return g_test_run();
+}
