view src/rvous.c @ 936:311b3f72e7b9

[gaim-migrate @ 946] Sha la la la la la la, mmm, uh huh Was down at the linux expo, starin' at this blue octane, Mr. Flynn strikes up a conversation, with a black haired CS Major. She codes in C while her father hacks, oh, she's suddenly geeky. We all want something geeky, man I wish I was geeky. So come hack in silence down through the morning, sha la la la la la la la, yeah, uhh huh, yeah. Cut up Mark Spencer, show me some of that free software, and pass me a laptop, Mr. Flynn! Believe in me! Help me believe in anything, cuz, I wanna be someone geeky! Mr. Flynn and Me, tell each other linux tales, and we stare at the beautiful penguins, it's lookin' at you, oh no no, it's looking at me. Smiling in the CRT, Mp3's on the stero, when everyone's geeky, you can never be lonely. Well I'm gonna hack a program, syntax highlighting in blue and red and black and grey. All of the beautiful colours are very very meaningingful. Well you know C is my favorite language, I felt so symbolic yesterday. If I knew R. Stallman, I'd buy myself a grey keyboard and hack! Mr. Flynn and me look into the future! We stare at the beautiful Penguins, it's lookin at me, I dont think so, It's looking at me. Hacking in the CRT, I bought myself a grey keyboard, When everbody's geeky, I will never be lonely. I will never be lonely. I'm never gonna be .. loonely. I wanna be a penguin. Eeh -- everybody wanna pass as birds, they all wanna be big big birds, but we got different reasons for that. Believe in me, cuz I don't believe in anything. And I, wanna be someone, geeky, geeky, geeky, yeaaaah! Mr. Flynn and me, storming through the expo, and we stare at the beautiful penguin! It's coming for you, man there's got to be one for me! I wanna be L. Torvalds, Mr. Flynn wishes he was someone just a little more geeky, when everybody loves you, oh son! It's just about as geeky as you can be! Mr. Flynn and me .. starin' at the penguins, when I look at slashdot I wanna see me, staring right back at me. We all wanna be big geeks, but we dont know why and we don't know how .. when everybody loves me I'll be just about as geeky as I can be ... Mr. Flynn and me.. gonna be big geeks. **bows and cheers** Thank You, Thank You. committer: Tailor Script <tailor@pidgin.im>
author Rob Flynn <gaim@robflynn.com>
date Sun, 24 Sep 2000 22:48:54 +0000
parents 2876c40108cd
children 2586b2a3725e
line wrap: on
line source

/*
 * gaim
 *
 * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
 * 
 * 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
 *
 */

#ifdef HAVE_CONFIG_H
#include "../config.h"
#endif
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h> 
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <gtk/gtk.h>
#include "gaim.h"

static void do_send_file(GtkWidget *, struct file_transfer *);
static void do_get_file (GtkWidget *, struct file_transfer *);

static int snpa = -1;

static void toggle(GtkWidget *w, int *m)
{
	*m = !(*m);
}

static void free_ft(struct file_transfer *ft)
{
	if (ft->window) { gtk_widget_destroy(ft->window); ft->window = NULL; }
	if (ft->filename) g_free(ft->filename);
	if (ft->user) g_free(ft->user);
	if (ft->message) g_free(ft->message);
	if (ft->ip) g_free(ft->ip);
	if (ft->cookie) g_free(ft->cookie);
	g_free(ft);
}

static void warn_callback(GtkWidget *widget, struct file_transfer *ft)
{
        show_warn_dialog(ft->user);
}

static void info_callback(GtkWidget *widget, struct file_transfer *ft)
{
        serv_get_info(ft->user);
}

static void cancel_callback(GtkWidget *widget, struct file_transfer *ft)
{
	if (ft->accepted) {
		return;
	}
	
	serv_rvous_cancel(ft->user, ft->cookie, ft->UID);

	free_ft(ft);
}

