# HG changeset patch
# Node ID 6cf1d83a5e01970ebb9710298ff343b11b273993
# Parent  4230fc2b6ec25c402819f5f0b94ca9622fe87e3e
diff --git a/ibis/ibissource.c b/ibis/ibissource.c
--- a/ibis/ibissource.c
+++ b/ibis/ibissource.c
@@ -88,6 +88,25 @@
 	g_clear_pointer(&regex, g_regex_unref);
 }
 
+char *
+ibis_source_serialize(const char *nick, const char *user, const char *host) {
+	GString *str = NULL;
+
+	g_return_val_if_fail(!ibis_str_is_empty(nick), NULL);
+
+	str = g_string_new(nick);
+
+	if(!ibis_str_is_empty(user)) {
+		g_string_append_printf(str, "!%s", user);
+
+		if(!ibis_str_is_empty(host)) {
+			g_string_append_printf(str, "@%s", host);
+		}
+	}
+
+	return g_string_free_and_steal(str);
+}
+
 /**
  * ibis_source_find_offset: (skip)
  * @source: The source.
diff --git a/ibis/ibissource.h b/ibis/ibissource.h
--- a/ibis/ibissource.h
+++ b/ibis/ibissource.h
@@ -52,6 +52,23 @@
 void ibis_source_parse(const char *source, char **nick, char **user, char **host);
 
 /**
+ * ibis_source_serialize:
+ * @nick: The nick.
+ * @user: (nullable): The user field.
+ * @host: (nullable): The host field.
+ *
+ * Creates a source from its parts.
+ *
+ * This does the reverse of [func@source_parse].
+ *
+ * Returns: The new source.
+ *
+ * Since: 0.9
+ */
+IBIS_AVAILABLE_IN_0_9
+char *ibis_source_serialize(const char *nick, const char *user, const char *host);
+
+/**
  * ibis_source_strip_prefix:
  * @source: The source to strip.
  * @prefixes: The list of prefixes that should be stripped.
diff --git a/ibis/tests/test_source.c b/ibis/tests/test_source.c
--- a/ibis/tests/test_source.c
+++ b/ibis/tests/test_source.c
@@ -86,8 +86,7 @@
 	char *host = NULL;
 
 	/* Once to make sure everything works. */
-	ibis_source_parse("pidgy!~u@53unc8n42i868.irc", &nick, &user,
-	                          &host);
+	ibis_source_parse("pidgy!~u@53unc8n42i868.irc", &nick, &user, &host);
 	g_assert_cmpstr(nick, ==, "pidgy");
 	g_clear_pointer(&nick, g_free);
 
@@ -143,6 +142,59 @@
 }
 
 /******************************************************************************
+ * Serialize Tests
+ *****************************************************************************/
+static void
+test_ibis_source_serialize_nick_required(void) {
+	if(g_test_subprocess()) {
+		ibis_source_serialize(NULL, NULL, NULL);
+	}
+
+	g_test_trap_subprocess(NULL, 0, G_TEST_SUBPROCESS_DEFAULT);
+	g_test_trap_assert_stderr("*'!ibis_str_is_empty(nick)' failed*");
+}
+
+static void
+test_ibis_source_serialize_nick(void) {
+	char *result = NULL;
+
+	result = ibis_source_serialize("irene", NULL, NULL);
+
+	g_assert_cmpstr(result, ==, "irene");
+	g_clear_pointer(&result, g_free);
+}
+
+static void
+test_ibis_source_serialize_user(void) {
+	char *result = NULL;
+
+	result = ibis_source_serialize("irene", "~u", NULL);
+
+	g_assert_cmpstr(result, ==, "irene!~u");
+	g_clear_pointer(&result, g_free);
+}
+
+static void
+test_ibis_source_serialize_host(void) {
+	char *result = NULL;
+
+	result = ibis_source_serialize("irene", "~u", "server");
+
+	g_assert_cmpstr(result, ==, "irene!~u@server");
+	g_clear_pointer(&result, g_free);
+}
+
+static void
+test_ibis_source_serialize_host_without_user(void) {
+	char *result = NULL;
+
+	result = ibis_source_serialize("irene", NULL, "server");
+
+	g_assert_cmpstr(result, ==, "irene");
+	g_clear_pointer(&result, g_free);
+}
+
+/******************************************************************************
  * Strip Prefix Tests
  *****************************************************************************/
 static void
@@ -253,6 +305,17 @@
 	g_test_add_func("/ibis/source/parse/baddies",
 	                test_ibis_source_parse_baddies);
 
+	g_test_add_func("/ibis/source/serialize/nick-required",
+	                test_ibis_source_serialize_nick_required);
+	g_test_add_func("/ibis/source/serialize/nick",
+	                test_ibis_source_serialize_nick);
+	g_test_add_func("/ibis/source/serialize/user",
+	                test_ibis_source_serialize_user);
+	g_test_add_func("/ibis/source/serialize/host",
+	                test_ibis_source_serialize_host);
+	g_test_add_func("/ibis/source/serialize/host-without-user",
+	                test_ibis_source_serialize_host_without_user);
+
 	g_test_add_func("/ibis/source/strip-prefix/none",
 	                test_ibis_source_strip_prefix_none);
 	g_test_add_func("/ibis/source/strip-prefix/single",
