v08i034: Uumail release 4.2, Part02/04

sources-request at mirror.UUCP sources-request at mirror.UUCP
Fri Feb 6 07:02:06 AEST 1987


Submitted by: sob at soma.BCM.TMC.EDU (Stan Barber)
Mod.sources: Volume 8, Issue 34
Archive-name: uumail4/Part02

[  IMPORTANT NOTE:  This version superceeds the recent net.sources posting
   because it also inclues the Patch#1.  An earlier version of Uumail
   was next in the backlog, hence this "rapid" posting.  --r$  ]

#! /bin/sh

# Make a new directory for the uumail sources, cd to it, 
# and run kits 1 thru 4 through sh. 
# When all 4 kits have been run, read README.

echo "This is uumail kit 2 (of 4).  If kit 2 is complete, the line"
echo '"'"End of kit 2 (of 4)"'" will echo at the end.'
echo ""
export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
echo Extracting uumail.c
cat >uumail.c <<'!STUFFY!FUNK!'
/*
 *  U U M A I L
 *  This program when invoked in the form:
 *  uumail host!user will consult the local usemap for
 *  the proper routing.
 * 
 *  If it finds it, it will invoke the proper uux call
 *  to send the mail.
 *  Otherwise it aborts with an error 68 (host unknown)
***************************************************************************
This work in its current form is Copyright 1986 Stan Barber
with the exception of resolve, gethostname and the original getpath which
as far as I know are in the Public Domain. This software may be distributed
freely as long as no profit is made from such distribution and this notice
is reproducted in whole.
***************************************************************************
This software is provided on an "as is" basis with no guarantee of 
usefulness or correctness of operation for any purpose, intended or
otherwise. The author is in no way liable for this software's performance
or any damage it may cause to any data of any kind anywhere.
***************************************************************************
 * $Log:	uumail.c,v $
 * Revision 4.2  87/02/02  15:43:50  sob
 * Added fix for lost line at the beginning of the message problems
 * 
 * Revision 4.1  86/12/15  13:14:44  sob
 * Added attempted fix for null userid in from line on some system V machines.
 * 
 * Revision 4.0  86/11/17  16:02:36  sob
 * Release version 4.0 -- uumail
 * 
 * Revision 3.16  86/10/28  23:26:05  sob
 * installed header bug fix from steve at jplgodo
 * 
 * Revision 3.15  86/10/20  15:05:52  sob
 * Ready for beta test
 * 
 * Revision 3.14  86/10/20  13:24:02  sob
 * Additions to correctly deal with KNOWNHOST
 * 
 * Revision 3.13  86/10/10  18:25:03  sob
 * Now deals with all forms of addresses correctly... close to beta release now
 * 
 * Revision 3.12  86/10/07  13:22:23  sob
 * Made more changes to be compatilble with new Configure script
 * 
 * Revision 3.11  86/10/07  01:07:33  sob
 * Correction for LOG definition
 * 
 * Revision 3.10  86/10/07  01:02:19  sob
 * Altered to work correctly with new Configure script
 * 
 * Revision 3.9  86/10/06  15:03:04  sob
 * Fixed another problem with getting neighbors in getpath.
 * 
 * Revision 3.8  86/10/01  15:52:08  sob
 * Reveresed sense of nghborflag to make it work right.
 * 
 * Revision 3.7  86/09/22  17:52:36  sob
 * This version appears to work when using and not using resolve.
 * Now to alpha test
 * 
 * Revision 3.6  86/09/22  15:58:19  sob
 * This version works correctly with resolve in the compilation. Now
 * to check the other alternatives.
 * Stan
 * 
 * Revision 3.5  86/09/22  12:44:24  sob
 * Added KNOWNHOST definition to allow a place to punt unresolved mail.
 * Hopefully this will help sites with small databases
 * 
 * Revision 3.4  86/09/02  23:32:14  sob
 * Now works with resolve... need to clean up for release.
 * Stan
 * 
 * Revision 3.3  86/08/18  14:13:16  sob
 * checkpoint
 * 
 * Revision 3.2  86/07/11  17:59:19  sob
 * This version now adapted to work with the uumail package.
 * Thanks to Mark and the UUCP project for their work on smail!
 * Stan
 * 
 * Revision 3.1  86/05/27  15:01:27  sob
 * Added modification suggested by tp at ndm20.UUCP to allow user 
 * to specify if uuname will be used to determine uucp neighbors.
 * Stan Barber
 * 
 * Revision 3.0  86/03/14  12:05:00  sob
 * Release of 3/15/86 --- 3rd Release
 * 
 * Revision 2.20  86/03/14  11:57:46  sob
 * 
 * 
 * Revision 2.19  86/03/11  11:29:11  sob
 * Added Copyright Notice
 * 
 * Revision 2.18  86/03/04  18:20:40  sob
 * Fixed some problems with local vs. non-local mail.
 * 
 * Revision 2.17  86/02/26  03:06:47  sob
 * Added error checking for a null name.
 * 
 * Revision 2.16  86/02/23  23:49:40  sob
 * 
 * 
 * Revision 2.15  86/02/23  23:19:09  sob
 * This version will hopefully work with the new pipeoutput option from 
 * aliasing.
 * Stan
 * 
 * Revision 2.14  86/02/18  02:56:38  sob
 * Correct pointer problem with linked list.
 * Stan
 * 
 * Revision 2.13  86/02/17  18:43:37  sob
 * Updated with linked list for addresses. This will allow aliasing which
 * will be added next.
 * Stan
 * 
 * Revision 2.12  86/02/17  17:33:12  sob
 * This update incorporates changes to the command line flags to
 * conform more with the syntax of sendmail.
 * Stan
 * 
 * Revision 2.11  86/02/07  16:06:16  sob
 * Altered the code to always unlink the temporary letter file when
 * DEBUG is NOT defined.
 * Stan
 * 
 * Revision 2.10  85/12/26  16:50:23  sob
 * Added fixes to allow uupath myhostname to work correctly.
 * Stan
 * 
 * Revision 2.9  85/12/10  20:36:01  sob
 * Added new return flag from getpath EX_TEMPFAIL to signal that the
 * path database is currently being updated.
 * 
 * Revision 2.8  85/12/02  16:51:39  sob
 * Added a fix to cope with percents in addresses returned by opath.
 * Thank to steve at umd-cs.UUCP for the bug report.
 * 
 * Revision 2.7  85/11/18  12:36:48  sob
 * Added the -h option to cause uumail NOT to add a From_ line.
 * 
 * Revision 2.6  85/11/14  20:20:06  sob
 * Added #ifdef DEBUG to allow compiliation with out DEBUG installed
 * 
 * Revision 2.5  85/11/14  20:14:11  sob
 * Another little buggie in the log format...sheesh.
 * 
 * Revision 2.4  85/11/13  15:53:18  sob
 * Reformated the log file a little bit.
 * 
 * Revision 2.3  85/11/08  03:03:51  sob
 * This is the release version.
 * 
 * 
 * Revision 2.2  85/09/30  02:51:18  sob
 * This version uses opath when defined during compile time.
 * With a bit of cleaning up, this is a release version.
 * 
 * Revision 2.1  85/09/30  02:46:06  sob
 * *** empty log message ***
 * 
 * Revision 2.0  85/09/09  18:22:56  UUCP
 * *** empty log message ***
 * 
 * Revision 2.0  85/09/09  18:22:56  UUCP
 * Added flags to conform with sendmail. Also updated the flags it could send
 * to uux to conform with 4.3 uux command.
 * Will add name resolution and header checking.
 * Also will allow multiple addresses per line.
 * 
 * Revision 1.7  85/08/03  00:49:14  UUCP
 * Cleaned up with lint.
 * Stan Barber
 * 
 * Revision 1.6  85/07/11  19:30:00  sob
 * changed PATHSIZE to PATHSIZ to conform with uupath
 * 
 * Revision 1.5  85/07/11  18:08:13  sob
 * This one works both as uumail and uupath!
 * Stan
 * 
 * Revision 1.4  85/07/10  18:35:05  sob
 * moved DBM to getpath
 * Stan Barber
 * 
 * Revision 1.3  85/07/09  01:28:14  sob
 * First attempt to integrate uupath
 * Not successful. Changed PATHALIAS define
 * to DBM... will ultimately alter getpath as well
 * added gethostname call to fill in for local host.
 * 
 * Revision 1.2  85/07/08  05:29:16  sob
 * This one works with pathalias database...
 * need to modify to substitue for uupath.
 * Stan
 * 
 * Revision 1.1  85/07/08  03:11:10  sob
 * Initial revision
 * 
 */
