# HG changeset patch # User Paul Aurich # Date 1228110424 0 # Node ID 7de1f124f95ac6f35d3dfa243d7b2f87db1a0b25 # Parent 1516525c86fa46c113bcf69a2408e34e59c73665 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 diff -r 1516525c86fa -r 7de1f124f95a libpurple/protocols/jabber/bosh.c --- 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) { diff -r 1516525c86fa -r 7de1f124f95a libpurple/protocols/jabber/bosh.h --- 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 - -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_ */ diff -r 1516525c86fa -r 7de1f124f95a libpurple/protocols/jabber/jabber.c --- 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; } diff -r 1516525c86fa -r 7de1f124f95a libpurple/protocols/jabber/jabber.h --- 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