changeset 17563:95affacf6f82

Added the ability to define extensions to caps
author Andreas Monitzer <pidgin@monitzer.com>
date Wed, 06 Jun 2007 01:19:49 +0000
parents 6ab1089e2101
children ac1ee71efd89
files libpurple/protocols/jabber/buddy.c libpurple/protocols/jabber/chat.c libpurple/protocols/jabber/disco.c libpurple/protocols/jabber/jabber.c libpurple/protocols/jabber/jabber.h libpurple/protocols/jabber/presence.c libpurple/protocols/jabber/presence.h
diffstat 7 files changed, 131 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/protocols/jabber/buddy.c	Wed Jun 06 00:04:29 2007 +0000
+++ b/libpurple/protocols/jabber/buddy.c	Wed Jun 06 01:19:49 2007 +0000
@@ -1257,7 +1257,7 @@
 	status    = purple_presence_get_active_status(gpresence);
 
 	purple_status_to_jabber(status, &state, &msg, &priority);
-	presence = jabber_presence_create(state, msg, priority);
+	presence = jabber_presence_create_js(js, state, msg, priority);
 
 	g_free(msg);
 
--- a/libpurple/protocols/jabber/chat.c	Wed Jun 06 00:04:29 2007 +0000
+++ b/libpurple/protocols/jabber/chat.c	Wed Jun 06 01:19:49 2007 +0000
@@ -261,7 +261,7 @@
 
 	purple_status_to_jabber(status, &state, &msg, &priority);
 
-	presence = jabber_presence_create(state, msg, priority);
+	presence = jabber_presence_create_js(js, state, msg, priority);
 	full_jid = g_strdup_printf("%s/%s", room_jid, handle);
 	xmlnode_set_attrib(presence, "to", full_jid);
 	g_free(full_jid);
@@ -634,7 +634,7 @@
 
 	purple_status_to_jabber(status, &state, &msg, &priority);
 
-	presence = jabber_presence_create(state, msg, priority);
+	presence = jabber_presence_create_js(chat->js, state, msg, priority);
 	full_jid = g_strdup_printf("%s@%s/%s", chat->room, chat->server, nick);
 	xmlnode_set_attrib(presence, "to", full_jid);
 	g_free(full_jid);
