about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--src/contact.c28
-rw-r--r--src/contact.h6
-rw-r--r--src/muc.c2
-rw-r--r--src/xmpp/roster.c64
-rw-r--r--src/xmpp/roster.h2
-rw-r--r--src/xmpp/stanza.c13
-rw-r--r--src/xmpp/stanza.h3
-rw-r--r--src/xmpp/xmpp.h2
8 files changed, 104 insertions, 16 deletions
diff --git a/src/contact.c b/src/contact.c
index 56202389..009478a0 100644
--- a/src/contact.c
+++ b/src/contact.c
@@ -33,6 +33,7 @@
 struct p_contact_t {
     char *barejid;
     char *name;
+    GSList *groups;
     char *subscription;
     char *offline_message;
     gboolean pending_out;
@@ -42,8 +43,8 @@ struct p_contact_t {
 
 PContact
 p_contact_new(const char * const barejid, const char * const name,
-    const char * const subscription, const char * const offline_message,
-    gboolean pending_out)
+    GSList *groups, const char * const subscription,
+    const char * const offline_message, gboolean pending_out)
 {
     PContact contact = malloc(sizeof(struct p_contact_t));
     contact->barejid = strdup(barejid);
@@ -54,6 +55,8 @@ p_contact_new(const char * const barejid, const char * const name,
         contact->name = NULL;
     }
 
+    contact->groups = groups;
+
     if (subscription != NULL)
         contact->subscription = strdup(subscription);
     else
@@ -87,6 +90,23 @@ p_contact_set_name(const PContact contact, const char * const name)
     }
 }
 
+void
+p_contact_set_groups(const PContact contact, GSList *groups)
+{
+    if (contact->groups != NULL) {
+        g_slist_free_full(contact->groups, g_free);
+        contact->groups = NULL;
+    }
+
+    contact->groups = groups;
+}
+
+GSList *
+p_contact_groups(const PContact contact)
+{
+    return contact->groups;
+}
+
 gboolean
 p_contact_remove_resource(PContact contact, const char * const resource)
 {
@@ -101,6 +121,10 @@ p_contact_free(PContact contact)
     FREE_SET_NULL(contact->subscription);
     FREE_SET_NULL(contact->offline_message);
 
+    if (contact->groups != NULL) {
+        g_slist_free_full(contact->groups, g_free);
+    }
+
     if (contact->last_activity != NULL) {
         g_date_time_unref(contact->last_activity);
     }
diff --git a/src/contact.h b/src/contact.h
index 5915fbbf..3aa8e6a3 100644
--- a/src/contact.h
+++ b/src/contact.h
@@ -28,8 +28,8 @@
 typedef struct p_contact_t *PContact;
 
 PContact p_contact_new(const char * const barejid, const char * const name,
-    const char * const subscription, const char * const offline_message,
-    gboolean pending_out);
+    GSList *groups, const char * const subscription,
+    const char * const offline_message, gboolean pending_out);
 void p_contact_add_resource(PContact contact, Resource *resource);
 gboolean p_contact_remove_resource(PContact contact, const char * const resource);
 void p_contact_free(PContact contact);
@@ -50,5 +50,7 @@ void p_contact_set_last_activity(const PContact contact, GDateTime *last_activit
 gboolean p_contact_is_available(const PContact contact);
 gboolean p_contact_has_available_resource(const PContact contact);
 Resource * p_contact_get_resource(const PContact contact, const char * const resource);
+void p_contact_set_groups(const PContact contact, GSList *groups);
+GSList * p_contact_groups(const PContact contact);
 
 #endif
diff --git a/src/muc.c b/src/muc.c
index 4f308f1d..0e0a879d 100644
--- a/src/muc.c
+++ b/src/muc.c
@@ -288,7 +288,7 @@ muc_add_to_roster(const char * const room, const char * const nick,
                     (g_strcmp0(p_contact_status(old), status) != 0)) {
             updated = TRUE;
         }
-        PContact contact = p_contact_new(nick, NULL, NULL, NULL, FALSE);
+        PContact contact = p_contact_new(nick, NULL, NULL, NULL, NULL, FALSE);
         resource_presence_t resource_presence = resource_presence_from_string(show);
         Resource *resource = resource_new(nick, resource_presence, status, 0, caps_str);
         p_contact_set_presence(contact, resource);
diff --git a/src/xmpp/roster.c b/src/xmpp/roster.c
index 4751bbd9..3aeef34d 100644
--- a/src/xmpp/roster.c
+++ b/src/xmpp/roster.c
@@ -45,6 +45,9 @@ static Autocomplete barejid_ac;
 // fulljids
 static Autocomplete fulljid_ac;
 
+// groups
+static Autocomplete groups_ac;
+
 // contacts, indexed on barejid
 static GHashTable *contacts;
 
@@ -62,6 +65,7 @@ static void _add_name_and_barejid(const char * const name,
     const char * const barejid);
 static void _replace_name(const char * const current_name,
     const char * const new_name, const char * const barejid);
+GSList * _get_groups_from_item(xmpp_stanza_t *item);
 static gboolean _key_equals(void *key1, void *key2);
 static gboolean _datetimes_equal(GDateTime *dt1, GDateTime *dt2);
 
@@ -90,6 +94,7 @@ roster_init(void)
     name_ac = autocomplete_new();
     barejid_ac = autocomplete_new();
     fulljid_ac = autocomplete_new();
+    groups_ac = autocomplete_new();
     contacts = g_hash_table_new_full(g_str_hash, (GEqualFunc)_key_equals, g_free,
         (GDestroyNotify)p_contact_free);
     name_to_barejid = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
@@ -102,6 +107,7 @@ roster_clear(void)
     autocomplete_clear(name_ac);
     autocomplete_clear(barejid_ac);
     autocomplete_clear(fulljid_ac);
+    autocomplete_clear(groups_ac);
     g_hash_table_destroy(contacts);
     contacts = g_hash_table_new_full(g_str_hash, (GEqualFunc)_key_equals, g_free,
         (GDestroyNotify)p_contact_free);
@@ -116,6 +122,7 @@ roster_free()
     autocomplete_free(name_ac);
     autocomplete_free(barejid_ac);
     autocomplete_free(fulljid_ac);
+    autocomplete_free(groups_ac);
 }
 
 void
