/*
**		S _ G E T
**
**
**	R E V I S I O N  H I S T O R Y
**
**	03/31/83  GWH	Split the SEND program into component parts
**			This module contains getuinfo, gethead, prefix,
**			and getaddr.
**
**	04/15/83  DPK	Changed address format from "user at host" to
**			"user@host". Also added call to getmailid() in get
**			getuinfo();
**
**	05/20/83  GWH	Modified getuinfo() to allow a number of user-
**			selectable options. These include the use of a
**			".sendrc" file on the user's home directory. With
**			the use of the "rc" file the user can set such things
**			default editor, local-alias-file, signature block,
**			and a directory for draft files. Also included is a
**			provision for keeping file copies of messages that
**			are successfully copied (incomplete at this time).
**
**	06/22/83  GWH	Added the required code to addrcat to enable local
**			alias file feature.
**
**	10/21/83  GWH	Fixed a bug in the alias file code (in addrcat).
**			Prevents segmentation faults when loops are found
**			in the alias file definitions.
**
**	11/16/83  DPK	Merged in DPK signature checking and Geo loop catcher
**
**	11/21/83  GWH	Added 'directedit' option.
**
**	03/18/85  DPK	Fixed usage of parsadr function so that after parsing
**		  VAK	we now use the components instead of original string.
**
*/


#include <stdio.h>
#include "./s.h"
#include "./s_externs.h"

extern char *getmailid();
extern char *malloc();
extern char *strdup();
extern struct passwd *getpwuid();
extern char *mktemp();
extern char *index();
extern char *getenv();

extern char *dflveditor;
extern char *dflchecker;

#define END	(char *)0

struct RCOPTION rcoptions[] = {
	"copyfile", COPYFILE,
	"draftdir", DRAFTDIR,
	"signature", SIGNATURE,
	"nosignature", NOSIGNATURE,
	"replyto", REPLYTO,
	"aliases", ALIASES,
	"subargs", SUBARGS,
	"editor", EDITOR,
	"veditor", VEDITOR,
	"file", CFILE,
	"fileonquery", QFILE,
	"nofile", NOFILE,
	"checker", CHECKER,
	"header", ADDHEADER,
	"paging", PAGING,
	END
};

int picko();
int ded = 0;
struct passwd *pw;
char *midp;
char *d_subargs = "vm";
char *tmp_tmplt = "tmpdrft.XXXXXX";
char *drft_tmplt = "drft.XXXXXX";
char linebuf[128];
char tmpline[128];

getuinfo() {
	FILE *fp;
	int realid, effecid;
	char *av[NARGS];
	char rcfilename[128];
	register char *p;
	char *rcname = "/.sendrc";

	int i;

	/* build a draft file name */

	mktemp(drft_tmplt);
	mktemp(tmp_tmplt);

	/* Who are we this time */

	getwho(&realid, &effecid);

	/* If nothing found return false. */

	if(( pw = getpwuid(effecid)) == NULL  ||
		(midp = getmailid(pw->pw_name)) == NULL )
			return(FALSE);

	/* Build a name for this user */
#ifdef PWNAME
	if (p = index( pw->pw_gecos, ',' )) *p = '\0';
	if (p = index( pw->pw_gecos, '<' )) *p = '\0';
	if (p = index( pw->pw_gecos, '&' )) {
		/* Deal with Berkeley folly */
		*p = 0;
		sprintf( from, "%s%c%s%s <%s@%s.%s>", pw->pw_gecos,
			 lowtoup( pw->pw_name[0] ),
#ifdef JNTMAIL
			 pw->pw_name+1, p+1, midp, ap_dmflip(locdomain), locname );
	} else
		sprintf( from, "%s <%s@%s.%s>", pw->pw_gecos, midp, ap_dmflip(locdomain), locname);
#else JNTMAIL
			pw->pw_name+1, p+1, midp, locname, locdomain);
	} else
		sprintf( from, "%s <%s@%s.%s>", pw->pw_gecos, midp, locname, locdomain );