--- a/libpurple/protocols/jabber/disco.c	Wed Jun 06 00:04:29 2007 +0000
+++ b/libpurple/protocols/jabber/disco.c	Wed Jun 06 01:19:49 2007 +0000
@@ -73,7 +73,6 @@
 			xmlnode_set_attrib(query, "node", node);
 
 		if(!node || !strcmp(node, CAPS0115_NODE "#" VERSION)) {
-
 			identity = xmlnode_new_child(query, "identity");
 			xmlnode_set_attrib(identity, "category", "client");
 			xmlnode_set_attrib(identity, "type", "pc"); /* XXX: bot, console,
@@ -98,18 +97,60 @@
 			SUPPORT_FEATURE("http://jabber.org/protocol/si/profile/file-transfer")
 			SUPPORT_FEATURE("http://jabber.org/protocol/xhtml-im")
 			SUPPORT_FEATURE("http://www.xmpp.org/extensions/xep-0199.html#ns")
+                
+            if(!node) { /* non-caps disco#info, add all extensions */
+                GList *features;
+                for(features = js->features; features; features = features->next) {
+                    JabberFeature *feat = (JabberFeature*)features->data;
+                    SUPPORT_FEATURE(feat->namespace);
+                }
+            }
 		} else {
-			xmlnode *error, *inf;
+            const char *ext = NULL;
+            unsigned pos;
+            unsigned nodelen = strlen(node);
+            unsigned capslen = strlen(CAPS0115_NODE);
+            /* do a basic plausability check */
+            if(nodelen > capslen+1) {
+                /* verify that the string is CAPS0115#<ext> and get the pointer to the ext part */
+                for(pos = 0; pos < capslen+1; ++pos) {
+                    if(pos == capslen) {
+                        if(node[pos] == '#')
+                            ext = &node[pos+1];
+                        else
+                            break;
+                    } else if(node[pos] != CAPS0115_NODE[pos])
+                        break;
+                }
+                
+                if(ext != NULL) {
+                    /* look for that ext */
+                    GList *features;
+                    for(features = js->features; features; features = features->next) {
+                        JabberFeature *feat = (JabberFeature*)features->data;
+                        if(!strcmp(feat->shortname, ext)) {
+                            SUPPORT_FEATURE(feat->namespace);
+                            break;
+                        }
+                    }
+                    if(features == NULL)
+                        ext = NULL;
+                }
+            }
+            
+            if(ext == NULL) {
+                xmlnode *error, *inf;
 
-			/* XXX: gross hack, implement jabber_iq_set_type or something */
-			xmlnode_set_attrib(iq->node, "type", "error");
-			iq->type = JABBER_IQ_ERROR;
+                /* XXX: gross hack, implement jabber_iq_set_type or something */
+                xmlnode_set_attrib(iq->node, "type", "error");
+                iq->type = JABBER_IQ_ERROR;
 
-			error = xmlnode_new_child(query, "error");
-			xmlnode_set_attrib(error, "code", "404");
-			xmlnode_set_attrib(error, "type", "cancel");
-			inf = xmlnode_new_child(error, "item-not-found");
-			xmlnode_set_namespace(inf, "urn:ietf:params:xml:ns:xmpp-stanzas");
+                error = xmlnode_new_child(query, "error");
+                xmlnode_set_attrib(error, "code", "404");
+                xmlnode_set_attrib(error, "type", "cancel");
+                inf = xmlnode_new_child(error, "item-not-found");
+                xmlnode_set_namespace(inf, "urn:ietf:params:xml:ns:xmpp-stanzas");
+            }
 		}
 
 		jabber_iq_send(iq);
--- a/libpurple/protocols/jabber/jabber.c	Wed Jun 06 00:04:29 2007 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Wed Jun 06 01:19:49 2007 +0000
@@ -1024,6 +1024,12 @@
 #endif
 	if(js->serverFQDN)
 		g_free(js->serverFQDN);
+	while(js->features) {
+        g_free(((JabberFeature*)js->features->data)->shortname);
+        g_free(((JabberFeature*)js->features->data)->namespace);
+		g_free(js->features->data);
+		js->features = g_list_delete_link(js->features, js->features);
+	}
 	g_free(js->server_name);
 	g_free(js->gmail_last_time);
 	g_free(js->gmail_last_tid);
@@ -1093,6 +1099,32 @@
 	js->idle = idle ? time(NULL) - idle : idle;
 }
 
+void jabber_add_feature(JabberStream *js, const char *shortname, const char *namespace) {
+    JabberFeature *feat = g_new0(JabberFeature,1);
+    feat->shortname = g_strdup(shortname);
+    feat->namespace = g_strdup(namespace);
+    
+    /* try to remove just in case it already exists in the list */
+    jabber_remove_feature(js, shortname);
+    
+    js->features = g_list_append(js->features, feat);
+}
+
+void jabber_remove_feature(JabberStream *js, const char *shortname) {
+    GList *feature;
+    for(feature = js->features; feature; feature = feature->next) {
+        JabberFeature *feat = (JabberFeature*)feature->data;
+        if(!strcmp(feat->shortname, shortname)) {
+            g_free(feat->shortname);
+            g_free(feat->namespace);
+            
+            g_free(feature->data);
+            feature = g_list_delete_link(feature, feature);
+            break;
+        }
+    }
+}
+
 const char *jabber_list_icon(PurpleAccount *a, PurpleBuddy *b)
 {
 	return "jabber";
--- a/libpurple/protocols/jabber/jabber.h	Wed Jun 06 00:04:29 2007 +0000
+++ b/libpurple/protocols/jabber/jabber.h	Wed Jun 06 01:19:49 2007 +0000
@@ -71,6 +71,12 @@
 	JABBER_STREAM_CONNECTED
 } JabberStreamState;
 
