/*
 * EveryBuddy 
 *
 * Copyright (C) 1999, Torrey Searle <tsearle@uci.edu>
 *
 * 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
 *
 */

/****************************
  Message Parser
  ***************************/

#include<gtk/gtk.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<sys/time.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include"account.h"
#include"contact.h"
#include"service.h"
#include"chat_window.h"
#include"message_parse.h"
#include"util.h"
#include"dialog.h"

char filename[1024];
// static unsigned long filename_len = 0; // unused
static int xfer_in_progress = 0;
static int input;
static FILE * fp;
static unsigned long amount_recieved;
static int fd;
static pthread_mutex_t mutex;

typedef struct _send_file_struct
{
	char filename[1024];
	int s;
} send_file_struct;


	

void send_file2(void * ptr )
{
	send_file_struct * sfs = ptr;
	unsigned long i = 0;
	char buff[1025];


	pthread_mutex_lock(&mutex);
	xfer_in_progress = 1;
	pthread_mutex_unlock(&mutex);
	signal(SIGPIPE,SIG_IGN); 



	if(!fp)
	{
		close(sfs->s);
		pthread_mutex_lock(&mutex);
		xfer_in_progress = -2;
		pthread_mutex_unlock(&mutex);
		signal(SIGPIPE,SIG_DFL); 
		pthread_mutex_destroy(&mutex);
		pthread_exit(0);
	}
	i = 0;
	while(!feof(fp))
	{
		buff[i%1024] = fgetc(fp);
		buff[i%1024+1] = 0;
		
		if(++i % 1024 == 0 )
		{
				int j = write(sfs->s, buff,1024);
				if( j < 0 )
				{
					signal(SIGPIPE,SIG_DFL); 
					fclose(fp);
					close(sfs->s);
					pthread_mutex_lock(&mutex);
					xfer_in_progress = -1;
					pthread_mutex_unlock(&mutex);
					pthread_mutex_destroy(&mutex);
					pthread_exit(0);
				}
				while(j < 1024 )
				{
					int k = send(sfs->s, j+buff, 1024-j,0);
					if(k < 0 )
					{
						signal(SIGPIPE,SIG_DFL); 
						pthread_mutex_lock(&mutex);
						xfer_in_progress = -1;
						pthread_mutex_unlock(&mutex);
						fclose(fp);
						close(sfs->s);
						pthread_mutex_destroy(&mutex);
						pthread_exit(0);
					}

					j += k;
				}
				pthread_mutex_lock(&mutex);
				amount_recieved = i;
				pthread_mutex_unlock(&mutex);
		}
	}

	if( (i-1)%1024 != 0 )
	{
		write(sfs->s, buff, (i-1)%1024);
	}

	signal(SIGPIPE,SIG_DFL); 

	pthread_mutex_lock(&mutex);
	xfer_in_progress = 0;
	pthread_mutex_unlock(&mutex);
	fclose(fp);
	close(sfs->s);
	pthread_mutex_destroy(&mutex);
	pthread_exit(0);
}
		
int update_send_progress(gpointer data )
{
	int * timer = data;
	pthread_mutex_lock(&mutex);
	if( xfer_in_progress > 0 )
	{
		update_progress(amount_recieved);
	}
	else if( xfer_in_progress == -1 )
	{
		do_error_dialog("Remote Side Disconnected", "Everybuddy file x-fer");
		progress_window_close();
		gtk_timeout_remove(*timer);
	}
	else if( xfer_in_progress == -2 )
	{
		do_error_dialog("Unable to open file!", "Everybuddy file x-fer");
		progress_window_close();
		gtk_timeout_remove(*timer);
	}
	else
	{
		do_error_dialog("File Sent Successfully", "Everybuddy file x-fer");
		progress_window_close();
		gtk_timeout_remove(*timer);
	}
	pthread_mutex_unlock(&mutex);
	return TRUE;
}

void send_file( char * filename, int s )
{
	static send_file_struct sfs;
	static int timer;
	struct stat fileinfo;
	static pthread_t thread;
	int i;
	char buff[6];
	unsigned long filelen;
//	struct timeval tv;
	char accept[10] = "";
//	fd_set set;

	if(xfer_in_progress)
		return;


	strncpy(sfs.filename, filename,1024);
	sfs.s = s;
	stat( sfs.filename, &fileinfo);

	for( i = strlen(filename); i >=0; i-- )
	{
		if(filename[i]=='/')
		{
			break;
		}
	}
	g_snprintf(buff, 1025, "%05d", strlen(filename+i+1));
	write(s,buff,5);
	write(s,filename+i+1,strlen(filename+i+1));
	filelen = htonl(fileinfo.st_size);
	write(s,&filelen,4);

	/*
	FD_ZERO(&set);
	FD_SET(s, &set);

	tv.tv_sec = 0;
	tv.tv_usec = 20;

	while(!select( s+1, &set, NULL, NULL, &tv ) )
	{
		 while (gtk_events_pending())
				gtk_main_iteration();
	}
*/
	read( s, accept, 10);

	if(!strcmp(accept,"ACCEPT") )
	{
		xfer_in_progress = 1;
		fp = fopen(filename,"rb");
		printf("%s %s %d %5d %p\n", filename, filename+i+1, strlen(filename), htons(strlen(filename+i+1)), fp);
		progress_window_new(filename,fileinfo.st_size);
		pthread_mutex_init(&mutex, NULL);
		if(pthread_create(&thread, NULL, 
					(void*)&send_file2, (void*)&sfs ))
			exit(1);
		timer = gtk_timeout_add((guint32)500, update_send_progress, &timer);
	}
	else
	{
		do_error_dialog("Remote Side has aborted the\nfile transfer",
						"Everybuddy File Transfer");
	}

}



