# HG changeset patch
# Node ID a74103355a4f
# Parent  276e97d2d581
diff --git a/finch/gntblist.c b/finch/gntblist.c
--- a/finch/gntblist.c
+++ b/finch/gntblist.c
@@ -1000,8 +1000,9 @@ chat_components_edit_ok(PurpleChat *chat
 			id = purple_request_field_get_id(field);
 			if (purple_request_field_get_field_type(field) == PURPLE_REQUEST_FIELD_INTEGER)
 				val = g_strdup_printf("%d", purple_request_field_int_get_value(field));
-			else
-				val = g_strdup(purple_request_field_string_get_value(field));
+			else {
+				val = g_strdup(purple_request_field_string_get_value(PURPLE_REQUEST_FIELD_STRING(field)));
+			}
 
 			if (!val) {
 				g_hash_table_remove(purple_chat_get_components(chat), id);
@@ -1040,8 +1041,10 @@ chat_components_edit(G_GNUC_UNUSED Purpl
 		} else {
 			field = purple_request_field_string_new(pce->identifier, pce->label,
 					g_hash_table_lookup(purple_chat_get_components(chat), pce->identifier), FALSE);
-			if (pce->secret)
-				purple_request_field_string_set_masked(field, TRUE);
+			if(pce->secret) {
+				purple_request_field_string_set_masked(PURPLE_REQUEST_FIELD_STRING(field),
+				                                       TRUE);
+			}
 		}
 
 		if (pce->required)
diff --git a/finch/gntrequest.c b/finch/gntrequest.c
--- a/finch/gntrequest.c
+++ b/finch/gntrequest.c
@@ -299,13 +299,15 @@ request_fields_cb(GntWidget *button, Pur
 				                                     "finch-ui-data");
 				gboolean value = gnt_check_box_get_checked(GNT_CHECK_BOX(check));
 				purple_request_field_bool_set_value(field, value);
-			}
-			else if (type == PURPLE_REQUEST_FIELD_STRING)
-			{
+			} else if(PURPLE_IS_REQUEST_FIELD_STRING(field)) {
 				GntWidget *entry = g_object_get_data(G_OBJECT(field),
 				                                     "finch-ui-data");
 				const char *text = gnt_entry_get_text(GNT_ENTRY(entry));
-				purple_request_field_string_set_value(field, (text && *text) ? text : NULL);
+				if(purple_strempty(text)) {
+					text = NULL;
+				}
+				purple_request_field_string_set_value(PURPLE_REQUEST_FIELD_STRING(field),
+				                                      text);
 			}
 			else if (type == PURPLE_REQUEST_FIELD_INTEGER)
 			{
@@ -424,11 +426,12 @@ create_boolean_field(PurpleRequestField 
 static GntWidget*
 create_string_field(PurpleRequestField *field, GntWidget **username)
 {
+	PurpleRequestFieldString *strfield = PURPLE_REQUEST_FIELD_STRING(field);
 	const char *hint = purple_request_field_get_type_hint(field);
 	GntWidget *entry = gnt_entry_new(
-			purple_request_field_string_get_default_value(field));
+			purple_request_field_string_get_default_value(strfield));
 	gnt_entry_set_masked(GNT_ENTRY(entry),
-			purple_request_field_string_is_masked(field));
+	                     purple_request_field_string_is_masked(strfield));
 	if (hint && g_str_has_prefix(hint, "screenname")) {
 		PurpleBlistNode *node = purple_blist_get_default_root();
 		gboolean offline = g_str_has_suffix(hint, "all");
@@ -659,7 +662,7 @@ finch_request_fields(const char *title, 
 
 			if (type == PURPLE_REQUEST_FIELD_BOOLEAN) {
 				widget = create_boolean_field(field);
-			} else if (type == PURPLE_REQUEST_FIELD_STRING) {
+			} else if(PURPLE_IS_REQUEST_FIELD_STRING(field)) {
 				widget = create_string_field(field, &username);
 			} else if (type == PURPLE_REQUEST_FIELD_INTEGER) {
 				widget = create_integer_field(field);
@@ -870,6 +873,10 @@ finch_request_save_in_prefs(G_GNUC_UNUSE
 			gpointer val = NULL;
 			const char *id = purple_request_field_get_id(field);
 
+			if(PURPLE_IS_REQUEST_FIELD_STRING(field)) {
+				PurpleRequestFieldString *sfield = PURPLE_REQUEST_FIELD_STRING(field);
+				val = (gpointer)purple_request_field_string_get_value(sfield);
+			} else {
 			switch (type) {
 				case PURPLE_REQUEST_FIELD_LIST:
 					val = purple_request_field_list_get_selected(field)->data;
@@ -881,12 +888,10 @@ finch_request_save_in_prefs(G_GNUC_UNUSE
 				case PURPLE_REQUEST_FIELD_INTEGER:
 					val = GINT_TO_POINTER(purple_request_field_int_get_value(field));
 					break;
-				case PURPLE_REQUEST_FIELD_STRING:
-					val = (gpointer)purple_request_field_string_get_value(field);
-					break;
 				default:
 					break;
 			}
+			}
 
 			pt = purple_prefs_get_pref_type(id);
 			switch (pt) {
@@ -917,16 +922,15 @@ finch_request_save_in_prefs(G_GNUC_UNUSE
 GntWidget *finch_request_field_get_widget(PurpleRequestField *field)
 {
 	GntWidget *ret = NULL;
-	if(PURPLE_IS_REQUEST_FIELD_ACCOUNT(field)) {
+	if(PURPLE_IS_REQUEST_FIELD_STRING(field)) {
+		ret = create_string_field(field, NULL);
+	} else if(PURPLE_IS_REQUEST_FIELD_ACCOUNT(field)) {
 		ret = create_account_field(field);
 	} else {
 	switch (purple_request_field_get_field_type(field)) {
 		case PURPLE_REQUEST_FIELD_BOOLEAN:
 			ret = create_boolean_field(field);
 			break;
-		case PURPLE_REQUEST_FIELD_STRING:
-			ret = create_string_field(field, NULL);
-			break;
 		case PURPLE_REQUEST_FIELD_INTEGER:
 			ret = create_integer_field(field);
 			break;
diff --git a/libpurple/account.c b/libpurple/account.c
--- a/libpurple/account.c
+++ b/libpurple/account.c
@@ -38,6 +38,7 @@
 #include "purpleprotocolmanager.h"
 #include "purpleprotocolserver.h"
 #include "request.h"
+#include "request/purplerequestfieldstring.h"
 #include "server.h"
 #include "signals.h"
 #include "util.h"
@@ -1077,7 +1078,8 @@ purple_account_request_password(PurpleAc
 	purple_request_page_add_group(page, group);
 
 	field = purple_request_field_string_new("password", _("Enter Password"), NULL, FALSE);
-	purple_request_field_string_set_masked(field, TRUE);
+	purple_request_field_string_set_masked(PURPLE_REQUEST_FIELD_STRING(field),
+	                                       TRUE);
 	purple_request_field_set_required(field, TRUE);
 	purple_request_group_add_field(group, field);
 
@@ -1114,7 +1116,8 @@ purple_account_request_change_password(P
 
 	field = purple_request_field_string_new("password", _("Original password"),
 										  NULL, FALSE);
-	purple_request_field_string_set_masked(field, TRUE);
+	purple_request_field_string_set_masked(PURPLE_REQUEST_FIELD_STRING(field),
+	                                       TRUE);
 	if (!protocol || !(purple_protocol_get_options(protocol) & OPT_PROTO_PASSWORD_OPTIONAL))
 		purple_request_field_set_required(field, TRUE);
 	purple_request_group_add_field(group, field);
@@ -1122,7 +1125,8 @@ purple_account_request_change_password(P
 	field = purple_request_field_string_new("new_password_1",
 										  _("New password"),
 										  NULL, FALSE);
-	purple_request_field_string_set_masked(field, TRUE);
+	purple_request_field_string_set_masked(PURPLE_REQUEST_FIELD_STRING(field),
+	                                       TRUE);
 	if (!protocol || !(purple_protocol_get_options(protocol) & OPT_PROTO_PASSWORD_OPTIONAL))
 		purple_request_field_set_required(field, TRUE);
 	purple_request_group_add_field(group, field);
@@ -1130,7 +1134,8 @@ purple_account_request_change_password(P
 	field = purple_request_field_string_new("new_password_2",
 										  _("New password (again)"),
 										  NULL, FALSE);
-	purple_request_field_string_set_masked(field, TRUE);
+	purple_request_field_string_set_masked(PURPLE_REQUEST_FIELD_STRING(field),
+	                                       TRUE);
 	if (!protocol || !(purple_protocol_get_options(protocol) & OPT_PROTO_PASSWORD_OPTIONAL))
 		purple_request_field_set_required(field, TRUE);
 	purple_request_group_add_field(group, field);
diff --git a/libpurple/meson.build b/libpurple/meson.build
--- a/libpurple/meson.build
+++ b/libpurple/meson.build
@@ -98,6 +98,7 @@ purple_coresources = [
 	'queuedoutputstream.c',
 	'request.c',
 	'request/purplerequestfieldaccount.c',
+	'request/purplerequestfieldstring.c',
 	'request-datasheet.c',
 	'roomlist.c',
 	'savedstatuses.c',
@@ -222,6 +223,7 @@ purple_coreheaders = [
 
 purple_request_headers = [
 	'request/purplerequestfieldaccount.h',
+	'request/purplerequestfieldstring.h',
 ]
 
 purple_generated_sources = []
diff --git a/libpurple/protocols/demo/purpledemoprotocolactions.c b/libpurple/protocols/demo/purpledemoprotocolactions.c
--- a/libpurple/protocols/demo/purpledemoprotocolactions.c
+++ b/libpurple/protocols/demo/purpledemoprotocolactions.c
@@ -490,7 +490,8 @@ purple_demo_protocol_request_fields_acti
 	field = purple_request_field_string_new("masked-string",
 	                                        _("A masked string"), _("default"),
 	                                        FALSE);
-	purple_request_field_string_set_masked(field, TRUE);
+	purple_request_field_string_set_masked(PURPLE_REQUEST_FIELD_STRING(field),
+	                                       TRUE);
 	purple_request_group_add_field(group, field);
 	field = purple_request_field_string_new("alphanumeric",
 	                                        _("An alphanumeric string"),
diff --git a/libpurple/protocols/gg/validator.c b/libpurple/protocols/gg/validator.c
--- a/libpurple/protocols/gg/validator.c
+++ b/libpurple/protocols/gg/validator.c
@@ -39,11 +39,9 @@ ggp_validator_password(PurpleRequestFiel
 {
 	const char *value;
 
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), FALSE);
-	g_return_val_if_fail(purple_request_field_get_field_type(field) ==
-		PURPLE_REQUEST_FIELD_STRING, FALSE);
+	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD_STRING(field), FALSE);
 
-	value = purple_request_field_string_get_value(field);
+	value = purple_request_field_string_get_value(PURPLE_REQUEST_FIELD_STRING(field));
 
 	if (value != NULL) {
 		size_t len = strlen(value);
@@ -67,15 +65,11 @@ gboolean ggp_validator_password_equal(Pu
 	const char *value1, *value2;
 	PurpleRequestField *field2 = field2_p;
 
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), FALSE);
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field2), FALSE);
-	g_return_val_if_fail(purple_request_field_get_field_type(field) ==
-		PURPLE_REQUEST_FIELD_STRING, FALSE);
-	g_return_val_if_fail(purple_request_field_get_field_type(field2) ==
-		PURPLE_REQUEST_FIELD_STRING, FALSE);
+	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD_STRING(field), FALSE);
+	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD_STRING(field2), FALSE);
 
-	value1 = purple_request_field_string_get_value(field);
-	value2 = purple_request_field_string_get_value(field2);
+	value1 = purple_request_field_string_get_value(PURPLE_REQUEST_FIELD_STRING(field));
+	value2 = purple_request_field_string_get_value(PURPLE_REQUEST_FIELD_STRING(field2));
 
 	if (g_strcmp0(value1, value2) == 0)
 		return TRUE;
diff --git a/libpurple/protocols/jabber/buddy.c b/libpurple/protocols/jabber/buddy.c
--- a/libpurple/protocols/jabber/buddy.c
+++ b/libpurple/protocols/jabber/buddy.c
@@ -557,7 +557,6 @@ jabber_set_buddy_icon(G_GNUC_UNUSED Purp
 static void
 jabber_format_info(PurpleConnection *gc, PurpleRequestPage *page) {
 	PurpleXmlNode *vc_node;
-	PurpleRequestField *field;
 	PurpleProtocol *protocol = NULL;
 	const char *text;
 	char *p;
@@ -573,11 +572,9 @@ jabber_format_info(PurpleConnection *gc,
 		if (*vc_tp->label == '\0')
 			continue;
 
-		field = purple_request_page_get_field(page, vc_tp->tag);
-		text  = purple_request_field_string_get_value(field);
+		text = purple_request_page_get_string(page, vc_tp->tag);
 
-
-		if (text != NULL && *text != '\0') {
+		if(!purple_strempty(text)) {
 			PurpleXmlNode *xp;
 
 			purple_debug_info("jabber", "Setting %s to '%s'\n", vc_tp->tag, text);
diff --git a/libpurple/protocols/jabber/jabber.c b/libpurple/protocols/jabber/jabber.c
--- a/libpurple/protocols/jabber/jabber.c
+++ b/libpurple/protocols/jabber/jabber.c
@@ -1923,13 +1923,15 @@ jabber_password_change(G_GNUC_UNUSED GSi
 
 	field = purple_request_field_string_new("password1", _("Password"),
 			"", FALSE);
-	purple_request_field_string_set_masked(field, TRUE);
+	purple_request_field_string_set_masked(PURPLE_REQUEST_FIELD_STRING(field),
+	                                       TRUE);
 	purple_request_field_set_required(field, TRUE);
 	purple_request_group_add_field(group, field);
 
 	field = purple_request_field_string_new("password2", _("Password (again)"),
 			"", FALSE);
-	purple_request_field_string_set_masked(field, TRUE);
+	purple_request_field_string_set_masked(PURPLE_REQUEST_FIELD_STRING(field),
+	                                       TRUE);
 	purple_request_field_set_required(field, TRUE);
 	purple_request_group_add_field(group, field);
 
diff --git a/libpurple/protocols/jabber/xdata.c b/libpurple/protocols/jabber/xdata.c
--- a/libpurple/protocols/jabber/xdata.c
+++ b/libpurple/protocols/jabber/xdata.c
@@ -84,7 +84,8 @@ jabber_x_data_ok_cb(struct jabber_x_data
 				case JABBER_X_DATA_TEXT_SINGLE:
 				case JABBER_X_DATA_JID_SINGLE:
 					{
-					const char *value = purple_request_field_string_get_value(field);
+					PurpleRequestFieldString *sfield = PURPLE_REQUEST_FIELD_STRING(field);
+					const char *value = purple_request_field_string_get_value(sfield);
 					if (value == NULL)
 						break;
 					fieldnode = purple_xmlnode_new_child(result, "field");
@@ -95,8 +96,9 @@ jabber_x_data_ok_cb(struct jabber_x_data
 					}
 				case JABBER_X_DATA_TEXT_MULTI:
 					{
+					PurpleRequestFieldString *sfield = PURPLE_REQUEST_FIELD_STRING(field);
+					const char *value = purple_request_field_string_get_value(sfield);
 					char **pieces, **p;
-					const char *value = purple_request_field_string_get_value(field);
 					if (value == NULL)
 						break;
 					fieldnode = purple_xmlnode_new_child(result, "field");
@@ -230,7 +232,8 @@ void *jabber_x_data_request_with_actions
 
 			field = purple_request_field_string_new(var, label,
 					value ? value : "", FALSE);
-			purple_request_field_string_set_masked(field, TRUE);
+			purple_request_field_string_set_masked(PURPLE_REQUEST_FIELD_STRING(field),
+			                                       TRUE);
 			purple_request_group_add_field(group, field);
 
 			g_hash_table_replace(data->fields, g_strdup(var), GINT_TO_POINTER(JABBER_X_DATA_TEXT_SINGLE));
diff --git a/libpurple/purplechatconversation.c b/libpurple/purplechatconversation.c
--- a/libpurple/purplechatconversation.c
+++ b/libpurple/purplechatconversation.c
@@ -29,6 +29,7 @@
 #include "purpleenums.h"
 #include "purpleprivate.h"
 #include "request.h"
+#include "request/purplerequestfieldstring.h"
 #include "server.h"
 
 typedef struct {
diff --git a/libpurple/purplerequestfield.h b/libpurple/purplerequestfield.h
--- a/libpurple/purplerequestfield.h
+++ b/libpurple/purplerequestfield.h
@@ -64,7 +64,6 @@ struct _PurpleRequestFieldClass {
 /**
  * PurpleRequestFieldType:
  * @PURPLE_REQUEST_FIELD_NONE: No field.
- * @PURPLE_REQUEST_FIELD_STRING: String field.
  * @PURPLE_REQUEST_FIELD_INTEGER: Integer field.
  * @PURPLE_REQUEST_FIELD_BOOLEAN: Boolean field.
  * @PURPLE_REQUEST_FIELD_CHOICE: Choice field (dropdown?).
@@ -78,7 +77,6 @@ struct _PurpleRequestFieldClass {
 typedef enum
 {
 	PURPLE_REQUEST_FIELD_NONE,
-	PURPLE_REQUEST_FIELD_STRING,
 	PURPLE_REQUEST_FIELD_INTEGER,
 	PURPLE_REQUEST_FIELD_BOOLEAN,
 	PURPLE_REQUEST_FIELD_CHOICE,
@@ -319,97 +317,6 @@ void purple_request_field_set_sensitive(
 gboolean purple_request_field_is_sensitive(PurpleRequestField *field);
 
 /**************************************************************************/
-/* String Field API                                                       */
-/**************************************************************************/
-
-/**
- * purple_request_field_string_new:
- * @id:            The field ID.
- * @text:          The text label of the field.
- * @default_value: The optional default value.
- * @multiline:     Whether or not this should be a multiline string.
- *
- * Creates a string request field.
- *
- * Returns: (transfer full): The new field.
- */
-PurpleRequestField *purple_request_field_string_new(const char *id,
-												const char *text,
-												const char *default_value,
-												gboolean multiline);
-
-/**
- * purple_request_field_string_set_default_value:
- * @field:         The field.
- * @default_value: The default value.
- *
- * Sets the default value in a string field.
- */
-void purple_request_field_string_set_default_value(PurpleRequestField *field,
-												 const char *default_value);
-
-/**
- * purple_request_field_string_set_value:
- * @field: The field.
- * @value: The value.
- *
- * Sets the value in a string field.
- */
-void purple_request_field_string_set_value(PurpleRequestField *field,
-										 const char *value);
-
-/**
- * purple_request_field_string_set_masked:
- * @field:  The field.
- * @masked: The masked value.
- *
- * Sets whether or not a string field is masked
- * (commonly used for password fields).
- */
-void purple_request_field_string_set_masked(PurpleRequestField *field,
-										  gboolean masked);
-
-/**
- * purple_request_field_string_get_default_value:
- * @field: The field.
- *
- * Returns the default value in a string field.
- *
- * Returns: The default value.
- */
-const char *purple_request_field_string_get_default_value(PurpleRequestField *field);
-
-/**
- * purple_request_field_string_get_value:
- * @field: The field.
- *
- * Returns the user-entered value in a string field.
- *
- * Returns: The value.
- */
-const char *purple_request_field_string_get_value(PurpleRequestField *field);
-
-/**
- * purple_request_field_string_is_multiline:
- * @field: The field.
- *
- * Returns whether or not a string field is multi-line.
- *
- * Returns: %TRUE if the field is mulit-line, or %FALSE otherwise.
- */
-gboolean purple_request_field_string_is_multiline(PurpleRequestField *field);
-
-/**
- * purple_request_field_string_is_masked:
- * @field: The field.
- *
- * Returns whether or not a string field is masked.
- *
- * Returns: %TRUE if the field is masked, or %FALSE otherwise.
- */
-gboolean purple_request_field_string_is_masked(PurpleRequestField *field);
-
-/**************************************************************************/
 /* Integer Field API                                                      */
 /**************************************************************************/
 
diff --git a/libpurple/purplerequestfield.h b/libpurple/request/purplerequestfieldstring.h
copy from libpurple/purplerequestfield.h
copy to libpurple/request/purplerequestfieldstring.h
--- a/libpurple/purplerequestfield.h
+++ b/libpurple/request/purplerequestfieldstring.h
@@ -24,303 +24,28 @@
 # error "only <purple.h> may be included directly"
 #endif
 
-#ifndef PURPLE_REQUEST_FIELD_H
-#define PURPLE_REQUEST_FIELD_H
+#ifndef PURPLE_REQUEST_FIELD_STRING_H
+#define PURPLE_REQUEST_FIELD_STRING_H
 
 #include <stdlib.h>
 
 #include <glib.h>
 #include <glib-object.h>
 
-/**
- * PurpleRequestField:
- *
- * A request field.
- */
-typedef struct _PurpleRequestField PurpleRequestField;
-
-#include "request.h"
-#include "request-datasheet.h"
-
-#define PURPLE_DEFAULT_ACTION_NONE	-1
-
-/**
- * PurpleRequestFieldClass:
- *
- * #PurpleRequestFieldClass defines the interface for a request field.
- *
- * Since: 3.0.0
- */
-struct _PurpleRequestFieldClass {
-	/*< private >*/
-	GObjectClass parent_class;
-
-	/*< public >*/
-
-	/*< private >*/
-	gpointer reserved[4];
-};
+#include "purplerequestfield.h"
 
 /**
- * PurpleRequestFieldType:
- * @PURPLE_REQUEST_FIELD_NONE: No field.
- * @PURPLE_REQUEST_FIELD_STRING: String field.
- * @PURPLE_REQUEST_FIELD_INTEGER: Integer field.
- * @PURPLE_REQUEST_FIELD_BOOLEAN: Boolean field.
- * @PURPLE_REQUEST_FIELD_CHOICE: Choice field (dropdown?).
- * @PURPLE_REQUEST_FIELD_LIST: List field.
- * @PURPLE_REQUEST_FIELD_LABEL: Label field.
- * @PURPLE_REQUEST_FIELD_IMAGE: Image field.
- * @PURPLE_REQUEST_FIELD_DATASHEET: Datasheet field.
+ * PurpleRequestFieldString:
  *
- * A type of field.
+ * A string request field.
  */
-typedef enum
-{
-	PURPLE_REQUEST_FIELD_NONE,
-	PURPLE_REQUEST_FIELD_STRING,
-	PURPLE_REQUEST_FIELD_INTEGER,
-	PURPLE_REQUEST_FIELD_BOOLEAN,
-	PURPLE_REQUEST_FIELD_CHOICE,
-	PURPLE_REQUEST_FIELD_LIST,
-	PURPLE_REQUEST_FIELD_LABEL,
-	PURPLE_REQUEST_FIELD_IMAGE,
-	PURPLE_REQUEST_FIELD_DATASHEET
-
-} PurpleRequestFieldType;
-
-typedef gboolean (*PurpleRequestFieldValidator)(PurpleRequestField *field,
-	gchar **errmsg, gpointer user_data);
+typedef struct _PurpleRequestFieldString PurpleRequestFieldString;
 
 G_BEGIN_DECLS
 
-/**************************************************************************/
-/* Field API                                                              */
-/**************************************************************************/
-
-#define PURPLE_TYPE_REQUEST_FIELD (purple_request_field_get_type())
-G_DECLARE_DERIVABLE_TYPE(PurpleRequestField, purple_request_field,
-                         PURPLE, REQUEST_FIELD, GObject)
-
-/**
- * purple_request_field_new:
- * @id:   The field ID.
- * @text: The text label of the field.
- * @type: The type of field.
- *
- * Creates a field of the specified type.
- *
- * Returns: (transfer full): The new field.
- */
-PurpleRequestField *purple_request_field_new(const char *id, const char *text,
-										 PurpleRequestFieldType type);
-
-/**
- * purple_request_field_set_label:
- * @field: The field.
- * @label: The text label.
- *
- * Sets the label text of a field.
- */
-void purple_request_field_set_label(PurpleRequestField *field, const char *label);
-
-/**
- * purple_request_field_set_visible:
- * @field:   The field.
- * @visible: TRUE if visible, or FALSE if not.
- *
- * Sets whether or not a field is visible.
- */
-void purple_request_field_set_visible(PurpleRequestField *field, gboolean visible);
-
-/**
- * purple_request_field_set_type_hint:
- * @field:     The field.
- * @type_hint: The type hint.
- *
- * Sets the type hint for the field.
- *
- * This is optionally used by the UIs to provide such features as
- * auto-completion for type hints like "account" and "screenname".
- */
-void purple_request_field_set_type_hint(PurpleRequestField *field,
-									  const char *type_hint);
-
-/**
- * purple_request_field_set_tooltip:
- * @field:     The field.
- * @tooltip:   The tooltip text.
- *
- * Sets the tooltip for the field.
- *
- * This is optionally used by the UIs to provide a tooltip for
- * the field.
- */
-void purple_request_field_set_tooltip(PurpleRequestField *field,
-									const char *tooltip);
-
-/**
- * purple_request_field_set_required:
- * @field:    The field.
- * @required: TRUE if required, or FALSE.
- *
- * Sets whether or not a field is required.
- */
-void purple_request_field_set_required(PurpleRequestField *field,
-									 gboolean required);
-
-/**
- * purple_request_field_get_field_type:
- * @field: The field.
- *
- * Returns the type of a field.
- *
- * Returns: The field's type.
- */
-PurpleRequestFieldType purple_request_field_get_field_type(PurpleRequestField *field);
-
-/**
- * purple_request_field_get_group:
- * @field: The field.
- *
- * Returns the group for the field.
- *
- * Returns: (transfer none): The UI data.
- */
-PurpleRequestGroup *purple_request_field_get_group(PurpleRequestField *field);
-
-/**
- * purple_request_field_get_id:
- * @field: The field.
- *
- * Returns the ID of a field.
- *
- * Returns: The ID
- */
-const char *purple_request_field_get_id(PurpleRequestField *field);
-
-/**
- * purple_request_field_get_label:
- * @field: The field.
- *
- * Returns the label text of a field.
- *
- * Returns: The label text.
- */
-const char *purple_request_field_get_label(PurpleRequestField *field);
-
-/**
- * purple_request_field_is_visible:
- * @field: The field.
- *
- * Returns whether or not a field is visible.
- *
- * Returns: TRUE if the field is visible. FALSE otherwise.
- */
-gboolean purple_request_field_is_visible(PurpleRequestField *field);
-
-/**
- * purple_request_field_get_type_hint:
- * @field: The field.
- *
- * Returns the field's type hint.
- *
- * Returns: The field's type hint.
- */
-const char *purple_request_field_get_type_hint(PurpleRequestField *field);
-
-/**
- * purple_request_field_get_tooltip:
- * @field: The field.
- *
- * Returns the field's tooltip.
- *
- * Returns: The field's tooltip.
- */
-const char *purple_request_field_get_tooltip(PurpleRequestField *field);
-
-/**
- * purple_request_field_is_required:
- * @field: The field.
- *
- * Returns whether or not a field is required.
- *
- * Returns: TRUE if the field is required, or FALSE.
- */
-gboolean purple_request_field_is_required(PurpleRequestField *field);
-
-/**
- * purple_request_field_is_filled:
- * @field: The field.
- *
- * Checks, if specified field has value.
- *
- * Returns: TRUE if the field has value, or FALSE.
- */
-gboolean purple_request_field_is_filled(PurpleRequestField *field);
-
-/**
- * purple_request_field_set_validator:
- * @field:     The field.
- * @validator: (scope notified): The validator callback, NULL to disable validation.
- * @user_data: The data to pass to the callback.
- *
- * Sets validator for a single field.
- */
-void purple_request_field_set_validator(PurpleRequestField *field,
-	PurpleRequestFieldValidator validator, void *user_data);
-
-/**
- * purple_request_field_is_validatable:
- * @field: The field.
- *
- * Returns whether or not field has validator set.
- *
- * Returns: TRUE if the field has validator, or FALSE.
- */
-gboolean purple_request_field_is_validatable(PurpleRequestField *field);
-
-/**
- * purple_request_field_is_valid:
- * @field:  The field.
- * @errmsg: If non-NULL, the memory area, where the pointer to validation
- *         failure message will be set.
- *
- * Checks, if specified field is valid.
- *
- * If detailed message about failure reason is needed, there is an option to
- * return (via errmsg argument) pointer to newly allocated error message.
- * It must be freed with g_free after use.
- *
- * Note: empty, not required fields are valid.
- *
- * Returns: TRUE, if the field is valid, FALSE otherwise.
- */
-gboolean purple_request_field_is_valid(PurpleRequestField *field, gchar **errmsg);
-
-/**
- * purple_request_field_set_sensitive:
- * @field:     The field.
- * @sensitive: TRUE if the field should be sensitive for user input.
- *
- * Sets field editable.
- */
-void purple_request_field_set_sensitive(PurpleRequestField *field,
-	gboolean sensitive);
-
-/**
- * purple_request_field_is_sensitive:
- * @field: The field.
- *
- * Checks, if field is editable.
- *
- * Returns: TRUE, if the field is sensitive for user input.
- */
-gboolean purple_request_field_is_sensitive(PurpleRequestField *field);
-
-/**************************************************************************/
-/* String Field API                                                       */
-/**************************************************************************/
+#define PURPLE_TYPE_REQUEST_FIELD_STRING (purple_request_field_string_get_type())
+G_DECLARE_FINAL_TYPE(PurpleRequestFieldString, purple_request_field_string,
+                     PURPLE, REQUEST_FIELD_STRING, PurpleRequestField)
 
 /**
  * purple_request_field_string_new:
@@ -345,8 +70,7 @@ PurpleRequestField *purple_request_field
  *
  * Sets the default value in a string field.
  */
-void purple_request_field_string_set_default_value(PurpleRequestField *field,
-												 const char *default_value);
+void purple_request_field_string_set_default_value(PurpleRequestFieldString *field, const char *default_value);
 
 /**
  * purple_request_field_string_set_value:
@@ -355,8 +79,7 @@ void purple_request_field_string_set_def
  *
  * Sets the value in a string field.
  */
-void purple_request_field_string_set_value(PurpleRequestField *field,
-										 const char *value);
+void purple_request_field_string_set_value(PurpleRequestFieldString *field, const char *value);
 
 /**
  * purple_request_field_string_set_masked:
@@ -366,8 +89,7 @@ void purple_request_field_string_set_val
  * Sets whether or not a string field is masked
  * (commonly used for password fields).
  */
-void purple_request_field_string_set_masked(PurpleRequestField *field,
-										  gboolean masked);
+void purple_request_field_string_set_masked(PurpleRequestFieldString *field, gboolean masked);
 
 /**
  * purple_request_field_string_get_default_value:
@@ -377,7 +99,7 @@ void purple_request_field_string_set_mas
  *
  * Returns: The default value.
  */
-const char *purple_request_field_string_get_default_value(PurpleRequestField *field);
+const char *purple_request_field_string_get_default_value(PurpleRequestFieldString *field);
 
 /**
  * purple_request_field_string_get_value:
@@ -387,7 +109,7 @@ const char *purple_request_field_string_
  *
  * Returns: The value.
  */
-const char *purple_request_field_string_get_value(PurpleRequestField *field);
+const char *purple_request_field_string_get_value(PurpleRequestFieldString *field);
 
 /**
  * purple_request_field_string_is_multiline:
@@ -397,7 +119,7 @@ const char *purple_request_field_string_
  *
  * Returns: %TRUE if the field is mulit-line, or %FALSE otherwise.
  */
-gboolean purple_request_field_string_is_multiline(PurpleRequestField *field);
+gboolean purple_request_field_string_is_multiline(PurpleRequestFieldString *field);
 
 /**
  * purple_request_field_string_is_masked:
@@ -407,514 +129,7 @@ gboolean purple_request_field_string_is_
  *
  * Returns: %TRUE if the field is masked, or %FALSE otherwise.
  */
-gboolean purple_request_field_string_is_masked(PurpleRequestField *field);
-
-/**************************************************************************/
-/* Integer Field API                                                      */
-/**************************************************************************/
-
-/**
- * purple_request_field_int_new:
- * @id:            The field ID.
- * @text:          The text label of the field.
- * @default_value: The default value.
- * @lower_bound:   The lower bound.
- * @upper_bound:   The upper bound.
- *
- * Creates an integer field.
- *
- * Returns: (transfer full): The new field.
- */
-PurpleRequestField *purple_request_field_int_new(const char *id,
-	const char *text, int default_value, int lower_bound, int upper_bound);
-
-/**
- * purple_request_field_int_set_default_value:
- * @field:         The field.
- * @default_value: The default value.
- *
- * Sets the default value in an integer field.
- */
-void purple_request_field_int_set_default_value(PurpleRequestField *field,
-											  int default_value);
-
-/**
- * purple_request_field_int_set_lower_bound:
- * @field:       The field.
- * @lower_bound: The lower bound.
- *
- * Sets the lower bound in an integer field.
- */
-void purple_request_field_int_set_lower_bound(PurpleRequestField *field, int lower_bound);
-
-/**
- * purple_request_field_int_set_upper_bound:
- * @field:       The field.
- * @upper_bound: The upper bound.
- *
- * Sets the upper bound in an integer field.
- */
-void purple_request_field_int_set_upper_bound(PurpleRequestField *field, int upper_bound);
-
-/**
- * purple_request_field_int_set_value:
- * @field: The field.
- * @value: The value.
- *
- * Sets the value in an integer field.
- */
-void purple_request_field_int_set_value(PurpleRequestField *field, int value);
-
-/**
- * purple_request_field_int_get_default_value:
- * @field: The field.
- *
- * Returns the default value in an integer field.
- *
- * Returns: The default value.
- */
-int purple_request_field_int_get_default_value(PurpleRequestField *field);
-
-/**
- * purple_request_field_int_get_lower_bound:
- * @field: The field.
- *
- * Returns the lower bound in an integer field.
- *
- * Returns: The lower bound.
- */
-int purple_request_field_int_get_lower_bound(PurpleRequestField *field);
-
-/**
- * purple_request_field_int_get_upper_bound:
- * @field: The field.
- *
- * Returns the upper bound in an integer field.
- *
- * Returns: The upper bound.
- */
-int purple_request_field_int_get_upper_bound(PurpleRequestField *field);
-
-/**
- * purple_request_field_int_get_value:
- * @field: The field.
- *
- * Returns the user-entered value in an integer field.
- *
- * Returns: The value.
- */
-int purple_request_field_int_get_value(PurpleRequestField *field);
-
-/**************************************************************************/
-/* Boolean Field API                                                      */
-/**************************************************************************/
-
-/**
- * purple_request_field_bool_new:
- * @id:            The field ID.
- * @text:          The text label of the field.
- * @default_value: The default value.
- *
- * Creates a boolean field.
- *
- * This is often represented as a checkbox.
- *
- * Returns: (transfer full): The new field.
- */
-PurpleRequestField *purple_request_field_bool_new(const char *id,
-											  const char *text,
-											  gboolean default_value);
-
-/**
- * purple_request_field_bool_set_default_value:
- * @field:         The field.
- * @default_value: The default value.
- *
- * Sets the default value in an boolean field.
- */
-void purple_request_field_bool_set_default_value(PurpleRequestField *field,
-											   gboolean default_value);
-
-/**
- * purple_request_field_bool_set_value:
- * @field: The field.
- * @value: The value.
- *
- * Sets the value in an boolean field.
- */
-void purple_request_field_bool_set_value(PurpleRequestField *field,
-									   gboolean value);
-
-/**
- * purple_request_field_bool_get_default_value:
- * @field: The field.
- *
- * Returns the default value in an boolean field.
- *
- * Returns: The default value.
- */
-gboolean purple_request_field_bool_get_default_value(PurpleRequestField *field);
-
-/**
- * purple_request_field_bool_get_value:
- * @field: The field.
- *
- * Returns the user-entered value in an boolean field.
- *
- * Returns: The value.
- */
-gboolean purple_request_field_bool_get_value(PurpleRequestField *field);
-
-/**************************************************************************/
-/* Choice Field API                                                       */
-/**************************************************************************/
-
-/**
- * purple_request_field_choice_new:
- * @id:            The field ID.
- * @text:          The optional label of the field.
- * @default_value: The default choice.
- *
- * Creates a multiple choice field.
- *
- * This is often represented as a group of radio buttons.
- *
- * Returns: (transfer full): The new field.
- */
-PurpleRequestField *
-purple_request_field_choice_new(const char *id, const char *text,
-	gpointer default_value);
-
-/**
- * purple_request_field_choice_add:
- * @field: The choice field.
- * @label: The choice label.
- * @data:  The choice value.
- *
- * Adds a choice to a multiple choice field.
- */
-void
-purple_request_field_choice_add(PurpleRequestField *field, const char *label,
-	gpointer data);
-
-/**
- * purple_request_field_choice_add_full:
- * @field: The choice field.
- * @label: The choice label.
- * @data:  The choice value.
- * @destroy: The value destroy function.
- *
- * Adds a choice to a multiple choice field with destructor for value.
- *
- * Since: 3.0.0
- */
-void
-purple_request_field_choice_add_full(PurpleRequestField *field, const char *label,
-                                     gpointer data, GDestroyNotify destroy);
-
-/**
- * purple_request_field_choice_set_default_value:
- * @field:         The field.
- * @default_value: The default value.
- *
- * Sets the default value in an choice field.
- */
-void
-purple_request_field_choice_set_default_value(PurpleRequestField *field,
-	gpointer default_value);
-
-/**
- * purple_request_field_choice_set_value:
- * @field: The field.
- * @value: The value.
- *
- * Sets the value in an choice field.
- */
-void
-purple_request_field_choice_set_value(PurpleRequestField *field,
-	gpointer value);
-
-/**
- * purple_request_field_choice_get_default_value:
- * @field: The field.
- *
- * Returns the default value in an choice field.
- *
- * Returns: The default value.
- */
-gpointer
-purple_request_field_choice_get_default_value(PurpleRequestField *field);
-
-/**
- * purple_request_field_choice_get_value:
- * @field: The field.
- *
- * Returns the user-entered value in an choice field.
- *
- * Returns: The value.
- */
-gpointer
-purple_request_field_choice_get_value(PurpleRequestField *field);
-
-/**
- * purple_request_field_choice_get_elements:
- * @field: The field.
- *
- * Returns a list of elements in a choice field.
- *
- * Returns: (element-type PurpleKeyValuePair) (transfer none): The list of pairs of {label, value}.
- */
-GList *
-purple_request_field_choice_get_elements(PurpleRequestField *field);
-
-/**************************************************************************/
-/* List Field API                                                         */
-/**************************************************************************/
-
-/**
- * purple_request_field_list_new:
- * @id:   The field ID.
- * @text: The optional label of the field.
- *
- * Creates a multiple list item field.
- *
- * Returns: (transfer full): The new field.
- */
-PurpleRequestField *purple_request_field_list_new(const char *id, const char *text);
-
-/**
- * purple_request_field_list_set_multi_select:
- * @field:        The list field.
- * @multi_select: TRUE if multiple selection is enabled,
- *                     or FALSE otherwise.
- *
- * Sets whether or not a list field allows multiple selection.
- */
-void purple_request_field_list_set_multi_select(PurpleRequestField *field,
-											  gboolean multi_select);
-
-/**
- * purple_request_field_list_get_multi_select:
- * @field: The list field.
- *
- * Returns whether or not a list field allows multiple selection.
- *
- * Returns: TRUE if multiple selection is enabled, or FALSE otherwise.
- */
-gboolean purple_request_field_list_get_multi_select(PurpleRequestField *field);
-
-/**
- * purple_request_field_list_get_data:
- * @field: The list field.
- * @text:  The item text.
- *
- * Returns the data for a particular item.
- *
- * Returns: The data associated with the item.
- */
-void *purple_request_field_list_get_data(PurpleRequestField *field, const char *text);
-
-/**
- * purple_request_field_list_add_icon:
- * @field:     The list field.
- * @item:      The list item.
- * @icon_path: The path to icon file, or %NULL for no icon.
- * @data:      The associated data.
- *
- * Adds an item to a list field.
- */
-void purple_request_field_list_add_icon(PurpleRequestField *field,
-								 const char *item, const char* icon_path, void* data);
-
-/**
- * purple_request_field_list_add_selected:
- * @field: The field.
- * @item:  The item to add.
- *
- * Adds a selected item to the list field.
- */
-void purple_request_field_list_add_selected(PurpleRequestField *field,
-										  const char *item);
-
-/**
- * purple_request_field_list_clear_selected:
- * @field: The field.
- *
- * Clears the list of selected items in a list field.
- */
-void purple_request_field_list_clear_selected(PurpleRequestField *field);
-
-/**
- * purple_request_field_list_set_selected:
- * @field: The field.
- * @items: (element-type utf8) (transfer none): The list of selected items.
- *
- * Sets a list of selected items in a list field.
- */
-void purple_request_field_list_set_selected(PurpleRequestField *field,
-										  GList *items);
-
-/**
- * purple_request_field_list_is_selected:
- * @field: The field.
- * @item:  The item.
- *
- * Returns whether or not a particular item is selected in a list field.
- *
- * Returns: TRUE if the item is selected. FALSE otherwise.
- */
-gboolean purple_request_field_list_is_selected(PurpleRequestField *field, const char *item);
-
-/**
- * purple_request_field_list_get_selected:
- * @field: The field.
- *
- * Returns a list of selected items in a list field.
- *
- * To retrieve the data for each item, use
- * purple_request_field_list_get_data().
- *
- * Returns: (element-type utf8) (transfer none): The list of selected items.
- */
-GList *purple_request_field_list_get_selected(PurpleRequestField *field);
-
-/**
- * purple_request_field_list_get_items:
- * @field: The field.
- *
- * Returns a list of items in a list field.
- *
- * Returns: (element-type PurpleKeyValuePair) (transfer none): The list of items.
- */
-GList *purple_request_field_list_get_items(PurpleRequestField *field);
-
-/**
- * purple_request_field_list_has_icons:
- * @field: The field.
- *
- * Indicates if list field has icons.
- *
- * Returns: TRUE if list field has icons, FALSE otherwise.
- *
- * Since: 3.0.0
- */
-gboolean purple_request_field_list_has_icons(PurpleRequestField *field);
-
-/**************************************************************************/
-/* Label Field API                                                        */
-/**************************************************************************/
-
-/**
- * purple_request_field_label_new:
- * @id:   The field ID.
- * @text: The label of the field.
- *
- * Creates a label field.
- *
- * Returns: (transfer full): The new field.
- */
-PurpleRequestField *purple_request_field_label_new(const char *id,
-											   const char *text);
-
-/**************************************************************************/
-/* Image Field API                                                        */
-/**************************************************************************/
-
-/**
- * purple_request_field_image_new:
- * @id:   The field ID.
- * @text: The label of the field.
- * @buf:  The image data.
- * @size: The size of the data in @buf.
- *
- * Creates an image field.
- *
- * Returns: (transfer full): The new field.
- */
-PurpleRequestField *purple_request_field_image_new(const char *id, const char *text,
-											   const char *buf, gsize size);
-
-/**
- * purple_request_field_image_set_scale:
- * @field: The image field.
- * @x:     The x scale factor.
- * @y:     The y scale factor.
- *
- * Sets the scale factors of an image field.
- */
-void purple_request_field_image_set_scale(PurpleRequestField *field, unsigned int x, unsigned int y);
-
-/**
- * purple_request_field_image_get_buffer:
- * @field: The image field.
- *
- * Returns pointer to the image.
- *
- * Returns: Pointer to the image.
- */
-const char *purple_request_field_image_get_buffer(PurpleRequestField *field);
-
-/**
- * purple_request_field_image_get_size:
- * @field: The image field.
- *
- * Returns size (in bytes) of the image.
- *
- * Returns: Size of the image.
- */
-gsize purple_request_field_image_get_size(PurpleRequestField *field);
-
-/**
- * purple_request_field_image_get_scale_x:
- * @field: The image field.
- *
- * Returns X scale coefficient of the image.
- *
- * Returns: X scale coefficient of the image.
- */
-unsigned int purple_request_field_image_get_scale_x(PurpleRequestField *field);
-
-/**
- * purple_request_field_image_get_scale_y:
- * @field: The image field.
- *
- * Returns Y scale coefficient of the image.
- *
- * Returns: Y scale coefficient of the image.
- */
-unsigned int purple_request_field_image_get_scale_y(PurpleRequestField *field);
-
-/**************************************************************************/
-/* Datasheet Field API                                                    */
-/**************************************************************************/
-
-/**
- * purple_request_field_datasheet_new:
- * @id:    The field ID.
- * @text:  The label of the field, may be %NULL.
- * @sheet: The datasheet.
- *
- * Creates a datasheet item field.
- *
- * Returns: (transfer full): The new field.
- */
-PurpleRequestField *purple_request_field_datasheet_new(const char *id,
-	const gchar *text, PurpleRequestDatasheet *sheet);
-
-/**
- * purple_request_field_datasheet_get_sheet:
- * @field: The field.
- *
- * Returns a datasheet for a field.
- *
- * Returns: (transfer none): The datasheet object.
- */
-PurpleRequestDatasheet *purple_request_field_datasheet_get_sheet(
-	PurpleRequestField *field);
-
-/**************************************************************************/
-/* Validators for request fields.                                         */
-/**************************************************************************/
+gboolean purple_request_field_string_is_masked(PurpleRequestFieldString *field);
 
 /**
  * purple_request_field_email_validator:
@@ -949,4 +164,4 @@ gboolean purple_request_field_alphanumer
 
 G_END_DECLS
 
-#endif /* PURPLE_REQUEST_FIELD_H */
+#endif /* PURPLE_REQUEST_FIELD_STRING_H */
diff --git a/libpurple/purplerequestfield.c b/libpurple/purplerequestfield.c
--- a/libpurple/purplerequestfield.c
+++ b/libpurple/purplerequestfield.c
@@ -23,6 +23,7 @@
 
 #include "glibcompat.h"
 #include "request.h"
+#include "request/purplerequestfieldstring.h"
 #include "debug.h"
 #include "purplekeyvaluepair.h"
 #include "purpleprivate.h"
@@ -41,13 +42,6 @@ typedef struct {
 
 	union {
 		struct {
-			gboolean multiline;
-			gboolean masked;
-			char *default_value;
-			char *value;
-		} string;
-
-		struct {
 			int default_value;
 			int value;
 			int lower_bound;
@@ -231,10 +225,7 @@ purple_request_field_finalize(GObject *o
 	g_free(priv->type_hint);
 	g_free(priv->tooltip);
 
-	if(priv->type == PURPLE_REQUEST_FIELD_STRING) {
-		g_free(priv->u.string.default_value);
-		g_free(priv->u.string.value);
-	} else if(priv->type == PURPLE_REQUEST_FIELD_CHOICE) {
+	if(priv->type == PURPLE_REQUEST_FIELD_CHOICE) {
 		g_list_free_full(priv->u.choice.elements,
 		                 (GDestroyNotify)purple_key_value_pair_free);
 	} else if(priv->type == PURPLE_REQUEST_FIELD_LIST) {
@@ -587,14 +578,12 @@ gboolean
 purple_request_field_is_filled(PurpleRequestField *field) {
 	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), FALSE);
 
-	switch (purple_request_field_get_field_type(field))
-	{
-		case PURPLE_REQUEST_FIELD_STRING:
-			return (purple_request_field_string_get_value(field) != NULL &&
-				*(purple_request_field_string_get_value(field)) != '\0');
-		default:
-			return TRUE;
+	if(PURPLE_IS_REQUEST_FIELD_STRING(field)) {
+		PurpleRequestFieldString *sfield = PURPLE_REQUEST_FIELD_STRING(field);
+		return !purple_strempty(purple_request_field_string_get_value(sfield));
 	}
+
+	return TRUE;
 }
 
 void
@@ -684,117 +673,6 @@ purple_request_field_is_sensitive(Purple
 }
 
 PurpleRequestField *
-purple_request_field_string_new(const char *id, const char *text,
-							  const char *default_value, gboolean multiline)
-{
-	PurpleRequestField *field;
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(id   != NULL, NULL);
-	g_return_val_if_fail(text != NULL, NULL);
-
-	field = purple_request_field_new(id, text, PURPLE_REQUEST_FIELD_STRING);
-	priv = purple_request_field_get_instance_private(field);
-
-	priv->u.string.multiline = multiline;
-
-	purple_request_field_string_set_default_value(field, default_value);
-	purple_request_field_string_set_value(field, default_value);
-
-	return field;
-}
-
-void
-purple_request_field_string_set_default_value(PurpleRequestField *field,
-											const char *default_value)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_REQUEST_FIELD(field));
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_if_fail(priv->type == PURPLE_REQUEST_FIELD_STRING);
-
-	g_free(priv->u.string.default_value);
-	priv->u.string.default_value = g_strdup(default_value);
-}
-
-void
-purple_request_field_string_set_value(PurpleRequestField *field, const char *value)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_REQUEST_FIELD(field));
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_if_fail(priv->type == PURPLE_REQUEST_FIELD_STRING);
-
-	g_free(priv->u.string.value);
-	priv->u.string.value = g_strdup(value);
-}
-
-void
-purple_request_field_string_set_masked(PurpleRequestField *field, gboolean masked)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_REQUEST_FIELD(field));
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_if_fail(priv->type == PURPLE_REQUEST_FIELD_STRING);
-
-	priv->u.string.masked = masked;
-}
-
-const char *
-purple_request_field_string_get_default_value(PurpleRequestField *field) {
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), NULL);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_val_if_fail(priv->type == PURPLE_REQUEST_FIELD_STRING, NULL);
-
-	return priv->u.string.default_value;
-}
-
-const char *
-purple_request_field_string_get_value(PurpleRequestField *field) {
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), NULL);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_val_if_fail(priv->type == PURPLE_REQUEST_FIELD_STRING, NULL);
-
-	return priv->u.string.value;
-}
-
-gboolean
-purple_request_field_string_is_multiline(PurpleRequestField *field) {
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), FALSE);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_val_if_fail(priv->type == PURPLE_REQUEST_FIELD_STRING, FALSE);
-
-	return priv->u.string.multiline;
-}
-
-gboolean
-purple_request_field_string_is_masked(PurpleRequestField *field) {
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), FALSE);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_val_if_fail(priv->type == PURPLE_REQUEST_FIELD_STRING, FALSE);
-
-	return priv->u.string.masked;
-}
-
-PurpleRequestField *
 purple_request_field_int_new(const char *id, const char *text,
 	int default_value, int lower_bound, int upper_bound)
 {
@@ -1434,72 +1312,3 @@ purple_request_field_datasheet_get_sheet
 
 	return priv->u.datasheet.sheet;
 }
-
-/* -- */
-
-gboolean
-purple_request_field_email_validator(PurpleRequestField *field, gchar **errmsg,
-                                     G_GNUC_UNUSED gpointer user_data)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-	const char *value;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), FALSE);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_val_if_fail(priv->type == PURPLE_REQUEST_FIELD_STRING, FALSE);
-
-	value = purple_request_field_string_get_value(field);
-
-	if (value != NULL && purple_email_is_valid(value))
-		return TRUE;
-
-	if (errmsg)
-		*errmsg = g_strdup(_("Invalid email address"));
-	return FALSE;
-}
-
-gboolean
-purple_request_field_alphanumeric_validator(PurpleRequestField *field,
-	gchar **errmsg, void *allowed_characters)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-	const char *value;
-	gchar invalid_char = '\0';
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), FALSE);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_val_if_fail(priv->type == PURPLE_REQUEST_FIELD_STRING, FALSE);
-
-	value = purple_request_field_string_get_value(field);
-
-	g_return_val_if_fail(value != NULL, FALSE);
-
-	if (allowed_characters)
-	{
-		gchar *value_r = g_strdup(value);
-		g_strcanon(value_r, allowed_characters, '\0');
-		invalid_char = value[strlen(value_r)];
-		g_free(value_r);
-	}
-	else
-	{
-		while (value)
-		{
-			if (!g_ascii_isalnum(*value))
-			{
-				invalid_char = *value;
-				break;
-			}
-			value++;
-		}
-	}
-	if (!invalid_char)
-		return TRUE;
-
-	if (errmsg)
-		*errmsg = g_strdup_printf(_("Invalid character '%c'"),
-			invalid_char);
-	return FALSE;
-}
diff --git a/libpurple/purplerequestfield.c b/libpurple/request/purplerequestfieldstring.c
copy from libpurple/purplerequestfield.c
copy to libpurple/request/purplerequestfieldstring.c
--- a/libpurple/purplerequestfield.c
+++ b/libpurple/request/purplerequestfieldstring.c
@@ -22,158 +22,68 @@
 #include <glib/gi18n-lib.h>
 
 #include "glibcompat.h"
-#include "request.h"
-#include "debug.h"
-#include "purplekeyvaluepair.h"
-#include "purpleprivate.h"
-
-typedef struct {
-	PurpleRequestFieldType type;
-	PurpleRequestGroup *group;
-
-	char *id;
-	char *label;
-	char *type_hint;
+#include "purplerequestfield.h"
+#include "purplerequestfieldstring.h"
 
-	gboolean visible;
-	gboolean required;
-	gboolean sensitive;
-
-	union {
-		struct {
-			gboolean multiline;
-			gboolean masked;
-			char *default_value;
-			char *value;
-		} string;
-
-		struct {
-			int default_value;
-			int value;
-			int lower_bound;
-			int upper_bound;
-		} integer;
+struct _PurpleRequestFieldString {
+	PurpleRequestField parent;
 
-		struct {
-			gboolean default_value;
-			gboolean value;
-		} boolean;
-
-		struct {
-			gpointer default_value;
-			gpointer value;
-
-			GList *elements;
-		} choice;
-
-		struct {
-			GList *items;
-			gboolean has_icons;
-			GHashTable *item_data;
-			GList *selected;
-			GHashTable *selected_table;
-
-			gboolean multiple_selection;
-		} list;
-
-		struct {
-			unsigned int scale_x;
-			unsigned int scale_y;
-			char *buffer;
-			gsize size;
-		} image;
-
-		struct {
-			PurpleRequestDatasheet *sheet;
-		} datasheet;
-	} u;
-
-	void *ui_data;
-	char *tooltip;
-
-	PurpleRequestFieldValidator validator;
-	void *validator_data;
-} PurpleRequestFieldPrivate;
+	gboolean multiline;
+	gboolean masked;
+	char *default_value;
+	char *value;
+};
 
 enum {
 	PROP_0,
-	PROP_ID,
-	PROP_LABEL,
-	PROP_VISIBLE,
-	PROP_SENSITIVE,
-	PROP_TYPE_HINT,
-	PROP_TOOLTIP,
-	PROP_REQUIRED,
-	PROP_IS_VALIDATABLE,
+	PROP_MULTILINE,
+	PROP_MASKED,
+	PROP_DEFAULT_VALUE,
+	PROP_VALUE,
 	N_PROPERTIES,
 };
 static GParamSpec *properties[N_PROPERTIES] = {NULL, };
 
-G_DEFINE_TYPE_WITH_PRIVATE(PurpleRequestField, purple_request_field, G_TYPE_OBJECT)
-
 /******************************************************************************
  * Helpers
  *****************************************************************************/
 static void
-purple_request_field_set_id(PurpleRequestField *field, const char *id) {
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	priv = purple_request_field_get_instance_private(field);
-
-	g_free(priv->id);
-	priv->id = g_strdup(id);
+purple_request_field_string_set_multiline(PurpleRequestFieldString *field,
+                                          gboolean multiline)
+{
+	field->multiline = multiline;
 
-	g_object_notify_by_pspec(G_OBJECT(field), properties[PROP_ID]);
-}
-
-static void
-purple_request_field_set_field_type(PurpleRequestField *field,
-                                    PurpleRequestFieldType type)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	priv = purple_request_field_get_instance_private(field);
-
-	priv->type = type;
+	g_object_notify_by_pspec(G_OBJECT(field), properties[PROP_MULTILINE]);
 }
 
 /******************************************************************************
  * GObject Implementation
  *****************************************************************************/
+G_DEFINE_TYPE(PurpleRequestFieldString, purple_request_field_string,
+              PURPLE_TYPE_REQUEST_FIELD)
+
 static void
-purple_request_field_get_property(GObject *obj, guint param_id, GValue *value,
-                                  GParamSpec *pspec)
+purple_request_field_string_get_property(GObject *obj, guint param_id,
+                                         GValue *value, GParamSpec *pspec)
 {
-	PurpleRequestField *field = PURPLE_REQUEST_FIELD(obj);
+	PurpleRequestFieldString *field = PURPLE_REQUEST_FIELD_STRING(obj);
 
 	switch(param_id) {
-		case PROP_ID:
-			g_value_set_string(value, purple_request_field_get_id(field));
-			break;
-		case PROP_LABEL:
-			g_value_set_string(value, purple_request_field_get_label(field));
+		case PROP_MULTILINE:
+			g_value_set_boolean(value,
+			                    purple_request_field_string_is_multiline(field));
 			break;
-		case PROP_VISIBLE:
-			g_value_set_boolean(value, purple_request_field_is_visible(field));
-			break;
-		case PROP_SENSITIVE:
+		case PROP_MASKED:
 			g_value_set_boolean(value,
-			                    purple_request_field_is_sensitive(field));
+			                    purple_request_field_string_is_masked(field));
 			break;
-		case PROP_TYPE_HINT:
+		case PROP_DEFAULT_VALUE:
 			g_value_set_string(value,
-			                   purple_request_field_get_type_hint(field));
-			break;
-		case PROP_TOOLTIP:
-			g_value_set_string(value, purple_request_field_get_tooltip(field));
+			                   purple_request_field_string_get_default_value(field));
 			break;
-		case PROP_REQUIRED:
-			g_value_set_boolean(value,
-			                    purple_request_field_is_required(field));
-			break;
-		case PROP_IS_VALIDATABLE:
-			g_value_set_boolean(value,
-			                    purple_request_field_is_validatable(field));
+		case PROP_VALUE:
+			g_value_set_string(value,
+			                   purple_request_field_string_get_value(field));
 			break;
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
@@ -182,36 +92,28 @@ purple_request_field_get_property(GObjec
 }
 
 static void
-purple_request_field_set_property(GObject *obj, guint param_id,
-                                  const GValue *value, GParamSpec *pspec)
+purple_request_field_string_set_property(GObject *obj, guint param_id,
+                                         const GValue *value,
+                                         GParamSpec *pspec)
 {
-	PurpleRequestField *field = PURPLE_REQUEST_FIELD(obj);
+	PurpleRequestFieldString *field = PURPLE_REQUEST_FIELD_STRING(obj);
 
 	switch(param_id) {
-		case PROP_ID:
-			purple_request_field_set_id(field, g_value_get_string(value));
+		case PROP_MULTILINE:
+			purple_request_field_string_set_multiline(field,
+			                                          g_value_get_boolean(value));
 			break;
-		case PROP_LABEL:
-			purple_request_field_set_label(field, g_value_get_string(value));
-			break;
-		case PROP_VISIBLE:
-			purple_request_field_set_visible(field,
-			                                 g_value_get_boolean(value));
+		case PROP_MASKED:
+			purple_request_field_string_set_masked(field,
+			                                       g_value_get_boolean(value));
 			break;
-		case PROP_SENSITIVE:
-			purple_request_field_set_sensitive(field,
-			                                   g_value_get_boolean(value));
+		case PROP_DEFAULT_VALUE:
+			purple_request_field_string_set_default_value(field,
+			                                              g_value_get_string(value));
 			break;
-		case PROP_TYPE_HINT:
-			purple_request_field_set_type_hint(field,
-			                                   g_value_get_string(value));
-			break;
-		case PROP_TOOLTIP:
-			purple_request_field_set_tooltip(field, g_value_get_string(value));
-			break;
-		case PROP_REQUIRED:
-			purple_request_field_set_required(field,
-			                                  g_value_get_boolean(value));
+		case PROP_VALUE:
+			purple_request_field_string_set_value(field,
+			                                      g_value_get_string(value));
 			break;
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
@@ -220,160 +122,80 @@ purple_request_field_set_property(GObjec
 }
 
 static void
-purple_request_field_finalize(GObject *obj) {
-	PurpleRequestField *field = PURPLE_REQUEST_FIELD(obj);
-	PurpleRequestFieldPrivate *priv = NULL;
+purple_request_field_string_finalize(GObject *obj) {
+	PurpleRequestFieldString *field = PURPLE_REQUEST_FIELD_STRING(obj);
 
-	priv = purple_request_field_get_instance_private(field);
-
-	g_free(priv->id);
-	g_free(priv->label);
-	g_free(priv->type_hint);
-	g_free(priv->tooltip);
+	g_free(field->default_value);
+	g_free(field->value);
 
-	if(priv->type == PURPLE_REQUEST_FIELD_STRING) {
-		g_free(priv->u.string.default_value);
-		g_free(priv->u.string.value);
-	} else if(priv->type == PURPLE_REQUEST_FIELD_CHOICE) {
-		g_list_free_full(priv->u.choice.elements,
-		                 (GDestroyNotify)purple_key_value_pair_free);
-	} else if(priv->type == PURPLE_REQUEST_FIELD_LIST) {
-		g_list_free_full(priv->u.list.items,
-		                 (GDestroyNotify)purple_key_value_pair_free);
-		g_list_free_full(priv->u.list.selected, g_free);
-		g_hash_table_destroy(priv->u.list.item_data);
-		g_hash_table_destroy(priv->u.list.selected_table);
-	} else if(priv->type == PURPLE_REQUEST_FIELD_DATASHEET) {
-		purple_request_datasheet_free(priv->u.datasheet.sheet);
-	} else if(priv->type == PURPLE_REQUEST_FIELD_IMAGE) {
-		g_free(priv->u.image.buffer);
-	}
+	G_OBJECT_CLASS(purple_request_field_string_parent_class)->finalize(obj);
+}
 
-	G_OBJECT_CLASS(purple_request_field_parent_class)->finalize(obj);
+static void
+purple_request_field_string_init(G_GNUC_UNUSED PurpleRequestFieldString *field)
+{
 }
 
 static void
-purple_request_field_init(PurpleRequestField *field) {
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	priv = purple_request_field_get_instance_private(field);
-
-	priv->visible = TRUE;
-	priv->sensitive = TRUE;
-}
-
-static void
-purple_request_field_class_init(PurpleRequestFieldClass *klass) {
+purple_request_field_string_class_init(PurpleRequestFieldStringClass *klass) {
 	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
 
-	obj_class->finalize = purple_request_field_finalize;
-	obj_class->get_property = purple_request_field_get_property;
-	obj_class->set_property = purple_request_field_set_property;
+	obj_class->finalize = purple_request_field_string_finalize;
+	obj_class->get_property = purple_request_field_string_get_property;
+	obj_class->set_property = purple_request_field_string_set_property;
 
 	/**
-	 * PurpleRequestField:id:
+	 * PurpleRequestFieldString:multiline:
 	 *
-	 * The ID of the field.
+	 * Whether the field should allow multiline input.
 	 *
 	 * Since: 3.0.0
 	 */
-	properties[PROP_ID] = g_param_spec_string(
-		"id", "id",
-		"The ID of the field.",
-		NULL,
+	properties[PROP_MULTILINE] = g_param_spec_boolean(
+		"multiline", "multiline",
+		"Whether the field should allow multiline input.",
+		FALSE,
 		G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
 
 	/**
-	 * PurpleRequestField:label:
+	 * PurpleRequestFieldString:masked:
 	 *
-	 * The label of the field.
+	 * Whether the field should be masked.
 	 *
 	 * Since: 3.0.0
 	 */
-	properties[PROP_LABEL] = g_param_spec_string(
-		"label", "label",
-		"The label of the field.",
+	properties[PROP_MASKED] = g_param_spec_boolean(
+		"masked", "masked",
+		"Whether the field should be masked.",
+		FALSE,
+		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+	/**
+	 * PurpleRequestFieldString:default-value:
+	 *
+	 * The default value of the field.
+	 *
+	 * Since: 3.0.0
+	 */
+	properties[PROP_DEFAULT_VALUE] = g_param_spec_string(
+		"default-value", "default-value",
+		"The default value of the field.",
 		NULL,
 		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 
 	/**
-	 * PurpleRequestField:visible:
-	 *
-	 * Whether the field should be visible.
-	 *
-	 * Since: 3.0.0
-	 */
-	properties[PROP_VISIBLE] = g_param_spec_boolean(
-		"visible", "visible",
-		"Whether the field should be visible.",
-		TRUE,
-		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleRequestField:sensitive:
+	 * PurpleRequestFieldString:value:
 	 *
-	 * Whether the field should be sensitive.
-	 *
-	 * Since: 3.0.0
-	 */
-	properties[PROP_SENSITIVE] = g_param_spec_boolean(
-		"sensitive", "sensitive",
-		"Whether the field should be sensitive.",
-		TRUE,
-		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleRequestField:type-hint:
-	 *
-	 * The type hint of the field.
+	 * The value of the field.
 	 *
 	 * Since: 3.0.0
 	 */
-	properties[PROP_TYPE_HINT] = g_param_spec_string(
-		"type-hint", "type-hint",
-		"The type hint of the field.",
-		NULL,
-		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleRequestField:tooltip:
-	 *
-	 * The tooltip of the field.
-	 *
-	 * Since: 3.0.0
-	 */
-	properties[PROP_TOOLTIP] = g_param_spec_string(
-		"tooltip", "tooltip",
-		"The tooltip of the field.",
+	properties[PROP_VALUE] = g_param_spec_string(
+		"value", "value",
+		"The value of the field.",
 		NULL,
 		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 
-	/**
-	 * PurpleRequestField:required:
-	 *
-	 * Whether the field is required to complete the request.
-	 *
-	 * Since: 3.0.0
-	 */
-	properties[PROP_REQUIRED] = g_param_spec_boolean(
-		"required", "required",
-		"Whether the field is required to complete the request.",
-		FALSE,
-		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleRequestField:is-validatable:
-	 *
-	 * Whether the field can be validated by the requestor.
-	 *
-	 * Since: 3.0.0
-	 */
-	properties[PROP_IS_VALIDATABLE] = g_param_spec_boolean(
-		"is-validatable", "is-validatable",
-		"Whether the field can be validated by the requestor.",
-		FALSE,
-		G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
-
 	g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
 }
 
@@ -381,1075 +203,107 @@ purple_request_field_class_init(PurpleRe
  * Public API
  *****************************************************************************/
 PurpleRequestField *
-purple_request_field_new(const char *id, const char *text,
-                         PurpleRequestFieldType type)
-{
-	PurpleRequestField *field;
-
-	g_return_val_if_fail(id != NULL, NULL);
-	g_return_val_if_fail(type != PURPLE_REQUEST_FIELD_NONE, NULL);
-
-	field = g_object_new(PURPLE_TYPE_REQUEST_FIELD,
-	                     "id", id,
-	                     "label", text,
-	                     NULL);
-	purple_request_field_set_field_type(field, type);
-
-	return field;
-}
-
-void
-_purple_request_field_set_group(PurpleRequestField *field,
-                                PurpleRequestGroup *group)
+purple_request_field_string_new(const char *id, const char *text,
+                                const char *default_value, gboolean multiline)
 {
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_REQUEST_FIELD(field));
-
-	priv = purple_request_field_get_instance_private(field);
-
-	priv->group = group;
-}
-
-void
-purple_request_field_set_label(PurpleRequestField *field, const char *label)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_REQUEST_FIELD(field));
-
-	priv = purple_request_field_get_instance_private(field);
-
-	g_free(priv->label);
-	priv->label = g_strdup(label);
+	g_return_val_if_fail(id != NULL, NULL);
+	g_return_val_if_fail(text != NULL, NULL);
 
-	g_object_notify_by_pspec(G_OBJECT(field), properties[PROP_LABEL]);
-}
-
-void
-purple_request_field_set_visible(PurpleRequestField *field, gboolean visible)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_REQUEST_FIELD(field));
-
-	priv = purple_request_field_get_instance_private(field);
-
-	priv->visible = visible;
-
-	g_object_notify_by_pspec(G_OBJECT(field), properties[PROP_VISIBLE]);
-}
-
-void
-purple_request_field_set_type_hint(PurpleRequestField *field,
-								 const char *type_hint)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_REQUEST_FIELD(field));
-
-	priv = purple_request_field_get_instance_private(field);
-
-	g_free(priv->type_hint);
-	priv->type_hint = g_strdup(type_hint);
-
-	g_object_notify_by_pspec(G_OBJECT(field), properties[PROP_TYPE_HINT]);
-}
-
-void
-purple_request_field_set_tooltip(PurpleRequestField *field, const char *tooltip)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_REQUEST_FIELD(field));
-
-	priv = purple_request_field_get_instance_private(field);
-
-	g_free(priv->tooltip);
-	priv->tooltip = g_strdup(tooltip);
-
-	g_object_notify_by_pspec(G_OBJECT(field), properties[PROP_TOOLTIP]);
+	return g_object_new(PURPLE_TYPE_REQUEST_FIELD_STRING,
+	                    "id", id,
+	                    "label", text,
+	                    "multiline", multiline,
+	                    "default-value", default_value,
+	                    "value", default_value,
+	                    NULL);
 }
 
 void
-purple_request_field_set_required(PurpleRequestField *field, gboolean required)
+purple_request_field_string_set_default_value(PurpleRequestFieldString *field,
+                                              const char *default_value)
 {
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_REQUEST_FIELD(field));
-
-	priv = purple_request_field_get_instance_private(field);
-
-	if(priv->required == required) {
-		return;
-	}
-
-	priv->required = required;
-
-	if(PURPLE_IS_REQUEST_GROUP(priv->group)) {
-		_purple_request_group_set_field_required(priv->group, field,
-		                                         required);
-	}
-
-	g_object_notify_by_pspec(G_OBJECT(field), properties[PROP_REQUIRED]);
-}
-
-PurpleRequestFieldType
-purple_request_field_get_field_type(PurpleRequestField *field) {
-	PurpleRequestFieldPrivate *priv = NULL;
+	g_return_if_fail(PURPLE_IS_REQUEST_FIELD_STRING(field));
 
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field),
-	                     PURPLE_REQUEST_FIELD_NONE);
-
-	priv = purple_request_field_get_instance_private(field);
-
-	return priv->type;
-}
-
-PurpleRequestGroup *
-purple_request_field_get_group(PurpleRequestField *field) {
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), NULL);
+	if(!purple_strequal(field->default_value, default_value)) {
+		g_free(field->default_value);
+		field->default_value = g_strdup(default_value);
 
-	priv = purple_request_field_get_instance_private(field);
-
-	return priv->group;
-}
-
-const char *
-purple_request_field_get_id(PurpleRequestField *field) {
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), NULL);
-
-	priv = purple_request_field_get_instance_private(field);
-
-	return priv->id;
+		g_object_notify_by_pspec(G_OBJECT(field),
+		                         properties[PROP_DEFAULT_VALUE]);
+	}
 }
 
-const char *
-purple_request_field_get_label(PurpleRequestField *field) {
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), NULL);
-
-	priv = purple_request_field_get_instance_private(field);
-
-	return priv->label;
-}
-
-gboolean
-purple_request_field_is_visible(PurpleRequestField *field) {
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), FALSE);
-
-	priv = purple_request_field_get_instance_private(field);
-
-	return priv->visible;
-}
-
-const char *
-purple_request_field_get_type_hint(PurpleRequestField *field) {
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), NULL);
-
-	priv = purple_request_field_get_instance_private(field);
-
-	return priv->type_hint;
-}
+void
+purple_request_field_string_set_value(PurpleRequestFieldString *field,
+                                      const char *value)
+{
+	g_return_if_fail(PURPLE_IS_REQUEST_FIELD_STRING(field));
 
-const char *
-purple_request_field_get_tooltip(PurpleRequestField *field) {
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), NULL);
-
-	priv = purple_request_field_get_instance_private(field);
-
-	return priv->tooltip;
-}
-
-gboolean
-purple_request_field_is_required(PurpleRequestField *field) {
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), FALSE);
+	if(!purple_strequal(field->value, value)) {
+		g_free(field->value);
+		field->value = g_strdup(value);
 
-	priv = purple_request_field_get_instance_private(field);
-
-	return priv->required;
-}
-
-gboolean
-purple_request_field_is_filled(PurpleRequestField *field) {
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), FALSE);
-
-	switch (purple_request_field_get_field_type(field))
-	{
-		case PURPLE_REQUEST_FIELD_STRING:
-			return (purple_request_field_string_get_value(field) != NULL &&
-				*(purple_request_field_string_get_value(field)) != '\0');
-		default:
-			return TRUE;
+		g_object_notify_by_pspec(G_OBJECT(field), properties[PROP_VALUE]);
 	}
 }
 
 void
-purple_request_field_set_validator(PurpleRequestField *field,
-	PurpleRequestFieldValidator validator, void *user_data)
+purple_request_field_string_set_masked(PurpleRequestFieldString *field,
+                                       gboolean masked)
 {
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_REQUEST_FIELD(field));
-
-	priv = purple_request_field_get_instance_private(field);
-
-	priv->validator = validator;
-	priv->validator_data = validator ? user_data : NULL;
-
-	if(PURPLE_IS_REQUEST_GROUP(priv->group)) {
-		_purple_request_group_set_field_validator(priv->group, field,
-		                                          validator != NULL);
-	}
-
-	g_object_notify_by_pspec(G_OBJECT(field), properties[PROP_IS_VALIDATABLE]);
-}
+	g_return_if_fail(PURPLE_IS_REQUEST_FIELD_STRING(field));
 
-gboolean
-purple_request_field_is_validatable(PurpleRequestField *field)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), FALSE);
-
-	priv = purple_request_field_get_instance_private(field);
-
-	return priv->validator != NULL;
-}
-
-gboolean
-purple_request_field_is_valid(PurpleRequestField *field, gchar **errmsg)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-	gboolean valid;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), FALSE);
-
-	priv = purple_request_field_get_instance_private(field);
-
-	if(!priv->validator) {
-		return TRUE;
+	if(field->masked == masked) {
+		return;
 	}
 
-	if (!purple_request_field_is_required(field) &&
-		!purple_request_field_is_filled(field))
-		return TRUE;
-
-	valid = priv->validator(field, errmsg, priv->validator_data);
-
-	if (valid && errmsg)
-		*errmsg = NULL;
-
-	return valid;
-}
-
-void
-purple_request_field_set_sensitive(PurpleRequestField *field,
-	gboolean sensitive)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_REQUEST_FIELD(field));
-
-	priv = purple_request_field_get_instance_private(field);
-
-	priv->sensitive = sensitive;
-
-	g_object_notify_by_pspec(G_OBJECT(field), properties[PROP_SENSITIVE]);
-}
-
-gboolean
-purple_request_field_is_sensitive(PurpleRequestField *field)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), FALSE);
-
-	priv = purple_request_field_get_instance_private(field);
-
-	return priv->sensitive;
-}
-
-PurpleRequestField *
-purple_request_field_string_new(const char *id, const char *text,
-							  const char *default_value, gboolean multiline)
-{
-	PurpleRequestField *field;
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(id   != NULL, NULL);
-	g_return_val_if_fail(text != NULL, NULL);
-
-	field = purple_request_field_new(id, text, PURPLE_REQUEST_FIELD_STRING);
-	priv = purple_request_field_get_instance_private(field);
-
-	priv->u.string.multiline = multiline;
+	field->masked = masked;
 
-	purple_request_field_string_set_default_value(field, default_value);
-	purple_request_field_string_set_value(field, default_value);
-
-	return field;
-}
-
-void
-purple_request_field_string_set_default_value(PurpleRequestField *field,
-											const char *default_value)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_REQUEST_FIELD(field));
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_if_fail(priv->type == PURPLE_REQUEST_FIELD_STRING);
-
-	g_free(priv->u.string.default_value);
-	priv->u.string.default_value = g_strdup(default_value);
-}
-
-void
-purple_request_field_string_set_value(PurpleRequestField *field, const char *value)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_REQUEST_FIELD(field));
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_if_fail(priv->type == PURPLE_REQUEST_FIELD_STRING);
-
-	g_free(priv->u.string.value);
-	priv->u.string.value = g_strdup(value);
-}
-
-void
-purple_request_field_string_set_masked(PurpleRequestField *field, gboolean masked)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_REQUEST_FIELD(field));
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_if_fail(priv->type == PURPLE_REQUEST_FIELD_STRING);
-
-	priv->u.string.masked = masked;
-}
-
-const char *
-purple_request_field_string_get_default_value(PurpleRequestField *field) {
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), NULL);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_val_if_fail(priv->type == PURPLE_REQUEST_FIELD_STRING, NULL);
-
-	return priv->u.string.default_value;
+	g_object_notify_by_pspec(G_OBJECT(field), properties[PROP_MASKED]);
 }
 
 const char *
