From d017999a91278f6c51aa42075c4a86a386806a52 Mon Sep 17 00:00:00 2001 From: James Booth Date: Wed, 22 May 2013 23:38:52 +0100 Subject: [PATCH] Add groups to roster contacts fixes #175 --- src/contact.c | 28 +++++++++++++++++++-- src/contact.h | 6 +++-- src/muc.c | 2 +- src/xmpp/roster.c | 64 +++++++++++++++++++++++++++++++++++++++++------ src/xmpp/roster.h | 2 +- src/xmpp/stanza.c | 13 +++++++++- src/xmpp/stanza.h | 3 ++- src/xmpp/xmpp.h | 2 +- 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);