static void accept_callback(GtkWidget *widget, struct file_transfer *ft)
{
	char buf[BUF_LEN];
	char fname[BUF_LEN];
	char *c;

	if (!strcmp(ft->UID, FILE_SEND_UID)) {
		c = ft->filename + strlen(ft->filename);

		while (c != ft->filename) {
			if (*c == '/' || *c == '\\') {
				strcpy(fname, c+1);
				break;
			}
			c--;
		}

		if (c == ft->filename)
	                strcpy(fname, ft->filename);
	}
	
	gtk_widget_destroy(ft->window);
	ft->window = NULL;
	
	ft->window = gtk_file_selection_new(_("Gaim - Save As..."));

	gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(ft->window));

	if (!strcmp(ft->UID, FILE_SEND_UID))
		g_snprintf(buf, BUF_LEN - 1, "%s/%s", getenv("HOME"), fname);
	else
		g_snprintf(buf, BUF_LEN - 1, "%s/", getenv("HOME"));
	gtk_file_selection_set_filename(GTK_FILE_SELECTION(ft->window), buf);

	gtk_signal_connect(GTK_OBJECT(ft->window), "destroy",
			   GTK_SIGNAL_FUNC(cancel_callback), ft);
                
	if (!strcmp(ft->UID, FILE_SEND_UID)) {
		gtk_signal_connect(GTK_OBJECT(
				GTK_FILE_SELECTION(ft->window)->ok_button),
			        "clicked", GTK_SIGNAL_FUNC(do_get_file), ft);
	} else {
		gtk_signal_connect(GTK_OBJECT(
				GTK_FILE_SELECTION(ft->window)->ok_button),
				"clicked", GTK_SIGNAL_FUNC(do_send_file), ft);
	}
	gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(ft->window)->cancel_button),
			   "clicked", GTK_SIGNAL_FUNC(cancel_callback), ft);

	gtk_widget_show(ft->window);
}

static int read_file_header(int fd, struct file_header *header) {
	char buf[257];
	int read_rv = read(fd, buf, 256);
	if (read_rv < 0)
		return read_rv;
	memcpy(&header->magic,		buf +   0,  4);
	memcpy(&header->hdrlen,		buf +   4,  2);
	memcpy(&header->hdrtype,	buf +   6,  2);
	memcpy(&header->bcookie,	buf +   8,  8);
	memcpy(&header->encrypt,	buf +  16,  2);
	memcpy(&header->compress,	buf +  18,  2);
	memcpy(&header->totfiles,	buf +  20,  2);
	memcpy(&header->filesleft,	buf +  22,  2);
	memcpy(&header->totparts,	buf +  24,  2);
	memcpy(&header->partsleft,	buf +  26,  2);
	memcpy(&header->totsize,	buf +  28,  4);
	memcpy(&header->size,		buf +  32,  4);
	memcpy(&header->modtime,	buf +  36,  4);
	memcpy(&header->checksum,	buf +  40,  4);
	memcpy(&header->rfrcsum,	buf +  44,  4);
	memcpy(&header->rfsize,		buf +  48,  4);
	memcpy(&header->cretime,	buf +  52,  4);
	memcpy(&header->rfcsum,		buf +  56,  4);
	memcpy(&header->nrecvd,		buf +  60,  4);
	memcpy(&header->recvcsum,	buf +  64,  4);
	memcpy(&header->idstring,	buf +  68, 32);
	memcpy(&header->flags,		buf + 100,  1);
	memcpy(&header->lnameoffset,	buf + 101,  1);
	memcpy(&header->lsizeoffset,	buf + 102,  1);
	memcpy(&header->dummy,		buf + 103, 69);
	memcpy(&header->macfileinfo,	buf + 172, 16);
	memcpy(&header->nencode,	buf + 188,  2);
	memcpy(&header->nlanguage,	buf + 190,  2);
	memcpy(&header->name,		buf + 192, 64);
	return read_rv;
}

