/* MLIST.C by Frank J. Wancho (WANCHO@SIMTEL20.ARPA) 02/14/87

MLIST normally takes no arguments.  However, if OEXEC is not defined
and an argument is given, the SUBMIT command will not be issued so
that the program may conveniently debugged.

MLIST was designed as one consolidated solution to two problems with
mailing list processing:

1. The first problem is that mailing lists tend to generate long
queues which interfere with the timely processing of "normal" mail
embedded in the same queue.  MLIST puts mailing list mail in its own
queue to be processed by a slightly modified version of MMAILR.  The
modified version of MMAILR simply contains "REDIST-" substituted for
all occurances of "QUEUED-" in a copy of the MMAILR source renamed to
RMAILR.MAC.

2. The second problem is that normally there is no way to specify that
notices and failures are to be sent to the mailing list maintainer.
MLIST specifies of the RETURN-PATH: to be listname-REQUEST@OHN when it
creates the new queued mail file.

MLIST takes advantage of the Special Network feature of MMAILR,
documented elsewhere, and the format of the message file files created
in the Special Network message file directory.  In particular, the
second line of the message file contains the username portion of the
redirected address, which is expected to be the name of the mailing
list.  MLIST also expects the actual mailing list address to be named
listname-MLIST.  The set of example entries for a hypothetical list
named INFO-TEST in MAIL:MAILING-LISTS.TXT for Special Network host
named MLIST is:

INFO-TEST= INFO-TEST-QUEUE
INFO-TEST-QUEUE= INFO-TEST@MLIST
INFO-TEST-MLIST= @PS:<list-maintainer-directory>listfilename
INFO-TEST-REQUEST= list-maintainer-address

MLIST is written to be compiled with KCC.  Edit the values for
QUEUENAME and OHN (the Official Host Name for you host), and compile
with -DOEXEC if your EXEC has not been modified to accept input from
its RSCAN buffer.  Copy the resulting MLIST.EXE file into the Special
Network directory for this "host".  Create a self-perpetuating batch
job in that directory and start it running under OPERATOR.  Finally,
create a version of MMAILR as RMAILR as described above and run it
under SYSJOB.

*/

#include <stdio.h>
#include <string.h>

/* src:<kccdist.kcc-6.lib.usys>exit.c */
extern void exit(int);

/* src:<kccdist.kcc-6.lib.usys>unlink.c */
extern int unlink(char *);

/*
 * Forward(s).
 */
int domsg(int);
long gtad(void);
int strip(char *);
int system(char *);
int _xfork(char *,char *);


#define LINESIZE    1026		/* max line input size from msg */
#define FNSIZE	    100			/* max file name size */
#define OHN	    "mathom.xkl.com"	/* Official Host Name of local host */
#define	QUEUENAME   "REDIST"		/* part of RMAILR queue filenames */

FILE	*inmsg;				/* input message file descriptor */
FILE	*outmsg;			/* output message file descriptor */

char    line[LINESIZE];			/* input line from message file */
char	infile[FNSIZE];			/* input filename */
char	outfile[FNSIZE];		/* output filename */
char	tmp[FNSIZE];			/* temporary string */
int	debug;				/* runtime debug flag */


