about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorJames Booth <boothj5@gmail.com>2012-11-27 23:43:32 +0000
committerJames Booth <boothj5@gmail.com>2012-11-27 23:43:32 +0000
commita061b0d45261e39c53e5734518eb2860706ef99f (patch)
treea77215b1f5d7d8051a3444bfd15e3be41d51ee77 /src
parent2f2fa8de66e16def92a10c5433459e1795fd5441 (diff)
downloadprofani-tty-a061b0d45261e39c53e5734518eb2860706ef99f.tar.gz
Handle roster subscription updates
Diffstat (limited to 'src')
-rw-r--r--src/command.c36
-rw-r--r--src/contact.c21
-rw-r--r--src/contact.h2
-rw-r--r--src/contact_list.c14
-rw-r--r--src/contact_list.h2
-rw-r--r--src/jabber.c64
-rw-r--r--src/stanza.h1
7 files changed, 122 insertions, 18 deletions
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 <add|del|req|show> [jid]", "Manage subscriptions.",
-        { "/sub <add|del|req|show> [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 <request|allow|deny|show> [jid]", "Manage subscriptions.",
+        { "/sub <request|allow|deny|show> [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;
@@ -744,6 +746,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"