#define _DEFINE

#include "uuconf.h"
#include "patchlevel.h"

EXTERN bool uupath;
extern int      errno;
extern struct passwd *getpwuid();
extern FILE	*popen();
extern char     *ctime();
extern char	*getlogin();
extern char	*index();
extern char	*rindex();
extern char	*malloc();
extern char     *getenv();
extern char     *Alias();
extern bool	nghborflag;
EXTERN char	progname[12];
EXTERN char  *paths;
char * bangpath[BUFSIZ];
char templet[64];
struct mailname addrlist;	/* list of addresses */
int local;


main(argc, argv)
	char **argv;
{
	FILE *out, *tmpf;	/* output to uux, temp file */

	char sender[512];	/* accumulated path of sender */
	char user[NAMESIZ];
	char cmd[2000];
	char **av;
	int i,
            error = 0,
            hopcount = 30;
		
        char c,
           grade = 'C',
	   *path,			/* uupath to the system */
           *p, *q, *r,			/* tmp pointer to argv's */
	   *FullName;
	   bool GrabTo,safecf,NoAlias,startuux,noheader,metoo;
	   extern intsig();
	   struct mailname *lp;
	   int form;

	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
		(void) signal(SIGINT, intsig);
	if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
		(void) signal(SIGHUP, intsig);
	(void) signal(SIGTERM, intsig);
	(void) signal(SIGPIPE, SIG_IGN);
	/* initialize Boolean Values */
	startuux = safecf = TRUE;
	metoo=GrabTo=NoAlias=noheader = FALSE;

	for (i = 3; i < 20; i++)
		(void) close(i);
	errno = 0;
	nghborflag = TRUE;	/* use uuname if possible */
	gethostname(Myname,32);
	paths=DATABASE;
#ifdef LOG
	logfile=LOGFILE;
#endif
	FullName=getenv("NAME");
	argv[argc] = NULL;
	av = argv;
	p = rindex(*av, '/');
	if (p++ == NULL)
		p = *av;
	strcpy(progname ,p);
	if(strcmp(p,"uupath") == 0)
		uupath = TRUE;
	while ((p = *++av) != NULL && p[0] == '-')
	{
		switch (p[1])
		{

		  case 'g':   /* set grade */
			grade = p[2];
			break;
	
# ifdef DEBUG
		  case 'd':	/* debug */
			Debug= atoi(&p[2]);
			if (Debug == 0) Debug = 1;
			setbuf(stdout, (char *) NULL);
			(void) printf("Version %s\n", Version);
			break;
# endif DEBUG

		  case 'f':	/* from address */
		  case 'r':	/* obsolete -f flag */
			p += 2;
			if (*p == '\0' && ((p = *++av) == NULL || *p == '-'))
			{
				p = *++av;
				if (p == NULL || *p == '-')
				{
					syserr("No \"from\" person");
					av--;
					break;
				}
			}
			if (from != NULL)
			{
				syserr("More than one \"from\" person");
				break;
			}
			from = p;
			break;

		  case 'F':	/* set full name */
			p += 2;
			if (*p == '\0' && ((p = *++av) == NULL || *p == '-'))
			{
				syserr("Bad -F flag");
				av--;
				break;
			}
			FullName = p;
			break;

		  case 'w':	/* just print the path */
			uupath = TRUE;
			break;
		  case 'h':	/* don't add a From line */
			noheader = TRUE;
			break;
		  case 'N':	/* don't use uuname to get neighbors */
			nghborflag = FALSE;
			break;
		  case 'n':     /* don't alias any addresses */
			NoAlias = TRUE;
			break;
		  case 't':	/* read Header for addresses */
			GrabTo = TRUE;
		        break;
		  case 'o':	/* sendmail-like options flag */
			switch(p[2]){
				case 'm': /* send this message to the sender*/
					metoo=TRUE;
					break;
				case 'c': /* don't connect to expensive
						mailer, or don't start uux*/
					startuux = FALSE;
					break;
				}
			break;
		  case 'b':	/* sendmail-like operation mode flag */
			switch(p[2]){
				case MD_DELIVER: /* deliver the mail */
					uupath = FALSE;
					break;
				case MD_VERIFY: /* verify an address */
					uupath = TRUE;
					break;
				default:
					(void) fprintf(stderr,
					"%s: mode %c not supported\n",
							progname,p[2]);
					exit(EX_USAGE);
				}
			break;
			}
    
		}

    handle = JUSTUUCP;	/* default handling is just uucp */
    if(*av==NULL && GrabTo!= TRUE)
	{
		(void) fprintf(stderr,"Usage: %s [flags] address\n",progname);
		exit(EX_USAGE);
	}


#ifndef NOALIAS
	if (AliasFile == NULL) AliasFile = ALIASFILE;
#endif

/* get login name of the sender... use environment variables if possible */

	if(from==NULL || strlen(from) == 0){
		if (((from = getenv("LOGNAME")) == NULL) || (strlen(from) == 0))
			from = getenv("USER");
		if ((from == NULL) || (strlen(from) == 0))
			from = getlogin();
		if ((from == NULL) || (strlen(from) == 0))
			from = getpwuid(geteuid())->pw_name;
	}

/* if from is still null, set it equal to UUMAIL daemon -- kluge! */

if (from == NULL) from = MAILERDAEMON;

/* If this is not uupath, then there must be a letter */

if (!uupath)
{    
#ifdef DEBUG
	if (Debug) (void) printf("Mail from %s\n",from);
#endif
	/*
	 * Make temporary file for letter
	 * (I wish ACCESS(2) would take care of this better !!)
	 */
	if ((p=getenv("HOME"))== NULL)
		p="/tmp";
	sprintf(&templet[0],"%s/.uumXXXXXX",p);
	mktemp(templet);
	unlink(templet);
	if ((i=open(templet,2)) < 0)
		{
			p="/tmp";
	
			sprintf(&templet[0],"%s/.uumXXXXXX",p);
			mktemp(templet);
			unlink(templet);
		}
	else
		{
			close(i);
			unlink(templet);
		}
#ifdef DEBUG
	if (Debug>2) (void) fprintf(stderr,"Temp file is %s\n",templet);
#endif
	if((tmpf = fopen(templet, "w")) == NULL){
		(void) fprintf(stderr, "%s : can't open %s for writing\n", progname,templet);
		fclose(stdin);
		exit(EX_CANTCREAT);

		}
	while(fgets(lbuf,sizeof lbuf,stdin))
		fputs(lbuf,tmpf);
	(void) fclose(tmpf);
	(void) fclose(stdin);
/* file now saved */
	if((tmpf = fopen(templet, "r")) == NULL){
		(void) fprintf(stderr, "%s : can't open %s for reading\n", progname,templet);
		unlink(templet);
		exit(EX_OSERR);
	}
	
}	
    (void) strcpy(sender, "");

    path = malloc(PATHSIZ);

/* build address list */


    while (*av != NULL && *av != NULL)
		add(*av++,&addrlist);

    if(metoo)   add(from,&addrlist); /* add me to the list too */

    if(!NoAlias) alias();		/* do aliasing if not turned off */
#ifndef NOALIAS				/* process forwarding files */
    for (lp = addrlist.m_next;lp;lp = lp->m_next) forward(lp->m_name);
#endif

    for (lp = addrlist.m_next;lp;lp = lp->m_next) /* mail it out */
    {

    if(strlen(lp->m_name) == 0) continue;
 
    local = 0;
 
    q = p = lp->m_name;
    
    
/* this is uupath command */    
    if (uupath) 
	{
		if ((error = getpath (p, path,paths)) != EX_OK)
			patherror(error,p);
		if (strcmp(path,"%s") == 0) local = 1;
	}
#ifdef RESOLVE
    else 
    {
	/* check for pipe to another program output here */
		if (lp->m_pipe == TRUE){
				strcat(cmd,lp->m_name);
				goto pipeout;
	}
 r = malloc(PATHSIZ);
 strcpy(r,p);
 if (index(p,'@') != NULL) handle = ALL;
/* try one */
    form = resolve(p,path,user);
    if ( (form == LOCAL && path[0] == '\0') 
		|| form == ERROR || form == ROUTE || form == DOMAIN){
		if (user[0] != '\0') strcpy(p,user);
		path[0] = user[0] = '\0';
/* try two */
	        if (index(p,'@') != NULL) handle = ALL;
		form = resolve(p,path,user);
    }
/* we could punt at this point, but let's forward it to a known
   host that might be able to resolve it */

#ifdef KNOWNHOST /* ugly... alternate suggestions welcome */
    if ( (exitstat || form == ERROR)
	 && (index(r,'@') != NULL || index(r,'!') != NULL) ){
	    strcpy(p,KNOWNHOST);
	    strcat(p,"!");
	    strcat(p,r);
	    user[0] = '\0';
	    form = resolve(p,path,user);
	}
#endif

#ifdef DEBUG
    if ((Debug > 1) && (!exitstat)) 
		(void) fprintf(stderr,"resolve returns %s!%s\n",path,user);
#endif

    if (exitstat || form == ERROR )
			 /* no match in pathalias database */
	{
		deadletter(tmpf,local,exitstat,p);
		unlink(templet);
		exit(exitstat);
	}
   

   if (form == LOCAL)
	{
		strcpy(path,Myname);
		local = 1;
	}
    } /* end of else uupath */
#else
	else
	{
	       p = index(q,'!');
	       if (p == NULL) local++;
	       else *p = '\0';
	       if(!local){
			if ((error = getpath (q,path,paths)) != EX_OK)
				patherror(error,q);
			if (*path != '\0' && index(path,'!')) 
					*(rindex(path,'!')+1) = '\0';
	 	        p++;
		        strcat(path,p);
		        p = index(path,'!');
		        if (p != NULL) {
				*p = '\0';
			        p++;
				strcpy(user,p);
		 	}
			else
			{
				strcpy(user,path);
				local++;
			}
		}
	}
#endif

#ifdef DEBUG
       if(Debug>3)
		(void) fprintf(stderr,
			"p = %s path = %s user = %s\n",p, path,user);
#endif

	if (uupath)
		{
			if (*path != '\0') *(rindex(path,'!')+1) = '\0';
			(void) printf("Path to %s:  %susername\n",
							lp->m_name,path);
			continue;
		}
	else
		{
			if (local)
				(void) sprintf(cmd, LOCALMAIL, user);
			else {
				(void) sprintf(cmd,"%s - ",REALUUX);
			if (!startuux)
				strcat(cmd,"-r");
#ifndef NORETURN
			if (from)
				{
					strcat(cmd," -a");
					strcat(cmd,from);
				}
#endif
#ifndef NOGRADE
			if (grade)
				{
					char work[10];
					(void) sprintf(work," -g%c",grade);
					strcat(cmd,work);
				}
#endif		
			if (index(user, '!'))
				{
					char work[100];
					(void)sprintf(work,
					 " %s!rmail \\(%s\\)",path,user);
					strcat(cmd,work);
				}
			else
				{
					char work[100];
					(void) sprintf(work, " %s!rmail %s",
					path,user);
					strcat(cmd,work);
				}
			}
pipeout:
#ifdef DEBUG
	if (Debug) (void) fprintf(stderr,"Command is %s\n",cmd);
#endif
		rewind(tmpf);
#ifdef DEBUG
		if (Debug)
			out = fopen("UUMAIL.TEST","w");
		else
#endif
			out = popen(cmd, "w");
/*		fputs(lbuf, out); */
/* reprocess header ? */
		if (!noheader) Putfrom(tmpf,out);
		while (fgets(lbuf, sizeof lbuf, tmpf))
			fputs(lbuf, out);

/* may not be needed */
		if (local!=0)
			(void) fprintf(out,"\n.\n");

#ifdef DEBUG
		if (Debug)
			i = fclose(out);
		else
#endif
			i = pclose(out);
		if ((i & 0377) != 0)
			{
				(void) fprintf(stderr, "pclose: status 0%o\n", i);
				deadletter(tmpf,local,EX_OSERR);
#ifdef DEBUG
				if (Debug <3)
#endif
						 unlink(templet);
				exit(EX_OSERR);
			}
#ifdef LOG
		maillog(cmd);
#endif
	   }
    }
#ifdef DEBUG
    if (Debug <3)
#endif
                unlink(templet);
exit(EX_OK);
}

