Article 2615 of vmsnet.uucp:
Path: nntpd.lkg.dec.com!pa.dec.com!news1.digital.com!decwrl!sdd.hp.com!vixen.cso.uiuc.edu!uwm.edu!math.ohio-state.edu!howland.reston.ans.net!ix.netcom.com!netcomsv!uu3news.netcom.com!netcomsv!uu4news.netcom.com!symark!marty
From: marty@symark.com
Newsgroups: vmsnet.uucp
Subject: Re: UUCP bug workaround
Message-ID: <1995Oct16.092157.141@symark.com>
Date: 16 Oct 95 09:21:57 PDT
References: <1995Oct13.171415.140@symark.com>
Organization: Symark Software, A Symark International Company
Lines: 447

In article <1995Oct13.171415.140@symark.com>, marty@symark.com writes:
> 
>        After being bitten by the UUCP mailer bug three times this
>        morning,  I decided to try and do something about it.  

[snip, see previous post for info on the bug and my workaround]

    I've been asked by a few people to post my workaround, so here it is. 
    This hasn't been rigorously tested, so insert the various disclaimers
    about it being provided as is, install at your own risk, YMMV, etc.

    And, as usual, 
>        If anyone can see a major flaw in this reasoning, let me know.

    Here's the C program.  Farther down you'll find the modified 
    UUXQT_DCL.COM.  Compile the I_CHECK program and put the EXE in 
    the UUCP_BIN directory.  If you don't have a C compiler it should
    be pretty easy to write the same thing in any other language, or
    DCL, if you're really hard up for entertainment.

    Put the new UUXQT command procedure in the UUCP_BIN directory also.














/*
!   I_CHECK.C
!
!   Open and read the input file.  See if there are any lines that are
!   over 255 bytes in length.  If so, return zero.  If a parameter isn't
!   passed in, can't open the file, or some other error occurs, don't
!   bother to report it.  This program is to report zero only if an input 
!   line > 255.  DECUS UUCP will go into an infinite loop and fill up a 
!   disk when this happens.  Not a good thing.  This program is called 
!   from a modified UUCP_BIN:UUXQT_DCL.COM procedure.  This program's
!   executable should be called I_CHECK.EXE and be placed in the UUCP_BIN
!   directory so that the modified command procedure can use it.
!
*/
#include <stdio.h>

int main
   ( 
   int   argc, 
   char *argv[]
   )
   {
   FILE *in_file;
   int   in_char, ctr, status;

   if ( argc < 2) 
      {
      printf("P1 should be a filename to check.  Exiting.\n");
      return( 1);
      }
   in_file = fopen( argv[1], "rb", "ctx=stm");
   if ( in_file == NULL)
      {
      printf("Couldn't open %s for binary read.  Exiting.\n", argv[1]);
      return( 1);
      }
   for ( ctr = 0; ( (in_char = fgetc( in_file)) != EOF); ctr++)
      {
      if ( ctr > 255) break;
      if ( ( (char) in_char == '\n') || 
           ( (char) in_char == '\r') ||
           ( (char) in_char == '\000')
         ) ctr = 0;
      }
   fclose( in_file);
   if ( in_char == EOF) return( 1);
   return( 0);
   }








