-purple_request_field_string_get_value(PurpleRequestField *field) {
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), NULL);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_val_if_fail(priv->type == PURPLE_REQUEST_FIELD_STRING, NULL);
-
-	return priv->u.string.value;
-}
-
-gboolean
-purple_request_field_string_is_multiline(PurpleRequestField *field) {
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), FALSE);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_val_if_fail(priv->type == PURPLE_REQUEST_FIELD_STRING, FALSE);
-
-	return priv->u.string.multiline;
-}
-
-gboolean
-purple_request_field_string_is_masked(PurpleRequestField *field) {
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), FALSE);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_val_if_fail(priv->type == PURPLE_REQUEST_FIELD_STRING, FALSE);
-
-	return priv->u.string.masked;
-}
-
-PurpleRequestField *
-purple_request_field_int_new(const char *id, const char *text,
-	int default_value, int lower_bound, int upper_bound)
+purple_request_field_string_get_default_value(PurpleRequestFieldString *field)
 {
-	PurpleRequestField *field;
-
-	g_return_val_if_fail(id   != NULL, NULL);
-	g_return_val_if_fail(text != NULL, NULL);
-
-	field = purple_request_field_new(id, text, PURPLE_REQUEST_FIELD_INTEGER);
+	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD_STRING(field), NULL);
 
