Index: protocols/bee.h
===================================================================
--- protocols/bee.h	(revision 088b07018963158ca822a289f4db7085454f9713)
+++ protocols/bee.h	(revision b8c336b12e7645075a8e642382911d26b9b8e50f)
@@ -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 088b07018963158ca822a289f4db7085454f9713)
+++ protocols/bee_chat.c	(revision b8c336b12e7645075a8e642382911d26b9b8e50f)
@@ -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/conference.c
===================================================================
--- protocols/jabber/conference.c	(revision 088b07018963158ca822a289f4db7085454f9713)
+++ protocols/jabber/conference.c	(revision b8c336b12e7645075a8e642382911d26b9b8e50f)
@@ -354,77 +354,87 @@
 	struct xt_node *subject = xt_find_node(node->children, "subject");
 	struct xt_node *body = xt_find_node(node->children, "body");
-	struct groupchat *chat = bud ? jabber_chat_by_jid(ic, bud->bare_jid) : NULL;
-	struct jabber_chat *jc = chat ? chat->data : NULL;
-	char *s;
+	struct groupchat *chat = NULL;
+	struct jabber_chat *jc = NULL;
+	char *from = NULL;
+	char *nick = NULL;
+	char *final_from = NULL;
+	char *bare_jid = NULL;
+
+	from = (bud) ? bud->full_jid : xt_find_attr(node, "from");
+
+	if (from) {
+		nick = strchr(from, '/');
+		if (nick) {
+			*nick = 0;
+		}
+		chat = jabber_chat_by_jid(ic, from);
+		if (nick) {
+			*nick = '/';
+			nick++;
+		}
+	}
+
+	jc = (chat) ? chat->data : NULL;
+
+	if (!bud) {
+		struct xt_node *c;
+		char *s;
+
+		/* Try some clever stuff to find out the real JID here */
+		c = xt_find_node_by_attr(node->children, "delay", "xmlns", XMLNS_DELAY);
+
+		if (c && ((s = xt_find_attr(c, "from")) ||
+		          (s = xt_find_attr(c, "from_jid")))) {
+			/* This won't be useful if it's the MUC JID */
+			if (!(jc && jabber_compare_jid(s, jc->name))) {
+				/* Hopefully this one makes more sense! */
+				bud = jabber_buddy_by_jid(ic, s, GET_BUDDY_FIRST | GET_BUDDY_CREAT);
+			}
+		}
+
+	}
 
 	if (subject && chat) {
-		s = (bud && bud->ext_jid) ? strchr(bud->ext_jid, '/') : NULL;
-		if (s) {
-			*s = 0;
-		}
-		imcb_chat_topic(chat, bud ? bud->ext_jid : NULL, subject->text_len > 0 ?
-		                subject->text : NULL, jabber_get_timestamp(node));
-		if (s) {
-			*s = '/';
-		}
-	}
-
-	if (bud == NULL || (jc && ~jc->flags & JCFLAG_MESSAGE_SENT && bud == jc->me)) {
-		char *nick;
-
-		if (body == NULL || body->text_len == 0) {
-			/* Meh. Empty messages aren't very interesting, no matter
-			   how much some servers love to send them. */
-			return;
-		}
-
-		s = xt_find_attr(node, "from");   /* pkt_message() already NULL-checked this one. */
-		nick = strchr(s, '/');
-		if (nick) {
-			/* If this message included a resource/nick we don't know,
-			   we might still know the groupchat itself. */
-			*nick = 0;
-			chat = jabber_chat_by_jid(ic, s);
-			*nick = '/';
-
-			nick++;
+		char *subject_text = subject->text_len > 0 ? subject->text : NULL;
+		if (g_strcmp0(chat->topic, subject_text) != 0) {
+			bare_jid = (bud) ? jabber_get_bare_jid(bud->ext_jid) : NULL;
+			imcb_chat_topic(chat, bare_jid, subject_text,
+			                jabber_get_timestamp(node));
+			g_free(bare_jid);
+		}
+	}
+
+	if (body == NULL || body->text_len == 0) {
+		/* Meh. Empty messages aren't very interesting, no matter
+		   how much some servers love to send them. */
+		return;
+	}
+
+	if (chat == NULL) {
+		if (nick == NULL) {
+			imcb_log(ic, "System message from unknown groupchat %s: %s", from, body->text);
 		} else {
-			/* message.c uses the EXACT_JID option, so bud should
-			   always be NULL here for bare JIDs. */
-			chat = jabber_chat_by_jid(ic, s);
-		}
-
-		if (nick == NULL) {
-			/* This is fine, the groupchat itself isn't in jd->buddies. */
-			if (chat) {
-				imcb_chat_log(chat, "From conference server: %s", body->text);
-			} else {
-				imcb_log(ic, "System message from unknown groupchat %s: %s", s, body->text);
-			}
-		} else {
-			/* This can happen too, at least when receiving a backlog when
-			   just joining a channel. */
-			if (chat) {
-				imcb_chat_log(chat, "Message from unknown participant %s: %s", nick, body->text);
-			} else {
-				imcb_log(ic, "Groupchat message from unknown JID %s: %s", s, body->text);
-			}
+			imcb_log(ic, "Groupchat message from unknown JID %s: %s", from, body->text);
 		}
 
 		return;
-	} else if (chat == NULL) {
-		/* How could this happen?? We could do kill( self, 11 )
-		   now or just wait for the OS to do it. :-) */
+	} else if (chat != NULL && bud == NULL && nick == NULL) {
+		imcb_chat_log(chat, "From conference server: %s", body->text);
 		return;
-	}
-	if (body && body->text_len > 0) {
-		s = (bud->ext_jid) ? strchr(bud->ext_jid, '/') : NULL;
-		if (s) {
-			*s = 0;
-		}
-		imcb_chat_msg(chat, bud->ext_jid, body->text, 0, jabber_get_timestamp(node));
-		if (s) {
-			*s = '/';
-		}
-	}
-}
+	} else if (jc && jc->flags & JCFLAG_MESSAGE_SENT && bud == jc->me) {
+		/* exclude self-messages since they would get filtered out
+		 * but not the ones in the backlog */
+		return;
+	}
+
+	if (bud && jc && bud != jc->me) {
+		bare_jid = jabber_get_bare_jid(bud->ext_jid ? bud->ext_jid : bud->full_jid);
+		final_from = bare_jid;
+	} else {
+		final_from = nick;
+	}
+
+	imcb_chat_msg(chat, final_from, body->text, 0, jabber_get_timestamp(node));
+
+	g_free(bare_jid);
+}
Index: protocols/jabber/hipchat.c
===================================================================
--- protocols/jabber/hipchat.c	(revision 088b07018963158ca822a289f4db7085454f9713)
+++ protocols/jabber/hipchat.c	(revision b8c336b12e7645075a8e642382911d26b9b8e50f)
@@ -27,7 +27,8 @@
 {
 	struct jabber_data *jd = ic->proto_data;
-	char *sep, *jid;
+	char *sep, *jid, *muc_host;
 
 	jid = xt_find_attr(node, "jid");
+	muc_host = xt_find_attr(node, "muc_host");
 
 	sep = strchr(jid, '/');
@@ -48,5 +49,6 @@
 	if (!jabber_get_roster(ic) ||
 	    !jabber_iq_disco_server(ic) ||
-	    !jabber_get_hipchat_profile(ic)) {
+	    !jabber_get_hipchat_profile(ic) ||
+            !jabber_iq_disco_muc(ic, muc_host)) {
 		return XT_ABORT;
 	}
@@ -92,2 +94,49 @@
 
 }