static int write_file_header(int fd, struct file_header *header) {
	char buf[257];
	memcpy(buf +   0, &header->magic,	 4);
	memcpy(buf +   4, &header->hdrlen,	 2);
	memcpy(buf +   6, &header->hdrtype,	 2);
	memcpy(buf +   8, &header->bcookie,	 8);
	memcpy(buf +  16, &header->encrypt,	 2);
	memcpy(buf +  18, &header->compress,	 2);
	memcpy(buf +  20, &header->totfiles,	 2);
	memcpy(buf +  22, &header->filesleft,	 2);
	memcpy(buf +  24, &header->totparts,	 2);
	memcpy(buf +  26, &header->partsleft,	 2);
	memcpy(buf +  28, &header->totsize,	 4);
	memcpy(buf +  32, &header->size,	 4);
	memcpy(buf +  36, &header->modtime,	 4);
	memcpy(buf +  40, &header->checksum,	 4);
	memcpy(buf +  44, &header->rfrcsum,	 4);
	memcpy(buf +  48, &header->rfsize,	 4);
	memcpy(buf +  52, &header->cretime,	 4);
	memcpy(buf +  56, &header->rfcsum,	 4);
	memcpy(buf +  60, &header->nrecvd,	 4);
	memcpy(buf +  64, &header->recvcsum,	 4);
	memcpy(buf +  68, &header->idstring,	32);
	memcpy(buf + 100, &header->flags,	 1);
	memcpy(buf + 101, &header->lnameoffset,	 1);
	memcpy(buf + 102, &header->lsizeoffset,	 1);
	memcpy(buf + 103, &header->dummy,	69);
	memcpy(buf + 172, &header->macfileinfo,	16);
	memcpy(buf + 188, &header->nencode,	 2);
	memcpy(buf + 190, &header->nlanguage,	 2);
	memcpy(buf + 192, &header->name,	64);
	return write(fd, buf, 256);
}

static void do_get_file(GtkWidget *w, struct file_transfer *ft)
{
	char *file = gtk_file_selection_get_filename(GTK_FILE_SELECTION(ft->window));
	char buf[BUF_LONG];
	char *buf2;
	struct file_header header;
	int read_rv;
	guint32 rcv;
	int cont = 1;
	GtkWidget *fw = NULL, *fbar = NULL, *label = NULL;
	GtkWidget *button = NULL, *pct = NULL;

	if (!(ft->f = fopen(file,"w"))) {
                g_snprintf(buf, BUF_LONG / 2, _("Error writing file %s"), file);
		do_error_dialog(buf, _("Error"));
		ft->accepted = 0;
		accept_callback(NULL, ft);
		return;
	}

	ft->accepted = 1;
	
	gtk_widget_destroy(ft->window);
	ft->window = NULL;
	serv_rvous_accept(ft->user, ft->cookie, ft->UID);

	
	ft->fd = connect_address(inet_addr(ft->ip), ft->port);

	if (ft->fd <= -1) {
		fclose(ft->f);
		free_ft(ft);
		return;
	}

	read_rv = read_file_header(ft->fd, &header);
	if(read_rv < 0) {
		close(ft->fd);
		fclose(ft->f);
		free_ft(ft);
		return;
	}

	sprintf(debug_buff, "header length %d\n", header.hdrlen);
	debug_print(debug_buff);

	header.hdrtype = 0x202;
	
	buf2 = frombase64(ft->cookie);
	memcpy(header.bcookie, buf2, 8);
	snprintf(header.idstring, 32, "Gaim");
	g_free(buf2);
	header.encrypt = 0; header.compress = 0;
	header.totparts = 1; header.partsleft = 1;

	sprintf(debug_buff, "sending confirmation\n");
	debug_print(debug_buff);
	write_file_header(ft->fd, &header);

	rcv = 0;

	fw = gtk_dialog_new();
	snprintf(buf, 2048, _("Receiving %s from %s"), ft->filename, ft->user);
	label = gtk_label_new(buf);
	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(fw)->vbox), label, 0, 0, 5);
	gtk_widget_show(label);
	fbar = gtk_progress_bar_new();
	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(fw)->action_area), fbar, 0, 0, 5);
	gtk_widget_show(fbar);
	pct = gtk_label_new("0 %");
	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(fw)->action_area), pct, 0, 0, 5);
	gtk_widget_show(pct);
	button = gtk_button_new_with_label(_("Cancel"));
	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(fw)->action_area), button, 0, 0, 5);
	gtk_widget_show(button);
	if (display_options & OPT_DISP_COOL_LOOK)
		gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
	gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc)toggle, &cont);
	gtk_window_set_title(GTK_WINDOW(fw), _("Gaim - File Transfer"));
	gtk_widget_realize(fw);
	aol_icon(fw->window);
	gtk_widget_show(fw);

	sprintf(debug_buff, "Receiving %s from %s (%d bytes)\n", ft->filename,
			ft->user, ft->size);
	debug_print(debug_buff);

	fcntl(ft->fd, F_SETFL, O_NONBLOCK);

	while (rcv != ft->size && cont) {
		int i;
		float pcnt = ((float)rcv)/((float)ft->size);
		int remain = ft->size - rcv > 1024 ? 1024 : ft->size - rcv;
		read_rv = read(ft->fd, buf, remain);
		if(read_rv < 0) {
			if (errno == EWOULDBLOCK) {
				while(gtk_events_pending())
					gtk_main_iteration();
				continue;
			}
			gtk_widget_destroy(fw);
			fw = NULL;
			fclose(ft->f);
			close(ft->fd);
			free_ft(ft);
			return;
		}
		rcv += read_rv;
		for (i = 0; i < read_rv; i++)
			fprintf(ft->f, "%c", buf[i]);
		gtk_progress_bar_update(GTK_PROGRESS_BAR(fbar), pcnt);
		sprintf(buf, "%d / %d K (%2.0f %%)", rcv/1024, ft->size/1024, 100*pcnt);
		gtk_label_set_text(GTK_LABEL(pct), buf);
		while(gtk_events_pending())
			gtk_main_iteration();
	}
	fclose(ft->f);
	gtk_widget_destroy(fw);
	fw = NULL;

	if (!cont) {
		char *tmp = frombase64(ft->cookie);
		serv_rvous_cancel(ft->user, tmp, ft->UID);
		close(ft->fd);
		free_ft(ft);
		return;
	}

	sprintf(debug_buff, "Download complete.\n");
	debug_print(debug_buff);

	header.hdrtype = 0x402;
	header.totparts = 0; header.partsleft = 0;
	header.flags = 0;
	header.recvcsum = header.checksum;
	header.nrecvd = header.totsize;
	write_file_header(ft->fd, &header);
	close(ft->fd);

	free_ft(ft);
}

