Index: protocols/account.c
===================================================================
--- protocols/account.c	(revision 2dd23da38926e777c1dba707350b2afcf9421b25)
+++ protocols/account.c	(revision fc650a8e92764ee66c7dab2737ddba43bdff0a15)
@@ -83,11 +83,4 @@
 		} else {
 			strcpy(tag, "aim");
-		}
-	} else if (strcmp(prpl->name, "jabber") == 0) {
-		if (strstr(a->user, "@gmail.com") ||
-		    strstr(a->user, "@googlemail.com")) {
-			strcpy(tag, "gtalk");
-		} else if (strstr(a->user, "@chat.facebook.com")) {
-			strcpy(tag, "fb");
 		}
 	}
Index: protocols/jabber/Makefile
===================================================================
--- protocols/jabber/Makefile	(revision 2dd23da38926e777c1dba707350b2afcf9421b25)
+++ protocols/jabber/Makefile	(revision fc650a8e92764ee66c7dab2737ddba43bdff0a15)
@@ -13,5 +13,5 @@
 
 # [SH] Program variables
-objects = conference.o io.o iq.o jabber.o jabber_util.o message.o presence.o s5bytestream.o sasl.o si.o
+objects = conference.o io.o iq.o jabber.o jabber_util.o message.o presence.o s5bytestream.o sasl.o si.o hipchat.o
 
 LFLAGS += -r
