diff options
author | dequis <dx@dxzone.com.ar> | 2015-11-23 14:49:09 -0300 |
---|---|---|
committer | dequis <dx@dxzone.com.ar> | 2015-11-23 14:49:09 -0300 |
commit | 9c8dbc75d416c8867be20ccf3732303163e620ce (patch) | |
tree | a714f5af6ca4a17db97981036c0f79ae5ffda7fd | |
parent | c34247d0b3111f16dae1a52d831df0d61c03ee35 (diff) |
hipchat: 'chat add hipchat "channel name"' now tries to guess the JID
It's basically prepending the organization id, appending the default MUC
host from the success packet, and generating a slug based on the name
for the middle part, which is replacing a few characters with
underscores and doing a unicode aware lowercasing.
Includes tests, which are useless other than validating the initial
implementation with the test vectors that i already tested manually.
Guaranteed to detect zero breakages in the future. Good test code.
-rw-r--r-- | protocols/jabber/hipchat.c | 50 | ||||
-rw-r--r-- | protocols/jabber/jabber.c | 13 | ||||
-rw-r--r-- | protocols/jabber/jabber.h | 4 | ||||
-rw-r--r-- | tests/check_jabber_util.c | 20 |
4 files changed, 87 insertions, 0 deletions
diff --git a/protocols/jabber/hipchat.c b/protocols/jabber/hipchat.c index 66675885..49e7c895 100644 --- a/protocols/jabber/hipchat.c +++ b/protocols/jabber/hipchat.c @@ -42,6 +42,8 @@ xt_status hipchat_handle_success(struct im_connection *ic, struct xt_node *node) *sep = '/'; } + jd->muc_host = g_strdup(xt_find_attr(node, "muc_host")); + /* Hipchat's auth doesn't expect a restart here */ jd->flags &= ~JFLAG_STREAM_RESTART; @@ -91,3 +93,51 @@ xt_status jabber_parse_hipchat_profile(struct im_connection *ic, struct xt_node return XT_HANDLED; } + +/* Returns a newly allocated string that tries to match the "slug" part of the JID using an + * approximation of the method used by the server. This might fail in some rare conditions + * (old JIDs generated a different way, locale settings unicode, etc) */ +char *hipchat_make_channel_slug(const char *name) +{ + char *lower; + char *new = g_malloc(strlen(name) + 1); + int i = 0; + + do { + if (*name == ' ') { + new[i++] = '_'; + } else if (*name && !strchr("\"&'/:<>@", *name)) { + new[i++] = *name; + } + } while (*(name++)); + + new[i] = '\0'; + + lower = g_utf8_strdown(new, -1); + g_free(new); + + return lower; +} + +char *hipchat_guess_channel_name(struct im_connection *ic, const char *name) +{ + struct jabber_data *jd = ic->proto_data; + char *slug, *retval, *underscore; + + if (!(underscore = strchr(jd->username, '_')) || !jd->muc_host) { + return NULL; + } + + slug = hipchat_make_channel_slug(name); + + /* Get the organization ID from the username, before the underscore */ + *underscore = '\0'; + + retval = g_strdup_printf("%s_%s@%s", jd->username, slug, jd->muc_host); + + *underscore = '_'; + + g_free(slug); + + return retval; +} diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 35cf0c90..ddf4f2d3 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -370,6 +370,7 @@ static void jabber_logout(struct im_connection *ic) g_free(jd->away_message); g_free(jd->internal_jid); g_free(jd->gmail_tid); + g_free(jd->muc_host); g_free(jd->username); g_free(jd->me); g_free(jd); @@ -532,12 +533,24 @@ static struct groupchat *jabber_chat_join_(struct im_connection *ic, const char final_nick = (char *) nick; } + if (jd->flags & JFLAG_HIPCHAT && jd->muc_host && !g_str_has_suffix(room, jd->muc_host)) { + char *guessed_name = hipchat_guess_channel_name(ic, room); + if (guessed_name) { + set_setstr(sets, "room", guessed_name); + g_free(guessed_name); + + /* call this same function again with the fixed name */ + return jabber_chat_join_(ic, set_getstr(sets, "room"), nick, password, sets); + } + } + if (strchr(room, '@') == NULL) { imcb_error(ic, "%s is not a valid Jabber room name. Maybe you mean %s@conference.%s?", room, room, jd->server); } else if (jabber_chat_by_jid(ic, room)) { imcb_error(ic, "Already present in chat `%s'", room); } else { + /* jabber_chat_join without the underscore is the conference.c one */ return jabber_chat_join(ic, room, final_nick, set_getstr(sets, "password")); } diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h index 75bd123f..b50e0cb5 100644 --- a/protocols/jabber/jabber.h +++ b/protocols/jabber/jabber.h @@ -112,6 +112,8 @@ struct jabber_data { GSList *filetransfers; GSList *streamhosts; int have_streamhosts; + + char *muc_host; }; struct jabber_away_state { @@ -357,5 +359,7 @@ void jabber_chat_invite(struct groupchat *c, char *who, char *message); 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); +char *hipchat_make_channel_slug(const char *name); +char *hipchat_guess_channel_name(struct im_connection *ic, const char *name); #endif diff --git a/tests/check_jabber_util.c b/tests/check_jabber_util.c index 1a574ec2..1ffea011 100644 --- a/tests/check_jabber_util.c +++ b/tests/check_jabber_util.c @@ -104,6 +104,25 @@ static void check_compareJID(int l) fail_if(jabber_compare_jid("", "bugtest@google.com/A")); } +static void check_hipchat_slug(int l) +{ + int i; + + const char *tests[] = { + "test !\"#$%&\'()*+,-./0123456789:;<=>?@ABC", "test_!#$%\()*+,-.0123456789;=?abc", + "test XYZ[\\]^_`abc", "test_xyz[\\]^_`abc", + "test {|}~¡¢£¤¥¦§¨©ª«¬\xad®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆ", "test_{|}~¡¢£¤¥¦§¨©ª«¬\xad®¯°±²³´µ¶·¸¹º»¼½¾¿àáâãäåæ", + "test IJ ij I ı I ı", "test_ij_ij_i_ı_i_ı", + NULL, + }; + + for (i = 0; tests[i]; i += 2) { + char *new = hipchat_make_channel_slug(tests[i]); + fail_unless(!strcmp(tests[i + 1], new)); + g_free(new); + } +} + Suite *jabber_util_suite(void) { Suite *s = suite_create("jabber/util"); @@ -120,5 +139,6 @@ Suite *jabber_util_suite(void) suite_add_tcase(s, tc_core); tcase_add_test(tc_core, check_buddy_add); tcase_add_test(tc_core, check_compareJID); + tcase_add_test(tc_core, check_hipchat_slug); return s; } |