$ !							UUXQT_DCL.COM
$ SET NOVERIFY
$ verbose = 0		! 1 or 0	! see UUCP_UUXQT_VERIFY below
$ GOTO START
$ !
$ !	This command procedure executes in a subprocess SPAWNed by
$ !	UUXQT.EXE .  
$ !	
$ !	P1	- logical name of mailbox in which to receive commands
$ !	
$ !	UUXQT interprets the lines in the X. file, processes them in 
$ !	ways appropriate for image- rather than DCL-based code (e.g. 
$ !	translates Unix file names to VMS, converts mail addresses), 
$ !	then passes them to this procedure via the mailbox.  The records
$ !	which we'll read in the mailbox are similar to those in the X file.
$ !	They are of the form 
$ !	
$ !	<type> <argument>
$ !	
$ !	<type> is a single character.  It is separated from the <argument>
$ !	by one space; that is, the argument starts with the third character
$ !	in the mailbox record.  Some arguments may contain imbedded spaces. 
$ !	
$ !	The following <types> are recognized:
$ !	
$ !	type	argument	interpretation
$ !	-------	---------------	--------------------------------------------
$ !	0	X.filename	invalid X.file -- an F check failed, or other
$ !				problems were discovered by uuxqt.  
$ !	1	X.filename	valid X.file .  
$ !	H	Hostname	remote site name initiating the command
$ !	U	User		remote user at site Hostname initiating the command
$ !	A	addressee	mail addressee for command 
$ !	I	filename	name of input file for command (VMS filename)
$ !	O	filename	name of output file for command (VMS filename)
$ !	C	command		command to be executed locally.  Must be 
$ !				last in a command sequence
$ !	/	(none)		"end of X.file" indication
$ !
$ !	uuxqt reads the entire X file, then (if it's valid) sends a type-1 
$ !	message followed by (optional, depending on the command) A, H, U, I, 
$ !	and O messages, followed by the C message.  Upon receipt of the C 
$ !	message we begin executing the command (so uuxqt has to send us 
$ !	everything else the command will need before sending the C).  
$ !
$ !	If we die while processing a command we don't want uuxqt to begin 
$ !	processing the next X file, assuming that we're still around.  So after
$ !	sending us the C, uuxqt sends us a / command, and waits until we've
$ !	read it before looking for the next X file.  We don't read the / until
$ !	we're done with the C command and ready for the next X file (0 or 1
$ !	command).  This precludes any overlap in processing between us and 
$ !	uuxqt, but that's okay because uuxqt does very little work.  
$ !
$ !	At the moment the only commands we support are rmail and rnews.  
$ !
$ !	Note to future implementors:  If this beast dies, UUXQT.EXE will
$ !	hang on its next mailbox write, so we have to be *very* robust.  
$ !
$ !	EFA identifies changes by Earle Ake,
$ !	    Internet: fac2%dayton.saic.com@uunet.uu.net    uucp: dayvb!fac2
$ !
$ ! Revisions:
$ !
$ ! 951013 MSK  Put in call to I_CHECK in the DO_RMAIL section.  This will
$ !             check to see if the input file has a line in it greater
$ !             than 255 char.  If so, it reports it and renames the X and 
$ !             D files to UUCP_DUMP:
$ !
$ !             Also fixed a problem in MBX_0.  It would try to mail a 
$ !             bad X file to the postmaster _after_ it renamed it.  The 
$ !             subject string for the message was not built correctly
$ !             either.
$ !
$ !             Also changed how FAILED_RMAIL_COMMON does it's infile rename.  
$ !             It would try to append a ;0 to the filename, which won't 
$ !             work in all situations (f.ex. the filename has been f$parsed)
$ !
$ START:
$	delete == "DELETE"
$	delete/symbol/global/all
$	COMPRESS = "$UUCP_BIN:COMPRESS.EXE"
$	SAY = "WRITE SYS$OUTPUT"
$	BABBLE = "IF (verbose) THEN WRITE SYS$OUTPUT"
$	SAY "UUXQT_DCL starting ", f$time(), " mailbox name is ", p1
$	err = "Can't open mailbox"
$	OPEN/READ/ERROR=ERROR_EXIT MBX 'p1
$
$ INIT_JOB:
$	verify = f$verify(f$trnlnm("UUCP_UUXQT_VERIFY"))! Set overall verify
$ 	verbose = f$trnlnm("UUCP_UUXQT_VERBOSE")	! Set BABBLE mode
$	command = ""
$	Hostname = ""
$	User = ""
$	addressee = ""
$	infile = ""
$	outfile = ""
$	xfile = ""
$	begin_xfile = 1
$	end_xfile = 0
$
$ READ_LOOP:
$	err = "Unexpected EOF or error on mailbox read"
$	ON ERROR THEN GOTO ERROR_CONT
$	BABBLE "  Reading mailbox"
$	READ/END=NORMAL_EXIT/ERROR=ERROR_EXIT MBX cmd_line
$
$	! parse the message
$
$	cmd = f$extr(0,1,cmd_line)
$	arg = f$extr(2,255,cmd_line)
$	BABBLE "  ...command is <", cmd, ">, arg is <", arg, ">"
$
$	IF (begin_xfile) THEN GOTO WANT_BEGIN
$	IF (end_xfile) THEN GOTO WANT_END
$	ON ERROR THEN GOTO ERROR_CONT
$	IF (cmd .eqs. "0" .or. cmd .eqs. "1" .or. cmd .eqs. "/") -
		THEN GOTO UNEXP_CMD
