#include <unistd.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/time.h>
#include <ncurses/ncurses.h>
#include <signal.h>
#include <string.h>
#include <stdlib.h>

#define PROGNAME "plany v0.1"
#define CFG_FILE "/etc/plany.cfg"
#define SUCCESS 0
#define NEUTRAL 1
#define FAILURE 2

#define INIT 1
#define RIGHT 2
#define LEFT 3
#define UP 4
#define DOWN 5
#define UPDATE 6
#define NOUPDATE 100

#define LIST 0
#define EXTRACT 1

#define FS 3

#define BASENAME 0
#define FULLPATH 1


struct DECOMP {
	char *suffix;
	char *list;
	char *extract;
	struct DECOMP *next;
};
struct FTYPE {
	int offset;  /* if -1, this is the default */
	int type;    /* 0 = string */
	char *match;
	char *exec;
	struct FTYPE *next;
};
struct FILELIST {
	char *filename;
	struct FILELIST *next;
	struct FILELIST *parent;
	struct FILELIST *child;
	int rating;
};

struct DISPLIST {
	char *name;
	struct FILELIST *filelist;
	int select_num;
};
struct DISPLIST *make_display_list(struct FILELIST *filelist, char *s);
struct FILELIST *get_filelist(int recur,char *dir, char *prefix, struct FILELIST *flst2);
int center(WINDOW *win, char *s);
int strip(char *s);
char *basename(char *s);
struct FILELIST *get_filelist_from_file(char *fname);
char *get_command(char *s, char *s2, int flag);


struct FTYPE *ftypes=NULL;
struct DECOMP *decomps=NULL;
int NowPlaying=-1;
int NextPlay=-1;
int NextSong=1;
int oldchild;

int child=0;