-	purple_request_field_int_set_lower_bound(field, lower_bound);
-	purple_request_field_int_set_upper_bound(field, upper_bound);
-	purple_request_field_int_set_default_value(field, default_value);
-	purple_request_field_int_set_value(field, default_value);
-
-	return field;
-}
-
-void
-purple_request_field_int_set_default_value(PurpleRequestField *field,
-										 int default_value)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_REQUEST_FIELD(field));
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_if_fail(priv->type == PURPLE_REQUEST_FIELD_INTEGER);
-
-	priv->u.integer.default_value = default_value;
-}
-
-void
-purple_request_field_int_set_lower_bound(PurpleRequestField *field,
-	int lower_bound)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_REQUEST_FIELD(field));
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_if_fail(priv->type == PURPLE_REQUEST_FIELD_INTEGER);
-
-	priv->u.integer.lower_bound = lower_bound;
-}
-
-void
-purple_request_field_int_set_upper_bound(PurpleRequestField *field,
-	int upper_bound)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_REQUEST_FIELD(field));
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_if_fail(priv->type == PURPLE_REQUEST_FIELD_INTEGER);
-
-	priv->u.integer.upper_bound = upper_bound;
+	return field->default_value;
 }
 
-void
-purple_request_field_int_set_value(PurpleRequestField *field, int value)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_REQUEST_FIELD(field));
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_if_fail(priv->type == PURPLE_REQUEST_FIELD_INTEGER);
-
-	if(value < priv->u.integer.lower_bound ||
-	   value > priv->u.integer.upper_bound)
-	{
-		purple_debug_error("request", "Int value out of bounds\n");
-		return;
-	}
-
-	priv->u.integer.value = value;
-}
-
-int
-purple_request_field_int_get_default_value(PurpleRequestField *field) {
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), 0);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_val_if_fail(priv->type == PURPLE_REQUEST_FIELD_INTEGER, 0);
-
-	return priv->u.integer.default_value;
-}
-
-int
-purple_request_field_int_get_lower_bound(PurpleRequestField *field) {
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), 0);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_val_if_fail(priv->type == PURPLE_REQUEST_FIELD_INTEGER, 0);
-
-	return priv->u.integer.lower_bound;
-}
-
-int
-purple_request_field_int_get_upper_bound(PurpleRequestField *field) {
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), 0);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_val_if_fail(priv->type == PURPLE_REQUEST_FIELD_INTEGER, 0);
-
-	return priv->u.integer.upper_bound;
-}
-
-int
-purple_request_field_int_get_value(PurpleRequestField *field) {
-	PurpleRequestFieldPrivate *priv = NULL;
+const char *
+purple_request_field_string_get_value(PurpleRequestFieldString *field) {
+	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD_STRING(field), NULL);
 
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), 0);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_val_if_fail(priv->type == PURPLE_REQUEST_FIELD_INTEGER, 0);
-
-	return priv->u.integer.value;
-}
-
-PurpleRequestField *
-purple_request_field_bool_new(const char *id, const char *text,
-							gboolean default_value)
-{
-	PurpleRequestField *field;
-
-	g_return_val_if_fail(id   != NULL, NULL);
-	g_return_val_if_fail(text != NULL, NULL);
-
-	field = purple_request_field_new(id, text, PURPLE_REQUEST_FIELD_BOOLEAN);
-
-	purple_request_field_bool_set_default_value(field, default_value);
-	purple_request_field_bool_set_value(field, default_value);
-
-	return field;
-}
-
-void
-purple_request_field_bool_set_default_value(PurpleRequestField *field,
-										  gboolean default_value)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_REQUEST_FIELD(field));
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_if_fail(priv->type == PURPLE_REQUEST_FIELD_BOOLEAN);
-
-	priv->u.boolean.default_value = default_value;
-}
-
-void
-purple_request_field_bool_set_value(PurpleRequestField *field, gboolean value)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_REQUEST_FIELD(field));
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_if_fail(priv->type == PURPLE_REQUEST_FIELD_BOOLEAN);
-
-	priv->u.boolean.value = value;
-}
-
-gboolean
-purple_request_field_bool_get_default_value(PurpleRequestField *field) {
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), FALSE);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_val_if_fail(priv->type == PURPLE_REQUEST_FIELD_BOOLEAN, FALSE);
-
-	return priv->u.boolean.default_value;
+	return field->value;
 }
 
 gboolean