$	GOTO MBX_'cmd
$
$ ERROR_CONT:
$	SAY -
 "Error status ", $status, ", ", f$message($status), ", continuing"
$	SAY err
$	GOTO INIT_JOB
$
$ ERROR_EXIT:
$	SAY -
 "Error status ", $status, ", ", f$message($status), ", aborting"
$	SAY err
$	EXIT 4
$
$ NORMAL_EXIT:
$	SAY "Received EOF on mailbox read, exiting"
$	EXIT 1
$
$ !----------------------------------------------------------------------
$
$ UNEXP_CMD:
$	SAY "* Error while in xfile ", xfile, " cmd is <", cmd, ">, expected one of <AIOC> (ignoring)"
$	GOTO READ_LOOP
$
$ WANT_BEGIN:
$	IF (cmd .eqs. "0") THEN GOTO MBX_0
$	IF (cmd .eqs. "1") THEN GOTO MBX_1
$	SAY "* Error while outside of xfile, cmd is <", cmd, ">, expected one of <01> (ignoring)"
$	GOTO READ_LOOP
$
$ WANT_END:
$	IF (cmd .eqs. "/") THEN GOTO INIT_JOB
$	SAY "* Error at end of xfile ", xfile, " cmd is <", cmd, ">, expected </> (ignoring)"
$	GOTO READ_LOOP
$
$ MBX_0:
$	SAY "* Bad X file ", arg, " moving to the dump"
$	subject = "Bad X file " + arg + " moving to UUCP_DUMP:"
$	MAIL 'arg' uucp_postmaster /SUBJECT=&subject
$	RENAME/LOG 'arg' UUCP_DUMP:X.*
$	GOTO INIT_JOB
$
$ MBX_1:
$	SAY "  Begin X file ", arg, " at ", f$time()
$	xfile = arg
$	begin_xfile = 0
$	GOTO READ_LOOP
$
$ MBX_I:
$	BABBLE "  ...Input file is ", arg
$	infile = arg
$	GOTO READ_LOOP
$
$ MBX_O:
$	BABBLE "  ...Output file is ", arg
$	outfile = arg
$	GOTO READ_LOOP
$
$ MBX_A:
$	BABBLE "  ...Addressee is ", arg
$	addressee = arg
$	GOTO READ_LOOP
$
$ MBX_H:
$	BABBLE "  ...Hostname is ", arg
$	Hostname = arg
$	GOTO READ_LOOP
$
$ MBX_U:
$	BABBLE "  ...User is ", arg
$	User = arg
$	GOTO READ_LOOP
$
$ MBX_C:
$	BABBLE "  ...Command is ", arg
$	end_xfile = 1
$	command = arg
$       
$	IF (f$edit(command, "UPCASE,TRIM") .EQS. "RMAIL") THEN GOTO DO_RMAIL
$	IF (f$edit(command, "UPCASE,TRIM") .EQS. "RNEWS") THEN GOTO DO_RNEWS
$	foreign_command = "UUCP_UUXQT_DCL_FOREIGN_" + command
$	foreign_command = f$trnlnm(foreign_command,"LNM$SYSTEM_TABLE",,"EXECUTIVE")
$	if foreign_command.nes."" THEN GOTO DO_FOREIGN
$
$	SAY "* Error, unsupported command <", command, "> in xfile ", xfile, " (ignoring)"
$	GOTO READ_LOOP
$
$ !----------------------------------------------------------------------
$
$ DO_FOREIGN:
$	saved_priv = f$setprv("")
$	BABBLE "  ...Executing Foreign Extended command <", command, ">"
$	SET NOON
$    	save_ver = f$verify(1)'
$	@'foreign_command' 'infile'
$	saved_status = $status		! 'f$verify(verify)'
$	junk_priv = f$setprv(saved_priv)
$	MAIL NL: uucp_postmaster /Subject="UUCP Foreign command execution:''command', completed with status = ''saved_status'"
$	IF F$SEARCH(infile+"*").nes."" THEN DELETE 'infile'*
$	DELETE 'xfile'		! this one comes to us with a version number
$	GOTO READ_LOOP
$
$ !----------------------------------------------------------------------
$
$ DO_RMAIL:
$	if (f$trnlnm("UUCP_UUXQT_DCL_RMAIL_MX")).and.(f$trnlnm("MX_EXE").nes."")
$	then		! MX mail handler
$	    RMAIL = "$MX_EXE:MX_RMAIL"
$	    rmail_needed_privs = "SYSPRV,DETACH,NETMBX,BYPASS,SYSLCK"
$	else
$	    if (f$trnlnm("UUCP_UUXQT_DCL_RMAIL_PMDF")).and.(f$trnlnm("PMDF_ROOT").nes."")
$	    then	! PMDF mail handler
$		RMAIL = "$PMDF_ROOT:[EXE]UUCP_SLAVE"
$		rmail_needed_privs = "BYPASS,CMKRNL"
$	    else	! Standard DECUS uucp mail handler
$		RMAIL = "MAIL/protocol=UUCP_MAILSHR"
$		rmail_needed_privs = "SYSPRV,DETACH,NETMBX,BYPASS,SYSLCK"
$	    endif
$	endif
$	saved_priv = f$setprv(rmail_needed_privs)
$	addressee = f$edit(addressee,"TRIM")
$	x = 0
$	infile = f$parse(infile)
$ 1:	addr = f$element(x, " ", addressee)
$	if addr .eqs. " " then goto 2
$	if addr .eqs. "" then goto 2
$	t = f$edit(addr,"LOWERCASE")
$	if t .eqs. "postmaster" .or. t .eqs. "root" then addr="UUCP_POSTMASTER"
$	on error then goto failed_rmail
$	if (f$trnlnm("UUCP_UUXQT_DCL_RMAIL_PMDF")).and.(f$trnlnm("PMDF_ROOT").nes."")
$	then
$	    save_ver = f$verify(1)
$	    define/user sys$input 'infile'
$	    RMAIL "''addr'"
$	    save_ver = 'f$verify(verify)'
$	else
$!
$! MSK
$!
$! When using the DECUS UUCP mailer, run the input file through the I_CHECK 
$! program before trying to mail it.  The I_CHECK program reads the file and 
$! determines if there are any lines in it over 255 characters long.  If so, 
$! then reject this file since there is a good chance that it will choke the 
$! mailer and fill up the UUCP_DISK.
$!
$           I_CHECK := $UUCP_BIN:I_CHECK
$	    BABBLE "  ...Running input file through I_CHECK"
$           set noon
$           I_CHECK 'infile
$           if ($status .and. 1) .ne. 1
$           then
$              SAY "* Input file has a line that exceeds 255 bytes."
$              SAY "* Current X file ", xfile
$              SAY "* Current I file ", infile  
$              saved_status = "[Exceeded 255 byte line limit]"
$              goto FAILED_RMAIL_1
$           endif
$	    on error then goto FAILED_RMAIL
$	    save_ver = f$verify(1)
$	    RMAIL 'infile' "''addr'"
$	    save_ver = 'f$verify(verify)'
$	endif
$	x = x + 1
$	goto 1
$ 2:	SET NOON
$	junk_priv = f$setprv(saved_priv)
$	DELETE 'infile'*
$	DELETE 'xfile'		! this one comes to us with a version number
$	GOTO READ_LOOP
$
$ FAILED_RMAIL:
$	saved_status = $status		! 'f$verify(verify)'
$	SAY "Attempt to send mail to <", addr, "> failed with status ", saved_status
$
$ ! If it is older than a few days, then we give up on it and pass it on to the 
$ ! local postmaster.
$	IF (F$CVTIME(F$FILE_ATTRIBUTES(xfile,"CDT")).LES. 		-
	    F$CVTIME("''F$FILE_ATTRIBUTES(xfile,"RDT")'-4-00:00:00"))  	-
		THEN GOTO FAILED_RMAIL_1
