changeset 25776:7de1f124f95a

Jabber BOSH: Many fixes * Move most of the function and structure definitions into bosh.c * Made js->bosh a pointer, the init function allocates and returns the pointer, etc. * Drop the account member of PurpleHTTPConnection * Fix many, many warnings, including a few bug-related things
author Paul Aurich <paul@darkrain42.org>
date Mon, 01 Dec 2008 05:47:04 +0000
parents 1516525c86fa
children 17b60b844803
files libpurple/protocols/jabber/bosh.c libpurple/protocols/jabber/bosh.h libpurple/protocols/jabber/jabber.c libpurple/protocols/jabber/jabber.h
diffstat 4 files changed, 168 insertions(+), 148 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/protocols/jabber/bosh.c	Mon Dec 01 04:00:41 2008 +0000
+++ b/libpurple/protocols/jabber/bosh.c	Mon Dec 01 05:47:04 2008 +0000
@@ -21,42 +21,136 @@
 #include "internal.h"
 #include "cipher.h"
 #include "debug.h"
-#include "imgstore.h"
 #include "prpl.h"
-#include "notify.h"
-#include "request.h"
 #include "util.h"
 #include "xmlnode.h"
 
-#include "buddy.h"
-#include "chat.h"
-#include "jabber.h"
-#include "iq.h"
-#include "presence.h"
-#include "xdata.h"
-#include "pep.h"
-#include "adhoccommands.h"
-#include "connection.h"
+#include "bosh.h"
+
+typedef struct _PurpleHTTPRequest PurpleHTTPRequest;
+typedef struct _PurpleHTTPResponse PurpleHTTPResponse;
+typedef struct _PurpleHTTPConnection PurpleHTTPConnection;
+
+typedef void (*PurpleHTTPConnectionConnectFunction)(PurpleHTTPConnection *conn);
+typedef void (*PurpleHTTPConnectionDisconnectFunction)(PurpleHTTPConnection *conn);
+typedef void (*PurpleHTTPRequestCallback)(PurpleHTTPRequest *req, PurpleHTTPResponse *res, void *userdata);
+typedef void (*PurpleBOSHConnectionConnectFunction)(PurpleBOSHConnection *conn);
+typedef void (*PurpleBOSHConnectionReceiveFunction)(PurpleBOSHConnection *conn, xmlnode *node);
+
+struct _PurpleBOSHConnection {
+    /* decoded URL */
+    char *host;
+    int port;
+    char *path; 
+    char *user;
+    char *passwd;
+    
+    int rid;
+    char *sid;
+    int wait;
+        
+    JabberStream *js;
+    PurpleAccount *account;
+    gboolean pipelining;
+    PurpleHTTPConnection *conn_a;
+    PurpleHTTPConnection *conn_b;
+    
+    gboolean ready;
+    PurpleBOSHConnectionConnectFunction connect_cb;
+    PurpleBOSHConnectionReceiveFunction receive_cb;
+};
+
+struct _PurpleHTTPConnection {
+    int fd;
+    char *host;
+    int port;
+    int handle;
+    int ie_handle;
+    PurpleConnection *conn;
+    GQueue *requests;
+    
+    PurpleHTTPResponse *current_response;
+    char *current_data;
+    int current_len;
+    
+    int pih;
+    PurpleHTTPConnectionConnectFunction connect_cb;
+    PurpleHTTPConnectionConnectFunction disconnect_cb;
+    void *userdata;
+};
 