int main(int argc, char **argv)
{
	struct DISPLIST *displist=NULL;
	char **songs;
	char *directory;
	char cmd[1024], regexpstr[20], oldregexpstr[20];
	WINDOW *filewin, *playerwin, *actwin, *tmpwin ;
	int i=0, cursel=0, tmpcursel=0,tmpcursel2=0;
	int topsel=0, botsel=0, lastsel=0;
	int ch=0;
	struct FILELIST *filelist=NULL, *filelist2=NULL, *tmplist=NULL;
	int fdin=0, fdout=0, QuitFlag=FALSE;
	fd_set rd_fsset, ex_fsset;


	int child_death();
	
	if (argc>1)
	{
		if (!strcmp("-d",argv[1]))
			filelist=get_filelist_from_file(NULL);
		else
		{
			directory=strdup(argv[1]);
			filelist2=get_filelist_from_file(NULL);
		}
	}
	else
		if ( (directory=getenv("MUSICDIR"))==NULL)
		{
			printf("No music directory specified--nor does the environment variable  MUSICDIR \nexist.\n");
			exit(5);
		}
	initscr();cbreak();noecho();
	keypad(stdscr,TRUE);
        filewin=newwin(LINES-5,COLS,0,0);
	box(filewin,0,0);
        wmove(filewin,0,(COLS-strlen(PROGNAME))/2);
	wprintw(filewin,"%s",PROGNAME);
	wrefresh(filewin);
	signal(SIGCHLD,(void *) child_death);

	
	strcpy(oldregexpstr,"");

	center(filewin,"Please Wait.. reading configuration files.");

	if (read_cfg_file(CFG_FILE,&ftypes, &decomps)==FAILURE)
	{
		center(filewin,"Error Reading Configuration file.");
		if (ftypes) free(ftypes);
		if (decomps) free(decomps);
	}
	else
	{
		center(filewin,"                                                     ");
		center(filewin,"Please Wait.. reading files (this can take a while).");
		if (directory)
		{
			sprintf(cmd,"find %s -type f -print",directory);
			filelist=get_filelist(1,cmd,"",filelist2);
		}
		displist=make_display_list(filelist,NULL);
		center(filewin,"Please Wait.. sorting.");
		sort_display_list(displist,BASENAME);
                center(filewin,"");
		playerwin=newwin(5,COLS-2,LINES-5,1);
		scrollok(playerwin, TRUE);
		wrefresh(playerwin);
		wrefresh(filewin);


		display_menu(filewin,displist, INIT);

		wrefresh(filewin);

		/* Now, start the keyboard input */

		cursel=0;
/*		wrefresh(filewin); */

		QuitFlag=FALSE;
		actwin=filewin;
		while( (QuitFlag==FALSE) )
		{
			FD_ZERO(&rd_fsset);
			FD_ZERO(&ex_fsset);
			FD_SET(fileno(stdin),&rd_fsset);
			if (child)
			{
				FD_SET(fdin,&rd_fsset);
				FD_SET(fdin,&ex_fsset);
			}

			if (oldchild==child)
				select(FD_SETSIZE,&rd_fsset,0,&ex_fsset,0);
			if (oldchild!=child)
			{
				for (i=0;displist[i].name!=NULL && displist[i].select_num!=NextPlay;i++);
				if (displist[i].name !=NULL)
				{
					child=play_song(playerwin,displist,i,&fdin,&fdout);
				}
				cursel=display_menu(filewin,displist,UPDATE);
			}
			if (FD_ISSET(fileno(stdin),&rd_fsset))
			{
				ch=getch();
				if (actwin==playerwin)
				{
					char tmpch;
					tmpch=ch;
					if (tmpch=='~')
						actwin=filewin;
					else
						write(fdout,&tmpch,1);
				}
				else if (actwin==filewin)
				{
					if (ch>='0' && ch <='9')
					{
						displist[cursel].filelist->rating=ch-'0';
						display_menu(filewin,displist,UPDATE);
					}
					else
						switch(ch)
						{
						  case 'q':
							 QuitFlag=TRUE;
							 write_filelist(filewin,filelist);
							 
						  case 's':
						  case 'n':
							 if (child)
							 {
#ifdef USE_PIPE
								 close(fdin);
								 close(fdout);
#else
								 close(fdin);
#endif
							 }
							 while (child)
							 {
								 
								 kill(child,SIGTERM);
								 sleep(1);
							 }
							 if (ch=='s')
								 oldchild=child;
							 actwin=filewin;
							 display_menu(filewin,displist, UPDATE);
							 break;
						  case '/':
							 tmpwin=newwin(3,COLS, (LINES/2)-2,0);
							 box(tmpwin,0,0);
							 wmove(tmpwin,1,2);
							 keypad(tmpwin,TRUE);
							 echo();
							 wprintw(tmpwin,"Enter Search String :");
							 wgetnstr(tmpwin,regexpstr,sizeof(regexpstr));
							 if (!strcmp(regexpstr,""))
								 strcpy(regexpstr,oldregexpstr);
							 else
								 strcpy(oldregexpstr,regexpstr);
							 noecho();
							 tmpcursel=tmpcursel2=cursel;
							 for(cursel=display_menu(filewin,displist,NOUPDATE+RIGHT);
								  cursel!=tmpcursel;
								  cursel=display_menu(filewin,displist,NOUPDATE+RIGHT))
							 {
								 tmpcursel=cursel;
								 if (strstr(displist[cursel].name,regexpstr)!=NULL)
									 break;
							 }
							 if (strstr(displist[cursel].name,regexpstr)==NULL)
							 {
								 for(cursel=display_menu(filewin,displist,NOUPDATE+INIT);
									  cursel!=tmpcursel2;
									  cursel=display_menu(filewin,displist,NOUPDATE+RIGHT))
								 {
									 if (strstr(displist[cursel].name,regexpstr)!=NULL)
										 break;
								 }					
							 }			 
							 delwin(tmpwin);
							 touchwin(filewin);
							 wrefresh(filewin);
					                 cursel=display_menu(filewin,displist,UPDATE);
							 break;
						  case ' ':
							 if (displist[cursel].select_num)
							 {
								 tmpcursel=displist[cursel].select_num;
								 for (tmpcursel2=0;displist[tmpcursel2].name!=NULL;tmpcursel2++)
								 {
									 if (displist[tmpcursel2].select_num>tmpcursel)
										 displist[tmpcursel2].select_num--;
								 }
								 displist[cursel].select_num=0;
								 NextSong--;
							 }
							 else
								 displist[cursel].select_num=NextSong++;
							 
							 cursel=display_menu(filewin,displist,RIGHT);
							 break; 
						  case '~':
							 actwin=playerwin;
							 break;
						  case '!':
							 sort_display_list(displist,BASENAME);
							 cursel=display_menu(filewin,displist,INIT);
							 break;
						  case '@':
							 sort_display_list(displist,FULLPATH);
							 cursel=display_menu(filewin,displist,INIT);
							 break;
						  case 'k':
						  case KEY_UP:
							 cursel=display_menu(filewin,displist,UP);
							 break;
						  case KEY_DOWN:
						  case 'j':
							 cursel=display_menu(filewin,displist,DOWN);
							 break;
						  case KEY_RIGHT:
						  case 'l':
							 cursel=display_menu(filewin,displist,RIGHT);
							 break;
						  case 'h':
						  case KEY_LEFT:
							 cursel=display_menu(filewin,displist,LEFT);
							 break;
						  case 'w':
							 write_filelist(filewin,filelist);
							 break;
							 
						  case 'p':
							 if (child)
							 {
#ifdef USE_PIPE
								 close(fdin);
								 close(fdout);
#else
								 close(fdin);
#endif
							 }
							 while (child)
							 {
								 
								 kill(child,SIGTERM);
								 sleep(1);
							 }
							 child=play_song(playerwin,displist,cursel,&fdin,&fdout);
							 display_menu(filewin,displist, UPDATE);
							 break;
						}
				}
			}
			else if (FD_ISSET(fdin,&rd_fsset))
			{
				char ch;
				read(fdin,&ch,1);
				wprintw(playerwin,"%c",ch);
				wrefresh(playerwin);
			}
		}
	}
	delwin(filewin);
	delwin(playerwin);
   endwin();
	return(0);
}


