/*
 this fixes it, test on linux - chkconfig --add dnews.init

Crashes are caused by
	null pointers
	file handle 

*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <errno.h>
#ifndef WIN32
#include <dirent.h>
#include <pwd.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
#endif

int errno;

#ifndef TRUE
#define FALSE 0 
#define TRUE (!FALSE)
#endif

#define DNEWS_CONF "/etc/dnews.conf"
#define ACCESS_CONF "/usr/local/dnews/access.conf"
#define FEED_CONF "/usr/local/dnews/newsfeeds.conf"
#define STARTUP_SH "/usr/local/dnews/dnews_start.sh"
#define STARTUP_RC "/etc/rc.d/rc.local"
#define MODE_EXE 0770
#define MODE_NORM 0660
#define BFSZ 3000

static char spool[BFSZ];
static char spoolx[BFSZ];
static char spoolw[BFSZ];
static char spoolh[BFSZ];
static char diskspace[BFSZ];
static char access_names[BFSZ];
static char access_nums[BFSZ];
static char access_ihave[BFSZ];
static char myname[BFSZ];
static char nntp_feeder[BFSZ];
static char me_groups[BFSZ];
static char config_dir[BFSZ];
static char dmgr_dir[BFSZ];
static int issuck,ismulti=FALSE;

void do_man(void);
void send_cmd(char *cmd);
void make_feed_conf(void);
char *mystrlwr(char *s);
char *mystrdup(char *s);
int wild_find2(char *xpath, char *wild, char *names[]);
void make_dnews_conf(void);
void make_access_conf(void);
void do_copy(char *src, char *dst);
void set_exe(char *xpath, char *wild, int mode);
int wild_find(char *wild, char *names[]);
void do_xcopy(char *src, char *dst, int required);
int user_ask(char *ques, char *dflt, char *rslt);
void remove_nohup(char *fname);
int user_ok(char *ques, int dflt);
int get_uid(void);
void do_setup(void);
void do_install(void);
void do_copy_name(char *src, char *dst);
int file_exists(char *s);
void do_upgrade(void);
void do_execopy(char *src, char *dst);
void mygets(char *bf2);
void do_exe(void);
void do_startup(void);
#ifdef NOUPPER
#define _tolower(_c)    ( (_c)-'A'+'a' )
#define _toupper(_c)    ( (_c)-'a'+'A' )
#endif

int main(int argc, char *argv[])
{
	
	char option[BFSZ];
	strcpy(config_dir,"/usr/local/dnews");
	sprintf(dmgr_dir,"%s/dmgr",config_dir);

	if (!file_exists("dnews.init")) {
		printf("Could not find dnews.init\n");
		printf("cd to dtemp before running dnews_setup\n");
		return 1;
	}
	if (getuid()!=0) if (!user_ok("WARNING, YOU MUST BE LOGGED IN AS ROOT TO INSTALL DNEWS, continue",FALSE)) return 0;
	if (!get_uid()) return TRUE;
	printf(" 1 Install DNEWS\n");
	printf(" 2 Upgrade existing DNEWS\n");
	printf(" 3 Quit without installing\n");
	strcpy(option,"1");
	if (file_exists(DNEWS_CONF)) {
		strcpy(option,"2");
	}
	user_ask("    Enter option (1,2,3) ",option,option);
	if (strcmp(option,"1")==0) do_setup();
	else if (strcmp(option,"2")==0) do_upgrade();
	else printf("No action peformed\n");	
	return 0;
} 
static int news_user,news_group;
int get_uid(void)
{
	struct passwd *pw;
	
	pw = getpwnam("news");
	if (pw==NULL) {
		printf("User 'news' is not in passwd file\nPlease create a user and group called 'news' then try again\n");
		return FALSE;
	}
	news_user = pw->pw_uid;
	news_group = pw->pw_gid;
	return TRUE;
}
void do_setup(void)
{
	if (file_exists(DNEWS_CONF)) {
		if (!user_ok("DNEWS already installed, continue ",FALSE)) return ;
	}
	do_install();
}
void fix_inetd(void);
void do_install(void)
{
	char bf[1000];
	char *s;
	int done_start=FALSE;
	gethostname(myname,190);

again:
	if (!user_ok("Have you read and agreed to http://netwinsite.com/dnews/license.htm ?",FALSE)) {
		printf("I'm sorry you need to read that before using our software. \nPlease read the end user license before continuing\n");
		goto again;
	};


	printf("You might want to format your spool/history/work drives \nwith 4096 byte blocks before installation! (typically the path /var/spool/dnews)  \n");
	printf("This is NOT critical but will improve performance on large systems\n");
	printf("e.g. on linux  /sbin/mke2fs -b 4096 -v  /dev/sdc1 (REPLACE WITH CORRECT DISK NAME)\n");
	printf("e.g. on solaris newfs -b 8192 -f  8192 -o time DEVICE_NAME\n\n");
	printf("We also STRONGLY recommend work and history areas be on separate PARTITIONS for best performance\n");	
	user_ask("What is the TCPIP name of this computer",myname,myname);
	issuck = user_ok("Are we going to suck news from another site ?",TRUE);
 	if (issuck) {
		user_ask("Name of news server to SUCK FROM","news.upstream.site",nntp_feeder);
		strcpy(access_ihave,nntp_feeder);
	} else {
		user_ask("Name or wildcard of server to accept news from","news*.sprint.net",access_ihave);
		user_ask("Name or server to send news back to","news.sprint.net",nntp_feeder);
	}
	user_ask("Where should I store the news spool database","/var/spool/dnews/spool",spool);
	user_ask("Leave about 10% free, so for a 4gig drive specify 3600\nHow many MB on this partition can DNEWS use","2000",diskspace);
	user_ask("List wildcard groups to allow on this server","*,!*binaries*",me_groups);
	user_ask("Give IP-Name wildcard to allow access","*your.domain",access_names);
	user_ask("Give IP-Number wildcard to allow access","132.22.3.*",access_nums);
	printf("Copying files...");

	mkdir("/usr",0755);
	mkdir("/usr/local",0755);
	mkdir("/usr/local/dnews",0770);
	mkdir("/usr/local/dnews/web",0775);
	mkdir("/usr/local/dnews/dmgr",0775);
	mkdir("/usr/local/bin",0775);
	mkdir("/usr/bin",0775); /* brian */
	strcpy(spoolx,spool);
	s = strstr(spoolx,"/spool");
	if (s!=NULL) s = strstr(s+1,"/spool");
	if (s!=NULL) *s = 0;
	strcpy(spoolw,spoolx);
	strcpy(spoolh,spoolx);

	strcat(spoolx,"/xover");
	strcat(spoolw,"/work");
	strcat(spoolh,"/hist");
	mkdir("/var/spool/dnews",0770);
	mkdir(spool,0770);
	mkdir(spoolx,0770);
	mkdir(spoolw,0770);
	mkdir(spoolh,0770);
	chown("/usr/local/dnews",news_user,news_group);
	chown("/var/spool/dnews",news_user,news_group);
	chown(spool,news_user,news_group);
	chmod(spool,MODE_EXE);
	chown(spoolx,news_user,news_group);
	chmod(spoolx,MODE_EXE);
	chown(spoolw,news_user,news_group);
	chmod(spoolw,MODE_EXE);

	do_xcopy("*.conf","/usr/local/dnews",TRUE);
	do_xcopy("nocached.body","/usr/local/dnews",TRUE);
	make_dnews_conf();
	make_access_conf();
	make_feed_conf();
	chown(DNEWS_CONF,news_user,news_group);
	chmod(DNEWS_CONF,0664);
	chown(ACCESS_CONF,news_user,news_group);
	chmod(ACCESS_CONF,MODE_NORM);
	chown(FEED_CONF,news_user,news_group);
	chmod(FEED_CONF,MODE_NORM);

	mkdir("/usr/local/dnews/web",0775);
	mkdir("/usr/local/dnews/dmgr",0775);
	do_xcopy("*.tpl","/usr/local/dnews/web",FALSE);
	do_xcopy("*.htm*","/usr/local/dnews/web",FALSE);
	do_xcopy("dmgr/*.htm*","/usr/local/dnews/dmgr",FALSE);
	do_execopy("dmgr/dmgrcgi.cgi","/usr/local/dnews/dmgr");
	do_xcopy("*.txt","/usr/local/dnews",FALSE);
	do_xcopy("*.ini","/usr/local/dnews",TRUE);
	do_xcopy("*.sh","/usr/local/dnews",TRUE);
	set_exe("/usr/local/dnews","*.sh",MODE_EXE);

	do_man();
	
	remove("/usr/local/dnews/dnews.conf");

	do_exe();
	printf("done.\n");

	fix_inetd();
	if (file_exists("/etc/rc.d/init.d")) {
		if (user_ok("Shall I install dnews.init in /etc/rc.d/*.d",TRUE)) {
			do_copy("dnews.init","/etc/rc.d/init.d");
			set_exe("/etc/rc.d","init.d",0775);
			chmod("/etc/rc.d/init.d/dnews.init",0775);
			symlink("../init.d/dnews.init","/etc/rc.d/rc0.d/K25dnews");
			symlink("../init.d/dnews.init","/etc/rc.d/rc1.d/K25dnews");
			symlink("../init.d/dnews.init","/etc/rc.d/rc6.d/K25dnews");
			symlink("../init.d/dnews.init","/etc/rc.d/rc2.d/S95dnews");
			symlink("../init.d/dnews.init","/etc/rc.d/rc3.d/S95dnews");
			printf("Coppied dnews and created sym links from /etc/rc.d/rc*.d directories\n");
			printf("As startup mechanisms vary from unix to unix you need to test this to ensure dnews starts on startup\n");
			goto skip_startup;
		}
	}
	if (file_exists(STARTUP_RC)) {
		if (user_ok("Shall I append a startup line to /etc/rc.d/rc.local",TRUE)) {
			do_startup();
			done_start = TRUE;
		}
	}

