/*
 * 5799-WZQ (C) COPYRIGHT = NONE
 * LICENSED MATERIALS - PROPERTY OF IBM
 */
/* $Header:sub.c 12.0$ */
/* $ACIS:sub.c 12.0$ */
/* $Source: /ibm/acis/usr/src/old/berknet/RCS/sub.c,v $ */

#ifndef lint
static char *rcsid = "$Header:sub.c 12.0$";
#endif

static char sccsid[] = "@(#)sub.c	4.5	(Berkeley)	1/5/83";

/*
	sub.c

	support procedures

	the following procedures end up reading the passwd file
	or the passwdf file and are to be avoided.

	getpwuid(uid)
	getpwnam(sn)
	PwdCurrent()
	getenv("HOME")		maybe if hget, hgethome don't work
	SnFromUid(uid)		maybe if hashed passwd stuff doesn't work
	SnCurrent()		maybe if getlogin fails calls SnFromUid(uid)
	getpwf()
	passwdent(uid,sn)
*/

# include "defs.h"
# include "config.h"
# include <varargs.h>

/* global variables */
int debugflg = DBV;	/* debug flag */
char local = LOCAL;	/* the machine we're on */
struct userinfo status;

char netcmd[]  =	NETCMD;
char resfile[] = 	RESFILE;
char senddir[] =	SENDDIR;
char Bsh[] =		BINSH;

char shomedir[100];

/*
	passwdent()

	Read the password file looking for current user's entry.
	Fill in the status structure.
	Has the (dangerous) side effect of giving a value to getenv("HOME").
*/
passwdent()
{
	register char *u;
	register struct passwd *pwd;
#ifdef CRN
	register struct gecos *gcos;
#endif
	pwd = PwdCurrent();
	if(pwd == NULL){
		err("Bad uid/username\n");
		return;
	}
	strcpy(status.localname,pwd->pw_name);
	status.muid = guid(pwd->pw_uid,pwd->pw_gid);
	status.mgid = pwd->pw_gid;
#ifdef CRN
	if( (gcos=pwgecos( pwd->pw_gecos) ) == NULL )
		strcpy( status.jobno, MAGICCRN );
	else {
		if( debugflg )
			debug( "crn found = %s\n", gcos->gc_crn );
		if( isalpha( gcos->gc_crn[0] ) ||
			isdigit( gcos->gc_crn[0] ) )
			strcpy( status.jobno, gcos->gc_crn );
		else
			strcpy( status.jobno, MAGICCRN );
	}
#else
	strcpy( status.jobno, "XYZZ" );
#endif
	strcpy(status.dir,pwd->pw_dir);
	strcpy(shomedir,pwd->pw_dir);		/* side effect */
	u = pwd->pw_shell;
	if(u[0] == 0 || strcmp(u,"/bin/sbash") == 0)u= Bsh;
	strcpy(status.loginshell,u);
	}
/*
	promptlogin(mchto)

	ask user for login and passwd on mchto.
	make sure status.localname has a value before calling
	this.  One way is to call passwdent().
*/
promptlogin(mchto)
	char mchto;
{
	char buf[BUFSIZ], mch;
	FILE *wf;
	int c;
	if(status.login[0]==0 || status.force){
		buf[0] = 0;
		wf = fopen("/dev/tty","r");
		if(wf != NULL){
			fprintf(stderr,"Name (%s:%s): ",longname(mchto),
				status.localname);
			if(fgets(buf, BUFSIZ, wf) != buf){
				perror("fgets");
				exit(EX_OSERR);
				}
			c = strlen(buf);
			buf[c > 0 ? c-1 : 0] = 0;
			if(c > 10){
				err("Login name too long.\n");
				exit(EX_USAGE);
				}
			if(FMemberSCh(buf,' ')){
				err("Login names don't have blanks in them.\n");
				exit(EX_USAGE);
				}
			fclose(wf);
			}
		if(buf[0] == 0)strcpy(buf,status.localname);
		mch = MchSFromAddr(status.login,buf);
		if(mch != local && mch != mchto){
			err("Must specify login name on %s machine\n",
				longname(mchto));
			exit(EX_USAGE);
			}
		}
	if(strcmp(status.login,"network") != 0
		&& (status.mpasswd[0]== 0 || status.force)){
		sprintf(buf,"Password (%s:%s):",
			longname(mchto), status.login);
		strcpy(status.mpasswd,getpass(buf));
		}
	if(status.login[0] == 0) strcpy(status.login,status.localname);
	if(status.mpasswd[0] == 0)strcpy(status.mpasswd,"\"\"");
	status.force = 0;
	}

