#ifndef lint
static char *sccsid = "@(#)pw.c	2.5 (smail) 9/15/87";
#endif

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include "defs.h"
#include <ctype.h>

char *malloc();
void free();

typedef struct pw_node pwlist;

struct pw_node {
	char *lname;			/* login name */
	char *fname;			/* full name  */
	int  uid;			/* user-id    */
	char *home;			/* login name */
	pwlist *vlink;			/* link to next item */
};

pwlist *pwhead;		/* head of linked list */
pwlist *pwparse();	/* head of linked list */

#define PNULL	((pwlist *) 0)

char *
pwfnam(user)
char *user;
{
	pwlist *f;

	/*
	** check for previously cached user
	*/

	for(f=pwhead; f != NULL; f=f->vlink) {
		if(strcmp(user, f->lname) == 0) {
			return(f->fname);
		}
	}
	/*
	** not found parse the password file
	*/

	while((f=pwparse()) != PNULL) {
		if(strcmp(user, f->lname) == 0) {
			return(f->fname);
		}
	}
	return(NULL);
}

char *
pwuid(uid)
int uid;
{
	pwlist *f;

	/*
	** check for previously cached user
	*/

	for(f=pwhead; f != NULL; f=f->vlink) {
		if(uid == f->uid) {
			return(f->lname);
		}
	}
	/*
	** not found parse the password file
	*/

	while((f=pwparse()) != PNULL) {
		if(uid == f->uid) {
			return(f->lname);
		}
	}
	return(NULL);
}

#ifndef SENDMAIL
char *
tilde(user)
char *user;
{
	pwlist *f;

	/*
	** check for previously cached user
	*/

	for(f=pwhead; f != NULL; f=f->vlink) {
		if(strcmp(user, f->lname) == 0) {
			return(f->home);
		}
	}
	/*
	** not found parse the password file
	*/

	while((f=pwparse()) != PNULL) {
		if(strcmp(user, f->lname) == 0) {
			return(f->home);
		}
	}
	return(NULL);
}
#endif /* not SENDMAIL */

char *
fullname(gecos)
char *gecos;
{
	static char fname[SMLBUF];
	register char *cend;

	(void) strcpy(fname, gecos);
	if (cend = index(fname, ','))
		*cend = '\0';
	if (cend = index(fname, '('))
		*cend = '\0';
	/*
	** Skip USG-style 0000-Name nonsense if necessary.
	*/
	if (isdigit(*(cend = fname))) {
		if ((cend = index(fname, '-')) != NULL)
			cend++;
		else
			/*
			** There was no `-' following digits.
			*/
			cend = fname;
	}
	return (cend);
}

pwlist *
pwparse()
{
	pwlist *f;
	char *p, *name;
	struct passwd *pwent, *getpwent();
	unsigned int i;
	static int pw_eof = 0;

	if((pw_eof == 1)
	|| ((pwent = getpwent()) == (struct passwd *) NULL)) {
		pw_eof = 1;
		return(PNULL);
	}
	/*
	** Get an entry from the password file.
	** Parse relevant strings.
	*/
	f = (pwlist *) malloc(sizeof(pwlist));
	if(f == PNULL) return(PNULL);

	f->vlink = pwhead;
	pwhead   = f;
	f->uid   = pwent->pw_uid;

	i=strlen(pwent->pw_name)+1;
	p = malloc(i);
	if(p == NULL) return(PNULL);
	f->lname = strcpy(p, pwent->pw_name);

	i=strlen(pwent->pw_dir)+1;
	p = malloc(i);
	if(p == NULL) return(PNULL);
	f->home  = strcpy(p, pwent->pw_dir);

	name = fullname(pwent->pw_gecos);
	i=strlen(name)+1;
	p = malloc(i);
	if(p == NULL) return(PNULL);
	f->fname = strcpy(p, name);
	return(f);
}

#ifdef FULLNAME
/*
** Resolve a full name to a login name.
** Not too much smarts here.
*/

char *
res_fname(user)
register char *user;
{
	long pos, middle, hi, lo;
	static long pathlength = 0;
	register char *s;
	int c;
	static FILE *file;
	int flag;
	char namebuf[SMLBUF], *path;
	extern enum edebug debug;
	extern char *fnlist;



DEBUG("res_fname: looking for '%s'\n", user);

	if(pathlength == 0) {	/* open file on first use */
		if((file=fopen(fnlist, "r")) == NULL) {
			DEBUG( "can't access %s.\n", fnlist);
			pathlength = -1;
		} else {
			(void) fseek(file, 0L, 2); 	/* find length */
			pathlength = ftell(file);
		}
	}

	if(pathlength == -1 ) return(NULL);

	lo = 0;
	hi = pathlength;
	path = namebuf;

	(void) strcpy( path, user );
	(void) strcat( path, "\t" );

	for( ;; ) {
		pos = middle = ( hi+lo+1 )/2;
		(void) fseek( file, pos, 0 );	/* find midpoint */
		if (pos != 0)		/* to beginning of next line */
			while( ( c=getc( file ) ) != EOF && c != '\n' );
		for( flag = 0, s = path; flag == 0; s++ ) { /* match??? */
			if ( *s == '\0' ) {
				goto solved;
			}
			c = getc( file );
			flag = lower( c ) - lower( *s );
		} 
		if (lo >= middle)		/* failure? */
			return(NULL);

		if(c != EOF && flag < 0)	/* close window */
			lo = middle;
		else 
			hi = middle - 1;
	}
/* 
** Now just copy the result.
*/
solved:
	while(((c  = getc(file)) != EOF) && (c != '\t') && (c != '\n')) {
		*path++ = c;
	}

	if(path == namebuf) {	/* NULL alias field */
		return(NULL);
	}

	*path = '\0';
	if((path = malloc((unsigned) strlen(namebuf)+1)) == NULL) {
		return(NULL);	/* sorry, no memory */
	}

	(void) strcpy(path, namebuf);
	return(path);

}
#endif	/* FULLNAME */