$ !
$ ! Note that we are simply leaving the infile in the spool directory.
$ ! This is deliberately done so that we don't have to invent another
$ ! mechanism to keep track of which X file goes which 'infile'.  Yes
$ ! we could always read the X file to locate it's 'infile', but this
$ ! can get sort of hairy, and that code is currently internal to UUXQT
$ ! itself.  We explicitly move it there if it isn't already there.
$	SET NOON
$	junk_priv = f$setprv(saved_priv)
$	RENAME/LOG 'xfile' 'f$parse(xfile,,,"DEVICE")''f$parse(xfile,,,"DIRECTORY")'REMAIL_X
$	GOTO READ_LOOP
$
$ FAILED_RMAIL_1:
$	ON ERROR THEN GOTO FAILED_RMAIL_2
$	SAY "* (FAILED_RMAIL) Error sending ",infile," to ",addressee,", forwarding to local postmaster"
$	subject = "Couldn't send this to "+addressee+", status ''saved_status'"
$	save_ver = f$verify(1)
$	MAIL 'infile' uucp_postmaster /SUBJECT=&subject
$	save_ver = 'f$verify(verify)'
$	GOTO FAILED_RMAIL_COMMON
$
$ FAILED_RMAIL_2:
$	save_ver = 'f$verify(verify)'
$	ON ERROR THEN GOTO FAILED_RMAIL_COMMON
$	SAY "* (FAILED_RMAIL_2) Error sending ",infile," to postmaster thru normal mail"
$	subject = "UUCP mail dlvry err, file <"+infile+">, to <"+addressee+">"
$	save_ver = f$verify(1)
$	MAIL sys$input: uucp_postmaster /SUBJECT=&subject
The file named in the subject line could not be delivered to the indicated
addressee.  Please review UUXQT_DCL.LOG and UUXQT_BATCH.LOG .  The offending
file (and its Xfile) have been moved to the UUCP_DUMP: directory.
$	save_ver = 'f$verify(verify)'
$
$FAILED_RMAIL_COMMON:
$	save_ver = 'f$verify(verify)'
$	SET NOON
$	junk_priv = f$setprv(saved_priv)
$	IF F$SEARCH(infile).NES."" THEN RENAME/LOG 'f$par(infile) UUCP_DUMP:
$	RENAME/LOG 'xfile' UUCP_DUMP:		! this one comes to us with a version number
$	GOTO READ_LOOP
$
$ !----------------------------------------------------------------------
$
$ DO_RNEWS:
$	newsbatch = F$PARSE("UUCP_RCVDNEWS:NEWS_BATCH",,infile,,"SYNTAX_ONLY")
$	batch_log = "NEWS_LOG:RNEWS_"+(f$parse(newsbatch,,,"TYPE")-".")
$	ON WARNING THEN GOTO FAILED_RNEWS_1
$	! Make sure there is only one version of the input file. >EFA
$	IF F$PARSE(F$SEARCH(infile),,,"VERSION") .NES. ";1" THEN PURGE/LOG 'infile'
$	RENAME/LOG 'infile';0 'newsbatch'
$
$	saved_priv = f$setprv("SYSPRV, CMKRNL")
$	save_ver = f$verify(1)
$	SUBMIT/NOPRINT/LOG='batch_log'			-
		/USER='f$logi("NEWS_MGR_UN")'		-
	       	/PARAMETER=('newsbatch',"''Hostname'")	-
		/QUEUE=NEWS_BATCH_QUEUE			-
		/RESTART				-
		UUCP_BIN:NEWS_RNEWS	
$	save_ver = 'f$verify(verify)'
$	junk_priv = f$setprv(saved_priv)
$
$	DELETE 'xfile'		! this one comes to us with a version number
$	GOTO READ_LOOP                                       
$
$ FAILED_RNEWS_1:
$	saved_status = $status		! 'f$verify(verify)'
$	junk_priv = f$setprv(saved_priv)
$	ON ERROR THEN GOTO FAILED_RNEWS_2
$	SAY "* (FAILED_RNEWS_1) Error starting NEWS_RNEWS for ", infile, ", Status=", saved_status
$	subject = "UUCP NEWS dlvry err, file <''infile'>, Status <''saved_status'>"
$	save_ver = f$verify(1)
$	MAIL/SUBJECT=&subject sys$input: uucp_postmaster
The file named in the subject line could not be dispatched to the NEWS system 
for processing.  Please review UUXQT_DCL.LOG and UUXQT_BATCH.LOG .  The 
offending Xfile has been moved to the UUCP_DUMP: d