int play_song(WINDOW *win, struct DISPLIST *dsplst, int sel, int *fdin, int *fdout)
{
/*	char cmd[255];*/
	int filedesrd[2], filedeswr[2];
	fd_set fdsetrd, fdsetwr;
	struct timeval timeout;
	int childpid;
	char *args[20];
	
	get_play_args(args,dsplst[sel].filelist);
	
#ifdef USE_PIPE
	pipe(filedesrd);
	pipe(filedeswr);
#else
	socketpair(AF_UNIX,SOCK_STREAM,0,filedesrd);
#endif

	if (!(oldchild=childpid=fork()))
	{
		close(fileno(stdin));
		close(fileno(stdout));
		close(fileno(stderr));
#ifdef USE_PIPE
		dup2(filedesrd[0],0);
		dup2(filedeswr[1],1);
		dup2(filedeswr[1],2);
		close(filedesrd[0]);
		close(filedesrd[1]);
		close(filedeswr[0]);
		close(filedeswr[1]);
#else
		dup2(filedesrd[0],0);
		dup2(filedesrd[0],1);
		dup2(filedesrd[0],2);
		close(filedesrd[0]);
		close(filedesrd[1]);
#endif
		execvp(args[0],args);
		exit(0);
	}
	else
	{
#ifdef USE_PIPE
		close(filedesrd[0]);
		close(filedeswr[1]);
		*fdout=filedesrd[1];
		*fdin=filedeswr[0];
#else
		close(filedesrd[0]);
		*fdout=filedesrd[1];
		*fdin=filedesrd[1];
#endif
	}
	NowPlaying=sel;
	NextPlay=dsplst[sel].select_num+1;
	return(childpid);
}
int child_death()
{
	int status;
	int death_during_child_death();

	signal(SIGCHLD,(void *) death_during_child_death);
	system("rm -fr /tmp/plany.del >/dev/null 2>&1");
	signal(SIGCHLD,(void *) child_death);
	child=0;
        NowPlaying=-1;
	wait(&status); 

}
int death_during_child_death()
{
	int status;
	wait(&status);
}
struct FILELIST *get_filelist_from_file(char *fname)
{
	char fname2[512];
	char buffer[1024];
	struct FILELIST *retval=NULL, *flist=NULL;
	FILE *fp;