-purple_request_field_bool_get_value(PurpleRequestField *field) {
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), FALSE);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_val_if_fail(priv->type == PURPLE_REQUEST_FIELD_BOOLEAN, FALSE);
-
-	return priv->u.boolean.value;
-}
-
-PurpleRequestField *
-purple_request_field_choice_new(const char *id, const char *text,
-	gpointer default_value)
-{
-	PurpleRequestField *field;
-
-	g_return_val_if_fail(id   != NULL, NULL);
-	g_return_val_if_fail(text != NULL, NULL);
-
-	field = purple_request_field_new(id, text, PURPLE_REQUEST_FIELD_CHOICE);
-
-	purple_request_field_choice_set_default_value(field, default_value);
-	purple_request_field_choice_set_value(field, default_value);
-
-	return field;
-}
-
-void
-purple_request_field_choice_add(PurpleRequestField *field, const char *label,
-	gpointer value)
-{
-	purple_request_field_choice_add_full(field, label, value, NULL);
-}
-
-void
-purple_request_field_choice_add_full(PurpleRequestField *field, const char *label,
-                                     gpointer value, GDestroyNotify destroy)
-{
-	PurpleKeyValuePair *choice;
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_REQUEST_FIELD(field));
-	g_return_if_fail(label != NULL);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_if_fail(priv->type == PURPLE_REQUEST_FIELD_CHOICE);
-
-	choice = purple_key_value_pair_new_full(label, value, destroy);
-
-	priv->u.choice.elements = g_list_append(priv->u.choice.elements, choice);
-}
-
-void
-purple_request_field_choice_set_default_value(PurpleRequestField *field,
-	gpointer default_value)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_REQUEST_FIELD(field));
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_if_fail(priv->type == PURPLE_REQUEST_FIELD_CHOICE);
-
-	priv->u.choice.default_value = default_value;
-}
-
-void
-purple_request_field_choice_set_value(PurpleRequestField *field, gpointer value)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_REQUEST_FIELD(field));
+purple_request_field_string_is_multiline(PurpleRequestFieldString *field) {
+	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD_STRING(field), FALSE);
 
