/* this file is a test implementation of my suncom.opl program */
/* this is as close to a straight port as I can manage */
/* this program is sort of stateless appart from the fact that */
/* all file operations requite the path to be setup */
/* if the #define CALLDEBUG is set a new command db */
/* comes into play, in this case all function calls can be logged into the */
/* file specified, note this command is only available and may cause */
/* problems with backup, (some code has been added to the activator call */
/* on the sun to attempt to handle this */
#include <plib.h>
#include <wlib.h>
#include <p_serial.h>
#include <p_xmodem.h>
/* SCCS Info @(#) suncom 3.27@(#) */
/* globals */
/* path strings */
TEXT sunname[200];
/* transmition strings */
TEXT hextxt[255], dectxt[255], suncmd[20], cmdlist[200];
/* temporary space */
TEXT tmp[300], wtmp[200] , ptmp[200] ;
/* index array for hex transformations */
TEXT hexarr[16] = "0123456789ABCDEF" ;
/* spacestr points to a sequence of spaces */
TEXT * spacestr ;
/* file handles */
VOID  *devh,  *fileh ;
/* line counters */
INT lineid, sndline ;
/* window line counters point */
INT lineidpt, sndlinept ;
/* toggles */
INT vrb, tmode, scr, filecs ;
/* window handles */
INT winline, winsnd, wintalk, winpath, wintog ;
/* window structures */
W_WINDATA wdline, wdsnd, wdtalk, wdpath, wdtog ;
/* graphics contexts */
UINT gcline, gcsnd, gctalk, gcpath, gctog ;
/* gc data setup structs */
G_GC gdline, gdsnd, gdtalk, gdpath, gdtog ;
/* input controler ??? */
INT linelen;
/* Process kill protection if 1 we will not kill processes begining with SYS */
INT procprot = 1;
/* line widths */
#define HALFWIDTH 105
#define FULLWIDTH 225
#define MODEASCII 1
#define MODEBINARY 0
#define MODEXMODEM 2
/* define the number of chars to read in each send block */
#define MAXRD 120
/* define the xmodem buffer size */
#define XMDMBUFSIZE 128
/* debug defines */
/* define CALLDEBUG to track the function calls set it to be the delay in 1/10 seconds */
/* #define CALLDEBUG 5 */
/* define PATHDEBUG (as above) to track file names  */
/*#define PATHDEBUG 5*/
/* set linedbg (as above) to see what goes along the serial line */
/* #define LINEDEBUG 5 */
/* how long to wait after shutting a process down */
#define SHUTDOWNSLEEP 5
#ifdef CALLDEBUG
/* do debugging */
INT logfile; /* logging flag */
VOID * logd ; /* logging file descriptor */
#endif
/* function definitions */
void main(void), getcmd(void), getline(void) ;
int ioget(void) ;
void setdefp(void) ,execmd(void), feedback(TEXT * msg), putline1( TEXT *), putline(TEXT * msg, int line) ;
void initlink(void), setline(void) ;
void initscr(void), wpath(void), wvb(void) ;
void wtm(void), wsc(void), wtalk( TEXT * msg), wline(void), wsnd(void), shutdown(void) ;
void initsys(void), sunvn(void), sunol(void), suniv(void), sunia(void), sunis(void), sunds(void);
void sunvb(void), sunsc(void), suntm(void), setp(void);
void updsp(void), sunsp(void), sundt(void), sunfc(void);
void sunrp(void), sunep(void), exlist(void);
void sunlp (void), sundc(void), sunmd(void) ;
void sungf(void), sungfb(void), wsline(void), wssnd(void);
void sunpf (void), sunpfb(void), sunsl(void), sunrl(void), suntalk(TEXT * msg) ;
void sunix(void), suntx(void), sunpfx(void), sungfx(void), suntf(void);
void dochksum(int *, char *,int);
/* process functions */
void sunpl(void), sunpk(void), sunpo(void), sunps(void) ;
/* return status on files */
void sunft(void), sunrw(void), sunsz(void), sunti(void), sunwn(void), sunwy(void), suncs(void) ;
void suncd(void), sunpp(void) ;
/* build commands for processes */
INT buildcmd(TEXT cmdbyte, TEXT * appname, TEXT * appext, TEXT * appalias, TEXT * fname, TEXT * cmdline) ;
#ifdef CALLDEBUG
/* do debugging defines */
void sunsd(void) ;
void suned(void) ;
#endif
#ifdef CALLDEBUG
void calldbg (TEXT * msg) ;
void calldbg (TEXT * msg)
{
	/* if we are not logging return pronto */
	if (! logfile)
	   return ;
	/* we are logging, assemble and write the message */
	p_write(logd, msg, p_slen(msg)) ;
	p_write(logd, "\n", p_slen("\n")) ;
}
#endif
#ifdef PATHDEBUG
void pathdbg (TEXT * msg, TEXT * msg1) ;
void pathdbg (TEXT * msg, TEXT * msg1) 
{
	p_print(":%s: :%s:\n",msg, msg1) ;
	p_sleep((ULONG) PATHDEBUG) ;
}
#endif

 void main(void)
{
#ifdef CALLDEBUG
	calldbg("main") ;
#endif
	initsys() ;
	while (p_scmpi("dc", suncmd) != 0)
        {
		getcmd() ;
		execmd() ;
	}
	shutdown() ;
}

 void getcmd(void) 
{
#ifdef CALLDEBUG
	calldbg("getcmd") ;
#endif
	getline() ;
	suncmd[0] = dectxt[0] ;
	suncmd[1] = dectxt[1] ;
	suncmd[2] = 0 ;
}

 void getline(void) 
{
#ifdef CALLDEBUG
	calldbg("getline") ;
#endif
	linelen=ioget() ;
	if (linelen < 2)
		p_scpy(dectxt, "XX") ;
}
void putline1(TEXT * msg)
{
	INT i ;
	char tmp[300] ;
	p_scpy(tmp, msg) ;
	/* put a CRLF pair at the end of the line and more the NULL allong */
	i = p_slen(tmp) ; 
	tmp[i] = 13 ;
	tmp[i+1] = 10 ;
	tmp[i+2] = 0 ;
	p_write(devh, tmp, i+2) ;
}