	if (fname==NULL)
		sprintf(fname2,"%s/%s",getenv("HOME"),".plany.db");
	else
		strcpy(fname2,fname);
	
	if ( (fp=fopen(fname2,"r"))==NULL)
		return(retval);
	else
		while (fgets(buffer,sizeof(buffer),fp)!=NULL)
		{
			strip(buffer);
			if (flist==NULL)
				flist=(struct FILELIST *) calloc(1,sizeof(struct FILELIST));
			else
			{
				flist->next=(struct FILELIST *) calloc(1,sizeof(struct FILELIST));
				flist=flist->next;
			}
			if (retval==NULL)
				retval=flist;
			flist->rating= *buffer-'0';
			flist->filename=strdup(buffer+1);
		}
	return(retval);
}
	
struct FILELIST *get_filelist(int recur,char *cmd, char *prefix, struct FILELIST *flist2)
{
	FILE *flst;
	struct DECOMP *tmpdecomp;
	int in_archive_flag=0;
	static struct FILELIST *retval=NULL, *tmplst=NULL, *tmplst2=NULL;
	char *newcmd;
	char buffer[80];
	static char *Fcurfile;
	char newprefix[512];

	flst=popen(cmd,"r");
	while (fgets(buffer,80,flst)!=NULL)
	{
		
		strip(buffer);

		if (*buffer=='\0') continue;

		if ( (newcmd=get_command(buffer,"",LIST))!=NULL)
		{
			if (!strcmp(newcmd,"SKIP")) continue;
			strcpy(newprefix,prefix);
			strcat(newprefix,buffer);
			strcat(newprefix,":");
			if (recur)
				get_filelist(recur,newcmd,newprefix,flist2);
			continue;
		}
                if ( *basename(buffer)=='\0') continue;
		if (tmplst==NULL)
			tmplst=(struct FILELIST *) calloc(1,sizeof(struct FILELIST));
		else
		{
			tmplst->next=(struct FILELIST *) calloc(1,sizeof(struct FILELIST));
			tmplst=tmplst->next;
		}
		tmplst->filename=(char *) malloc(1+strlen(prefix)+strlen(buffer));
		strcpy(tmplst->filename,prefix);
		strcat(tmplst->filename,buffer);
		
		for (tmplst2=flist2;tmplst2!=NULL;tmplst2=tmplst2->next)
		{
			if (!strcmp(tmplst2->filename,tmplst->filename))
			{
				tmplst->rating=tmplst2->rating;
				break;
			}
		}

		if (retval==NULL)
			retval=tmplst;
	}
	pclose(flst);
	return(retval);
}
int strip (char *s)
{
	while(s[strlen(s)-1]==13 || s[strlen(s)-1]==10 )
		s[strlen(s)-1]='\0';
}
sort_display_list(struct DISPLIST *dsplst, int sortby)
{
	struct DISPLIST *tmpptr1, *tmpptr2, tmpdsplst;
	char *s1, *s2;
	int i,j;
	int didswap=TRUE;
	int compare_fullpath();
	int compare_basename();

	for (i=0;dsplst[i].name!=NULL;i++);
	i--;
	if (sortby==BASENAME)
		qsort(dsplst,i,sizeof(struct DISPLIST),compare_basename);
	else
		qsort(dsplst,i,sizeof(struct DISPLIST),compare_fullpath);
}	
int compare_basename(struct DISPLIST *d1, struct DISPLIST *d2)
{
	return(strcmp(basename(d1->name),basename(d2->name)));
}
int compare_fullpath(struct DISPLIST *d1, struct DISPLIST *d2)
{
	return(strcmp(d1->name,d2->name));
}
struct DISPLIST *make_display_list(struct FILELIST *filelist, char *regexpr)
{
	static struct DISPLIST *retval=NULL;
	static int num_entries=0;
	static char *filename=NULL;
	int i;
	int status=SUCCESS;
	char *tmpfilename=NULL;
	while(filelist!=NULL && status==SUCCESS)
	{
		if (filename)
		{
			char *tmpf;
			
			tmpf=(char *) malloc(strlen(filename)+strlen(filelist->filename)+1);
			strcpy(tmpf,filename);
			free(filename);
			filename=tmpf;
/*			filename=(char *) realloc(filename,strlen(filename)+strlen(filelist->filename)+1); */
			tmpfilename=strdup(filename);
			strcat(filename,filelist->filename);
		}
		else
		{
			filename=strdup(filelist->filename);
			tmpfilename=(char *) calloc(1,1);
		}

		if (filename==NULL)
			status=FAILURE;
		if (status==SUCCESS && filelist->child!=NULL)
			make_display_list(filelist->child, regexpr);
		else
		{
			if (status==SUCCESS && (num_entries % 10)==0)
			{
				if (retval!=NULL)
				{
					retval=(struct DISPLIST *) realloc(retval,sizeof(struct DISPLIST)*(11+num_entries));
					memset(retval+num_entries,0,sizeof(struct DISPLIST)*11);
				}
				else
					retval=(struct DISPLIST *) calloc(11,sizeof(struct DISPLIST));
				if (retval==NULL)
					status=FAILURE;
			}
			retval[num_entries].name=strdup(filename);
			retval[num_entries].filelist=filelist;
			num_entries++;
		}
		free(filename);
		filename=strdup(tmpfilename);
		free(tmpfilename);
		filelist=filelist->next;
	}
	free(filename);
	return(retval);
}
	