-	priv = purple_request_field_get_instance_private(field);
-	g_return_if_fail(priv->type == PURPLE_REQUEST_FIELD_CHOICE);
-
-	priv->u.choice.value = value;
-}
-
-gpointer
-purple_request_field_choice_get_default_value(PurpleRequestField *field) {
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), NULL);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_val_if_fail(priv->type == PURPLE_REQUEST_FIELD_CHOICE, NULL);
-
-	return priv->u.choice.default_value;
-}
-
-gpointer
-purple_request_field_choice_get_value(PurpleRequestField *field) {
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), NULL);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_val_if_fail(priv->type == PURPLE_REQUEST_FIELD_CHOICE, NULL);
-
-	return priv->u.choice.value;
-}
-
-GList *
-purple_request_field_choice_get_elements(PurpleRequestField *field) {
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), NULL);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_val_if_fail(priv->type == PURPLE_REQUEST_FIELD_CHOICE, NULL);
-
-	return priv->u.choice.elements;
-}
-
-PurpleRequestField *
-purple_request_field_list_new(const char *id, const char *text)
-{
-	PurpleRequestField *field;
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(id   != NULL, NULL);
-
-	field = purple_request_field_new(id, text, PURPLE_REQUEST_FIELD_LIST);
-	priv = purple_request_field_get_instance_private(field);
-
-	priv->u.list.item_data = g_hash_table_new_full(g_str_hash, g_str_equal,
-	                                               g_free, NULL);
-
-	priv->u.list.selected_table = g_hash_table_new_full(g_str_hash, g_str_equal,
-	                                                    g_free, NULL);
-
-	return field;
-}
-
-void
-purple_request_field_list_set_multi_select(PurpleRequestField *field,
-										 gboolean multi_select)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_REQUEST_FIELD(field));
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_if_fail(priv->type == PURPLE_REQUEST_FIELD_LIST);
-
-	priv->u.list.multiple_selection = multi_select;
+	return field->multiline;
 }
 
 gboolean