INT ioget(void)
{
	INT ret, cnt, chksum, schksum;
	UWORD v ;
	TEXT *ptr ;
#ifdef CALLDEBUG
	calldbg("ioget") ;
#endif
	/* as the psion does not work at the same speed as the sun we need 
	   to hold the sun of sending anything intill it recieved the 
	   goahead (>) by sending the > here we should be OK */
	putline1(">") ;
	chksum = 0 ;
	schksum = 1 ;
	while (chksum != schksum)
	{
		/* get the line length */
		ret = p_read(devh, tmp, 3) ;
		tmp[3] = '\0';
		ptr = tmp + 1;
		/* convert the length */
  	      	p_stog(&ptr, &v, 16) ;
		cnt = (INT) v ;
		/* read the data */
		ret = p_read(devh, dectxt, cnt) ;
		dectxt[cnt] = '\0' ;
		/* read the suns chksum */
		ret = p_read(devh, tmp, 3) ;
		tmp[3] = '\0';
		ptr = tmp + 1;
		/* convert the length */
     		p_stog(&ptr, &v, 16) ;
		schksum = (INT) v ;
		/* compute our chksum */
		chksum = 0 ;
		dochksum(&chksum, dectxt, cnt) ;
		if (chksum == schksum)
			putline1("O") ;
		else
			putline1("R") ;
	}

#ifdef LINEDEBUG
	p_print("ioget, count = %d, data :%s:\n", cnt, dectxt) ;
	p_sleep((ULONG) LINEDEBUG) ;
#endif
	lineid ++ ;
	wline() ;
	ret ++ ; /* stop irritating compile warnings */
	return (cnt) ;
}


 void execmd(void)
{


#ifdef CALLDEBUG
	calldbg("execmd");
#endif
	
	/* this section is rewritten to operate as a switch */

	if (p_scmpi("dc", suncmd) == 0) /* disconnect */
		sundc() ;
	else if (p_scmpi("vn", suncmd) == 0) /* version number */
		sunvn() ;
	else if (p_scmpi("ft", suncmd) == 0) /* file attributes */
		sunft() ;
	else if (p_scmpi("sz", suncmd) == 0) /* file size */
		sunsz() ;
	else if (p_scmpi("rw", suncmd) == 0) /* is file ro or rw */
		sunrw() ;
	else if (p_scmpi("sp", suncmd) == 0) /* set the path */
		sunsp() ;
	else if (p_scmpi("rp", suncmd) == 0) /* remove the file */
		sunrp() ;
	else if (p_scmpi("ti", suncmd) == 0) /* file modified time */
		sunti() ;
	else if (p_scmpi("lp", suncmd) == 0) /* list the path */
		sunlp() ;
	else if (p_scmpi("ep", suncmd) == 0) /* does the path exist ? */
		sunep() ;
	else if (p_scmpi("gf", suncmd) == 0) /* get file from the sun */
		sungf() ;
	else if (p_scmpi("pf", suncmd) == 0) /* put file to the sun */
		sunpf() ;
	else if (p_scmpi("md", suncmd) == 0) /* mkdir the path */
		sunmd() ;
	else if (p_scmpi("vb", suncmd) == 0) /* tobble verbose mode */
		sunvb() ;
	else if (p_scmpi("ds", suncmd) == 0) /* dump current strings */
		sunds() ;
	else if (p_scmpi("tm", suncmd) == 0) /* transfer mode binary */
		suntm() ;
	else if (p_scmpi("tx", suncmd) == 0) /* transfer mode xmodem*/
		suntx() ;
	else if (p_scmpi("iv", suncmd) == 0) /* are we verbose ? */
		suniv() ;
	else if (p_scmpi("ia", suncmd) == 0) /* are we using ascii ? */
		sunia() ;
	else if (p_scmpi("ix", suncmd) == 0) /* are we using xmodem ? */
		sunix() ;
	else if (p_scmpi("sc", suncmd) == 0) /* toggle the screen mode */
		sunsc() ;
	else if (p_scmpi("is", suncmd) == 0) /* is the screen on ? */
		sunis() ;
	else if (p_scmpi("sl", suncmd) == 0) /* reset sent line counter */
		sunsl() ;
	else if (p_scmpi("rl", suncmd) == 0) /* reset recieved line counter */
		sunrl() ;
	else if (p_scmpi("ol", suncmd) == 0) /* are we online ? */
		sunol() ;
	else if (p_scmpi("dt", suncmd) == 0) /* display text in window */
		sundt() ;
	else if (p_scmpi("wy", suncmd) == 0) /* set rw mode on file */
		sunwy() ;
	else if (p_scmpi("wn", suncmd) == 0) /* set ro mode on file */
		sunwn() ;
	else if (p_scmpi("cs", suncmd) == 0) /* compute the checksum on a file */		suncs() ;
	else if (p_scmpi("cd", suncmd) == 0) /* cd to a directory */
		suncd() ;
	else if (p_scmpi("pp", suncmd) == 0) /* send back the default path */
		sunpp() ;
	else if (p_scmpi("tf", suncmd) == 0) /* truncate sunname to the given length (Very dangerous) */
		suntf() ;
	else if (p_scmpi("fc", suncmd) == 0) /* enable / disable file transfer level binary check summs */
		sunfc() ;
	else if (p_scmpi("pl", suncmd) == 0) /* process listing */
		sunpl() ;	
	else if (p_scmpi("pk", suncmd) == 0) /* process killing */
		sunpk() ;
	else if (p_scmpi("po", suncmd) == 0) /* protection overide on killing SYS processes */
		sunpo() ;
	else if (p_scmpi("ps", suncmd) == 0) /* send process shutdown commands */
		sunps() ;
#ifdef CALLDEBUG
	else if (p_scmpi("sd", suncmd) == 0) /* start debugging */
		sunsd() ;
	else if (p_scmpi("ed", suncmd) == 0) /* end debugging */
		suned() ;
#endif
	else
		feedback("BADCMD") ;
}

 void feedback( TEXT  * msg)
{
#ifdef CALLDEBUG
	calldbg("feedback");
#endif
	tmp[0] = 0 ;

	p_scpy(tmp, "X") ;
        p_scat(tmp, msg) ;
	putline(tmp, 1) ;
}

 void putline(TEXT * msg, INT line) 
{
	INT len, chksum;
	char tmp[255] ;
	char resp[10] ;
#ifdef CALLDEBUG
	calldbg("putline");
#endif
#ifdef LINEDEBUG
	p_print("putline :%s:\n", msg) ;
	p_sleep ((ULONG) LINEDEBUG) ;
#endif
	/* how long is the message ? */
	len = p_slen(msg) ;
	/* calculate the chksum */
	chksum = 0 ;
	dochksum(&chksum, msg, len) ;
	p_atos(tmp, "$%2x%s$%2x", len, msg, chksum) ;
	putline1(tmp) ;
	/* hang around untill we get the response */
	resp[0] = 'R' ;
	while (resp[0] != 'O')
	{
		/* get the response */
		p_read(devh, resp, 1) ;
		if (resp[0] != 'O')
		{
			/* we need to resend here */
			putline1(tmp) ;
		}
	}
	if (line)
	{
		sndline ++ ;
		wsnd() ;
	}
}

 void initlink(void)
{
	INT ret ;
#ifdef CALLDEBUG
	calldbg("initlink");
#endif
	ret = p_open(&devh, "TTY:A", -1) ;
	if (ret != 0)
	{
		suntalk("Error in opening device\n");
		p_getch() ;
		p_exit(0) ;
	}
	feedback("ONLINE") ;
}

 void setline(void)
{
	P_SRCHAR pchar ;
#ifdef CALLDEBUG
	calldbg("setline");
#endif

	/* get the serial port informatrion */
	p_iow(devh, P_FSENSE, &pchar) ;
	/* not force the data we need */
	pchar.tbaud = P_BAUD_9600 ;
	pchar.rbaud = P_BAUD_9600 ;
	pchar.frame = P_DATA_7 ;
	pchar.parity= P_PAR_EVEN || (! P_TWOSTOP) ;
	pchar.hand  = P_IGN_CTS ;
	p_iow(devh, P_FSET, &pchar) ;
}

 void initsys(void)
{
#ifdef CALLDEBUG
	calldbg("initsys") ;
#endif
	hextxt[0] = 0 ;
	dectxt[0] = 0 ;
	suncmd[0] = 0 ;
	spacestr =  "                                 " ;
        p_scpy(cmdlist, "dc,vn,sp,lp,ep,rp,gf,pf,md,vb,ds,tm,iv,ia,sc,is,sl,rl,ol,dt") ;
	vrb = 1 ;
	tmode = MODEBINARY ;
	filecs = 0 ;
	lineid = 0 ;
	scr = 1 ;
	procprot = 1 ;
	setdefp() ;
	initscr () ;
	initlink() ;
#ifdef CALLDEBUG
	logfile = 0 ;
#endif
}

void setdefp(void)
{
#ifdef CALLDEBUG
	calldbg("setdefp") ;
#endif
	p_scpy(sunname, "M:") ;
}

void sunvn(void)
{
#ifdef CALLDEBUG
	calldbg("sunvn") ;
#endif
	suntalk ("Sunvn") ;
	feedback("3.27") ;
}

 void suniv(void)
{
#ifdef CALLDEBUG
	calldbg("suniv") ;
#endif
	suntalk ("Suniv") ;
	if (vrb)
		feedback("YES") ;
	else
		feedback("NO") ;
}

 void sunia (void)
{
#ifdef CALLDEBUG
	calldbg("sunia") ;
#endif
	suntalk ("Sunia") ;
	if (tmode == MODEASCII)
		feedback("YES") ;
	else
		feedback("NO") ;
}

