Index: irc.h
===================================================================
--- irc.h	(revision c0e4c22e4a6b79f044885ebf6524cc43720bc9fc)
+++ irc.h	(revision 830864dc35395ec3a580a8d465f80506e8b00040)
@@ -147,4 +147,7 @@
 	IRC_CHANNEL_TEMP = 2,   /* Erase the channel when the user leaves,
 	                           and don't save it. */
+
+	/* Show a placeholder of the channel in listings, but don't save it */
+	IRC_CHANNEL_KEEP_PLACEHOLDER = 4,
 
 	/* Hack: Set this flag right before jumping into IM when we expect
@@ -299,4 +302,6 @@
 void irc_channel_name_strip(char *name);
 int irc_channel_name_cmp(const char *a_, const char *b_);
+char *irc_channel_name_gen(bee_t *bee, const char *name);
+gboolean irc_channel_name_hint(irc_channel_t *ic, const char *name);
 void irc_channel_update_ops(irc_channel_t *ic, char *value);
 char *set_eval_irc_channel_ops(struct set *set, char *value);
Index: irc_channel.c
===================================================================
--- irc_channel.c	(revision c0e4c22e4a6b79f044885ebf6524cc43720bc9fc)
+++ irc_channel.c	(revision 830864dc35395ec3a580a8d465f80506e8b00040)
@@ -276,5 +276,5 @@
 		if (ic->irc->status & USTATUS_SHUTDOWN) {
 			/* Don't do anything fancy when we're shutting down anyway. */
-		} else if (ic->flags & IRC_CHANNEL_TEMP) {
+		} else if (ic->flags & IRC_CHANNEL_TEMP && !(ic->flags & IRC_CHANNEL_KEEP_PLACEHOLDER)) {
 			irc_channel_free_soon(ic);
 		} else {
@@ -556,4 +556,75 @@
 }
 
