
/*	KERMSRV		Kermit-11 server for Bitnet on node UOFT02	*/
/*			Interface to Jnet				*/
/*									*/
/*	23-APR-1985 09:02 Brian Nelson					*/
/*									*/
/*	Edits:								*/
/*									*/
/*	29-APR-1985 BDN	Fix DIR command if no argument (force *.*)	*/
/*	30-APR-1985 BDN	Check $STATUS after DIR and SEND. Add SET NOON	*/
/*	11-SEP-1985 BDN Fix bugs introduced with VAX C v2 (and bad code)*/
/*	02-Apr-1986 BDN Jnet version 2 mods				*/
/*									*/
/*									*/
/*									*/
/*									*/
/*	$ cc kermsrv							*/
/*	$ link kermsrv+jan_sys:bitlib/lib				*/
/*	$ cop kermsrv.exe jan_sys:					*/
/*	$ cp								*/
/*	define kermsrv/link/daemon=kermsrv				*/
/*	start kermsrv							*/
/*	$ exit								*/
/*									*/
/*	Runs as a detached process for user KERMSRV.  All replies  are	*/
/*	either terminal messages or batch jobs accessing the jnet SEND	*/
/*	command.							*/

#include	<descrip.h>
#include	<stdio.h>
#include	<opcdef>
#define	then


extern char *getmsg(),*malloc(),*strchr() , *strcat() , *strcpy() , *tmpnam() ;
extern char *upcase() ;

int vmserror ;

struct dsc {
		int len ;
		char *addr ;
	   } ;

FILE *infile ;

char sysmsg[257] ;

char kermsrv[] = "KERMSRV     " ;
char kermsrv_dir[] = "SYS$SYSROOT:[KERMSRV]" ;

main(argc,argv)
int argc ;
char *argv[] ;
{
	char msg[100],buffer[80],opmsg[140] ;
	int msglen,status ;
	char node[10],user[10] ;
	struct dsc nodedsc = { 8,&node } ;
	struct dsc userdsc = { 8,&user } ;
	struct dsc msgbuf  = { 100,&msg } ;
	struct dsc opdsc   = { 120,&opmsg } ;
	$DESCRIPTOR(nulldsc,"\0") ;
	$DESCRIPTOR(local_node,"UOFT02") ;
	$DESCRIPTOR(local_user,"KERMSRV") ;
	$DESCRIPTOR(local_msguser,"BRIAN") ;
	int mode ;

	mode = 2 ;
	
	if ( jan_daemon_init(&local_user) == 0 ) then return(0) ;

	while (1) {

	  if ( (status=jan_receive_msg(&mode,&nodedsc,&userdsc
				      ,&msgbuf,&msglen))==0 )
		then  sys$hiber() ;
		else
		  if ( mode != 2 )
			{
			msgbuf.len = msglen&0377 ;
			str$concat(&opdsc,&nodedsc,&userdsc,&msgbuf,&nulldsc) ;
			sendopcom(opdsc.addr) ; 
			*(nodedsc.addr+(nodedsc.len&0377)) = 0 ;
			*(userdsc.addr+(userdsc.len&0377)) = 0 ;
			*(msgbuf.addr+ (msgbuf.len&0377))  = 0 ;
			upcase(msgbuf.addr) ; 
			docommand(nodedsc.addr,userdsc.addr,msgbuf.addr) ;
			msgbuf.len = 100 ;
			}
		  }


}





#define	TEXTFILE 1
#define	JNETDUMP 2

docommand(node,user,msgbuf)

char *node,*user,*msgbuf ;

{

#define	SEND	1
#define	HELP	2
#define	DIR	3
#define	SENT	4
#define VMSDUMP	5

	struct cmdtype	{
			char command[8] ;
			int index ;
			} ;

	static struct cmdtype cmdlist[]
				 = {	"SEND",SEND,
					"HELP",HELP,
					"DIR" ,DIR ,
					"SENT",SENT,
					"VMS" ,VMSDUMP,
					"VMSDUMP",VMSDUMP,
					""    ,0
				   } ;
	struct cmdtype *cmdp ;
	char *s,*d,cmd[100],arg[100] ;
	int i ;

	d = cmd ;
	s = msgbuf ;
	while ( *s == ' ' ) s++ ;
	while ( *s && *s != ' ' ) *d++ = *s++ ;
	*d = 0 ;
	while ( *s == ' ' ) s++ ;
	d = arg ;
	while ( (*d = *s++) != 0 && *d != ' ') d++ ;
	*d = 0 ;
	i = 0 ;

	cmdp = &cmdlist[0] ;
	while ( cmdp->command[0] != 0 && strcmp(cmd,cmdp->command) != 0 )
		cmdp++ ;
	switch( cmdp->index ) {
		case SEND:
			sendfile(arg,node,user,TEXTFILE) ;
			break ;
		case VMSDUMP:
			sendfile(arg,node,user,JNETDUMP) ;
			break ;
		case DIR:
			senddir(arg,node,user) ;
			break ;
		case HELP:
			sendhelp(arg,node,user) ;
			break ;
		case SENT:	/* Ignore messages for file forwarding */
			break ;
		default:
			sendbad(cmd,node,user) ;
			break ;
			}
}