int center(WINDOW *win, char *s)
{
	wmove(win,LINES/2,1);
	wprintw(win,"%-*.*s",COLS-2,COLS-2,"");
	wmove(win,LINES/2,(COLS-strlen(s)) /2 );
	wprintw(win,s);
	wrefresh(win);
}


int read_cfg_file(char *filename, struct FTYPE **ftypes, struct DECOMP **decomps)
{
	FILE *fp;
	struct FTYPE *tmpftype=NULL;
	struct DECOMP *tmpdecomp=NULL;
	int status=SUCCESS;
	char *tmps;
	char buf[512];
	if ( (fp=fopen(filename,"r"))==NULL)
		status=FAILURE;
	while (status==SUCCESS && fgets(buf,sizeof(buf),fp)!=NULL)
	{
		strip(buf);
		if (*buf=='#' || *buf=='\0') continue;
		tmps=strtok(buf," 	=");
		if (!strcmp(tmps,"SUFFIX"))
		{
			if (tmpdecomp==NULL)
			{
				tmpdecomp=(struct DECOMP *) calloc(1,sizeof(struct DECOMP));
			}
			else
			{
				tmpdecomp->next=(struct DECOMP *) calloc(1,sizeof(struct DECOMP));
				tmpdecomp=tmpdecomp->next;
			}
			tmps=strtok(buf," 	");
			if (tmps==NULL)
				status=FAILURE;
			else
				tmpdecomp->suffix=strdup(buf+7);
			if (*decomps==NULL)
				*decomps=tmpdecomp;
		}
		else if (!strcmp(tmps,"LIST"))
			tmpdecomp->list=strdup(buf+5);
		else if (!strcmp(tmps,"EXTRACT"))
			tmpdecomp->extract=strdup(buf+8);
		else if (!strcmp(tmps,"PLAYER"))
		{
			if (tmpftype==NULL)
			{
				tmpftype=(struct FTYPE *) calloc(1,sizeof(struct FTYPE));
			}
			else
			{
				tmpftype->next=(struct FTYPE *) calloc(1,sizeof(struct FTYPE));
				tmpftype=tmpftype->next;
			}
			if (*ftypes==NULL)
				*ftypes=tmpftype;
		}
		else if (!strcmp(tmps,"TEST"))
		{
			tmps=strtok(NULL," 	");
			if (!strcmp(tmps,"DEFAULT"))
				tmpftype->offset=-1;
			else
			{
				tmpftype->offset=atoi(tmps);
				tmps=strtok(NULL," 	");
				tmps=strtok(NULL," 	");
				tmpftype->match=strdup(tmps);
			}
		}
		else if (!strcmp(tmps,"PROG"))
			tmpftype->exec=strdup(buf+5);
	}
	return status;
}
char *basename(char *s)
{
	char *tmps;
	tmps=s+strlen(s);

	while (tmps>s && *tmps!='/' && *tmps!=':' )
		tmps--;
	if (*tmps=='/' || *tmps==':')
		tmps++;
	return(tmps);
}