-purple_request_field_list_get_multi_select(PurpleRequestField *field) {
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), FALSE);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_val_if_fail(priv->type == PURPLE_REQUEST_FIELD_LIST, FALSE);
-
-	return priv->u.list.multiple_selection;
-}
-
-void *
-purple_request_field_list_get_data(PurpleRequestField *field, const char *text)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), NULL);
-	g_return_val_if_fail(text  != NULL, NULL);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_val_if_fail(priv->type == PURPLE_REQUEST_FIELD_LIST, NULL);
-
-	return g_hash_table_lookup(priv->u.list.item_data, text);
-}
-
-void
-purple_request_field_list_add_icon(PurpleRequestField *field, const char *item, const char* icon_path,
-							void *data)
-{
-	PurpleKeyValuePair *kvp;
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_REQUEST_FIELD(field));
-	g_return_if_fail(item  != NULL);
-	g_return_if_fail(data  != NULL);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_if_fail(priv->type == PURPLE_REQUEST_FIELD_LIST);
-
-	priv->u.list.has_icons = priv->u.list.has_icons || (icon_path != NULL);
-	kvp = purple_key_value_pair_new_full(item, g_strdup(icon_path), g_free);
-	priv->u.list.items = g_list_append(priv->u.list.items, kvp);
-	g_hash_table_insert(priv->u.list.item_data, g_strdup(item), data);
-}
-
-void
-purple_request_field_list_add_selected(PurpleRequestField *field, const char *item)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_REQUEST_FIELD(field));
-	g_return_if_fail(item  != NULL);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_if_fail(priv->type == PURPLE_REQUEST_FIELD_LIST);
-
-	if(!purple_request_field_list_get_multi_select(field) &&
-	   priv->u.list.selected != NULL)
-	{
-		purple_debug_warning("request",
-						   "More than one item added to non-multi-select "
-						   "field %s\n",
-						   purple_request_field_get_id(field));
-		return;
-	}
-
-	priv->u.list.selected = g_list_append(priv->u.list.selected,
-	                                      g_strdup(item));
-
-	g_hash_table_add(priv->u.list.selected_table, g_strdup(item));
-}
+purple_request_field_string_is_masked(PurpleRequestFieldString *field) {
+	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD_STRING(field), FALSE);
 