+gboolean irc_channel_is_unused(bee_t *bee, char *name)
+{
+	char *type, *chat_type;
+	irc_channel_t *oic;
+
+	if (!irc_channel_name_ok(name)) {
+		return FALSE;
+	}
+
+	if (!(oic = irc_channel_by_name(bee->ui_data, name))) {
+		return TRUE;
+	}
+
+	type = set_getstr(&oic->set, "type");
+	chat_type = set_getstr(&oic->set, "chat_type");
+
+	if (type && chat_type && oic->data == FALSE &&
+	    strcmp(type, "chat") == 0 &&
+	    strcmp(chat_type, "groupchat") == 0) {
+		/* There's a channel with this name already, but it looks
+		   like it's not in use yet. Most likely the IRC client
+		   rejoined the channel after a reconnect. Remove it so
+		   we can reuse its name. */
+		irc_channel_free(oic);
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+char *irc_channel_name_gen(bee_t *bee, const char *hint)
+{
+	char name[MAX_NICK_LENGTH + 1] = { 0 };
+
+	name[0] = '#';
+	strncpy(name + 1, hint, MAX_NICK_LENGTH - 1);
+	name[MAX_NICK_LENGTH] = '\0';
+
+	irc_channel_name_strip(name);
+
+	if (set_getbool(&bee->set, "lcnicks")) {
+		nick_lc(bee->ui_data, name + 1);
+	}
+
+	while (!irc_channel_is_unused(bee, name)) {
+		underscore_dedupe(name);
+	}
+
+	return g_strdup(name);
+}
+
+gboolean irc_channel_name_hint(irc_channel_t *ic, const char *name)
+{
+	irc_t *irc = ic->irc;
+	char *full_name;
+
+	/* Don't rename a channel if the user's in it already. */
+	if (ic->flags & IRC_CHANNEL_JOINED) {
+		return FALSE;
+	}
+
+	if (!(full_name = irc_channel_name_gen(irc->b, name))) {
+		return FALSE;
+	}
+
+	g_free(ic->name);
+	ic->name = full_name;
+
+	return TRUE;
+}
+
 static gint irc_channel_user_cmp(gconstpointer a_, gconstpointer b_)
 {
Index: irc_im.c
===================================================================
--- irc_im.c	(revision c0e4c22e4a6b79f044885ebf6524cc43720bc9fc)
+++ irc_im.c	(revision 830864dc35395ec3a580a8d465f80506e8b00040)
@@ -609,4 +609,25 @@
 }
 
+static gboolean bee_irc_chat_placeholder_new(bee_t *bee, struct im_connection *ic, const char *handle,
+                                             const char *name, const char *topic)
+{
+	irc_t *irc = bee->ui_data;
+	irc_channel_t *ircc;
+	char *full_name = irc_channel_name_gen(bee, name);
+
+	ircc = irc_channel_new(irc, full_name);
+
+	set_setstr(&ircc->set, "type", "chat");
+	set_setstr(&ircc->set, "chat_type", "placeholder");
+	set_setstr(&ircc->set, "account", ic->acc->tag);
+	set_setstr(&ircc->set, "room", (char *) handle);
+
+	irc_channel_set_topic(ircc, topic, NULL);
+
+	g_free(full_name);
+
+	return TRUE;
+}
+
 static gboolean bee_irc_chat_log(bee_t *bee, struct groupchat *c, const char *text)
 {
@@ -701,53 +722,5 @@
 static gboolean bee_irc_chat_name_hint(bee_t *bee, struct groupchat *c, const char *name)
 {
-	irc_t *irc = bee->ui_data;
-	irc_channel_t *ic = c->ui_data, *oic;
-	char stripped[MAX_NICK_LENGTH + 1], *full_name;
-
-	if (ic == NULL) {
-		return FALSE;
-	}
-
-	/* Don't rename a channel if the user's in it already. */
-	if (ic->flags & IRC_CHANNEL_JOINED) {
-		return FALSE;
-	}
-
-	strncpy(stripped, name, MAX_NICK_LENGTH);
-	stripped[MAX_NICK_LENGTH] = '\0';
-	irc_channel_name_strip(stripped);
-	if (set_getbool(&bee->set, "lcnicks")) {
-		nick_lc(irc, stripped);
-	}
-
-	if (stripped[0] == '\0') {
-		return FALSE;
-	}
-
-	full_name = g_strdup_printf("#%s", stripped);
-	if ((oic = irc_channel_by_name(irc, full_name))) {
-		char *type, *chat_type;
-
-		type = set_getstr(&oic->set, "type");
-		chat_type = set_getstr(&oic->set, "chat_type");
-
-		if (type && chat_type && oic->data == FALSE &&
-		    strcmp(type, "chat") == 0 &&
-		    strcmp(chat_type, "groupchat") == 0) {
-			/* There's a channel with this name already, but it looks
-			   like it's not in use yet. Most likely the IRC client
-			   rejoined the channel after a reconnect. Remove it so
-			   we can reuse its name. */
-			irc_channel_free(oic);
-		} else {
-			g_free(full_name);
-			return FALSE;
-		}
-	}
-
-	g_free(ic->name);
-	ic->name = full_name;
-
-	return TRUE;
+	return irc_channel_name_hint(c->ui_data, name);
 }
 
@@ -877,8 +850,10 @@
 static gboolean bee_irc_channel_chat_join(irc_channel_t *ic)
 {
-	char *acc_s, *room;
+	char *acc_s, *room, *chat_type;
 	account_t *acc;
 
-	if (strcmp(set_getstr(&ic->set, "chat_type"), "room") != 0) {
+	chat_type = set_getstr(&ic->set, "chat_type");
+
+	if (strcmp(chat_type, "room") != 0 && strcmp(chat_type, "placeholder") != 0) {
 		return TRUE;
 	}
@@ -1036,8 +1011,12 @@
 	struct irc_channel *ic = set->data;
 
+	ic->flags &= ~(IRC_CHANNEL_TEMP | IRC_CHANNEL_KEEP_PLACEHOLDER);
+
 	if (strcmp(value, "groupchat") == 0) {
 		ic->flags |= IRC_CHANNEL_TEMP;
 	} else if (strcmp(value, "room") == 0) {
-		ic->flags &= ~IRC_CHANNEL_TEMP;
+		// beep boop
+	} else if (strcmp(value, "placeholder") == 0) {
+		ic->flags |= IRC_CHANNEL_TEMP | IRC_CHANNEL_KEEP_PLACEHOLDER;
 	} else {
 		return NULL;
@@ -1123,4 +1102,5 @@
 	bee_irc_chat_new,
 	bee_irc_chat_free,
+	bee_irc_chat_placeholder_new,
 	bee_irc_chat_log,
 	bee_irc_chat_msg,
Index: nick.c
===================================================================
--- nick.c	(revision c0e4c22e4a6b79f044885ebf6524cc43720bc9fc)
+++ nick.c	(revision 830864dc35395ec3a580a8d465f80506e8b00040)
@@ -214,4 +214,20 @@
 }
 
+/* Used for nicks and channel names too! */
+void underscore_dedupe(char nick[MAX_NICK_LENGTH + 1])
+{
+	if (strlen(nick) < (MAX_NICK_LENGTH - 1)) {
+		nick[strlen(nick) + 1] = 0;
+		nick[strlen(nick)] = '_';
+	} else {
+		/* We've got no more space for underscores,
+		   so truncate it and replace the last three
+		   chars with a random "_XX" suffix */
+		int len = truncate_utf8(nick, MAX_NICK_LENGTH - 3);
+		nick[len] = '_';
+		g_snprintf(nick + len + 1, 3, "%2x", rand());
+	}
+}
+
 void nick_dedupe(bee_user_t *bu, char nick[MAX_NICK_LENGTH + 1])
 {
@@ -224,15 +240,6 @@
 	while (!nick_ok(irc, nick) ||
 	       ((iu = irc_user_by_name(irc, nick)) && iu->bu != bu)) {
-		if (strlen(nick) < (MAX_NICK_LENGTH - 1)) {
-			nick[strlen(nick) + 1] = 0;
-			nick[strlen(nick)] = '_';
-		} else {
-			/* We've got no more space for underscores,
-			   so truncate it and replace the last three
-			   chars with a random "_XX" suffix */
-			int len = truncate_utf8(nick, MAX_NICK_LENGTH - 3);
-			nick[len] = '_';
-			g_snprintf(nick + len + 1, 3, "%2x", rand());
-		}
+
+		underscore_dedupe(nick);
 
 		if (inf_protection-- == 0) {
Index: nick.h
===================================================================
--- nick.h	(revision c0e4c22e4a6b79f044885ebf6524cc43720bc9fc)
+++ nick.h	(revision 830864dc35395ec3a580a8d465f80506e8b00040)
@@ -28,4 +28,5 @@
 char *nick_get(bee_user_t *bu);
 char *nick_gen(bee_user_t *bu);
+void underscore_dedupe(char nick[MAX_NICK_LENGTH + 1]);
 void nick_dedupe(bee_user_t * bu, char nick[MAX_NICK_LENGTH + 1]);
 int nick_saved(bee_user_t *bu);
Index: protocols/bee.h
===================================================================
--- protocols/bee.h	(revision c0e4c22e4a6b79f044885ebf6524cc43720bc9fc)
+++ protocols/bee.h	(revision 830864dc35395ec3a580a8d465f80506e8b00040)
@@ -115,4 +115,6 @@
 	gboolean (*chat_new)(bee_t *bee, struct groupchat *c);
 	gboolean (*chat_free)(bee_t *bee, struct groupchat *c);
+	gboolean (*chat_placeholder_new)(bee_t *bee, struct im_connection *ic, const char *handle,
+	                                 const char *name, const char *topic);
 	/* System messages of any kind. */
 	gboolean (*chat_log)(bee_t *bee, struct groupchat *c, const char *text);
@@ -165,4 +167,6 @@
  *   user, too. */
 G_MODULE_EXPORT struct groupchat *imcb_chat_new(struct im_connection *ic, const char *handle);
+G_MODULE_EXPORT void imcb_chat_placeholder_new(struct im_connection *ic, const char *handle, const char *name,
+                                               const char *topic);
 G_MODULE_EXPORT void imcb_chat_name_hint(struct groupchat *c, const char *name);
 G_MODULE_EXPORT void imcb_chat_free(struct groupchat *c);
Index: protocols/bee_chat.c
===================================================================
--- protocols/bee_chat.c	(revision c0e4c22e4a6b79f044885ebf6524cc43720bc9fc)
+++ protocols/bee_chat.c	(revision 830864dc35395ec3a580a8d465f80506e8b00040)
@@ -54,4 +54,13 @@
 }
 
+void imcb_chat_placeholder_new(struct im_connection *ic, const char *handle, const char *name, const char *topic)
+{
+	bee_t *bee = ic->bee;
+
+	if (bee->ui->chat_placeholder_new) {
+		bee->ui->chat_placeholder_new(bee, ic, handle, name, topic);
+	}
+}
+
 void imcb_chat_name_hint(struct groupchat *c, const char *name)
 {
Index: protocols/jabber/hipchat.c
===================================================================
--- protocols/jabber/hipchat.c	(revision c0e4c22e4a6b79f044885ebf6524cc43720bc9fc)
+++ protocols/jabber/hipchat.c	(revision 830864dc35395ec3a580a8d465f80506e8b00040)
@@ -132,8 +132,5 @@
 	while ((c = xt_find_node(c, "item"))) {
 		struct xt_node *c2;
-		struct groupchat *gc;
-		struct irc_channel *ircc;
 		char *topic = NULL;
-		gboolean new_room = FALSE;
 		char *jid = xt_find_attr(c, "jid");
 		char *name = xt_find_attr(c, "name");
@@ -146,23 +143,5 @@
 		}
 
-		gc = bee_chat_by_title(ic->bee, ic, jid);
-		if (!gc) {
-			gc = imcb_chat_new(ic, jid);
-			new_room = TRUE;
-		}
-		imcb_chat_name_hint(gc, name);
-		imcb_chat_topic(gc, NULL, topic, 0);
-
-		ircc = gc->ui_data;
-		set_setstr(&ircc->set, "account", ic->acc->tag);
-		set_setstr(&ircc->set, "room", jid);
-		set_setstr(&ircc->set, "chat_type", "room");
-
-		if (new_room) {
-			/* This cleans everything but leaves the irc channel around,
-			 * since it just graduated to a room.*/
-			imcb_chat_free(gc);
-		}
-
+		imcb_chat_placeholder_new(ic, jid, name, topic);
 		c = c->next;
 	}