#endif JNTMAIL
#else
	sprintf( from, "%c%s@%s.%s",	/* default from text */
#ifdef JNTMAIL
		lowtoup( midp[0] ), &(midp[1]), ap_dmflip(locdomain), locname);
#else JNTMAIL
		lowtoup( midp[0] ), &( midp[1] ), locname, locdomain );
#endif JNTMAIL
#endif
	/* Set default values for those options that need defaults */

	strcpy(editor, ((p = getenv("VISUAL")) && *p) ? p : 
 		        (((p = getenv("EDITOR")) && *p) ? p : dflveditor));
	strcpy(checker, dflchecker);
	sprintf(linebuf, "%s/.sent", pw->pw_dir);
	strcpy(copyfile, linebuf);
	sprintf(drffile, "%s/%s", pw->pw_dir, drft_tmplt);
 	sprintf(tmpdrffile, "%s/%s", pw->pw_dir, tmp_tmplt);
	strcpy( subargs, d_subargs );
	wflag = 0;
	cflag = 0;
	rflag = 0;
	qflag = 0;
	pflag = 0;
       	strcpy (signature, from);
	/* Get info from the ".sendrc" file */

	sprintf( rcfilename, "%s/%s", pw->pw_dir, rcname );
	if(( fp = fopen(rcfilename, "r")) != NULL ) {
		char *cp;

		/* Process info a line at a time */
		while( fgets(linebuf, sizeof(linebuf), fp ) != NULL ) {
			if (cp = index(linebuf, '\n'))
				*cp = 0;
			if (sstr2arg(linebuf, NARGS, av, " \t") < 0)
				continue;
			if( (i=picko(av[0])) < 0)
				continue; /* bad option */
			select_o( i, av );
		}	/* end of while on lines */
	}	/* end of if statement on file open */

	return(TRUE);
}	/* end of getuinfo routine */

/* select an option */

picko (pp)
char **pp;
{
	struct RCOPTION *rcopt;

	rcopt = rcoptions;
	while(rcopt->name != END ) {
		if( lexequ( rcopt->name, pp ) )
			return(rcopt->idnum);
		rcopt++;
	}

	return(-1); /* no match */
}

select_o (key, pp)
int key;
char **pp;
{
	register char *p;
	char *akey, *list;
	char tmpbuf[512];

	switch( key ) {
	case COPYFILE:
		/* Pick a file to store file copies of sent messages */
		if( *(++pp) == NULL )
		{
			fprintf(stderr,"You need to specify a copy file in your .sendrc.\n");
			fprintf(stderr,"Defaulting to '.sent'\n");
		}
		else
		{
			strcpy( copyfile, *pp);
			if( copyfile[0] != '/' ) 
			{
				strcpy(tmpline, copyfile);
				sprintf(copyfile, "%s/%s",pw->pw_dir,tmpline);
			}
		}
		break;

	case DRAFTDIR:
		/* pickup the draft directory */
		if( *(++pp) != NULL )
		{
			sprintf( drffile, "%s/%s", *pp, drft_tmplt );
			sprintf( tmpdrffile, "%s/%s", *pp, tmp_tmplt );
		}
		else
		{
			sprintf( drffile, "%s/%s", pw->pw_dir, drft_tmplt);
			sprintf( tmpdrffile, "%s/%s", pw->pw_dir, tmp_tmplt);
		}
		break;

	case SIGNATURE:
		/* If he wants a signature block use it */
		if( *(++pp) == 0 ){
#ifdef PWNAME
			sprintf( signature, "%c%s@%s.%s", /* use his login name alone */
#ifdef JNTMAIL
			   lowtoup(midp[0]), &(midp[1]), ap_dmflip(locdomain), locname );
#else JNTMAIL
			   lowtoup(midp[0]), &(midp[1]), locname, locdomain );
#endif JNTMAIL
#else
			strcpy( signature, from );	/* NO-OP ? */
#endif
		} else {
			linebuf[0] = '\0';
			while( *pp != 0){
				strcat(linebuf, *pp);
				strcat(linebuf, " ");
				*pp++;
			}
			if (checksignature (linebuf) == 0) {
#ifdef JNTMAIL
				sprintf(tmpline, "%s.%s", ap_dmflip(locdomain), locname);
#else JNTMAIL
				sprintf(tmpline, "%s.%s", locname, locdomain);
#endif JNTMAIL
				for( p=tmpline ; *p ; p++)
					*p = uptolow(*p);
				sprintf( signature, "%s <%s@%s>",
				   linebuf, midp, tmpline);
			} else {
				fprintf(stderr,"Illegal signature, using default\n");
			}
		}
		break;

	case NOSIGNATURE:
#ifdef PWNAME
		sprintf( signature, "%c%s@%s.%s", /* use his login name alone */
#ifdef JNTMAIL
			   lowtoup(midp[0]), &(midp[1]), ap_dmflip(locdomain), locname );
#else JNTMAIL
			   lowtoup(midp[0]), &(midp[1]), locname, locdomain);
