changeset 6764:6d0d4e9149b9

[gaim-migrate @ 7296] well, jabber.org is being a pain in the moment, as is my server. but this seems to work, so here it is. Jabber SSL support. Make sure you set the port to 5223 and check the "Use SSL" checkbox in the account editor. committer: Tailor Script <tailor@pidgin.im>
author Nathan Walp <nwalp@pidgin.im>
date Sat, 06 Sep 2003 16:04:41 +0000
parents 362e60e7c265
children 34fefdecf2d3
files src/protocols/jabber/jabber.c src/ssl-gnutls.c src/ssl-nss.c src/sslconn.c src/sslconn.h
diffstat 5 files changed, 173 insertions(+), 83 deletions(-) [+]
line wrap: on
line diff
--- a/src/protocols/jabber/jabber.c	Sat Sep 06 15:15:24 2003 +0000
+++ b/src/protocols/jabber/jabber.c	Sat Sep 06 16:04:41 2003 +0000
@@ -36,6 +36,7 @@
 #include "request.h"
 #include "util.h"
 #include "html.h"
+#include "sslconn.h"
 
 /* XXX */
 #include "gaim.h"
@@ -110,6 +111,8 @@
 
 	void *priv;
 
+	GaimSslConnection *gsc;
+
 } *gjconn, gjconn_struct;
 
 typedef void (*gjconn_state_h)(gjconn gjc, int state);
@@ -510,7 +513,10 @@
 	gjab_send_raw(gjc, "</stream:stream>");
 	gjc->state = JCONN_STATE_OFF;
 	gjc->was_connected = 0;
-	close(gjc->fd);
+	if(gjc->gsc)
+		gaim_ssl_close(gjc->gsc);
+	else
+		close(gjc->fd);
 	gjc->fd = -1;
 	XML_ParserFree(gjc->parser);
 	gjc->parser = NULL;
