diff --git a/libpurple/purplechanneljoindetails.h b/libpurple/purplechanneljoindetails.h
--- a/libpurple/purplechanneljoindetails.h
+++ b/libpurple/purplechanneljoindetails.h
@@ -51,8 +51,11 @@
 
 /**
  * purple_channel_join_details_new:
+ * @name_max_length: The maximum length for a channel name.
  * @nickname_supported: Whether or not nicknames are supported.
+ * @nickname_max_length: The maximum length for a nickname.
  * @password_supported: Whether or not passwords are supported.
+ * @password_max_length: The maximum length for a password.
  *
  * Creates a new [class@ChannelJoinDetails].
  *
@@ -61,7 +64,7 @@
  * Since: 3.0
  */
 PURPLE_AVAILABLE_IN_3_0
-PurpleChannelJoinDetails *purple_channel_join_details_new(gboolean nickname_supported, gboolean password_supported);
+PurpleChannelJoinDetails *purple_channel_join_details_new(int name_max_length, gboolean nickname_supported, int nickname_max_length, gboolean password_supported, int password_max_length);
 
 /**
  * purple_channel_join_details_get_name:
@@ -89,6 +92,20 @@
 void purple_channel_join_details_set_name(PurpleChannelJoinDetails *details, const char *name);
 
 /**
+ * purple_channel_join_details_get_name_max_length:
+ * @details: The instance.
+ *
+ * Gets the maximum length that the channel's name can be in characters.
+ *
+ * Returns: The maximum number of characters the channel name can be or %0 for
+ *          no limit.
+ *
+ * Since: 3.0
+ */
+PURPLE_AVAILABLE_IN_3_0
+int purple_channel_join_details_get_name_max_length(PurpleChannelJoinDetails *details);
+
+/**
  * purple_channel_join_details_get_nickname:
  * @details: The instance.
  *
@@ -127,6 +144,21 @@
 gboolean purple_channel_join_details_get_nickname_supported(PurpleChannelJoinDetails *details);
 
 /**
+ * purple_channel_join_details_get_nickname_max_length:
+ * @details: The instance.
+ *
+ * Gets the maximum length that the user's channel-specific nickname can be in
+ * characters.
+ *
+ * Returns: The maximum number of characters the nickname can be or %0 for no
+ *          limit.
+ *
+ * Since: 3.0
+ */
+PURPLE_AVAILABLE_IN_3_0
+int purple_channel_join_details_get_nickname_max_length(PurpleChannelJoinDetails *details);
+
+/**
  * purple_channel_join_details_get_password:
  * @details: The instance.
  *
@@ -165,6 +197,20 @@
 gboolean purple_channel_join_details_get_password_supported(PurpleChannelJoinDetails *details);
 
 /**
+ * purple_channel_join_details_get_password_max_length:
+ * @details: The instance.
+ *
+ * Gets the maximum length that the channel password can be in characters.
+ *
+ * Returns: The maximum number of characters the password can be or %0 for no
+ *          limit.
+ *
+ * Since: 3.0
+ */
+PURPLE_AVAILABLE_IN_3_0
+int purple_channel_join_details_get_password_max_length(PurpleChannelJoinDetails *details);
+
+/**
  * purple_channel_join_details_merge:
  * @source: The instance to copy from.
  * @destination: The instance to copy to.
# HG changeset patch
# Node ID 8ed9fb1c35f54463b0b25c655239ce553f8799d5
# Parent  767b7685a4a4152ae88e0a1aa089e38c3314e3cf
diff --git a/libpurple/purplechanneljoindetails.c b/libpurple/purplechanneljoindetails.c
--- a/libpurple/purplechanneljoindetails.c
+++ b/libpurple/purplechanneljoindetails.c
@@ -26,10 +26,13 @@
 enum {
 	PROP_0,
 	PROP_NAME,
-	PROP_NICKNAME,
+	PROP_NAME_MAX_LENGTH,
 	PROP_NICKNAME_SUPPORTED,
+	PROP_NICKNAME,
+	PROP_NICKNAME_MAX_LENGTH,
+	PROP_PASSWORD_SUPPORTED,
 	PROP_PASSWORD,
-	PROP_PASSWORD_SUPPORTED,
+	PROP_PASSWORD_MAX_LENGTH,
 	N_PROPERTIES,
 };
 static GParamSpec *properties[N_PROPERTIES] = {NULL, };
@@ -38,16 +41,35 @@
 	GObject parent;
 
 	char *name;
-	char *nickname;
+	int name_max_length;
+
 	gboolean nickname_supported;
+	char *nickname;
+	int nickname_max_length;
+
+	gboolean password_supported;
 	char *password;
-	gboolean password_supported;
+	int password_max_length;
 };
 
 /******************************************************************************
  * Helpers
  *****************************************************************************/
 static void
