/* 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 */ /* 21-OCT-1986 BDN Change from Daemon to run as a hook. */ /* 21-OCT-1986 BDN PUNCH command (include :READ File Type Date)*/ /* 4-NOV-1986 BDN Remove trailing spaces from USER and NODE */ /* 10-NOV-1986 BDN Remove call to STAT(), replace with FSTAT() */ /* due to bug in C RTL version of STAT. */ /* 20-APR-1987 BDN Treat SYSTEM messages as no-ops. Got into a loop*/ /* with ARIZMIS sending messages telling KERMSRV */ /* to send messages to explicit vaxcluster nodes. */ /* */ /* */ /* */ /* */ /* $ cc kermsrv */ /* $ link kermsrv+jan_sys:bitlib/lib */ /* $ cop kermsrv.exe jan_sys: */ /* $ run/det/proc=kermsrv jan_sys: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 #include #include #include #define then extern char *getmsg(),*malloc(),*strchr() , *strcat() , *strcpy() , *tmpnam() ; extern char *upcase() ; int vmserror ; #define QUE_SIZE 200 /* Size of file to defer sending */ struct dsc { int len ; char *addr ; } ; FILE *infile ,*header_file ; char sysmsg[257] ; char kermsrv[] = "KERBATCH " ; char kermsrv_dir[] = "SYS$SYSROOT:[KERMSRV]" ; char note_file[] = "SYS$SYSROOT:[KERMSRV]XFER.INFO" ; main(argc,argv) int argc ; char *argv[] ; { char msg[100],buffer[80],opmsg[140], *cp ; 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) ;*/ if ( jan_hook_init(&mode,&local_user) == 0 ) 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 ; cp = userdsc.addr ; while ( *cp ) { if ( *cp == ' ' ) *cp = 0; cp++; } ; cp = nodedsc.addr ; while ( *cp ) { if ( *cp == ' ' ) *cp = 0; cp++; } ; upcase(msgbuf.addr) ; if ( ! ( *userdsc.addr == 0 || *userdsc.addr == ' ' ) ) docommand(nodedsc.addr,userdsc.addr,msgbuf.addr) ; msgbuf.len = 100 ; } } } #define TEXTFILE 1 #define JNETDUMP 2 #define PUNCHFILE 3 docommand(node,user,msgbuf) char *node,*user,*msgbuf ; { #define SEND 1 #define HELP 2 #define DIR 3 #define SENT 4 #define VMSDUMP 5 #define PUNCH 6 struct cmdtype { char command[10] ; int index ; } ; static struct cmdtype cmdlist[] = { "SEND",SEND, "HELP",HELP, "DIR" ,DIR , "DIRECTORY",DIR, "INDEX",DIR, "SENT",SENT, "VMS" ,VMSDUMP, "VMSDUMP",VMSDUMP, "SENDME",SEND, "SEN",SEND, "GET",SEND, "PUNCH",PUNCH, "PUN",PUNCH, "?",HELP, "" ,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++ ; if ( *d == ' ' ) { *d++ = '.' ; 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: if (strcmp(arg,"DIR") == 0 || strcmp(arg,"INDEX") == 0) senddir("*.*",node,user) ; else sendfile(arg,node,user,TEXTFILE) ; break ; case VMSDUMP: sendfile(arg,node,user,JNETDUMP) ; break ; case PUNCH: sendfile(arg,node,user,PUNCHFILE) ; 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 as_name[80],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(as_name,tmpnam(cmd)) ; 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) ; sprintf(cmd,"$ DIR/SIZE/DATE/OUT=%s KERFILES_ALL:%s\n", tmpout,s) ; 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); sprintf(cmd,"$ SEND %s@%s 'erm\n",user,node) ; fputs(cmd,infile) ; sprintf(cmd,"$ SEN/FI NOTFOUND.TEXT %s@%s\n",user,node); fputs(cmd,infile) ; fputs("$ exit\012",infile) ; fputs("$sendit:\012",infile) ; sprintf(cmd,"$SEND/FILE/CON/NAME=%s %s,%s %s@%s\n", as_name,note_file,tmpout,user,node); fputs(cmd,infile) ; fclose(infile) ; vmserror = sendbatch(tmpcom,0) ; } } return(vmserror & 1) ; } sendfile(s,node,user,type) char *s ; char *node,*user ; int type ; { struct stat *attrs,*getstat() ; char tmpcom[100],tmpcmd[100],*cp ; char cmd[133] ,*cmd_name,read_header[100],read_header_name[100],*fn; int flags,i,wild ; char punch_com[]= "$ SEND/FIL/CONC/NAM=%s SYS$SYSROOT:[KERMSRV]%s.HDR,KER:"; char text_com[] = "$ SEND/FILE KER:" ; char bin_com[] = "$ SEND/FILE/VMSDUMP KERFILES_ALL:" ; char notfound[] = "$ SEND/FILE SYS$SYSROOT:[KERMSRV]NOTFOUND.TEXT " ; char sendsoon[] = "The file(s) will be sent shortly" ; char sendlate[] = "Due to size of this file, it will be sent at 23:00"; char *chk_time[]= { "$ now = f$cvt(f$tim())\n", "$ endtime = f$cvt(\"08:00:00.0\")\n", "$ if now .ges. f$cvt(\"22:00:00.0\") -\n", " then endtime = f$cvt(\"TOMORROW+08:00\")\n", "$ if now .lts. endtime then goto doit\n", "" } ; if ( checksyntax(s) == 0 ) then { sendmsg(node,user,"Bad filename syntax or access violation"); return(vmserror=0) ; } ; wild = 0 ; if ( strchr(s,'*') != 0 || strchr(s,'%') != 0 ) then { if ( type == PUNCHFILE ) { sendmsg(node,user,"Wildcards are not allowed with the PUNCH"); sendmsg(node,user,"command. Use the SEND command for this.") ;; } else { 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. Please do not abuse policy") ; sendmsg(node,user,"by resubmitting individual filenames.") ; 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 { sprintf(cmd,"%s%s","KERFILES_ALL:",s) ; if ( wild == 0 ) { attrs = getstat(cmd) ; if ( attrs && (wild = (attrs->st_size/512 > QUE_SIZE)) ) then sendmsg(node,user,sendlate) ; else sendmsg(node,user,sendsoon) ; } ; strcpy(tmpcom,kermsrv_dir) ; strcat(tmpcom,tmpnam(cmd)) ; strcat(tmpcom,".COM") ; switch( type ) { case JNETDUMP: cmd_name = bin_com ; break ; case TEXTFILE: cmd_name = text_com ; break ; case PUNCHFILE: sprintf(read_header_name,"%s%s%s",kermsrv_dir, tmpnam(read_header),".HDR"); header_file = fopen(read_header_name,"w") ; fn = s ; cp = read_header_name ; while ( *cp = *fn++ ) { if (*cp == '.') *cp = ' '; cp++ ;} ; if ( attrs ) sprintf(tmpcmd,":READ %-30.30sA1 %s", read_header_name,ctime(&attrs->st_ctime)) ; else sprintf(tmpcmd,":READ %s",read_header_name) ; fputs(tmpcmd,header_file) ; fclose(header_file) ; sprintf(tmpcmd,punch_com,s,read_header) ; cmd_name = tmpcmd ; break ; } ; if ( ( infile = fopen(tmpcom,"w") ) == NULL ) then { vmserror = 0 ; return(0) ; } else { fputs("$ SET NOON\012",infile) ; fputs("$ dq = \"\"\"\012",infile) ; if ( wild ) { for ( i=0; *chk_time[i] != '\0';i++ ) fputs(chk_time[i],infile) ; sprintf(cmd,"$ SUB/AFT=22:00 %s\n",tmpcom); fputs(cmd,infile) ; fputs("$ EXIT\n",infile) ; fputs("$DOIT:\n",infile) ; } ; sprintf(cmd,"%s%s %s@%s\n",cmd_name,s,user,node); fputs(cmd,infile) ; fputs("$ sts = $STATUS\012",infile) ; fputs("$ if sts .eq. 1 then goto ex\012",infile) ; fputs("$ if sts .eq. %X7FF42D70 then goto ex\012", infile) ; fputs("$ erm = dq+f$mes(sts)+dq\012",infile); sprintf(cmd,"$ SEND %s@%s 'erm\n",user,node); fputs(cmd,infile) ; strcpy(cmd,notfound); 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,"The commands are SEND file, DIR file, PUNCH file and"); sendmsg(node,user,"VMSDUMP file. PUNCH adds a :READ header into the file"); sendmsg(node,user,"VMSDUMP file can be used to get executable files in") ; sendmsg(node,user,"jnet VMSDUMP format (.EXE,.TSK,.SAV files) and will") ; sendmsg(node,user,"provide protection from nonstandard EBCDIC tables.") ; sendmsg(node,user,"All filenames must be in FILENAME.TYPE or FILE TYPE") ; sendmsg(node,user,"format.") ; } 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,"KERFILES_ALL:*.*") ; 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 PUNCHFILE: 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$KERMIT_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) ; } /* Due to a bug in the CRTL we will have to open, FSTAT and then close. The STAT call never deassigns the I/O channel that the file is accessed on. */ #include struct stat *getstat(f) char *f ; { static struct stat attrs, *ret_attrs ; unsigned int file_d, f_size ; /* if ( stat(f,&attrs) ) return(0) ; else return(&attrs) ; */ if ( ( file_d = open(f,O_RDONLY,0) ) == -1 ) return(0) ; if ( fstat(file_d,&attrs) ) ret_attrs == 0 ; else ret_attrs = &attrs ; close( file_d ) ; return( ret_attrs ) ; }