void sunix (void)
{
#ifdef CALLDEBUG
	calldbg("sunix") ;
#endif
	suntalk ("Sunix") ;
	if (tmode == MODEXMODEM)
		feedback("YES") ;
	else
		feedback("NO") ;
}

 void sunis (void)
{
#ifdef CALLDEBUG
	calldbg("sunis") ;
#endif
	suntalk ("Sunis") ;
	if (scr)
		feedback("YES") ;
	else
		feedback ("NO") ;
}

 void sunds (void)
{
#ifdef CALLDEBUG
	calldbg("sunds") ;
#endif
	suntalk ("Sunds") ;
	feedback ("START") ;
	p_scpy(tmp, "Path ") ;
	p_scat(tmp, sunname) ;
	putline(tmp,1) ;
	feedback ("END") ;
}

 void sunvb (void)
{
#ifdef CALLDEBUG
	calldbg("sunvb") ;
#endif
	if (vrb == 0)
	{
		vrb = 1 ;
		suntalk ("Sunvb on") ;
	}
	else
	{
		vrb = 0 ;
		suntalk("Sunvb off") ;
	}
	feedback("OK") ;
	wvb() ;
}

#ifdef CALLDEBUG
 void suned (void)
{
    /* end debugging */
    INT ret ;
    ret = p_close (logd) ;
    logfile = 0 ;
    if (ret != 0)
    {
    	feedback("BADCLOSE") ;
    	return ;
    }
    else
    {
    	feedback("GOODCLOSE") ;
    	return ;
    }
    
}

 void sunsd (void)
{
    /* start debugging */
    INT ret ;
    ret = p_open(&logd, sunname, P_FSTREAM | P_FUPDATE | P_FCREATE) ;
    if (ret != 0)
    {
    	feedback("BADOPEN") ;
    	logfile = 0 ;
    	return ;
    }
    /* succesfully opened the log file */
    else
    {
    	feedback("GOODOPEN") ;
    	logfile = 1 ;
    	return ;
    }
}
#endif
 void sunsc (void)
{
#ifdef CALLDEBUG
	calldbg("sunsc") ;
#endif
	if (scr == 0)
	{
		scr = 1;
		suntalk("Sunsc ON") ;
		wpath() ;
		wsc() ;
		wvb() ;
		wtm() ;
		wsline() ;
		wline() ;
		wssnd() ;
		wsnd() ;
		wCancelBusyMsg() ;
	}
	else
	{
		scr = 0 ;
		suntalk("Sunsc OFF") ;
		wSetBusyMsg("Display Updates OFF", W_CORNER_BOTTOM_LEFT | 0) ; 
	}
	feedback ("OK") ;
	wsc() ;
}

 void suntm (void)
{
#ifdef CALLDEBUG
	calldbg("suntm") ;
#endif
	if (tmode == MODEASCII)
	{
		feedback("BADMODE") ;
	}
	else
	{
		tmode = MODEBINARY ;
		suntalk ("BINARY") ;
	}
	feedback ("OK") ;
	wtm() ;
}
 void suntx (void)
{
#ifdef CALLDEBUG
	calldbg("suntx") ;
#endif
	if (tmode == MODEASCII)
	{
		feedback("BADMODE") ;
	}
	else
	{
		tmode = MODEXMODEM ;
		suntalk ("XMODEM") ;
	}
	feedback ("OK") ;
	wtm() ;
}

 void setpath(void)
{
#ifdef CALLDEBUG
	calldbg("setdefp") ;
#endif
	p_scpy(sunname, "M:") ;
}
 void sunsp(void)
{
#ifdef CALLDEBUG
	calldbg("sunsp") ;
#endif
	if (linelen < 4)
	{
		feedback("BADPARAM") ;
		return;
	}
	p_scpy(sunname, (dectxt + 3)) ;
	p_scpy(tmp, "Sunsp ") ;
	p_scat(tmp, sunname) ;
	suntalk (tmp) ;
	updsp() ;
	feedback("OK") ;
}
 void suntf(void)
{
	TEXT tmp [100] ;
	TEXT len [10], *lenptr ;
	LONG ilen ;
	ULONG ulen ;
	VOID *fileh ;
	INT ret ;
#ifdef CALLDEBUG
	calldbg("suntf") ;
#endif
	if (linelen < 4)
	{
		feedback("BADPARAM") ;
		return;
	}
	lenptr = len ; /* avoid compile time warnings */
	p_scpy(len, (dectxt + 3)) ;
	p_scpy(tmp, "Sunsp ") ;
	p_scat(tmp, " ") ;
	p_scat(tmp, len) ;
	p_stol(&lenptr, &ilen) ;
	ulen = (ULONG) ilen ;
	ret = p_open(&fileh, sunname, P_FOPEN | P_FSTREAM | P_FUPDATE) ;
	if ( ret < 0 )
	{
		feedback("BADOPEN") ;
		return ;
	}
	ret = p_iow(fileh, P_FSETEOF, &ulen) ;
	if (ret < 0)
	{
		feedback("BADSETEOF") ;
		return;
	}
	ret = p_close (fileh) ;
	if (ret < 0)
	{
		feedback ("BADCLOSE") ;
		return ;
	}
	suntalk (tmp) ;
	feedback("OK") ;
}
 void sunfc(void)
{
#ifdef CALLDEBUG
	calldbg("sunfc") ;
#endif
	if (linelen < 4)
	{
		feedback("BADPARAM") ;
		return;
	}
	if (dectxt[3] == '1')
	{
		filecs = 1 ;
		suntalk("File transfer binary checking on") ;
	}
	else if (dectxt[3] == '0')
	{
		filecs = 0 ;
		suntalk("File transfer binary checking off") ;
	}
	else
	{
		feedback("BADPARAM") ;
		return;
	}
	feedback ("OK") ;
}

 void sundt(void)
{
#ifdef CALLDEBUG
	calldbg("sundt") ;
#endif
	if (linelen < 4)
	{
		feedback("BADPARAM") ;
		return ;
	}
	p_scpym(tmp, "Sundt ", (dectxt + 3)) ;
	suntalk (tmp) ;
	feedback ("OK") ;
}

 void updsp(void)
{
#ifdef CALLDEBUG
	calldbg("updsp") ;
#endif
	wpath() ;
}


 void sunep(void)
{
	P_INFO fstat ;
	INT ret ;
#ifdef CALLDEBUG
	calldbg("sunep") ;
#endif
	p_scpym(tmp, (TEXT * ) "Sunep ", sunname, NULL) ;
	suntalk(tmp) ;
	ret = p_finfo(sunname, &fstat) ;
	if (ret == 0)
		feedback ("YES") ;
	else
	{
		feedback ("NO") ;
	}
	
}

 void sunlp(void)
{
	VOID * tmpd ;
	P_INFO fstat ;
	P_FPARSE pstruct ;
	TEXT ltmp[300];
#ifdef CALLDEBUG
	calldbg("sunlp") ;
#endif
	p_scpym(tmp, "Sunlp ", sunname, NULL) ;
	suntalk(tmp) ;
	feedback("STARTLIST") ;
	if (p_open(&tmpd, sunname, P_FDIR) != 0)
	{
		feedback("BADPATH") ;
		return ;
	}
	/* as we are now dealing with the full pathname we need to break it
	down to its parts and to then build it up to get the real pathname */
	/* allow wild cards */
	pstruct.flags = P_PWILD_ANY ;
	p_fparse(sunname, "", tmp, &pstruct) ;
	/* now build up the initial details from the structure , just use the device , directory
	though to save on bandwidth */
	/* set the appropriate nulls */
	tmp[pstruct.system+pstruct.device+pstruct.path] = '\0';
	p_scpy(ltmp, tmp+pstruct.system) ;
	while(p_iow(tmpd, P_FREAD, tmp, &fstat) != E_FILE_EOF)
	{
		/* we use ptmp here as we are alread using tmp and I dont like
		the idea of hacking the strings around as I'm not a good enough
		C programer to decide what will be overwritten when ! */
		p_scpym(ptmp, ltmp, tmp, NULL) ;
		putline(ptmp,1) ;
	}
	p_close(tmpd) ;
	feedback("ENDLIST") ;
}

 void sunrp(void)
{
#ifdef CALLDEBUG
        calldbg("sunrp") ;
#endif 
        p_scpym(tmp, "Sunrp ", sunname, NULL) ;
        suntalk(tmp) ;
        if (p_delete((TEXT * ) sunname) != 0)
        {
                feedback("BADRF") ;
        }
        else
        {
                feedback("OK") ;
        }
}
 void sunsz(void)
{
	P_INFO fileinfo ;
	TEXT tmp[100] ;
#ifdef CALLDEBUG
	calldbg("sunsz") ;
#endif
	p_scpym(tmp, "Sunsz ", sunname, NULL) ;
	suntalk(tmp) ;
	if (p_finfo(sunname,&fileinfo) != 0)
	{
		feedback("BADPATH") ;
		return ;
	}
	tmp[p_ltob(tmp,fileinfo.size)] = 0 ;
	feedback(tmp) ;
}
 void sunti(void)
{
	P_INFO fileinfo ;
	TEXT tmp[100] ;
#ifdef CALLDEBUG
	calldbg("sunti") ;
#endif
	p_scpym(tmp, "Sunti ", sunname, NULL) ;
	suntalk(tmp) ;
	if (p_finfo(sunname,&fileinfo) != 0)
	{
		feedback("BADPATH") ;
		return ;
	}
	/* this is the mod time in seconds, we can just transfer this
	   as unix uses time in seconds from midnight on  1/1/1970 */
	tmp[p_ltob(tmp,fileinfo.modst)] = 0 ;
	feedback(tmp) ;
}
 void sunwy(void)
{
	P_INFO fileinfo ;
#ifdef CALLDEBUG
	calldbg("sunwy") ;
#endif
	p_scpym(tmp, (TEXT * ) "Sunwy ", sunname, NULL) ;
	suntalk(tmp) ;
	/* does the file exist */
	if (p_finfo(sunname,&fileinfo) != 0)
	{
		feedback("BADPATH") ;
		return ;
	}
	/* set the appropriate bit */
	if (p_sfstat(sunname, P_FAWRITE, P_FAWRITE) == 0)
	{
		feedback ("OK") ;
		return ;
	}
	else
	{
		feedback ("BADSET") ;
		return ;
	}
}
 void sunwn(void)
{
	P_INFO fileinfo ;
#ifdef CALLDEBUG
	calldbg("sunwn") ;
#endif
	p_scpym(tmp, (TEXT * ) "Sunwn ", sunname, NULL) ;
	suntalk(tmp) ;
	/* does the file exist */
	if (p_finfo(sunname,&fileinfo) != 0)
	{
		feedback("BADPATH") ;
		return ;
	}
	/* set the appropriate bit */
	if (p_sfstat(sunname, 0, P_FAWRITE) == 0)
	{
		feedback ("OK") ;
		return ;
	}
	else
	{
		feedback ("BADSET") ;
		return ;
	}
}

 void sunrw(void)
{
	P_INFO fileinfo ;
	TEXT tmp[100] ;

#ifdef CALLDEBUG
	calldbg("sunrw") ;
#endif
	p_scpym(tmp, "Sunrw ", sunname, NULL) ;
	suntalk(tmp) ;
	if (p_finfo(sunname,&fileinfo) != 0)
	{
		feedback("BADPATH") ;
		return ;
	}
	if (fileinfo.status & P_FAWRITE)
	{
		feedback("RW") ;
	}
	else
	{
		feedback("RO") ;
	}
}

 void sunft(void)
{
	P_INFO fileinfo ;
	TEXT tmp[100] ;
#ifdef CALLDEBUG
	calldbg("sunft") ;
#endif
	p_scpym(tmp, "Sunft ", sunname, NULL) ;
	suntalk(tmp) ;
	if (p_finfo(sunname,&fileinfo) != 0)
	{
		feedback("BADPATH") ;
		return ;
	}
	tmp[0] = 0 ;
	
	if (fileinfo.status & P_FADIR)
	{
		p_scat(tmp, "DIR ") ;
	}
	else if (fileinfo.status & P_FATEXT)
	{
		p_scat(tmp,"TEXT ") ;
	}
	else if (fileinfo.status & P_FAHIDDEN)
	{
		p_scat(tmp,"HIDDEN ") ;
	}
	else if (fileinfo.status & P_FASYSTEM)
	{
		p_scat(tmp,"SYSTEM ") ;
	}
	else if (fileinfo.status & P_FAVOLUME)
	{
		p_scat(tmp,"VOLUME ") ;
	}
	feedback(tmp) ;
}


 void sundc(void)
{
#ifdef CALLDEBUG
	calldbg("sundc") ;
#endif
	suntalk("Sundc") ;
	feedback("DISCONNECTED") ;
}

 void sunpp(void)
{
	char path[P_FNAMESIZE] ;
#ifdef CALLDEBUG
	calldbg("sunpp") ;
#endif
	p_scpym(tmp, "Sunpp ", NULL) ;
	suntalk(tmp) ;
	p_getpth(path) ;
	/* remove the LOC:: bit, we know about that and return the string */
	feedback (path + 5) ;
}
	

 void suncd(void)
{
#ifdef CALLDEBUG
	calldbg("suncd") ;
#endif
	p_scpym(tmp, "Suncd ", sunname, NULL) ;
	suntalk(tmp) ;
	if (p_setpth(sunname) != 0)
	{
		feedback("BADRCD") ;
	}
	else
	{
		feedback("OK") ;
	}
}


 void sunmd(void)
{
#ifdef CALLDEBUG
	calldbg("sunmd") ;
#endif
	p_scpym(tmp, "Sunmd ", sunname, NULL) ;
	suntalk(tmp) ;
	if (p_mkdir(sunname) != 0)
	{
		feedback("BADMKDIR") ;
	}
	else
	{
		feedback("OK") ;
	}
}

 void sungf (void)
{

#ifdef CALLDEBUG
	calldbg("sungf") ;
#endif
	if (tmode == MODEASCII)
	{
		sungfb() ;
	}
	else if (tmode == MODEXMODEM)
	{
		sungfx() ;
	}
	else
	{
		sungfb() ;
	}
}
 void sungfx(void)
{
	TEXT buff[XMDMBUFSIZE] ;
	INT obuff_len ;
	VOID * fcb ;
	UWORD mode, type ;
	INT  io_stat, ret  ;
#ifdef CALLDEBUG
	calldbg("sungfx") ;
#endif
	p_scpym(tmp, "Sungfx ", sunname, NULL) ;
	suntalk(tmp) ;
	feedback("STARTPUT") ;
	ret = p_open(&fcb, sunname, P_FREPLACE | P_FSTREAM|P_FUPDATE) ;
	if (ret < 0)
		suntalk ("Error in opening file") ;

	obuff_len = XMDMBUFSIZE ;

	/* open the xmdm stuff */
	io_stat = p_open(&devh, "XMD:", -1) ; /* attach xmodem drivers to serial line */
	if (io_stat < 0)
		suntalk("Error in opening xmdm drvrs") ;
	/* connect to remote xmodem */
	type=P_XMDM_INIT ; /* we are starting the link */
	mode = P_XMDM_CRCMODE ;
	io_stat=p_iow(devh,P_FCONNECT, &type, &mode) ;
	if (io_stat <0)
		suntalk ("Error in connect") ;
	/* we now have the xmodem connection */
	FOREVER
	{
		io_stat = p_read(devh, buff, obuff_len) ;
		if (io_stat == E_FILE_EOF)
			break ;
		if (io_stat == 0)
			break ;
		if (io_stat < 0)
			suntalk("Error reading xmodem") ;
		io_stat = p_write(fcb, buff, obuff_len) ;
		if (io_stat < 0)
			suntalk("Error writting to file") ;
	}
	/* close the file */
	io_stat = p_close(fcb) ;
	if (io_stat <0)
		suntalk ("Error closing output file") ;
	/* remove the xmodem stuff from the device handler */
	io_stat = p_close(devh) ;
	if (io_stat <0)
		suntalk("Error in removing xmdm drivers") ;
}

 void sungfb(void)
{
	INT ret, tctr, dctr, max;
	INT pcs, scs ;
	UWORD v ;
	TEXT tmp[200], mysumstr[10], * mysumptr ;
#ifdef CALLDEBUG
	calldbg("sungfb") ;
#endif
	p_scpym(tmp, "Sunfgb ", sunname, NULL) ;
	suntalk(tmp) ;
	feedback("STARTGET") ;
	ret = p_open(&fileh, sunname, P_FSTREAM | P_FUPDATE | P_FCREATE) ; ;
	if ( ret != 0 )
	{
		feedback("BADOPEN") ;
		p_print("p_open returns %d\n", ret) ;
		return ;
	}
	else
	{
		feedback("GOODOPEN") ;
	}
#ifdef CALLDEBUG
	calldbg("Recieving file") ;
	calldbg(sunname) ;
	calldbg("got to a good open") ;
#endif
	/* loop, getting the line , decoding it and writting it */
	while (ret == 0)
	{
		ioget() ;
		if (p_scmp("XE", dectxt) == 0)
			break ;
		/* if we are checksumming at the file transfer level */
		if (filecs)
		{
			pcs = 0 ;
			scs = 1 ;
			while (pcs != scs)
			{
				/* extract the sun checksum */
				mysumstr[0] = dectxt[0] ;
				mysumstr[1] = dectxt[1] ;
				mysumstr[2] = '\0' ;
				dctr = 2 ; /* skip over the sun generated checksum */
				tctr = 0 ;
				max = p_slen(dectxt);
				/* decode the line */
				while (dctr < max)
				{
					tmp[tctr] = (((dectxt[dctr] - 'A') * 16) + (dectxt[dctr + 1] - 'A')) ;
					tctr ++ ;
					dctr += 2 ;
				}
				/* I dont know why this has to be like this but
				   it seems to be important */
				mysumptr = &mysumstr[0] ;
				/* get the checksum from the sun */
				p_stog(&mysumptr,&v, 16) ;
				scs = (INT) v ;
				/* compute our current checksum */
				pcs = 0;
				dochksum(&pcs,tmp,tctr) ;
				/* are they the same, is everything OK ? */
				if (pcs == scs)
				{
					feedback("G") ;
				}
				else
				{
					feedback("B") ;
					/* reget the line */
					ioget() ;
				}
			}
			/* we have now assembled the output line, lets write it */
			ret = p_write(fileh, tmp, tctr) ;
#ifdef CALLDEBUG
			calldbg("Writing data line");
#endif
		}
		else
		{
			dctr = 0 ;
			tctr = 0 ;
			max = p_slen(dectxt) ;
			/* decode the line */
			while (dctr < max)
			{
				tmp[tctr] = (((dectxt[dctr] - 'A') * 16) + (dectxt[dctr + 1] - 'A')) ;
				tctr ++ ;
				dctr += 2 ;
			}
			/* we have now assembled the output line, lets write it */
			ret = p_write(fileh, tmp, tctr) ;
#ifdef CALLDEBUG
			calldbg("Writing data line");
#endif
		}
	}
#ifdef CALLDEBUG
	calldbg("Finished get, about to close file") ;
	calldbg("Last data recieved was") ;
	calldbg(dectxt) ;
#endif
	if (ret != 0)
	{
		feedback("BADGET") ;
		ret = p_close(fileh) ;
		return ;
	}
	ret = p_close(fileh) ;
	if (ret != 0)
	{
		feedback("BADGET") ;
		return ;
	}
	
	feedback("ENDGET") ;
}

 void suncs(void)
{
	int sum ;
	TEXT htxt [20] ;
	INT ret ;
#ifdef CALLDEBUG
	calldbg("suncs") ;
#endif
	p_scpym(tmp, "Suncs ", sunname, NULL) ;
	suntalk(tmp) ;
	feedback("STARTSUM") ;
	ret = p_open(&fileh, sunname, P_FOPEN | P_FSTREAM | P_FSHARE) ;
	if ( ret < 0 )
	{
		feedback("BADOPEN") ;
		return ;
	}
	else
	{
		feedback("GOODOPEN") ;
	}
	sum = 0 ;
	ret = 0 ;
	while ( ret >= 0)
	{
		ret = p_read(fileh, dectxt, MAXRD) ;
		if (ret <= 0)
		{
			break ;
		}
		else
		{
			dochksum(&sum, dectxt, ret) ;
		}
	}
	if ((ret != E_FILE_EOF) && ( ret != 0))
	{
		feedback("BADSUM") ;
		p_close(fileh) ;
		return ;
	}
	p_atos(htxt,"%d",sum) ;

	feedback(htxt) ;
	feedback("ENDSUM") ;
	p_close(fileh) ;
}
void dochksum(number, str,limit)
int * number ;
int limit ;
char * str ;
{
        int i ;
        int res ;
        res = *number ;
        for (i = 0 ; i < limit ; i ++)
        {
                res = 0xff & (res + str[i]) ;
        }
        *number = res ;
}


 void sunpf()
 {
#ifdef CALLDEBUG
	calldbg("sunpf") ;
#endif
	if (tmode == MODEBINARY)
 	{
 		sunpfb() ;
 	}
 	else if (tmode == MODEXMODEM)
 	{
 		sunpfx() ;
 	}
 }
 
 void sunpfx(void)
{
	TEXT buff[XMDMBUFSIZE] ;
	INT obuff_len ;
	VOID * fcb ;
	UWORD mode, type ;
	INT io_stat, ret , zero ;
#ifdef CALLDEBUG
	calldbg("sunpfx") ;
#endif
	p_scpym(tmp, "Sunpfx ", sunname, NULL) ;
	suntalk(tmp) ;
	feedback("STARTPUT") ;
	ret = p_open(&fcb, sunname, P_FOPEN | P_FSTREAM | P_FSHARE) ;

	obuff_len = XMDMBUFSIZE ;
	zero = 0 ;

	/* open the xmdm stuff */
	io_stat = p_open(&devh, "XMD:", -1) ; /* attach xmodem drivers to serial line */
	if (io_stat < 0)
		suntalk("Error in opening xmdm drvrs") ;
	/* connect to remote xmodem */
	type=P_XMDM_ACCP ; /* wait for remote end to init link */
	mode = P_XMDM_CRCMODE ;
	io_stat=p_iow(devh,P_FCONNECT, &type, &mode) ;
	/* we now have the xmodem connection */
	FOREVER
	{
		io_stat = p_read(fcb, buff, obuff_len) ;
		if (io_stat == E_FILE_EOF)
			break ;
		if (io_stat < 0)
			suntalk("Error reading file") ;
		io_stat = p_iow(devh, P_FWRITE, buff, &obuff_len) ;
		if (io_stat < 0)
			suntalk("Error writting to xmodem") ;
	}
	/* send the end of file thingy */
	io_stat = p_iow(devh, P_FWRITE, buff, &zero) ;
	if (io_stat < 0)
		suntalk ("Error in sending xmdm EOF") ;
	/* close the file */
	io_stat = p_close(fcb) ;
	if (io_stat <0)
		suntalk ("Error closing input file") ;
	/* disconnect the xmodem */
	io_stat=p_iow(devh, P_FDISCONNECT, zero, zero) ;
	if (io_stat < 0)
		suntalk ("Error in disconnecting xmdm") ;
	/* remove the xmodem stuff from the device handler */
	io_stat = p_close(devh) ;
	if (io_stat <0)
		suntalk("Error in removing xmdm drivers") ;
	zero ++ ; ret ++ ; /* avoid nasty compiler warnings about zero never being used */
}

 void sunpfb(void)
{
	INT ret, hctr, dctr, chksum ;
	TEXT mytxt[255];
#ifdef CALLDEBUG
	calldbg("sunpfb") ;
#endif
	p_scpym(tmp, "Sunpfb ", sunname, NULL) ;
	suntalk(tmp) ;
	feedback("STARTPUT") ;
	ret = p_open(&fileh, sunname, P_FOPEN | P_FSTREAM | P_FSHARE) ;
	if ( ret < 0 )
	{
		feedback("BADOPEN") ;
		return ;
	}
	else
	{
		feedback("GOODOPEN") ;
	}
	ret = 0 ;
	while ( ret >= 0)
	{
		ret = p_read(fileh, mytxt, MAXRD) ;
		if (ret <= 0)
		{
			break ;
		}
		hctr = dctr = 0 ;
		/* are we file transfer level binary checksumming if so
		   install the checksum */
		if (filecs)
		{
			/* determine the checksum */
			chksum = 0;
			dochksum(&chksum,mytxt,ret) ;
			/* install the checksum */
			/* convert the ascii to hex */
			/* use a bit mask and index array, p_gtob doesn't seem
			   to be able to handle it properley */
			hextxt[hctr++] = hexarr[(chksum & 0x00F0) >> 4] ;
			hextxt[hctr++] = hexarr[chksum & 0x000F] ;
		} /* carry on hctr has been incremented as required */
		/* process the string to convert to Binary from ASCII */
		while (dctr < ret)
		{
			/* convert the ascii to hex */
			/* use a bit mask and index array, p_gtob doesn't seem
			   to be able to handle it properley */
			hextxt[hctr++] = hexarr[(mytxt[dctr] & 0x00F0) >> 4] ;
			hextxt[hctr++] = hexarr[mytxt[dctr++] & 0x000F] ;
		}
		/* terminate the string */
		hextxt[hctr] = '\0' ;
		/* send the line */
		putline(hextxt, 1) ;
		/* is we are checksumming at the file transfer level wait for 
		   a response, if it is G just carry on otherwise resend and 
		   wait for a G */
		if (filecs)
		{
			dectxt[0] = 'B' ;
			while (dectxt[0] != 'G')
			{
				ioget() ;
				/* if not good resend */
				if (dectxt[0] != 'G')
					putline(hextxt,1) ;
			}
		}
	}
	feedback("E") ;
	if ((ret != E_FILE_EOF) && ( ret != 0))
	{
		feedback("BADPUT") ;
		p_close(fileh) ;
	}
	feedback("ENDPUT") ;
	p_close(fileh) ;
}

 void sunsl(void)
{
#ifdef CALLDEBUG
	calldbg("sunsl") ;
#endif
	suntalk("Sunsl") ;
	sndline = 0 ;
	feedback("OK") ;
	wsnd() ;
}

 void sunrl(void)
{
#ifdef CALLDEBUG
	calldbg("sunrl") ;
#endif
	suntalk("Sunrl") ;
	lineid = 0 ;
	feedback("OK") ;
	wline() ;
}