/* print an error message on stderr */

syserr(string)
char * string;
{
	(void) fprintf(stderr,"%s\n",string);
}

/* make a unix type From line and send it out the stream */
/* based on smail code (rline subroutine )  to be compatible with RFC 976 */

Putfrom(into,outto)
FILE *into, *outto;
{
	char	*asctime();
	struct	tm *bp, *localtime();
	char	*tp, *zp,*c;
	int	parts,fromflag=0;
	char 	*partv[16];
	char buf[BUFSIZ], addr[PATHSIZ], domain[PATHSIZ], user[NAMESIZ];
	int form;
	extern build();
	long iop, offset;
	(void) strcpy( bangpath,"");  /* zero bang path */
	/* code from smail follows  (Thanks Mark!) */
	for( ;; )
	{
		offset=ftell(into); /* get current position in file */
		if ( fgets( buf, sizeof(buf), into )==NULL )
			break;
		if ( strncmp( "From ", buf, 5 ) 
		    && strncmp( ">From ", buf, 6 ) )
			break;
/*
**  Crack the line apart using ssplit.
*/
		if( c = index( buf, '\n' ) );
			*c = '\0';

 		parts = ssplit( buf, ' ', partv );
/*
**  Tack host! onto the bangpath argument if "remote from host" is present.
*/

		if ( parts > 3 
		    && !strncmp( "remote from ", partv[parts-3], 12 ) )
		{
			(void) strcat( bangpath, partv[parts-1] );
			(void) strcat( bangpath, "!" );
		} 
/*
**  Stuff user name into addr, overwriting the user name from previous 
**  From_ lines, since only the last one counts.  Then rewrite user at host 
**  into host!user, since @'s don't belong in the From_ argument.
*/
		(void) strncpy( addr, partv[1], partv[2]-partv[1]-1 ); 
		addr[partv[2]-partv[1]-1] = '\0';	/* ugh */

		(void) parse( addr, domain, user );
		if(*domain == '\0') {
			form= LOCAL;
		} else {
			form = UUCP;
		}

		build( domain, user, form, addr );

	}
/*
**  Now tack the user name onto the from argument.
*/
	(void) strcat( bangpath, addr );
/*
**  If we still have no from argument, we have junk headers.
**  We use the from name determined at startup time.
*/
	if (bangpath[0] == '\0') strcpy(bangpath,from);

/*
 * Format time
 */
	time(&iop);
	bp = localtime(&iop);
	tp = asctime(bp);
/*	zp = tzname[bp->tm_isdst];*/

/*	sprintf(buf, "%s%s %.16s %.3s %.5s", from, tp, zp, tp+20);*/
 	(void) sprintf(buf, "From %s %.16s %.4s", bangpath, tp, tp+20); 

	if (local == 0){
			strcat(buf," remote from ");
			strcat(buf,Myname);
		   }

	strcat(buf,"\n");
	/* if there is no output file (no headers), exit */
	if (outto == NULL) return;
	(void) write(outto->_file,buf,strlen(buf));
	/* now reset the input file to the beginning of the header
	 * following the "From " lines
	 */
	(void) fseek(into,offset,0);
	(void) fflush(outto);

}