#endif JNTMAIL
#else
		strcpy( signature, from );
#endif
		break;

	case REPLYTO:
		rflag = 1;
		break;

	case ALIASES:
		if( *(++pp) == NULL )
			fprintf(stderr,"You need to specify an alias file name!\n");
		else
		{
			strcpy( aliasfilename, *pp );
			if( aliasfilename[0] != '/' ) 
			{
				strcpy(tmpline, aliasfilename);
				sprintf(aliasfilename, "%s/%s",pw->pw_dir,tmpline);
			}
		}
		aliasinit( aliasfilename );
		break;

	case SUBARGS:
		while( *(++pp) != NULL )
			strcat(subargs, *pp);
		wflag = 1;
		break;
	case EDITOR:
		if(ded)
			break;
		else if( *(++pp) == NULL )
		{
			fprintf(stderr,"You need to specify an editor after 'editor' in your .sendrc.\n");
			fprintf(stderr,"Defaulting to %s.\n",editor);
		}
		else
			strcpy( editor, *pp );
		break;
	case VEDITOR:
		/* Default editor for use with the "e" command */
		if( *(++pp) == NULL )
		{
			fprintf(stderr,"You need to specify an editor with the veditor in your .sendrc.\n");
			fprintf(stderr,"Defaulting to %s.\n",editor);
		}
		else
			strcpy( editor, *pp );
		ded = 1;
		break;

	case CHECKER:
		/* Default spelling checker for use with the "c" command */
		if( *(++pp) == NULL )
		{
			fprintf(stderr,"You need to specify a spelling checker after 'checker' in your .sendrc.\n");
			fprintf(stderr,"Defaulting to %s.\n",checker);
		}
		else
			strcpy( checker, *pp );
		break;

   	case PAGING : 
	   	/* Turn on paging during message review */
   		pflag = 1;
   		break;

	case CFILE:
		cflag = 1;
		break;

	case QFILE:
		qflag = 1;
		/* DROP */
	case NOFILE:
		cflag = 0;
		break;

	case ADDHEADER:
		/* Add a header line to the message */
		++pp;
		if (isstr(*pp))
			addheader(pp[0], pp[1]);
		break;

	default:
		fprintf(stderr,"GETUINFO - NO SUCH OPTION key = %d\n", key);

	} /* end of switch */
}
/* Prompts for a header with print as prompt and gathers it up */