+purple_channel_join_details_set_name_max_length(PurpleChannelJoinDetails *details,
+                                                int name_max_length)
+{
+	g_return_if_fail(PURPLE_IS_CHANNEL_JOIN_DETAILS(details));
+
+	if(details->name_max_length != name_max_length) {
+		details->name_max_length = name_max_length;
+
+		g_object_notify_by_pspec(G_OBJECT(details),
+		                         properties[PROP_NAME_MAX_LENGTH]);
+	}
+}
+
+static void
 purple_channel_join_details_set_nickname_supported(PurpleChannelJoinDetails *details,
                                                    gboolean nickname_supported)
 {
@@ -62,6 +84,20 @@
 }
 
 static void
+purple_channel_join_details_set_nickname_max_length(PurpleChannelJoinDetails *details,
+                                                    int nickname_max_length)
+{
+	g_return_if_fail(PURPLE_IS_CHANNEL_JOIN_DETAILS(details));
+
+	if(details->nickname_max_length != nickname_max_length) {
+		details->nickname_max_length = nickname_max_length;
+
+		g_object_notify_by_pspec(G_OBJECT(details),
+		                         properties[PROP_NICKNAME_MAX_LENGTH]);
+	}
+}
+
+static void
 purple_channel_join_details_set_password_supported(PurpleChannelJoinDetails *details,
                                                    gboolean password_supported)
 {
@@ -75,6 +111,20 @@
 	}
 }
 
+static void
+purple_channel_join_details_set_password_max_length(PurpleChannelJoinDetails *details,
+                                                    int password_max_length)
+{
+	g_return_if_fail(PURPLE_IS_CHANNEL_JOIN_DETAILS(details));
+
+	if(details->password_max_length != password_max_length) {
+		details->password_max_length = password_max_length;
+
+		g_object_notify_by_pspec(G_OBJECT(details),
+		                         properties[PROP_PASSWORD_MAX_LENGTH]);
+	}
+}
+
 /******************************************************************************
  * GObject Implementation
  *****************************************************************************/
@@ -103,21 +153,33 @@
 		g_value_set_string(value,
 		                   purple_channel_join_details_get_name(details));
 		break;
-	case PROP_NICKNAME:
-		g_value_set_string(value,
-		                   purple_channel_join_details_get_nickname(details));
+	case PROP_NAME_MAX_LENGTH:
+		g_value_set_int(value,
+		                purple_channel_join_details_get_name_max_length(details));
 		break;
 	case PROP_NICKNAME_SUPPORTED:
 		g_value_set_boolean(value,
 		                    purple_channel_join_details_get_nickname_supported(details));
 		break;
+	case PROP_NICKNAME:
+		g_value_set_string(value,
+		                   purple_channel_join_details_get_nickname(details));
+		break;
+	case PROP_NICKNAME_MAX_LENGTH:
+		g_value_set_int(value,
+		                purple_channel_join_details_get_nickname_max_length(details));
+		break;
+	case PROP_PASSWORD_SUPPORTED:
+		g_value_set_boolean(value,
+		                    purple_channel_join_details_get_password_supported(details));
+		break;
 	case PROP_PASSWORD:
 		g_value_set_string(value,
 		                   purple_channel_join_details_get_password(details));
 		break;
-	case PROP_PASSWORD_SUPPORTED:
-		g_value_set_boolean(value,
-		                    purple_channel_join_details_get_password_supported(details));
+	case PROP_PASSWORD_MAX_LENGTH:
+		g_value_set_int(value,
+		                purple_channel_join_details_get_password_max_length(details));
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
@@ -137,21 +199,33 @@
 		purple_channel_join_details_set_name(details,
 		                                     g_value_get_string(value));
 		break;
+	case PROP_NAME_MAX_LENGTH:
+		purple_channel_join_details_set_name_max_length(details,
+		                                                g_value_get_int(value));
+		break;
+	case PROP_NICKNAME_SUPPORTED:
+		purple_channel_join_details_set_nickname_supported(details,
+		                                                   g_value_get_boolean(value));
+		break;
 	case PROP_NICKNAME:
 		purple_channel_join_details_set_nickname(details,
 		                                         g_value_get_string(value));
 		break;