/* end of code derived from smail */


/* go here on a signal we want to catch */
intsig()
{
	unlink(templet);
	exit(EX_OK);
}

/* put command strings in the logfile */

#ifdef LOG

maillog(command)
char * command;
{
	FILE *f;
	char atime[24];
	long clock;
	time (&clock);
	strncpy(atime,ctime(&clock),24);

	if ((f=fopen(logfile,"a")) != NULL)
		{
			(void) fprintf(f,"%s: %s - %s\n",progname,atime,command);
			fclose(f);
		}
}

#endif

/* print a path error and exit */
patherror(error,name)
int error;
char * name;
{
	switch(error){
		case EX_NOHOST:
		(void) fprintf(stderr,"System %s not found in network map.\n",
						 name);
			break;
		case EX_NOINPUT:
			 (void) fprintf(stderr,
				"Database %s could not be opened.\n",paths);
			break;
		case EX_TEMPFAIL:
			 (void) fprintf(stderr,
		"Database %s is being updated.\nTry again later.\n",paths);
			break;
		}
	exit(EX_NOHOST);
}
!STUFFY!FUNK!
echo Extracting getpath.c
cat >getpath.c <<'!STUFFY!FUNK!'
/*
 * Name: getpath -- return the full usenet path of the given name
 *
 * Paramaters: sysname (input) -- The system name to be expanded
 *	       pathname (output)  The usenet path of the given system name
 *	       pathfile (input) the file to search for the system name
 *
 * Returns: EX_OK     -- path found
 *	    EX_NOHOST -- path not found
 *	    EX_NOINPUT-- unable to open usemap
 *          EX_TEMPFAIL -- database being rebuilt
 *
 * Original Version Author: J. Donnelly   3/82
 *
 */

/*    IF YOU ARE USING A DBM DATABASE, READ THIS!
 *    If the special sentinel value of @@@ is not present in the
 *    database, then it is assumed that the database is being
 *    rebuilt and the requesting process is blocked for TIMEOUT
 *    (default = 180) seconds.  If, after 5 such blocks, the
 *    sentinel is not present, the error code EX_TEMPFAIL is returned.
 *    The same is true if the dbm files cannot be initialized.
 */

/***************************************************************************
This work in its current form is Copyright 1986 Stan Barber
with the exception of opath, gethostname and the original getpath which
as far as I know are in the Public Domain. This software may be distributed
freely as long as no profit is made from such distribution and this notice
is reproducted in whole.
***************************************************************************
This software is provided on an "as is" basis with no guarantee of 
usefulness or correctness of operation for any purpose, intended or
otherwise. The author is in no way liable for this software's performance
or any damage it may cause to any data of any kind anywhere.
***************************************************************************/
/* 22-jun-83 Sheppard
 * modified to rewind path file (if open), rather than open again
 *
 * $Log:	getpath.c,v $
 * Revision 4.0  86/11/17  16:02:15  sob
 * Release version 4.0 -- uumail
 * 
 * Revision 3.11  86/11/06  01:59:48  sob
 * Altered DBM to UUDBM to avoid possible conflicts under 4.3 BSD
 * Thanks to page at ulowell for the report
 * 
 * Revision 3.10  86/10/20  15:05:14  sob
 * Ready for beta test
 * 
 * Revision 3.9  86/10/20  13:23:36  sob
 * Revisions to work more correctly in SORTED and nonSORTED databases
 * 
 * Revision 3.7  86/10/10  18:24:16  sob
 * Moved dbm.h include here from uuconf.h
 * 
 * Revision 3.6  86/10/06  15:03:23  sob
 * Fixed another problem with getting neighbors in getpath.
 * 
 * Revision 3.5  86/10/01  15:49:15  sob
 * Revisions to deal with problems arrising from the neighbors array.
 * Still not completely solved.
 * 
 * Revision 3.4  86/07/11  17:58:07  sob
 * Fixed the alternate case conversion to work right.
 * Stan
 * 
 * Revision 3.3  86/07/10  15:29:21  sob
 * Added modifications that allow getpath to work with hosts that have
 * names that are all uppercase or all lowercase.
 * Stan
 * 
 * Revision 3.2  86/07/06  17:39:57  sob
 * Added changes provided to dynamically allocate enough space for
 * neighbors array. Thanks to rct for the help.
 * Stan
 * 
 * Revision 3.0  86/03/14  12:04:46  sob
 * Release of 3/15/86 --- 3rd Release
 * 
 * Revision 1.19  86/03/14  11:57:23  sob
 * updated copyright
 * 
 * Revision 1.18  86/03/11  11:28:58  sob
 * Added Copyright Notice
 * 
 * Revision 1.17  86/03/03  17:16:59  sob
 * Added fixes provided by desint!geoff.
 * Stan
 * 
 * Revision 1.16  86/02/24  12:45:36  sob
 * Bug fix in scanning the list from uuname.
 * Stan
 * 
 * Revision 1.15  86/02/23  23:01:53  sob
 * This version will use data from the uuname command as well as
 * data from the database
 * 
 * Revision 1.14  85/12/13  15:23:21  sob
 * Added patches from umd-cs!steve
 * 
 * Revision 1.13  85/12/10  20:36:58  sob
 * Added modifications suggested in gatech's version of uumail.
 * Now, the DBM version of the database needs to have a SENTINAL in it
 * to indicate that the DATABASE is not being updated. Also added similiar
 * indicators to the non-DBM version to compare modification times and act
 * accordingly. 
 * 
 * Revision 1.12  85/12/02  15:48:39  sob
 * Combined speed hacks and old way of reading database and
 * added compile flag SORTED. If database is SORTED and not DBM, use
 * -DSORTED in CFLAGS to make it fast. If database is not sorted
 * DO NOT use this flag.
 * 
 * Revision 1.11  85/11/24  15:03:41  sob
 * Added changes suggested by regina!mark
 * 
 * Revision 1.10  85/11/24  04:21:45  sob
 * Added efficiency hacks supplied by meccts!asby (Shane P. McCarron)
 * 
 * Revision 1.9  85/11/14  20:21:49  sob
 * Added #ifdef DEBUG to allow compilation without DEBUG
 * 
 * Revision 1.8  85/11/08  03:04:49  sob
 * release version
 * 
 * Revision 1.7  85/09/30  02:47:40  sob
 * Altered to use path filename from global variable.
 * 
 * Revision 1.6  85/08/03  00:48:57  UUCP
 * Cleaned up with lint.
 * Stan Barber
 * 
 * Revision 1.5  85/07/19  17:45:13  UUCP
 * Added \t as a valid seperation character for the database
 * in the non DBM case. This is what pathalias uses.
 * 
 * Revision 1.4  85/07/19  16:44:07  UUCP
 * revised to return proper things in accordance with sysexits
 * Stan
 * 
 * Revision 1.3  85/07/11  19:30:31  sob
 * added "uuconf.h" include file and deleted duplicated information
 * 
 * Revision 1.2  85/07/10  18:30:59  sob
 * updated to add DBM capabilities
 * Stan Barber, Baylor College of Medicine
 * 
 * Revision 1.1  85/07/10  18:03:28  sob
 * Initial revision
 * 
 */