#define	tst(a,b)	(*mode == 'r'? (b) : (a))
#define	RDR	0
#define	WTR	1
static	int	popen_pid[20];

/* return a file descriptor suitable for writing, send to 
  user toaddress from fromaddress,
  if cautious != 0 then don't do any forwarding
  hopcnt is passed thru the mail program.
	  normal value is 0
  */
FILE *
mailopen(toaddress, fromaddress, cautious, hopcnt)
char *toaddress, *fromaddress;
int cautious, hopcnt;
{
	char	cmd[100];
	char	*mode = "w";
	int p[2];
	register myside, hisside, pid;
	char shopcnt[20];

	if(pipe(p) < 0)
		return NULL;
	myside = tst(p[WTR], p[RDR]);
	hisside = tst(p[RDR], p[WTR]);
	while((pid = fork()) == -1)sleep(2);
	if(pid == 0) {
		/* myside and hisside reverse roles in child */
		close(myside);
		/*
		dup2(hisside, tst(0, 1));
		*/
		close(0);
		dup(hisside);
		close(hisside);
		sprintf(shopcnt,"%d",hopcnt);
		if(fromaddress != NULL){
			/* by convention, MAILFWD1 may forward this mail
			   and response messages shouldn't be forwarded */
			if(!cautious && !FMemberSCh(toaddress,'/')){
# ifdef SENDMAIL
				mexecl("/usr/lib/sendmail",
					"sendmail", "-oee", "-r", fromaddress,
					"-h",shopcnt, toaddress, 0);
# endif SENDMAIL
				mexecl(MAILFWD1, "mail","-r",fromaddress,
					"-h",shopcnt,toaddress,0);
			}
			mexecl(SYSMAIL2, "mail","-d","-r",fromaddress,
				"-h", shopcnt,toaddress,0);
		} else {
			if(!cautious && !FMemberSCh(toaddress,'/')){
# ifdef SENDMAIL
				mexecl("/usr/lib/sendmail",
					"sendmail", "-ee", "-h", shopcnt,
					toaddress, 0);
# endif
				mexecl(MAILFWD1, "mail","-h", shopcnt,
					toaddress,0);
			}
			mexecl(SYSMAIL2, "mail","-d","-h", shopcnt,toaddress,0);
		}
		perror(SYSMAIL2);
		exit(EX_UNAVAILABLE);
	}
	if(pid == -1)
		return NULL;
	popen_pid[myside] = pid;
	close(hisside);
	return(fdopen(myside, mode));
}

mailclose(ptr)
FILE *ptr;
{
	register f, r, (*hstat)(), (*istat)(), (*qstat)();
	int status;

	f = fileno(ptr);
	fclose(ptr);
	istat = signal(SIGINT, SIG_IGN);
	qstat = signal(SIGQUIT, SIG_IGN);
	hstat = signal(SIGHUP, SIG_IGN);
	while((r = wait(&status)) != popen_pid[f] && r != -1)
		;
	if(r == -1)
		status = -1;
	signal(SIGINT, istat);
	signal(SIGQUIT, qstat);
	signal(SIGHUP, hstat);
	return(status);
}
	
