xref: /csrg-svn/usr.bin/finger/finger.c (revision 35627)
121554Sdist /*
2*35627Sbostic  * Copyright (c) 1980 The Regents of the University of California.
3*35627Sbostic  * All rights reserved.
4*35627Sbostic  *
5*35627Sbostic  * Redistribution and use in source and binary forms are permitted
6*35627Sbostic  * provided that the above copyright notice and this paragraph are
7*35627Sbostic  * duplicated in all such forms and that any documentation,
8*35627Sbostic  * advertising materials, and other materials related to such
9*35627Sbostic  * distribution and use acknowledge that the software was developed
10*35627Sbostic  * by the University of California, Berkeley.  The name of the
11*35627Sbostic  * University may not be used to endorse or promote products derived
12*35627Sbostic  * from this software without specific prior written permission.
13*35627Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14*35627Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*35627Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1621554Sdist  */
1721554Sdist 
1813619Ssam #ifndef lint
1921554Sdist char copyright[] =
20*35627Sbostic "@(#) Copyright (c) 1980 The Regents of the University of California.\n\
2121554Sdist  All rights reserved.\n";
22*35627Sbostic #endif /* not lint */
231014Sbill 
2421554Sdist #ifndef lint
25*35627Sbostic static char sccsid[] = "@(#)finger.c	5.11 (Berkeley) 09/20/88";
26*35627Sbostic #endif /* not lint */
2721554Sdist 
2818606Sedward /*
2918606Sedward  * This is a finger program.  It prints out useful information about users
3018606Sedward  * by digging it up from various system files.  It is not very portable
3118606Sedward  * because the most useful parts of the information (the full user name,
3218606Sedward  * office, and phone numbers) are all stored in the VAX-unused gecos field
3318606Sedward  * of /etc/passwd, which, unfortunately, other UNIXes use for other things.
341014Sbill  *
3518606Sedward  * There are three output formats, all of which give login name, teletype
3618606Sedward  * line number, and login time.  The short output format is reminiscent
3718606Sedward  * of finger on ITS, and gives one line of information per user containing
3818606Sedward  * in addition to the minimum basic requirements (MBR), the full name of
3918606Sedward  * the user, his idle time and office location and phone number.  The
4018606Sedward  * quick style output is UNIX who-like, giving only name, teletype and
4118606Sedward  * login time.  Finally, the long style output give the same information
4218606Sedward  * as the short (in more legible format), the home directory and shell
4318606Sedward  * of the user, and, if it exits, a copy of the file .plan in the users
4418606Sedward  * home directory.  Finger may be called with or without a list of people
4518606Sedward  * to finger -- if no list is given, all the people currently logged in
4618606Sedward  * are fingered.
471014Sbill  *
4818606Sedward  * The program is validly called by one of the following:
491014Sbill  *
501014Sbill  *	finger			{short form list of users}
511014Sbill  *	finger -l		{long form list of users}
521014Sbill  *	finger -b		{briefer long form list of users}
531014Sbill  *	finger -q		{quick list of users}
541014Sbill  *	finger -i		{quick list of users with idle times}
551014Sbill  *	finger namelist		{long format list of specified users}
561014Sbill  *	finger -s namelist	{short format list of specified users}
571014Sbill  *	finger -w namelist	{narrow short format list of specified users}
581014Sbill  *
5918606Sedward  * where 'namelist' is a list of users login names.
6018606Sedward  * The other options can all be given after one '-', or each can have its
6118606Sedward  * own '-'.  The -f option disables the printing of headers for short and
6218606Sedward  * quick outputs.  The -b option briefens long format outputs.  The -p
6318606Sedward  * option turns off plans for long format outputs.
641014Sbill  */
651014Sbill 
6618606Sedward #include <sys/types.h>
6718606Sedward #include <sys/stat.h>
6818606Sedward #include <utmp.h>
6918606Sedward #include <sys/signal.h>
7018606Sedward #include <pwd.h>
7118606Sedward #include <stdio.h>
7218606Sedward #include <lastlog.h>
7318606Sedward #include <ctype.h>
7418606Sedward #include <sys/time.h>
7518606Sedward #include <sys/socket.h>
7618606Sedward #include <netinet/in.h>
7718606Sedward #include <netdb.h>
781014Sbill 
7918606Sedward #define ASTERISK	'*'		/* ignore this in real name */
8018606Sedward #define COMMA		','		/* separator in pw_gecos field */
8118606Sedward #define COMMAND		'-'		/* command line flag char */
8218606Sedward #define CORY		'C'		/* cory hall office */
8318606Sedward #define EVANS		'E'		/* evans hall office */
8418606Sedward #define SAMENAME	'&'		/* repeat login name in real name */
8526869Smckusick #define TALKABLE	0220		/* tty is writable if 220 mode */
861014Sbill 
8718606Sedward struct utmp user;
8818606Sedward #define NMAX sizeof(user.ut_name)
8918606Sedward #define LMAX sizeof(user.ut_line)
9018606Sedward #define HMAX sizeof(user.ut_host)
911014Sbill 
9218606Sedward struct person {			/* one for each person fingered */
9318606Sedward 	char *name;			/* name */
9418606Sedward 	char tty[LMAX+1];		/* null terminated tty line */
9518606Sedward 	char host[HMAX+1];		/* null terminated remote host name */
9618606Sedward 	long loginat;			/* time of (last) login */
9718606Sedward 	long idletime;			/* how long idle (if logged in) */
9818606Sedward 	char *realname;			/* pointer to full name */
9918606Sedward 	char *office;			/* pointer to office name */
10018606Sedward 	char *officephone;		/* pointer to office phone no. */
10118606Sedward 	char *homephone;		/* pointer to home phone no. */
10218606Sedward 	char *random;			/* for any random stuff in pw_gecos */
10318606Sedward 	struct passwd *pwd;		/* structure of /etc/passwd stuff */
10418606Sedward 	char loggedin;			/* person is logged in */
10518606Sedward 	char writable;			/* tty is writable */
10618606Sedward 	char original;			/* this is not a duplicate entry */
10718606Sedward 	struct person *link;		/* link to next person */
1081014Sbill };
1091014Sbill 
11018606Sedward char LASTLOG[] = "/usr/adm/lastlog";	/* last login info */
11118606Sedward char USERLOG[] = "/etc/utmp";		/* who is logged in */
11218606Sedward char PLAN[] = "/.plan";			/* what plan file is */
11318606Sedward char PROJ[] = "/.project";		/* what project file */
11418606Sedward 
11518606Sedward int unbrief = 1;			/* -b option default */
11618606Sedward int header = 1;				/* -f option default */
11718606Sedward int hack = 1;				/* -h option default */
11818606Sedward int idle = 0;				/* -i option default */
11918606Sedward int large = 0;				/* -l option default */
12018606Sedward int match = 1;				/* -m option default */
12118606Sedward int plan = 1;				/* -p option default */
12218606Sedward int unquick = 1;			/* -q option default */
12318606Sedward int small = 0;				/* -s option default */
12418606Sedward int wide = 1;				/* -w option default */
1251014Sbill 
12618606Sedward int unshort;
12718606Sedward int lf;					/* LASTLOG file descriptor */
12818606Sedward struct person *person1;			/* list of people */
12918606Sedward long tloc;				/* current time */
1301014Sbill 
13118606Sedward struct passwd *pwdcopy();
13218606Sedward char *strcpy();
13318606Sedward char *malloc();
13418606Sedward char *ctime();
1351014Sbill 
13618606Sedward main(argc, argv)
13718606Sedward 	int argc;
13818606Sedward 	register char **argv;
13918606Sedward {
14018606Sedward 	FILE *fp;
14118606Sedward 	register char *s;
1421014Sbill 
14318606Sedward 	/* parse command line for (optional) arguments */
14418606Sedward 	while (*++argv && **argv == COMMAND)
14518606Sedward 		for (s = *argv + 1; *s; s++)
14618606Sedward 			switch (*s) {
14718606Sedward 			case 'b':
14818606Sedward 				unbrief = 0;
14918606Sedward 				break;
15018606Sedward 			case 'f':
15118606Sedward 				header = 0;
15218606Sedward 				break;
15318606Sedward 			case 'h':
15418606Sedward 				hack = 0;
15518606Sedward 				break;
15618606Sedward 			case 'i':
15718606Sedward 				idle = 1;
15818606Sedward 				unquick = 0;
15918606Sedward 				break;
16018606Sedward 			case 'l':
16118606Sedward 				large = 1;
16218606Sedward 				break;
16318606Sedward 			case 'm':
16418606Sedward 				match = 0;
16518606Sedward 				break;
16618606Sedward 			case 'p':
16718606Sedward 				plan = 0;
16818606Sedward 				break;
16918606Sedward 			case 'q':
17018606Sedward 				unquick = 0;
17118606Sedward 				break;
17218606Sedward 			case 's':
17318606Sedward 				small = 1;
17418606Sedward 				break;
17518606Sedward 			case 'w':
17618606Sedward 				wide = 0;
17718606Sedward 				break;
17818606Sedward 			default:
17918606Sedward 				fprintf(stderr, "Usage: finger [-bfhilmpqsw] [login1 [login2 ...] ]\n");
18018606Sedward 				exit(1);
18118606Sedward 			}
18218606Sedward 	if (unquick || idle)
18318606Sedward 		time(&tloc);
18418606Sedward 	/*
18518606Sedward 	 * *argv == 0 means no names given
18618606Sedward 	 */
18718606Sedward 	if (*argv == 0)
18818606Sedward 		doall();
18918606Sedward 	else
19018606Sedward 		donames(argv);
19124461Sedward 	if (person1)
19224461Sedward 		print();
19318606Sedward 	exit(0);
19418606Sedward }
1951014Sbill 
19618606Sedward doall()
1971014Sbill {
19818606Sedward 	register struct person *p;
19918606Sedward 	register struct passwd *pw;
20018606Sedward 	int uf;
20118606Sedward 	char name[NMAX + 1];
2021014Sbill 
20318606Sedward 	unshort = large;
20418606Sedward 	if ((uf = open(USERLOG, 0)) < 0) {
20518606Sedward 		fprintf(stderr, "finger: error opening %s\n", USERLOG);
20618606Sedward 		exit(2);
2071014Sbill 	}
20818606Sedward 	if (unquick) {
20918606Sedward 		extern _pw_stayopen;
2101014Sbill 
2111014Sbill 		setpwent();
21218606Sedward 		_pw_stayopen = 1;
2131014Sbill 		fwopen();
21418606Sedward 	}
21518606Sedward 	while (read(uf, (char *)&user, sizeof user) == sizeof user) {
21618606Sedward 		if (user.ut_name[0] == 0)
21718606Sedward 			continue;
21818606Sedward 		if (person1 == 0)
21918606Sedward 			p = person1 = (struct person *) malloc(sizeof *p);
22018606Sedward 		else {
22118606Sedward 			p->link = (struct person *) malloc(sizeof *p);
2221014Sbill 			p = p->link;
2231014Sbill 		}
22418606Sedward 		bcopy(user.ut_name, name, NMAX);
22518606Sedward 		name[NMAX] = 0;
22618606Sedward 		bcopy(user.ut_line, p->tty, LMAX);
22718606Sedward 		p->tty[LMAX] = 0;
22818606Sedward 		bcopy(user.ut_host, p->host, HMAX);
22918606Sedward 		p->host[HMAX] = 0;
23018606Sedward 		p->loginat = user.ut_time;
23118606Sedward 		p->pwd = 0;
23218606Sedward 		p->loggedin = 1;
23318606Sedward 		if (unquick && (pw = getpwnam(name))) {
23418606Sedward 			p->pwd = pwdcopy(pw);
23518606Sedward 			decode(p);
23618606Sedward 			p->name = p->pwd->pw_name;
23718606Sedward 		} else
23818606Sedward 			p->name = strcpy(malloc(strlen(name) + 1), name);
23918606Sedward 	}
24018606Sedward 	if (unquick) {
2411014Sbill 		fwclose();
2421014Sbill 		endpwent();
2431014Sbill 	}
24418606Sedward 	close(uf);
24518606Sedward 	if (person1 == 0) {
24618606Sedward 		printf("No one logged on\n");
24724461Sedward 		return;
24818606Sedward 	}
24918606Sedward 	p->link = 0;
25018606Sedward }
2511014Sbill 
25218606Sedward donames(argv)
25318606Sedward 	char **argv;
25418606Sedward {
25518606Sedward 	register struct person *p;
25618606Sedward 	register struct passwd *pw;
25718606Sedward 	int uf;
2581014Sbill 
25918606Sedward 	/*
26018606Sedward 	 * get names from command line and check to see if they're
26118606Sedward 	 * logged in
26218606Sedward 	 */
26318606Sedward 	unshort = !small;
26418606Sedward 	for (; *argv != 0; argv++) {
26518606Sedward 		if (netfinger(*argv))
26618606Sedward 			continue;
26718606Sedward 		if (person1 == 0)
26818606Sedward 			p = person1 = (struct person *) malloc(sizeof *p);
26918606Sedward 		else {
27018606Sedward 			p->link = (struct person *) malloc(sizeof *p);
27118606Sedward 			p = p->link;
27216469Ssam 		}
27318606Sedward 		p->name = *argv;
2741014Sbill 		p->loggedin = 0;
27518606Sedward 		p->original = 1;
27618606Sedward 		p->pwd = 0;
27718606Sedward 	}
27824461Sedward 	if (person1 == 0)
27924461Sedward 		return;
28018606Sedward 	p->link = 0;
28118606Sedward 	/*
28218606Sedward 	 * if we are doing it, read /etc/passwd for the useful info
28318606Sedward 	 */
28418606Sedward 	if (unquick) {
28518606Sedward 		setpwent();
28618606Sedward 		if (!match) {
28718606Sedward 			extern _pw_stayopen;
2881014Sbill 
28918606Sedward 			_pw_stayopen = 1;
29018606Sedward 			for (p = person1; p != 0; p = p->link)
29118606Sedward 				if (pw = getpwnam(p->name))
29218606Sedward 					p->pwd = pwdcopy(pw);
29318606Sedward 		} else while ((pw = getpwent()) != 0) {
29418606Sedward 			for (p = person1; p != 0; p = p->link) {
29518606Sedward 				if (!p->original)
29618606Sedward 					continue;
29718606Sedward 				if (strcmp(p->name, pw->pw_name) != 0 &&
29818606Sedward 				    !matchcmp(pw->pw_gecos, pw->pw_name, p->name))
29918606Sedward 					continue;
30018606Sedward 				if (p->pwd == 0)
30118606Sedward 					p->pwd = pwdcopy(pw);
30218606Sedward 				else {
30318606Sedward 					struct person *new;
30418606Sedward 					/*
30518606Sedward 					 * handle multiple login names, insert
30618606Sedward 					 * new "duplicate" entry behind
30718606Sedward 					 */
30818606Sedward 					new = (struct person *)
30918606Sedward 						malloc(sizeof *new);
31018606Sedward 					new->pwd = pwdcopy(pw);
31118606Sedward 					new->name = p->name;
31218606Sedward 					new->original = 1;
31318606Sedward 					new->loggedin = 0;
31418606Sedward 					new->link = p->link;
31518606Sedward 					p->original = 0;
31618606Sedward 					p->link = new;
31718606Sedward 					p = new;
31818606Sedward 				}
3191014Sbill 			}
3201014Sbill 		}
3211014Sbill 		endpwent();
32218606Sedward 	}
32318606Sedward 	/* Now get login information */
32418606Sedward 	if ((uf = open(USERLOG, 0)) < 0) {
32518606Sedward 		fprintf(stderr, "finger: error opening %s\n", USERLOG);
32618606Sedward 		exit(2);
32718606Sedward 	}
32818606Sedward 	while (read(uf, (char *)&user, sizeof user) == sizeof user) {
32918606Sedward 		if (*user.ut_name == 0)
33018606Sedward 			continue;
33118606Sedward 		for (p = person1; p != 0; p = p->link) {
33218606Sedward 			if (p->loggedin == 2)
33318606Sedward 				continue;
33418606Sedward 			if (strncmp(p->pwd ? p->pwd->pw_name : p->name,
33518606Sedward 				    user.ut_name, NMAX) != 0)
33618606Sedward 				continue;
33718606Sedward 			if (p->loggedin == 0) {
33818606Sedward 				bcopy(user.ut_line, p->tty, LMAX);
33918606Sedward 				p->tty[LMAX] = 0;
34018606Sedward 				bcopy(user.ut_host, p->host, HMAX);
34118606Sedward 				p->host[HMAX] = 0;
34218606Sedward 				p->loginat = user.ut_time;
34318606Sedward 				p->loggedin = 1;
34418606Sedward 			} else {	/* p->loggedin == 1 */
34518606Sedward 				struct person *new;
34618606Sedward 				new = (struct person *) malloc(sizeof *new);
34718606Sedward 				new->name = p->name;
34818606Sedward 				bcopy(user.ut_line, new->tty, LMAX);
34918606Sedward 				new->tty[LMAX] = 0;
35018606Sedward 				bcopy(user.ut_host, new->host, HMAX);
35118606Sedward 				new->host[HMAX] = 0;
35218606Sedward 				new->loginat = user.ut_time;
35318606Sedward 				new->pwd = p->pwd;
35418606Sedward 				new->loggedin = 1;
35518606Sedward 				new->original = 0;
35618606Sedward 				new->link = p->link;
35718606Sedward 				p->loggedin = 2;
35818606Sedward 				p->link = new;
35918606Sedward 				p = new;
3601014Sbill 			}
3611014Sbill 		}
36218606Sedward 	}
36318606Sedward 	close(uf);
36418606Sedward 	if (unquick) {
3651014Sbill 		fwopen();
36618606Sedward 		for (p = person1; p != 0; p = p->link)
36718606Sedward 			decode(p);
3681014Sbill 		fwclose();
3691014Sbill 	}
37018606Sedward }
3711014Sbill 
37218606Sedward print()
37318606Sedward {
37418606Sedward 	register FILE *fp;
37518606Sedward 	register struct person *p;
37618606Sedward 	register char *s;
37718606Sedward 	register c;
3781014Sbill 
37918606Sedward 	/*
38018606Sedward 	 * print out what we got
38118606Sedward 	 */
38218606Sedward 	if (header) {
38318606Sedward 		if (unquick) {
38418606Sedward 			if (!unshort)
38518606Sedward 				if (wide)
38618606Sedward 					printf("Login       Name              TTY Idle    When            Office\n");
38718606Sedward 				else
38818606Sedward 					printf("Login    TTY Idle    When            Office\n");
38918606Sedward 		} else {
39018606Sedward 			printf("Login      TTY            When");
39118606Sedward 			if (idle)
39218606Sedward 				printf("             Idle");
39318606Sedward 			putchar('\n');
3941014Sbill 		}
39518606Sedward 	}
39618606Sedward 	for (p = person1; p != 0; p = p->link) {
39718606Sedward 		if (!unquick) {
39818606Sedward 			quickprint(p);
39918606Sedward 			continue;
4001014Sbill 		}
40118606Sedward 		if (!unshort) {
40218606Sedward 			shortprint(p);
40318606Sedward 			continue;
40418606Sedward 		}
40518606Sedward 		personprint(p);
40618606Sedward 		if (p->pwd != 0) {
40718606Sedward 			if (hack) {
40818606Sedward 				s = malloc(strlen(p->pwd->pw_dir) +
40918606Sedward 					sizeof PROJ);
41018606Sedward 				strcpy(s, p->pwd->pw_dir);
41118606Sedward 				strcat(s, PROJ);
41218606Sedward 				if ((fp = fopen(s, "r")) != 0) {
41318606Sedward 					printf("Project: ");
41418606Sedward 					while ((c = getc(fp)) != EOF) {
41518606Sedward 						if (c == '\n')
41618606Sedward 							break;
41725589Sbloom 						if (isprint(c) || isspace(c))
41825589Sbloom 							putchar(c);
41925589Sbloom 						else
42025589Sbloom 							putchar(c ^ 100);
42118606Sedward 					}
42218606Sedward 					fclose(fp);
42318606Sedward 					putchar('\n');
4241014Sbill 				}
42518606Sedward 				free(s);
4261014Sbill 			}
42718606Sedward 			if (plan) {
42818606Sedward 				s = malloc(strlen(p->pwd->pw_dir) +
42918606Sedward 					sizeof PLAN);
43018606Sedward 				strcpy(s, p->pwd->pw_dir);
43118606Sedward 				strcat(s, PLAN);
43218606Sedward 				if ((fp = fopen(s, "r")) == 0)
43318606Sedward 					printf("No Plan.\n");
43418606Sedward 				else {
43518606Sedward 					printf("Plan:\n");
43618606Sedward 					while ((c = getc(fp)) != EOF)
43725589Sbloom 						if (isprint(c) || isspace(c))
43825589Sbloom 							putchar(c);
43925589Sbloom 						else
44025589Sbloom 							putchar(c ^ 100);
44118606Sedward 					fclose(fp);
4421014Sbill 				}
44318606Sedward 				free(s);
4441014Sbill 			}
4451014Sbill 		}
44618606Sedward 		if (p->link != 0)
44718606Sedward 			putchar('\n');
44818606Sedward 	}
4491014Sbill }
4501014Sbill 
45118606Sedward /*
45218606Sedward  * Duplicate a pwd entry.
45318606Sedward  * Note: Only the useful things (what the program currently uses) are copied.
4541014Sbill  */
45518606Sedward struct passwd *
45618606Sedward pwdcopy(pfrom)
45718606Sedward 	register struct passwd *pfrom;
45818606Sedward {
45918606Sedward 	register struct passwd *pto;
4601014Sbill 
46118606Sedward 	pto = (struct passwd *) malloc(sizeof *pto);
46218606Sedward #define savestr(s) strcpy(malloc(strlen(s) + 1), s)
46318606Sedward 	pto->pw_name = savestr(pfrom->pw_name);
4641014Sbill 	pto->pw_uid = pfrom->pw_uid;
46518606Sedward 	pto->pw_gecos = savestr(pfrom->pw_gecos);
46618606Sedward 	pto->pw_dir = savestr(pfrom->pw_dir);
46718606Sedward 	pto->pw_shell = savestr(pfrom->pw_shell);
46818606Sedward #undef savestr
46918606Sedward 	return pto;
4701014Sbill }
4711014Sbill 
47218606Sedward /*
47318606Sedward  * print out information on quick format giving just name, tty, login time
47418606Sedward  * and idle time if idle is set.
4751014Sbill  */
47618606Sedward quickprint(pers)
47718606Sedward 	register struct person *pers;
4781014Sbill {
47918606Sedward 	printf("%-*.*s  ", NMAX, NMAX, pers->name);
48018606Sedward 	if (pers->loggedin) {
48118606Sedward 		if (idle) {
48218606Sedward 			findidle(pers);
48318606Sedward 			printf("%c%-*s %-16.16s", pers->writable ? ' ' : '*',
48418606Sedward 				LMAX, pers->tty, ctime(&pers->loginat));
48518606Sedward 			ltimeprint("   ", &pers->idletime, "");
48618606Sedward 		} else
48718606Sedward 			printf(" %-*s %-16.16s", LMAX,
48818606Sedward 				pers->tty, ctime(&pers->loginat));
48918606Sedward 		putchar('\n');
49018606Sedward 	} else
49118606Sedward 		printf("          Not Logged In\n");
4921014Sbill }
4931014Sbill 
49418606Sedward /*
49518606Sedward  * print out information in short format, giving login name, full name,
49618606Sedward  * tty, idle time, login time, office location and phone.
4971014Sbill  */
49818606Sedward shortprint(pers)
49918606Sedward 	register struct person *pers;
5001014Sbill {
50118606Sedward 	char *p;
50218606Sedward 	char dialup;
5031014Sbill 
50418606Sedward 	if (pers->pwd == 0) {
50518606Sedward 		printf("%-15s       ???\n", pers->name);
50618606Sedward 		return;
5071014Sbill 	}
50818606Sedward 	printf("%-*s", NMAX, pers->pwd->pw_name);
5091014Sbill 	dialup = 0;
51018606Sedward 	if (wide) {
51118606Sedward 		if (pers->realname)
51218606Sedward 			printf(" %-20.20s", pers->realname);
51318606Sedward 		else
51418606Sedward 			printf("        ???          ");
5151014Sbill 	}
51618606Sedward 	putchar(' ');
51718606Sedward 	if (pers->loggedin && !pers->writable)
51818606Sedward 		putchar('*');
51918606Sedward 	else
52018606Sedward 		putchar(' ');
52118606Sedward 	if (*pers->tty) {
52218606Sedward 		if (pers->tty[0] == 't' && pers->tty[1] == 't' &&
52318606Sedward 		    pers->tty[2] == 'y') {
52418606Sedward 			if (pers->tty[3] == 'd' && pers->loggedin)
52518606Sedward 				dialup = 1;
52618606Sedward 			printf("%-2.2s ", pers->tty + 3);
52718606Sedward 		} else
52818606Sedward 			printf("%-2.2s ", pers->tty);
52918606Sedward 	} else
53018606Sedward 		printf("   ");
53118606Sedward 	p = ctime(&pers->loginat);
53218606Sedward 	if (pers->loggedin) {
53318606Sedward 		stimeprint(&pers->idletime);
53418606Sedward 		printf(" %3.3s %-5.5s ", p, p + 11);
53518606Sedward 	} else if (pers->loginat == 0)
53618606Sedward 		printf(" < .  .  .  . >");
5378842Smckusick 	else if (tloc - pers->loginat >= 180 * 24 * 60 * 60)
53818606Sedward 		printf(" <%-6.6s, %-4.4s>", p + 4, p + 20);
5398842Smckusick 	else
54018606Sedward 		printf(" <%-12.12s>", p + 4);
54118606Sedward 	if (dialup && pers->homephone)
54218606Sedward 		printf(" %20s", pers->homephone);
54318606Sedward 	else {
54418606Sedward 		if (pers->office)
54518606Sedward 			printf(" %-11.11s", pers->office);
54618606Sedward 		else if (pers->officephone || pers->homephone)
54718606Sedward 			printf("            ");
54818606Sedward 		if (pers->officephone)
54918606Sedward 			printf(" %s", pers->officephone);
55018606Sedward 		else if (pers->homephone)
55118606Sedward 			printf(" %s", pers->homephone);
5521014Sbill 	}
55318606Sedward 	putchar('\n');
5541014Sbill }
5551014Sbill 
55618606Sedward /*
55718606Sedward  * print out a person in long format giving all possible information.
55818606Sedward  * directory and shell are inhibited if unbrief is clear.
5591014Sbill  */
56018606Sedward personprint(pers)
56118606Sedward 	register struct person *pers;
5621014Sbill {
56318606Sedward 	if (pers->pwd == 0) {
56418606Sedward 		printf("Login name: %-10s\t\t\tIn real life: ???\n",
56518606Sedward 			pers->name);
56618606Sedward 		return;
5671014Sbill 	}
56818606Sedward 	printf("Login name: %-10s", pers->pwd->pw_name);
56918606Sedward 	if (pers->loggedin && !pers->writable)
57018606Sedward 		printf("	(messages off)	");
57118606Sedward 	else
57218606Sedward 		printf("			");
57318606Sedward 	if (pers->realname)
57418606Sedward 		printf("In real life: %s", pers->realname);
57518606Sedward 	if (pers->office) {
57618606Sedward 		printf("\nOffice: %-.11s", pers->office);
57718606Sedward 		if (pers->officephone) {
57818606Sedward 			printf(", %s", pers->officephone);
57918606Sedward 			if (pers->homephone)
58018606Sedward 				printf("\t\tHome phone: %s", pers->homephone);
58118606Sedward 			else if (pers->random)
58218606Sedward 				printf("\t\t%s", pers->random);
58318606Sedward 		} else
58418606Sedward 			if (pers->homephone)
58518606Sedward 				printf("\t\t\tHome phone: %s", pers->homephone);
58618606Sedward 			else if (pers->random)
58718606Sedward 				printf("\t\t\t%s", pers->random);
58818606Sedward 	} else if (pers->officephone) {
58918606Sedward 		printf("\nPhone: %s", pers->officephone);
59018606Sedward 		if (pers->homephone)
59118606Sedward 			printf(", %s", pers->homephone);
59218606Sedward 		if (pers->random)
59318606Sedward 			printf(", %s", pers->random);
59418606Sedward 	} else if (pers->homephone) {
59518606Sedward 		printf("\nPhone: %s", pers->homephone);
59618606Sedward 		if (pers->random)
59718606Sedward 			printf(", %s", pers->random);
59818606Sedward 	} else if (pers->random)
59918606Sedward 		printf("\n%s", pers->random);
60018606Sedward 	if (unbrief) {
60118606Sedward 		printf("\nDirectory: %-25s", pers->pwd->pw_dir);
60218606Sedward 		if (*pers->pwd->pw_shell)
60318606Sedward 			printf("\tShell: %-s", pers->pwd->pw_shell);
6041014Sbill 	}
60518606Sedward 	if (pers->loggedin) {
60618606Sedward 		register char *ep = ctime(&pers->loginat);
60718606Sedward 		if (*pers->host) {
60818606Sedward 			printf("\nOn since %15.15s on %s from %s",
60918606Sedward 				&ep[4], pers->tty, pers->host);
61018606Sedward 			ltimeprint("\n", &pers->idletime, " Idle Time");
61118606Sedward 		} else {
61218606Sedward 			printf("\nOn since %15.15s on %-*s",
61318606Sedward 				&ep[4], LMAX, pers->tty);
61418606Sedward 			ltimeprint("\t", &pers->idletime, " Idle Time");
6151014Sbill 		}
61618606Sedward 	} else if (pers->loginat == 0)
61718606Sedward 		printf("\nNever logged in.");
6188842Smckusick 	else if (tloc - pers->loginat > 180 * 24 * 60 * 60) {
61918606Sedward 		register char *ep = ctime(&pers->loginat);
62018606Sedward 		printf("\nLast login %10.10s, %4.4s on %s",
62118606Sedward 			ep, ep+20, pers->tty);
62218606Sedward 		if (*pers->host)
62318606Sedward 			printf(" from %s", pers->host);
62418606Sedward 	} else {
62518606Sedward 		register char *ep = ctime(&pers->loginat);
62618606Sedward 		printf("\nLast login %16.16s on %s", ep, pers->tty);
62718606Sedward 		if (*pers->host)
62818606Sedward 			printf(" from %s", pers->host);
6298842Smckusick 	}
63018606Sedward 	putchar('\n');
6311014Sbill }
6321014Sbill 
6331014Sbill /*
6341014Sbill  *  very hacky section of code to format phone numbers.  filled with
6351014Sbill  *  magic constants like 4, 7 and 10.
6361014Sbill  */
63718606Sedward char *
63818606Sedward phone(s, len, alldigits)
63918606Sedward 	register char *s;
64018606Sedward 	int len;
64118606Sedward 	char alldigits;
6421014Sbill {
64318606Sedward 	char fonebuf[15];
64418606Sedward 	register char *p = fonebuf;
64518606Sedward 	register i;
6461014Sbill 
64718606Sedward 	if (!alldigits)
64818606Sedward 		return (strcpy(malloc(len + 1), s));
64918606Sedward 	switch (len) {
65018606Sedward 	case 4:
65118606Sedward 		*p++ = ' ';
65218606Sedward 		*p++ = 'x';
65318606Sedward 		*p++ = '2';
65418606Sedward 		*p++ = '-';
65518606Sedward 		for (i = 0; i < 4; i++)
65618606Sedward 			*p++ = *s++;
6571014Sbill 		break;
65824463Sbloom 	case 5:
65924463Sbloom 		*p++ = ' ';
66024463Sbloom 		*p++ = 'x';
66124463Sbloom 		*p++ = *s++;
66224463Sbloom 		*p++ = '-';
66324463Sbloom 		for (i = 0; i < 4; i++)
66424463Sbloom 			*p++ = *s++;
66524463Sbloom 		break;
66618606Sedward 	case 7:
66718606Sedward 		for (i = 0; i < 3; i++)
66818606Sedward 			*p++ = *s++;
66918606Sedward 		*p++ = '-';
67018606Sedward 		for (i = 0; i < 4; i++)
67118606Sedward 			*p++ = *s++;
6721014Sbill 		break;
67318606Sedward 	case 10:
67418606Sedward 		for (i = 0; i < 3; i++)
67518606Sedward 			*p++ = *s++;
67618606Sedward 		*p++ = '-';
67718606Sedward 		for (i = 0; i < 3; i++)
67818606Sedward 			*p++ = *s++;
67918606Sedward 		*p++ = '-';
68018606Sedward 		for (i = 0; i < 4; i++)
68118606Sedward 			*p++ = *s++;
6821014Sbill 		break;
68318606Sedward 	case 0:
68418606Sedward 		return 0;
68518606Sedward 	default:
68618606Sedward 		return (strcpy(malloc(len + 1), s));
6871014Sbill 	}
68818606Sedward 	*p++ = 0;
68918606Sedward 	return (strcpy(malloc(p - fonebuf), fonebuf));
6901014Sbill }
6911014Sbill 
69218606Sedward /*
69318606Sedward  * decode the information in the gecos field of /etc/passwd
6941014Sbill  */
69518606Sedward decode(pers)
69618606Sedward 	register struct person *pers;
6971014Sbill {
69818606Sedward 	char buffer[256];
69918606Sedward 	register char *bp, *gp, *lp;
70018606Sedward 	int alldigits;
70118606Sedward 	int hasspace;
70218606Sedward 	int len;
7031014Sbill 
70418606Sedward 	pers->realname = 0;
70518606Sedward 	pers->office = 0;
70618606Sedward 	pers->officephone = 0;
70718606Sedward 	pers->homephone = 0;
70818606Sedward 	pers->random = 0;
70918606Sedward 	if (pers->pwd == 0)
71018606Sedward 		return;
71118606Sedward 	gp = pers->pwd->pw_gecos;
71218606Sedward 	bp = buffer;
71318606Sedward 	if (*gp == ASTERISK)
7141014Sbill 		gp++;
71518606Sedward 	while (*gp && *gp != COMMA)			/* name */
71618606Sedward 		if (*gp == SAMENAME) {
71718606Sedward 			lp = pers->pwd->pw_name;
71818606Sedward 			if (islower(*lp))
71918606Sedward 				*bp++ = toupper(*lp++);
72018606Sedward 			while (*bp++ = *lp++)
72118606Sedward 				;
72218606Sedward 			bp--;
72318606Sedward 			gp++;
72418606Sedward 		} else
72518606Sedward 			*bp++ = *gp++;
72618606Sedward 	*bp++ = 0;
72718606Sedward 	if ((len = bp - buffer) > 1)
72818606Sedward 		pers->realname = strcpy(malloc(len), buffer);
72918606Sedward 	if (*gp == COMMA) {				/* office */
73018606Sedward 		gp++;
73118606Sedward 		hasspace = 0;
73218606Sedward 		bp = buffer;
73318606Sedward 		while (*gp && *gp != COMMA) {
73418606Sedward 			*bp = *gp++;
73518606Sedward 			if (*bp == ' ')
73618606Sedward 				hasspace = 1;
73718606Sedward 			/* leave 5 for Cory and Evans expansion */
73818606Sedward 			if (bp < buffer + sizeof buffer - 6)
73918606Sedward 				bp++;
7401014Sbill 		}
74118606Sedward 		*bp = 0;
74218606Sedward 		len = bp - buffer;
74318606Sedward 		bp--;			/* point to last character */
74418606Sedward 		if (hasspace || len == 0)
74518606Sedward 			len++;
74618606Sedward 		else if (*bp == CORY) {
74718606Sedward 			strcpy(bp, " Cory");
74818606Sedward 			len += 5;
74918606Sedward 		} else if (*bp == EVANS) {
75018606Sedward 			strcpy(bp, " Evans");
75118606Sedward 			len += 6;
75218606Sedward 		} else
75318606Sedward 			len++;
75418606Sedward 		if (len > 1)
75518606Sedward 			pers->office = strcpy(malloc(len), buffer);
75618606Sedward 	}
75718606Sedward 	if (*gp == COMMA) {				/* office phone */
75818606Sedward 		gp++;
75918606Sedward 		bp = buffer;
76018606Sedward 		alldigits = 1;
76118606Sedward 		while (*gp && *gp != COMMA) {
76218606Sedward 			*bp = *gp++;
76318606Sedward 			if (!isdigit(*bp))
76418606Sedward 				alldigits = 0;
76518606Sedward 			if (bp < buffer + sizeof buffer - 1)
76618606Sedward 				bp++;
7671014Sbill 		}
76818606Sedward 		*bp = 0;
76918606Sedward 		pers->officephone = phone(buffer, bp - buffer, alldigits);
77018606Sedward 	}
77118606Sedward 	if (*gp == COMMA) {				/* home phone */
7721014Sbill 		gp++;
77318606Sedward 		bp = buffer;
7741014Sbill 		alldigits = 1;
77518606Sedward 		while (*gp && *gp != COMMA) {
7761014Sbill 			*bp = *gp++;
77718606Sedward 			if (!isdigit(*bp))
77818606Sedward 				alldigits = 0;
77918606Sedward 			if (bp < buffer + sizeof buffer - 1)
7801014Sbill 				bp++;
7811014Sbill 		}
78218606Sedward 		*bp = 0;
78318606Sedward 		pers->homephone = phone(buffer, bp - buffer, alldigits);
7841014Sbill 	}
78518606Sedward 	if (pers->loggedin)
78618606Sedward 		findidle(pers);
78718606Sedward 	else
78818606Sedward 		findwhen(pers);
7891014Sbill }
7901014Sbill 
79118606Sedward /*
79218606Sedward  * find the last log in of a user by checking the LASTLOG file.
79318606Sedward  * the entry is indexed by the uid, so this can only be done if
79418606Sedward  * the uid is known (which it isn't in quick mode)
7951014Sbill  */
7961014Sbill 
7971014Sbill fwopen()
7981014Sbill {
79918606Sedward 	if ((lf = open(LASTLOG, 0)) < 0)
80018606Sedward 		fprintf(stderr, "finger: %s open error\n", LASTLOG);
8011014Sbill }
8021014Sbill 
80318606Sedward findwhen(pers)
80418606Sedward 	register struct person *pers;
8051014Sbill {
80618606Sedward 	struct lastlog ll;
80718606Sedward 	int i;
8081014Sbill 
80918606Sedward 	if (lf >= 0) {
81018606Sedward 		lseek(lf, (long)pers->pwd->pw_uid * sizeof ll, 0);
81118606Sedward 		if ((i = read(lf, (char *)&ll, sizeof ll)) == sizeof ll) {
81218606Sedward 			bcopy(ll.ll_line, pers->tty, LMAX);
81318606Sedward 			pers->tty[LMAX] = 0;
81418606Sedward 			bcopy(ll.ll_host, pers->host, HMAX);
81518606Sedward 			pers->host[HMAX] = 0;
81618606Sedward 			pers->loginat = ll.ll_time;
81718606Sedward 		} else {
81818606Sedward 			if (i != 0)
81918606Sedward 				fprintf(stderr, "finger: %s read error\n",
82018606Sedward 					LASTLOG);
82118606Sedward 			pers->tty[0] = 0;
82218606Sedward 			pers->host[0] = 0;
82318606Sedward 			pers->loginat = 0L;
82418606Sedward 		}
82518606Sedward 	} else {
82618606Sedward 		pers->tty[0] = 0;
82718606Sedward 		pers->host[0] = 0;
8281014Sbill 		pers->loginat = 0L;
8291014Sbill 	}
8301014Sbill }
8311014Sbill 
8321014Sbill fwclose()
8331014Sbill {
83418606Sedward 	if (lf >= 0)
83518606Sedward 		close(lf);
8361014Sbill }
8371014Sbill 
83818606Sedward /*
83918606Sedward  * find the idle time of a user by doing a stat on /dev/tty??,
84018606Sedward  * where tty?? has been gotten from USERLOG, supposedly.
8411014Sbill  */
84218606Sedward findidle(pers)
84318606Sedward 	register struct person *pers;
8441014Sbill {
84518606Sedward 	struct stat ttystatus;
84618606Sedward 	static char buffer[20] = "/dev/";
84718606Sedward 	long t;
84818606Sedward #define TTYLEN 5
8491014Sbill 
85018606Sedward 	strcpy(buffer + TTYLEN, pers->tty);
85118606Sedward 	buffer[TTYLEN+LMAX] = 0;
85218606Sedward 	if (stat(buffer, &ttystatus) < 0) {
85318606Sedward 		fprintf(stderr, "finger: Can't stat %s\n", buffer);
85418606Sedward 		exit(4);
85518606Sedward 	}
85618606Sedward 	time(&t);
85718606Sedward 	if (t < ttystatus.st_atime)
8581014Sbill 		pers->idletime = 0L;
85918606Sedward 	else
86018606Sedward 		pers->idletime = t - ttystatus.st_atime;
86118606Sedward 	pers->writable = (ttystatus.st_mode & TALKABLE) == TALKABLE;
8621014Sbill }
8631014Sbill 
86418606Sedward /*
86518606Sedward  * print idle time in short format; this program always prints 4 characters;
86618606Sedward  * if the idle time is zero, it prints 4 blanks.
8671014Sbill  */
86818606Sedward stimeprint(dt)
86918606Sedward 	long *dt;
8701014Sbill {
87118606Sedward 	register struct tm *delta;
8721014Sbill 
87318606Sedward 	delta = gmtime(dt);
87418606Sedward 	if (delta->tm_yday == 0)
87518606Sedward 		if (delta->tm_hour == 0)
87618606Sedward 			if (delta->tm_min == 0)
87718606Sedward 				printf("    ");
87818606Sedward 			else
87918606Sedward 				printf("  %2d", delta->tm_min);
88018606Sedward 		else
88118606Sedward 			if (delta->tm_hour >= 10)
88218606Sedward 				printf("%3d:", delta->tm_hour);
88318606Sedward 			else
88418606Sedward 				printf("%1d:%02d",
88518606Sedward 					delta->tm_hour, delta->tm_min);
88618606Sedward 	else
88718606Sedward 		printf("%3dd", delta->tm_yday);
8881014Sbill }
8891014Sbill 
89018606Sedward /*
89118606Sedward  * print idle time in long format with care being taken not to pluralize
89218606Sedward  * 1 minutes or 1 hours or 1 days.
89318606Sedward  * print "prefix" first.
8941014Sbill  */
89518606Sedward ltimeprint(before, dt, after)
89618606Sedward 	long *dt;
89718606Sedward 	char *before, *after;
8981014Sbill {
89918606Sedward 	register struct tm *delta;
9001014Sbill 
90118606Sedward 	delta = gmtime(dt);
90218606Sedward 	if (delta->tm_yday == 0 && delta->tm_hour == 0 && delta->tm_min == 0 &&
90318606Sedward 	    delta->tm_sec <= 10)
90418606Sedward 		return (0);
90518606Sedward 	printf("%s", before);
90618606Sedward 	if (delta->tm_yday >= 10)
90718606Sedward 		printf("%d days", delta->tm_yday);
90818606Sedward 	else if (delta->tm_yday > 0)
90918606Sedward 		printf("%d day%s %d hour%s",
91018606Sedward 			delta->tm_yday, delta->tm_yday == 1 ? "" : "s",
91118606Sedward 			delta->tm_hour, delta->tm_hour == 1 ? "" : "s");
91218606Sedward 	else
91318606Sedward 		if (delta->tm_hour >= 10)
91418606Sedward 			printf("%d hours", delta->tm_hour);
91518606Sedward 		else if (delta->tm_hour > 0)
91618606Sedward 			printf("%d hour%s %d minute%s",
91718606Sedward 				delta->tm_hour, delta->tm_hour == 1 ? "" : "s",
91818606Sedward 				delta->tm_min, delta->tm_min == 1 ? "" : "s");
91918606Sedward 		else
92018606Sedward 			if (delta->tm_min >= 10)
92118606Sedward 				printf("%2d minutes", delta->tm_min);
92218606Sedward 			else if (delta->tm_min == 0)
92318606Sedward 				printf("%2d seconds", delta->tm_sec);
92418606Sedward 			else
92518606Sedward 				printf("%d minute%s %d second%s",
92618606Sedward 					delta->tm_min,
92718606Sedward 					delta->tm_min == 1 ? "" : "s",
92818606Sedward 					delta->tm_sec,
92918606Sedward 					delta->tm_sec == 1 ? "" : "s");
93018606Sedward 	printf("%s", after);
9311014Sbill }
9321014Sbill 
93318606Sedward matchcmp(gname, login, given)
93418606Sedward 	register char *gname;
93518606Sedward 	char *login;
93618606Sedward 	char *given;
9371014Sbill {
93818606Sedward 	char buffer[100];
93918606Sedward 	register char *bp, *lp;
94018606Sedward 	register c;
9411014Sbill 
94218606Sedward 	if (*gname == ASTERISK)
94318606Sedward 		gname++;
94418606Sedward 	lp = 0;
94518606Sedward 	bp = buffer;
94618606Sedward 	for (;;)
94718606Sedward 		switch (c = *gname++) {
94818606Sedward 		case SAMENAME:
94918606Sedward 			for (lp = login; bp < buffer + sizeof buffer
95018606Sedward 					 && (*bp++ = *lp++);)
95118606Sedward 				;
95218606Sedward 			bp--;
95318606Sedward 			break;
95418606Sedward 		case ' ':
95518606Sedward 		case COMMA:
95618606Sedward 		case '\0':
95718606Sedward 			*bp = 0;
95818606Sedward 			if (namecmp(buffer, given))
95918606Sedward 				return (1);
96018606Sedward 			if (c == COMMA || c == 0)
96118606Sedward 				return (0);
96218606Sedward 			bp = buffer;
96318606Sedward 			break;
96418606Sedward 		default:
96518606Sedward 			if (bp < buffer + sizeof buffer)
96618606Sedward 				*bp++ = c;
9671014Sbill 		}
96818606Sedward 	/*NOTREACHED*/
9691014Sbill }
9701014Sbill 
97118606Sedward namecmp(name1, name2)
97218606Sedward 	register char *name1, *name2;
9731014Sbill {
97418606Sedward 	register c1, c2;
9751014Sbill 
97618606Sedward 	for (;;) {
97718606Sedward 		c1 = *name1++;
97818606Sedward 		if (islower(c1))
97918606Sedward 			c1 = toupper(c1);
98018606Sedward 		c2 = *name2++;
98118606Sedward 		if (islower(c2))
98218606Sedward 			c2 = toupper(c2);
98318606Sedward 		if (c1 != c2)
98418606Sedward 			break;
98518606Sedward 		if (c1 == 0)
98618606Sedward 			return (1);
9871014Sbill 	}
98818606Sedward 	if (!c1) {
98918606Sedward 		for (name2--; isdigit(*name2); name2++)
99018606Sedward 			;
99118606Sedward 		if (*name2 == 0)
99218606Sedward 			return (1);
99318606Sedward 	} else if (!c2) {
99418606Sedward 		for (name1--; isdigit(*name1); name1++)
99518606Sedward 			;
99618606Sedward 		if (*name2 == 0)
99718606Sedward 			return (1);
9981014Sbill 	}
99918606Sedward 	return (0);
10001014Sbill }
10011014Sbill 
100216469Ssam netfinger(name)
100318606Sedward 	char *name;
100416469Ssam {
100516469Ssam 	char *host;
100616469Ssam 	char fname[100];
100716469Ssam 	struct hostent *hp;
100816469Ssam 	struct servent *sp;
100918606Sedward 	struct sockaddr_in sin;
101016469Ssam 	int s;
101116469Ssam 	char *rindex();
101216469Ssam 	register FILE *f;
101316469Ssam 	register int c;
101416469Ssam 	register int lastc;
101516469Ssam 
101616469Ssam 	if (name == NULL)
101718606Sedward 		return (0);
101816469Ssam 	host = rindex(name, '@');
101916469Ssam 	if (host == NULL)
102018606Sedward 		return (0);
102116469Ssam 	*host++ = 0;
102216469Ssam 	hp = gethostbyname(host);
102316469Ssam 	if (hp == NULL) {
102416469Ssam 		static struct hostent def;
102516469Ssam 		static struct in_addr defaddr;
102625240Sbloom 		static char *alist[1];
102716469Ssam 		static char namebuf[128];
102816469Ssam 		int inet_addr();
102916469Ssam 
103016469Ssam 		defaddr.s_addr = inet_addr(host);
103116469Ssam 		if (defaddr.s_addr == -1) {
103216469Ssam 			printf("unknown host: %s\n", host);
103318606Sedward 			return (1);
103416469Ssam 		}
103516469Ssam 		strcpy(namebuf, host);
103616469Ssam 		def.h_name = namebuf;
103725239Ssam 		def.h_addr_list = alist, def.h_addr = (char *)&defaddr;
103816469Ssam 		def.h_length = sizeof (struct in_addr);
103916469Ssam 		def.h_addrtype = AF_INET;
104016469Ssam 		def.h_aliases = 0;
104116469Ssam 		hp = &def;
104216469Ssam 	}
104316469Ssam 	sp = getservbyname("finger", "tcp");
104416469Ssam 	if (sp == 0) {
104516469Ssam 		printf("tcp/finger: unknown service\n");
104618606Sedward 		return (1);
104716469Ssam 	}
104816469Ssam 	sin.sin_family = hp->h_addrtype;
104916469Ssam 	bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
105016469Ssam 	sin.sin_port = sp->s_port;
105116469Ssam 	s = socket(hp->h_addrtype, SOCK_STREAM, 0);
105216469Ssam 	if (s < 0) {
105316469Ssam 		perror("socket");
105418606Sedward 		return (1);
105516469Ssam 	}
105630958Sbostic 	printf("[%s]\n", hp->h_name);
105730958Sbostic 	fflush(stdout);
105816469Ssam 	if (connect(s, (char *)&sin, sizeof (sin)) < 0) {
105916469Ssam 		perror("connect");
106016469Ssam 		close(s);
106118606Sedward 		return (1);
106216469Ssam 	}
106316469Ssam 	if (large) write(s, "/W ", 3);
106416469Ssam 	write(s, name, strlen(name));
106516469Ssam 	write(s, "\r\n", 2);
106616469Ssam 	f = fdopen(s, "r");
106716469Ssam 	while ((c = getc(f)) != EOF) {
106816469Ssam 		switch(c) {
106916469Ssam 		case 0210:
107016469Ssam 		case 0211:
107116469Ssam 		case 0212:
107216469Ssam 		case 0214:
107316469Ssam 			c -= 0200;
107416469Ssam 			break;
107516469Ssam 		case 0215:
107616469Ssam 			c = '\n';
107716469Ssam 			break;
107816469Ssam 		}
107925589Sbloom 		lastc = c;
108025589Sbloom 		if (isprint(c) || isspace(c))
108125589Sbloom 			putchar(c);
108225589Sbloom 		else
108325589Sbloom 			putchar(c ^ 100);
108416469Ssam 	}
108516469Ssam 	if (lastc != '\n')
108616469Ssam 		putchar('\n');
108725121Sbloom 	(void)fclose(f);
108818606Sedward 	return (1);
108916469Ssam }
1090