#include	"uuconf.h"
#ifdef UUDBM
#include <dbm.h>
#else
#include <sys/types.h>
#include <sys/stat.h>
#endif

static char rcsid[] = "$Header: getpath.c,v 4.0 86/11/17 16:02:15 sob Exp $";
extern char * index();

extern FILE * fopen (), *popen();
FILE * in;
bool nghborflag,gotneighbors;
char **neighbors, *n_array;	/* rct */

int getpath (sysname, pathname, pathfile)
char   *sysname, *pathname,*pathfile;
{
    int indx,x;
    char ACsysname[NAMESIZ];			/* alternate case sysname */
#ifdef UUDBM
    datum lhs,rhs;
#else
	struct stat st;
        time_t modtime;
	char name[NAMESIZ];
#ifdef SORTED
	int scomp();

	long lo,hi;
	long cur;
	long last;
	static char buf[256];
#else
    char    * p, * q, t;
#endif
#endif


/* build sysname in the alternate case to conform to methods in SMAIL */
	if (*(sysname) == '.' || isupper(*sysname)) /* a kludge */
		{
			for (x=0;x<strlen(sysname);x++)
				ACsysname[x] = tolower(*(sysname+x));
		}
	else
		{
			for (x=0;x<strlen(sysname);x++)
				ACsysname[x] = toupper(*(sysname+x));
		}

	if (x < NAMESIZ) ACsysname[x] = '\0';
/* end case switch */
#ifdef DEBUG
if (Debug>2) (void) fprintf
	(stderr,"getpath: Sysname = %s, Alternate = %s, Pathfile = %s\n",
						sysname,ACsysname,paths);
#endif
	if(nghborflag == TRUE)
	{
	if (gotneighbors != TRUE) getneighbors();
	indx = 0;
/* is it a neighbor? */
	while(neighbors[indx] != NULL && *(neighbors[indx]) != '\0'){
		if(!strcmp(sysname, neighbors[indx]) 
			|| !strcmp(ACsysname,neighbors[indx])){
				strcpy(pathname, neighbors[indx]);
				strcat(pathname, "!%s");
				return(EX_OK);
			}
			indx++;
		}
	}
/* not a neighbor, let's look in the database */
#ifdef UUDBM
    for (indx = 0; indx < 5; indx++)
    {
	if ((x = dbminit (pathfile)) >= 0)
	    break;
	
#ifdef DEBUG
	if (Debug>2)
	    (void) fprintf (stderr, "Database unavailable.  Sleeping.\n");
#endif
	sleep (TIMEOUT);
    }

    if (x < 0)
	return(EX_OSFILE);

    lhs.dptr = SENTINEL;
    lhs.dsize = strlen (SENTINEL) + 1;
    for (indx = 0; indx < 5; indx++)
    {
	rhs = fetch (lhs);
	if (rhs.dsize > 0)
	    break;
	
#ifdef DEBUG
	if (Debug>2)
	    (void) fprintf (stderr, "Database incomplete.  Sleeping.\n");
#endif
	sleep (TIMEOUT);
    }
    if (rhs.dsize <= 0)
	return(EX_TEMPFAIL);

    	lhs.dptr = sysname;
	lhs.dsize = strlen(sysname)+1;
	rhs = fetch(lhs);
	if (rhs.dptr == NULL){		/* try other case */
		lhs.dptr=ACsysname;
		rhs = fetch(lhs);
		if (rhs.dptr == NULL) return(EX_NOHOST); /* no name found */
	}
	strcpy(pathname,rhs.dptr);
        return(EX_OK);			/* system name found */

#else
if (in == NULL) 
    {
	for (indx = 0; indx < 5; indx++)
	    {
		if ((in = fopen(pathfile, "r")) != NULL)
		    break;
	
#ifdef DEBUG
		if (Debug>2)
		    (void) fprintf (stderr, "Database unavailable.  Sleeping.\n");
#endif
		sleep (TIMEOUT);
	    }
    if (in == NULL)
	return(EX_OSFILE);
    }
    else
	rewind(in);
    indx = 0;
    strcpy(name,sysname);
restart:
	indx++;
	if (indx > 5) return(EX_TEMPFAIL);
	stat(pathfile, &st);
	modtime=st.st_mtime; /* original last modification time */

#ifdef SORTED
	lo = 0;
	hi = st.st_size;
	last = 0;
	cur = hi >> 1;

	while (cur > lo && cur < hi)
	{
		stat(pathfile,&st);
		if (st.st_mtime > modtime) goto restart;
		(void)fseek(in, cur, 0);
		if (fgets(buf, sizeof(buf), in)== NULL) return(EX_TEMPFAIL);
		cur = ftell(in);
		if (fgets(buf, sizeof(buf), in) == NULL) return(EX_TEMPFAIL);

#ifdef	DEBUG
	if (Debug > 4)
		(void) printf("Found site %s\n", buf);
#endif
		if (scomp(name, buf) < 0) hi = cur;
		else
		if (scomp(name, buf) > 0) lo = cur;
		else
		{
			buf[strlen(buf)-1] = '\0';
			strcpy(pathname, (char *)index(buf, '\t') + 1);
			return(EX_OK);
		}
		cur = lo + ((hi - lo)>>1);
		if (last == cur) 
		{
			(void)fseek(in, lo, 0);
			do
			{
				if (fgets(buf, sizeof(buf), in) == NULL)
						return(EX_TEMPFAIL);
				lo = ftell(in);
				if (scomp(name, buf) == 0 )
				{
					buf[strlen(buf)-1] = '\0';
					strcpy(pathname, (char *)index(buf, '\t') + 1);
					return(EX_OK);
				}
			} while (lo <= hi);
			break;
		} /* end if */
		last = cur;
	} /* end while */
	if (!strcmp(name,ACsysname)) return(EX_NOHOST);
	else {
		strcpy(name,ACsysname);
		goto restart;
	}
#else
    p = (char *) malloc(NAMESIZ);
    if (p == NULL) return(EX_OSERR);	 /* can't get space */
    q = p;
    for (;;)
    {
	p = q;
	while ((t = getc(in)) != EOF && (*p++ = t) != ' ' && t != '\t');
					 /* read the system name */
        stat(pathfile,&st);
        if (st.st_mtime > modtime) goto restart;		
					/* database update in progress */
	if( t == EOF ) return(EX_NOHOST);
	*--p = '\0';			/* set end of string */
	p = q;
#ifdef DEBUG
	if (Debug>4) (void) printf("Found %s\n",p);
#endif
	if (!strcmp (p,name) || !strcmp(p,ACsysname))break;
	while (((t = getc (in)) !=EOF && t != '\n'));	/* skip this path */
    }
    p = pathname;			/* save start loc of pathname */
    while ((*pathname++ = getc (in)) != '\n' && *(pathname-1) != EOF);
    *--pathname = '\0';
    pathname = p;
    return(EX_OK);			/* system name found */

#endif
#endif
}

#ifdef	SORTED
#define MAPTAB(c) ((c=='\t')?'\0':c)

