# HG changeset patch
# Node ID b42a3c2e55924639e0749003adc7bde90e2b09f0
# Parent  b650ebd3e157f2b9bb7b7c7a285356e892737651
diff --git a/libpurple/meson.build b/libpurple/meson.build
--- a/libpurple/meson.build
+++ b/libpurple/meson.build
@@ -252,6 +252,7 @@
 	'purpleconnection.h',
 	'purplecontactinfo.h',
 	'purpleconversation.h',
+	'purplecreateconversationdetails.h',
 	'purplefiletransfer.h',
 	'purpleplugininfo.h',
 	'purplepresence.h',
diff --git a/libpurple/purplecreateconversationdetails.c b/libpurple/purplecreateconversationdetails.c
--- a/libpurple/purplecreateconversationdetails.c
+++ b/libpurple/purplecreateconversationdetails.c
@@ -20,6 +20,8 @@
  * this library; if not, see <https://www.gnu.org/licenses/>.
  */
 
+#include <glib/gi18n-lib.h>
+
 #include <gio/gio.h>
 
 #include "purplecreateconversationdetails.h"
@@ -41,6 +43,9 @@
 	GListModel *participants;
 };
 
+G_DEFINE_QUARK(purple-create-conversation-details-error,
+               purple_create_conversation_details_error)
+
 /******************************************************************************
  * Helpers
  *****************************************************************************/
@@ -194,6 +199,60 @@
 	return details->participants;
 }
 
+gboolean
+purple_create_conversation_details_is_valid(PurpleCreateConversationDetails *details,
+                                            GError **error)
+{
+	guint n_participants = 0;
+
+	g_return_val_if_fail(PURPLE_IS_CREATE_CONVERSATION_DETAILS(details),
+	                     FALSE);
+
+	if(G_IS_LIST_MODEL(details->participants)) {
+		n_participants = g_list_model_get_n_items(details->participants);
+	}
+
+	if(n_participants == 0) {
+		/* TRANSLATORS: This error message is to tell users when they tried to
+		 * create a conversation but did not provide any other participants for
+		 * the conversation.
+		 */
+		g_set_error_literal(error,
+		                    PURPLE_CREATE_CONVERSATION_DETAILS_ERROR,
+		                    PURPLE_CREATE_CONVERSATION_DETAILS_ERROR_NO_PARTICIPANTS,
+		                    _("no participants were provided"));
+
+		return FALSE;
+	}
+
+	/* max-participants with a value of 0 means unlimited, so there is nothing
+	 * to validate in that case.
+	 */
+	if(details->max_participants > 0) {
+		if(n_participants > details->max_participants) {
+			const char *format = NULL;
+
+			/* TRANSLATORS: This error message is to tell users that they tried to
+			 * create a conversation but they have added too many participants to
+			 * it.
+			 */
+			format = g_dngettext(GETTEXT_PACKAGE,
+			                     "a maximum of %u participant is allowed",
+			                     "a maximum of %u participants are allowed",
+			                     details->max_participants);
+
+			g_set_error(error,
+			            PURPLE_CREATE_CONVERSATION_DETAILS_ERROR,
+			            PURPLE_CREATE_CONVERSATION_DETAILS_ERROR_TOO_MANY_PARTICIPANTS,
+			            format, details->max_participants);
+
+			return FALSE;
+		}
+	}
+
+	return TRUE;
+}
+
 void
 purple_create_conversation_details_set_participants(PurpleCreateConversationDetails *details,
                                                     GListModel *participants)
diff --git a/libpurple/purplecreateconversationdetails.h b/libpurple/purplecreateconversationdetails.h
--- a/libpurple/purplecreateconversationdetails.h
+++ b/libpurple/purplecreateconversationdetails.h
@@ -39,6 +39,36 @@
 PURPLE_AVAILABLE_IN_3_0
 G_DECLARE_FINAL_TYPE(PurpleCreateConversationDetails, purple_create_conversation_details, PURPLE, CREATE_CONVERSATION_DETAILS, GObject)
 