skip_startup:
	if (user_ok("Shall I start DNEWS now",TRUE)) {
		printf("Ignore warning about 'nohup.out' and 'nohup.old'\n");
		sprintf(bf,"%s/dnews_start.sh",config_dir);
		send_cmd(bf);
		sleep(2);
	} 
	if (!done_start) {
		printf("\nRemember to place this line in your rc startup script\n\n");
		printf("/usr/local/dnews/dnews_start.sh\n\n");
	}
	printf("\nPLEASE check the install notes http://netwinsite.com/manual/install.htm\n");
	printf("DOCS and email help available from http://netwinsite.com\n");
	printf("\nCheck /usr/local/dnews/dnews.log wait 60 seconds then try \"tellnews status\"\n");
	printf("\nNEW KEY SYSTEM - Please see - http://netwinsite.com/activate.htm\n");
}
void do_man(void)
{
	FILE *f;
	f = fopen("/usr/man/man1/dnewstest.tmp","a");
	if (f!=NULL) {
		fclose(f); remove("/usr/man/man1/dnewstest.tmp");
		do_xcopy("*.1","/usr/man/man1",TRUE);
		chmod("/usr/man/man1/drobot.1",0666);
		chmod("/usr/man/man1/xmit.1",0666);
		chmod("/usr/man/man1/dposter.1",0666);
	}
}
void fix_inetd(void)
{
	FILE *f;
	FILE *fout;
	char bf[BFSZ];
	char bf2[BFSZ];
	char *s;
	int fixed=FALSE;
	f = fopen("/etc/inetd.conf","r");
	fout = fopen("/etc/inetd.new","w");
	if (f==NULL) return;
	if (fout==NULL) return;
	for (;!feof(f);) {
		if (fgets(bf,BFSZ-10,f)==NULL) break;
		strcpy(bf2,bf);
		s = strtok(bf2," \t\n");
		if (s==NULL) goto skip;
		mystrlwr(s);
		if (strcmp(s,"nntp")==0) {
			printf("Commenting out nntp line from inetd.conf\n");
			fixed = TRUE;	
			strcpy(bf2,bf);
			sprintf(bf,"#%s",bf2);
		}
skip:
		if (fprintf(fout,"%s",bf)<0) return;
	}	
	fclose(f);
	fclose(fout);
	if (fixed) {
		rename("/etc/inetd.conf","/etc/inetd.conf_old");
		rename("/etc/inetd.new","/etc/inetd.conf");
		printf("Modified /etc/inetd.conf, Sending kill -HUP <inetd process id>\n");
		send_cmd("./fixinet.sh");
		sleep(1);
	}	
}
void do_startup(void)
{
	FILE *f;
	char bf[BFSZ];
	f = fopen(STARTUP_RC,"r");
	if (f==NULL) return;
	for (;!feof(f);) {
		if (fgets(bf,BFSZ-10,f)==NULL) break;
		if (strstr(bf,STARTUP_SH)!=NULL) {
			printf("Startup line already appended\n");
			fclose(f);
			return;
		}
	}

	f = fopen(STARTUP_RC,"a");
	if (f==NULL) {perror(STARTUP_RC); return;}
	fprintf(f,"#	Startup DNEWS NNTP news server\n");
	fprintf(f,"%s\n",STARTUP_SH);
	printf("Appending:\n   %s\n",STARTUP_SH);
	fclose(f);
}
void do_exe(void)
{
	do_execopy("dnews",config_dir);
	do_execopy("dmgr/dmgrsvc",config_dir);
	do_execopy("dnews_start",config_dir);
	do_execopy("xmit",config_dir);
	do_execopy("dfeed",config_dir);
	do_execopy("dudp",config_dir);
	do_execopy("dnewssrt",config_dir);
	do_execopy("duse",config_dir);
	do_execopy("tellnews",config_dir);
	do_execopy("tellnews","/usr/bin");
	do_execopy("tellnews","/usr/local/bin");
	do_execopy("drobot",config_dir);
	do_execopy("dposter",config_dir);
	do_execopy("dnewsweb",config_dir);
	do_execopy("gupcgi",config_dir);
	do_execopy("dmulti",config_dir);
}
void do_execopy(char *src, char *xdst)
{
	char bf[BFSZ];
	char *last;
	char *s;

	do_copy(src,xdst);
	last = src;
	for (s=src;*s!=0;s++) {
		if (*s=='/') last=s+1;
	}
	sprintf(bf,"%s/%s",xdst,last);

	chown(bf,news_user,news_group);
	chmod(bf,MODE_EXE);
}