int scomp(a,b)
char *a,*b;
{
int r;
	while (!(r=(MAPTAB(*a)-MAPTAB(*b))) && *a && *b && *a!='\t' && *b!='\t')
	{
	       a++; b++;
	}
	return(r);
}
#endif

getneighbors()
{
	FILE *ppntr;
	char * ptr;
	int x = 0;
	char n_neigh[16], *calloc();	/* rct */
	int nelem = 0;			/* rct */

	gotneighbors = TRUE;

	/*
	*  Let's get the number of neighbors we have.
	*
	*  Beginning of added code.	--rct
	*/

	if((ppntr = popen("uuname | wc -l", "r")) != NULL){
#ifdef DEBUG
		if(Debug > 2)
			(void)fprintf(stderr, "Starting uuname | wc -l\n");
#endif
	}
	else{
		(void)fprintf(stderr, "Error: popen\(\"uuname | wc -l\"\)\n");
		exit(1);
	}
	if((fgets(n_neigh, sizeof(n_neigh), ppntr)) != (char *)0){
		if((ptr = index(n_neigh, '\n')) != (char *)0)
			*ptr = '\0';
	}
	else{
		(void)fprintf(stderr, "Error: fgets\(n_neigh\)\n");
		exit(2);
	}
#ifdef DEBUG
	if (Debug > 2)
		(void)fprintf(stderr, "n_neigh = %s\n", n_neigh);
#endif
	(void)pclose(ppntr);

	/*
	*  Allocate storage for neighbors based on n_neigh.
	*  Assumption being made here is that no system has a name
	*  longer than 14 characters.  If this assumption ever turns
	*  out to be wrong, lots of other code will break before this
	*  does!	--rct
	*/

	nelem = atoi(n_neigh) + 2;

	if(((neighbors = (char **)calloc((unsigned)nelem,
		sizeof(char **))) == (char **)0) ||
		((n_array = calloc((unsigned)nelem, 15)) == (char *)0)){
		(void)fprintf(stderr, "Error: getneighbors\(\): calloc\(\)\n");
		exit(3);
	}

	/*
	*  Set up pointers.
	*/

	for(x = 0; x < nelem; x++)
		neighbors[x] = &n_array[x * 15];

	/*
	*  Now, let's read them in!
	*
	*  End of added code.	--rct
	*/

	if ((ppntr = popen("uuname", "r")) != NULL) {
#ifdef DEBUG
		if (Debug>2)
			(void)fprintf(stderr, "Starting uuname\n");
#endif
		x = 0;
		while((fgets(neighbors[x], 15, ppntr)) != NULL){
			if ((ptr = index(neighbors[x], '\n')) != NULL)
				*ptr = '\0';
#ifdef DEBUG
			if (Debug>4)
				(void) fprintf(stderr, "Neighbor # %d: %s\n",
					x + 1, neighbors[x]);
#endif
			x++;
		}	
		(void) pclose(ppntr);
	}
	strcpy(neighbors[x], Myname);
}



!STUFFY!FUNK!
echo Extracting resolve.c
cat >resolve.c <<'!STUFFY!FUNK!'
/*
**
**  Resolve.c
**
**  Routes then resolves addresses into UUCP or LOCAL.
**
*/
#ifndef lint
static char 	*sccsid="@(#)$Header: resolve.c,v 4.0 86/11/17 16:02:28 sob Exp $";
#endif

#include	<ctype.h>
#include	<stdio.h>
#include	"uuconf.h"



/*
**
**  rsvp(): how to resolve addresses.
**
**  After parsing an address into <form>, the resolved form will be
**  rsvp( form ).  If == ROUTE, we route the parsed address and parse again.
**
*/

# define rsvp(a) table[(int)a-1][handle-1]

int table[5][3] = {
/*	all		uucponly	none */
{ 	ERROR, 		ERROR, 		ERROR }, 	/* error */
{ 	LOCAL, 		LOCAL,	 	LOCAL }, 	/* local */
{ 	ROUTE, 		LOCAL, 		LOCAL }, 	/* domain */
{ 	UUCP, 		UUCP, 		LOCAL }, 	/* uucp */
{	ERROR, 		ERROR, 		ERROR }};	/* route */


/*
**  NOTE: in this module <domainv> replaces <hostv>. <domainv> contains 
**  the domain part of each address, though by the time it leaves here it 
**  can only be a host name.
*/


/*
**
**  resolve(): resolve addresses to <host, user, form>.
**
**  This is a gnarly piece of code, but it does it all.  Each section 
**  is documented.
**
*/

resolve( address, domain, user )
char *address;				/* the input address 	*/
char *domain;				/* the returned domain 	*/
char *user;				/* the returned user 	*/
{
	int form;		/* the returned form	*/ 
	int parts;			/* to ssplit addresses	*/
	char *partv[PATHSIZ];		/* "  "      "		*/
 	char temp[PATHSIZ];		/* "  "      "		*/
	int i;
		

/*
**  If we set REROUTE and are prepared to deliver UUCP mail, we split the 
**  address apart at !'s and try to resolve successively larger righthand 
**  substrings until we succeed.  Regularly, we just resolve the whole thing 
**  once.
*/
	if ( rsvp( UUCP ) == UUCP )
		parts = ssplit( address, '!', partv );
	else
		parts = 1, partv[0] = address;
/*
**  This for( i ) loop selects successively larger righthand substrings 
**  for BULLYing, see above. 
*/
	for( i = parts - 1; i >= 0; i-- )
	{
/*
**  Parse the address.  If we are BULLYing and our substring parses to 
**  the LOCAL address, we skip to the next larger.
*/
		(void) strcpy( temp, partv[i] );
		form = parse( temp, domain, user );
#ifdef DEBUG
	if (Debug>2) 
	printf("resolve: parse address '%s' = %s @ %s (%d)\n",temp,user,domain,form);
#endif
		if ( i && form == LOCAL )
			continue;
/*
**  Routing is next step, so we break out if we don't have a UUCP form (if 
**  we are set to route ALWAYS or REROUTE) or a ROUTE form.
*/
		if ( rsvp( form ) != ROUTE && 
		    ( rsvp( form ) != UUCP ) )
				break;
/*
**  Apply router.  If BULLYing and routing failed, try next larger substring.
*/
		if ( route( form, domain, user, temp ) )
			continue;
/*
**  After routing, reparse and resolve.
*/
		form = parse( temp, domain, user );
#ifdef DEBUG
if (Debug>2)printf("resolve: parse route '%s' = %s @ %s (%d)\n",temp,user,domain,form);
#endif
		break;
	}
/*
**  For LOCAL mail in non-local format, we rewrite the full address into 
**  <user> and leave <domain> blank.
*/
	if ( rsvp( form ) == LOCAL && form != LOCAL )
	{
		build( domain, user, form, temp );
		(void) strcpy( user, temp );
		(void) strcpy( domain, "" );
		form = LOCAL;
	}
/*
**  If we were supposed to route and address but failed (form == ERROR), 
**  or after routing once we are left with an address that still needs to
**  be routed (rsvp( form ) == ROUTE), complain.  It is possible that we 
**  may want to resolve this address more than once (if the routing tables
**  return a domain-style address), but most likely this address partially 
**  resolved to this host.
*/
	if ( form == ERROR || rsvp( form ) == ROUTE )
	{
		exitstat = EX_NOHOST;
#ifdef DEBUG
 	if (Debug) printf( "%s...couldn't resolve %s.\n", address, domain );
#endif
		form = ERROR;
	}
	return ( form );
}


/*
**
** parse(): parse <address> into <domain, user, form>.
**
** 	input		form
**	-----		----
**	user		LOCAL
**	domain!user	DOMAIN
**	user at domain	DOMAIN
**	@domain,address	LOCAL	(just for sendmail)
**	host!address	UUCP
**
*/