+#define PURPLE_CREATE_CONVERSATION_DETAILS_ERROR purple_create_conversation_details_error_quark()
+
+/**
+ * purple_create_conversation_details_error_quark:
+ *
+ * The error domain to identify errors in create conversation details.
+ *
+ * Returns: The error domain.
+ *
+ * Since: 3.0
+ */
+PURPLE_AVAILABLE_IN_3_0
+GQuark purple_create_conversation_details_error_quark(void);
+
+/**
+ * PurpleCreateConversationDetailsError:
+ * @PURPLE_CREATE_CONVERSATION_DETAILS_ERROR_NO_PARTICIPANTS: no participants
+ *  were set.
+ * @PURPLE_CREATE_CONVERSATION_DETAILS_ERROR_TOO_MANY_PARTICIPANTS: the number
+ *  of participants is more than are allowed.
+ *
+ * Error codes returned by create conversation details validation.
+ *
+ * Since: 3.0
+ */
+typedef enum {
+	PURPLE_CREATE_CONVERSATION_DETAILS_ERROR_NO_PARTICIPANTS PURPLE_AVAILABLE_ENUMERATOR_IN_3_0,
+	PURPLE_CREATE_CONVERSATION_DETAILS_ERROR_TOO_MANY_PARTICIPANTS PURPLE_AVAILABLE_ENUMERATOR_IN_3_0,
+} PurpleCreateConversationDetailsError;
+
 /**
  * PurpleCreateConversationDetails:
  *
@@ -94,6 +124,26 @@
 GListModel *purple_create_conversation_details_get_participants(PurpleCreateConversationDetails *details);
 
 /**
+ * purple_create_conversation_details_is_valid:
+ * @error: (nullable): a return address for an error
+ *
+ * Checks if a create conversation details is valid or not.
+ *
+ * This verifies that there is at least one participant and that the number of
+ * participants is not greater than
+ * [property@CreateConversationDetails:max-participants].
+ *
+ * This may do additional checks in the future.
+ *
+ * Returns: true if the details are valid; otherwise false with @error possibly
+ *          set.
+ *
+ * Since: 3.0
+ */
+PURPLE_AVAILABLE_IN_3_0
+gboolean purple_create_conversation_details_is_valid(PurpleCreateConversationDetails *details, GError **error);
+
+/**
  * purple_create_conversation_details_set_participants:
  * @details: The instance.
  * @participants: (nullable) (transfer none): The new participants.
diff --git a/libpurple/tests/test_create_conversation_details.c b/libpurple/tests/test_create_conversation_details.c
--- a/libpurple/tests/test_create_conversation_details.c
+++ b/libpurple/tests/test_create_conversation_details.c
@@ -70,6 +70,158 @@
 	g_assert_finalize_object(store);
 }
 
+static void
+test_purple_create_conversation_details_is_valid_null(void) {
+	PurpleCreateConversationDetails *details = NULL;
+	GError *error = NULL;
+	gboolean is_valid = FALSE;
+
+	details = purple_create_conversation_details_new(1);
+
+	is_valid = purple_create_conversation_details_is_valid(details, &error);
+	g_assert_error(error, PURPLE_CREATE_CONVERSATION_DETAILS_ERROR,
+	               PURPLE_CREATE_CONVERSATION_DETAILS_ERROR_NO_PARTICIPANTS);
+	g_clear_error(&error);
+	g_assert_false(is_valid);
+
+	g_assert_finalize_object(details);
+}
+
+static void
+test_purple_create_conversation_details_is_valid_empty(void) {
+	PurpleCreateConversationDetails *details = NULL;
+	GListStore *participants = NULL;
+	GError *error = NULL;
+	gboolean is_valid = FALSE;
+
+	details = purple_create_conversation_details_new(1);
+	participants = g_list_store_new(PURPLE_TYPE_CONTACT);
+	purple_create_conversation_details_set_participants(details,
+	                                                    G_LIST_MODEL(participants));
+	g_clear_object(&participants);
+
+	is_valid = purple_create_conversation_details_is_valid(details, &error);
+	g_assert_error(error, PURPLE_CREATE_CONVERSATION_DETAILS_ERROR,
+	               PURPLE_CREATE_CONVERSATION_DETAILS_ERROR_NO_PARTICIPANTS);
+	g_clear_error(&error);
+	g_assert_false(is_valid);
+
+	g_assert_finalize_object(details);
+}
+
+
+static void
+test_purple_create_conversation_details_is_valid_too_many(void) {
+	PurpleAccount *account = NULL;
+	PurpleContact *contact = NULL;
+	PurpleCreateConversationDetails *details = NULL;
+	GListStore *participants = NULL;
+	GError *error = NULL;
+	gboolean is_valid = FALSE;
+
+	account = purple_account_new("test", "test");
+
+	details = purple_create_conversation_details_new(1);
+	participants = g_list_store_new(PURPLE_TYPE_CONTACT);
+
+	/* We need to add 2 contacts to exceed the max-participants. */
+	contact = purple_contact_new(account, NULL);
+	g_list_store_append(participants, contact);
+	g_clear_object(&contact);
+
+	contact = purple_contact_new(account, NULL);
+	g_list_store_append(participants, contact);
+	g_clear_object(&contact);
+
+	/* Set the participants on the details. */
+	purple_create_conversation_details_set_participants(details,
+	                                                    G_LIST_MODEL(participants));
+	g_clear_object(&participants);
+
+	/* Check validation. */
+	is_valid = purple_create_conversation_details_is_valid(details, &error);
+	g_assert_error(error, PURPLE_CREATE_CONVERSATION_DETAILS_ERROR,
+	               PURPLE_CREATE_CONVERSATION_DETAILS_ERROR_TOO_MANY_PARTICIPANTS);
+	g_clear_error(&error);
+	g_assert_false(is_valid);
+
+	g_assert_finalize_object(details);
+	g_assert_finalize_object(account);
+}
+
+static void
+test_purple_create_conversation_details_is_valid_limited(void) {
+	PurpleAccount *account = NULL;
+	PurpleContact *contact = NULL;
+	PurpleCreateConversationDetails *details = NULL;
+	GListStore *participants = NULL;
+	GError *error = NULL;
+	gboolean is_valid = FALSE;
+
+	account = purple_account_new("test", "test");
+
+	details = purple_create_conversation_details_new(1);
+	participants = g_list_store_new(PURPLE_TYPE_CONTACT);
+
+	contact = purple_contact_new(account, NULL);
+	g_list_store_append(participants, contact);
+	g_clear_object(&contact);
+
+	/* Set the participants on the details. */
+	purple_create_conversation_details_set_participants(details,
+	                                                    G_LIST_MODEL(participants));
+	g_clear_object(&participants);
+
+	/* Check validation. */
+	is_valid = purple_create_conversation_details_is_valid(details, &error);
+	g_assert_no_error(error);
+	g_assert_true(is_valid);
+
+	g_assert_finalize_object(details);
+	g_assert_finalize_object(account);
+}
+
+static void
+test_purple_create_conversation_details_is_valid_unlimited(void) {
+	PurpleAccount *account = NULL;
+	PurpleContact *contact = NULL;
+	PurpleCreateConversationDetails *details = NULL;
+	GListStore *participants = NULL;
+	GError *error = NULL;
+	gboolean is_valid = FALSE;
+
+	account = purple_account_new("test", "test");
+
+	details = purple_create_conversation_details_new(0);
+	participants = g_list_store_new(PURPLE_TYPE_CONTACT);
+
+	/* Add 3 additional contacts to spice things up! */
+	contact = purple_contact_new(account, NULL);
+	g_list_store_append(participants, contact);
+	g_clear_object(&contact);
+
+	contact = purple_contact_new(account, NULL);
+	g_list_store_append(participants, contact);
+	g_clear_object(&contact);
+
+	contact = purple_contact_new(account, NULL);
+	g_list_store_append(participants, contact);
+	g_clear_object(&contact);
+
+	/* Set the participants on the details. */
+	purple_create_conversation_details_set_participants(details,
+	                                                    G_LIST_MODEL(participants));
+	g_clear_object(&participants);
+
+	/* Check validation. */
+	is_valid = purple_create_conversation_details_is_valid(details, &error);
+	g_assert_no_error(error);
+	g_assert_true(is_valid);
+
+	g_assert_finalize_object(details);
+	g_assert_finalize_object(account);
+}
+
 /******************************************************************************
  * Main
  *****************************************************************************/
@@ -83,5 +235,16 @@
 	g_test_add_func("/create-conversation-details/properties",
 	                test_purple_create_conversation_details_properties);
 
+	g_test_add_func("/create-conversation-details/is-valid/null",
+	                test_purple_create_conversation_details_is_valid_null);
+	g_test_add_func("/create-conversation-details/is-valid/empty",
+	                test_purple_create_conversation_details_is_valid_empty);
+	g_test_add_func("/create-conversation-details/is-valid/too-many",
+	                test_purple_create_conversation_details_is_valid_too_many);
+	g_test_add_func("/create-conversation-details/is-valid/limited",
+	                test_purple_create_conversation_details_is_valid_limited);
+	g_test_add_func("/create-conversation-details/is-valid/unlimited",
+	                test_purple_create_conversation_details_is_valid_unlimited);
+
 	return g_test_run();
 }