/* 
	ch means 'a'-'z', inx in 0..25
	ch means '0'-'9', inx in 26..35
*/
chtoinx(ch) {
	if('a' <= ch && ch <= 'z')
		return(ch - 'a');
	if('0' <= ch && ch <= '9')
		return((ch - '0') + 26);
	err("bad ch");
}

/* 
	inx is 0..25 means 'a'-'z'
	inx is 26..35 means '0'-'9'
*/
inxtoch(inx) {
	if(0 <= inx && inx <= 25)
		return(inx + 'a');
	if(26 <= inx && inx <= 35)
		return('0' + (inx - 26));
	err("bad ch");
}

/* determine through machine */
gothru(from,to){
	register int i;
	switch(from){
# ifdef RAND
	case 'a':	i = configA[chtoinx(to)]; break;
	case 'b':	i = configB[chtoinx(to)]; break;
	case 'c':	i = configC[chtoinx(to)]; break;
# endif
# ifdef NOSC
	case 'a':	i = configA[chtoinx(to)]; break;
	case 'c':	i = configC[chtoinx(to)]; break;
	case 'm':	i = configM[chtoinx(to)]; break;
# endif
# ifdef BERKELEY
	/* for Berkeley */
	case 'a':	i = configA[chtoinx(to)]; break;
	case 'b':	i = configB[chtoinx(to)]; break;
	case 'c':	i = configC[chtoinx(to)]; break;
	case 'd':	i = configD[chtoinx(to)]; break;
	case 'e':	i = configE[chtoinx(to)]; break;
	case 'f':	i = configF[chtoinx(to)]; break;
	case 'g':	i = configG[chtoinx(to)]; break;
	case 'h':	i = configH[chtoinx(to)]; break;
	case 'i':	i = configI[chtoinx(to)]; break;
	case 'j':	i = configJ[chtoinx(to)]; break;
	case 'k':	i = configK[chtoinx(to)]; break;
	case 'l':	i = configL[chtoinx(to)]; break;
	case 'm':	i = configM[chtoinx(to)]; break;
	case 'n':	i = configN[chtoinx(to)]; break;
	case 'o':	i = configO[chtoinx(to)]; break;
	case 'p':	i = configP[chtoinx(to)]; break;
	case 'r':	i = configR[chtoinx(to)]; break;
	case 's':	i = configS[chtoinx(to)]; break;
	case 't':	i = configT[chtoinx(to)]; break;
	case 'u':	i = configU[chtoinx(to)]; break;
	case 'v':	i = configV[chtoinx(to)]; break;
	case 'w':	i = configW[chtoinx(to)]; break;
	case 'x':	i = configX[chtoinx(to)]; break;
	case 'y':	i = configY[chtoinx(to)]; break;
	case 'z':	i = configZ[chtoinx(to)]; break;
# endif
	default:	i = 0; break;
	}
	return(i);
	}

# define NPARMS 20
/* prints out commands before executing them */
/*VARARGS0*/
mexecl(va_alist)
  	va_dcl
{
	char *arr[NPARMS], *file, *f;
	va_list ap;
	register int i;
	va_start(ap);
	file = va_arg(ap, char *);
	i = 0;
	while(f = va_arg(ap, char *)){
		if(i >= NPARMS){
			err("too many args");
			arr[NPARMS-1] = NULL;
			break;
			}
		if(debugflg) err("'%s' ",f);
		arr[i++] = f;
		}
	arr[i] = NULL;
	va_end(ap);
	if(debugflg) putc('\n',stderr);
	execv(file, arr);
	}

/* prints out commands before executing them */
mexecv(s,p)
  register char *s, **p;{
	register int i;
	if(debugflg){
		err("'%s' ",s);
		for(i=0; p[i]; i++)err("'%s' ",p[i]);
		putc('\n',stderr);
		}
	execv(s,p);
	}

