# HG changeset patch
# Node ID 36963a8ebbc4
# Parent  449e20a06b79
diff --git a/libpurple/protocols/demo/meson.build b/libpurple/protocols/demo/meson.build
--- a/libpurple/protocols/demo/meson.build
+++ b/libpurple/protocols/demo/meson.build
@@ -5,6 +5,8 @@ DEMO_SOURCES = [
 	'purpledemoplugin.h',
 	'purpledemoprotocol.c',
 	'purpledemoprotocol.h',
+	'purpledemoprotocolactions.c',
+	'purpledemoprotocolactions.h',
 	'purpledemoprotocolclient.c',
 	'purpledemoprotocolclient.h',
 	'purpledemoprotocolim.c',
diff --git a/libpurple/protocols/demo/purpledemoprotocol.c b/libpurple/protocols/demo/purpledemoprotocol.c
--- a/libpurple/protocols/demo/purpledemoprotocol.c
+++ b/libpurple/protocols/demo/purpledemoprotocol.c
@@ -21,6 +21,7 @@
 #include <glib/gi18n-lib.h>
 
 #include "purpledemoprotocol.h"
+#include "purpledemoprotocolactions.h"
 #include "purpledemoprotocolclient.h"
 #include "purpledemoprotocolim.h"
 
@@ -78,6 +79,8 @@ G_DEFINE_DYNAMIC_TYPE_EXTENDED(
 	purple_demo_protocol,
 	PURPLE_TYPE_PROTOCOL,
 	0,
+	G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_ACTIONS,
+	                              purple_demo_protocol_actions_init)
 	G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_CLIENT,
 	                              purple_demo_protocol_client_init)
 	G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_IM,