main (num, arg)
int	num;
char	*arg[];
{
    char   *d;			       /* pointer to string returned by dir() */
    char   *name[500];		       /* pointer to pointers to names */
    char   *dir();		       /* required declaration */
    char   *malloc();		       /* required declaration */
    int     nfiles;		       /* count of number of files found */
    int	    n;			       /* loop counter */

    debug = 0;
    if (num > 1) {		       /* if any args */
	debug = 1;		       /* set flag */
    }

    /* First rename any left over files from some previous run */

    for (d = dir ("-MESSAGE.*.*", 1); *d; d = dir (NULL, 1)) {
	sprintf (infile, "-MAIL.0%o-%d", gtad(), ++nfiles);
	if (rename (d, infile)) {      /* if rename fails */
	    exit (1);		       /* exit */
	}
    }
    nfiles = 0;			       /* initialize count */

    /* Find and save the names of all message files */

    for (d = dir ("-MAIL.*", 1); *d; d = dir (NULL, 1)) {
	name[nfiles] = malloc (strlen (d) + 1); /* allocate space */
	strcpy (name[nfiles], d);	/* save the name */
	if (nfiles++ > 200) {	       /* found one - bump count */
	    break;
	}
    }
    if (nfiles) {		       /* if any file found */
	/* Rename each file, one at a time, process and delete it */
	for (n = 0; n < nfiles; n++) {
	    sprintf (infile, "-MESSAGE.%o-%d", gtad(), n+1);
	    if (rename (name[n], infile)) { /* if rename failed */
		exit (1);	       /* exit */
	    }
	    if ((inmsg = fopen (infile, "r")) == NULL) { /* open the file */
		exit (1);	       /* exit if failed to open */
	    }
	    domsg (n);		       /* process the file */
	    fclose (inmsg);	       /* close it */
	    unlink (infile);	       /* delete and expunge it */
	}
    }
#ifndef OEXEC			       /* if EXEC modified, compile this */
    if (!debug) {		       /* if debug off */
system ("EXEC SUBMIT MLIST.CTL/OUTPUT:NOLOG/UNI:NO/BAT:SUPER/TIM:60/AFTER:+1:00/RESTART:YES"); /* self-perpetuate */
    }
#endif
    exit (0);			       /* done for now */
}

/* domsg() takes one arg - the current loop counter value for creating
a unique queue filename, creates the new queue file from the message file. */

int
domsg (n)
int	n;
{
    sprintf (outfile, "\026[--%s-MAIL--\026].NEW-%o-MLIST-%d",
	     QUEUENAME, gtad(), n);    /* create the unique queue filename */
    if ((outmsg = fopen (outfile, "w")) == NULL) { /* open it for write */
	exit (1);		       /* exit on failure */
    }
    fgets (line, LINESIZE, inmsg);     /* read the first line from message */
    fgets (line, LINESIZE, inmsg);     /* read the second line */
    strip (line);		       /* remove any useless chars */
    fprintf(outmsg, "\f=RETURN-PATH:%s-REQUEST@%s\n", line, OHN);
    fprintf(outmsg, "\f_%s\n%s-REQUEST\n", OHN, line);
    fprintf(outmsg, "\f%s\n%s-MLIST\n", OHN, line); /* write envelope */
    while (fgets (line, LINESIZE, inmsg) != NULL) { /* copy rest of file */
	fputs (line, outmsg);	       /* to new queue file */
    }
    fclose (outmsg);		       /* close queue file */
    sprintf(tmp, "MAILQ:%s", outfile); /* form target name in MAILQ: */
    rename (outfile, tmp);	       /* rename it and ignore failures */
    return (0);
}

#include <jsys.h>

static char result[FNSIZE];

char *
dir(fname, flg)	/* expands wildcard filename, returning the next  */
char *fname;	/* available filename on each successive call. */
		/* Returns NULL when list exhausted */
int flg;	/* If flag is 1, only the fn.typ is returned. */
{
    int     ablock[5];
    int     njfn;
    char    buf[FNSIZE];
    static int  first = 1;	/* true only on first call */
    static int  jfn;

    if (fname) {		/* if filename is given, use it */
	ablock[1] = GJ_SHT | GJ_OLD | GJ_IFG | T20_BIT (13);
	ablock[2] = (int) (fname - 1);
	if (!(jsys (GTJFN, ablock))) {
	    return NULL;
	}
	jfn = ablock[1];
	njfn = ablock[1];
    } else {
	if (first) {		/* if no name and first call */
	    return NULL;	/* then not much we can do */
	} else {		/* else search for next */
	    ablock[1] = jfn;
	    if (!(jsys (GNJFN, ablock))) {
		first = 1;
		return NULL;
	    }
	    njfn = ablock[1];
	}
    }
    first = 0;			/* no longer first time */

    ablock[1] = (int) (buf - 1);
    ablock[2] = njfn & 0777777;
    if (flg) {
	ablock[3] = T20_BIT (8) | T20_BIT (11) | T20_BIT (35);
    } else {
	ablock[3] = 0;
    }
    if (!(jsys (JFNS, ablock))) {
	first = 1;
	return NULL;
    }
    strcpy (result, buf);	/* save name of file */
    return result;
}

