diff src/protocols/jabber/jabber.c @ 3630:9682c0e022c6

[gaim-migrate @ 3753] Yeah this will probably break a lot of shit knowing my luck. But hey, I really don't care what people thnk. committer: Tailor Script <tailor@pidgin.im>
author Rob Flynn <gaim@robflynn.com>
date Fri, 11 Oct 2002 03:14:01 +0000
parents 95669ff6dc3b
children 5e50f6746509
line wrap: on
line diff
--- a/src/protocols/jabber/jabber.c	Fri Oct 11 02:10:08 2002 +0000
+++ b/src/protocols/jabber/jabber.c	Fri Oct 11 03:14:01 2002 +0000
@@ -20,23 +20,27 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  */
-
 #ifdef HAVE_CONFIG_H
-#include "config.h"
+#include <config.h>
 #endif
 
-
+#ifndef _WIN32
 #include <netdb.h>
-#include <unistd.h>
-#include <errno.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
+#include <sys/socket.h>
+#include <sys/utsname.h>
+#include <unistd.h>
+#else
+#include <winsock.h>
+#include "utsname.h"
+#endif
+
+#include <errno.h>
 #include <string.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <time.h>
-#include <sys/socket.h>
-#include <sys/utsname.h>
 #include <sys/stat.h>
 #include "multi.h"
 #include "prpl.h"
@@ -50,6 +54,10 @@
 #include "jabber.h"
 #include "proxy.h"
 
+#ifdef _WIN32
+#include "win32dep.h"
+#endif
+
 #include "pixmaps/protocols/jabber/available.xpm"
 #include "pixmaps/protocols/jabber/available-away.xpm"
 #include "pixmaps/protocols/jabber/available-chat.xpm"
@@ -57,6 +65,9 @@
 #include "pixmaps/protocols/jabber/available-dnd.xpm"
 #include "pixmaps/protocols/jabber/available-error.xpm"
 
+/* for win32 compatability */
+G_MODULE_IMPORT GSList *connections;
+
 /* The priv member of gjconn's is a gaim_connection for now. */
 #define GJ_GC(x) ((struct gaim_connection *)(x)->priv)
 
@@ -140,6 +151,7 @@
 	time_t idle;
 	gboolean die;
 	GHashTable *buddies;
+	GSList *file_transfers;
 };
 
 /*
@@ -229,6 +241,8 @@
 
 static void jabber_handlevcard(gjconn, xmlnode, char *);
 
+static char *jabber_normalize(const char *s);
+
 static char *create_valid_jid(const char *given, char *server, char *resource)
 {
 	char *valid;
@@ -492,7 +506,11 @@
 	gjab_send_raw(gjc, "</stream:stream>");
 	gjc->state = JCONN_STATE_OFF;
 	gjc->was_connected = 0;
+#ifndef _WIN32
 	close(gjc->fd);
+#else
+	closesocket(gjc->fd);
+#endif
 	gjc->fd = -1;
 	XML_ParserFree(gjc->parser);
 	gjc->parser = NULL;
@@ -535,7 +553,11 @@
 	if (gjc && gjc->state != JCONN_STATE_OFF) {
 		char *buf = xmlnode2str(x);
 		if (buf)
+#ifndef _WIN32
 			write(gjc->fd, buf, strlen(buf));
+#else
+			send(gjc->fd, buf, strlen(buf), 0);
+#endif
 		debug_printf("gjab_send: %s\n", buf);
 	}
 }
@@ -546,7 +568,11 @@
 		/*
 		 * JFIXME: No error detection?!?!
 		 */
