From a061b0d45261e39c53e5734518eb2860706ef99f Mon Sep 17 00:00:00 2001 From: James Booth Date: Tue, 27 Nov 2012 23:43:32 +0000 Subject: Handle roster subscription updates --- src/command.c | 36 +++++++++++++++--------------- src/contact.c | 21 ++++++++++++++++++ src/contact.h | 2 ++ src/contact_list.c | 14 ++++++++++++ src/contact_list.h | 2 ++ src/jabber.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++- src/stanza.h | 1 + 7 files changed, 122 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/command.c b/src/command.c index c0155c38..a36f5c23 100644 --- a/src/command.c +++ b/src/command.c @@ -276,18 +276,20 @@ static struct cmd_t main_commands[] = { "/sub", _cmd_sub, parse_args, 1, 2, - { "/sub [jid]", "Manage subscriptions.", - { "/sub [jid]", - "-----------------------------", - "add : Approve subscription to a contact.", - "del : Remove subscription for a contact.", - "req : Send a subscription request to the user to be informed of their", - " : presence.", - "show : Show subscriprion status for a contact.", + { "/sub [jid]", "Manage subscriptions.", + { "/sub [jid]", + "------------------------------------", + "request : Send a subscription request to the user to be informed of their", + " : presence.", + "allow : Approve contacts subscription reqeust to see your presence.", + "deny : Remove subscription for a contact, or deny a request", + "show : Show subscriprion status for a contact.", "", "If optional parameter 'jid' isn't set command belongs to the current window.", "", - "Example: /sub add myfriend@jabber.org", + "Example: /sub request myfriend@jabber.org", + "Example: /sub allow myfriend@jabber.org", + "Example: /sub request (whilst in chat with contact)", NULL } } }, { "/tiny", @@ -622,9 +624,9 @@ cmd_init(void) p_autocomplete_add(notify_ac, strdup("remind")); sub_ac = p_autocomplete_new(); - p_autocomplete_add(sub_ac, strdup("add")); - p_autocomplete_add(sub_ac, strdup("del")); - p_autocomplete_add(sub_ac, strdup("req")); + p_autocomplete_add(sub_ac, strdup("request")); + p_autocomplete_add(sub_ac, strdup("allow")); + p_autocomplete_add(sub_ac, strdup("deny")); p_autocomplete_add(sub_ac, strdup("show")); log_ac = p_autocomplete_new(); @@ -995,15 +997,15 @@ _cmd_sub(gchar **args, struct cmd_help_t help) bare_jid = strtok(jid, "/"); - if (strcmp(subcmd, "add") == 0) { + if (strcmp(subcmd, "allow") == 0) { jabber_subscription(bare_jid, PRESENCE_SUBSCRIBED); cons_show("Accepted subscription for %s", bare_jid); log_info("Accepted subscription for %s", bare_jid); - } else if (strcmp(subcmd, "del") == 0) { + } else if (strcmp(subcmd, "deny") == 0) { jabber_subscription(bare_jid, PRESENCE_UNSUBSCRIBED); - cons_show("Deleted subscription for %s", bare_jid); - log_info("Deleted subscription for %s", bare_jid); - } else if (strcmp(subcmd, "req") == 0) { + cons_show("Deleted/denied subscription for %s", bare_jid); + log_info("Deleted/denied subscription for %s", bare_jid); + } else if (strcmp(subcmd, "request") == 0) { jabber_subscription(bare_jid, PRESENCE_SUBSCRIBE); cons_show("Sent subscription request to %s.", bare_jid); log_info("Sent subscription request to %s.", bare_jid); diff --git a/src/contact.c b/src/contact.c index 9cbe5d69..552150cb 100644 --- a/src/contact.c +++ b/src/contact.c @@ -195,6 +195,27 @@ p_contact_set_status(const PContact contact, const char * const status) } } +void +p_contact_set_subscription(const PContact contact, const char * const subscription) +{ + if (contact->subscription != NULL) { + free(contact->subscription); + contact->subscription = NULL; + } + + if (subscription == NULL) { + contact->subscription = strdup("none"); + } else { + contact->subscription = strdup(subscription); + } +} + +void +p_contact_set_pending_out(const PContact contact, gboolean pending_out) +{ + contact->pending_out = pending_out; +} + int p_contacts_equal_deep(const PContact c1, const PContact c2) { diff --git a/src/contact.h b/src/contact.h index 314cf0f4..c86e624e 100644 --- a/src/contact.h +++ b/src/contact.h @@ -38,6 +38,8 @@ const char * p_contact_subscription(const PContact contact); gboolean p_contact_pending_out(const PContact contact); void p_contact_set_presence(const PContact contact, const char * const presence); void p_contact_set_status(const PContact contact, const char * const status); +void p_contact_set_subscription(const PContact contact, const char * const subscription); +void p_contact_set_pending_out(const PContact contact, gboolean pending_out); int p_contacts_equal_deep(const PContact c1, const PContact c2); #endif diff --git a/src/contact_list.c b/src/contact_list.c index 4b3b3a03..ddbe969c 100644 --- a/src/contact_list.c +++ b/src/contact_list.c @@ -96,6 +96,20 @@ contact_list_update_contact(const char * const jid, const char * const presence, return changed; } +void +contact_list_update_subscription(const char * const jid, + const char * const subscription, gboolean pending_out) +{ + PContact contact = g_hash_table_lookup(contacts, jid); + + if (contact == NULL) { + return; + } else { + p_contact_set_subscription(contact, subscription); + p_contact_set_pending_out(contact, pending_out); + } +} + GSList * get_contact_list(void) { diff --git a/src/contact_list.h b/src/contact_list.h index 0fd27010..44322048 100644 --- a/src/contact_list.h +++ b/src/contact_list.h @@ -35,6 +35,8 @@ gboolean contact_list_add(const char * const jid, const char * const name, const char * const subscription, gboolean pending_out); gboolean contact_list_update_contact(const char * const jid, const char * const presence, const char * const status); +void contact_list_update_subscription(const char * const jid, + const char * const subscription, gboolean pending_out); GSList * get_contact_list(void); char * contact_list_find_contact(char *search_str); PContact contact_list_get_contact(const char const *jid); diff --git a/src/jabber.c b/src/jabber.c index 3a0c23bd..19457423 100644 --- a/src/jabber.c +++ b/src/jabber.c @@ -71,6 +71,8 @@ static int _groupchat_message_handler(xmpp_stanza_t * const stanza); static int _error_handler(xmpp_stanza_t * const stanza); static int _chat_message_handler(xmpp_stanza_t * const stanza); +static int _iq_handler(xmpp_conn_t * const conn, + xmpp_stanza_t * const stanza, void * const userdata); static int _roster_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _presence_handler(xmpp_conn_t * const conn, @@ -673,7 +675,7 @@ _connection_handler(xmpp_conn_t * const conn, xmpp_handler_add(conn, _message_handler, NULL, STANZA_NAME_MESSAGE, NULL, ctx); xmpp_handler_add(conn, _presence_handler, NULL, STANZA_NAME_PRESENCE, NULL, ctx); - xmpp_id_handler_add(conn, _roster_handler, "roster", ctx); + xmpp_handler_add(conn, _iq_handler, NULL, STANZA_NAME_IQ, NULL, ctx); if (prefs_get_autoping() != 0) { int millis = prefs_get_autoping() * 1000; @@ -743,6 +745,66 @@ _connection_handler(xmpp_conn_t * const conn, } } +static int +_iq_handler(xmpp_conn_t * const conn, + xmpp_stanza_t * const stanza, void * const userdata) +{ + char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID); + + // handle the initial roster request + if ((id != NULL) && (strcmp(id, "roster") == 0)) { + return _roster_handler(conn, stanza, userdata); + + // handle roster updates + } else { + char *type = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_TYPE); + if (type == NULL) { + return TRUE; + } + + if (strcmp(type, "set") != 0) { + return TRUE; + } + + xmpp_stanza_t *query = + xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY); + + if (query == NULL) { + return TRUE; + } + + char *xmlns = xmpp_stanza_get_attribute(query, STANZA_ATTR_XMLNS); + + if (xmlns == NULL) { + return TRUE; + } + + if (strcmp(xmlns, XMPP_NS_ROSTER) != 0) { + return TRUE; + } + + xmpp_stanza_t *item = + xmpp_stanza_get_child_by_name(query, STANZA_NAME_ITEM); + + if (item == NULL) { + return TRUE; + } + + const char *jid = xmpp_stanza_get_attribute(item, STANZA_ATTR_JID); + const char *sub = xmpp_stanza_get_attribute(item, STANZA_ATTR_SUBSCRIPTION); + + gboolean pending_out = FALSE; + const char *ask = xmpp_stanza_get_attribute(item, STANZA_ATTR_ASK); + if ((ask != NULL) && (strcmp(ask, "subscribe") == 0)) { + pending_out = TRUE; + } + + contact_list_update_subscription(jid, sub, pending_out); + + return TRUE; + } +} + static int _roster_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) diff --git a/src/stanza.h b/src/stanza.h index e29aa873..50d5e4a9 100644 --- a/src/stanza.h +++ b/src/stanza.h @@ -68,6 +68,7 @@ #define STANZA_ATTR_XMLNS "xmlns" #define STANZA_ATTR_NICK "nick" #define STANZA_ATTR_ASK "ask" +#define STANZA_ATTR_ID "id" #define STANZA_TEXT_AWAY "away" #define STANZA_TEXT_DND "dnd" -- cgit 1.4.1-2-gfad0