@@ -124,20 +131,30 @@ roster_reset_search_attempts(void)
     autocomplete_reset(name_ac);
     autocomplete_reset(barejid_ac);
     autocomplete_reset(fulljid_ac);
+    autocomplete_reset(groups_ac);
 }
 
 gboolean
-roster_add(const char * const barejid, const char * const name,
+roster_add(const char * const barejid, const char * const name, GSList *groups,
     const char * const subscription, gboolean pending_out)
 {
     gboolean added = FALSE;
     PContact contact = g_hash_table_lookup(contacts, barejid);
 
     if (contact == NULL) {
-        contact = p_contact_new(barejid, name, subscription, NULL, pending_out);
+        contact = p_contact_new(barejid, name, groups, subscription, NULL,
+            pending_out);
+
+        // add groups
+        while (groups != NULL) {
+            autocomplete_add(groups_ac, strdup(groups->data));
+            groups = g_slist_next(groups);
+        }
+
         g_hash_table_insert(contacts, strdup(barejid), contact);
         autocomplete_add(barejid_ac, strdup(barejid));
         _add_name_and_barejid(name, barejid);
+
         added = TRUE;
     }
 
@@ -146,12 +163,12 @@ roster_add(const char * const barejid, const char * const name,
 
 void
 roster_update(const char * const barejid, const char * const name,
-    const char * const subscription, gboolean pending_out)
+    GSList *groups, const char * const subscription, gboolean pending_out)
 {
     PContact contact = g_hash_table_lookup(contacts, barejid);
 
     if (contact == NULL) {
-        roster_add(barejid, name, subscription, pending_out);
+        roster_add(barejid, name, groups, subscription, pending_out);
     } else {
         p_contact_set_subscription(contact, subscription);
         p_contact_set_pending_out(contact, pending_out);
@@ -163,7 +180,14 @@ roster_update(const char * const barejid, const char * const name,
         }
 
         p_contact_set_name(contact, new_name);
+        p_contact_set_groups(contact, groups);
         _replace_name(current_name, new_name, barejid);
+
+        // add groups
+        while (groups != NULL) {
+            autocomplete_add(groups_ac, strdup(groups->data));
+            groups = g_slist_next(groups);
+        }
     }
 }
 
@@ -225,9 +249,12 @@ roster_change_name(const char * const barejid, const char * const new_name)
         p_contact_set_name(contact, new_name);
         _replace_name(current_name, new_name, barejid);
 
+        GSList *groups = p_contact_groups(contact);
+
         xmpp_conn_t * const conn = connection_get_conn();
         xmpp_ctx_t * const ctx = connection_get_ctx();
-        xmpp_stanza_t *iq = stanza_create_roster_set(ctx, barejid, new_name);
+        xmpp_stanza_t *iq = stanza_create_roster_set(ctx, barejid, new_name,
+            groups);
         xmpp_send(conn, iq);
         xmpp_stanza_release(iq);
     }
@@ -356,8 +383,10 @@ _roster_handle_push(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
             pending_out = TRUE;
         }
 
+        GSList *groups = _get_groups_from_item(item);
+
         // update the local roster
-        roster_update(barejid, name, sub, pending_out);
+        roster_update(barejid, name, groups, sub, pending_out);
     }
 
     return 1;
@@ -389,7 +418,9 @@ _roster_handle_result(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
                 pending_out = TRUE;
             }
 
-            gboolean added = roster_add(barejid, name, sub, pending_out);
+            GSList *groups = _get_groups_from_item(item);
+
+            gboolean added = roster_add(barejid, name, groups, sub, pending_out);
 
             if (!added) {
                 log_warning("Attempt to add contact twice: %s", barejid);
@@ -435,6 +466,25 @@ _replace_name(const char * const current_name, const char * const new_name,
     }
 }
 