@@ -553,14 +559,22 @@
 	if (gjc && gjc->state != JCONN_STATE_OFF) {
 		char *buf = xmlnode2str(x);
 		if (buf) {
+			if(gjc->gsc) {
+				if(gaim_ssl_write(gjc->gsc, buf, strlen(buf)) < 0) {
+					gaim_connection_error(GJ_GC(gjc), _("Write error"));
+				} else {
+					gaim_debug(GAIM_DEBUG_MISC, "jabber", "gjab_send (ssl): %s\n", buf);
+				}
+			} else {
 #ifndef _WIN32
-			if(write(gjc->fd, buf, strlen(buf)) < 0) {
+				if(write(gjc->fd, buf, strlen(buf)) < 0) {
 #else
-			if(send(gjc->fd, buf, strlen(buf), 0) < 0) {
+				if(send(gjc->fd, buf, strlen(buf), 0) < 0) {
 #endif
-				gaim_connection_error(GJ_GC(gjc), _("Write error"));
-			} else {
-				gaim_debug(GAIM_DEBUG_MISC, "jabber", "gjab_send: %s\n", buf);
+					gaim_connection_error(GJ_GC(gjc), _("Write error"));
+				} else {
+					gaim_debug(GAIM_DEBUG_MISC, "jabber", "gjab_send: %s\n", buf);
+				}
 			}
 		}
 	}
@@ -572,16 +586,24 @@
 		/*
 		 * JFIXME: No error detection?!?!
 		 */
+		if(gjc->gsc) {
+			if(gaim_ssl_write(gjc->gsc, str, strlen(str)) < 0) {
+				gaim_connection_error(GJ_GC(gjc), _("Write error"));
+			} else {
+				gaim_debug(GAIM_DEBUG_MISC, "jabber", "gjab_send_raw (ssl): %s\n", str);
+			}
+		} else {
 #ifndef _WIN32
-		if(write(gjc->fd, str, strlen(str)) < 0) {
+			if(write(gjc->fd, str, strlen(str)) < 0) {
 #else
-		if(send(gjc->fd, str, strlen(str), 0) < 0) {
+			if(send(gjc->fd, str, strlen(str), 0) < 0) {
 #endif
-			gaim_connection_error(GJ_GC(gjc), _("Write error"));
+				gaim_connection_error(GJ_GC(gjc), _("Write error"));
+			}
+			/* printing keepalives to the debug window is really annoying */
+			if(strcmp(str, JABBER_KEEPALIVE_STRING))
+				gaim_debug(GAIM_DEBUG_MISC, "jabber", "gjab_send_raw: %s\n", str);
 		}
-		/* printing keepalives to the debug window is really annoying */
-		if(strcmp(str, JABBER_KEEPALIVE_STRING))
-			gaim_debug(GAIM_DEBUG_MISC, "jabber", "gjab_send_raw: %s\n", str);
 	}
 }
 
@@ -682,6 +704,28 @@
 	}
 }
 
+static void gjab_ssl_recv(gpointer data, GaimSslConnection *gsc,
+		GaimInputCondition cond)
+{
+	static char buf[4096];
+	int len;
+	GaimConnection *gc = data;
+	struct jabber_data *jd = gc->proto_data;
+	gjconn gjc = jd->gjc;
+
+	if (!gjc || gjc->state == JCONN_STATE_OFF)
+		return;
+
+	if((len = gaim_ssl_read(gsc, buf, sizeof(buf) -1)) > 0) {
+		buf[len] = '\0';
+		gaim_debug(GAIM_DEBUG_MISC, "jabber",
+				"input (ssl) (len %d): %s\n", len, buf);
+		XML_Parse(gjc->parser, buf, len, 0);
+	} else if(len < 0) {
+		STATE_EVT(JCONN_STATE_OFF)
+	}
+}
+
 static void startElement(void *userdata, const char *name, const char **attribs)
 {
 	xmlnode x;
@@ -752,10 +796,52 @@
 		xmlnode_insert_cdata(gjc->current, s, slen);
 }
 
-static void gjab_connected(gpointer data, gint source, GaimInputCondition cond)
+
+static void gjab_start_stream(gjconn gjc)
 {
 	xmlnode x;
 	char *t, *t2;
+
+	gjc->state = JCONN_STATE_CONNECTED;
+	STATE_EVT(JCONN_STATE_CONNECTED)
+
+	/* start stream */
+	x = jutil_header(NS_CLIENT, gjc->user->server);
+	t = xmlnode2str(x);
+	/* this is ugly, we can create the string here instead of jutil_header */
+	/* what do you think about it? -madcat */
+	t2 = strstr(t, "/>");
+	*t2++ = '>';
+	*t2 = '\0';
+	gjab_send_raw(gjc, "<?xml version='1.0'?>");
+	gjab_send_raw(gjc, t);
+	xmlnode_free(x);
+}
+
+static void gjab_ssl_connected(gpointer data, GaimSslConnection *gsc,
+		GaimInputCondition cond)
+{
+	GaimConnection *gc = data;
+	struct jabber_data *jd;
+	gjconn gjc;
+
+	if (!g_list_find(gaim_connections_get_all(), gc)) {
+		gaim_ssl_close(gsc);
+		return;
+	}
+
+	jd = gc->proto_data;
+	gjc = jd->gjc;
+
+	gjab_start_stream(gjc);
+
+	/* this seems wrong, but... */
+
+	gaim_ssl_input_add(gsc, gjab_ssl_recv, gc);
+}
+
+static void gjab_connected(gpointer data, gint source, GaimInputCondition cond)
+{
 	GaimConnection *gc = data;
 	struct jabber_data *jd;
 	gjconn gjc;
@@ -775,22 +861,8 @@
 		return;
 	}
 
-	gjc->state = JCONN_STATE_CONNECTED;
-	STATE_EVT(JCONN_STATE_CONNECTED)
-
-	/* start stream */
-	x = jutil_header(NS_CLIENT, gjc->user->server);
-	t = xmlnode2str(x);
-	/* this is ugly, we can create the string here instead of jutil_header */
-	/* what do you think about it? -madcat */
-	t2 = strstr(t, "/>");
-	*t2++ = '>';
-	*t2 = '\0';
-	gjab_send_raw(gjc, "<?xml version='1.0'?>");
-	gjab_send_raw(gjc, t);
-	xmlnode_free(x);
-
-	gc = GJ_GC(gjc);
+	gjab_start_stream(gjc);
+
 	gc->inpa = gaim_input_add(gjc->fd, GAIM_INPUT_READ, jabber_callback, gc);
 }
 
@@ -815,10 +887,19 @@
 	XML_SetElementHandler(gjc->parser, startElement, endElement);
 	XML_SetCharacterDataHandler(gjc->parser, charData);
 
-	rc = gaim_proxy_connect(account, server, port, gjab_connected, GJ_GC(gjc));
-	if (!account->gc || (rc != 0)) {
-		STATE_EVT(JCONN_STATE_OFF)
-		return;
+	if(gaim_account_get_bool(account, "ssl", FALSE)
+			&& gaim_ssl_is_supported()) {
+		gjc->gsc = gaim_ssl_connect(account, server, port,
+				gjab_ssl_connected, GJ_GC(gjc));
+	}
+
+	if(!gjc->gsc) {
+		rc = gaim_proxy_connect(account, server, port, gjab_connected,
+				GJ_GC(gjc));
+		if (!account->gc || (rc != 0)) {
+			STATE_EVT(JCONN_STATE_OFF)
+				return;
+		}
 	}
 }
 
@@ -4426,6 +4507,13 @@
 	prpl_info.user_splits = g_list_append(prpl_info.user_splits, split);
 
 	/* Account Options */
+
+	if(gaim_ssl_is_supported()) {
+		option = gaim_account_option_bool_new(_("Use SSL"), "ssl", FALSE);
+		prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
+				option);
+	}
+
 	option = gaim_account_option_int_new(_("Port"), "port", DEFAULT_PORT);
 	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options,
 											   option);