+
+int jabber_iq_disco_muc(struct im_connection *ic, char *muc_server)
+{
+	struct xt_node *node;
+	int st;
+
+	imcb_log(ic, "Fetching MUC list");
+
+	node = xt_new_node("query", NULL, NULL);
+	xt_add_attr(node, "xmlns", XMLNS_DISCO_ITEMS);
+	node = jabber_make_packet("iq", "get", muc_server, node);
+
+	jabber_cache_add(ic, node, jabber_parse_muc_list);
+	st = jabber_write_packet(ic, node);
+
+	return st;
+}
+
+xt_status jabber_parse_muc_list(struct im_connection *ic, struct xt_node *node, struct xt_node *orig)
+{
+	struct xt_node *query, *c;
+
+	if (!(query = xt_find_node(node->children, "query"))) {
+		imcb_log(ic, "Warning: Received NULL MUC list packet");
+		return XT_HANDLED;
+	}
+
+	c = query->children;
+	while ((c = xt_find_node(c, "item"))) {
+		struct xt_node *c2;
+		char *topic = NULL;
+		char *jid = xt_find_attr(c, "jid");
+		char *name = xt_find_attr(c, "name");
+
+		imcb_log(ic, "Debug: adding MUC to channel list: %s - '%s'", jid, name);
+
+		if ((c2 = xt_find_node_by_attr(c->children, "x", "xmlns", XMLNS_HIPCHAT_MUC)) &&
+		    (c2 = xt_find_node(c2->children, "topic"))) {
+			topic = c2->text;
+		}
+
+		imcb_chat_placeholder_new(ic, jid, name, topic);
+		c = c->next;
+	}
+	return XT_HANDLED;
+
+}
Index: protocols/jabber/jabber.h
===================================================================
--- protocols/jabber/jabber.h	(revision 088b07018963158ca822a289f4db7085454f9713)
+++ protocols/jabber/jabber.h	(revision b8c336b12e7645075a8e642382911d26b9b8e50f)
@@ -239,4 +239,5 @@
 #define XMLNS_HIPCHAT         "http://hipchat.com"
 #define XMLNS_HIPCHAT_PROFILE "http://hipchat.com/protocol/profile"