static void send_file_callback(gpointer data, gint source,
		GdkInputCondition condition) {
	struct file_transfer *ft = (struct file_transfer *)data;
	struct file_header fhdr;
	int read_rv;
	char buf[2048];
	GtkWidget *fw = NULL, *fbar = NULL, *label = NULL;
	GtkWidget *button = NULL, *pct = NULL;
	int rcv, cont;

	gdk_input_remove(snpa);
	snpa = -1;

	if (condition & GDK_INPUT_EXCEPTION) {
		fclose(ft->f);
		close(ft->fd);
		free_ft(ft);
		return;
	}

	/* OK, so here's what's going on: we need to send a file. The person
	 * sends us a file_header, then we send a file_header, then they send
	 * us a file header, then we send the file, then they send a header,
	 * and we're done. */

	/* we can do some neat tricks because the other person sends us back
	 * all the information we need in the file_header */

	read_rv = read_file_header(ft->fd, &fhdr);
	if (read_rv < 0) {
		fclose(ft->f);
		close(ft->fd);
		free_ft(ft);
		return;
	}

	if (fhdr.hdrtype != 0xc12) {
		sprintf(debug_buff, "%s decided to cancel. (%x)\n", ft->user,
				fhdr.hdrtype);
		debug_print(debug_buff);
		fclose(ft->f);
		close(ft->fd);
		free_ft(ft);
		return;
	}

	/* now we need to set the hdrtype to a certain value, but I don't know
	 * what that value is, and I don't happen to have a win computer to do
	 * my sniffing from :-P */
	fhdr.hdrtype = ntohs(0x101);
	fhdr.totfiles = 1;
	fhdr.filesleft = 1;
	fhdr.flags = 0x20;
	write_file_header(ft->fd, &fhdr);
	read_file_header(ft->fd, &fhdr);

	fw = gtk_dialog_new();
	snprintf(buf, 2048, _("Sending %s to %s"), fhdr.name, ft->user);
	label = gtk_label_new(buf);
	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(fw)->vbox), label, 0, 0, 5);
	gtk_widget_show(label);
	fbar = gtk_progress_bar_new();
	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(fw)->action_area), fbar, 0, 0, 5);
	gtk_widget_show(fbar);
	pct = gtk_label_new("0 %");
	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(fw)->action_area), pct, 0, 0, 5); 
	gtk_widget_show(pct);
	button = gtk_button_new_with_label(_("Cancel"));
	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(fw)->action_area), button, 0, 0, 5);
	gtk_widget_show(button);
	if (display_options & OPT_DISP_COOL_LOOK)
		gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
	gtk_signal_connect(GTK_OBJECT(button), "clicked", (GtkSignalFunc)toggle, &cont);
	gtk_window_set_title(GTK_WINDOW(fw), _("Gaim - File Transfer"));
	gtk_widget_realize(fw);
	aol_icon(fw->window);
	gtk_widget_show(fw);

	sprintf(debug_buff, "Sending %s to %s (%ld bytes)\n", fhdr.name,
			ft->user, fhdr.totsize);
	debug_print(debug_buff);

	rcv = 0; cont = 1;
	while (rcv != ntohl(fhdr.totsize) && cont) {
		int i;
		float pcnt = ((float)rcv)/((float)ntohl(fhdr.totsize));
		int remain = ntohl(fhdr.totsize) - rcv > 1024 ? 1024 :
			ntohl(fhdr.totsize) - rcv;
		for (i = 0; i < remain; i++)
			fscanf(ft->f, "%c", &buf[i]);
		read_rv = write(ft->fd, buf, remain);
		if (read_rv < 0) {
			fclose(ft->f);
			gtk_widget_destroy(fw);
			fw = NULL;
			fclose(ft->f);
			close(ft->fd);
			free_ft(ft);
			return;
		}
		rcv += read_rv;
		gtk_progress_bar_update(GTK_PROGRESS_BAR(fbar), pcnt);
		sprintf(buf, "%d / %d K (%2.0f %%)", rcv/1024,
				ntohl(fhdr.totsize)/1024, 100*pcnt);
		gtk_label_set_text(GTK_LABEL(pct), buf);
		while(gtk_events_pending())
			gtk_main_iteration();
	}
	fclose(ft->f);
	gtk_widget_destroy(fw);
	fw = NULL;

	if (!cont) {
		char *tmp = frombase64(ft->cookie);
		serv_rvous_cancel(ft->user, tmp, ft->UID);
		close(ft->fd);
		free_ft(ft);
		return;
	}

	sprintf(debug_buff, "Upload complete.\n");
	debug_print(debug_buff);

	read_file_header(ft->fd, &fhdr);

	close(ft->fd);
	free_ft(ft);
}