-	case PROP_NICKNAME_SUPPORTED:
-		purple_channel_join_details_set_nickname_supported(details,
+	case PROP_NICKNAME_MAX_LENGTH:
+		purple_channel_join_details_set_nickname_max_length(details,
+		                                                    g_value_get_int(value));
+		break;
+	case PROP_PASSWORD_SUPPORTED:
+		purple_channel_join_details_set_password_supported(details,
 		                                                   g_value_get_boolean(value));
 		break;
 	case PROP_PASSWORD:
 		purple_channel_join_details_set_password(details,
 		                                         g_value_get_string(value));
 		break;
-	case PROP_PASSWORD_SUPPORTED:
-		purple_channel_join_details_set_password_supported(details,
-		                                                   g_value_get_boolean(value));
+	case PROP_PASSWORD_MAX_LENGTH:
+		purple_channel_join_details_set_password_max_length(details,
+		                                                    g_value_get_int(value));
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
@@ -180,12 +254,37 @@
 	 * Since: 3.0
 	 */
 	properties[PROP_NAME] = g_param_spec_string(
-		"name", "name",
-		"The name of the channel to join.",
+		"name", NULL, NULL,
 		NULL,
 		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 
 	/**
+	 * PurpleChannelJoinDetails:name-max-length:
+	 *
+	 * The maximum length of the name of the channel to join.
+	 *
+	 * A value of %0 means there is no maximum.
+	 *
+	 * Since: 3.0
+	 */
+	properties[PROP_NAME_MAX_LENGTH] = g_param_spec_int(
+		"name-max-length", NULL, NULL,
+		0, G_MAXINT, 0,
+		G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+	/**
+	 * PurpleChannelJoinDetails:nickname-supported:
+	 *
+	 * Whether or not the protocol supports channel-specific nicknames.
+	 *
+	 * Since: 3.0
+	 */
+	properties[PROP_NICKNAME_SUPPORTED] = g_param_spec_boolean(
+		"nickname-supported", NULL, NULL,
+		FALSE,
+		G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+	/**
 	 * PurpleChannelJoinDetails:nickname:
 	 *
 	 * The nickname of the user in the channel.
@@ -197,21 +296,33 @@
 	 * Since: 3.0
 	 */
 	properties[PROP_NICKNAME] = g_param_spec_string(
-		"nickname", "nickname",
-		"The channel-specific nickname for the user.",
+		"nickname", NULL, NULL,
 		NULL,
 		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 
 	/**
-	 * PurpleChannelJoinDetails:nickname-supported:
+	 * PurpleChannelJoinDetails:nickname-max-length:
 	 *
-	 * Whether or not the protocol supports channel-specific nicknames.
+	 * The maximum length for the channel specific nickname.
+	 *
+	 * A value of %0 indicates no limit.
 	 *
 	 * Since: 3.0
 	 */
-	properties[PROP_NICKNAME_SUPPORTED] = g_param_spec_boolean(
-		"nickname-supported", "nickname-supported",
-		"Whether or not the protocol supports channel-specific nicknames.",
+	properties[PROP_NICKNAME_MAX_LENGTH] = g_param_spec_int(
+		"nickname-max-length", NULL, NULL,
+		0, G_MAXINT, 0,
+		G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+	/**
+	 * PurpleChannelJoinDetails:password-supported:
+	 *
+	 * Whether or not the protocol supports channel passwords.
+	 *
+	 * Since: 3.0
+	 */
+	properties[PROP_PASSWORD_SUPPORTED] = g_param_spec_boolean(
+		"password-supported", NULL, NULL,
 		FALSE,
 		G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
 
@@ -227,24 +338,25 @@
 	 * Since: 3.0
 	 */
 	properties[PROP_PASSWORD] = g_param_spec_string(
-		"password", "password",
-		"The password to join this channel.",
+		"password", NULL, NULL,
 		NULL,
 		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 
 	/**
-	 * PurpleChannelJoinDetails:password-supported:
+	 * PurpleChannelJoinDetails:password-max-length:
 	 *
-	 * Whether or not the protocol supports channel passwords.
+	 * The maximum length for the channel specific password.
+	 *
+	 * A value of %0 indicates no limit.
 	 *
 	 * Since: 3.0
 	 */
-	properties[PROP_PASSWORD_SUPPORTED] = g_param_spec_boolean(
-		"password-supported", "password-supported",
-		"Whether or not the protocol supports channel passwords.",
-		FALSE,
+	properties[PROP_PASSWORD_MAX_LENGTH] = g_param_spec_int(
+		"password-max-length", NULL, NULL,
+		0, G_MAXINT, 0,
 		G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
 
+
 	g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
 }
 
@@ -252,13 +364,19 @@
  * Public API
  *****************************************************************************/
 PurpleChannelJoinDetails *
-purple_channel_join_details_new(gboolean nickname_supported,
-                                gboolean password_supported)
+purple_channel_join_details_new(int name_max_length,
+                                gboolean nickname_supported,
+                                int nickname_max_length,
+                                gboolean password_supported,
+                                int password_max_length)
 {
 	return g_object_new(
 		PURPLE_TYPE_CHANNEL_JOIN_DETAILS,
+		"name-max-length", name_max_length,
 		"nickname-supported", nickname_supported,
+		"nickname-max-length", nickname_max_length,
 		"password-supported", password_supported,
+		"password-max-length", password_max_length,
 		NULL);
 }
 
@@ -280,6 +398,21 @@
 	}
 }
 
+int
+purple_channel_join_details_get_name_max_length(PurpleChannelJoinDetails *details)
+{
+	g_return_val_if_fail(PURPLE_IS_CHANNEL_JOIN_DETAILS(details), 0);
+
+	return details->name_max_length;
+}
+
+gboolean
+purple_channel_join_details_get_nickname_supported(PurpleChannelJoinDetails *details) {
+	g_return_val_if_fail(PURPLE_IS_CHANNEL_JOIN_DETAILS(details), FALSE);
+
+	return details->nickname_supported;
+}
+
 const char *
 purple_channel_join_details_get_nickname(PurpleChannelJoinDetails *details) {
 	g_return_val_if_fail(PURPLE_IS_CHANNEL_JOIN_DETAILS(details), NULL);
@@ -298,11 +431,20 @@
 	}
 }
 
+int
+purple_channel_join_details_get_nickname_max_length(PurpleChannelJoinDetails *details)
+{
+	g_return_val_if_fail(PURPLE_IS_CHANNEL_JOIN_DETAILS(details), 0);
+
+	return details->nickname_max_length;
+}
+
 gboolean
-purple_channel_join_details_get_nickname_supported(PurpleChannelJoinDetails *details) {
+purple_channel_join_details_get_password_supported(PurpleChannelJoinDetails *details)
+{
 	g_return_val_if_fail(PURPLE_IS_CHANNEL_JOIN_DETAILS(details), FALSE);
 
-	return details->nickname_supported;
+	return details->password_supported;
 }
 
 const char *
@@ -323,12 +465,12 @@
 	}
 }
 
-gboolean
-purple_channel_join_details_get_password_supported(PurpleChannelJoinDetails *details)
+int
+purple_channel_join_details_get_password_max_length(PurpleChannelJoinDetails *details)
 {
-	g_return_val_if_fail(PURPLE_IS_CHANNEL_JOIN_DETAILS(details), FALSE);
+	g_return_val_if_fail(PURPLE_IS_CHANNEL_JOIN_DETAILS(details), 0);
 
-	return details->password_supported;
+	return details->password_max_length;
 }
 
 void
diff --git a/libpurple/tests/test_channel_join_details.c b/libpurple/tests/test_channel_join_details.c
--- a/libpurple/tests/test_channel_join_details.c
+++ b/libpurple/tests/test_channel_join_details.c
@@ -27,7 +27,7 @@
 test_purple_channel_join_details_new(void) {
 	PurpleChannelJoinDetails *details = NULL;
 
-	details = purple_channel_join_details_new(FALSE, FALSE);
+	details = purple_channel_join_details_new(0, FALSE, 0, FALSE, 0);
 
 	g_assert_true(PURPLE_IS_CHANNEL_JOIN_DETAILS(details));
 
@@ -40,38 +40,53 @@
 	char *name = NULL;
 	char *nickname = NULL;
 	char *password = NULL;
+	int name_max_length = 0;
+	int nickname_max_length = 0;
+	int password_max_length = 0;
 	gboolean nickname_supported = FALSE;
 	gboolean password_supported = FALSE;
 
 	details = g_object_new(
 		PURPLE_TYPE_CHANNEL_JOIN_DETAILS,
 		"name", "name",
+		"name-max-length", 42,
 		"nickname", "nickname",
+		"nickname-max-length", 1337,
 		"nickname-supported", TRUE,
 		"password", "hunter2",
+		"password-max-length", 8,
 		"password-supported", TRUE,
 		NULL);
 
 	g_object_get(
 		details,
 		"name", &name,
+		"name-max-length", &name_max_length,
 		"nickname", &nickname,
+		"nickname-max-length", &nickname_max_length,
 		"nickname-supported", &nickname_supported,
 		"password", &password,
+		"password-max-length", &password_max_length,
 		"password-supported", &password_supported,
 		NULL);
 
 	g_assert_cmpstr(name, ==, "name");
 	g_clear_pointer(&name, g_free);
 
+	g_assert_cmpint(name_max_length, ==, 42);
+
 	g_assert_cmpstr(nickname, ==, "nickname");
 	g_clear_pointer(&nickname, g_free);
 
+	g_assert_cmpint(nickname_max_length, ==, 1337);
+
 	g_assert_true(nickname_supported);
 
 	g_assert_cmpstr(password, ==, "hunter2");
 	g_clear_pointer(&password, g_free);
 
+	g_assert_cmpint(password_max_length, ==, 8);
+
 	g_assert_true(password_supported);
 
 	g_clear_object(&details);
@@ -84,12 +99,12 @@
 	const char *str = NULL;
 	gboolean supported = FALSE;
 
-	source = purple_channel_join_details_new(TRUE, TRUE);
+	source = purple_channel_join_details_new(16, TRUE, 16, TRUE, 0);
 	purple_channel_join_details_set_name(source, "name");
 	purple_channel_join_details_set_nickname(source, "nickname");
 	purple_channel_join_details_set_password(source, "password");
 
-	destination = purple_channel_join_details_new(FALSE, FALSE);
+	destination = purple_channel_join_details_new(0, FALSE, 0, FALSE, 0);
 
 	purple_channel_join_details_merge(source, destination);
 
@@ -119,6 +134,8 @@
 main(gint argc, gchar *argv[]) {
 	g_test_init(&argc, &argv, NULL);
 
+	g_test_set_nonfatal_assertions();
+
 	g_test_add_func("/channel-join-details/new",
 	                test_purple_channel_join_details_new);
 	g_test_add_func("/channel-join-details/properties",
diff --git a/libpurple/tests/test_protocol_conversation.c b/libpurple/tests/test_protocol_conversation.c
--- a/libpurple/tests/test_protocol_conversation.c
+++ b/libpurple/tests/test_protocol_conversation.c
@@ -413,7 +413,7 @@
 		protocol = g_object_new(test_purple_protocol_conversation_empty_get_type(),
 		                        NULL);
 		account = purple_account_new("test", "test");
-		details = purple_channel_join_details_new(FALSE, FALSE);
+		details = purple_channel_join_details_new(0, FALSE, 0, FALSE, 0);
 
 		purple_protocol_conversation_join_channel_async(protocol, account,
 		                                                details, NULL, NULL,
@@ -733,7 +733,7 @@
 	g_assert_true(PURPLE_IS_PROTOCOL_CONVERSATION(protocol));
 	g_assert_true(PURPLE_IS_ACCOUNT(account));
 
-	return purple_channel_join_details_new(TRUE, TRUE);
+	return purple_channel_join_details_new(16, TRUE, 16, TRUE, 0);
 }
 
 static void
@@ -1343,7 +1343,7 @@
 	g_object_set_data_full(G_OBJECT(protocol), "account", account,
 	                       g_object_unref);
 
-	details = purple_channel_join_details_new(FALSE, FALSE);
+	details = purple_channel_join_details_new(0, FALSE, 0, FALSE, 0);
 	g_object_set_data_full(G_OBJECT(protocol), "details", details,
 	                       g_object_unref);
 
diff --git a/pidgin/pidginchanneljoindialog.c b/pidgin/pidginchanneljoindialog.c
--- a/pidgin/pidginchanneljoindialog.c
+++ b/pidgin/pidginchanneljoindialog.c
@@ -288,7 +288,7 @@
 	                                  pidgin_channel_join_dialog_filter_accounts,
 	                                  NULL, NULL);
 
-	dialog->details = purple_channel_join_details_new(FALSE, FALSE);
+	dialog->details = purple_channel_join_details_new(0, FALSE, 0, FALSE, 0);
 
 	/* Bind the visible properties. */
 	g_object_bind_property(dialog->details, "nickname-supported",
diff --git a/protocols/ircv3/purpleircv3protocolconversation.c b/protocols/ircv3/purpleircv3protocolconversation.c
--- a/protocols/ircv3/purpleircv3protocolconversation.c
+++ b/protocols/ircv3/purpleircv3protocolconversation.c
@@ -89,7 +89,7 @@
 purple_ircv3_protocol_conversation_get_channel_join_details(G_GNUC_UNUSED PurpleProtocolConversation *protocol,
                                                             G_GNUC_UNUSED PurpleAccount *account)
 {
-	return purple_channel_join_details_new(FALSE, TRUE);
+	return purple_channel_join_details_new(0, FALSE, 0, TRUE, 0);
 }
 
 static void