--- a/src/ssl-gnutls.c	Sat Sep 06 15:15:24 2003 +0000
+++ b/src/ssl-gnutls.c	Sat Sep 06 16:04:41 2003 +0000
@@ -60,16 +60,6 @@
 }
 
 static void
-input_func(gpointer data, gint source, GaimInputCondition cond)
-{
-	GaimSslConnection *gsc = (GaimSslConnection *)data;
-
-	gaim_debug_misc("gnutls", "In input_func\n");
-
-	gsc->input_func(gsc->user_data, gsc, cond);
-}
-
-static void
 ssl_gnutls_connect_cb(gpointer data, gint source, GaimInputCondition cond)
 {
 	GaimSslConnection *gsc = (GaimSslConnection *)data;
@@ -103,14 +93,12 @@
 	{
 		gaim_debug_error("gnutls", "Handshake failed\n");
 
+		/* XXX: notify the guy expecting the callback somehow? */
 		gaim_ssl_close(gsc);
 	}
 	else
 	{
-		gaim_debug_info("gnutls", "Adding input handler.\n");
-		gsc->inpa = gaim_input_add(gsc->fd,
-								   GAIM_INPUT_READ | GAIM_INPUT_WRITE,
-								   input_func, gsc);
+		gsc->connect_cb(gsc->connect_cb_data, gsc, cond);
 	}
 }
 
--- a/src/ssl-nss.c	Sat Sep 06 15:15:24 2003 +0000
+++ b/src/ssl-nss.c	Sat Sep 06 16:04:41 2003 +0000
@@ -117,33 +117,6 @@
 	return status;
 }
 
-static void
-input_func(gpointer data, gint source, GaimInputCondition cond)
-{
-	GaimSslConnection *gsc = (GaimSslConnection *)data;
-#if 0
-	GaimSslNssData *nss_data = GAIM_SSL_NSS_DATA(gsc);
-	char *cp, *ip, *sp;
-	int op, kp0, kp1;
-	int result;
-
-	result = SSL_SecurityStatus(nss_data->in, &op, &cp, &kp0,
-								&kp1, &ip, &sp);
-
-	gaim_debug_misc("nss",
-		"bulk cipher %s, %d secret key bits, %d key bits, status: %d\n"
-		"subject DN: %s\n"
-		"issuer  DN: %s\n",
-		cp, kp1, kp0, op, sp, ip);
-
-	PR_Free(cp);
-	PR_Free(ip);
-	PR_Free(sp);
-#endif
-
-	gsc->input_func(gsc->user_data, gsc, cond);
-}
-
 static gboolean
 ssl_nss_init(void)
 {
@@ -227,9 +200,14 @@
 		return;
 	}
 