/*	SENDDIR		send a directory listing to remote		*/


senddir(f,node,user)
char *f ;
char *node,*user ;
{
	char tmpout[100],tmpcom[100] ;
	char cmd[133] ;
	char s[256],*cp,*dp ;
	struct dsc cmdline ;
	int flags,i,m ;

	m = 2 ;
	cp = f ;
	dp = s ;
	for ( i=strlen(f); i > 0; i-- ) if ( (*dp = *cp++) > ' ' ) then dp++ ;
	*dp = 0 ;
	if ( s[0] == 0 ) then strcpy(s,"*.*") ;
	if ( checksyntax(s) == 0 )
	  then	{
		sendmsg(node,user,"Bad filename syntax or access violation");
		return(vmserror=0) ;
		}
	  else	{
		strcpy(tmpcom,kermsrv_dir) ;
		strcpy(tmpout,kermsrv_dir) ;
		strcat(tmpcom,tmpnam(cmd)) ;
		strcat(tmpout,tmpnam(cmd)) ;
		strcat(tmpcom,".COM") ;
		strcat(tmpout,".LIS") ;
		if ( ( infile = fopen(tmpcom,"w") ) == NULL )
		  then	{
			vmserror = 0 ;
			return(0) ;
			}
		  else	{	
			sendmsg(node,user,"The file will be sent shortly") ;
			fputs("$ SET NOON\012",infile) ;
			fputs("$ dq = \"\"\"\012",infile) ;
			strcpy(cmd,"$ DIR/SIZE/DATE/OUT=") ;
			strcat(cmd,tmpout) ;
			strcat(cmd," ") ;
			strcat(cmd,"KERBIN:,KER:") ;
			strcat(cmd,s) ;
			strcat(cmd,"\012") ;
			fputs(cmd,infile) ;
			fputs("$ dirstatus = $STATUS\012",infile) ;
			fputs("$ if dirstatus then goto sendit\012",infile) ;
			fputs("$ erm = dq + f$mes(dirstatus) + dq\012",infile);
			strcpy(cmd,"$ SEND/REM ") ;
			strcat(cmd,node) ;
			strcat(cmd," ") ;
			strcat(cmd,user) ;
			strcat(cmd," 'erm\012") ;
			fputs(cmd,infile) ;
			fputs("$ exit\012",infile) ;
			fputs("$sendit:\012",infile) ;
			strcpy(cmd,"$ SEND/FILE ") ;
			strcat(cmd,tmpout) ;
			strcat(cmd," ") ;
			strcat(cmd,user) ;
			strcat(cmd,"@") ;
			strcat(cmd,node) ;
			strcat(cmd,"\012") ;
			fputs(cmd,infile) ;
			fclose(infile) ;
			vmserror = sendbatch(tmpcom,0) ;
			}
		}
	return(vmserror & 1) ;
}