void find_config(void);
void kill_dmgr(void)
{
	FILE *f; 
	char bf[BFSZ];
	int pid;
	sprintf(bf,"%s/dmgrsvc.pid",config_dir);
	f = fopen(bf,"r");
	if (f!=NULL) {
		fgets(bf,100,f);
		pid = atoi(bf);
		if (pid>0) {
			printf("Stopping dmgrsvc pid=%d\n",pid);
			kill(pid,SIGKILL);
		}
		fclose(f);
	}
}
void do_upgrade(void)
{
	char bf[BFSZ];
	char webdir[BFSZ];

again:
	if (!user_ok("Have you read and agreed to http://netwinsite.com/dnews/license.htm ?",FALSE)) {
		printf("I'm sorry you need to read that before using our software. \nPlease read the end user license before continuing\n");
		goto again;
	}
	
	find_config();
	printf("Stopping current version of DNEWS (two commands are sent to ensure old versions shutdown)\n");
	
	if (file_exists("/usr/local/bin/tellnews")) {
		send_cmd("/usr/local/bin/tellnews exit");
		send_cmd("/usr/local/bin/tellnews -s0 exit");
		sleep(9);
	} else {
		printf("Cannot find /usr/local/bin/tellnews\n");
		if (!user_ok("Have you stopped DNEWS",FALSE)) {
			printf("You must stop dnews before running dnews_setup");
			exit(1);
		}
	}
	kill_dmgr();
	printf("Copying files...");
	sprintf(webdir,"%s/web",config_dir);
	mkdir(config_dir,0775);
	sprintf(dmgr_dir,"%s/dmgr",config_dir);
	mkdir(dmgr_dir,0775);
	mkdir(webdir,0775);
	chmod(webdir,0775);
	chmod(spool,MODE_EXE);
	if (chmod(config_dir,0775)<0) perror("chmod failed");
	do_xcopy("dmgr/*.htm*",dmgr_dir,FALSE);
	do_execopy("dmgr/dmgrcgi.cgi",dmgr_dir);
	do_xcopy("*.tpl",webdir,FALSE);
	do_xcopy("*.htm*",webdir,FALSE);
	do_xcopy("*.txt",config_dir,TRUE);
	do_xcopy("*.ini",config_dir,TRUE);
	do_man();
	set_exe(webdir,"*.tpl",0775);

	do_exe();

	sprintf(bf,"%s/dnews_start.sh",config_dir);
	remove_nohup(bf);
	sprintf(bf,"%s/dmulti_start.sh",config_dir);
	remove_nohup(bf);
	printf("done.\n");
	strcpy(bf,"Shall I start DNEWS now");
	if (ismulti) strcpy(bf,"Shall I start DMULTI now");
	if (user_ok(bf,TRUE)) {
		printf("Ignore warning about 'nohup.out' and 'nohup.old'\n");
		sprintf(bf,"%s/dnews_start.sh",config_dir);
		if (ismulti) sprintf(bf,"%s/dmulti_start.sh",config_dir);

		send_cmd(bf);
		sleep(2);
		printf("\nCheck %s/dnews.log wait 60 seconds then try \"tellnews status\"\n",config_dir);
	} 
	printf("\nCheck the update notes via\n        http://netwinsite.com/manual/updates.htm\n");
	printf("\nNEW KEY SYSTEM - Please see - http://netwinsite.com/activate.htm\n");
}
void remove_nohup(char *fname)
{
	FILE *f,*fout;
	char *s;
	int found_svc = FALSE;
	char newname[BFSZ],bf[BFSZ],bf2[BFSZ],oldname[BFSZ];
	int found=FALSE;
	strcpy(newname,fname);
	strcat(newname,"_new");
	strcpy(oldname,fname);
	strcat(oldname,"_old");
	f = fopen(fname,"r");
	if (f==NULL) return;
	fout = fopen(newname,"w");
	if (fout==NULL) return;
	for (;!feof(f);) {
		if (fgets(bf,BFSZ-10,f)==NULL) break;
		if (strncmp(bf,"nohup",5)==0) {
			printf("\nNOTE: Removing 'nohup' and '&' from %s\n",fname);
			found = TRUE;
			strcpy(bf2,bf+6);
			strcpy(bf,bf2);
			s = strchr(bf,'&');
			if (s!=NULL) *s = ' ';
		}
		if (strstr(bf,"dmgrsvc")!=NULL) {
			found_svc = TRUE;
		}
		if (strstr(bf,"dnews_start")!=NULL) {
			if (!found_svc) {
				found = TRUE;
				found_svc = TRUE;
				printf("\nNOTE: Adding dmgrsvc to %s\n",fname);
				fprintf(fout,"./dmgrsvc\n");
			}
		}
		fprintf(fout,"%s",bf);
	}
	fclose(f); fclose(fout);
	if (found) {
		remove(oldname);
		rename(fname,oldname);
		rename(newname,fname);
		chmod(fname,MODE_EXE);		
	}
}
void find_config(void)
{
	FILE *f;
	char *s;
	char bf[BFSZ];
	f = fopen(DNEWS_CONF,"r");
	if (f==NULL) {perror("Could not read /etc/dnews.conf"); return;}
	for (;!feof(f);) {
		if (fgets(bf,BFSZ-10,f)==NULL) break;
		s = strtok(bf," \t\n");
		if (s==NULL) continue;
		mystrlwr(s);
		if (strcmp(s,"config")==0) {
			s = strtok(NULL," \t\n");
			if (s==NULL) continue;
			strcpy(config_dir,s);
		}
		if (strcmp(s,"slave_n")==0) {
			s = strtok(NULL," \t\n");
			if (s==NULL) continue;
			if (atoi(s)>0) ismulti = TRUE;
		}
	}		
	fclose(f);
}