parse( address, domain, user )
char *address;		/* input address 	*/
char *domain;		/* output domain 	*/
char *user;		/* output user 		*/
{
	int parts;
	char *partv[PATHSIZ];				/* to crack address */

/*
**  If this is route address form @hosta, at hostb:user at hostd, break for
**  LOCAL since only sendmail would want to eat it.
*/
	if ( *address == '@' )
		goto local;
/*
**  Try splitting at !. If it works, see if the piece before the ! has
**  a . in it (domain!user, form DOMAIN) or not (host!user, form UUCP).
*/
	if ( ssplit( address, '!', partv ) > 1 )
	{
		(void) strcpy( user, partv[1] );
		(void) strncpy( domain, partv[0], partv[1]-partv[0]-1 );
		domain[partv[1]-partv[0]-1] = '\0';
		if( ( parts = ssplit( domain, '.', partv ) ) < 2 )
			return( UUCP );
		if( partv[parts-1][0] == '\0' )	
			partv[parts-1][-1] = '\0'; /* strip trailing . */
		return ( DOMAIN );
	}
/*
**  Try splitting at @.  If it work, this is user at domain, form DOMAIN.
**  Prefer the righthand @ in a at b@c.
*/
	if ( ( parts = ssplit( address, '@', partv ) ) >= 2 )
	{
		(void) strcpy( domain, partv[parts-1] );
		(void) strncpy( user, partv[0], partv[parts-1]-partv[0]-1 );
		user[partv[parts-1]-partv[0]-1] = '\0';
		return ( DOMAIN );
	} 
/* 
**  Done trying.  This must be just a user name, form LOCAL.
*/
local:
	(void) strcpy( user, address );
	(void) strcpy( domain, "" );
	return( LOCAL );				/* user */
}


/*
**
**  route(): route domain, plug in user.
**
**  Less complicated than it looks.  Each section is documented.
**
*/

route( form, domain, user, result )
int form;			/* domain is UUCP host? */
char *domain;			/* domain or host name 	*/
char *user;			/* user name 		*/
char *result;			/* output route 	*/
{
	int	domains, step;			/* to split domain	*/
	char	*domainv[MAXDOMS];		/* "  "     "		*/
	char	temp[PATHSIZ], path[PATHSIZ];

/*
**  Fully qualify the domain, and then strip the last (top level domain) 
**  component off, so that we look it up separately.
*/
	(void) strcpy( temp, ".");
	(void) strcat( temp, domain );

	domains = ssplit( temp+1, '.', domainv );
	/* If the domain ends in .UUCP, trim that off. */
	if ( domains && isuucp(domainv[domains-1]))
		domainv[domains-1][-1] = '\0';
/*
**  Try to get the path for successive components of the domain.  
**  Example for osgd.cb.att.uucp:
**	osgd.cb.att
**	cb.att
**	att
**	uucp ( remember stripping top level? )
**  Returns with error if we find no path.
*/
	step = 0;
	while ( step<domains && getpath( domainv[step]-1, path,paths )
							 /* w/dot */
			     && getpath( domainv[step]  , path, paths) )
							/* no dot */
		step++;
	if ( step == domains )
	{
#ifdef DEBUG
	if(Debug>2) printf( "resolve: getpath '%s' failed\n", domain );
#endif
		exitstat = EX_NOHOST;
		return( exitstat );
	}
#ifdef DEBUG
	if(Debug>2)printf("resolve: getpath '%s' (%s) = %s\n",domain,domainv[step],path);
#endif
/*
**  If we matched on the entire domain name, this address is fully resolved, 
**  and we plug <user> into it.  If we matched on only part of the domain 
**  name, we plug <domain>!<user> in.  
*/
	build( domain, user, step ? UUCP:LOCAL, temp+1 );
	(void) sprintf( result, path, temp+1 );
	exitstat=EX_OK;
	return( exitstat );
}

/*
 * Return 1 iff the string is "UUCP" (ignore case).
 */
isuucp(str)
char *str;
{
	if (islower(*str) != 'u') return 0;
	++str;
	if (islower(*str) != 'u') return 0;
	++str;
	if (islower(*str) != 'c') return 0;
	++str;
	if (islower(*str) != 'p') return 0;
	++str;
	if (*str != '\0') return 0;
	return 1;
}

/*
**
** qualifydomain(): turn domain into full domain name.
**
** Best explained by examples, if hostdomain = a.b.c.UUCP
**	host.domain.UUCP -> host.domain.UUCP
**	host.b -> host.b.c.UUCP
**	host.x -> host.x.UUCP
**
*/

/* qualifydomain():
 * Taken out 3/21/86 by MRH - if hostdomain is, say. a.b.c.COM,
 * and domain is x.UUCP, it turns it into x.UUCP.COM and then
 * barfs on it.  I don't see a way to handle PQN's this easily.
 */

build( domain, user, form, result )
char *domain;
char *user;
int form;
char *result;
{
	switch( form )
	{
	case LOCAL:
		(void) sprintf( result, "%s", user ); 
		break;
	case UUCP:
		(void) sprintf( result, "%s!%s", domain, user );
		break;
	case DOMAIN:
		(void) sprintf( result, "%s@%s", user, domain );
		break;
	}
}



/*
**  ssplit(): split a line into array pointers.
**
**  Each pointer wordv[i] points to the first character after the i'th 
**  occurence of c in buf.  Note that each wordv[i] includes wordv[i+1].
**
*/

ssplit( buf, c, ptr )
register char *buf;		/* line to split up 		*/
char c;				/* character to split on	*/
char **ptr;			/* the resultant vector		*/
{
        int count = 0;
        int wasword = 0;

        for( ; *buf; buf++ )
        {
		if ( !wasword )
			count++, *ptr++ = buf;
		wasword = ( c != *buf );
        }
	if ( !wasword )
		count++, *ptr++ = buf;
        *ptr = NULL;
        return( count );
}

!STUFFY!FUNK!
echo Extracting aliascheck.c
cat >aliascheck.c <<'!STUFFY!FUNK!'
#ifndef lint
static char * rcsid="$Header: aliascheck.c,v 4.0 86/11/17 16:02:05 sob Exp $";
#endif
/***************************************************************************
This work in its current form is Copyright 1986 Stan Barber
with the exception of resolve, gethostname and the original getpath which
as far as I know are in the Public Domain. This software may be distributed
freely as long as no profit is made from such distribution and this notice
is reproducted in whole.
***************************************************************************
This software is provided on an "as is" basis with no guarantee of 
usefulness or correctness of operation for any purpose, intended or
otherwise. The author is in no way liable for this software's performance
or any damage it may cause to any data of any kind anywhere.
***************************************************************************/
/* This program based in part on the aliascheck program from MH Version 1.7 */
#include "uuconf.h"
#include <grp.h>
#include <sys/param.h>

#ifdef LIBNDIR
#include <ndir.h>
#else
#ifdef USENDIR
#include "ndir.h"
#else
#include <dir.h>
#endif
#endif

char    *AliasFile =    ALIASFILE;
char    *Password  =    "/etc/passwd";
char    *MailDir   =    MAILFILE;

char *termptr;

struct  mailname {
	struct mailname *m_next;
	char            *m_name;
	int              m_seen;
}  users, bad;

char *getcpy(str)
{
	register char *cp;

	cp = (char *) malloc(strlen(str) + 1);
	strcpy(cp, str);
	return(cp);
}
uleq(c1, c2)
register char *c1, *c2;
{
	register int c;

	while(c = *c1++)
		if((c|040) != (*c2|040))
			return(0);
		else
			c2++;
	return(*c2 == 0);
}