static void do_send_file(GtkWidget *w, struct file_transfer *ft) {
	char *file = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(ft->window)));
	char buf[BUF_LONG];
	char *buf2;
	int read_rv;
	struct file_header fhdr;
	guint32 rcv = 0;
	char *c;
	struct stat st;
	struct tm *fortime;

	stat(file, &st);
	if (!(ft->f = fopen(file, "r"))) {
		g_snprintf(buf, BUF_LONG / 2, _("Error reading file %s"), file);
		do_error_dialog(buf, _("Error"));
		ft->accepted = 0;
		accept_callback(NULL, ft);
		free_ft(ft);
		return;
	}

	ft->accepted = 1;
	ft->filename = file;

	gtk_widget_destroy(ft->window);
	ft->window = NULL;
	serv_rvous_accept(ft->user, ft->cookie, ft->UID);



	ft->fd = connect_address(inet_addr(ft->ip), ft->port);

	if (ft->fd <= -1) {
		free_ft(ft);
		return;
	}

	/* here's where we differ from do_get_file */
	/* 1. build/send header
	 * 2. receive header
	 * 3. send listing file
	 * 4. receive header
	 *
	 * then we need to wait to actually send the file, if they want.
	 *
	 */

	/* 1. build/send header */
	c = file + strlen(file);
	while (*(c - 1) != '/') c--;
	buf2 = frombase64(ft->cookie);
	sprintf(debug_buff, "Building header to send %s (cookie: %s)\n", file, buf2);
	debug_print(debug_buff);
	fhdr.magic[0] = 'O'; fhdr.magic[1] = 'F';
	fhdr.magic[2] = 'T'; fhdr.magic[3] = '2';
	fhdr.hdrlen = htons(256);
	fhdr.hdrtype = htons(0x1108);
	snprintf(fhdr.bcookie, 8, "%s", buf2);
	g_free(buf2);
	fhdr.encrypt = 0;
	fhdr.compress = 0;
	fhdr.totfiles = htons(1);
	fhdr.filesleft = htons(1);
	fhdr.totparts = htons(1);
	fhdr.partsleft = htons(1);
	fhdr.totsize = htonl((long)st.st_size); /* combined size of all files */
	/* size = strlen("mm/dd/yyyy hh:mm sizesize 'name'\r\n") */
	fhdr.size = htonl(28 + strlen(c)); /* size of listing.txt */
	fhdr.modtime = htonl(time(NULL)); /* time since UNIX epoch */
	fhdr.checksum = htonl(0x89f70000); /* ? i don't think this matters */
	fhdr.rfrcsum = 0;
	fhdr.rfsize = 0;
	fhdr.cretime = 0;
	fhdr.rfcsum = 0;
	fhdr.nrecvd = 0;
	fhdr.recvcsum = 0;
	snprintf(fhdr.idstring, 32, "OFT_Windows ICBMFT V1.1 32");
	fhdr.flags = 0x02;		/* don't ask me why */
	fhdr.lnameoffset = 0x1A;	/* ? still no clue */
	fhdr.lsizeoffset = 0x10;	/* whatever */
	memset(fhdr.dummy, 0, 69);
	memset(fhdr.macfileinfo, 0, 16);
	fhdr.nencode = 0;
	fhdr.nlanguage = 0;
	snprintf(fhdr.name, 64, "listing.txt");
	read_rv = write_file_header(ft->fd, &fhdr);
	if (read_rv <= -1) {
		sprintf(debug_buff, "Couldn't write opening header\n");
		debug_print(debug_buff);
		close(ft->fd);
		free_ft(ft);
		return;
	}

	/* 2. receive header */
	sprintf(debug_buff, "Receiving header\n");
	debug_print(debug_buff);
	read_rv = read_file_header(ft->fd, &fhdr);
	if (read_rv <= -1) {
		sprintf(debug_buff, "Couldn't read header\n");
		debug_print(debug_buff);
		close(ft->fd);
		free_ft(ft);
		return;
	}

	/* 3. send listing file */
	/* mm/dd/yyyy hh:mm sizesize name.ext\r\n */
	/* creation date ^ */
	sprintf(debug_buff, "Sending file\n");
	debug_print(debug_buff);
	fortime = localtime(&st.st_ctime);
	snprintf(buf, ntohl(fhdr.size) + 1, "%2d/%2d/%4d %2d:%2d %8ld %s\r\n",
			fortime->tm_mon + 1, fortime->tm_mday, fortime->tm_year + 1900,
			fortime->tm_hour + 1, fortime->tm_min + 1,
			st.st_size, c);
	sprintf(debug_buff, "Sending listing.txt (%d bytes) to %s\n",
			ntohl(fhdr.size) + 1, ft->user);
	debug_print(debug_buff);

	read_rv = write(ft->fd, buf, ntohl(fhdr.size));
	if (read_rv <= -1) {
		sprintf(debug_buff, "Could not send file, wrote %d\n", rcv);
		debug_print(debug_buff);
		close(ft->fd);
		free_ft(ft);
		return;
	}

	/* 4. receive header */
	sprintf(debug_buff, "Receiving closing header\n");
	debug_print(debug_buff);
	read_rv = read_file_header(ft->fd, &fhdr);
	if (read_rv <= -1) {
		sprintf(debug_buff, "Couldn't read closing header\n");
		debug_print(debug_buff);
		close(ft->fd);
		free_ft(ft);
		return;
	}

	snpa = gdk_input_add(ft->fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION,
				send_file_callback, ft);

}