/* Process related functions WARNING these are dangerous, done mess with them */
 void sunpl(void)
{
	HANDLE h ;
	TEXT b[E_MAX_NAME+2], procspec[E_MAX_NAME+5] ;
	TEXT tmp[40];
#ifdef CALLDEBUG
	calldbg("sunpl") ;
#endif
	if (linelen < 4)
	{
		/* is a parameter is not supplied list all processes */
		p_scpy(procspec, "*") ;
	}
	else
	{
		/* make sure that we are not going to overflow the buffer */
		if ((p_slen(dectxt) - 3) > E_MAX_NAME)
		{
			feedback("BADPARAM") ;
			return ;
		}
		/* if dectxt[3] is * (i.e all of them resolve it down to **/
		if (((p_slen(dectxt) -3) == 1) && (dectxt[3] == '*'))
		{
			p_scpy(procspec, "*") ;
		}
		else
		{
			/* list the processes given */
			p_scpym(procspec, "*",(dectxt + 3), "*", NULL) ;
		}
	}
	p_scpym(tmp, "sunpl: ", procspec, NULL) ;
	suntalk(tmp) ;
	feedback("STARTLIST") ;
	for (h = 0 ; h >= 0 ;)
	{
		h = p_pfind(h,procspec, &b[0]) ;
		if (h >= 0)
			putline(b,1) ;
	}
	feedback("ENDLIST") ;
}
 
 void sunpo (void)
{
#ifdef CALLDEBUG
	calldbg("sunpo") ;
#endif
	if (linelen < 4)
	{
		feedback("BADPARAM") ;
		return;
	}
	if(dectxt[3] == '0') /* disable protection, naughty */
	{
		procprot = 0 ;
		feedback("OFF") ;
		suntalk("Process Kill protection IS OFF") ;
	}
	else 
	{
		procprot = 1 ;
		feedback("ON") ;
		suntalk("Process Kill protection IS ON") ;
	}
}