long
gtad()		/* Calls GTAD and returns the value in AC1, the */
		/* current system date. */
{
    int	ac[5];

    jsys (GTAD, ac);
    return (ac[1]);
}

int
strip(s)	/* Returns s stripped of any leading or trailing */
char *s;	/* blanks and trailing CRs */
{
    int i;
    char *p;

    if (strlen (s) == 0) {
	return (1);
    }
    p = s;
    while (*p == ' ')		/* strip leading blanks */
	for (i = 0; *(p+i); i++)
	    *(p+i) = *(p+i+1);
    while (*p) p++;
    --p;
    while ((*p == ' ') || (*p == '\n')) {/* strip trailing blanks an cr */
	*p = 0;
	p--;
    }
}

system(s)	/* Processes the command line, s, composed of a */
char *s;	/* program name to run in an inferior fork with the */
		/* line passed to the program via RSCAN.  If the first */
		/* characters are "EXEC ", these characters are */
		/* stripped off the string and SYSTEM:EXEC.EXE is the */
		/* program loaded in the inferior fork and the */
		/* remainder of the string is passed to EXEC via */
		/* RSCAN, assuming that it has been modifed to read */
		/* its rescan buffer. */
{
	char	*p, t[256], q[256];
	char	*index ();

	if (!strncmp (s, "EXEC ", 5)) {
	    strcpy (t, "SYSTEM:");
	} else {
	    strcpy (t, "SYS:");
	}
	strcat (t, s);
	p = t;
	if (p = index (t, ' '))
		*p = '\0';
	strcat (t, ".EXE");
	strcpy (q, s);
	strcat (q, "\n");

	_xfork (t, q);
}

int `jfn`;
int `frk`;				/* fork handle */
int `pc`;				/* starting pc of process */

int
_xfork (pgmname, cmdline)
char	*pgmname;		/* Program name to run */
char	*cmdline;		/* Command line */
{
#asm
	SEARCH	MONSYM
	EXTERN $RETZ, $RETT, $RETF	/* From CRT */

	movsi	1,(GJ%OLD+GJ%SHT)
	seto 	2,0
	adjbp	2,-1(17)
;[rwf]	%CHRBP	2,-1(17)		; get pointer to program name
	gtjfn%				; get JFN of program file
	 ERJMP	$RETZ			; cannot open exe file
	hrrzm	1,JFN			; save JFN

	hrli	1,(CR%CAP)		; run subfork
	cfork%				; create inferior with same capability
	 ERJMP	RELJFN			; cannot create fork
	movem	1,FRK			; save fork handle
	ffork%				; and freeze the fork
	
	hrlz	1,FRK			; fork handle
	hrr	1,JFN			; JFN of program file
	setzm	2
	get%				; load program image into inferior fork
	 ERJMP	RELJFN

	hrrz	1,FRK
	gevec%				; get entry vector
	 ERJMP	RELJFN			; oops??
	hrrz	2,2
	movem	2,PC

;[Rwf]	%CHRBP	1,-2(17)		; Get RSCAN buffer as ILDB pointer
	rscan%				; Set it
	 ERJMP	RELJFN			; Lost

	hrrz	1,FRK
	move	2,PC
	sfork%				; start fork
	rfork%				; resume frozen fork
	wfork%				; wait for fork to terminate
	kfork%				; then kill fork
	jrst	$RETT

RELJFN:	hrrz	1,JFN
	rljfn%
	jrst	$RETF

#endasm
}