Index: protocols/jabber/conference.c
===================================================================
--- protocols/jabber/conference.c	(revision 2dd23da38926e777c1dba707350b2afcf9421b25)
+++ protocols/jabber/conference.c	(revision fc650a8e92764ee66c7dab2737ddba43bdff0a15)
@@ -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 ? 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 = strchr(bud->ext_jid, '/');
-		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 fc650a8e92764ee66c7dab2737ddba43bdff0a15)
+++ protocols/jabber/hipchat.c	(revision fc650a8e92764ee66c7dab2737ddba43bdff0a15)
@@ -0,0 +1,181 @@
+/***************************************************************************\
+*                                                                           *
+*  BitlBee - An IRC to IM gateway                                           *
+*  Jabber module - HipChat specific functions                               *
+*                                                                           *
+*  Copyright 2015 Xamarin Inc                                               *
+*                                                                           *
+*  This program is free software; you can redistribute it and/or modify     *
+*  it under the terms of the GNU General Public License as published by     *
+*  the Free Software Foundation; either version 2 of the License, or        *
+*  (at your option) any later version.                                      *
+*                                                                           *
+*  This program is distributed in the hope that it will be useful,          *
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
+*  GNU General Public License for more details.                             *
+*                                                                           *
+*  You should have received a copy of the GNU General Public License along  *
+*  with this program; if not, write to the Free Software Foundation, Inc.,  *
+*  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.              *
+*                                                                           *
+\***************************************************************************/
+
+#include "jabber.h"
+
+xt_status hipchat_handle_success(struct im_connection *ic, struct xt_node *node)
+{
+	struct jabber_data *jd = ic->proto_data;
+	char *sep, *jid, *muc_host;
+
+	jid = xt_find_attr(node, "jid");
+	muc_host = xt_find_attr(node, "muc_host");
+
+	sep = strchr(jid, '/');
+	if (sep) {
+		*sep = '\0';
+	}
+
+	jabber_set_me(ic, jid);
+	imcb_log(ic, "Setting Hipchat JID to %s", jid);
+
+	if (sep) {
+		*sep = '/';
+	}
+
+	/* Hipchat's auth doesn't expect a restart here */
+	jd->flags &= ~JFLAG_STREAM_RESTART;
+
+	if (!jabber_get_roster(ic)) {
+		return XT_ABORT;
+	}
+	if (!jabber_iq_disco_server(ic)) {
+		return XT_ABORT;
+	}
+	if (!jabber_get_hipchat_profile(ic)) {
+		return XT_ABORT;
+	}
+	if (!jabber_iq_disco_muc(ic, muc_host)) {
+		return XT_ABORT;
+	}
+
+	return XT_HANDLED;
+}
+
+int jabber_get_hipchat_profile(struct im_connection *ic)
+{
+	struct jabber_data *jd = ic->proto_data;
+	struct xt_node *node;
+	int st;
+
+	imcb_log(ic, "Fetching hipchat profile for %s", jd->me);
+
+	node = xt_new_node("query", NULL, NULL);
+	xt_add_attr(node, "xmlns", XMLNS_HIPCHAT_PROFILE);
+	node = jabber_make_packet("iq", "get", jd->me, node);
+
+	jabber_cache_add(ic, node, jabber_parse_hipchat_profile);
+	st = jabber_write_packet(ic, node);
+
+	return st;
+}
+
+xt_status jabber_parse_hipchat_profile(struct im_connection *ic, struct xt_node *node, struct xt_node *orig)
+{
+	struct xt_node *query, *name_node;
+
+	//char *name;
+
+	if (!(query = xt_find_node(node->children, "query"))) {
+		imcb_log(ic, "Warning: Received NULL profile packet");
+		return XT_ABORT;
+	}
+
+	name_node = xt_find_node(query->children, "name");
+	if (!name_node) {
+		imcb_log(ic, "Warning: Can't find real name in profile. Joining groupchats will not be possible.");
+		return XT_ABORT;
+	}
+
+	set_setstr(&ic->acc->set, "display_name", name_node->text);
+	return XT_HANDLED;
+
+}
+
+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;
+		struct groupchat *gc;
+		struct irc_channel *ircc;
+		//char *participants = NULL;
+		char *topic = NULL;
+		gboolean new_room = FALSE;
+		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);
+
+		c2 = xt_find_node_by_attr(c->children, "x", "xmlns", XMLNS_HIPCHAT_MUC);
+
+		if (c2) {
+			struct xt_node *node;
+			/*
+			if ( ( node = xt_find_node( c2->children, "num_participants" ) ) ) {
+			        participants = node->text;
+			}
+			*/
+			if ((node = xt_find_node(c2->children, "topic"))) {
+				topic = node->text;
+			}
+		}
+
+		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);
+		}
+
+		c = c->next;
+	}
+	return XT_HANDLED;
+
+}
Index: protocols/jabber/iq.c
===================================================================
--- protocols/jabber/iq.c	(revision 2dd23da38926e777c1dba707350b2afcf9421b25)
+++ protocols/jabber/iq.c	(revision fc650a8e92764ee66c7dab2737ddba43bdff0a15)
@@ -27,5 +27,4 @@
 static xt_status jabber_parse_roster(struct im_connection *ic, struct xt_node *node, struct xt_node *orig);
 static xt_status jabber_iq_display_vcard(struct im_connection *ic, struct xt_node *node, struct xt_node *orig);
-static int jabber_iq_disco_server(struct im_connection *ic);
 
 xt_status jabber_pkt_iq(struct xt_node *node, gpointer data)
@@ -388,4 +387,6 @@
 		char *name = xt_find_attr(c, "name");
 		char *sub = xt_find_attr(c, "subscription");
+		char *mention_name = xt_find_attr(c, "mention_name");
+		char *nick = mention_name ? : name;
 
 		if (jid && sub) {
@@ -396,4 +397,8 @@
 				if (name) {
 					imcb_rename_buddy(ic, jid, name);
+				}
+
+				if (nick) {
+					imcb_buddy_nick_hint(ic, jid, nick);
 				}
 			} else if (strcmp(sub, "remove") == 0) {
@@ -855,5 +860,5 @@
                                                  struct xt_node *node, struct xt_node *orig);
 
-static int jabber_iq_disco_server(struct im_connection *ic)
+int jabber_iq_disco_server(struct im_connection *ic)
 {
 	struct xt_node *node, *iq;
Index: protocols/jabber/jabber.c
===================================================================
--- protocols/jabber/jabber.c	(revision 2dd23da38926e777c1dba707350b2afcf9421b25)
+++ protocols/jabber/jabber.c	(revision fc650a8e92764ee66c7dab2737ddba43bdff0a15)
@@ -54,14 +54,25 @@
 };
 