/* this routine sends p_pterminate signals to processes. THIS IS VERY 
   DANGEROUS ! normaly we do sensible checking to make cure we are not 
   doing anything rash, if procprot is set to 0 however anything goes */ 
 void sunpk(void)
 {
 	HANDLE h ;
 	INT ret,  dontkill ;
 	INT cnt ;
 	TEXT procname[E_MAX_NAME+10] ;
 	TEXT retname[E_MAX_NAME+2] ;
 	TEXT tmp[10] ;
 	TEXT tmp1[40] ;
 #ifdef CALLDEBUG
 	calldbg("sunpk") ;
 #endif
	if (linelen < 4)
	{
		feedback("BADPARAM") ;
		return;
	}
	/* make sure that we are not going to overflow the buffer */
	if ((p_slen(dectxt) - 3) > E_MAX_NAME)
	{
		feedback("BADPARAM") ;
		return ;
	}
 	h = 0 ;
 	cnt = 0 ;
 	ret = 0 ;
 	/* get a working copy of the string */
 	if (((p_slen(dectxt) -3) == 1) && (dectxt[3] == '*'))
 	{
 		p_scpy(procname, "*") ;
 	}
 	else
 	{
 		p_scpym(procname,"*",&dectxt[3],"*",NULL) ;
 	}
 	/* say what we are doing */
	p_scpym(tmp1, "Sunpk: ", procname, NULL) ;
	suntalk(tmp1) ;
 	/* capitalise it */
 	p_scap(procname) ;
 	/* find the first process */
 	h = p_pfind(h, procname, &retname[0]) ;
 	if (h < 0)
 	{
 		/* no process */
 		feedback("KILLNOPROC") ;
 		return ;
 	}
 

 	/* do the killing of all matching processes*/
 	for ( ; h >= 0 ; )
 	{
 		/* if procprot is in place dont kill processes containing
 		   TIME, SUNCOM or SYS in the process name */
 		dontkill = 0 ;
  		if (procprot != 0) /* failsafe incase procprot has been munged*/
 		{
 			/* is TIME at the start ? */
 			if (p_ssubi(retname, "TIME") == 0)
 			{
 				dontkill = 1 ;
 			}
 			/* is suncom there */
 			if (p_ssubi(retname,"SUNCOM") == 0) 
 			{
 				dontkill = 1 ;
 			}
 			/* is SYS there */
 			if (p_ssubi(retname,"SYS") == 0)
 			{
 				dontkill = 1 ;
 				/* it's OK to kill SYS$PRGO processes as they 
 				   are OPL processes. to have got here we know
 				   SYS is in the name so just check for PRGO */
 				if (p_ssubi(retname, "PRGO") >= 0)
 				{
 					dontkill = 0 ;
 				}
  			}
 		}
 		/* if dontkill has not been set to 1 we can kill this process */
 		if (dontkill == 0)
 		{
 			ret = p_pterminate(h,0) ;
 			cnt ++ ;
 		}
  		if (ret != 0)
 		{
 			feedback("KILLERRPROC") ;
  			return ;
 		}
 		/* find the next process */
 		/* reset h to zero as the existing process has died ! */
 		/* but ony is this was a killed process */
 		if (dontkill == 0)
 			h = 0 ;
 		h = p_pfind(h, procname, &retname[0]) ;
  	}
 	/* report back on what we have done */
 	p_atos(tmp,"%d",cnt) ; 
 	feedback(tmp) ;
 }
 /* this routine sends messages to clients of the window manager (virtualy all 
    processes appart from system ones) instructing them to shutdown. It's realy
    upto the application as to how they interpret these messages (or if they 
    handle them at all) but the psion builtin apps all save their state and
    gracefully exit and I'd assume most processes will do the same */
 void sunps(void)
 {
 	HANDLE h ;
 	INT ret,  dontkill ;
 	INT cnt ;
 	TEXT procname[E_MAX_NAME+10] ;
 	TEXT retname[E_MAX_NAME+2] ;
 	TEXT tmp[10] ;
 	TEXT tmp1[40], cmdline[127] ;
 #ifdef CALLDEBUG
 	calldbg("sunps") ;
 #endif
	if (linelen < 4)
	{
		feedback("BADPARAM") ;
		return;
	}
	/* make sure that we are not going to overflow the buffer */
	if ((p_slen(dectxt) - 3) > E_MAX_NAME)
	{
		feedback("BADPARAM") ;
		return ;
	}
 	h = 0 ;
 	cnt = 0 ;
 	ret = 0 ;
 	/* get a working copy of the string */
 	if (((p_slen(dectxt) -3) == 1) && (dectxt[3] == '*'))
 	{
 		p_scpy(procname, "*") ;
 	}
 	else
 	{
 		p_scpym(procname,"*",&dectxt[3],"*",NULL) ;
 	}
 	/* say what we are doing */
	p_scpym(tmp1, "Sunps: ", procname, NULL) ;
	suntalk(tmp1) ;
 	/* capitalise it */
 	p_scap(procname) ;
 	/* find the first process */
 	h = p_pfind(h, procname, &retname[0]) ;
 	if (h < 0)
 	{
 		/* no process */
 		feedback("SDNOPROC") ;
 		return ;
 	}
 

 	/* do the shutdown of all matching processes*/
 	for ( ; h >= 0 ; )
 	{
 		/* if procprot is in place dont shutdown processes containing
 		   TIME, SUNCOM or SYS in the process name */
 		dontkill = 0 ;
  		if (procprot != 0) /* failsafe incase procprot has been munged*/
 		{
 			/* is TIME at the start ? */
 			if (p_ssubi(retname, "TIME") == 0)
 			{
 				dontkill = 1 ;
 			}
 			/* is suncom there */
 			if (p_ssubi(retname,"SUNCOM") == 0) 
 			{
 				dontkill = 1 ;
 			}
 			/* is SYS there */
 			if (p_ssubi(retname,"SYS") == 0)
 			{
 				dontkill = 1 ;
 				/* it's OK to shutdown SYS$PRGO processes as they 
 				   are OPL processes. to have got here we know
 				   SYS is in the name so just check for PRGO */
 				if (p_ssubi(retname, "PRGO") >= 0)
 				{
 					dontkill = 0 ;
 				}
  			}
 		}
 		/* if dontkill has not been set to 1 we can kill this process */
 		if (dontkill == 0)
 		{
 			/* build the command line to shutdown the process*/
 			ret = buildcmd('X', "", NULL, NULL, NULL, cmdline) ;
 			ret = wSendCommand(h,(VOID *) cmdline, (UINT) ret) ;
 			cnt ++ ;
 			/* hang aroung for a little bit so the process has a chance to shutdown */
 			p_sleep((ULONG) SHUTDOWNSLEEP) ;
 		}
  		if (ret != 0)
 		{
 			feedback("SDERRPROC") ;
  			return ;
 		}
 		/* find the next process */
 		/* reset h to zero as the existing process has died ! */
 		/* but ony is this was a shutdown process */
 		if (dontkill == 0)
 			h = 0 ;
 		h = p_pfind(h, procname, &retname[0]) ;
  	}
 	/* report back on what we have done */
 	p_atos(tmp,"%d",cnt) ; 
 	feedback(tmp) ;
 }

 void initscr(void)
{
	
#ifdef CALLDEBUG
	calldbg("initscr") ;
#endif
	/* paths window */
	wdpath.extent.tl.x = 0 ;
	wdpath.extent.tl.y = 60 ;
	wdpath.extent.width = 235 ;
	wdpath.extent.height = 15 ;
	wdpath.flags = W_WIN_PRIORITY ;
	wdpath.mouse_icon = 0 ;
	wdpath.filler = 0;
	wdpath.background = W_WIN_BACK_BITMAP ;
	/* the toggles window */
	wdtog.extent.tl.x = 120 ;
	wdtog.extent.tl.y = 0 ;
	wdtog.extent.width = 115 ;
	wdtog.extent.height = 35 ;
	wdtog.flags = W_WIN_PRIORITY ;
	wdtog.mouse_icon = 0 ;
	wdtog.filler = 0;
	wdtog.background = W_WIN_BACK_BITMAP ;
	/* the message window */
	wdtalk.extent.tl.x = 0 ;
	wdtalk.extent.tl.y = 40 ;
	wdtalk.extent.width = 235 ;
	wdtalk.extent.height = 15 ;
	wdtalk.flags = W_WIN_PRIORITY ;
	wdtalk.mouse_icon = 0 ;
	wdtalk.filler = 0;
	wdtalk.background = W_WIN_BACK_BITMAP ;
	/* the recieved line window */
	wdline.extent.tl.x = 0 ;
	wdline.extent.tl.y = 0 ;
	wdline.extent.width = 115 ;
	wdline.extent.height = 15 ;
	wdline.flags = W_WIN_PRIORITY ;
	wdline.mouse_icon = 0 ;
	wdline.filler = 0;
	wdline.background = W_WIN_BACK_BITMAP ;
	/* the sent line window */
	wdsnd.extent.tl.x = 0 ;
	wdsnd.extent.tl.y = 20 ;
	wdsnd.extent.width = 115 ;
	wdsnd.extent.height = 15 ;
	wdsnd.flags = W_WIN_PRIORITY ;
	wdsnd.mouse_icon = 0 ;
	wdsnd.filler = 0;
	wdsnd.background = W_WIN_BACK_BITMAP ;
	/* setup the gc data structs (all the same realy ) */
	gdline.gmode = G_TRMODE_SET ;
	gdline.textmode = G_TRMODE_REPL ;
	gdline.style = G_STY_NORMAL ;
	gdline.filler = 0 ;
	gdline.font = WS_FONT_BASE ;
	gdsnd.gmode = G_TRMODE_SET ;
	gdsnd.textmode = G_TRMODE_REPL ;
	gdsnd.style = G_STY_NORMAL ;
	gdsnd.filler = 0 ;
	gdsnd.font = WS_FONT_BASE ;
	gdtog.gmode = G_TRMODE_SET ;
	gdtog.textmode = G_TRMODE_REPL ;
	gdtog.style = G_STY_NORMAL ;
	gdtog.filler = 0 ;
	gdtog.font = WS_FONT_BASE ;
	gdpath.gmode = G_TRMODE_SET ;
	gdpath.textmode = G_TRMODE_REPL ;
	gdpath.style = G_STY_NORMAL ;
	gdpath.filler = 0 ;
	gdpath.font = WS_FONT_BASE ;
	gdtalk.gmode = G_TRMODE_SET ;
	gdtalk.textmode = G_TRMODE_REPL ;
	gdtalk.style = G_STY_NORMAL ;
	gdtalk.filler = 0 ;
	gdtalk.font = WS_FONT_BASE ;
	/* actualy create the sub windows */
	/* the path data window */
	winpath= wCreateWindow(0, W_WIN_EXTENT | W_WIN_BACKGROUND , &wdpath, 1) ;
	wInitialiseWindowTree(winpath) ;
	gcpath= gCreateGC(winpath, G_GC_MASK_GMODE | G_GC_MASK_TEXTMODE | G_GC_MASK_STYLE, &gdpath) ;
	wMakeVisible(winpath) ;
	gSetGC0(gcpath) ;
	gBorder(W_BORD_CUSHION|W_BORD_SHADOW_S|W_BORD_SHADOW_ON) ;
	wpath() ;
	/* the  togles window */
	wintog= wCreateWindow(0, W_WIN_EXTENT | W_WIN_BACKGROUND , &wdtog, 2) ;
	wInitialiseWindowTree(wintog) ;
	gctog= gCreateGC(wintog, G_GC_MASK_GMODE | G_GC_MASK_TEXTMODE | G_GC_MASK_STYLE, &gdtog) ;
	wMakeVisible(wintog) ;
	gSetGC0(gctog) ;
	gBorder(W_BORD_CUSHION|W_BORD_SHADOW_S|W_BORD_SHADOW_ON) ;
	wvb() ;
	wtm() ;
	wsc() ;
	/* the message window */
	wintalk= wCreateWindow(0, W_WIN_EXTENT | W_WIN_BACKGROUND , &wdtalk, 3) ;
	wInitialiseWindowTree(wintalk) ;
	gctalk= gCreateGC(wintalk, G_GC_MASK_GMODE | G_GC_MASK_TEXTMODE | G_GC_MASK_STYLE, &gdtalk) ;
	wMakeVisible(wintalk) ;
	gSetGC0(gctalk) ;
	gBorder(W_BORD_CUSHION|W_BORD_SHADOW_S|W_BORD_SHADOW_ON) ;
	wtalk("") ;
	/* the recieved line count */
	winline= wCreateWindow(0, W_WIN_EXTENT | W_WIN_BACKGROUND , &wdline, 4) ;
	wInitialiseWindowTree(winline) ;
	gcline= gCreateGC(winline, G_GC_MASK_GMODE | G_GC_MASK_TEXTMODE | G_GC_MASK_STYLE, &gdline) ;
	wMakeVisible(winline) ;
	gSetGC0(gcline) ;
	gBorder(W_BORD_CUSHION|W_BORD_SHADOW_S|W_BORD_SHADOW_ON) ;
	wsline() ;
	wline() ;
	/* the sent line count */
	winsnd= wCreateWindow(0, W_WIN_EXTENT | W_WIN_BACKGROUND , &wdsnd, 5) ;
	wInitialiseWindowTree(winsnd) ;
	gcsnd= gCreateGC(winsnd, G_GC_MASK_GMODE | G_GC_MASK_TEXTMODE | G_GC_MASK_STYLE, &gdsnd) ;
	wMakeVisible(winsnd) ;
	gSetGC0(gcsnd) ;
	gBorder(W_BORD_CUSHION|W_BORD_SHADOW_S|W_BORD_SHADOW_ON) ;
	wssnd() ;
	wsnd() ;
	/* ensure that any screen message is nolonger displayed */
	wCancelBusyMsg() ;
}

 void sunol(void)
{
#ifdef CALLDEBUG
	calldbg("sunol") ;
#endif
	feedback("ONLINE") ;
}

 void shutdown(void)
{
#ifdef CALLDEBUG
	calldbg("shutdown") ;
#endif
	p_close(devh) ;
	/* I think that we should destroy the graphics contexts and windows  */
	wFree(gcline) ;
	wFree(gcsnd) ;
	wFree(gcpath) ;
	wFree(gctog) ;
	wFree(gctalk) ;
	wDisconnect() ;
}

 void wpath(void)
{
#ifdef CALLDEBUG
	calldbg("wpart") ;
#endif
	if (scr != 1)
		return ;
	gSetGC0(gcpath) ;
	p_scpym(wtmp, "Path : ", sunname, spacestr, NULL) ;
	gPrintClipText(5, 10, wtmp, p_slen(wtmp), FULLWIDTH) ;
}

 void wvb(void)
{
#ifdef CALLDEBUG
	calldbg("wvb") ;
#endif
	if (scr != 1)
		return ;
	gSetGC0(gctog) ;
	if (vrb)
		p_scpym(wtmp, "Verbose : YES", spacestr, NULL) ;
	else
		p_scpym(wtmp, "Verbose : NO  ", spacestr, NULL) ;
	gPrintClipText(5 ,10, wtmp, p_slen(wtmp),HALFWIDTH) ;
}

 void wtm(void)
{
#ifdef CALLDEBUG
	calldbg("wtm") ;
#endif
	if (scr != 1)
		return ;
	if (tmode == MODEASCII)
		p_scpym(wtmp, "Transfer : ASCII", spacestr, NULL) ;
	else if (tmode == MODEXMODEM)
		p_scpym(wtmp, "Transfer : XMODEM", spacestr, NULL) ;
	else
		p_scpym(wtmp, "Transfer : BINARY ", spacestr, NULL) ;
	gSetGC0(gctog) ;
	gPrintClipText(5, 20, wtmp, p_slen(wtmp), HALFWIDTH) ;
}

 void wsc(void)
{
#ifdef CALLDEBUG
	calldbg("wsc") ;
#endif
	gSetGC0(gctog) ;
	if (scr == 0)
		p_scpym(wtmp, "Screen Update NO", spacestr, NULL) ;
	else
		p_scpym(wtmp, "Screen Update YES", spacestr, NULL) ;
	gPrintClipText(5, 30, wtmp, p_slen(wtmp) , HALFWIDTH) ;
}

 void wtalk( TEXT * msg)
{
#ifdef CALLDEBUG
	calldbg("wtalk") ;
#endif
	if (scr != 1)
		return ;
	gSetGC0(gctalk) ;
	wtmp[0] = '\0' ;
	p_scpym(wtmp, msg, spacestr, NULL) ;
	gPrintClipText(5,10,wtmp, p_slen(wtmp), FULLWIDTH ) ;
}

 void wsline(void)
{
#ifdef CALLDEBUG
	calldbg("wsline") ;
#endif
	gSetGC0(gcline) ;
	p_scpy(wtmp, "Recieved Ctr :");
	gPrintText(5, 10, wtmp, p_slen(wtmp)) ;
	lineidpt = gTextWidth(WS_FONT_BASE, G_STY_NORMAL, wtmp, p_slen(wtmp)) ;
}

 void wssnd(void)
{
#ifdef CALLDEBUG
	calldbg("wssnd") ;
#endif
	gSetGC0(gcsnd) ;
	p_scpy(wtmp, "Sent Ctr : ");
	gPrintText(5,10,wtmp, p_slen(wtmp)) ;
	sndlinept = gTextWidth(WS_FONT_BASE, G_STY_NORMAL, wtmp, p_slen(wtmp)) ;
}

 void wline(void)
{
	TEXT linet[10] ;
#ifdef CALLDEBUG
	calldbg("wline") ;
#endif
	if (scr != 1) 
		return ;
	gSetGC0(gcline) ;
	linet[p_itob(linet, lineid)] = '\0' ;
	p_scpym(wtmp, linet, spacestr, NULL) ;
	gPrintClipText(lineidpt, 10, wtmp, p_slen(wtmp), HALFWIDTH - lineidpt) ;
	
}

 void wsnd(void)
{
	TEXT linet[10] ;
#ifdef CALLDEBUG
	calldbg("wsnd") ;
#endif
	if (scr != 1)
		return ;
	gSetGC0(gcsnd) ;
	linet[p_itob(linet, sndline)] = '\0' ;
	p_scpym(wtmp, linet, "  ", NULL) ;
	gPrintClipText(sndlinept, 10, wtmp, p_slen(wtmp), HALFWIDTH - sndlinept) ;
}

 void suntalk(TEXT *msg)
{
	
	if (scr != 1)
		return ;
	wtalk(msg) ;
}