+#define XMLNS_HIPCHAT_MUC     "http://hipchat.com/protocol/muc#room"
 
 /* jabber.c */
@@ -249,4 +250,5 @@
 int jabber_get_roster(struct im_connection *ic);
 int jabber_get_vcard(struct im_connection *ic, char *bare_jid);
+int jabber_iq_disco_muc(struct im_connection *ic, char *muc_server);
 int jabber_add_to_roster(struct im_connection *ic, const char *handle, const char *name, const char *group);
 int jabber_remove_from_roster(struct im_connection *ic, char *handle);
@@ -312,4 +314,5 @@
 void jabber_error_free(struct jabber_error *err);
 gboolean jabber_set_me(struct im_connection *ic, const char *me);
+char *jabber_get_bare_jid(char *jid);
 
 extern const struct jabber_away_state jabber_away_state_list[];
@@ -351,4 +354,5 @@
 xt_status jabber_parse_hipchat_profile(struct im_connection *ic, struct xt_node *node, struct xt_node *orig);
 xt_status hipchat_handle_success(struct im_connection *ic, struct xt_node *node);
+xt_status jabber_parse_muc_list(struct im_connection *ic, struct xt_node *node, struct xt_node *orig);
 
 #endif
Index: protocols/jabber/jabber_util.c
===================================================================
--- protocols/jabber/jabber_util.c	(revision 088b07018963158ca822a289f4db7085454f9713)
+++ protocols/jabber/jabber_util.c	(revision b8c336b12e7645075a8e642382911d26b9b8e50f)
@@ -820,2 +820,18 @@
 	return TRUE;
 }
+
+/* Returns new reference! g_free() afterwards. */
+char *jabber_get_bare_jid(char *jid)
+{
+	char *s = NULL;
+
+	if (jid == NULL) {
+		return NULL;
+	}
+
+	if ((s = strchr(jid, '/'))) {
+		return g_strndup(jid, s - jid);
+	} else {
+		return g_strdup(jid);
+	}
+}