+#ifndef _WIN32
 		if(write(gjc->fd, str, strlen(str)) < 0) {
+#else
+		if(send(gjc->fd, str, strlen(str), 0) < 0) {
+#endif
 			fprintf(stderr, "DBG: Problem sending.  Error: %d\n", errno);
 			fflush(stderr);
 		}
@@ -636,8 +662,11 @@
 
 	if (!gjc || gjc->state == JCONN_STATE_OFF)
 		return;
-
+#ifndef _WIN32
 	if ((len = read(gjc->fd, buf, sizeof(buf) - 1)) > 0) {
+#else
+	if ((len = recv(gjc->fd, buf, sizeof(buf) - 1, 0)) > 0) {
+#endif
 		struct jabber_data *jd = GJ_GC(gjc)->proto_data;
 		buf[len] = '\0';
 		debug_printf("input (len %d): %s\n", len, buf);
@@ -727,7 +756,11 @@
 	gjconn gjc;
 
 	if (!g_slist_find(connections, gc)) {
+#ifndef _WIN32
 		close(source);
+#else
+		closesocket(source);
+#endif
 		return;
 	}
 
@@ -1901,12 +1934,194 @@
 	xmlnode_free(x);
 }
 
+struct jabber_file_transfer {
+	enum { JFT_SENDFILE_IN, JFT_SENDFILE_OUT } type;
+	struct file_transfer *xfer;
+	char *from;
+	struct g_url *url;
+	char *name;
+	GString *headers;
+
+	int len;
+	int fd;
+	int watcher;
+
+	gboolean sentreq;
+	gboolean newline;
+	gboolean startsaving;
+
+	struct gaim_connection *gc;
+};
+
+static struct jabber_file_transfer *find_jft_by_xfer(struct gaim_connection *gc,
+				struct file_transfer *xfer) {
+	GSList *g = ((struct jabber_data *)gc->proto_data)->file_transfers;
+	struct jabber_file_transfer *f = NULL;
+
+	while(g) {
+		f = (struct jabber_file_transfer *)g->data;
+		if(f->xfer == xfer)
+			break;
+		g = g->next;
+		f = NULL;
+	}
+
+	return f;
+}
+
+static void jabber_http_recv_callback(gpointer data, gint source, GaimInputCondition condition) {
+	struct jabber_file_transfer *jft = data;
+	char test;
+
+	jft->fd = source;
+	if(!jft->sentreq) {
+		char buf[1024];
+		g_snprintf(buf, sizeof(buf), "GET /%s HTTP/1.1\r\nHost: %s\r\n\r\n", jft->url->page, jft->url->address);
+		write(source, buf, strlen(buf));
+		fcntl(source, F_SETFL, O_NONBLOCK);
+		jft->sentreq = TRUE;
+		jft->watcher = gaim_input_add(source, GAIM_INPUT_READ, jabber_http_recv_callback,data);
+		return;
+	}
+
+	if(!jft->startsaving) {
+		if(read(source, &test, sizeof(test)) > 0 || errno == EWOULDBLOCK) {
+			if(errno == EWOULDBLOCK) {
+				errno = 0;
+				return;
+			}
+
+			jft->headers = g_string_append_c(jft->headers, test);
+			if(test == '\r')
+				return;
+			if(test == '\n') {
+				if(jft->newline) {
+					gchar *lenstr = strstr(jft->headers->str, "Content-Length: ");
+					if(lenstr) {
+						sscanf(lenstr, "Content-Length: %d", &jft->len);
+					}
+					jft->startsaving = TRUE;
+				} else
+					jft->newline = TRUE;
+				return;
+			}
+			jft->newline = FALSE;
+			return;
+		} else {
+			gaim_input_remove(jft->watcher);
+			close(source);
+			//FIXME: ft_cancel(NULL, jft->xfer);
+		}
+		return;
+	}
+
+	/* we've parsed the headers, gotten the size, all is good.  now we pass the reception of
+	 * the file off to the core, and leave it in it's capable...err...hands?? */
+	gaim_input_remove(jft->watcher);
+	jft->watcher = 0;
+	transfer_in_do(jft->xfer, jft->fd, jft->name, jft->len);
+}
+
+static void jabber_file_transfer_cancel(struct gaim_connection *gc, struct file_transfer *xfer) {
+	struct jabber_data *jd = gc->proto_data;
+	struct jabber_file_transfer *jft = find_jft_by_xfer(gc, xfer);\
+	xmlnode x,y;
+
+	jd->file_transfers = g_slist_remove(jd->file_transfers, jft);
+
+	gaim_input_remove(jft->watcher);
+	close(jft->fd);
+
+	x = xmlnode_new_tag("iq");
+	xmlnode_put_attrib(x, "type", "error");
+	xmlnode_put_attrib(x, "to", jft->from);
+	y = xmlnode_insert_tag(x, "error");
+	/* FIXME: need to handle other kinds of errors here */
+	xmlnode_put_attrib(y, "code", "406");
+	xmlnode_insert_cdata(y, "File Transfer Refused", -1);
+
+	gjab_send(jd->gjc, x);
+
+	xmlnode_free(x);
+
+	g_string_free(jft->headers, TRUE);
+	g_free(jft->from);
+	g_free(jft->url);
+	g_free(jft->name);
+
+	g_free(jft);
+}
+
+static void jabber_file_transfer_done(struct gaim_connection *gc, struct file_transfer *xfer) {
+	struct jabber_data *jd = gc->proto_data;
+	struct jabber_file_transfer *jft = find_jft_by_xfer(gc, xfer);
+	xmlnode x;
+
+	jd->file_transfers = g_slist_remove(jd->file_transfers, jft);
+
+	gaim_input_remove(jft->watcher);
+	close(jft->fd);
+
+	x = xmlnode_new_tag("iq");
+	xmlnode_put_attrib(x, "type", "result");
+	xmlnode_put_attrib(x, "to", jft->from);
+
+	gjab_send(jd->gjc, x);
+
+	xmlnode_free(x);
+
+	g_string_free(jft->headers, TRUE);
+	g_free(jft->from);
+	g_free(jft->url);
+	g_free(jft->name);
+
+	g_free(jft);
+}
+
+static void jabber_file_transfer_in(struct gaim_connection *gc, struct file_transfer *xfer, int offset) {
+	struct jabber_file_transfer *jft = find_jft_by_xfer(gc, xfer);
+
+	proxy_connect(jft->url->address, jft->url->port, jabber_http_recv_callback, jft);
+}
+
+static void jabber_handleoob(gjconn gjc, xmlnode iqnode) {
+	struct jabber_file_transfer *jft;
+	struct jabber_data *jd = GJ_GC(gjc)->proto_data;
+	char *msg = NULL;
+	xmlnode querynode = xmlnode_get_tag(iqnode, "query");
+	xmlnode urlnode,descnode;
+
+	if(!querynode)
+		return;
+	urlnode = xmlnode_get_tag(querynode, "url");
+	if(!urlnode)
+		return;
+	descnode = xmlnode_get_tag(querynode, "desc");
+	if(descnode)
+		msg = xmlnode_get_data(descnode);
+
+	jft = g_new0(struct jabber_file_transfer, 1);
+	jft->type = JFT_SENDFILE_IN;
+	jft->gc = GJ_GC(gjc);
+	jft->url = parse_url(xmlnode_get_data(urlnode));
+	jft->from = g_strdup(xmlnode_get_attrib(iqnode, "from"));
+	jft->name = g_strdup(g_strrstr(jft->url->page,"/"));
+	if (!jft->name)
+			jft->name = g_strdup(jft->url->page);
+	jft->headers = g_string_new("");
+	jft->len = -1;
+
+	jd->file_transfers = g_slist_append(jd->file_transfers, jft);
+
+	jft->xfer = transfer_in_add(GJ_GC(gjc), jft->from, jft->name, jft->len, 1, msg);
+}
+
 static void jabber_handlelast(gjconn gjc, xmlnode iqnode) {
-   	xmlnode x, querytag;
+	xmlnode x, querytag;
 	char *id, *from;
 	struct jabber_data *jd = GJ_GC(gjc)->proto_data;
 	char idle_time[32];
-	
+
 	id = xmlnode_get_attrib(iqnode, "id");
 	from = xmlnode_get_attrib(iqnode, "from");
 
@@ -1979,6 +2194,8 @@
 			querynode = xmlnode_get_tag(p->x, "query");
 			if (NSCHECK(querynode, "jabber:iq:roster")) {
 				jabber_handlebuddy(gjc, xmlnode_get_firstchild(querynode));
+			} else if(NSCHECK(querynode, "jabber:iq:oob")) {
+				jabber_handleoob(gjc, p->x);
 			}
 		} else if (jpacket_subtype(p) == JPACKET__GET) {
 		   	xmlnode querynode;
@@ -2261,7 +2478,7 @@
 	xmlnode_insert_tag(y, "composing");
 
 	if (message && strlen(message)) {
-		char *utf8 = str_to_utf8(message);
+		char *utf8 = str_to_utf8((char*)message);
 		y = xmlnode_insert_tag(x, "body");
 		xmlnode_insert_cdata(y, utf8, -1);
 		g_free(utf8);
@@ -2748,7 +2965,7 @@
 	g_free(subject);
 
 	if (message && strlen(message)) {
-		char *utf8 = str_to_utf8(message);
+		char *utf8 = str_to_utf8((char*)message);
 		y = xmlnode_insert_tag(x, "body");
 		xmlnode_insert_cdata(y, utf8, -1);
 		g_free(utf8);
@@ -3960,7 +4177,7 @@
 
 static struct prpl *my_protocol = NULL;
 
-void jabber_init(struct prpl *ret)
+G_MODULE_EXPORT void jabber_init(struct prpl *ret)
 {
 	/* the NULL's aren't required but they're nice to have */
 	struct proto_user_opt *puo;
@@ -4009,7 +4226,12 @@
 	ret->send_typing = jabber_send_typing;
 	ret->convo_closed = jabber_convo_closed;
 	ret->rename_group = jabber_rename_group;
-       
+	ret->file_transfer_out = NULL; /* TODO */
+	ret->file_transfer_in = jabber_file_transfer_in;
+	ret->file_transfer_data_chunk = NULL; /* TODO */
+	ret->file_transfer_done = jabber_file_transfer_done;
+	ret->file_transfer_cancel = jabber_file_transfer_cancel;
+
 	puo = g_new0(struct proto_user_opt, 1);
 	puo->label = g_strdup("Port:");
 	puo->def = g_strdup("5222");
@@ -4021,7 +4243,7 @@
 
 #ifndef STATIC
 
-void *gaim_prpl_init(struct prpl *prpl)
+G_MODULE_EXPORT void gaim_prpl_init(struct prpl *prpl)
 {
 	jabber_init(prpl);
 	prpl->plug->desc.api_version = PLUGIN_API_VERSION;