+static jabber_subproto_desc_t jabber_subproto_list[] = {
+	{ "jabber", JSUB_NONE, NULL, NULL },
+	{ "gtalk", JSUB_GTALK, &oauth2_service_google, "talk.google.com" },
+	{ "fb", JSUB_FACEBOOK, &oauth2_service_facebook, "chat.facebook.com" },
+	{ "hipchat", JSUB_HIPCHAT, NULL, "chat.hipchat.com" },
+	{ NULL },
+};
+
 static void jabber_init(account_t *acc)
 {
 	set_t *s;
 	char str[16];
+	jabber_subproto_desc_t *subproto = acc->prpl->data;
 
 	s = set_add(&acc->set, "activity_timeout", "600", set_eval_int, acc);
 
-	s = set_add(&acc->set, "oauth", "false", set_eval_oauth, acc);
-
 	s = set_add(&acc->set, "display_name", NULL, NULL, acc);
+
+	if (subproto->oauth2_service) {
+		s = set_add(&acc->set, "oauth", "false", set_eval_oauth, acc);
+	}
 
 	g_snprintf(str, sizeof(str), "%d", jabber_port_list[0]);
@@ -100,4 +111,8 @@
 	acc->flags |= ACC_FLAG_AWAY_MESSAGE | ACC_FLAG_STATUS_MESSAGE |
 	              ACC_FLAG_HANDLE_DOMAINS;
+
+	if (subproto->server) {
+		set_setstr(&acc->set, "server", (char *) subproto->server);
+	}
 }
 
@@ -108,4 +123,5 @@
 	struct im_connection *ic = imcb_new(acc);
 	struct jabber_data *jd = g_new0(struct jabber_data, 1);
+	jabber_subproto_desc_t *subproto = acc->prpl->data;
 	char *s;
 
@@ -117,4 +133,5 @@
 	jd->ic = ic;
 	ic->proto_data = jd;
+	jd->subproto = subproto->id;
 
 	jabber_set_me(ic, acc->user);
@@ -141,5 +158,5 @@
 	jd->buddies = g_hash_table_new(g_str_hash, g_str_equal);
 