-void
-purple_request_field_list_clear_selected(PurpleRequestField *field)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_REQUEST_FIELD(field));
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_if_fail(priv->type == PURPLE_REQUEST_FIELD_LIST);
-
-	if(priv->u.list.selected != NULL) {
-		g_list_free_full(priv->u.list.selected, g_free);
-		priv->u.list.selected = NULL;
-	}
-
-	g_hash_table_remove_all(priv->u.list.selected_table);
-}
-
-void
-purple_request_field_list_set_selected(PurpleRequestField *field, GList *items)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-	GList *l;
-
-	g_return_if_fail(PURPLE_IS_REQUEST_FIELD(field));
-	g_return_if_fail(items != NULL);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_if_fail(priv->type == PURPLE_REQUEST_FIELD_LIST);
-
-	purple_request_field_list_clear_selected(field);
-
-	if (!purple_request_field_list_get_multi_select(field) && items->next) {
-		purple_debug_warning("request",
-						   "More than one item added to non-multi-select "
-						   "field %s\n",
-						   purple_request_field_get_id(field));
-		return;
-	}
-
-	for (l = items; l != NULL; l = l->next) {
-		char *selected = l->data;
-		priv->u.list.selected = g_list_append(priv->u.list.selected,
-		                                      g_strdup(selected));
-		g_hash_table_add(priv->u.list.selected_table, g_strdup(selected));
-	}
-}
-
-gboolean
-purple_request_field_list_is_selected(PurpleRequestField *field,
-                                      const char *item)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), FALSE);
-	g_return_val_if_fail(item  != NULL, FALSE);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_val_if_fail(priv->type == PURPLE_REQUEST_FIELD_LIST, FALSE);
-
-	return g_hash_table_contains(priv->u.list.selected_table, item);
-}
-
-GList *
-purple_request_field_list_get_selected(PurpleRequestField *field) {
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), NULL);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_val_if_fail(priv->type == PURPLE_REQUEST_FIELD_LIST, NULL);
-
-	return priv->u.list.selected;
+	return field->masked;
 }
 
