about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorJames Booth <boothj5@gmail.com>2013-01-26 16:13:11 +0000
committerJames Booth <boothj5@gmail.com>2013-01-26 16:13:11 +0000
commitd239a1278b4c5761cc08f0514e411b1594c6ed23 (patch)
treeb125dc3fd2759ec3a5545811ab0534c7987950e3
parent527e739ac6962627ad6b5c76fa08357e33b6da0e (diff)
downloadprofani-tty-d239a1278b4c5761cc08f0514e411b1594c6ed23.tar.gz
Fixed jid handling to allow @ and / in resource
-rw-r--r--src/jid.c99
-rw-r--r--tests/test_jid.c48
2 files changed, 93 insertions, 54 deletions
diff --git a/src/jid.c b/src/jid.c
index 66a066dd..1798c987 100644
--- a/src/jid.c
+++ b/src/jid.c
@@ -36,70 +36,59 @@ jid_create(const gchar * const str)
     if (str == NULL) {
         return NULL;
     }
-    if (strlen(str) == 0) {
-        return NULL;
-    }
 
     gchar *trimmed = g_strdup(str);
 
-    if (g_str_has_prefix(trimmed, "/") || g_str_has_prefix(trimmed, "@")) {
-        g_free(trimmed);
+    if (strlen(trimmed) == 0) {
         return NULL;
-    } else if (g_str_has_suffix(trimmed, "/") || g_str_has_suffix(trimmed, "@")) {
+    }
+
+    if (g_str_has_prefix(trimmed, "/") || g_str_has_prefix(trimmed, "@")) {
         g_free(trimmed);
         return NULL;
     }
 
-    gchar *slashp = g_strrstr(trimmed, "/");
-
-    // has resourcepart
-    if (slashp != NULL) {
-        result = malloc(sizeof(struct jid_t));
-        result->str = strdup(trimmed);
-        result->resourcepart = g_strdup(slashp + 1);
-        result->barejid = g_strndup(trimmed, strlen(trimmed) - strlen(result->resourcepart) - 1);
-        result->fulljid = g_strdup(trimmed);
+    if (!g_utf8_validate(trimmed, -1, NULL)) {
+        return NULL;
+    }
 
-        gchar *atp = g_strrstr(result->barejid, "@");
+    result = malloc(sizeof(struct jid_t));
+    result->localpart = NULL;
+    result->domainpart = NULL;
+    result->resourcepart = NULL;
+    result->barejid = NULL;
+    result->fulljid = NULL;
 
-        // has domain and local parts
-        if (atp != NULL) {
-            result->domainpart = g_strndup(atp + 1, strlen(trimmed));
-            result->localpart = g_strndup(trimmed, strlen(trimmed) - (strlen(result->resourcepart) + strlen(result->domainpart) + 2));
+    gchar *atp = g_utf8_strchr(trimmed, -1, '@');
+    gchar *slashp = g_utf8_strchr(trimmed, -1, '/');
+    gchar *domain_start = trimmed;
 
-        // only domain part
-        } else {
-            result->domainpart = strdup(result->barejid);
-            result->localpart = NULL;
-        }
 
-        g_free(trimmed);
-        return result;
+    if (atp != NULL) {
+        result->localpart = g_utf8_substring(trimmed, 0, g_utf8_pointer_to_offset(trimmed, atp));
+        domain_start = atp + 1;
+    }
 
-    // no resourcepart
+    if (slashp != NULL) {
+        result->resourcepart = g_strdup(slashp + 1);
+        result->domainpart = g_utf8_substring(domain_start, 0, g_utf8_pointer_to_offset(domain_start, slashp));
+        result->barejid = g_utf8_substring(trimmed, 0, g_utf8_pointer_to_offset(trimmed, slashp));
+        result->fulljid = g_strdup(trimmed);
     } else {
-        result = malloc(sizeof(struct jid_t));
-        result->str = strdup(trimmed);
-        result->resourcepart = NULL;
+        result->domainpart = g_strdup(domain_start);
         result->barejid = g_strdup(trimmed);
-        result->fulljid = NULL;
+    }
 
-        gchar *atp = g_strrstr(trimmed, "@");
+    if (result->domainpart == NULL) {
+        free(trimmed);
+        return NULL;
+    }
 
-        // has local and domain parts
-        if (atp != NULL) {
-            result->domainpart = g_strdup(atp + 1);
-            result->localpart = g_strndup(trimmed, strlen(trimmed) - strlen(result->domainpart) - 1);
+    result->str = g_strdup(trimmed);
 
-        // only domain part
-        } else {
-            result->domainpart = g_strdup(trimmed);
-            result->localpart = NULL;
-        }
+    free(trimmed);
 
-        g_free(trimmed);
-        return result;
-    }
+    return result;
 }
 
 Jid *