void append_file(FILE *fout,char *fname);
void make_feed_conf(void)
{
	FILE *f;
	f = fopen(FEED_CONF,"w");
	if (f==NULL) {perror(FEED_CONF); return;}
	append_file(f,"newsfeeds.head");
	fprintf(f,"site me\n");
	fprintf(f,"\tgroups %s\n",me_groups);
	fprintf(f,"\n");
	if (issuck) {
	 fprintf(f,"site $nntp_feeder\n");
	 fprintf(f,"\tgroups *\n");
	 fprintf(f,"\tposting\n");
	 fprintf(f,"\tbuiltin\n");
	} else {
	 fprintf(f,"site %s\n",nntp_feeder);
	 fprintf(f,"\tgroups *\n");
	 fprintf(f,"\tbuiltin\n");
	}
	fprintf(f,"\n");
	fclose(f);
}

void append_file(FILE *fout,char *fname)
{
	FILE *f;
	char bf[BFSZ];
	f = fopen(fname,"r");
	if (f==NULL) {perror(fname); return;}

	for (;!feof(f);) {
		if (fgets(bf,BFSZ-10,f)==NULL) break;
		fprintf(fout,"%s",bf);
	}	
	fclose(f);
}
void make_access_conf(void)
{
	FILE *f;
	f = fopen(ACCESS_CONF,"w");
	if (f==NULL) {perror(ACCESS_CONF); return;}
	append_file(f,"access.head");
	fprintf(f,"*:logoff:::*\n");
	fprintf(f,"%s:ihave:::*\n",access_ihave);
	fprintf(f,"%s:read,post:::*\n",access_names);
	fprintf(f,"%s:read,post:::*\n",access_nums);
	fclose(f);
}
void make_dnews_conf(void)
{
	FILE *f;
	FILE *fout;
	char bf[BFSZ];
	char bfl[BFSZ];
	char *s;
	f = fopen("dnews.conf","r");
	if (f==NULL) {perror("dnews.conf"); return;}
	fout = fopen(DNEWS_CONF,"w");
	if (fout==NULL) {perror(DNEWS_CONF); return;}
	fprintf(fout,"# The name of this computer\n");
	fprintf(fout,"myname %s\n",myname);
	if (issuck) {
		fprintf(fout,"# The place we will suck news from\n");
		fprintf(fout,"nntp_feeder %s\n",nntp_feeder);
	}
	fprintf(fout,"# The amount of diskpace DNEWS can use\n");
	fprintf(fout,"diskspace %d\n",atoi(diskspace)*10/9);
	fprintf(fout,"# The main spool area for the dnews database\n");
	fprintf(fout,"spool %s\n",spool);
	fprintf(fout,"# Various work files, active file...\n");
	fprintf(fout,"workarea %s\n",spoolw);
	fprintf(fout,"# History database allow 5%% of spool area \n");
	fprintf(fout,"history %s\n",spoolh);
	fprintf(fout,"# Xover database, allow 10%% of spool area \n");
	fprintf(fout,"xover_dir %s\n",spoolx);
	if (!issuck) {
		fprintf(fout,"# Stops downloading messages appearing\n");
		fprintf(fout,"cachedall true\n");
	}
	for (;!feof(f);) {
		if (fgets(bf,BFSZ-10,f)==NULL) break;
		strcpy(bfl,bf);
		mystrlwr(bfl);
		s = strtok(bfl," \t\n");
		if (s==NULL) continue;
		if (strcmp(s,"nntp_feeder")==0) ;
		else if (strcmp(s,"myname")==0) ;
		else if (strcmp(s,"diskspace")==0) ;
		else if (strcmp(s,"spool")==0) ;
		else if (strcmp(s,"workarea")==0) ;
		else if (strcmp(s,"history")==0) ;
		else if (strcmp(s,"xover_dir")==0) ;
		else if (strcmp(s,"cachedall")==0) ;
		else fprintf(fout,"%s",bf);
	}
	fclose(fout);
	fclose(f);
}
void do_xcopy(char *src, char *dst, int required)
{
	char *wild_names[10000];
	int i;
	int nwild;

	nwild = wild_find(src,wild_names);
	if (required) if (nwild==0) printf("Installation files missing {%s} - !! you must cd to dtemp before running dnews_setup !!! \n",src);
	for (i=0; i<nwild; i++) {
		/* if (required) printf("xcopy %s --> %s\n",wild_names[i],dst);*/
		do_copy(wild_names[i],dst);
	}
}
void set_exe(char *xpath, char *wild, int mode)
{
	char *wild_names[10000];
	char bf[BFSZ];
	int i;
	int nwild;

	/* printf("xcopy %s --> %s\n",src,dst);	*/
	nwild = wild_find2(xpath,wild,wild_names);
	for (i=0; i<nwild; i++) {
		sprintf(bf,"%s/%s",xpath,wild_names[i]);
		chmod(bf,mode);
	}
}