-GList *
-purple_request_field_list_get_items(PurpleRequestField *field) {
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), NULL);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_val_if_fail(priv->type == PURPLE_REQUEST_FIELD_LIST, NULL);
-
-	return priv->u.list.items;
-}
-
-gboolean
-purple_request_field_list_has_icons(PurpleRequestField *field) {
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), FALSE);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_val_if_fail(priv->type == PURPLE_REQUEST_FIELD_LIST, FALSE);
-
-	return priv->u.list.has_icons;
-}
-
-PurpleRequestField *
-purple_request_field_label_new(const char *id, const char *text)
-{
-	PurpleRequestField *field;
-
-	g_return_val_if_fail(id   != NULL, NULL);
-	g_return_val_if_fail(text != NULL, NULL);
-
-	field = purple_request_field_new(id, text, PURPLE_REQUEST_FIELD_LABEL);
-
-	return field;
-}
-
-PurpleRequestField *
-purple_request_field_image_new(const char *id, const char *text, const char *buf, gsize size)
-{
-	PurpleRequestField *field;
-
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(id   != NULL, NULL);
-	g_return_val_if_fail(text != NULL, NULL);
-	g_return_val_if_fail(buf  != NULL, NULL);
-	g_return_val_if_fail(size > 0, NULL);
-
-	field = purple_request_field_new(id, text, PURPLE_REQUEST_FIELD_IMAGE);
-	priv = purple_request_field_get_instance_private(field);
-
-	priv->u.image.buffer = g_memdup2(buf, size);
-	priv->u.image.size = size;
-	priv->u.image.scale_x = 1;
-	priv->u.image.scale_y = 1;
-
-	return field;
-}
-
-void
-purple_request_field_image_set_scale(PurpleRequestField *field, unsigned int x, unsigned int y)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_REQUEST_FIELD(field));
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_if_fail(priv->type == PURPLE_REQUEST_FIELD_IMAGE);
-
-	priv->u.image.scale_x = x;
-	priv->u.image.scale_y = y;
-}
-
-const char *
-purple_request_field_image_get_buffer(PurpleRequestField *field)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), NULL);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_val_if_fail(priv->type == PURPLE_REQUEST_FIELD_IMAGE, NULL);
-
-	return priv->u.image.buffer;
-}
-
-gsize
-purple_request_field_image_get_size(PurpleRequestField *field)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), 0);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_val_if_fail(priv->type == PURPLE_REQUEST_FIELD_IMAGE, 0);
-
-	return priv->u.image.size;
-}
-
-unsigned int
-purple_request_field_image_get_scale_x(PurpleRequestField *field)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), 0);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_val_if_fail(priv->type == PURPLE_REQUEST_FIELD_IMAGE, 0);
-
-	return priv->u.image.scale_x;
-}
-
-unsigned int
-purple_request_field_image_get_scale_y(PurpleRequestField *field)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), 0);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_val_if_fail(priv->type == PURPLE_REQUEST_FIELD_IMAGE, 0);
-
-	return priv->u.image.scale_y;
-}
-
-PurpleRequestField *
-purple_request_field_datasheet_new(const char *id,
-	const gchar *text, PurpleRequestDatasheet *sheet)
-{
-	PurpleRequestField *field;
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(id != NULL, NULL);
-	g_return_val_if_fail(sheet != NULL, NULL);
-
-	field = purple_request_field_new(id, text, PURPLE_REQUEST_FIELD_DATASHEET);
-	priv = purple_request_field_get_instance_private(field);
-
-	priv->u.datasheet.sheet = sheet;
-
-	return field;
-}
-
-PurpleRequestDatasheet *
-purple_request_field_datasheet_get_sheet(PurpleRequestField *field)
-{
-	PurpleRequestFieldPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), NULL);
-
-	priv = purple_request_field_get_instance_private(field);
-	g_return_val_if_fail(priv->type == PURPLE_REQUEST_FIELD_DATASHEET, NULL);
-
-	return priv->u.datasheet.sheet;
-}
-
-/* -- */
+/******************************************************************************
+ * Validators
+ *****************************************************************************/
 
 gboolean
 purple_request_field_email_validator(PurpleRequestField *field, gchar **errmsg,
                                      G_GNUC_UNUSED gpointer user_data)
 {
-	PurpleRequestFieldPrivate *priv = NULL;
 	const char *value;
 
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), FALSE);
+	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD_STRING(field), FALSE);
 
-	priv = purple_request_field_get_instance_private(field);
-	g_return_val_if_fail(priv->type == PURPLE_REQUEST_FIELD_STRING, FALSE);
-
-	value = purple_request_field_string_get_value(field);
+	value = purple_request_field_string_get_value(PURPLE_REQUEST_FIELD_STRING(field));
 
 	if (value != NULL && purple_email_is_valid(value))
 		return TRUE;
@@ -1463,16 +317,12 @@ gboolean
 purple_request_field_alphanumeric_validator(PurpleRequestField *field,
 	gchar **errmsg, void *allowed_characters)
 {
-	PurpleRequestFieldPrivate *priv = NULL;
 	const char *value;
 	gchar invalid_char = '\0';
 
-	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), FALSE);
+	g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD_STRING(field), FALSE);
 
-	priv = purple_request_field_get_instance_private(field);
-	g_return_val_if_fail(priv->type == PURPLE_REQUEST_FIELD_STRING, FALSE);
-
-	value = purple_request_field_string_get_value(field);
+	value = purple_request_field_string_get_value(PURPLE_REQUEST_FIELD_STRING(field));
 
 	g_return_val_if_fail(value != NULL, FALSE);
 
diff --git a/libpurple/purplerequestpage.c b/libpurple/purplerequestpage.c
--- a/libpurple/purplerequestpage.c
+++ b/libpurple/purplerequestpage.c
@@ -24,6 +24,7 @@
 #include "glibcompat.h"
 #include "purplerequestpage.h"
 #include "request/purplerequestfieldaccount.h"
+#include "request/purplerequestfieldstring.h"
 #include "purpleprivate.h"
 
 struct _PurpleRequestPage {
@@ -296,11 +297,12 @@ purple_request_page_get_string(PurpleReq
 	g_return_val_if_fail(PURPLE_IS_REQUEST_PAGE(page), NULL);
 	g_return_val_if_fail(id     != NULL, NULL);
 
-	if((field = purple_request_page_get_field(page, id)) == NULL) {
+	field = purple_request_page_get_field(page, id);
+	if(!PURPLE_IS_REQUEST_FIELD_STRING(field)) {
 		return NULL;
 	}
 
-	return purple_request_field_string_get_value(field);
+	return purple_request_field_string_get_value(PURPLE_REQUEST_FIELD_STRING(field));
 }
 
 int
diff --git a/pidgin/gtkrequest.c b/pidgin/gtkrequest.c
--- a/pidgin/gtkrequest.c
+++ b/pidgin/gtkrequest.c
@@ -195,7 +195,7 @@ choice_response_cb(GtkDialog *dialog, gi
 
 static gboolean
 field_string_focus_out_cb(GtkEventControllerFocus *controller,
-                          PurpleRequestField *field)
+                          PurpleRequestFieldString *field)
 {
 	GtkWidget *entry = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller));
 	const char *value;
@@ -1042,21 +1042,27 @@ req_entry_field_changed_cb(GtkWidget *en
 		int value = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(entry));
 		purple_request_field_int_set_value(field, value);
 
-	} else if (purple_request_field_string_is_multiline(field)) {
-		char *text;
-		GtkTextIter start_iter, end_iter;
-
-		gtk_text_buffer_get_start_iter(GTK_TEXT_BUFFER(entry), &start_iter);
-		gtk_text_buffer_get_end_iter(GTK_TEXT_BUFFER(entry), &end_iter);
-
-		text = gtk_text_buffer_get_text(GTK_TEXT_BUFFER(entry), &start_iter, &end_iter, FALSE);
-		purple_request_field_string_set_value(field, (!text || !*text) ? NULL : text);
-		g_free(text);
-
 	} else {
-		const char *text = NULL;
-		text = gtk_editable_get_text(GTK_EDITABLE(entry));
-		purple_request_field_string_set_value(field, (*text == '\0') ? NULL : text);
+		PurpleRequestFieldString *strfield = PURPLE_REQUEST_FIELD_STRING(field);
+		if(purple_request_field_string_is_multiline(strfield)) {
+			char *text;
+			GtkTextIter start_iter, end_iter;
+
+			gtk_text_buffer_get_start_iter(GTK_TEXT_BUFFER(entry), &start_iter);
+			gtk_text_buffer_get_end_iter(GTK_TEXT_BUFFER(entry), &end_iter);
+
+			text = gtk_text_buffer_get_text(GTK_TEXT_BUFFER(entry),
+			                                &start_iter, &end_iter, FALSE);
+			purple_request_field_string_set_value(strfield,
+			                                      purple_strempty(text) ? NULL : text);
+			g_free(text);
+
+		} else {
+			const char *text = NULL;
+			text = gtk_editable_get_text(GTK_EDITABLE(entry));
+			purple_request_field_string_set_value(strfield,
+			                                      purple_strempty(text) ? NULL : text);
+		}
 	}
 
 	req_field_changed_common(entry, field);
@@ -1109,15 +1115,15 @@ setup_entry_field(GtkWidget *entry, Purp
 static GtkWidget *
 create_string_field(PurpleRequestField *field)
 {
+	PurpleRequestFieldString *strfield = PURPLE_REQUEST_FIELD_STRING(field);
 	const char *value;
 	GtkWidget *widget;
 	gboolean is_editable;
 
-	value = purple_request_field_string_get_default_value(field);
+	value = purple_request_field_string_get_default_value(strfield);
 	is_editable = purple_request_field_is_sensitive(field);
 
-	if (purple_request_field_string_is_multiline(field))
-	{
+	if(purple_request_field_string_is_multiline(strfield)) {
 		GtkWidget *textview;
 		GtkEventController *controller;
 
@@ -1162,7 +1168,7 @@ create_string_field(PurpleRequestField *
 	{
 		GtkEventController *controller = NULL;
 
-		if (purple_request_field_string_is_masked(field)) {
+		if(purple_request_field_string_is_masked(strfield)) {
 			widget = gtk_password_entry_new();
 			g_object_set(widget, "activates-default", TRUE,
 			             "show-peek-icon", TRUE, NULL);
@@ -2044,8 +2050,8 @@ pidgin_request_fields(const char *title,
 				rows++;
 			}
 			else if ((type == PURPLE_REQUEST_FIELD_LIST) ||
-				 (type == PURPLE_REQUEST_FIELD_STRING &&
-				  purple_request_field_string_is_multiline(field)))
+				 (PURPLE_IS_REQUEST_FIELD_STRING(field) &&
+				  purple_request_field_string_is_multiline(PURPLE_REQUEST_FIELD_STRING(field))))
 			{
 				rows += 2;
 			} else if (compact && type != PURPLE_REQUEST_FIELD_BOOLEAN)
@@ -2114,8 +2120,8 @@ pidgin_request_fields(const char *title,
 
 					if (type == PURPLE_REQUEST_FIELD_LABEL ||
 					    type == PURPLE_REQUEST_FIELD_LIST ||
-						(type == PURPLE_REQUEST_FIELD_STRING &&
-						 purple_request_field_string_is_multiline(field)))
+						(PURPLE_IS_REQUEST_FIELD_STRING(field) &&
+						 purple_request_field_string_is_multiline(PURPLE_REQUEST_FIELD_STRING(field))))
 					{
 						gtk_grid_attach(GTK_GRID(grid), label,
 							0, row_num, 2 * cols, 1);
@@ -2135,9 +2141,9 @@ pidgin_request_fields(const char *title,
 				                                      "pidgin-ui-data"));
 				if (widget == NULL)
 				{
-					if (type == PURPLE_REQUEST_FIELD_STRING)
+					if(PURPLE_IS_REQUEST_FIELD_STRING(field)) {
 						widget = create_string_field(field);
-					else if (type == PURPLE_REQUEST_FIELD_INTEGER)
+					} else if (type == PURPLE_REQUEST_FIELD_INTEGER)
 						widget = create_int_field(field);
 					else if (type == PURPLE_REQUEST_FIELD_BOOLEAN)
 						widget = create_bool_field(field, cpar);
@@ -2166,8 +2172,8 @@ pidgin_request_fields(const char *title,
 				gtk_widget_set_margin_start(widget, 5);
 				gtk_widget_set_margin_end(widget, 5);
 
-				if (type == PURPLE_REQUEST_FIELD_STRING &&
-					purple_request_field_string_is_multiline(field))
+				if(PURPLE_IS_REQUEST_FIELD_STRING(field) &&
+					purple_request_field_string_is_multiline(PURPLE_REQUEST_FIELD_STRING(field)))
 				{
 					gtk_grid_attach(GTK_GRID(grid), widget,
 						0, row_num, 2 * cols, 1);
diff --git a/pidgin/pidginmooddialog.c b/pidgin/pidginmooddialog.c
--- a/pidgin/pidginmooddialog.c
+++ b/pidgin/pidginmooddialog.c
@@ -85,10 +85,7 @@ pidgin_mood_dialog_edit_cb(PurpleConnect
 
 		flags = purple_connection_get_flags(connection);
 		if (flags & PURPLE_CONNECTION_FLAG_SUPPORT_MOOD_MESSAGES) {
-			PurpleRequestField *text_field = NULL;
-
-			text_field = purple_request_page_get_field(page, "text");
-			text = purple_request_field_string_get_value(text_field);
+			text = purple_request_page_get_string(page, "text");
 		} else {
 			text = NULL;
 		}