-	if (set_getbool(&acc->set, "oauth")) {
+	if (subproto->oauth2_service && set_getbool(&acc->set, "oauth")) {
 		GSList *p_in = NULL;
 		const char *tok;
@@ -147,9 +164,5 @@
 		jd->fd = jd->r_inpa = jd->w_inpa = -1;
 
-		if (strstr(jd->server, ".facebook.com")) {
-			jd->oauth2_service = &oauth2_service_facebook;
-		} else {
-			jd->oauth2_service = &oauth2_service_google;
-		}
+		jd->oauth2_service = subproto->oauth2_service;
 
 		oauth_params_parse(&p_in, ic->acc->pass);
@@ -655,34 +668,40 @@
 void jabber_initmodule()
 {
-	struct prpl *ret = g_new0(struct prpl, 1);
-
-	ret->name = "jabber";
-	ret->mms = 0;                        /* no limit */
-	ret->login = jabber_login;
-	ret->init = jabber_init;
-	ret->logout = jabber_logout;
-	ret->buddy_msg = jabber_buddy_msg;
-	ret->away_states = jabber_away_states;
-	ret->set_away = jabber_set_away;
-//	ret->set_info = jabber_set_info;
-	ret->get_info = jabber_get_info;
-	ret->add_buddy = jabber_add_buddy;
-	ret->remove_buddy = jabber_remove_buddy;
-	ret->chat_msg = jabber_chat_msg_;
-	ret->chat_topic = jabber_chat_topic_;
-	ret->chat_invite = jabber_chat_invite_;
-	ret->chat_leave = jabber_chat_leave_;
-	ret->chat_join = jabber_chat_join_;
-	ret->chat_with = jabber_chat_with_;
-	ret->chat_add_settings = jabber_chat_add_settings;
-	ret->chat_free_settings = jabber_chat_free_settings;
-	ret->keepalive = jabber_keepalive;
-	ret->send_typing = jabber_send_typing;
-	ret->handle_cmp = g_strcasecmp;
-	ret->handle_is_self = jabber_handle_is_self;
-	ret->transfer_request = jabber_si_transfer_request;
-	ret->buddy_action_list = jabber_buddy_action_list;
-	ret->buddy_action = jabber_buddy_action;
-
-	register_protocol(ret);
-}
+	int i;
+	struct prpl funcs;
+
+	memset(&funcs, 0, sizeof(funcs));
+
+	funcs.mms = 0;                        /* no limit */
+	funcs.login = jabber_login;
+	funcs.init = jabber_init;
+	funcs.logout = jabber_logout;
+	funcs.buddy_msg = jabber_buddy_msg;
+	funcs.away_states = jabber_away_states;
+	funcs.set_away = jabber_set_away;
+	funcs.get_info = jabber_get_info;
+	funcs.add_buddy = jabber_add_buddy;
+	funcs.remove_buddy = jabber_remove_buddy;
+	funcs.chat_msg = jabber_chat_msg_;
+	funcs.chat_topic = jabber_chat_topic_;
+	funcs.chat_invite = jabber_chat_invite_;
+	funcs.chat_leave = jabber_chat_leave_;
+	funcs.chat_join = jabber_chat_join_;
+	funcs.chat_with = jabber_chat_with_;
+	funcs.chat_add_settings = jabber_chat_add_settings;
+	funcs.chat_free_settings = jabber_chat_free_settings;
+	funcs.keepalive = jabber_keepalive;
+	funcs.send_typing = jabber_send_typing;
+	funcs.handle_cmp = g_strcasecmp;
+	funcs.handle_is_self = jabber_handle_is_self;
+	funcs.transfer_request = jabber_si_transfer_request;
+	funcs.buddy_action_list = jabber_buddy_action_list;
+	funcs.buddy_action = jabber_buddy_action;
+
+	for (i = 0; jabber_subproto_list[i].name; i++) {
+		struct prpl *subproto = g_memdup(&funcs, sizeof(funcs));
+		subproto->name = jabber_subproto_list[i].name;
+		subproto->data = &jabber_subproto_list[i];
+		register_protocol(subproto);
+	}
+}
Index: protocols/jabber/jabber.h
===================================================================
--- protocols/jabber/jabber.h	(revision 2dd23da38926e777c1dba707350b2afcf9421b25)
+++ protocols/jabber/jabber.h	(revision fc650a8e92764ee66c7dab2737ddba43bdff0a15)
@@ -77,4 +77,18 @@
 } jabber_chat_flags_t;
 
+typedef enum {
+	JSUB_NONE = 0,
+	JSUB_GTALK,
+	JSUB_FACEBOOK,
+	JSUB_HIPCHAT,
+} jabber_subproto_t;
+
+typedef struct {
+	const char *name;
+	jabber_subproto_t id;
+	const struct oauth2_service *oauth2_service;
+	const char *server;
+} jabber_subproto_desc_t;
+
 struct jabber_data {
 	struct im_connection *ic;
@@ -88,4 +102,5 @@
 	struct xt_parser *xt;
 	jabber_flags_t flags;
+	jabber_subproto_t subproto;
 
 	char *username;         /* USERNAME@server */
@@ -235,4 +250,9 @@
 #define XMLNS_IBB          "http://jabber.org/protocol/ibb"                      /* XEP-0047 */
 
+/* Hipchat protocol extensions*/
+#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 */
 void jabber_connect(struct im_connection *ic);
@@ -244,4 +264,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);
@@ -249,4 +270,5 @@
 xt_status jabber_iq_query_server(struct im_connection *ic, char *jid, char *xmlns);
 void jabber_iq_version_send(struct im_connection *ic, struct jabber_buddy *bud, void *data);