+typedef struct _JabberFeature
+{
+    gchar *shortname;
+    gchar *namespace;
+} JabberFeature;
+
 typedef struct _JabberStream
 {
 	int fd;
@@ -149,7 +155,9 @@
 	GString *sasl_mechs;
 #endif
     char *serverFQDN;
-
+    
+    /* what kind of additional features as returned from disco#info are supported? */
+    GList *features;
 } JabberStream;
 
 void jabber_process_packet(JabberStream *js, xmlnode *packet);
@@ -165,6 +173,9 @@
 
 char *jabber_parse_error(JabberStream *js, xmlnode *packet);
 
+void jabber_add_feature(JabberStream *js, const gchar *shortname, const gchar *namespace);
+void jabber_remove_feature(JabberStream *js, const gchar *shortname);
+
 /** PRPL functions */
 const char *jabber_list_icon(PurpleAccount *a, PurpleBuddy *b);
 const char* jabber_list_emblem(PurpleBuddy *b);
--- a/libpurple/protocols/jabber/presence.c	Wed Jun 06 00:04:29 2007 +0000
+++ b/libpurple/protocols/jabber/presence.c	Wed Jun 06 01:19:49 2007 +0000
@@ -118,7 +118,7 @@
 	purple_status_to_jabber(status, &state, &stripped, &priority);
 
 
-	presence = jabber_presence_create(state, stripped, priority);
+	presence = jabber_presence_create_js(js, state, stripped, priority);
 	g_free(stripped);
 
 	if(js->avatar_hash) {
@@ -138,6 +138,11 @@
 
 xmlnode *jabber_presence_create(JabberBuddyState state, const char *msg, int priority)
 {
+    return jabber_presence_create_js(NULL, state, msg, priority);
+}
+
+xmlnode *jabber_presence_create_js(JabberStream *js, JabberBuddyState state, const char *msg, int priority)
+{
 	xmlnode *show, *status, *presence, *pri, *c;
 	const char *show_string = NULL;
 
@@ -172,6 +177,31 @@
 	xmlnode_set_namespace(c, "http://jabber.org/protocol/caps");
 	xmlnode_set_attrib(c, "node", CAPS0115_NODE);
 	xmlnode_set_attrib(c, "ver", VERSION);
+    
+    if(js != NULL) {
+        /* add the extensions */
+        char extlist[1024];
+        unsigned remaining = 1023; /* one less for the \0 */
+        GSList *feature;
+        
+        extlist[0] = '\0';
+        for(feature = js->features; feature && remaining > 0; feature = feature->next) {
+            JabberFeature *feat = (JabberFeature*)feature->data;
+            unsigned featlen = strlen(feat->shortname);
+            
+            /* cut off when we don't have any more space left in our buffer (too bad) */
+            if(featlen > remaining)
+                break;
+            
+            strncat(extlist,feat->shortname,remaining);
+            remaining -= featlen;
+            strncat(extlist," ",remaining);
+            --remaining;
+        }
+        /* did we add anything? */
+        if(remaining < 1023)
+            xmlnode_set_attrib(c, "ext", extlist);
+    }
 
 	return presence;
 }
--- a/libpurple/protocols/jabber/presence.h	Wed Jun 06 00:04:29 2007 +0000
+++ b/libpurple/protocols/jabber/presence.h	Wed Jun 06 01:19:49 2007 +0000
@@ -27,7 +27,8 @@
 #include "xmlnode.h"
 
 void jabber_presence_send(PurpleAccount *account, PurpleStatus *status);
-xmlnode *jabber_presence_create(JabberBuddyState state, const char *msg, int priority);
+xmlnode *jabber_presence_create(JabberBuddyState state, const char *msg, int priority); /* DEPRECATED */
+xmlnode *jabber_presence_create_js(JabberStream *js, JabberBuddyState state, const char *msg, int priority);
 void jabber_presence_parse(JabberStream *js, xmlnode *packet);
 void jabber_presence_subscription_set(JabberStream *js, const char *who,
 		const char *type);