gethead (print, buf, flag)
char    print[];
register char   *buf;
int     flag;                     /* print contents, if any?            */
{
    char    c;
    int retval;                   /* type of FLD modification           */
    register int    n;
    register int    max = S_BSIZE;

    if (flag && *buf)             /* print what already is there        */
	printf (shrtfmt, print, buf);

    flag = TRUE;                  /* always & only look at first char   */
    do
    {
	printf ("%s", print);     /* prompt                             */
	if (*buf == '\\')
	{
	    *buf++ = ',';
	    *buf++ = '\n';
	}
	fflush (stdout);

	if (flag)
	{
	    flag = FALSE;         /* ignore first char of next lines    */
	    switch (c = getchar ())
	    {
		case '-':         /* delete single name                */
			retval = ITMRMV;
			break;
		case '#':         /* delete all contents     */
		    *buf = 0;
		    while (getchar () != '\n');
		    return (FLDREMV);

		case '\n':        /* leave it as it is                  */
		    return (FLDSAME);

		case '+':         /* append to end of field             */
		    retval = FLDADD;
		    if (*buf != '\0')
		    {                 /*   if not already empty             */
			buf = &buf[strlen (buf)];
				      /* point to end of buf                */
			*buf++ = ','; /* assume it's an address field       */
			*buf++ = ' ';
			max -= 2;
		    }
		    break;

		default:          /* copy over it                       */
		    retval = FLDOVER;
		    *buf++ = c;
		    max--;
		    break;
	    }
	}
	n = gather (buf, max);    /* get rest of header line            */
	max -= n;
	buf = &buf[n - 1];
    }
    while (*buf == '\\');         /* user wants to add more?            */
    return (retval);
}

prefix (buf, pre)
char   *buf,
       *pre;
{
    while (*pre)
	if (*buf++ != *pre++)
	    return (FALSE);
    return (TRUE);
}


getaddr (print, buf, flag, defhost)
    char print[];
    char *buf;
    int flag;
    char defhost[];
{
    char addrin[S_BSIZE];     /* temporary store for user input     */
    char    *dn, *gstrindex();

    if (flag && *buf)             /* print what already is there        */
	printf (shrtfmt, print, buf);

    addrin[0] = '\0';             /* mark temp buffer as empty          */
    switch (gethead (print, addrin, NO))
    {
	case FLDREMV:             /* erase any existing contents        */
	    buf[0] = '\0';
	    break;

	case ITMRMV:		 /* delete single name			*/
		dn = gstrindex(addrin, buf);
		if(dn == 0){
			fprintf(stderr," no such name in the list; name = '%s'\n",addrin);
			break;
		}
		dlt_name( buf, dn );
	    break;
	case FLDSAME:             /* leave as is                        */
	    break;

	case FLDOVER:             /* overwrite existing contents        */
	    buf[0] = '\0';        /* erase existing, then add           */
	    aliasmap(buf, addrin, defhost);
	    break;

	case FLDADD:              /* append to existing                 */
	    aliasmap(buf, addrin, defhost);
	    break;
    }
}

/*
**	S P E C I A L  S T R I N D E X  F U N C T I O N
**
** Specially modified by George Hartwig to return a pointer to the beginning
** of the requested string instead of the offset.
*/

char *gstrindex (str, target)           /* return column str starts in target */
register char   *str,
		*target;
{
    char *otarget;
    register short slen;

    for (otarget = target, slen = strlen (str); ; target++)
    {
	if (*target == '\0')
	    return ((char *) 0);

	if (equal (str, target, slen))
	    return( target );
    }
}
dlt_name(buf, pos)
char *buf, *pos;

/* buf is a pointer to a character array and pos is a pointer to a position  */
/* within that array. The purpose of this routine is delete the name field   */
/* pointed to by pos. In order to do this we will search backward to either  */
/* comma ',' or a colon ':' (if a comma, we will then delete that comma also */
/* and then delete forward until another comma or 			     */
/* a end-of-string '\0' is found. 					     */