-	gsc->inpa = gaim_input_add(gsc->fd,
-							   GAIM_INPUT_READ | GAIM_INPUT_WRITE,
-							   input_func, gsc);
+	gsc->connect_cb(gsc->connect_cb_data, gsc, cond);
+}
+
+static void
+ssl_nss_recv_cb(gpointer data, gint source, GaimInputCondition cond)
+{
+	GaimSslConnection *gsc = data;
+	gsc->recv_cb(gsc->recv_cb_data, gsc, cond);
 }
 
 static void
@@ -264,6 +242,7 @@
 	ssl_nss_init,
 	ssl_nss_uninit,
 	ssl_nss_connect_cb,
+	ssl_nss_recv_cb,
 	ssl_nss_close,
 	ssl_nss_read,
 	ssl_nss_write
--- a/src/sslconn.c	Sat Sep 06 15:15:24 2003 +0000
+++ b/src/sslconn.c	Sat Sep 06 16:04:41 2003 +0000
@@ -93,8 +93,8 @@
 
 	gsc->host       = g_strdup(host);
 	gsc->port       = port;
-	gsc->user_data  = data;
-	gsc->input_func = func;
+	gsc->connect_cb_data  = data;
+	gsc->connect_cb = func;
 
 	i = gaim_proxy_connect(account, host, port, ops->connect_cb, gsc);
 
@@ -109,6 +109,29 @@
 	return (GaimSslConnection *)gsc;
 }
 
+static void
+recv_cb(gpointer data, gint source, GaimInputCondition cond)
+{
+	GaimSslConnection *gsc = data;
+
+	gsc->recv_cb(gsc->recv_cb_data, gsc, cond);
+}
+
+void
+gaim_ssl_input_add(GaimSslConnection *gsc, GaimSslInputFunction func, void *data)
+{
+	GaimSslOps *ops;
+
+	g_return_if_fail(func != NULL);
+	g_return_if_fail(gaim_ssl_is_supported());
+
+	ops = gaim_ssl_get_ops();
+
+	gsc->recv_cb_data = data;
+	gsc->recv_cb = func;
+	gsc->inpa = gaim_input_add(gsc->fd, GAIM_INPUT_READ, recv_cb, gsc);
+}
+
 GaimSslConnection *
 gaim_ssl_connect_fd(GaimAccount *account, int fd,
 					GaimSslInputFunction func, void *data)
@@ -133,8 +156,8 @@
 
 	gsc = g_new0(GaimSslConnection, 1);
 
-	gsc->user_data  = data;
-	gsc->input_func = func;
+	gsc->connect_cb_data  = data;
+	gsc->connect_cb = func;
 
 	ops->connect_cb(gsc, fd, GAIM_INPUT_READ);
 
--- a/src/sslconn.h	Sat Sep 06 15:15:24 2003 +0000
+++ b/src/sslconn.h	Sat Sep 06 16:04:41 2003 +0000
@@ -36,8 +36,10 @@
 {
 	char *host;
 	int port;
-	void *user_data;
-	GaimSslInputFunction input_func;
+	void *connect_cb_data;
+	GaimSslInputFunction connect_cb;
+	void *recv_cb_data;
+	GaimSslInputFunction recv_cb;
 
 	int fd;
 	int inpa;
@@ -93,6 +95,16 @@
 									void *data);
 
 /**
+ * Adds an input watcher for the specified SSL connection.
+ *
+ * @param gsc   The SSL connection handle.
+ * @param func  The callback function.
+ * @param data  User-defined data.
+ */
+void gaim_ssl_input_add(GaimSslConnection *gsc, GaimSslInputFunction func,
+									void *data);
+
+/**
  * Makes a SSL connection using an already open file descriptor.
  *
  * @param account The account making the connection.