int display_menu(WINDOW *win, struct DISPLIST *displist, int flag)
{
	static int topsel=0;
	static int botsel=0;
	static int cursel=0;
	static int maxsel=0;
	int maxcols=4;
	int maxrows=16;
	int sel_len=19;
	int i,x,y;
        int updateflag=TRUE;
        
        if (flag>=NOUPDATE)
        {
           updateflag=FALSE;
           flag-=NOUPDATE;
        } 
	switch(flag)
	{
         case UPDATE:
	        break;
	 case INIT:
		topsel=0;
		for (maxsel=0;displist[maxsel].name!=NULL;maxsel++);
		if (maxsel>0) maxsel--;
		
		botsel= maxsel<(maxrows*maxcols)-1 ? maxsel: maxrows*maxcols-1;
		
		cursel=0;
		break;
	 case RIGHT:
		if (cursel<maxsel) cursel++;
		if (cursel>botsel)
		{
			botsel+=maxcols;
			topsel+=maxcols;
		}
		break;
	 case LEFT:
		if (cursel>0)
			cursel--;
		if (cursel<topsel)
		{
			botsel-=maxcols;
			topsel-=maxcols;
		}
		break;
	 case UP:
		if (cursel>=maxcols)
			cursel-=maxcols;
		if (cursel<topsel)
		{
			botsel-=maxcols;
			topsel-=maxcols;
		}
		break;
	 case DOWN:
		if ( (maxsel-cursel)>maxcols)
			cursel+=maxcols;
		if (cursel>botsel)
		{
			botsel+=maxcols;
			topsel+=maxcols;
			if (topsel>maxsel) topsel=maxsel;
			if (botsel>maxsel) botsel=maxsel;
		}
	}
        if (updateflag==TRUE)
        {
	   for (i=topsel;i<=botsel;i++)
	   {
		   wmove(win, 1+(i-topsel)/maxcols, 2+((i-topsel)%maxcols) * (sel_len));
		   if (i==cursel)
			   wattron(win,A_REVERSE);
		   if (displist[i].select_num)
			   wattron(win,A_BOLD);
		   if (i==NowPlaying)
			   wattron(win,A_BLINK);
		   if (displist[i].select_num)
			   wprintw(win,"%-3.3d %-*.*s",displist[i].select_num,sel_len-6, sel_len-6,basename(displist[i].name));
		   else
			   wprintw(win,"    %-*.*s",sel_len-6, sel_len-6,basename(displist[i].name));
		   if (displist[i].filelist->rating)
			   wprintw(win,"%d",displist[i].filelist->rating);
		   else
			   wprintw(win," ");
   
		   if (i==NowPlaying)
			   wattroff(win,A_BLINK);
		   if (displist[i].select_num)
			   wattroff(win,A_BOLD);
		   if (i==cursel)
			   wattroff(win,A_REVERSE);
	   }
	   wmove(win,maxrows+2,2);
	   wprintw(win,"File: %-70.70s", displist[cursel].name);
	   wrefresh(win);
        }
	return(cursel);
}
char *get_command(char *ffrom,char *fto, int flag)
{
	struct DECOMP *tmpdc;
	static char *retval=NULL;

	if (retval)
	{
		free(retval);
		retval=NULL;
	}
	for (tmpdc=decomps;retval==NULL && tmpdc!=NULL;tmpdc=tmpdc->next)
	{
		if (!(strcmp(ffrom+strlen(ffrom)-strlen(tmpdc->suffix),tmpdc->suffix)))
		{
			retval=(char *) calloc(1,1024);
			if (flag==LIST)
				sprintf(retval,tmpdc->list,ffrom);
			else if (flag==EXTRACT)
				sprintf(retval,tmpdc->extract,ffrom,fto);
		}
	}
	return(retval);
}
int get_play_args(char **args,struct FILELIST *filelist)
{
	struct FTYPE *tmpft;
	int status=NEUTRAL;
	char *ffrom, *fto;
	char curdir[256], *tmps;
	char *cmd;
	FILE *fp;

	getcwd(curdir,sizeof(curdir));
	ffrom=(char *) malloc(20+strlen(filelist->filename)+strlen(curdir));

	if (*filelist->filename!='/')
	{
		strcpy(ffrom,curdir);
		strcat(ffrom,"/");
	}
	else
		strcpy(ffrom,"");
	strcat(ffrom,filelist->filename);

	if ((tmps=strstr(ffrom,":"))!=NULL)
	{
		*tmps='\0';
		fto=strdup(tmps+1);
		
		if (access("/tmp/plany.del",F_OK))
			mkdir("/tmp/plany.del",777);
		chdir("/tmp/plany.del");
		cmd=get_command(ffrom,fto,EXTRACT);

		system(cmd);
		chdir(curdir);
		strcpy(ffrom,"/tmp/plany.del/");
		strcat(ffrom,fto);
		free(fto);
	}
	
	for (tmpft=ftypes;tmpft!=NULL && status==NEUTRAL;)
	{
		char buf[512];
		/* If the filename in ffrom is of this type, then fill in the arg
			array appropriately. */
		fp=fopen(ffrom,"r");
		fseek(fp,tmpft->offset,SEEK_SET);
		fread(buf,sizeof(buf),1,fp);
		if (strncmp(buf,tmpft->match,strlen(tmpft->match))==0)
			status=SUCCESS;
		fclose(fp);
		if (status==NEUTRAL)
			tmpft=tmpft->next;
	}
	if (status==SUCCESS)
	{
		int i=0;
		char *tmps2;
		tmps2=strdup(tmpft->exec);
		tmps=strtok(tmps2," ");
		for (i=0;tmps!=NULL;i++)
		{
			if (strcmp(tmps,"%s")==0)
				args[i]=strdup(ffrom);
			else
				args[i]=strdup(tmps);
			tmps=strtok(NULL," ");
		}
		args[i]=NULL;
	}
}

int write_filelist(WINDOW *filewin,struct FILELIST *filelist)
{
	int i;
	static int recur_level=0;
	static FILE *fp=NULL;
	char filename1[255],filename2[255];
	char buffer[1024];

	
	++recur_level;
	sprintf(filename1,"%s/%s",getenv("HOME"),"/.plany.db.tmp");
	if (fp==NULL)
		if ( (fp=fopen(filename1,"a+"))==NULL)
		{
			return FAILURE;
		}
	
	while (filelist!=NULL)
	{
		fprintf(fp,"%d%s\n",filelist->rating,filelist->filename);
		if (filelist->child)
			write_filelist(filewin,filelist->child);
		filelist=filelist->next;
	}
	recur_level--;

	if (recur_level==0)
	{
		fclose(fp);
		fp=NULL;
		sprintf(filename2,"%s/%s",getenv("HOME"),"/.plany.db");
		if (!access(filename2,F_OK))
		{
			sprintf(buffer,"cat %s >> %s",filename2,filename1);
			system(buffer);
		}
		sprintf(buffer,"sort -u +0.1 < %s > %s ; rm %s",
				  filename1,filename2,filename1);
		system(buffer);
	}
	return SUCCESS;
}
		