/*VARARGS0*/
/* fills in -l - -p from commands like rcp */
/* must be called with at least two arguments */
kexecl(va_alist)
  va_dcl
{
	char *a[NPARMS], i = 1, *file;
	va_list ap;
	va_start(ap);
	file = va_arg(ap, char *);
	a[0] = va_arg(ap, char *);
	if(status.login[0]){
		a[i++] = "-l";
		a[i++] = status.login;
		}
	if(status.mpasswd[0]){
		a[i++] = "-p";
		a[i++] = status.mpasswd;
		}
	if(status.nonotify)a[i++] = "-b";
	if(status.force)   a[i++] = "-f";
	if(status.quiet)   a[i++] = "-q";
	if(status.nowrite) a[i++] = "-n";
	while (a[i++] = va_arg(ap, char *)){
		if(i >= NPARMS){
			err("too many args");
			a[NPARMS-1] = NULL;
			break;
			}
		};
	mexecv(file, a);
	}

/*
	MchSFromAddr(sn,addr)

	take an address of the form "mach:username"
	and return mch as the 1 char code of "mach" and
	in sn put "username".
	If addr has no colon in it, return mch==local, sn==addr.
	Return 0 for mch if host unknown.
*/
MchSFromAddr(sn,addr)
	char *sn, *addr;
{
	char fcolon = 0, *s, mch, stemp[BUFSIZ];

	/* assume addr is a local address */

	strcpy(stemp,addr);
	s = stemp;
	while(*s){
		if(*s == ':'){
			fcolon = 1;
			*s++ = 0;
			break;
		}
		s++;
	}
	if(fcolon != 1){
		/* sn better be the right size for addr */
		mch = local;
		strcpy(sn,addr);
		return(mch);
	}

	/* addr has a colon in it, s pts to name */
	mch = lookup(stemp);
	strcpy(sn,s);
	return(mch);
}


/* returns a single character for machine S */
/* returns 0 for unknown host */
lookup(s)
  register char *s; {
	register struct tt *t;
	if(strlen(s) == 1)return(isupper(*s) ? tolower(*s) : *s);
	for(t = table; t->bigname; t++)
		if(streql(s,t->bigname) == 0)return(t->lname);
	return(0);
	}

/* returns a long name (string) for single character machine c */
char *longname(c)
  register char c;
	{
	register struct tt *t;
	if(c == 0)return("UNKNOWN");
	for(t = table; t->bigname; t++)
		if(c == t->lname)return(t->bigname);
	return("UNKNOWN");
	}
/*
	FMemberSCh(s,ch)

	return 1 if ch is a character in string s.
	0 otherwise.
*/
FMemberSCh(s,ch)
	register char *s, ch; 
{
	while(*s)if(*s++ == ch)return(1);
	return(0);
}

/* return a static string with the form "X hrs X mins X secs" */
/* t is # of secs */
char *comptime(t)
  long t; {
	static char str[30];
	char buf[20];
	long w;
	str[0] = 0;
	w = t/3600L;
	if(w > 0L){
		sprintf(buf,"%ld hr ",w);
		strcat(str,buf);
		}
	t = t % 3600L;
	w = t/60L;
	if(w > 0L){
		sprintf(buf,"%ld min ",w);
		strcat(str,buf);
		}
	t = t % 60L;
	sprintf(buf,"%ld sec",t);
	strcat(str,buf);
	return(str);
	}
/*
	parseparmlist(string)

	parses variable parameter lists in string,
	as defined in genparmlist in net.c
*/
parseparmlist(parmlist)
	char *parmlist;
{
	while(*parmlist && *parmlist != '(')parmlist++;
}

/* just like strcmp except upper- and lower-case are ignored */
streql(s1,s2)
  char *s1, *s2; {
	char a,b;
	while(*s1 && *s2){
		a = isupper(*s1) ? tolower(*s1) : *s1;
		b = isupper(*s2) ? tolower(*s2) : *s2;
		if(a < b)return(-1);
		if(a > b)return(1);
		s1++, s2++;
		}
	if(*s2)return(-1);
	if(*s1)return(1);
	return(0);
	}
/* VARARGS0 */
err(s,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r) {
	fprintf(stderr,s,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r);
	}