sendfile(s,node,user,type)
char *s ;
char *node,*user ;
int type ;
{
	char tmpcom[100] ;
	char cmd[133] ,*cmd_name ;
	int flags,wild ;
	char text_com[] = "$ SEND/FILE KER:" ;
	char bin_com[]  = "$ SEND/FILE/VMSDUMP KERBIN:" ;

	if ( checksyntax(s) == 0 )
	  then	{
		sendmsg(node,user,"Bad filename syntax or access violation");
		return(vmserror=0) ;
		} ;
	wild = 0 ;
	if ( strchr(s,'*') != 0 )
	  then	{
		sendmsg(node,user,"Your request will not be honored until") ;
		sendmsg(node,user,"23:00 hours EST since your filename is") ;
		sendmsg(node,user,"wildcarded") ;
		wild = 1 ;
		} ;
	if ( strchr(s,'.') == 0 )
	  then	{
		sendmsg(node,user,"Please include an explicit filetype") ;
		sendmsg(node,user,"As in: SEND K11*.MAC or SEND AA*.TXT") ;
		return(0) ;
		} ;
	if ( strcmp(s,"*.*") == 0 )
	  then	{
		sendmsg(node,user,"Please wildcard FILENAME or FILETYPE only");
		sendmsg(node,user,"as there are over 60,000 blocks of Kermit");
		sendmsg(node,user,"files on this node") ;
		return(0) ;
		}
	  else	if ( findfile(s,type) == 0 )
		  then	sendmsg(node,user,getmsg(vmserror)) ;
		  else	{
			sendmsg(node,user,"The file(s) will be sent shortly") ;
			strcpy(tmpcom,kermsrv_dir) ;
			strcat(tmpcom,tmpnam(cmd)) ;
			strcat(tmpcom,".COM") ;
			cmd_name = ( type == JNETDUMP ) ?bin_com:text_com ;

			if ( ( infile = fopen(tmpcom,"w") ) == NULL )
			  then	{
				vmserror = 0 ;
				return(0) ;
				}
			  else	{	
				fputs("$ SET NOON\012",infile) ;
				fputs("$ dq = \"\"\"\012",infile) ;
				strcat(strcpy(cmd,cmd_name),s) ;
				strcat(cmd," ") ;
				strcat(cmd,user) ;
				strcat(cmd,"@") ;
				strcat(cmd,node) ;
				strcat(cmd,"\012") ;
				fputs(cmd,infile) ;
				fputs("$ sts = $STATUS\012",infile) ;
				fputs("$ if sts then goto ex\012",infile) ;
				fputs("$ erm = dq+f$mes(sts)+dq\012",infile);
				strcpy(cmd,"$ SEND/REM ") ;
				strcat(cmd,node) ;
				strcat(cmd," ") ;
				strcat(cmd,user) ;
				strcat(cmd," 'erm\012") ;
				fputs(cmd,infile) ;
				strcpy(cmd,"$ SEND/FILE KER:NOTFOUND.TEXT ");
				strcat(strcat(strcat(cmd,user),"@"),node) ;
				fputs(strcat(cmd,"\012"),infile) ;
				fputs("$ex:\012",infile) ;
				fputs("$ exit\012",infile) ;
				fclose(infile) ;
				vmserror = sendbatch(tmpcom,wild) ;
				}
			}
	return(vmserror & 1) ;
}


sendhelp(s,node,user)
char *s ;
char *node,*user ;

{

sendmsg(node,user,"Commands are SEND file, DIR file, and VMSDUMP file") ;
sendmsg(node,user,"VMSDUMP file can be used to get executable files in");
sendmsg(node,user,"jnet VMSDUMP format (ie, .EXE, .TSK, .SAV files).") ;

}


sendbad(s,node,user)
char *s ;
char *node,*user ;
{
	struct dsc nd,ud,em ;
	char msg[133] ;

	strcpy(msg,"Unknown command UOFT02 Kermsrv - ") ;
	strcat(msg,s) ;
	sendmsg(node,user,msg) ;
}





sendmsg(node,user,msg)
char *node,*user,*msg ;
{
	struct dsc nd,ud,md ;
	int mode ;

	mode = 2 ;
	md.addr = msg ;
	md.len  = strlen(msg) ;
	nd.addr = node ;
	nd.len  = strlen(node) ;
	ud.addr = user ;
	ud.len  = strlen(user) ;
	jan_send_msg(&mode,&nd,&ud,&md) ;
}


checksyntax(s)
char *s ;
{
	extern char *strchr() ;

	return(    strchr(s,'[') == 0 && strchr(s,':') == 0
		&& strchr(s,'<') == 0 ) ;
}

	





findfile(f,type)
char *f ;
int type ;
{

/*	Verify that at least one file will match the filename passed	*/
/*	so that we can have some assurance that the batch job we submit	*/
/*	to do the actual send will succeed.				*/

	char fname[256] ;
	struct dsc$descriptor_s srcbuf ;
	struct dsc$descriptor_d resbuf ;
	int context,status ;

	$DESCRIPTOR(def_spec,"KER:*.*") ;
	$DESCRIPTOR(alt_spec,"KERBIN:*.*") ;

	strcpy(fname,f) ;
	if ( strchr(fname,'.') == 0 ) then strcat(fname,"*.*") ;
	context = 0 ;
	srcbuf.dsc$w_length = strlen( fname ) ;
	srcbuf.dsc$b_class  = DSC$K_CLASS_S ;
	srcbuf.dsc$b_dtype  = DSC$K_DTYPE_T ;
	srcbuf.dsc$a_pointer = fname ;

	resbuf.dsc$w_length = 0 ;
	resbuf.dsc$b_class  = DSC$K_CLASS_S ;
	resbuf.dsc$b_dtype  = DSC$K_DTYPE_D ;
	resbuf.dsc$a_pointer = 0 ;
	
	switch (type) {
	  case TEXTFILE:
		vmserror = lib$find_file(&srcbuf,&resbuf,&context,&def_spec) ;
		break ;
	  case JNETDUMP:
		vmserror = lib$find_file(&srcbuf,&resbuf,&context,&alt_spec) ;
		break ;
	} ;
	lib$find_file_end(&context) ;
	return( vmserror & 1 ) ;
	
}




