diff src/toc.c @ 1457:c6f9d0cdaa00

[gaim-migrate @ 1467] all of toc in one file; rewritten file transfer. no get file yet; just send file. but why would you want to send files to people anyway? ;) committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Thu, 01 Feb 2001 11:29:15 +0000
parents f16e17d42b43
children d6340f73e94b
line wrap: on
line diff
--- a/src/toc.c	Thu Feb 01 08:37:16 2001 +0000
+++ b/src/toc.c	Thu Feb 01 11:29:15 2001 +0000
@@ -46,7 +46,7 @@
 #include "pixmaps/dt_icon.xpm"
 #include "pixmaps/free_icon.xpm"
 
-#define REVISION "gaim:$Revision: 1445 $"
+#define REVISION "gaim:$Revision: 1467 $"
 
 #define TYPE_SIGNON    1
 #define TYPE_DATA      2
@@ -69,6 +69,27 @@
 #define STATE_ONLINE 3
 #define STATE_PAUSE 4
 
+#define VOICE_UID     "09461341-4C7F-11D1-8222-444553540000"
+#define FILE_SEND_UID "09461343-4C7F-11D1-8222-444553540000"
+#define IMAGE_UID     "09461345-4C7F-11D1-8222-444553540000"
+#define B_ICON_UID    "09461346-4C7F-11D1-8222-444553540000"
+#define STOCKS_UID    "09461347-4C7F-11D1-8222-444553540000"
+#define FILE_GET_UID  "09461348-4C7F-11D1-8222-444553540000"
+#define GAMES_UID     "0946134a-4C7F-11D1-8222-444553540000"
+
+struct ft_request {
+	struct gaim_connection *gc;
+        char *user;
+	char UID[2048];
+        char *cookie;
+        char *ip;
+        int port;
+        char *message;
+        char *filename;
+	int files;
+        int size;
+};
+
 struct toc_data {
 	int toc_fd;
 	int seqno;
@@ -98,6 +119,7 @@
 
 static void toc_callback(gpointer, gint, GdkInputCondition);
 static unsigned char *roast_password(char *);
+static void accept_file_dialog(struct ft_request *);
 
 /* ok. this function used to take username/password, and return 0 on success.
  * now, it takes username/password, and returns NULL on error or a new gaim_connection
@@ -161,7 +183,7 @@
 	close(((struct toc_data *)gc->proto_data)->toc_fd);
 }
 
-int sflap_send(struct gaim_connection *gc, char *buf, int olen, int type)
+static int sflap_send(struct gaim_connection *gc, char *buf, int olen, int type)
 {
 	int len;
 	int slen = 0;
@@ -337,8 +359,7 @@
 		g_snprintf(snd, sizeof snd, "toc_init_done");
 		sflap_send(gc, snd, -1, TYPE_DATA);
 
-		g_snprintf(snd, sizeof snd, "toc_set_caps %s %s",
-			   FILE_SEND_UID, FILE_GET_UID);
+		g_snprintf(snd, sizeof snd, "toc_set_caps %s", FILE_SEND_UID);
 		sflap_send(gc, snd, -1, TYPE_DATA);
 
 		return;
@@ -561,7 +582,7 @@
 			int unk[4], i;
 			char *messages[4], *tmp, *name;
 			int subtype, files, totalsize = 0;
-			struct file_transfer *ft;
+			struct ft_request *ft;
 
 			for (i = 0; i < 4; i++) {
 				sscanf(strtok(NULL, ":"), "%d", &unk[i]);
@@ -588,7 +609,7 @@
 
 			name = tmp + 8;
 
-			ft = g_new0(struct file_transfer, 1);
+			ft = g_new0(struct ft_request, 1);
 			ft->cookie = g_strdup(cookie);
 			ft->ip = g_strdup(pip);
 			ft->port = port;
@@ -599,6 +620,7 @@
 			ft->filename = g_strdup(name);
 			ft->user = g_strdup(user);
 			ft->size = totalsize;
+			ft->files = files;
 			g_snprintf(ft->UID, sizeof(ft->UID), "%s", FILE_SEND_UID);
 			ft->gc = gc;
 
@@ -606,12 +628,15 @@
 			for (i--; i >= 0; i--)
 				g_free(messages[i]);
 
+			debug_printf("English translation of RVOUS_PROPOSE: %s requests Send File (i.e."
+				" send a file to you); %s:%d (verified_ip:port), %d files at"
+				" total size of %ld bytes.\n", user, vip, port, files, totalsize);
 			accept_file_dialog(ft);
 		} else if (!strcmp(uuid, FILE_GET_UID)) {
-			/* they want us to send a file */
+			/* they want us to send a file
 			int unk[4], i;
 			char *messages[4], *tmp;
-			struct file_transfer *ft;
+			struct ft_request *ft;
 
 			for (i = 0; i < 4; i++) {
 				sscanf(strtok(NULL, ":"), "%d", unk + i);
@@ -621,7 +646,7 @@
 			}
 			tmp = frombase64(strtok(NULL, ":"));
 
-			ft = g_new0(struct file_transfer, 1);
+			ft = g_new0(struct ft_request, 1);
 			ft->cookie = g_strdup(cookie);
 			ft->ip = g_strdup(pip);
 			ft->port = port;
@@ -638,6 +663,7 @@
 				g_free(messages[i]);
 
 			accept_file_dialog(ft);
+			*/
 		} else if (!strcmp(uuid, VOICE_UID)) {
 			/* oh goody. voice over ip. fun stuff. */
 		} else if (!strcmp(uuid, B_ICON_UID)) {
@@ -1219,3 +1245,284 @@
 	ret->chat_send = toc_chat_send;
 	ret->keepalive = toc_keepalive;
 }