void accept_file_dialog(struct file_transfer *ft)
{
        GtkWidget *accept, *info, *warn, *cancel;
        GtkWidget *label;
        GtkWidget *vbox, *bbox;
        char buf[1024];

        
        ft->window = gtk_window_new(GTK_WINDOW_DIALOG);
        gtk_window_set_wmclass(GTK_WINDOW(ft->window), "accept_file", "Gaim");

        accept = gtk_button_new_with_label(_("Accept"));
        info = gtk_button_new_with_label(_("Info"));
        warn = gtk_button_new_with_label(_("Warn"));
        cancel = gtk_button_new_with_label(_("Cancel"));

        bbox = gtk_hbox_new(TRUE, 10);
        vbox = gtk_vbox_new(FALSE, 5);

        gtk_widget_show(accept);
        gtk_widget_show(info);
        gtk_widget_show(warn);
        gtk_widget_show(cancel);

		if (display_options & OPT_DISP_COOL_LOOK)
		{
			gtk_button_set_relief(GTK_BUTTON(accept), GTK_RELIEF_NONE);
			gtk_button_set_relief(GTK_BUTTON(info), GTK_RELIEF_NONE);
			gtk_button_set_relief(GTK_BUTTON(warn), GTK_RELIEF_NONE);
			gtk_button_set_relief(GTK_BUTTON(cancel), GTK_RELIEF_NONE);
		}

        gtk_box_pack_start(GTK_BOX(bbox), accept, TRUE, TRUE, 10);
        gtk_box_pack_start(GTK_BOX(bbox), info, TRUE, TRUE, 10);
        gtk_box_pack_start(GTK_BOX(bbox), warn, TRUE, TRUE, 10);
        gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 10);

	if (!strcmp(ft->UID, FILE_SEND_UID)) {
	        g_snprintf(buf, sizeof(buf), _("%s requests you to accept the file: %s (%d bytes)"),
				ft->user, ft->filename, ft->size);
	} else {
		g_snprintf(buf, sizeof(buf), _("%s requests you to send them a file"),
				ft->user);
	}
        if (ft->message)
		strncat(buf, ft->message, sizeof(buf) - strlen(buf));
        label = gtk_label_new(buf);
        gtk_widget_show(label);
        gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 5);
        gtk_box_pack_start(GTK_BOX(vbox), bbox, TRUE, TRUE, 5);

        gtk_window_set_title(GTK_WINDOW(ft->window), _("Gaim - File Transfer?"));
        gtk_window_set_focus(GTK_WINDOW(ft->window), accept);
        gtk_container_add(GTK_CONTAINER(ft->window), vbox);
        gtk_container_border_width(GTK_CONTAINER(ft->window), 10);
        gtk_widget_show(vbox);
        gtk_widget_show(bbox);
        gtk_widget_realize(ft->window);
        aol_icon(ft->window->window);

        gtk_widget_show(ft->window);


	gtk_signal_connect(GTK_OBJECT(accept), "clicked",
			   GTK_SIGNAL_FUNC(accept_callback), ft);
	gtk_signal_connect(GTK_OBJECT(cancel), "clicked",
			   GTK_SIGNAL_FUNC(cancel_callback), ft);
	gtk_signal_connect(GTK_OBJECT(warn), "clicked",
			   GTK_SIGNAL_FUNC(warn_callback), ft);
	gtk_signal_connect(GTK_OBJECT(info), "clicked",
			   GTK_SIGNAL_FUNC(info_callback), ft);


	if (ft->message) {
		/* we'll do this later
		while(gtk_events_pending())
			gtk_main_iteration();
		html_print(text, ft->message);
		*/
	}
}