INT buildcmd(TEXT cmdbyte, TEXT * appname, TEXT * appext, TEXT * appalias, TEXT * fname, TEXT * cmdline)
{
	TEXT * cmdptr;
	INT cmdlen ;

	/* initialisation */
	cmdlen = 0 ;
	cmdptr = cmdline ;
	/* do the command byte */
		/* insert it */
		* cmdptr = cmdbyte ;
		/* the length has just been increased */
		cmdlen ++ ;
		/* move cmdptr allong one to skip over the command */
		cmdptr ++ ;
	/* insert the appname */
		/* insert it */
		p_scpy(cmdptr, appname) ;
		/* move over it and the \0 */
		cmdptr = cmdptr + p_slen(appname) +1 ;
		/* add the length and the \0 to the total length */
		cmdlen = cmdlen + p_slen(appname) +1 ;
	/* insert the extension and other stuff if appext is non NULL */
	if (appext != NULL)
	{
		/* insert the extension */
		p_scpy(cmdptr, appext) ;
		/* move over it BUT NOT THE NULL (we may have an alias)*/
		cmdptr = cmdptr + p_slen(appext) ;
		/* add the length to the total length */
		cmdlen = cmdlen + p_slen(appext) ;

		/* if the alias is non NULL add it */
		if (appalias != NULL) 
		{
			/* insert a space */
			*cmdptr = ' ' ;
			/* move over the space */
			cmdptr ++ ;
			/* add the space to the total length */
			cmdlen ++ ;
			/* insert the appalias */
			p_scpy(cmdptr, appalias) ;
			/* move over the alias BUT NOT THE NULL (then is dealt with below)*/
			cmdptr = cmdptr + p_slen(appalias) ;
			/* increment the total length */
			cmdlen = cmdlen + p_slen(appalias) ;
		}

		/* because we have not accounted for the \0 at the end of the appext / appext+appalias
		   move over it now */
		cmdptr ++ ;
		cmdlen ++ ;

		/* if there is a filename add it */
		if (fname != NULL)
		{
			/*insert the filename */
			p_scpy(cmdptr, fname) ;
			/* add the length and vF \0 to the total length */
			cmdlen = cmdlen + p_slen(fname) + 1 ;
			/* we done need to move cmdptr as we are at the end of the operatrion */
		}
	}
	/* return with the length of the assembled string */
	return(cmdlen) ;
}