sendopcomdsc(s)
struct dsc *s ;
{
	char *m ;
	int slen ;

	slen = s->len & 0xFFFF ;
	if ( (m=malloc(slen + 1)) != 0 )
	  then	{
		strncpy(m,s->addr,slen) ;
		m[slen] = 0 ;
		sendopcom(m) ;
		free(m) ;
		} ;
}

sendopcom(s)
char *s ;

/*	Send a asciz message to opcom					*/
{

	struct opcfmt {
			unsigned char type ;
			short int target_0_15 ;
			unsigned char target_16_23 ;
			unsigned long rqstid ;
			char msg[80] ;
		      } ;
	struct dsc    {
			long length ;
			struct opcfmt *addr ;
		      } ;

	struct opcfmt msgdsc ;
	struct dsc opmsg = { 80,&msgdsc } ;
	int reply_chan,status ;

	reply_chan = 0 ;
	msgdsc.type = OPC$_RQ_RQST ;
	msgdsc.target_0_15 = OPC$M_NM_CENTRL ;
	msgdsc.target_16_23 = 0 ;
	msgdsc.rqstid = 0 ;
	strcpy(msgdsc.msg,s) ;
	opmsg.length = 8 + strlen(msgdsc.msg) ;
	opmsg.addr = &msgdsc ;
	return( (vmserror=sys$sndopr(&opmsg,reply_chan)) & 1 ) ;

}	

char *getmsg(n)
int n ;
{
	struct dsc msgd ;
	int mlen ;
	char junk[4] ;

	mlen = 0 ;
	msgd.len = 256 ;
	msgd.addr = sysmsg ;
	sys$getmsg(n,&mlen,&msgd,0,&junk) ;
	sysmsg[mlen] = 0 ;
	return( &sysmsg ) ;
}
	




sendbatch(f,late)
char *f ;
int late ;
{

#define	SJC$_AFTER_TIME		3
#define	SJC$_ENTER_FILE		19
#define	SJC$_QUEUE		134
#define	SJC$_FILE_SPECIFICATION	42
#define	SJC$_NO_LOG_SPOOL	101
#define	SJC$_NO_DELETE_FILE	25
#define	SJC$_USERNAME		159

	struct itmlst	{
			short int buflen;
			short int code	;
			char *bufadr	;
			int *retlen	;
			} ;

	$DESCRIPTOR(latetime,"-- 23:00:00.00") ;
	static struct itmlst dobatch[10] ;
	int status,iosb[2],abstime[2] ;

	static char batch[] = "SYS$BATCH" ;

	sys$bintim(&latetime,&abstime) ;
	dobatch[0].buflen = strlen(batch) ;
	dobatch[0].code   = SJC$_QUEUE ;
	dobatch[0].bufadr = &batch ;
	dobatch[0].retlen = 0 ;
	dobatch[1].buflen = strlen(f) ;
	dobatch[1].code   = SJC$_FILE_SPECIFICATION ;
	dobatch[1].bufadr = f ;
	dobatch[1].retlen = 0 ;
	dobatch[2].buflen = 0 ;
	dobatch[2].code   = SJC$_NO_LOG_SPOOL ;
	dobatch[2].bufadr = 0 ;
	dobatch[2].retlen = 0 ;
	dobatch[3].buflen = 12 ;
	dobatch[3].code   = SJC$_USERNAME ;
	dobatch[3].bufadr = &kermsrv ;
	dobatch[3].retlen = 0 ;
	if (late)
	  then	{
		dobatch[4].buflen = 8 ;
		dobatch[4].code   = SJC$_AFTER_TIME ;
		dobatch[4].bufadr = &abstime ;
		dobatch[4].retlen = 0 ;
		}
	  else	{
		dobatch[4].buflen = 0 ;
		dobatch[4].code   = 0 ;
		} ;
	dobatch[5].buflen = 0 ;
	dobatch[5].code   = 0 ;

	status = sys$sndjbcw(0,SJC$_ENTER_FILE,0,&dobatch,&iosb,0,0) ;
	return(iosb[0]) ;
}
		





char *upcase(s)
char *s ;
{
	char *cp ;
	cp = s ;
	while ( *cp ) { *cp = toupper(*cp) ; cp++ ; } ;
	return(s) ;
}

char *lowcase(s)
char *s ;
{
	char *cp ;
	cp = s ;
	while ( *cp ) { *cp = tolower(*cp) ; cp++ ; } ;
	return(s) ;
}