void get_file2( gpointer data, gint source, GdkInputCondition condition )
{
	char buffer[1025];

			int len2;
			
			if(!(len2 = recv(source, buffer, 1024, 0)))
			{
				fclose(fp);
				close(source);
				do_error_dialog("File Receive Complete",
"Everybuddy File x-fer");
				progress_window_close();

				xfer_in_progress = 0;
				gdk_input_remove(*((int*)data));
				return;
			}
			else
			{
				int i;
				for(i=0; i <len2; i++)
				{
					fputc(buffer[i], fp);
				}
				amount_recieved += len2;
				update_progress(amount_recieved);
			}
}

	
void accept_file( GtkWidget * widget, gpointer data )
{
	int result = gtk_object_get_user_data( GTK_OBJECT(widget));
	if(result)
	{
		char val[10] = "ACCEPT";
		printf("write: %d\n", write(fd, val, 10));
		fsync(fd);
		input = gdk_input_add(fd, GDK_INPUT_READ, get_file2, &input); 
	}
	else
	{
		char val[10] = "DENY";
		write(fd, val, 10);
		close(fd);
		fclose(fp);
		xfer_in_progress = 0;
		progress_window_close();
	}
}

void get_file( int s )
{
	int len;
	unsigned long filelen;
	struct timeval tv;
	char buffer2[1024];
	char buffer[1024];
	char buffer3[1024];
	fd_set set;

	fd = accept(s, NULL, NULL );
	close(s);
	if(xfer_in_progress)
		return;
	xfer_in_progress = 1;

	FD_ZERO(&set);
	FD_SET(fd, &set);

	tv.tv_sec = 0;
	tv.tv_usec = 20;

	while(!select( fd+1, &set, NULL, NULL, &tv ) )
	{
		 while (gtk_events_pending())
				gtk_main_iteration();
	}

	recv(fd, buffer, 5, 0);
	buffer[5] = 0;
	len = atoi(buffer);
	recv(fd, buffer2, len, 0);
	buffer2[len]=0;
	recv(fd, &filelen, 4, 0);
	filelen = ntohl(filelen);

	progress_window_new(buffer2, filelen);

	g_snprintf( buffer, 1024, "%s/.everybuddy/files/%s", getenv("HOME"),buffer2);
	printf("receiving file %s\n", buffer);
	amount_recieved = 0;
	fp = fopen(buffer, "wb");

	g_snprintf( buffer3, 1024, "Would you like to accept\n the file %s?\nSize=%lu", buffer2,(unsigned long)filelen);
	do_dialog( buffer3, "Download File", accept_file, NULL );

	//input = gdk_input_add(fd, GDK_INPUT_READ, get_file2, &input); 
}


void eb_parse_incomming_message( eb_local_account * account,
								 eb_account * remote,
								 gchar * message )
{
	char buff[2048];
	char * ptr;
	strncpy( buff, message, 2048 );

	ptr = strtok(buff," ");

	if(ptr && !strcmp(ptr, "EB_COMMAND") && !xfer_in_progress)
	{
		ptr = strtok(NULL, " ");
		if(ptr && !strcmp(ptr, "SEND_FILE"))
		{
			char buff2[1024];
 			char   myname[1024];
  			int    s;
  			struct sockaddr_in sa;
  			struct hostent *hp;

  			memset(&sa, 0, sizeof(struct sockaddr_in)); /* clear our address */
  			gethostname(myname, 1023);           /* who are we? */
  			hp= gethostbyname(myname);                  /* get our address info */
  			if (hp == NULL)                             /* we don't exist !? */
    			return;
  			sa.sin_family= hp->h_addrtype;              /* this is our host address */
  			sa.sin_port= htons(82599);                /* this is our port number */
  			if ((s= socket(AF_INET, SOCK_STREAM, 0)) < 0) /* create socket */
    				return;
  			if (bind(s,&sa,sizeof(struct sockaddr_in)) < 0) {
    				close(s);
   			 		return;                               /* bind address to socket */
  			}
  			listen(s, 1);                               /* max # of queued connects */
			g_snprintf(buff2,1024,"EB_COMMAND ACCEPT %s", get_local_addresses());
			RUN_SERVICE(remote)->send_im(account,remote, buff2);
			get_file(s);
		}
		if(ptr && !strcmp(ptr, "ACCEPT"))
		{
			int sockfd;
			struct sockaddr_in dest_addr;

			ptr = strtok(NULL, " ");
			if(!ptr)
			{
				return;
			}

			sockfd = socket(AF_INET, SOCK_STREAM, 0);

			dest_addr.sin_family = AF_INET;
			dest_addr.sin_port = htons(82599);
			dest_addr.sin_addr.s_addr = inet_addr(ptr);
			memset(&(dest_addr.sin_zero), 0, 8);

			connect(sockfd, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr));

			   send_file(filename, sockfd);
		}
	}
	else
	{
		gchar * message2 = linkify(message);
		eb_chat_window_display_remote_message( account, remote, message2 );
		g_free(message2);
	}
}