+GSList *
+_get_groups_from_item(xmpp_stanza_t *item)
+{
+    GSList *groups = NULL;
+    xmpp_stanza_t *group_element = xmpp_stanza_get_children(item);
+
+    while (group_element != NULL) {
+        if (strcmp(xmpp_stanza_get_name(group_element), STANZA_NAME_GROUP) == 0) {
+            char *groupname = xmpp_stanza_get_text(group_element);
+            if (groupname != NULL) {
+                groups = g_slist_append(groups, groupname);
+            }
+        }
+        group_element = xmpp_stanza_get_next(group_element);
+    }
+
+    return groups;
+}
+
 static
 gboolean _key_equals(void *key1, void *key2)
 {
diff --git a/src/xmpp/roster.h b/src/xmpp/roster.h
index 48f6a330..8aba28f4 100644
--- a/src/xmpp/roster.h
+++ b/src/xmpp/roster.h
@@ -27,6 +27,6 @@ void roster_add_handlers(void);
 void roster_request(void);
 
 void roster_update(const char * const barejid, const char * const name,
-    const char * const subscription, gboolean pending_out);
+    GSList *groups, const char * const subscription, gboolean pending_out);
 
 #endif
diff --git a/src/xmpp/stanza.c b/src/xmpp/stanza.c
index 722fe4dd..78d85c18 100644
--- a/src/xmpp/stanza.c
+++ b/src/xmpp/stanza.c
@@ -91,7 +91,7 @@ stanza_create_message(xmpp_ctx_t *ctx, const char * const recipient,
 
 xmpp_stanza_t *
 stanza_create_roster_set(xmpp_ctx_t *ctx, const char * const jid,
-    const char * const handle)
+    const char * const handle, GSList *groups)
 {
     xmpp_stanza_t *iq = xmpp_stanza_new(ctx);
     xmpp_stanza_set_name(iq, STANZA_NAME_IQ);
@@ -104,12 +104,23 @@ stanza_create_roster_set(xmpp_ctx_t *ctx, const char * const jid,
     xmpp_stanza_t *item = xmpp_stanza_new(ctx);
     xmpp_stanza_set_name(item, STANZA_NAME_ITEM);
     xmpp_stanza_set_attribute(item, STANZA_ATTR_JID, jid);
+
     if (handle != NULL) {
         xmpp_stanza_set_attribute(item, STANZA_ATTR_NAME, handle);
     } else {
         xmpp_stanza_set_attribute(item, STANZA_ATTR_NAME, "");
     }
 
+    while (groups != NULL) {
+        xmpp_stanza_t *group = xmpp_stanza_new(ctx);
+        xmpp_stanza_t *groupname = xmpp_stanza_new(ctx);
+        xmpp_stanza_set_name(group, STANZA_NAME_GROUP);
+        xmpp_stanza_set_text(groupname, groups->data);
+        xmpp_stanza_add_child(group, groupname);
+        xmpp_stanza_add_child(item, group);
+        groups = g_slist_next(groups);
+    }
+
     xmpp_stanza_add_child(query, item);
     xmpp_stanza_add_child(iq, query);
 
diff --git a/src/xmpp/stanza.h b/src/xmpp/stanza.h
index a79be3cd..169497bc 100644
--- a/src/xmpp/stanza.h
+++ b/src/xmpp/stanza.h
@@ -51,6 +51,7 @@
 #define STANZA_NAME_FEATURE "feature"
 #define STANZA_NAME_INVITE "invite"
 #define STANZA_NAME_REASON "reason"
+#define STANZA_NAME_GROUP "group"
 
 #define STANZA_TYPE_CHAT "chat"
 #define STANZA_TYPE_GROUPCHAT "groupchat"
@@ -178,6 +179,6 @@ char * stanza_get_status(xmpp_stanza_t *stanza, char *def);
 char * stanza_get_show(xmpp_stanza_t *stanza, char *def);
 
 xmpp_stanza_t * stanza_create_roster_set(xmpp_ctx_t *ctx, const char * const jid,
-    const char * const handle);
+    const char * const handle, GSList *groups);
 
 #endif
diff --git a/src/xmpp/xmpp.h b/src/xmpp/xmpp.h
index 41d182d2..70b41d59 100644
--- a/src/xmpp/xmpp.h
+++ b/src/xmpp/xmpp.h
@@ -139,7 +139,7 @@ char * roster_find_contact(char *search_str);
 char * roster_find_jid(char *search_str);
 char * roster_find_resource(char *search_str);
 gboolean roster_add(const char * const barejid, const char * const name,
-    const char * const subscription, gboolean pending_out);
+    GSList *groups, const char * const subscription, gboolean pending_out);
 void roster_change_name(const char * const barejid, const char * const new_name);
 char * roster_barejid_from_name(const char * const name);