+
+/*********
+ * RVOUS ACTIONS
+ ********/
+
+struct file_header {
+	char  magic[4];		/* 0 */
+	short hdrlen;		/* 4 */
+	short hdrtype;		/* 6 */
+	char  bcookie[8];	/* 8 */
+	short encrypt;		/* 16 */
+	short compress;		/* 18 */
+	short totfiles;		/* 20 */
+	short filesleft;	/* 22 */
+	short totparts;		/* 24 */
+	short partsleft;	/* 26 */
+	long  totsize;		/* 28 */
+	long  size;		/* 32 */
+	long  modtime;		/* 36 */
+	long  checksum;		/* 40 */
+	long  rfrcsum;		/* 44 */
+	long  rfsize;		/* 48 */
+	long  cretime;		/* 52 */
+	long  rfcsum;		/* 56 */
+	long  nrecvd;		/* 60 */
+	long  recvcsum;		/* 64 */
+	char  idstring[32];	/* 68 */
+	char  flags;		/* 100 */
+	char  lnameoffset;	/* 101 */
+	char  lsizeoffset;	/* 102 */
+	char  dummy[69];	/* 103 */
+	char  macfileinfo[16];	/* 172 */
+	short nencode;		/* 188 */
+	short nlanguage;	/* 190 */
+	char  name[64];		/* 192 */
+				/* 256 */
+};
+
+struct file_transfer {
+	struct file_header hdr;
+
+	struct gaim_connection *gc;
+
+	char *user;
+	char *cookie;
+	char *ip;
+	int port;
+	long size;
+
+	GtkWidget *window;
+	FILE *file;
+	int recvsize;
+
+	gint inpa;
+};
+
+static void toc_get_file(gpointer a, struct file_transfer *ft) {
+	char *dirname = gtk_file_selection_get_filename(GTK_FILE_SELECTION(ft->window));
+
+	if (file_is_dir(dirname, ft->window))
+		return;
+	gtk_widget_destroy(ft->window);
+}
+
+static void debug_header(struct file_transfer *ft) {
+	struct file_header *f = (struct file_header *)ft;
+	debug_printf("TOC FT HEADER:\n"
+			"\t%s %d 0x%04x\n"
+			"\t%s %d %d\n"
+			"\t%d %d %d %d %ld %ld\n"
+			"\t%ld %ld %ld %ld %ld %ld %ld %ld\n"
+			"\t%s\n"
+			"\t0x%02x, 0x%02x, 0x%02x\n"
+			"\t%s %s\n"
+			"\t%d %d\n"
+			"\t%s\n",
+			f->magic, ntohs(f->hdrlen), f->hdrtype,
+			f->bcookie, ntohs(f->encrypt), ntohs(f->compress),
+			ntohs(f->totfiles), ntohs(f->filesleft), ntohs(f->totparts),
+				ntohs(f->partsleft), ntohl(f->totsize), ntohl(f->size),
+			ntohl(f->modtime), ntohl(f->checksum), ntohl(f->rfrcsum), ntohl(f->rfsize),
+				ntohl(f->cretime), ntohl(f->rfcsum), ntohl(f->nrecvd),
+				ntohl(f->recvcsum),
+			f->idstring,
+			f->flags, f->lnameoffset, f->lsizeoffset,
+			f->dummy, f->macfileinfo,
+			ntohs(f->nencode), ntohs(f->nlanguage),
+			f->name);
+}
+
+static void toc_send_file_callback(gpointer data, gint source, GdkInputCondition cond) {
+	char buf[BUF_LONG];
+	int rt, i;
+
+	struct file_transfer *ft = data;
+
+	if (cond & GDK_INPUT_EXCEPTION) {
+		gdk_input_remove(ft->inpa);
+		close(source);
+		g_free(ft->user);
+		g_free(ft->ip);
+		g_free(ft->cookie);
+		fclose(ft->file);
+		g_free(ft);
+		return;
+	}
+
+	if (ft->hdr.hdrtype != 0x202) {
+		char *buf = frombase64(ft->cookie);
+
+		read(source, ft, 8);
+		read(source, &ft->hdr.bcookie, MIN(256 - 8, ntohs(ft->hdr.hdrlen) - 8));
+		debug_header(ft);
+
+		ft->hdr.hdrtype = 0x202;
+		memcpy(ft->hdr.bcookie, buf, 8);
+		g_free(buf);
+		ft->hdr.encrypt = 0; ft->hdr.compress = 0;
+		debug_header(ft);
+		write(source, ft, 256);
+
+		return;
+	}
+
+	rt = read(source, buf, MIN(ntohl(ft->hdr.size) - ft->recvsize, 1024));
+	if (rt < 0) {
+		do_error_dialog("File transfer failed; other side probably canceled.", "Error");
+		gdk_input_remove(ft->inpa);
+		close(source);
+		g_free(ft->user);
+		g_free(ft->ip);
+		g_free(ft->cookie);
+		fclose(ft->file);
+		g_free(ft);
+		return;
+	}
+	ft->recvsize += rt;
+	for (i = 0; i < rt; i++)
+		fprintf(ft->file, "%c", buf[i]);
+
+	if (ft->recvsize == ntohl(ft->hdr.size)) {
+		ft->hdr.hdrtype = 0x402;
+		ft->hdr.filesleft = htons(ntohs(ft->hdr.filesleft) - 1);
+		ft->hdr.partsleft = htons(ntohs(ft->hdr.partsleft) - 1);
+		ft->hdr.recvcsum = ft->hdr.checksum; /* uh... */
+		ft->hdr.nrecvd = htons(ntohs(ft->hdr.nrecvd) + 1);
+		ft->hdr.flags = 0;
+		write(source, ft, 256);
+		ft->recvsize = 0;
+		if (ft->hdr.filesleft != 0) {
+			char *msg = g_strdup_printf("%s tried to send you more than one file, but"
+					" currently that is not possible.", ft->user);
+			do_error_dialog(msg, "Error");
+			g_free(msg);
+		}
+		gdk_input_remove(ft->inpa);
+		close(source);
+		g_free(ft->user);
+		g_free(ft->ip);
+		g_free(ft->cookie);
+		fclose(ft->file);
+		g_free(ft);
+	}
+}
+
+static void toc_send_file(gpointer a, struct file_transfer *old_ft) {
+	struct file_transfer *ft;
+	char *dirname = gtk_file_selection_get_filename(GTK_FILE_SELECTION(old_ft->window));
+	int fd;
+	struct aim_user *user;
+	char *buf;
+
+	if (file_is_dir(dirname, old_ft->window))
+		return;
+	ft = g_new0(struct file_transfer, 1);
+	ft->file = fopen(dirname, "w");
+	if (!ft->file) {
+		do_error_dialog(_("Could not open file for writing!"), _("Error"));
+		g_free(ft);
+		gtk_widget_destroy(old_ft->window);
+		return;
+	}
+
+	ft->cookie = g_strdup(old_ft->cookie);
+	ft->user = g_strdup(old_ft->user);
+	ft->ip = g_strdup(old_ft->ip);
+	ft->port = old_ft->port;
+	ft->gc = old_ft->gc;
+	user = ft->gc->user;
+	gtk_widget_destroy(old_ft->window);
+
+	buf = g_strdup_printf("toc_rvous_accept %s %s %s", ft->user, ft->cookie, FILE_SEND_UID);
+	sflap_send(ft->gc, buf, -1, TYPE_DATA);
+	g_free(buf);
+
+	fd =
+	    proxy_connect(ft->ip, ft->port,
+			  user->proto_opt[USEROPT_SOCKSHOST],
+			  atoi(user->proto_opt[USEROPT_SOCKSPORT]),
+			  atoi(user->proto_opt[USEROPT_PROXYTYPE]));
+	if (fd < 0) {
+		do_error_dialog(_("Could not connect for transfer!"), _("Error"));
+		g_free(ft->cookie);
+		g_free(ft->user);
+		g_free(ft->ip);
+		g_free(ft);
+		return;
+	}
+
+	ft->inpa = gdk_input_add(fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION, toc_send_file_callback, ft);
+}
+
+static void cancel_callback(gpointer a, struct file_transfer *ft) {
+	gtk_widget_destroy(ft->window);
+	if (a == ft->window) {
+		g_free(ft->cookie);
+		g_free(ft->user);
+		g_free(ft->ip);
+		g_free(ft);
+	}
+}
+
+static void toc_accept_ft(gpointer a, struct ft_request *fr) {
+	GtkWidget *window;
+	char buf[BUF_LEN];
+
+	struct file_transfer *ft = g_new0(struct file_transfer, 1);
+	ft->gc = fr->gc;
+	ft->user = g_strdup(fr->user);
+	ft->cookie = g_strdup(fr->cookie);
+	ft->ip = g_strdup(fr->ip);
+	ft->port = fr->port;
+
+	ft->window = window = gtk_file_selection_new(_("Gaim - Save As..."));
+	g_snprintf(buf, sizeof(buf), "%s/%s", g_get_home_dir(), fr->filename ? fr->filename : "");
+	gtk_file_selection_set_filename(GTK_FILE_SELECTION(window), buf);
+	gtk_signal_connect(GTK_OBJECT(window), "destroy",
+			   GTK_SIGNAL_FUNC(cancel_callback), ft);
+	gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(ft->window)->cancel_button), "clicked",
+			   GTK_SIGNAL_FUNC(cancel_callback), ft);
+
+	if (!strcmp(fr->UID, FILE_SEND_UID))
+		gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(window)->ok_button), "clicked",
+				   GTK_SIGNAL_FUNC(toc_send_file), ft);
+	else
+		gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(window)->ok_button), "clicked",
+				   GTK_SIGNAL_FUNC(toc_get_file), ft);
+
+	gtk_widget_show(window);
+}
+
+static void toc_reject_ft(gpointer a, struct ft_request *ft) {
+	g_free(ft->user);
+	g_free(ft->filename);
+	g_free(ft->ip);
+	g_free(ft->cookie);
+	if (ft->message)
+		g_free(ft->message);
+	g_free(ft);
+}
+
+static void accept_file_dialog(struct ft_request *ft) {
+	char buf[BUF_LONG];
+	if (!strcmp(ft->UID, FILE_SEND_UID)) {
+		/* holy crap. who the fuck would transfer gigabytes through AIM?! */
+		static char *sizes[4] = { "bytes", "KB", "MB", "GB" };
+		float size = ft->size;
+		int index = 0;
+		while ((index < 4) && (size > 1024)) {
+			size /= 1024;
+			index++;
+		}
+	        g_snprintf(buf, sizeof(buf), _("%s requests %s to accept %d file%s: %s (%.2f %s)%s%s"),
+				ft->user, ft->gc->username, ft->files, (ft->files == 1) ? "" : "s",
+				ft->filename, size, sizes[index], (ft->message) ? "\n" : "",
+				(ft->message) ? ft->message : "");
+	} else {
+		g_snprintf(buf, sizeof(buf), _("%s requests you to send them a file"), ft->user);
+	}
+	do_ask_dialog(buf, ft, toc_accept_ft, toc_reject_ft);
+}