# HG changeset patch
# Node ID 573ba2ff1a44
# Parent  b069ea54b906
diff --git a/libpurple/meson.build b/libpurple/meson.build
--- a/libpurple/meson.build
+++ b/libpurple/meson.build
@@ -52,6 +52,7 @@
 	'purpleconversationmanager.c',
 	'purpleconversationmember.c',
 	'purpleconversationuiops.c',
+	'purplecreateconversationdetails.c',
 	'purplecredentialmanager.c',
 	'purplecredentialprovider.c',
 	'purpledebugui.c',
@@ -176,6 +177,7 @@
 	'purpleconversationmanager.h',
 	'purpleconversationmember.h',
 	'purpleconversationuiops.h',
+	'purplecreateconversationdetails.h',
 	'purplecredentialmanager.h',
 	'purplecredentialprovider.h',
 	'purpledebugui.h',
diff --git a/libpurple/purplecreateconversationdetails.h b/libpurple/purplecreateconversationdetails.h
new file mode 100644
--- /dev/null
+++ b/libpurple/purplecreateconversationdetails.h
@@ -0,0 +1,114 @@
+/*
+ * 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_CREATE_CONVERSATION_DETAILS_H
+#define PURPLE_CREATE_CONVERSATION_DETAILS_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "purpleversion.h"
+
+G_BEGIN_DECLS
+
+#define PURPLE_TYPE_CREATE_CONVERSATION_DETAILS (purple_create_conversation_details_get_type())
+
+PURPLE_AVAILABLE_IN_3_0
+G_DECLARE_FINAL_TYPE(PurpleCreateConversationDetails, purple_create_conversation_details, PURPLE, CREATE_CONVERSATION_DETAILS, GObject)
+
+/**
+ * PurpleCreateConversationDetails:
+ *
+ * The details that are necessary for a [class@Protocol] to create a
+ * conversation.
+ *
+ * This is only used to create direct messages and group direct messages. The
+ * user interface will ask a protocol for a [class@CreateConversationDetails]
+ * and then fill it out and pass it back to the protocol to actually create a
+ * conversation.
+ *
+ * Since: 3.0
+ */
+
+/**
+ * purple_create_conversation_details_new:
+ * @max_participants: The maximum number of participants. %0 to say unlimited.
+ *
+ * Creates a new [class@CreateConversationDetails].
+ *
+ * Returns: (transfer full): The new instance.
+ *
+ * Since: 3.0
+ */
+PURPLE_AVAILABLE_IN_3_0
+PurpleCreateConversationDetails *purple_create_conversation_details_new(guint max_participants);
+
+/**
+ * purple_create_conversation_details_get_max_participants:
+ * @details: The instance.
+ *
+ * Gets the maximum number of participants that are supported not including the
+ * libpurple user.
+ *
+ * Returns: The maximum number of participants.
+ *
+ * Since: 3.0
+ */
+PURPLE_AVAILABLE_IN_3_0
+guint purple_create_conversation_details_get_max_participants(PurpleCreateConversationDetails *details);
+
+/**
+ * purple_create_conversation_details_get_participants:
+ * @details: The instance.
+ *
+ * Gets the participants to add to the conversation.
+ *
+ * Returns: (transfer none) (nullable): The participants.
+ *
+ * Since: 3.0
+ */
+PURPLE_AVAILABLE_IN_3_0
+GListModel *purple_create_conversation_details_get_participants(PurpleCreateConversationDetails *details);
+
+/**
+ * purple_create_conversation_details_set_participants:
+ * @details: The instance.
+ * @participants: (nullable) (transfer none): The new participants.
+ *
+ * Sets the participants to @participants.
+ *
+ * Participants must have an item type of [class@Contact] and the number of
+ * items must be less than or equal to
+ * [property@CreateConversationDetails:max-participants].
+ *
+ * Since: 3.0
+ */
+PURPLE_AVAILABLE_IN_3_0
+void purple_create_conversation_details_set_participants(PurpleCreateConversationDetails *details, GListModel *participants);
+
+G_END_DECLS
+
+#endif /* PURPLE_CREATE_CONVERSATION_DETAILS_H */
diff --git a/libpurple/purplecreateconversationdetails.c b/libpurple/purplecreateconversationdetails.c
new file mode 100644
--- /dev/null
+++ b/libpurple/purplecreateconversationdetails.c
@@ -0,0 +1,213 @@
+/*
+ * 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 <gio/gio.h>
+
+#include "purplecreateconversationdetails.h"
+
+#include "purplecontact.h"
+
+enum {
+	PROP_0,
+	PROP_MAX_PARTICIPANTS,
+	PROP_PARTICIPANTS,
+	N_PROPERTIES,
+};
+static GParamSpec *properties[N_PROPERTIES] = {NULL, };
+
+struct _PurpleCreateConversationDetails {
+	GObject parent;
+
+	guint max_participants;
+	GListModel *participants;
+};
+
+/******************************************************************************
+ * Helpers
+ *****************************************************************************/
+static void
+purple_create_conversation_details_set_max_participants(PurpleCreateConversationDetails *details,
+                                                        guint max_participants)
+{
+	g_return_if_fail(PURPLE_IS_CREATE_CONVERSATION_DETAILS(details));
+
+	if(details->max_participants != max_participants) {
+		details->max_participants = max_participants;
+
+		g_object_notify_by_pspec(G_OBJECT(details),
+		                         properties[PROP_MAX_PARTICIPANTS]);
+	}
+}
+
+/******************************************************************************
+ * GObject Implementation
+ *****************************************************************************/
+G_DEFINE_TYPE(PurpleCreateConversationDetails,
+              purple_create_conversation_details,
+              G_TYPE_OBJECT)
+
+static void
+purple_create_conversation_details_finalize(GObject *obj) {
+	PurpleCreateConversationDetails *details = NULL;
+
+	details = PURPLE_CREATE_CONVERSATION_DETAILS(obj);
+
+	g_clear_object(&details->participants);
+
+	G_OBJECT_CLASS(purple_create_conversation_details_parent_class)->finalize(obj);
+}
+
+static void
+purple_create_conversation_details_get_property(GObject *obj, guint param_id,
+                                                GValue *value,
+                                                GParamSpec *pspec)
+{
+	PurpleCreateConversationDetails *details = NULL;
+
+	details = PURPLE_CREATE_CONVERSATION_DETAILS(obj);
+
+	switch(param_id) {
+	case PROP_MAX_PARTICIPANTS:
+		g_value_set_uint(value,
+		                 purple_create_conversation_details_get_max_participants(details));
+		break;
+	case PROP_PARTICIPANTS:
+		g_value_set_object(value,
+		                   purple_create_conversation_details_get_participants(details));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+		break;
+	}
+}
+
+static void
+purple_create_conversation_details_set_property(GObject *obj, guint param_id,
+                                                const GValue *value,
+                                                GParamSpec *pspec)
+{
+	PurpleCreateConversationDetails *details = NULL;
+
+	details = PURPLE_CREATE_CONVERSATION_DETAILS(obj);
+
+	switch(param_id) {
+	case PROP_MAX_PARTICIPANTS:
+		purple_create_conversation_details_set_max_participants(details,
+		                                                        g_value_get_uint(value));
+		break;
+	case PROP_PARTICIPANTS:
+		purple_create_conversation_details_set_participants(details,
+		                                                    g_value_get_object(value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+		break;
+	}
+}
+
+static void
+purple_create_conversation_details_init(G_GNUC_UNUSED PurpleCreateConversationDetails *details)
+{
+}
+
+static void
+purple_create_conversation_details_class_init(PurpleCreateConversationDetailsClass *klass)
+{
+	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+
+	obj_class->finalize = purple_create_conversation_details_finalize;
+	obj_class->get_property = purple_create_conversation_details_get_property;
+	obj_class->set_property = purple_create_conversation_details_set_property;
+
+	/**
+	 * PurpleCreateConversationDetails:max-participants:
+	 *
+	 * The maximum number of participants that can be supported by the
+	 * protocol not including the libpurple user.
+	 *
+	 * Since: 3.0.0
+	 */
+	properties[PROP_MAX_PARTICIPANTS] = g_param_spec_uint(
+		"max-participants", "max-participants",
+		"The maximum number of participants that the protocol supports.",
+		1, G_MAXUINT, 1,
+		G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+	/**
+	 * PurpleCreateConversationDetails:participants:
+	 *
+	 * A [iface@Gio.ListModel] of [class@Contact]s to add to the conversation
+	 * not including the libpurple user.
+	 *
+	 * Since: 3.0.0
+	 */
+	properties[PROP_PARTICIPANTS] = g_param_spec_object(
+		"participants", "participants",
+		"The list of contacts to add to the conversation.",
+		G_TYPE_LIST_MODEL,
+		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
+}
+
+/******************************************************************************
+ * Public API
+ *****************************************************************************/
+PurpleCreateConversationDetails *
+purple_create_conversation_details_new(guint max_participants) {
+	return g_object_new(
+		PURPLE_TYPE_CREATE_CONVERSATION_DETAILS,
+		"max-participants", max_participants,
+		NULL);
+}
+
+guint
+purple_create_conversation_details_get_max_participants(PurpleCreateConversationDetails *details)
+{
+	g_return_val_if_fail(PURPLE_IS_CREATE_CONVERSATION_DETAILS(details), 0);
+
+	return details->max_participants;
+}
+
+GListModel *
+purple_create_conversation_details_get_participants(PurpleCreateConversationDetails *details)
+{
+	g_return_val_if_fail(PURPLE_IS_CREATE_CONVERSATION_DETAILS(details), NULL);
+
+	return details->participants;
+}
+
+void
+purple_create_conversation_details_set_participants(PurpleCreateConversationDetails *details,
+                                                    GListModel *participants)
+{
+	g_return_if_fail(PURPLE_IS_CREATE_CONVERSATION_DETAILS(details));
+
+	if(G_IS_LIST_MODEL(participants)) {
+		g_return_if_fail(g_list_model_get_item_type(participants) == PURPLE_TYPE_CONTACT);
+	}
+
+	if(g_set_object(&details->participants, participants)) {
+		g_object_notify_by_pspec(G_OBJECT(details),
+		                         properties[PROP_PARTICIPANTS]);
+	}
+}
diff --git a/libpurple/tests/meson.build b/libpurple/tests/meson.build
--- a/libpurple/tests/meson.build
+++ b/libpurple/tests/meson.build
@@ -4,6 +4,7 @@
     'authorization_request',
     'channel_join_details',
     'circular_buffer',
+    'create_conversation_details',
     'contact',
     'contact_info',
     'contact_manager',
diff --git a/libpurple/tests/test_create_conversation_details.c b/libpurple/tests/test_create_conversation_details.c
new file mode 100644
--- /dev/null
+++ b/libpurple/tests/test_create_conversation_details.c
@@ -0,0 +1,87 @@
+/*
+ * 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.h>
+
+#include <purple.h>
+
+/******************************************************************************
+ * Tests
+ *****************************************************************************/
+static void
+test_purple_create_conversation_details_new(void) {
+	PurpleCreateConversationDetails *details = NULL;
+
+	details = purple_create_conversation_details_new(9);
+	g_assert_true(PURPLE_IS_CREATE_CONVERSATION_DETAILS(details));
+
+	g_assert_finalize_object(details);
+}
+
+static void
+test_purple_create_conversation_details_properties(void) {
+	PurpleCreateConversationDetails *details = NULL;
+	GListStore *store = NULL;
+	GListModel *model = NULL;
+	guint max_participants = 0;
+
+	store = g_list_store_new(PURPLE_TYPE_CONTACT);
+
+	details = g_object_new(
+		PURPLE_TYPE_CREATE_CONVERSATION_DETAILS,
+		"max-participants", 9,
+		"participants", store,
+		NULL);
+
+	g_assert_true(PURPLE_IS_CREATE_CONVERSATION_DETAILS(details));
+
+	g_object_get(
+		G_OBJECT(details),
+		"max-participants", &max_participants,
+		"participants", &model,
+		NULL);
+
+	g_assert_cmpuint(max_participants, ==, 9);
+
+	g_assert_true(G_IS_LIST_MODEL(model));
+	g_assert_true(model == G_LIST_MODEL(store));
+	g_clear_object(&model);
+
+	g_clear_object(&store);
+
+	g_assert_finalize_object(details);
+}
+
+/******************************************************************************
+ * Main
+ *****************************************************************************/
+int
+main(int argc, char *argv[]) {
+	g_test_init(&argc, &argv, NULL);
+
+	g_test_add_func("/create-conversation-details/new",
+	                test_purple_create_conversation_details_new);
+	g_test_add_func("/create-conversation-details/properties",
+	                test_purple_create_conversation_details_properties);
+
+	return g_test_run();
+}