diff --git a/libpurple/protocols/demo/purpledemoprotocolactions.h b/libpurple/protocols/demo/purpledemoprotocolactions.h
new file mode 100644
--- /dev/null
+++ b/libpurple/protocols/demo/purpledemoprotocolactions.h
@@ -0,0 +1,28 @@
+/*
+ * 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/>.
+ */
+
+#ifndef PURPLE_DEMO_PROTOCOL_ACTIONS_H
+#define PURPLE_DEMO_PROTOCOL_ACTIONS_H
+
+#include <glib.h>
+
+#include <purple.h>
+
+G_GNUC_INTERNAL void purple_demo_protocol_actions_init(PurpleProtocolActionsInterface *iface);
+
+#endif /* PURPLE_DEMO_PROTOCOL_ACTIONS_H */
diff --git a/libpurple/protocols/demo/purpledemoprotocolactions.c b/libpurple/protocols/demo/purpledemoprotocolactions.c
new file mode 100644
--- /dev/null
+++ b/libpurple/protocols/demo/purpledemoprotocolactions.c
@@ -0,0 +1,186 @@
+/*
+ * 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/gi18n-lib.h>
+
+#include "purpledemoprotocol.h"
+#include "purpledemoprotocolactions.h"
+
+/******************************************************************************
+ * Action Implementations
+ *****************************************************************************/
+#define REAPER_BUDDY_NAME ("Gary")
+#define DEFAULT_REAP_TIME (5)  /* seconds */
+
+static gboolean
+purple_demo_protocol_failure_fatal_cb(gpointer data) {
+	PurpleConnection *connection = PURPLE_CONNECTION(data);
+	PurpleAccount *account = purple_connection_get_account(connection);
+	gchar *message = NULL;
+	gint timeout = 0;
+
+	timeout = GPOINTER_TO_INT(g_object_steal_data(G_OBJECT(connection),
+	                                              "reaping-time"));
+	timeout--;
+	if(timeout > 0) {
+		g_object_set_data(G_OBJECT(connection), "reaping-time",
+		                  GINT_TO_POINTER(timeout));
+
+		message = g_strdup_printf(ngettext("Reaping connection in %d second...",
+		                                   "Reaping connection in %d seconds...",
+		                                   timeout),
+		                          timeout);
+		purple_protocol_got_user_status(account, REAPER_BUDDY_NAME,
+		                                "available", "message", message, NULL);
+		g_free(message);
+
+		return G_SOURCE_CONTINUE;
+	}
+
+	message = g_strdup_printf("%s reaped the connection", REAPER_BUDDY_NAME);
+	purple_connection_error(connection, PURPLE_CONNECTION_ERROR_OTHER_ERROR,
+	                        message);
+	g_free(message);
+
+	return G_SOURCE_REMOVE;
+}
+
+static gboolean
+purple_demo_protocol_failure_temporary_cb(gpointer data) {
+	PurpleConnection *connection = PURPLE_CONNECTION(data);
+	PurpleAccount *account = purple_connection_get_account(connection);
+	gchar *message = NULL;
+	gint timeout = 0;
+
+	timeout = GPOINTER_TO_INT(g_object_steal_data(G_OBJECT(connection),
+	                                              "reaping-time"));
+	timeout--;
+	if(timeout > 0) {
+		g_object_set_data(G_OBJECT(connection), "reaping-time",
+		                  GINT_TO_POINTER(timeout));
+
+		message = g_strdup_printf(ngettext("Pruning connection in %d second...",
+		                                   "Pruning connection in %d seconds...",
+		                                   timeout),
+		                          timeout);
+		purple_protocol_got_user_status(account, REAPER_BUDDY_NAME,
+		                                "available", "message", message, NULL);
+		g_free(message);
+
+		return G_SOURCE_CONTINUE;
+	}
+
+	message = g_strdup_printf("%s pruned the connection", REAPER_BUDDY_NAME);
+	purple_connection_error(connection, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+	                        message);
+	g_free(message);
+
+	return G_SOURCE_REMOVE;
+}
+
+static void
+purple_demo_protocol_failure_action_activate(GSimpleAction *action,
+                                             GVariant *parameter,
+                                             gpointer data)
+{
+	PurpleConnection *connection = PURPLE_CONNECTION(data);
+	PurpleAccount *account = purple_connection_get_account(connection);
+	gboolean fatal = FALSE;
+	gchar *status = NULL;
+
+	if(!g_variant_is_of_type(parameter, G_VARIANT_TYPE_BOOLEAN)) {
+		g_critical("Demo failure action parameter is of incorrect type %s",
+		           g_variant_get_type_string(parameter));
+	}
+
+	fatal = g_variant_get_boolean(parameter);
+
+	purple_protocol_got_user_idle(account, REAPER_BUDDY_NAME, FALSE, 0);
+	if(fatal) {
+		status = g_strdup_printf(
+		        ngettext("Reaping connection in %d second...",
+		                 "Reaping connection in %d seconds...",
+		                 DEFAULT_REAP_TIME),
+		        DEFAULT_REAP_TIME);
+	} else {
+		status = g_strdup_printf(
+		        ngettext("Pruning connection in %d second...",
+		                 "Pruning connection in %d seconds...",
+		                 DEFAULT_REAP_TIME),
+		        DEFAULT_REAP_TIME);
+	}
+	purple_protocol_got_user_status(account, REAPER_BUDDY_NAME, "available",
+	                                "message", status, NULL);
+	g_free(status);
+
+	g_object_set_data(G_OBJECT(connection), "reaping-time",
+	                  GINT_TO_POINTER(DEFAULT_REAP_TIME));
+	if(fatal) {
+		g_timeout_add_seconds(1, purple_demo_protocol_failure_fatal_cb,
+		                      connection);
+	} else {
+		g_timeout_add_seconds(1, purple_demo_protocol_failure_temporary_cb,
+		                      connection);
+	}
+	g_simple_action_set_enabled(action, FALSE);
+}
+
+/******************************************************************************
+ * PurpleProtocolActions Implementation
+ *****************************************************************************/
+static GActionGroup *
+purple_demo_protocol_get_action_group(PurpleProtocolActions *actions,
+                                      PurpleConnection *connection)
+{
+	GSimpleActionGroup *group = NULL;
+	GActionEntry entries[] = {
+		{
+			.name = "failure",
+			.activate = purple_demo_protocol_failure_action_activate,
+			.parameter_type = "b",
+		},
+	};
+	gsize nentries = G_N_ELEMENTS(entries);
+
+	group = g_simple_action_group_new();
+	g_action_map_add_action_entries(G_ACTION_MAP(group), entries, nentries,
+	                                connection);
+
+	return G_ACTION_GROUP(group);
+}
+
+static GMenu *
+purple_demo_protocol_get_menu(PurpleProtocolActions *actions)
+{
+	GMenu *menu = NULL;
+
+	menu = g_menu_new();
+
+	g_menu_insert(menu, 0, _("Trigger temporary connection failure..."),
+	              "prpl-demo.failure(false)");
+	g_menu_insert(menu, 1, _("Trigger fatal connection failure..."),
+	              "prpl-demo.failure(true)");
+
+	return menu;
+}
+
+void
+purple_demo_protocol_actions_init(PurpleProtocolActionsInterface *iface) {
+	iface->get_action_group = purple_demo_protocol_get_action_group;
+	iface->get_menu = purple_demo_protocol_get_menu;
+}
