/* $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred.
 */

/* $Header: getpwwho.c 2.0 86/01/28 $ */

From James.Gosling@CMU-VLSI@CMU-10A  Thu Sep 10 07:13:52 1981
Date: 10 Sep 1981 10:07:48-EDT
From: James.Gosling at CMU-VLSI at CMU-10A
Reply-To: James.Gosling at CMU-10A
To: IngVAX.eric@Berkeley
Subject: getpwwho.c
Status: R

/*
 **********************************************************************
 * HISTORY
 * 11-Dec-80  Mike Accetta(mja) at Carnegie-Mellon University
 *	Changed to convert all separator characters to spaces when
 *	copying name into internal buffer so that dots in names with
 *	more than two parts will match password file entries.
 *
 * 03-Dec-80  Mike Accetta (mja) at Carnegie-Mellon University
 *	Changed to treat everything before last blank in name as first
 *	name and modified to close password file when called with null
 *	pointer.
 *
 * 29-Nov-80  Mike Accetta (mja) at Carnegie-Mellon University
 *	Changed to allow '.' as separator in names.
 *
 * 07-Nov-80  Mike Accetta (mja) at Carnegie-Mellon University
 *	Removed reference to (extinct) alias name.
 *
 **********************************************************************
 */

#include <stdio.h>
#include <ctype.h>
#include <pwd.h>
#include <gecos.h>

#define	dotisspace(c)	(isspace(c) || (c) == '.')

struct gecos *parsgecos();

static char PASSWD[]	= "/etc/passwd";
static char EMPTY[] = "";
static FILE *pwf = NULL;
static char line[BUFSIZ+1], auxline[BUFSIZ+1];
static struct passwd passwd, auxpasswd;
static struct gecos auxgecos;
static int ambigstate;

static setpwent()
{
	if( pwf == NULL )
		pwf = fopen( PASSWD, "r" );
	else
		rewind( pwf );
}

static endpwent()
{
	if( pwf != NULL ){
		fclose( pwf );
		pwf = NULL;
	}
}

static char *
pwskip(p)
register char *p;
{
	while( *p && *p != ':' )
		++p;
	if( *p ) *p++ = 0;
	return(p);
}

static struct passwd *getpwent(passwd,line)
register struct passwd *passwd;
char * line;
{
	register char *p;

	if (pwf == NULL) {
		if( (pwf = fopen( PASSWD, "r" )) == NULL )
			return(0);
	}
	p = fgets(line, BUFSIZ, pwf);
	if (p==NULL)
		return(0);
	passwd->pw_name = p;
	p = pwskip(p);
	passwd->pw_passwd = p;
	p = pwskip(p);
	passwd->pw_uid = atoi(p);
	p = pwskip(p);
	passwd->pw_gid = atoi(p);
	passwd->pw_quota = 0;
	passwd->pw_comment = EMPTY;
	p = pwskip(p);
	passwd->pw_gecos = p;
	p = pwskip(p);
	passwd->pw_dir = p;
	p = pwskip(p);
	passwd->pw_shell = p;
	while(*p && *p != '\n') p++;
	*p = '\0';
	return(passwd);
}

struct gecos *_gecos;

static char name1[100], name2[100];
static int name1l, name2l;

static scanpw (pw, buf)
register struct passwd *pw;
char   *buf;
{
    register struct gecos  *ge;
    register char  *cp;

    while (getpwent (pw, buf)) {
	_gecos = ge = parsgecos (pw -> pw_gecos);
	if (*name1 == '\0' && strcmp (name2, pw -> pw_name) == 0)
	    return 1;
	if (IsName (ge -> pw_who))
	    return 2;
    }
    return 0;
}

static  IsName (name)
char   *name; {
    register char  *p1,
                   *p2;
    if (!FoldedEQ (name, name1, name1l))
	return (0);
    p1 = p2 = name;
    while (*p2){
	if (dotisspace (*p2))
	    p1 = p2+1;
	p2++;
    }
    return (FoldedEQ (p1, name2, name2l));
}

struct passwd  *
getpwwho (name)
char   *name; {
    register char *s, *d;
    ambigstate = -1;
    if (name == NULL)
    {
	endpwent();
	return(0);
    }
    s = d = name2;
    name1[0] = '\0';
    strcpy(name2, name);
    for(; *d; d++)
	if (dotisspace(*d)) {
	    *d = ' ';
	    s = d;
	}
    if(dotisspace(*s)){
	*s++ = 0;
	strcpy (name1, name2);
	strcpy (name2, s);
    }
    name1l = strlen (name1);
    name2l = strlen (name2);
    setpwent ();
    switch (scanpw (&passwd, line)) {
	case 0: 
	    return (0);
	case 1: 
	    return (&passwd);
	default: ;
    }
    auxgecos = *_gecos;
    while (1) {
	switch (scanpw (&auxpasswd, auxline)) {
	    case 0: 
		if (ambigstate == -1) {
		    _gecos = &auxgecos;
		    return & passwd;
		}
		return (struct passwd  *) - 1;
	    case 1: 
		return & auxpasswd;
	    case 2: 
		ambigstate = 0;
		break;
	}
    }
    /*  NOTREACHED */
}

struct passwd  *getpwambig () {
    if (ambigstate < 0)
	return 0;
    if (ambigstate++ == 0)
	setpwent();
    if (!scanpw (&passwd, line)) {
	ambigstate = -1;
	return 0;
    }
    return & passwd;
}

static FoldedEQ(s1,s2,len)
register char *s1,*s2;
register len; {
	while(--len>=0 && *s1 && (isupper(*s1) ? tolower(*s1) : *s1)
			      == (isupper(*s2) ? tolower(*s2) : *s2))
		s1++, s2++;
	return len<0 || *s1==0 && *s2==0;
}