-void jabber_bosh_connection_init(PurpleBOSHConnection *conn, PurpleAccount *account, JabberStream *js, char *url) {
-	conn->pipelining = TRUE;
-	conn->account = account;
-	if (!purple_url_parse(url, &(conn->host), &(conn->port), &(conn->path), &(conn->user), &(conn->passwd))) {
+struct _PurpleHTTPRequest {
+    PurpleHTTPRequestCallback cb;
+    char *method;
+    char *path;
+    GHashTable *header;
+    char *data;
+    int data_len;
+    void *userdata;
+};
+
+struct _PurpleHTTPResponse {
+    int status;
+    GHashTable *header;
+    char *data;
+    int data_len;
+};
+
+static void jabber_bosh_connection_stream_restart(PurpleBOSHConnection *conn);
+static gboolean jabber_bosh_connection_error_check(PurpleBOSHConnection *conn, xmlnode *node);
+static void jabber_bosh_connection_received(PurpleBOSHConnection *conn, xmlnode *node);
+static void jabber_bosh_connection_auth_response(PurpleBOSHConnection *conn, xmlnode *node);
+static void jabber_bosh_connection_boot_response(PurpleBOSHConnection *conn, xmlnode *node);
+static void jabber_bosh_connection_http_received_cb(PurpleHTTPRequest *req, PurpleHTTPResponse *res, void *userdata);
+static void jabber_bosh_connection_send_native(PurpleBOSHConnection *conn, xmlnode *node);
+
+static void jabber_bosh_http_connection_receive_parse_header(PurpleHTTPResponse *response, char **data, int *len);
+static PurpleHTTPConnection* jabber_bosh_http_connection_init(const char *host, int port);
+static void jabber_bosh_http_connection_connect(PurpleHTTPConnection *conn);
+static void jabber_bosh_http_connection_send_request(PurpleHTTPConnection *conn, PurpleHTTPRequest *req);
+static void jabber_bosh_http_connection_clean(PurpleHTTPConnection *conn);
+
+static void jabber_bosh_http_request_init(PurpleHTTPRequest *req, const char *method, const char *path, PurpleHTTPRequestCallback cb, void *userdata);
+static void jabber_bosh_http_request_add_to_header(PurpleHTTPRequest *req, const char *field, const char *value);
+static void jabber_bosh_http_request_set_data(PurpleHTTPRequest *req, char *data, int len);
+static void jabber_bosh_http_request_clean(PurpleHTTPRequest *req);
+
+static void jabber_bosh_http_response_init(PurpleHTTPResponse *res);
+static void jabber_bosh_http_response_clean(PurpleHTTPResponse *res);
+
+PurpleBOSHConnection* jabber_bosh_connection_init(JabberStream *js, const char *url) {
+	PurpleBOSHConnection *conn;
+	char *host, *path, *user, *passwd;
+	int port;
+
+	if (!purple_url_parse(url, &host, &port, &path, &user, &passwd)) {
 		purple_debug_info("jabber", "Unable to parse given URL.\n");
-		return;
+		return NULL;
 	}
+
+	conn = g_new0(PurpleBOSHConnection, 1);
+	conn->host = host;
+	conn->port = port;
+	conn->path = path;
+	conn->user = user;
+	conn->passwd = passwd;
+	conn->pipelining = TRUE;
+
 	if (conn->user || conn->passwd) {
-		purple_debug_info("jabber", "Sorry, HTTP Authentication isn't supported yet. Username and password in the BOSH URL will be ignored.\n");
+		purple_debug_info("jabber", "Ignoring unsupported BOSH HTTP "
+				"Authentication username and password.\n");
 	}
+
 	conn->js = js;
 	conn->rid = rand() % 100000 + 1728679472;
 	conn->ready = FALSE;
-	conn->conn_a = g_new0(PurpleHTTPConnection, 1);
-	jabber_bosh_http_connection_init(conn->conn_a, conn->account, conn->host, conn->port);
+	conn->conn_a = jabber_bosh_http_connection_init(conn->host, conn->port);
 	conn->conn_a->userdata = conn;
+
+	return conn;
 }
 
-void jabber_bosh_connection_stream_restart(PurpleBOSHConnection *conn) {
+static void jabber_bosh_connection_stream_restart(PurpleBOSHConnection *conn) {
 	xmlnode *restart = xmlnode_new("body");
 	char *tmp = NULL;
 	conn->rid++;
@@ -72,8 +166,8 @@
 	jabber_bosh_connection_send_native(conn, restart);
 }
 
-gboolean jabber_bosh_connection_error_check(PurpleBOSHConnection *conn, xmlnode *node) {
-	char *type;
+static gboolean jabber_bosh_connection_error_check(PurpleBOSHConnection *conn, xmlnode *node) {
+	const char *type;
 	
 	if (!node) return FALSE;
 	type = xmlnode_get_attrib(node, "type");
@@ -88,7 +182,7 @@
 	return FALSE;
 }
 
-void jabber_bosh_connection_received(PurpleBOSHConnection *conn, xmlnode *node) {
+static void jabber_bosh_connection_received(PurpleBOSHConnection *conn, xmlnode *node) {
 	xmlnode *child;
 	JabberStream *js = conn->js;
 	
@@ -110,7 +204,7 @@
 	}
 }
 
-void jabber_bosh_connection_auth_response(PurpleBOSHConnection *conn, xmlnode *node) {
+static void jabber_bosh_connection_auth_response(PurpleBOSHConnection *conn, xmlnode *node) {
 	xmlnode *child = node->child;
 	
 	if (jabber_bosh_connection_error_check(conn, node) == TRUE) return;
@@ -132,7 +226,7 @@
 	} else printf("\n!! no child!!\n");
 }
 
-void jabber_bosh_connection_boot_response(PurpleBOSHConnection *conn, xmlnode *node) {
+static void jabber_bosh_connection_boot_response(PurpleBOSHConnection *conn, xmlnode *node) {
 	char *version;
 	
 	if (jabber_bosh_connection_error_check(conn, node) == TRUE) return;
@@ -142,17 +236,24 @@
 	} else {
 		purple_debug_info("jabber", "Connection manager doesn't behave BOSH-like!\n");
 	}
-	
-	if ((version = xmlnode_get_attrib(node, "ver"))) {
-		version[1] = 0;
-		if (!(atoi(version) >= 1 && atoi(&version[2]) >= 6)) purple_debug_info("jabber", 	"Unsupported version of BOSH protocol. The connection manager must at least support version 1.6!\n");
-		else {
+
+	if ((version = g_strdup(xmlnode_get_attrib(node, "ver")))) {
+		char *dot = strstr(version, ".");
+		int major = atoi(version);
+		int minor = atoi(dot + 1);
+
+		if (major > 1 || (major == 1 && minor >= 6)) {
 			xmlnode *packet = xmlnode_get_child(node, "features");
 			conn->js->use_bosh = TRUE;
 			conn->receive_cb = jabber_bosh_connection_auth_response;
-			jabber_stream_features_parse(conn->js, packet);
+			jabber_stream_features_parse(conn->js, packet);		
+		} else {
+			purple_debug_info("jabber", "Unsupported version of BOSH protocol. The connection manager must at least support version 1.6!\n");
+			/* XXX This *must* handle this by killing the connection and
+			 * reporting an error. */
 		}
-		version[1] = '.';
+
+		g_free(version);
 	} else {
 		purple_debug_info("jabber", "Missing version in session creation response!\n");	
 	}
@@ -180,7 +281,7 @@
 	jabber_bosh_connection_send_native(conn, init);
 }
 
-void jabber_bosh_connection_http_received_cb(PurpleHTTPRequest *req, PurpleHTTPResponse *res, void *userdata) {
+static void jabber_bosh_connection_http_received_cb(PurpleHTTPRequest *req, PurpleHTTPResponse *res, void *userdata) {
 	PurpleBOSHConnection *conn = userdata;
 	if (conn->receive_cb) {
 		xmlnode *node = xmlnode_from_str(res->data, res->data_len);
@@ -213,7 +314,7 @@
 	jabber_bosh_connection_send_native(conn, packet);
 }
 
-void jabber_bosh_connection_send_native(PurpleBOSHConnection *conn, xmlnode *node) {
+static void jabber_bosh_connection_send_native(PurpleBOSHConnection *conn, xmlnode *node) {
 	PurpleHTTPRequest *request = g_new0(PurpleHTTPRequest, 1);
 	
 	char *txt = xmlnode_to_formatted_str(node, NULL);
@@ -252,10 +353,10 @@
 	jabber_bosh_http_connection_connect(conn->conn_a);
 }
 
-void jabber_bosh_http_connection_receive_parse_header(PurpleHTTPResponse *response, char **data, int *len) {
+static void jabber_bosh_http_connection_receive_parse_header(PurpleHTTPResponse *response, char **data, int *len) {
 	GHashTable *header = response->header;
 	char *beginning = *data;
-	char *found = g_strstr_len(*data, len, "\r\n\r\n");
+	char *found = g_strstr_len(*data, *len, "\r\n\r\n");
 	char *field = NULL;
 	char *value = NULL;
 	char *old_data = *data;
@@ -312,9 +413,8 @@
 		
 		if (!response) {
 			/* check for header footer */
-			char *found = NULL;
-			if (found = g_strstr_len(conn->current_data, conn->current_len, "\r\n\r\n")) {
-				
+			char *found = g_strstr_len(conn->current_data, conn->current_len, "\r\n\r\n");
+			if (found) {
 				// new response
 				response = conn->current_response = g_new0(PurpleHTTPResponse, 1);
 				jabber_bosh_http_response_init(response);
@@ -329,7 +429,7 @@
 			if (conn->current_len >= response->data_len) {
 				PurpleHTTPRequest *request = g_queue_pop_head(conn->requests);
 				
-				#warning for a pure HTTP 1.1 stack this would be needed to be handled elsewhereƄ
+#warning For a pure HTTP 1.1 stack, this would need to be handled elsewhere.
 				if (bosh_conn->ready == TRUE && g_queue_is_empty(conn->requests) == TRUE) {
 					jabber_bosh_connection_send(bosh_conn, NULL); 
 					printf("\n SEND AN EMPTY REQUEST \n");
@@ -363,14 +463,14 @@
 	}
 }
 
-void jabber_bosh_http_connection_init(PurpleHTTPConnection *conn, PurpleAccount *account, char *host, int port) {
-	conn->account = account;
-	conn->host = host;
+PurpleHTTPConnection *jabber_bosh_http_connection_init(const char *host, int port)
+{
+	PurpleHTTPConnection *conn = g_new0(PurpleHTTPConnection, 1);
+	conn->host = g_strdup(host);
 	conn->port = port;
-	conn->connect_cb = NULL;
-	conn->current_response = NULL;
-	conn->current_data = NULL;
 	conn->requests = g_queue_new();
+
+	return conn;
 }
 
 void jabber_bosh_http_connection_clean(PurpleHTTPConnection *conn) {
@@ -390,9 +490,13 @@
 }
 
 void jabber_bosh_http_connection_connect(PurpleHTTPConnection *conn) {
-	if((purple_proxy_connect(&(conn->handle), conn->account, conn->host, conn->port, jabber_bosh_http_connection_callback, conn)) == NULL) {
+	PurpleBOSHConnection *bosh_conn = conn->userdata;
+	PurpleConnection *gc = bosh_conn->js->gc;
+	PurpleAccount *account = purple_connection_get_account(gc);
+
+	if((purple_proxy_connect(&(conn->handle), account, conn->host, conn->port, jabber_bosh_http_connection_callback, conn)) == NULL) {
 		purple_debug_info("jabber", "Unable to connect to %s.\n", conn->host);
-	} 
+	}
 }
 
 static void jabber_bosh_http_connection_send_request_add_field_to_string(gpointer key, gpointer value, gpointer user_data) {
@@ -426,8 +530,10 @@
 	req->header = g_hash_table_new(g_str_hash, g_str_equal);
 }
 
-void jabber_bosh_http_request_add_to_header(PurpleHTTPRequest *req, const char *field, const char *value) {
-	g_hash_table_replace(req->header, field, value);
+static void jabber_bosh_http_request_add_to_header(PurpleHTTPRequest *req, const char *field, const char *value) {
+	char *f = g_strdup(field);
+	char *v = g_strdup(value);
+	g_hash_table_replace(req->header, f, v);
 }
 
 void jabber_bosh_http_request_set_data(PurpleHTTPRequest *req, char *data, int len) {
--- a/libpurple/protocols/jabber/bosh.h	Mon Dec 01 04:00:41 2008 +0000
+++ b/libpurple/protocols/jabber/bosh.h	Mon Dec 01 05:47:04 2008 +0000
@@ -22,95 +22,11 @@
 #ifndef _PURPLE_JABBER_BOSH_H_
 #define _PURPLE_JABBER_BOSH_H_
 
-#include <glib.h>
-
-typedef struct _PurpleHTTPRequest PurpleHTTPRequest;
-typedef struct _PurpleHTTPResponse PurpleHTTPResponse;
-typedef struct _PurpleHTTPConnection PurpleHTTPConnection;
 typedef struct _PurpleBOSHConnection PurpleBOSHConnection;
 
-typedef void (*PurpleHTTPConnectionConnectFunction)(PurpleHTTPConnection *conn);
-typedef void (*PurpleHTTPConnectionDisconnectFunction)(PurpleHTTPConnection *conn);
-typedef void (*PurpleHTTPRequestCallback)(PurpleHTTPRequest *req, PurpleHTTPResponse *res, void *userdata);
-typedef void (*PurpleBOSHConnectionConnectFunction)(PurpleBOSHConnection *conn);
-typedef void (*PurpleBOSHConnectionReciveFunction)(PurpleBOSHConnection *conn, xmlnode *node);
-
-struct _PurpleBOSHConnection {
-    /* decoded URL */
-    char *host;
-    int port;
-    char *path; 
-    char *user;
-    char *passwd;
-    
-    int rid;
-    char *sid;
-    int wait;
-        
-    JabberStream *js;
-    void *userdata;
-    PurpleAccount *account;
-    gboolean pipelining;
-    PurpleHTTPConnection *conn_a;
-    PurpleHTTPConnection *conn_b;
-    
-    gboolean ready;
-    PurpleBOSHConnectionConnectFunction connect_cb;
-    PurpleBOSHConnectionReciveFunction receive_cb;
-};
+#include "jabber.h"
 
-struct _PurpleHTTPConnection {
-    int fd;
-    char *host;
-    int port;
-    int handle;
-    int ie_handle;
-    PurpleConnection *conn;
-    PurpleAccount *account;
-    GQueue *requests;
-    
-    PurpleHTTPResponse *current_response;
-    char *current_data;
-    int current_len;
-    
-    int pih;
-    PurpleHTTPConnectionConnectFunction connect_cb;
-    PurpleHTTPConnectionConnectFunction disconnect_cb;
-    void *userdata;
-};
-
-struct _PurpleHTTPRequest {
-    PurpleHTTPRequestCallback cb;
-    char *method;
-    char *path;
-    GHashTable *header;
-    char *data;
-    int data_len;
-    void *userdata;
-};
-
-struct _PurpleHTTPResponse {
-    int status;
-    GHashTable *header;
-    char *data;
-    int data_len;
-};
-
-void jabber_bosh_connection_init(PurpleBOSHConnection *conn, PurpleAccount *account, JabberStream *js, char *url);
+PurpleBOSHConnection* jabber_bosh_connection_init(JabberStream *js, const char *url);
 void jabber_bosh_connection_connect(PurpleBOSHConnection *conn);
-void jabber_bosh_connection_send_native(PurpleBOSHConnection *conn, xmlnode *node);
 void jabber_bosh_connection_send(PurpleBOSHConnection *conn, xmlnode *node);
-
-void jabber_bosh_http_connection_init(PurpleHTTPConnection *conn, PurpleAccount *account, char *host, int port);
-void jabber_bosh_http_connection_connect(PurpleHTTPConnection *conn);
-void jabber_bosh_http_connection_send_request(PurpleHTTPConnection *conn, PurpleHTTPRequest *req);
-void jabber_bosh_http_connection_clean(PurpleHTTPConnection *conn);
-
-void jabber_bosh_http_request_init(PurpleHTTPRequest *req, const char *method, const char *path, PurpleHTTPRequestCallback cb, void *userdata);
-void jabber_bosh_http_request_add_to_header(PurpleHTTPRequest *req, const char *field, const char *value);
-void jabber_bosh_http_request_set_data(PurpleHTTPRequest *req, char *data, int len);
-void jabber_bosh_http_request_clean(PurpleHTTPRequest *req);
-
-void jabber_bosh_http_response_init(PurpleHTTPResponse *res);
-void jabber_bosh_http_response_clean(PurpleHTTPResponse *res);
 #endif /* _PURPLE_JABBER_BOSH_H_ */
--- a/libpurple/protocols/jabber/jabber.c	Mon Dec 01 04:00:41 2008 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Mon Dec 01 05:47:04 2008 +0000
@@ -393,7 +393,7 @@
 
 	if (js->use_bosh) {
 		xmlnode *xnode = xmlnode_from_str(data, len);
-		if (xnode) jabber_bosh_connection_send(&(js->bosh), xnode);
+		if (xnode) jabber_bosh_connection_send(js->bosh, xnode);
 		else {
 			purple_connection_error_reason(js->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR,
 							_("Someone tried to send non-XML in a Jabber world."));
@@ -572,8 +572,7 @@
 static void 
 txt_resolved_cb(PurpleTxtResponse *resp, int results, gpointer data)
 {
-	PurpleConnection *gc = data;
-	JabberStream *js = gc->proto_data;
+	JabberStream *js = data;
 	int n;
 	
 	js->srv_query_data = NULL;
@@ -581,7 +580,7 @@
 	if (results == 0) {
 		gchar *tmp;
 		tmp = g_strdup_printf(_("Could not find alternative XMPP connection methods after failing to connect directly.\n"));
-		purple_connection_error_reason (gc,
+		purple_connection_error_reason (js->gc,
 				PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
 		g_free(tmp);
 		return;	
@@ -592,15 +591,14 @@
 		token = g_strsplit(resp[n].content, "=", 2);
 		if (!strcmp(token[0], "_xmpp-client-xbosh")) {
 			purple_debug_info("jabber","Found alternative connection method using %s at %s.\n", token[0], token[1]);
-			jabber_bosh_connection_init(&(js->bosh), js->gc->account, js, token[1]);
+			js->bosh = jabber_bosh_connection_init(js, token[1]);
 			g_strfreev(token);
 			break;
 		}
 		g_strfreev(token);
 	}
-	if (js->bosh.host) {
-		js->bosh.userdata = gc;
-		jabber_bosh_connection_connect(&(js->bosh));
+	if (js->bosh) {
+		jabber_bosh_connection_connect(js->bosh);
 	} else {
 		purple_debug_info("jabber","Didn't find an alternative connection method.\n");
 	}
@@ -618,7 +616,7 @@
 			try_srv_connect(js);
 		} else {
 			purple_debug_info("jabber","Couldn't connect directly to %s. Trying to find alternative connection methods, like BOSH.\n", js->user->domain);
-			js->srv_query_data = purple_txt_resolve("_xmppconnect", js->user->domain, txt_resolved_cb, gc);
+			js->srv_query_data = purple_txt_resolve("_xmppconnect", js->user->domain, txt_resolved_cb, js);
 		}
 		return;
 	}
@@ -771,7 +769,7 @@
 
 	/* XXX FORCE_BOSH: Remove this */
 	if (force_bosh) {
-		js->srv_query_data = purple_txt_resolve("_xmppconnect", js->user->domain, txt_resolved_cb, gc);
+		js->srv_query_data = purple_txt_resolve("_xmppconnect", js->user->domain, txt_resolved_cb, js);
 		return;
 	}
 
--- a/libpurple/protocols/jabber/jabber.h	Mon Dec 01 04:00:41 2008 +0000
+++ b/libpurple/protocols/jabber/jabber.h	Mon Dec 01 05:47:04 2008 +0000
@@ -243,7 +243,7 @@
 
 	/* BOSH stuff */
 	gboolean use_bosh;
-	PurpleBOSHConnection bosh;
+	PurpleBOSHConnection *bosh;
 
 	/**
 	 * This linked list contains PurpleUtilFetchUrlData structs