+int jabber_iq_disco_server(struct im_connection *ic);
 
 /* si.c */
@@ -306,4 +328,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[];
@@ -341,3 +364,9 @@
 void jabber_chat_invite(struct groupchat *c, char *who, char *message);
 
+/* hipchat.c */
+int jabber_get_hipchat_profile(struct im_connection *ic);
+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 2dd23da38926e777c1dba707350b2afcf9421b25)
+++ protocols/jabber/jabber_util.c	(revision fc650a8e92764ee66c7dab2737ddba43bdff0a15)
@@ -819,2 +819,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);
+	}
+}
Index: protocols/jabber/sasl.c
===================================================================
--- protocols/jabber/sasl.c	(revision 2dd23da38926e777c1dba707350b2afcf9421b25)
+++ protocols/jabber/sasl.c	(revision fc650a8e92764ee66c7dab2737ddba43bdff0a15)
@@ -55,5 +55,5 @@
 	char *s;
 	int sup_plain = 0, sup_digest = 0, sup_gtalk = 0, sup_fb = 0;
-	int want_oauth = FALSE;
+	int want_oauth = FALSE, want_hipchat = FALSE;
 	GString *mechs;
 
@@ -75,4 +75,5 @@
 
 	want_oauth = set_getbool(&ic->acc->set, "oauth");
+	want_hipchat = (jd->subproto == JSUB_HIPCHAT);
 
 	mechs = g_string_new("");
@@ -111,5 +112,9 @@
 
 	reply = xt_new_node("auth", NULL, NULL);
-	xt_add_attr(reply, "xmlns", XMLNS_SASL);
+	if (!want_hipchat) {
+		xt_add_attr(reply, "xmlns", XMLNS_SASL);
+	} else {
+		xt_add_attr(reply, "xmlns", XMLNS_HIPCHAT);
+	}
 
 	if (sup_gtalk && want_oauth) {
@@ -143,13 +148,31 @@
 	} else if (sup_plain) {
 		int len;
-
-		xt_add_attr(reply, "mechanism", "PLAIN");
+		GString *gs;
+		char *username;
+
+		if (!want_hipchat) {
+			xt_add_attr(reply, "mechanism", "PLAIN");
+			username = jd->username;
+		} else {
+			username = jd->me;
+		}
+
+		/* set an arbitrary initial size to avoid reallocations */
+		gs = g_string_sized_new(128);
 
 		/* With SASL PLAIN in XMPP, the text should be b64(\0user\0pass) */
-		len = strlen(jd->username) + strlen(ic->acc->pass) + 2;
-		s = g_malloc(len + 1);
-		s[0] = 0;
-		strcpy(s + 1, jd->username);
-		strcpy(s + 2 + strlen(jd->username), ic->acc->pass);
+		g_string_append_c(gs, '\0');
+		g_string_append(gs, username);
+		g_string_append_c(gs, '\0');
+		g_string_append(gs, ic->acc->pass);
+		if (want_hipchat) {
+			/* Hipchat's variation adds \0resource at the end */
+			g_string_append_c(gs, '\0');
+			g_string_append(gs, set_getstr(&ic->acc->set, "resource"));
+		}
+
+		len = gs->len;
+		s = g_string_free(gs, FALSE);
+
 		reply->text = base64_encode((unsigned char *) s, len);
 		reply->text_len = strlen(reply->text);
@@ -397,4 +420,8 @@
 		imcb_log(ic, "Authentication finished");
 		jd->flags |= JFLAG_AUTHENTICATED | JFLAG_STREAM_RESTART;
+
+		if (jd->subproto == JSUB_HIPCHAT) {
+			return hipchat_handle_success(ic, node);
+		}
 	} else if (strcmp(node->name, "failure") == 0) {
 		imcb_error(ic, "Authentication failure");
