diff src/protocols/jabber/si.c @ 7395:b250288fa948

[gaim-migrate @ 7990] this would be the non-working start of file transfer (the real way) for jabber also approximately eleventy billion jabber tweaks committer: Tailor Script <tailor@pidgin.im>
author Nathan Walp <nwalp@pidgin.im>
date Fri, 31 Oct 2003 02:43:58 +0000
parents
children 8f4ce853e685
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/protocols/jabber/si.c	Fri Oct 31 02:43:58 2003 +0000
@@ -0,0 +1,270 @@
+/*
+ * gaim - Jabber Protocol Plugin
+ *
+ * Copyright (C) 2003, Nathan Walp <faceprint@faceprint.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include "internal.h"
+#include "debug.h"
+#include "ft.h"
+#include "notify.h"
+#include "util.h"
+
+#include "buddy.h"
+#include "jabber.h"
+#include "iq.h"
+#include "si.h"
+
+#include "si.h"
+
+static GaimXfer *jabber_si_xfer_find_by_id(JabberStream *js, const char *id)
+{
+	GList *xfers;
+
+	if(!id)
+		return NULL;
+
+	for(xfers = js->file_transfers; xfers; xfers = xfers->next) {
+		GaimXfer *xfer = xfers->data;
+		JabberSIXfer *jsx = xfer->data;
+
+		if(!strcmp(jsx->id, id))
+			return xfer;
+	}
+
+	return NULL;
+}
+
+static void
+jabber_si_xfer_ibb_start(JabberStream *js, xmlnode *packet, gpointer data) {
+	GaimXfer *xfer = data;
+	JabberSIXfer *jsx = xfer->data;
+
+	/* Make sure we didn't get an error back */
+
+	/* XXX: OK, here we need to set up a g_idle thing to send messages
+	 * until our eyes bleed, but do it without interfering with normal
+	 * gaim operations.  When we're done, we have to send a <close> like
+	 * we sent the <open> to start this damn thing.  If we're really
+	 * fortunate, Exodus or someone else will implement something to test
+	 * against soon */
+}
+
+void jabber_si_parse(JabberStream *js, xmlnode *packet)
+{
+	GaimXfer *xfer;
+	JabberSIXfer *jsx;
+	xmlnode *si, *feature, *x, *field, *value;
+
+	si = xmlnode_get_child(packet, "si");
+
+	xfer = jabber_si_xfer_find_by_id(js, xmlnode_get_attrib(si, "id"));
+
+	if(!xfer)
+		return;
+
+	jsx = xfer->data;
+
+	if(!(feature = xmlnode_get_child(si, "feature")))
+		return;
+
+	for(x = feature->child; x; x = x->next) {
+		const char *xmlns;
+		if(x->type != NODE_TYPE_TAG)
+			continue;
+		if(!(xmlns = xmlnode_get_attrib(x, "xmlns")))
+			continue;
+		if(strcmp(xmlns, "jabber:x:data"))
+			continue;
+		for(field = x->child; field; field = field->next) {
+			const char *var;
+			if(field->type != NODE_TYPE_TAG)
+				continue;
+			if(!(var = xmlnode_get_attrib(field, "var")))
+				continue;
+			if(!strcmp(var, "stream-method")) {
+				if((value = xmlnode_get_child(field, "value"))) {
+					char *val_data = xmlnode_get_data(value);
+					if(!val_data)
+						jsx->stream_method = STREAM_METHOD_UNKNOWN;
+					else if(!strcmp(val_data,
+								"http://jabber.org/protocol/bytestreams"))
+						jsx->stream_method = STREAM_METHOD_BYTESTREAMS;
+					else if(!strcmp(val_data, "http://jabber.org/protocol/ibb"))
+						jsx->stream_method = STREAM_METHOD_IBB;
+					else
+						jsx->stream_method = STREAM_METHOD_UNSUPPORTED;
+					g_free(val_data);
+				}
+			}
+		}
+	}
+	if(jsx->stream_method == STREAM_METHOD_UNKNOWN) {
+		/* XXX */
+	} else if(jsx->stream_method == STREAM_METHOD_UNSUPPORTED) {
+		/* XXX */
+	} else if(jsx->stream_method == STREAM_METHOD_BYTESTREAMS) {
+		/* XXX: open the port and stuff */
+		char *buf;
+		xmlnode *query, *streamhost;
+		JabberIq *iq = jabber_iq_new_query(js, JABBER_IQ_SET,
+				"http://jabber.org/protocol/bytestreams");
+
+		buf = g_strdup_printf("%s/%s", xfer->who, jsx->resource);
+		xmlnode_set_attrib(iq->node, "to", buf);
+		g_free(buf);
+
+		query = xmlnode_get_child(iq->node, "query");
+		xmlnode_set_attrib(query, "sid", jsx->id);
+		streamhost = xmlnode_new_child(query, "streamhost");
+		xmlnode_set_attrib(streamhost, "jid",
+				gaim_account_get_username(js->gc->account));
+		xmlnode_set_attrib(streamhost, "host", xfer->local_ip);
+		buf = g_strdup_printf("%d", xfer->local_port);
+		xmlnode_set_attrib(streamhost, "port", buf);
+		g_free(buf);
+		jabber_iq_send(iq);
+	} else if(jsx->stream_method == STREAM_METHOD_IBB) {
+		char *buf;
+		xmlnode *open;
+		JabberIq *iq = jabber_iq_new(js, JABBER_IQ_SET);
+		buf = g_strdup_printf("%s/%s", xfer->who, jsx->resource);
+		xmlnode_set_attrib(iq->node, "to", buf);
+		g_free(buf);
+
+		open = xmlnode_new_child(iq->node, "open");
+		xmlnode_set_attrib(open, "xmlns", "http://jabber.org/protocol/ibb");
+		xmlnode_set_attrib(open, "sid", jsx->id);
+
+		jabber_iq_set_callback(iq, jabber_si_xfer_ibb_start, xfer);
+
+		jabber_iq_send(iq);
+
+	}
+}
+
+static void jabber_si_xfer_send_request(GaimXfer *xfer)
+{
+	JabberSIXfer *jsx = xfer->data;
+	JabberIq *iq;
+	xmlnode *si, *file, *feature, *x, *field, *option, *value;
+	char buf[32];
+	char *to;
+
+	xfer->filename = g_path_get_basename(xfer->local_filename);
+
+	iq = jabber_iq_new(jsx->js, JABBER_IQ_SET);
+	to = g_strdup_printf("%s/%s", xfer->who, jsx->resource);
+	xmlnode_set_attrib(iq->node, "to", to);
+	g_free(to);
+	si = xmlnode_new_child(iq->node, "si");
+	xmlnode_set_attrib(si, "xmlns", "http://jabber.org/protocol/si");
+	jsx->id = jabber_get_next_id(jsx->js);
+	xmlnode_set_attrib(si, "id", jsx->id);
+	xmlnode_set_attrib(si, "profile",
+			"http://jabber.org/protocol/si/profile/file-transfer");
+
+	file = xmlnode_new_child(si, "file");
+	xmlnode_set_attrib(file, "xmlns",
+			"http://jabber.org/protocol/si/profile/file-transfer");
+	xmlnode_set_attrib(file, "name", xfer->filename);
+	g_snprintf(buf, sizeof(buf), "%d", xfer->size);
+	xmlnode_set_attrib(file, "size", buf);
+	/* maybe later we'll do hash and date attribs */
+
+	feature = xmlnode_new_child(si, "feature");
+	xmlnode_set_attrib(feature, "xmlns",
+			"http://jabber.org/protocol/feature-neg");
+	x = xmlnode_new_child(feature, "x");
+	xmlnode_set_attrib(x, "xmlns", "jabber:x:data");
+	xmlnode_set_attrib(x, "type", "form");
+	field = xmlnode_new_child(x, "field");
+	xmlnode_set_attrib(field, "var", "stream-method");
+	xmlnode_set_attrib(field, "type", "list-single");
+	option = xmlnode_new_child(field, "option");
+	value = xmlnode_new_child(option, "value");
+	xmlnode_insert_data(value, "http://jabber.org/protocol/bytestreams",
+			-1);
+	option = xmlnode_new_child(field, "option");
+	value = xmlnode_new_child(option, "value");
+	xmlnode_insert_data(value, "http://jabber.org/protocol/ibb", -1);
+
+	jabber_iq_send(iq);
+}
+
+void jabber_si_xfer_init(GaimXfer *xfer)
+{
+	JabberSIXfer *jsx = xfer->data;
+	if(gaim_xfer_get_type(xfer) == GAIM_XFER_SEND) {
+		JabberBuddy *jb;
+		JabberBuddyResource *jbr = NULL;
+		GList *resources;
+		GList *xfer_resources = NULL;
+
+		jb = jabber_buddy_find(jsx->js, xfer->who, TRUE);
+		if(!jb)
+			return;
+
+		for(resources = jb->resources; resources; resources = resources->next) {
+			jbr = resources->data;
+			if(jbr->capabilities & JABBER_CAP_SI_FILE_XFER)
+				xfer_resources = g_list_append(xfer_resources, jbr);
+		}
+
+		if(g_list_length(xfer_resources) == 1) {
+			jbr = xfer_resources->data;
+			jsx->resource = g_strdup(jbr->name);
+			jabber_si_xfer_send_request(xfer);
+		} else if(g_list_length(xfer_resources) == 0) {
+			char *buf = g_strdup_printf(_("Could not send %s to %s, protocol not supported."), xfer->filename, xfer->who);
+			gaim_notify_error(jsx->js->gc, _("File Send Failed"),
+					_("File Send Failed"), buf);
+			g_free(buf);
+		} else {
+			/* XXX: ask which resource to send to! */
+		}
+		g_list_free(xfer_resources);
+	}
+}
+
+void jabber_si_xfer_start(GaimXfer *xfer)
+{
+	gaim_debug(GAIM_DEBUG_INFO, "jabber", "in jabber_si_xfer_start\n");
+}
+
+void jabber_si_xfer_end(GaimXfer *xfer)
+{
+	gaim_debug(GAIM_DEBUG_INFO, "jabber", "in jabber_si_xfer_end\n");
+}
+
+void jabber_si_xfer_cancel_send(GaimXfer *xfer)
+{
+	gaim_debug(GAIM_DEBUG_INFO, "jabber", "in jabber_si_xfer_cancel_send\n");
+}
+
+
+void jabber_si_xfer_cancel_recv(GaimXfer *xfer)
+{
+	gaim_debug(GAIM_DEBUG_INFO, "jabber", "in jabber_si_xfer_cancel_recv\n");
+}
+
+
+void jabber_si_xfer_ack(GaimXfer *xfer, const char *buffer, size_t size)
+{
+	gaim_debug(GAIM_DEBUG_INFO, "jabber", "in jabber_si_xfer_ack\n");
+}
+