void do_copy(char *src, char *xdst)
{
	FILE *fsrc,*fdst;
	int r;
	char bf[2000];
	char dst[BFSZ];
	char *last,*s;

	last = src;
	for (s=src;*s!=0;s++) {
		if (*s=='/') last=s+1;
	}
	sprintf(dst,"%s/%s",xdst,last);
	
/*printf("Copy %s --> %s\n",src,dst);	*/
	fsrc = fopen(src,"r");
	if (fsrc==NULL) {perror(src); return;}
	fdst = fopen(dst,"w");
	if (fdst==NULL) {
		if (errno==ETXTBSY) sleep(8);
		fdst = fopen(dst,"w");
	}
	if (fdst==NULL) {sprintf(bf,"Cannot write to (%s) ",dst); perror(bf); return;}
	for (;!feof(fsrc);) {
		r = fread(bf,1,1000,fsrc);
		if (r<=0) break;
		if (fwrite(bf,1,r,fdst)!=r) perror(dst);
	}
	fclose(fsrc);
	if(fclose(fdst)!=0) {
		sprintf(bf,"Could not close destination file (%s) ",dst);
		perror(bf);
		return;
	};
	chown(dst,news_user,news_group);
	chmod(dst,MODE_NORM);
}
void do_copy_name(char *src, char *dst)
{
	FILE *fsrc,*fdst;
	int r;
	char bf[2000];
	
/*printf("Copy %s --> %s\n",src,dst);	*/
	fsrc = fopen(src,"r");
	if (fsrc==NULL) {perror(src); return;}
	fdst = fopen(dst,"w");
	if (fdst==NULL) {
		if (errno==ETXTBSY) sleep(8);
		fdst = fopen(dst,"w");
	}
	if (fdst==NULL) {sprintf(bf,"Cannot write to (%s) ",dst); perror(bf); return;}
	for (;!feof(fsrc);) {
		r = fread(bf,1,1000,fsrc);
		if (r<=0) break;
		if (fwrite(bf,1,r,fdst)!=r) perror(dst);
	}
	fclose(fsrc);
	if(fclose(fdst)!=0) {
		sprintf(bf,"Could not close destination file (%s) ",dst);
		perror(bf);
		return;
	};
	chown(dst,news_user,news_group);
	chmod(dst,MODE_NORM);
}
int wild_find(char *wild, char *names[])
{
        DIR *dirp;
	int n=0;
        struct dirent *direntp; 
	char bf[100],bf2[100],dname[200],dadd[200];
	char *s;
	strcpy(bf,wild);
	s = strchr(bf,'/');
	if (s!=NULL) {
		*s = 0;
		strcpy(dname,bf);
		strcpy(dadd,dname);
		strcat(dadd,"/");
		wild = s+1;

	} else {
		strcpy(dname,".");
		strcpy(dadd,"");
	}
        dirp = opendir(dname); 
        if (dirp==NULL) {perror("Could not read directory file"); return 0;}
	
        while ((direntp=readdir(dirp))!=NULL) {
                if (match_wild(wild,direntp->d_name)) {
             		if (strcmp(direntp->d_name,".")==0) continue;
             		if (strcmp(direntp->d_name,"..")==0) continue;
                        sprintf(bf2,"%s%s",dadd,direntp->d_name);
                        names[n++] = mystrdup(bf2);
		}
		if (n>1000) break;
        }
        closedir(dirp);
	return n;
}
int wild_find2(char *xpath, char *wild, char *names[])
{
        DIR *dirp;
	int n=0;
        struct dirent *direntp; 

        dirp = opendir(xpath); 
        if (dirp==NULL) {perror("Could not read directory file"); return 0;}
	
        while ((direntp=readdir(dirp))!=NULL) {
                if (match_wild(wild,direntp->d_name)) {
             		if (strcmp(direntp->d_name,".")==0) continue;
             		if (strcmp(direntp->d_name,"..")==0) continue;
                        names[n++] = mystrdup(direntp->d_name);
		}
		if (n>1000) break;
        }
        closedir(dirp);
	return n;
}
void mygets(char *bf2)
{
	char *s;
	static char bf[BFSZ];
	fgets(bf,BFSZ-10,stdin);
	s = strtok(bf,"\r\n");
	if (s==NULL) {strcpy(bf2,""); return;}
	strcpy(bf2,s);
}
int user_ask(char *ques, char *dflt, char *rslt)
{
	char bf[BFSZ];
again:
	printf("%s [%s] ? ",ques,dflt);
	mygets(bf);
	if (strcmp(bf,"yes")==0) goto again;
	if (strcmp(bf,"YES")==0) goto again;
	if (strcmp(bf,"NO")==0) goto again;
	if (strcmp(bf,"no")==0) goto again;
	if (strcmp(bf,"y")==0) goto again;
	if (strcmp(bf,"n")==0) goto again;
	if (strlen(bf)==0) strcpy(bf,dflt);
	strcpy(rslt,bf);
	return TRUE;
}
int user_ok(char *ques, int dflt)
{
	char bf[BFSZ];
	char dflt_str[BFSZ];
	if (dflt) strcpy(dflt_str,"yes");
	else strcpy(dflt_str,"no");
	printf("%s [%s] ?",ques,dflt_str);
	mygets(bf);
	mystrlwr(bf);
	if (strlen(bf)==0) return dflt;
	if (strstr(bf,"y")!=NULL) return TRUE;
	return FALSE;
}
int file_exists(char *s)
{
	FILE *f;
	f = fopen(s,"r");
	if (f==NULL) return FALSE;
	fclose(f);
	return TRUE;
}
char *mystrlwr(char *s)
{
        char *ss=s;
        for (;*s!=0;s++) if (isupper(*s)) if (*s>0) *s = _tolower(*s);
        return ss;
}
char *mystrdup(char *s)
{
        char *t;
        t = malloc(strlen(s)+1);
        strcpy(t,s);
        return t;
}
#define FLUSH(x) (fflush(f)==EOF || ferror(f))

void send_cmd(char *cmd)
{
	int i;
	FILE *f;
   
	printf("Spawn (%s)\n",cmd);
	if ((f = popen(cmd,"w"))==NULL)  {perror("popen"); return ; }
	if (FLUSH(f)) {pclose(f); perror("fflush"); return;    }
	if (pclose(f)!=0) {return;}
}