@@ -142,21 +131,23 @@ jid_is_valid_room_form(Jid *jid)
 gboolean
 parse_room_jid(const char * const full_room_jid, char **room, char **nick)
 {
-    gboolean result = FALSE;
-    char **tokens = g_strsplit(full_room_jid, "/", 0);
+    Jid *jid = jid_create(full_room_jid);
 
-    if (tokens == NULL)
+    if (jid == NULL) {
         return FALSE;
+    }
 
-    if (tokens[0] != NULL && tokens[1] != NULL) {
-        *room = strdup(tokens[0]);
-        *nick = strdup(tokens[1]);
-        result = TRUE;
+    if (jid->resourcepart == NULL) {
+        jid_destroy(jid);
+        return FALSE;
     }
 
-    g_strfreev(tokens);
+    *room = strdup(jid->barejid);
+    *nick = strdup(jid->resourcepart);
 
-    return result;
+    jid_destroy(jid);
+
+    return TRUE;
 }
 
 /*
diff --git a/tests/test_jid.c b/tests/test_jid.c
index 99ae4f12..ce33909a 100644
--- a/tests/test_jid.c
+++ b/tests/test_jid.c
@@ -119,6 +119,50 @@ void create_room_jid_returns_nick(void)
     assert_string_equals("myname", result->resourcepart);
 }
 
+void create_with_slash_in_resource(void)
+{
+    Jid *result = jid_create("room@conference.domain.org/my/nick");
+
+    assert_string_equals("room", result->localpart);
+    assert_string_equals("conference.domain.org", result->domainpart);
+    assert_string_equals("my/nick", result->resourcepart);
+    assert_string_equals("room@conference.domain.org", result->barejid);
+    assert_string_equals("room@conference.domain.org/my/nick", result->fulljid);
+}
+
+void create_with_at_in_resource(void)
+{
+    Jid *result = jid_create("room@conference.domain.org/my@nick");
+
+    assert_string_equals("room", result->localpart);
+    assert_string_equals("conference.domain.org", result->domainpart);
+    assert_string_equals("my@nick", result->resourcepart);
+    assert_string_equals("room@conference.domain.org", result->barejid);
+    assert_string_equals("room@conference.domain.org/my@nick", result->fulljid);
+}
+
+void create_with_at_and_slash_in_resource(void)
+{
+    Jid *result = jid_create("room@conference.domain.org/my@nick/something");
+
+    assert_string_equals("room", result->localpart);
+    assert_string_equals("conference.domain.org", result->domainpart);
+    assert_string_equals("my@nick/something", result->resourcepart);
+    assert_string_equals("room@conference.domain.org", result->barejid);
+    assert_string_equals("room@conference.domain.org/my@nick/something", result->fulljid);
+}
+
+void create_full_with_trailing_slash(void)
+{
+    Jid *result = jid_create("room@conference.domain.org/nick/");
+
+    assert_string_equals("room", result->localpart);
+    assert_string_equals("conference.domain.org", result->domainpart);
+    assert_string_equals("nick/", result->resourcepart);
+    assert_string_equals("room@conference.domain.org", result->barejid);
+    assert_string_equals("room@conference.domain.org/nick/", result->fulljid);
+}
+
 void register_jid_tests(void)
 {
     TEST_MODULE("jid tests");
@@ -141,4 +185,8 @@ void register_jid_tests(void)
     TEST(create_jid_from_bare_returns_domainpart);
     TEST(create_room_jid_returns_room);
     TEST(create_room_jid_returns_nick);
+    TEST(create_with_slash_in_resource);
+    TEST(create_with_at_in_resource);
+    TEST(create_with_at_and_slash_in_resource);
+    TEST(create_full_with_trailing_slash);
 }