char *parse(ptr, buf)
register char *ptr;
char *buf;
{
	register char *cp;

	cp = buf;
	while(isspace(*ptr) || *ptr == ',' || *ptr == ':')
		ptr++;
	while(isalnum(*ptr) || *ptr == '/' || *ptr == '-' || *ptr == '.')
		*cp++ = *ptr++;
	if(cp == buf) {
		switch(*ptr) {
		case '<':
		case '*':
		case '=':
			*cp++ = *ptr++;
		}
	}
	*cp = 0;
	if(cp == buf)
		return 0;
	termptr = ptr;
	return buf;
}


char   *mail = 0;
FILE   *out;
int     donecd = 0;

main(argc, argv)
	int argc;
	char *argv[];
{
	register char *cp, *pp, **cpp;
	register struct mailname *lp;
	register struct group *gp;
	struct direct *dir;
	DIR *dirp;
	char line[256], pbuf[64];
	FILE *a;

	if(argc == 3 && strcmp(argv[1], "-mail") == 0)
		mail = argv[2];
	if(!mail)
		out = stdout;
	if((a = fopen(Password, "r")) == NULL) {
		om();
		fprintf(out, "Can't open password file ");
		perror(Password);
		exit(1);
	}
	while(fgets(line, sizeof line, a)) {
		if(line[0] == '\n' || line[0] == ';')
			continue;
		cp = parse(line, pbuf);
		add(cp, &users);
	}
	fclose(a);
	if((a = fopen(AliasFile, "r")) == NULL) {
		om();
		fprintf(out, "Can't open alias file: %s\n", AliasFile);
		donecd = 1;
	} else {
		while(fgets(line, sizeof line, a)) {
			if(line[0] == '\n' || line[0] == ';')
				continue;
			cp = parse(line, pbuf);
			if(check(cp, 0)) {
				add(line, &bad);
				donecd = 1;
			}
		}
		fclose(a);
		if(donecd < 1) {
			if(out)
				fprintf(out, "No Alias Inconsistencies.\n");
		} else {
			om();
			fprintf(out, "%s :: %s Collisions:\n",
				Password, AliasFile);
			fprintf(out, "Colliding alias lines:\n");
			for(lp = bad.m_next; lp; lp = lp->m_next)
				fprintf(out, "%s", lp->m_name);
			donecd = 1;
		}
	}
	while(gp = getgrent()) {
		for(cpp = gp->gr_mem; *cpp; cpp++)
			if(!check(*cpp, 1)) {
				om();
				fprintf(out, "Group: %s--User: %s not in /etc/passwd\n",
					gp->gr_name, *cpp);
				donecd = 2;
			}
	}
	if(donecd < 2 && out)
		fprintf(out, "No extraneous group entries.\n");
#ifdef RAND
	for(lp = users.m_next; lp; lp = lp->m_next)
		if(lp->m_seen == 0) {
			om();
			fprintf(out, "User: %s not in a group.\n", lp->m_name);
			donecd = 3;
		}
	if(donecd < 3 && out)
		fprintf(out, "No Users not in any group.\n");
#endif
	if ((dirp = opendir(MailDir)) == 0) {
		om();
		fprintf(out, "Can't open mail directory: %s\n", MailDir);
		donecd = 4;
	} else {
		(void) readdir(dirp);		/* skip . */
		(void) readdir(dirp);		/* skip .. */
		while (dir = readdir(dirp)) {
			if (!check(dir->d_name, 0)) {
				om();
				fprintf(out, "Mail drop: %s--Nonexistent user.\n",
					dir->d_name);
				donecd = 4;
			}
		}
		closedir(dirp);
	}
	if(donecd < 4 && out)
		fprintf(out, "No Extra mail drops.\n");

	exit(donecd);
}


add(name, list)
char *name;
struct mailname *list;
{
	register struct mailname *mp;
	char *getcpy();

	for(mp = list; mp->m_next; mp = mp->m_next)
		;
	mp->m_next = (struct mailname *) malloc(sizeof *mp->m_next);
	mp = mp->m_next;
	mp->m_next = 0;
	mp->m_name = getcpy(name);
}

check(name, mark)
	char *name;
	int mark;
{
	register struct mailname *mp;

	for(mp = users.m_next; mp; mp = mp->m_next)
		if(uleq(name, mp->m_name)) {
			if(mark)
				mp->m_seen = 1;
			return 1;
		}
	return 0;
}


om()
{
	int pipes[2], child;

	if(out)
		return;
	if(mail) {
		pipe(pipes);
		out = fdopen(pipes[1], "w");
		if((child = fork()) == -1) {
			fprintf(stderr, "Aliascheck: no forks!\n");
			exit(1);
		}
		if(child == 0) {
			close(pipes[1]);
			close(0);
			dup(pipes[0]);
			close(pipes[0]);
			execl("/bin/mail", "mail", mail, 0);
			execl("/usr/bin/mail", "mail", mail, 0);
			execl("/bin/bellmail", "mail", mail,0);
			perror("mail");
			exit(1);
		}
		fprintf(out, "Aliascheck: ");
	}
}

#ifdef USENDIR
#include "ndir.c"
#endif
!STUFFY!FUNK!
echo Extracting MANIFEST
cat >MANIFEST <<'!STUFFY!FUNK!'
After all the uumail kits are run you should have the following files:

Filename	Kit Description
--------	--- -----------
Alias.Design     3  How the aliasing mechanism works.
Binary.Only      3  How to use uumail at a site with a Binary Only license.
Configure        1  A shell script that deals with system dependancies.
MANIFEST         2  This list of files.
Makefile.SH      3  The makefile builder.
README           1  READ THIS FIRST!
SYNOPSIS.txt     3  General features of uumail (for mod.sources)
Sendmail         3  How to use uumail with Sendmail.
address.1.SH     3  Manual Page builder for address
address.c        3  address program file
alias.c          3  The aliasing subroutines based on the ideas in MH.
aliascheck.c     2  A program to check the format of alias files.
deadletter.c     3  The subroutine that deals with returning mail that fails.
gethostnam.c     3  The subroutine that returns the name of the local host.
getpath.c        2  The paths database search subroutine.
kitleader        4  Shell script to produce front of kit. (SYSTEM DEPENDANT)
kitlists.c       3  Kit packer (SYSTEM DEPENDANT)
kittrailer       4  Shell script to product end of kit. (SYSTEM DEPENDANT)
makedepend.SH    3  Shell script to generate make dependancies.
makekit          3  Shell script to make a kit file
manifake         1  Shell script to make MANIFEST.new file.
manimake         3  Shell script to make MANIFEST file.
ndir.c           3  Source file for Berkeley directory subroutine simulation
ndir.h           3  Include file for Berkeley directory subroutine simulation
palias           3  Sample paths database file.
patchlevel.h     3  Patch level and version header file
resolve.c        2  The path resolving subroutine.
rmail.c          3  rmail replacement to call uumail.
uumail.8.SH      3  The manual page builder for uumail.8.
uumail.c         2  The main program for uumail/uupath.
uux.c            3  uux replacement for Binary Only sites.
!STUFFY!FUNK!
echo ""
echo "End of kit 2 (of 4)"
cat /dev/null >kit2isdone
config=true
for iskit in 1           	2           	3           	4           	; do
    if test -f kit${iskit}isdone; then
	echo "You have run kit ${iskit}."
    else
	echo "You still need to run kit ${iskit}."
	config=false
    fi
done
case $config in
    true)
	echo "You have run all your kits.  Please read README and then type Configure."
	chmod 755 Configure
	;;
esac
: I do not append .signature, but someone might mail this.
exit



More information about the Mod.sources mailing list