{
	char tmpbuffer[S_BSIZE];
	char *sd, *ed, *cp;
	int quote_flag;


	cp = pos;
	quote_flag = 0;

	while(cp >= buf ) {
		if( *cp == '"' )
			if( quote_flag == 0 )
				quote_flag = 1;
			else
				quote_flag = 0;
		if( *cp == ',' && quote_flag == 0 )
			break;
		else
			cp--;
	}
	sd = cp;

	cp = pos;

	while( *cp != '\0' ) {
		if( *cp == '"' )
			if( quote_flag == 0 )
				quote_flag = 1;
			else
				quote_flag = 0;
		if( *cp == ',' && quote_flag == 0 )
			break;
		else
			cp++;
	}

	ed = cp;

	/* at this point *sd should point at the comma preceding the name
	** to be deleted or the beginning of the line and ed should be
	** pointing to the trailing comma or the end of the line. So it is
	** necessary at this point to determine just which of these cases
	** have occurred so that the string may be properly reassembled.
	*/

	if( *sd == ',' && *ed == ',' ){
		sd++;
		*sd = '\0';
		ed++;
		sprintf( tmpbuffer, "%s%s", buf, ed);
	}

	else
	if( sd <= buf ){
		ed++;
		strcpy(tmpbuffer, ed);
	}
	else
	if( *ed == '\0' ){
		*sd = '\0';
		strcpy(tmpbuffer, buf);
	}
	strcpy( buf, tmpbuffer );
}

/*
 *	checksignature ()
 *
 *  Verifies that the signature string does not contain any special
 *  characters or is quoted.  Also checks for blank "name" portion.
 */
checksignature (sp)
register char *sp;
{
	char tptr[128], *savptr, *ptr;
	char *rindex();
	static char quote[] = "\"";
	
	savptr = sp;
	while (*sp && isspace(*sp))  /* eat leading whitespace */
		sp++;
	if (*sp == '\0') {
		fprintf(stderr,"Signature is blank\n");
		return (-1);     /* must have some signature */
	}
	while (*sp) {
		switch (*sp) {
		case '<':
		case '>':
		case '@':
		case ',':
		case ';':
		case ':':
		case '.':	/*  Arggggg...  */
		case '[':
		case ']':
			/* surround bad signature with quotes */
			tptr[0] = '\0';
			strcat( tptr, quote );
			sp = savptr;
			strcat( tptr, sp );
			if( ptr = rindex( tptr, ' ' ) )
				*ptr = '\0';
			strcat( tptr, quote );
			strcpy( sp, tptr );
			return( 0 );

		case '\\':
			sp++;
			if (*sp == '\0')
				return (-1);
			break;

		case '"':
			for (sp++; *sp != '"'; sp++) {
				if (*sp == '\\') {
					sp++;
					if (*sp == '\0')
						return (-1);
				} else if (*sp == '\0') {
					fprintf(stderr,"Unmatched '\"' in signature\n");
					return (-1);
				}
			}
			break;

		default:
			break;
		}
		sp++;
	}

	return (0);
}

addheader(name, data)
char	*name;
char	*data;
{
	register struct header *nhp;
	register struct header *ohp;
	register char *cp;
	char	buf[LINESIZE];

	if(!isstr(name))
	    return;
	for (cp = name; *cp; cp++)
		if (!isprint(*cp) && *cp != '\t') {
			fprintf(stderr,"Illegal character in header name.\n");
			return;
		}
	data = (isstr(data) ? data : "");
	for (cp = data; *cp; cp++)
		if (!isprint(*cp) && *cp != '\t') {
			fprintf(stderr,"Illegal character in header data.\n");
			return;
		}
	if (headers) {
		for (ohp = headers; !lexequ(name, ohp->hname); ohp = ohp->hnext)
			if (ohp->hnext == (struct header *)0)
				break;
		if(lexequ(name, ohp->hname)) {
			strncpy(ohp->hdata, data, sizeof(ohp->hdata)-1);
			return;
		}
	}
	nhp = (struct header *)malloc(sizeof (*nhp));
	sprintf(buf, "%s:  ", name);
	if (nhp == NULL || (nhp->hname = strdup(buf)) == NULL) {
		fprintf(stderr,"No memory for header '%s'\n", buf);
		if (nhp)
			free(nhp);
		return;
	}
	strncpy(nhp->hdata, data, sizeof(nhp->hdata)-1);
	nhp->hnext = (struct header *)0;
	nhp->hdata[sizeof(nhp->hdata)-1] = '\0';
	if (headers == (struct header *)0) {
		headers = nhp;
		return;
	}
	ohp->hnext = nhp;
}
