/*
 * getfn v0.5.3
 *
 * Alan Ford <ajf101@ecs.soton.ac.uk> for CSLib 04/09/2002
 *
 * Output suitable for use for address book queries in mutt. Quicker than 
 * using the Perl version of this I first wrote.
 *
 * ChangeLog:
 * 0.1 04/09/2002 - Initial Release
 * 0.2 17/09/2002 - Offers YP Search capability
 * 0.2.1 16/02/2003 - Fix for commas in gecos field; multiple NIS searches
 * 0.2.2 22/03/2003 - Improved searching (only if in pw_name || pw_gecos)
 * 0.2.3 22/06/2003 & 11/08/2003 - Ignore case (-i) option added
 * 0.3 17/09/2002 - Non-NIS (getpwent) version. Pretty slow, disregarded.
 * 0.5 16/02/2003 - Initial attempt at merging stuff together.
 * 0.5.1 28/03/2003 - Maybe better than last one!
 * 0.5.2 02/04/2003 - Better domain handling
 * 0.5.3 11/08/2003 - Ignore case (-i) option added
 *
 * Compile: gcc -o getfn53 getfn53.c -lnsl /usr/lib/librpcsvc.a
 * Options:
 * -DNO_NIS for no NIS support (then the -lnsl above is also not required)
 * -DDOMAIN="domain.dom" to set custom domain
 */
 
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <pwd.h>
#include <sys/types.h>
#include <unistd.h>
#include <netdb.h>
#ifndef NO_NIS
#include <rpcsvc/ypclnt.h>
#include <rpcsvc/yp_prot.h>
#include <rpc/rpc.h>
#endif

#ifndef DOMAIN
#define DOMAIN "ecs.soton.ac.uk"
#endif

static char *search;
static int ignorecase=0;
char *domain;

void printaddr (char *u, char *fn) {
	char *comma = strchr(fn, ',');
	if (comma)
		*comma = '\0';
	printf("%s@%s\t%s\n", u, domain, fn);
}

void strlow (char *s) {
	for (;*s != '\0';s++)
		*s = tolower(*s);
}

static int searchandprint (int status, char *inkey, int inkeylen, char *inval, int invallen, char *indata __attribute__ ((unused))) {
	struct passwd *sp_pw;
	char *name, *gecos;

	if (status != 1)
		return status;

	if (ignorecase)
		strlow(inval);

	if (inkeylen > 0 && strstr(inval, search)) {
		sp_pw = getpwnam(inkey);
		name = strdup(sp_pw->pw_name);
		gecos = strdup(sp_pw->pw_gecos);

		if (ignorecase) {
			strlow(name);
			strlow(gecos);
		}
		
		if (strstr(name, search) || strstr(gecos, search))
			printaddr(sp_pw->pw_name, sp_pw->pw_gecos);
	}
	return 0;
}

int main(int argc, char *argv[])
{
	int i=1, minargs=2;
	struct passwd *pw;
	struct hostent *hp;
	char name[128];
	char *p;
	char *domainname = NULL;
	char *user, *uname, *gecos;

	if (argv[i] && !strcmp(argv[i], "-i")) {
		ignorecase = 1;
		minargs++;
		i++;
	}

	if (argc < minargs)
		printf("Too Few Arguments.\n\n");
	if (argc < minargs || strstr(argv[i], "-help")) {
		printf("getfn 0.5.3 (2003-08-11)\nUsage:\t%s [-i] user [...]\nLooks up the full name of user.\n\n\t-i\tIgnore case in searching.\n\nReport bugs to <ajf101@ecs.soton.ac.uk>\n", argv[0]);
		exit(1);
	}

	gethostname(name, 128);
	hp = gethostbyname(name);
	if (p = strchr(hp->h_name, '.'))
		domain = ++p;
	else
		domain = DOMAIN;

	printf("Querying passwd file...\n");

#ifndef NO_NIS
	yp_get_default_domain(&domainname);
#endif

	for (;i<argc;i++) {
		char *at;
		user = argv[i];
		at = strchr(user, '@');
		if (at) {
			*at = '\0';
			domain = ++at;
		}

		pw = getpwnam(user);
		if (pw)
			printaddr(user, pw->pw_gecos);
#ifndef NO_NIS
		else if (!domainname) {
#else
		else {
#endif
			while (pw = getpwent()) {
				uname = strdup(pw->pw_name);
				gecos = strdup(pw->pw_gecos);
				if (ignorecase) {
					strlow(uname);
					strlow(gecos);
					strlow(user);
				}
				if (strstr(uname, user) || strstr(gecos, user))
					printaddr(pw->pw_name, pw->pw_gecos);
			}
#ifndef NO_NIS
		} else {
			struct ypall_callback ypcb;
			int res;
			search = user;
			if (ignorecase)
				strlow(search);
			ypcb.foreach = searchandprint;
			ypcb.data = NULL;
			res = yp_all(domainname, "passwd.byname", &ypcb);
#endif
		}
	}
}

