xref: /csrg-svn/usr.bin/finger/finger.c (revision 37629)
121554Sdist /*
235627Sbostic  * Copyright (c) 1980 The Regents of the University of California.
335627Sbostic  * All rights reserved.
435627Sbostic  *
535627Sbostic  * Redistribution and use in source and binary forms are permitted
635627Sbostic  * provided that the above copyright notice and this paragraph are
735627Sbostic  * duplicated in all such forms and that any documentation,
835627Sbostic  * advertising materials, and other materials related to such
935627Sbostic  * distribution and use acknowledge that the software was developed
1035627Sbostic  * by the University of California, Berkeley.  The name of the
1135627Sbostic  * University may not be used to endorse or promote products derived
1235627Sbostic  * from this software without specific prior written permission.
1335627Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1435627Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1535627Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1621554Sdist  */
1721554Sdist 
1813619Ssam #ifndef lint
1921554Sdist char copyright[] =
2035627Sbostic "@(#) Copyright (c) 1980 The Regents of the University of California.\n\
2121554Sdist  All rights reserved.\n";
2235627Sbostic #endif /* not lint */
231014Sbill 
2421554Sdist #ifndef lint
25*37629Sbostic static char sccsid[] = "@(#)finger.c	5.12 (Berkeley) 05/04/89";
2635627Sbostic #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 <sys/signal.h>
6918606Sedward #include <sys/time.h>
7018606Sedward #include <sys/socket.h>
7118606Sedward #include <netinet/in.h>
7218606Sedward #include <netdb.h>
73*37629Sbostic #include <utmp.h>
74*37629Sbostic #include <pwd.h>
75*37629Sbostic #include <stdio.h>
76*37629Sbostic #include <ctype.h>
77*37629Sbostic #include "pathnames.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 PLAN[] = "/.plan";			/* what plan file is */
11118606Sedward char PROJ[] = "/.project";		/* what project file */
11218606Sedward 
11318606Sedward int unbrief = 1;			/* -b option default */
11418606Sedward int header = 1;				/* -f option default */
11518606Sedward int hack = 1;				/* -h option default */
11618606Sedward int idle = 0;				/* -i option default */
11718606Sedward int large = 0;				/* -l option default */
11818606Sedward int match = 1;				/* -m option default */
11918606Sedward int plan = 1;				/* -p option default */
12018606Sedward int unquick = 1;			/* -q option default */
12118606Sedward int small = 0;				/* -s option default */
12218606Sedward int wide = 1;				/* -w option default */
1231014Sbill 
12418606Sedward int unshort;
125*37629Sbostic int lf;					/* _PATH_LASTLOG file descriptor */
12618606Sedward struct person *person1;			/* list of people */
12718606Sedward long tloc;				/* current time */
1281014Sbill 
12918606Sedward struct passwd *pwdcopy();
13018606Sedward char *strcpy();
13118606Sedward char *malloc();
13218606Sedward char *ctime();
1331014Sbill 
13418606Sedward main(argc, argv)
13518606Sedward 	int argc;
13618606Sedward 	register char **argv;
13718606Sedward {
13818606Sedward 	FILE *fp;
13918606Sedward 	register char *s;
1401014Sbill 
14118606Sedward 	/* parse command line for (optional) arguments */
14218606Sedward 	while (*++argv && **argv == COMMAND)
14318606Sedward 		for (s = *argv + 1; *s; s++)
14418606Sedward 			switch (*s) {
14518606Sedward 			case 'b':
14618606Sedward 				unbrief = 0;
14718606Sedward 				break;
14818606Sedward 			case 'f':
14918606Sedward 				header = 0;
15018606Sedward 				break;
15118606Sedward 			case 'h':
15218606Sedward 				hack = 0;
15318606Sedward 				break;
15418606Sedward 			case 'i':
15518606Sedward 				idle = 1;
15618606Sedward 				unquick = 0;
15718606Sedward 				break;
15818606Sedward 			case 'l':
15918606Sedward 				large = 1;
16018606Sedward 				break;
16118606Sedward 			case 'm':
16218606Sedward 				match = 0;
16318606Sedward 				break;
16418606Sedward 			case 'p':
16518606Sedward 				plan = 0;
16618606Sedward 				break;
16718606Sedward 			case 'q':
16818606Sedward 				unquick = 0;
16918606Sedward 				break;
17018606Sedward 			case 's':
17118606Sedward 				small = 1;
17218606Sedward 				break;
17318606Sedward 			case 'w':
17418606Sedward 				wide = 0;
17518606Sedward 				break;
17618606Sedward 			default:
17718606Sedward 				fprintf(stderr, "Usage: finger [-bfhilmpqsw] [login1 [login2 ...] ]\n");
17818606Sedward 				exit(1);
17918606Sedward 			}
18018606Sedward 	if (unquick || idle)
18118606Sedward 		time(&tloc);
18218606Sedward 	/*
18318606Sedward 	 * *argv == 0 means no names given
18418606Sedward 	 */
18518606Sedward 	if (*argv == 0)
18618606Sedward 		doall();
18718606Sedward 	else
18818606Sedward 		donames(argv);
18924461Sedward 	if (person1)
19024461Sedward 		print();
19118606Sedward 	exit(0);
19218606Sedward }
1931014Sbill 
19418606Sedward doall()
1951014Sbill {
19618606Sedward 	register struct person *p;
19718606Sedward 	register struct passwd *pw;
19818606Sedward 	int uf;
19918606Sedward 	char name[NMAX + 1];
2001014Sbill 
20118606Sedward 	unshort = large;
202*37629Sbostic 	if ((uf = open(_PATH_UTMP, 0)) < 0) {
203*37629Sbostic 		fprintf(stderr, "finger: error opening %s\n", _PATH_UTMP);
20418606Sedward 		exit(2);
2051014Sbill 	}
20618606Sedward 	if (unquick) {
2071014Sbill 
2081014Sbill 		setpwent();
2091014Sbill 		fwopen();
21018606Sedward 	}
21118606Sedward 	while (read(uf, (char *)&user, sizeof user) == sizeof user) {
21218606Sedward 		if (user.ut_name[0] == 0)
21318606Sedward 			continue;
21418606Sedward 		if (person1 == 0)
21518606Sedward 			p = person1 = (struct person *) malloc(sizeof *p);
21618606Sedward 		else {
21718606Sedward 			p->link = (struct person *) malloc(sizeof *p);
2181014Sbill 			p = p->link;
2191014Sbill 		}
22018606Sedward 		bcopy(user.ut_name, name, NMAX);
22118606Sedward 		name[NMAX] = 0;
22218606Sedward 		bcopy(user.ut_line, p->tty, LMAX);
22318606Sedward 		p->tty[LMAX] = 0;
22418606Sedward 		bcopy(user.ut_host, p->host, HMAX);
22518606Sedward 		p->host[HMAX] = 0;
22618606Sedward 		p->loginat = user.ut_time;
22718606Sedward 		p->pwd = 0;
22818606Sedward 		p->loggedin = 1;
22918606Sedward 		if (unquick && (pw = getpwnam(name))) {
23018606Sedward 			p->pwd = pwdcopy(pw);
23118606Sedward 			decode(p);
23218606Sedward 			p->name = p->pwd->pw_name;
23318606Sedward 		} else
23418606Sedward 			p->name = strcpy(malloc(strlen(name) + 1), name);
23518606Sedward 	}
23618606Sedward 	if (unquick) {
2371014Sbill 		fwclose();
2381014Sbill 		endpwent();
2391014Sbill 	}
24018606Sedward 	close(uf);
24118606Sedward 	if (person1 == 0) {
24218606Sedward 		printf("No one logged on\n");
24324461Sedward 		return;
24418606Sedward 	}
24518606Sedward 	p->link = 0;
24618606Sedward }
2471014Sbill 
24818606Sedward donames(argv)
24918606Sedward 	char **argv;
25018606Sedward {
25118606Sedward 	register struct person *p;
25218606Sedward 	register struct passwd *pw;
25318606Sedward 	int uf;
2541014Sbill 
25518606Sedward 	/*
25618606Sedward 	 * get names from command line and check to see if they're
25718606Sedward 	 * logged in
25818606Sedward 	 */
25918606Sedward 	unshort = !small;
26018606Sedward 	for (; *argv != 0; argv++) {
26118606Sedward 		if (netfinger(*argv))
26218606Sedward 			continue;
26318606Sedward 		if (person1 == 0)
26418606Sedward 			p = person1 = (struct person *) malloc(sizeof *p);
26518606Sedward 		else {
26618606Sedward 			p->link = (struct person *) malloc(sizeof *p);
26718606Sedward 			p = p->link;
26816469Ssam 		}
26918606Sedward 		p->name = *argv;
2701014Sbill 		p->loggedin = 0;
27118606Sedward 		p->original = 1;
27218606Sedward 		p->pwd = 0;
27318606Sedward 	}
27424461Sedward 	if (person1 == 0)
27524461Sedward 		return;
27618606Sedward 	p->link = 0;
27718606Sedward 	/*
27818606Sedward 	 * if we are doing it, read /etc/passwd for the useful info
27918606Sedward 	 */
28018606Sedward 	if (unquick) {
28118606Sedward 		setpwent();
28218606Sedward 		if (!match) {
28318606Sedward 			for (p = person1; p != 0; p = p->link)
28418606Sedward 				if (pw = getpwnam(p->name))
28518606Sedward 					p->pwd = pwdcopy(pw);
28618606Sedward 		} else while ((pw = getpwent()) != 0) {
28718606Sedward 			for (p = person1; p != 0; p = p->link) {
28818606Sedward 				if (!p->original)
28918606Sedward 					continue;
29018606Sedward 				if (strcmp(p->name, pw->pw_name) != 0 &&
29118606Sedward 				    !matchcmp(pw->pw_gecos, pw->pw_name, p->name))
29218606Sedward 					continue;
29318606Sedward 				if (p->pwd == 0)
29418606Sedward 					p->pwd = pwdcopy(pw);
29518606Sedward 				else {
29618606Sedward 					struct person *new;
29718606Sedward 					/*
29818606Sedward 					 * handle multiple login names, insert
29918606Sedward 					 * new "duplicate" entry behind
30018606Sedward 					 */
30118606Sedward 					new = (struct person *)
30218606Sedward 						malloc(sizeof *new);
30318606Sedward 					new->pwd = pwdcopy(pw);
30418606Sedward 					new->name = p->name;
30518606Sedward 					new->original = 1;
30618606Sedward 					new->loggedin = 0;
30718606Sedward 					new->link = p->link;
30818606Sedward 					p->original = 0;
30918606Sedward 					p->link = new;
31018606Sedward 					p = new;
31118606Sedward 				}
3121014Sbill 			}
3131014Sbill 		}
3141014Sbill 		endpwent();
31518606Sedward 	}
31618606Sedward 	/* Now get login information */
317*37629Sbostic 	if ((uf = open(_PATH_UTMP, 0)) < 0) {
318*37629Sbostic 		fprintf(stderr, "finger: error opening %s\n", _PATH_UTMP);
31918606Sedward 		exit(2);
32018606Sedward 	}
32118606Sedward 	while (read(uf, (char *)&user, sizeof user) == sizeof user) {
32218606Sedward 		if (*user.ut_name == 0)
32318606Sedward 			continue;
32418606Sedward 		for (p = person1; p != 0; p = p->link) {
32518606Sedward 			if (p->loggedin == 2)
32618606Sedward 				continue;
32718606Sedward 			if (strncmp(p->pwd ? p->pwd->pw_name : p->name,
32818606Sedward 				    user.ut_name, NMAX) != 0)
32918606Sedward 				continue;
33018606Sedward 			if (p->loggedin == 0) {
33118606Sedward 				bcopy(user.ut_line, p->tty, LMAX);
33218606Sedward 				p->tty[LMAX] = 0;
33318606Sedward 				bcopy(user.ut_host, p->host, HMAX);
33418606Sedward 				p->host[HMAX] = 0;
33518606Sedward 				p->loginat = user.ut_time;
33618606Sedward 				p->loggedin = 1;
33718606Sedward 			} else {	/* p->loggedin == 1 */
33818606Sedward 				struct person *new;
33918606Sedward 				new = (struct person *) malloc(sizeof *new);
34018606Sedward 				new->name = p->name;
34118606Sedward 				bcopy(user.ut_line, new->tty, LMAX);
34218606Sedward 				new->tty[LMAX] = 0;
34318606Sedward 				bcopy(user.ut_host, new->host, HMAX);
34418606Sedward 				new->host[HMAX] = 0;
34518606Sedward 				new->loginat = user.ut_time;
34618606Sedward 				new->pwd = p->pwd;
34718606Sedward 				new->loggedin = 1;
34818606Sedward 				new->original = 0;
34918606Sedward 				new->link = p->link;
35018606Sedward 				p->loggedin = 2;
35118606Sedward 				p->link = new;
35218606Sedward 				p = new;
3531014Sbill 			}
3541014Sbill 		}
35518606Sedward 	}
35618606Sedward 	close(uf);
35718606Sedward 	if (unquick) {
3581014Sbill 		fwopen();
35918606Sedward 		for (p = person1; p != 0; p = p->link)
36018606Sedward 			decode(p);
3611014Sbill 		fwclose();
3621014Sbill 	}
36318606Sedward }
3641014Sbill 
36518606Sedward print()
36618606Sedward {
36718606Sedward 	register FILE *fp;
36818606Sedward 	register struct person *p;
36918606Sedward 	register char *s;
37018606Sedward 	register c;
3711014Sbill 
37218606Sedward 	/*
37318606Sedward 	 * print out what we got
37418606Sedward 	 */
37518606Sedward 	if (header) {
37618606Sedward 		if (unquick) {
37718606Sedward 			if (!unshort)
37818606Sedward 				if (wide)
37918606Sedward 					printf("Login       Name              TTY Idle    When            Office\n");
38018606Sedward 				else
38118606Sedward 					printf("Login    TTY Idle    When            Office\n");
38218606Sedward 		} else {
38318606Sedward 			printf("Login      TTY            When");
38418606Sedward 			if (idle)
38518606Sedward 				printf("             Idle");
38618606Sedward 			putchar('\n');
3871014Sbill 		}
38818606Sedward 	}
38918606Sedward 	for (p = person1; p != 0; p = p->link) {
39018606Sedward 		if (!unquick) {
39118606Sedward 			quickprint(p);
39218606Sedward 			continue;
3931014Sbill 		}
39418606Sedward 		if (!unshort) {
39518606Sedward 			shortprint(p);
39618606Sedward 			continue;
39718606Sedward 		}
39818606Sedward 		personprint(p);
39918606Sedward 		if (p->pwd != 0) {
40018606Sedward 			if (hack) {
40118606Sedward 				s = malloc(strlen(p->pwd->pw_dir) +
40218606Sedward 					sizeof PROJ);
40318606Sedward 				strcpy(s, p->pwd->pw_dir);
40418606Sedward 				strcat(s, PROJ);
40518606Sedward 				if ((fp = fopen(s, "r")) != 0) {
40618606Sedward 					printf("Project: ");
40718606Sedward 					while ((c = getc(fp)) != EOF) {
40818606Sedward 						if (c == '\n')
40918606Sedward 							break;
41025589Sbloom 						if (isprint(c) || isspace(c))
41125589Sbloom 							putchar(c);
41225589Sbloom 						else
41325589Sbloom 							putchar(c ^ 100);
41418606Sedward 					}
41518606Sedward 					fclose(fp);
41618606Sedward 					putchar('\n');
4171014Sbill 				}
41818606Sedward 				free(s);
4191014Sbill 			}
42018606Sedward 			if (plan) {
42118606Sedward 				s = malloc(strlen(p->pwd->pw_dir) +
42218606Sedward 					sizeof PLAN);
42318606Sedward 				strcpy(s, p->pwd->pw_dir);
42418606Sedward 				strcat(s, PLAN);
42518606Sedward 				if ((fp = fopen(s, "r")) == 0)
42618606Sedward 					printf("No Plan.\n");
42718606Sedward 				else {
42818606Sedward 					printf("Plan:\n");
42918606Sedward 					while ((c = getc(fp)) != EOF)
43025589Sbloom 						if (isprint(c) || isspace(c))
43125589Sbloom 							putchar(c);
43225589Sbloom 						else
43325589Sbloom 							putchar(c ^ 100);
43418606Sedward 					fclose(fp);
4351014Sbill 				}
43618606Sedward 				free(s);
4371014Sbill 			}
4381014Sbill 		}
43918606Sedward 		if (p->link != 0)
44018606Sedward 			putchar('\n');
44118606Sedward 	}
4421014Sbill }
4431014Sbill 
44418606Sedward /*
44518606Sedward  * Duplicate a pwd entry.
44618606Sedward  * Note: Only the useful things (what the program currently uses) are copied.
4471014Sbill  */
44818606Sedward struct passwd *
44918606Sedward pwdcopy(pfrom)
45018606Sedward 	register struct passwd *pfrom;
45118606Sedward {
45218606Sedward 	register struct passwd *pto;
4531014Sbill 
45418606Sedward 	pto = (struct passwd *) malloc(sizeof *pto);
45518606Sedward #define savestr(s) strcpy(malloc(strlen(s) + 1), s)
45618606Sedward 	pto->pw_name = savestr(pfrom->pw_name);
4571014Sbill 	pto->pw_uid = pfrom->pw_uid;
45818606Sedward 	pto->pw_gecos = savestr(pfrom->pw_gecos);
45918606Sedward 	pto->pw_dir = savestr(pfrom->pw_dir);
46018606Sedward 	pto->pw_shell = savestr(pfrom->pw_shell);
46118606Sedward #undef savestr
46218606Sedward 	return pto;
4631014Sbill }
4641014Sbill 
46518606Sedward /*
46618606Sedward  * print out information on quick format giving just name, tty, login time
46718606Sedward  * and idle time if idle is set.
4681014Sbill  */
46918606Sedward quickprint(pers)
47018606Sedward 	register struct person *pers;
4711014Sbill {
47218606Sedward 	printf("%-*.*s  ", NMAX, NMAX, pers->name);
47318606Sedward 	if (pers->loggedin) {
47418606Sedward 		if (idle) {
47518606Sedward 			findidle(pers);
47618606Sedward 			printf("%c%-*s %-16.16s", pers->writable ? ' ' : '*',
47718606Sedward 				LMAX, pers->tty, ctime(&pers->loginat));
47818606Sedward 			ltimeprint("   ", &pers->idletime, "");
47918606Sedward 		} else
48018606Sedward 			printf(" %-*s %-16.16s", LMAX,
48118606Sedward 				pers->tty, ctime(&pers->loginat));
48218606Sedward 		putchar('\n');
48318606Sedward 	} else
48418606Sedward 		printf("          Not Logged In\n");
4851014Sbill }
4861014Sbill 
48718606Sedward /*
48818606Sedward  * print out information in short format, giving login name, full name,
48918606Sedward  * tty, idle time, login time, office location and phone.
4901014Sbill  */
49118606Sedward shortprint(pers)
49218606Sedward 	register struct person *pers;
4931014Sbill {
49418606Sedward 	char *p;
49518606Sedward 	char dialup;
4961014Sbill 
49718606Sedward 	if (pers->pwd == 0) {
49818606Sedward 		printf("%-15s       ???\n", pers->name);
49918606Sedward 		return;
5001014Sbill 	}
50118606Sedward 	printf("%-*s", NMAX, pers->pwd->pw_name);
5021014Sbill 	dialup = 0;
50318606Sedward 	if (wide) {
50418606Sedward 		if (pers->realname)
50518606Sedward 			printf(" %-20.20s", pers->realname);
50618606Sedward 		else
50718606Sedward 			printf("        ???          ");
5081014Sbill 	}
50918606Sedward 	putchar(' ');
51018606Sedward 	if (pers->loggedin && !pers->writable)
51118606Sedward 		putchar('*');
51218606Sedward 	else
51318606Sedward 		putchar(' ');
51418606Sedward 	if (*pers->tty) {
51518606Sedward 		if (pers->tty[0] == 't' && pers->tty[1] == 't' &&
51618606Sedward 		    pers->tty[2] == 'y') {
51718606Sedward 			if (pers->tty[3] == 'd' && pers->loggedin)
51818606Sedward 				dialup = 1;
51918606Sedward 			printf("%-2.2s ", pers->tty + 3);
52018606Sedward 		} else
52118606Sedward 			printf("%-2.2s ", pers->tty);
52218606Sedward 	} else
52318606Sedward 		printf("   ");
52418606Sedward 	p = ctime(&pers->loginat);
52518606Sedward 	if (pers->loggedin) {
52618606Sedward 		stimeprint(&pers->idletime);
52718606Sedward 		printf(" %3.3s %-5.5s ", p, p + 11);
52818606Sedward 	} else if (pers->loginat == 0)
52918606Sedward 		printf(" < .  .  .  . >");
5308842Smckusick 	else if (tloc - pers->loginat >= 180 * 24 * 60 * 60)
53118606Sedward 		printf(" <%-6.6s, %-4.4s>", p + 4, p + 20);
5328842Smckusick 	else
53318606Sedward 		printf(" <%-12.12s>", p + 4);
53418606Sedward 	if (dialup && pers->homephone)
53518606Sedward 		printf(" %20s", pers->homephone);
53618606Sedward 	else {
53718606Sedward 		if (pers->office)
53818606Sedward 			printf(" %-11.11s", pers->office);
53918606Sedward 		else if (pers->officephone || pers->homephone)
54018606Sedward 			printf("            ");
54118606Sedward 		if (pers->officephone)
54218606Sedward 			printf(" %s", pers->officephone);
54318606Sedward 		else if (pers->homephone)
54418606Sedward 			printf(" %s", pers->homephone);
5451014Sbill 	}
54618606Sedward 	putchar('\n');
5471014Sbill }
5481014Sbill 
54918606Sedward /*
55018606Sedward  * print out a person in long format giving all possible information.
55118606Sedward  * directory and shell are inhibited if unbrief is clear.
5521014Sbill  */
55318606Sedward personprint(pers)
55418606Sedward 	register struct person *pers;
5551014Sbill {
55618606Sedward 	if (pers->pwd == 0) {
55718606Sedward 		printf("Login name: %-10s\t\t\tIn real life: ???\n",
55818606Sedward 			pers->name);
55918606Sedward 		return;
5601014Sbill 	}
56118606Sedward 	printf("Login name: %-10s", pers->pwd->pw_name);
56218606Sedward 	if (pers->loggedin && !pers->writable)
56318606Sedward 		printf("	(messages off)	");
56418606Sedward 	else
56518606Sedward 		printf("			");
56618606Sedward 	if (pers->realname)
56718606Sedward 		printf("In real life: %s", pers->realname);
56818606Sedward 	if (pers->office) {
56918606Sedward 		printf("\nOffice: %-.11s", pers->office);
57018606Sedward 		if (pers->officephone) {
57118606Sedward 			printf(", %s", pers->officephone);
57218606Sedward 			if (pers->homephone)
57318606Sedward 				printf("\t\tHome phone: %s", pers->homephone);
57418606Sedward 			else if (pers->random)
57518606Sedward 				printf("\t\t%s", pers->random);
57618606Sedward 		} else
57718606Sedward 			if (pers->homephone)
57818606Sedward 				printf("\t\t\tHome phone: %s", pers->homephone);
57918606Sedward 			else if (pers->random)
58018606Sedward 				printf("\t\t\t%s", pers->random);
58118606Sedward 	} else if (pers->officephone) {
58218606Sedward 		printf("\nPhone: %s", pers->officephone);
58318606Sedward 		if (pers->homephone)
58418606Sedward 			printf(", %s", pers->homephone);
58518606Sedward 		if (pers->random)
58618606Sedward 			printf(", %s", pers->random);
58718606Sedward 	} else if (pers->homephone) {
58818606Sedward 		printf("\nPhone: %s", pers->homephone);
58918606Sedward 		if (pers->random)
59018606Sedward 			printf(", %s", pers->random);
59118606Sedward 	} else if (pers->random)
59218606Sedward 		printf("\n%s", pers->random);
59318606Sedward 	if (unbrief) {
59418606Sedward 		printf("\nDirectory: %-25s", pers->pwd->pw_dir);
59518606Sedward 		if (*pers->pwd->pw_shell)
59618606Sedward 			printf("\tShell: %-s", pers->pwd->pw_shell);
5971014Sbill 	}
59818606Sedward 	if (pers->loggedin) {
59918606Sedward 		register char *ep = ctime(&pers->loginat);
60018606Sedward 		if (*pers->host) {
60118606Sedward 			printf("\nOn since %15.15s on %s from %s",
60218606Sedward 				&ep[4], pers->tty, pers->host);
60318606Sedward 			ltimeprint("\n", &pers->idletime, " Idle Time");
60418606Sedward 		} else {
60518606Sedward 			printf("\nOn since %15.15s on %-*s",
60618606Sedward 				&ep[4], LMAX, pers->tty);
60718606Sedward 			ltimeprint("\t", &pers->idletime, " Idle Time");
6081014Sbill 		}
60918606Sedward 	} else if (pers->loginat == 0)
61018606Sedward 		printf("\nNever logged in.");
6118842Smckusick 	else if (tloc - pers->loginat > 180 * 24 * 60 * 60) {
61218606Sedward 		register char *ep = ctime(&pers->loginat);
61318606Sedward 		printf("\nLast login %10.10s, %4.4s on %s",
61418606Sedward 			ep, ep+20, pers->tty);
61518606Sedward 		if (*pers->host)
61618606Sedward 			printf(" from %s", pers->host);
61718606Sedward 	} else {
61818606Sedward 		register char *ep = ctime(&pers->loginat);
61918606Sedward 		printf("\nLast login %16.16s on %s", ep, pers->tty);
62018606Sedward 		if (*pers->host)
62118606Sedward 			printf(" from %s", pers->host);
6228842Smckusick 	}
62318606Sedward 	putchar('\n');
6241014Sbill }
6251014Sbill 
6261014Sbill /*
6271014Sbill  *  very hacky section of code to format phone numbers.  filled with
6281014Sbill  *  magic constants like 4, 7 and 10.
6291014Sbill  */
63018606Sedward char *
63118606Sedward phone(s, len, alldigits)
63218606Sedward 	register char *s;
63318606Sedward 	int len;
63418606Sedward 	char alldigits;
6351014Sbill {
63618606Sedward 	char fonebuf[15];
63718606Sedward 	register char *p = fonebuf;
63818606Sedward 	register i;
6391014Sbill 
64018606Sedward 	if (!alldigits)
64118606Sedward 		return (strcpy(malloc(len + 1), s));
64218606Sedward 	switch (len) {
64318606Sedward 	case 4:
64418606Sedward 		*p++ = ' ';
64518606Sedward 		*p++ = 'x';
64618606Sedward 		*p++ = '2';
64718606Sedward 		*p++ = '-';
64818606Sedward 		for (i = 0; i < 4; i++)
64918606Sedward 			*p++ = *s++;
6501014Sbill 		break;
65124463Sbloom 	case 5:
65224463Sbloom 		*p++ = ' ';
65324463Sbloom 		*p++ = 'x';
65424463Sbloom 		*p++ = *s++;
65524463Sbloom 		*p++ = '-';
65624463Sbloom 		for (i = 0; i < 4; i++)
65724463Sbloom 			*p++ = *s++;
65824463Sbloom 		break;
65918606Sedward 	case 7:
66018606Sedward 		for (i = 0; i < 3; i++)
66118606Sedward 			*p++ = *s++;
66218606Sedward 		*p++ = '-';
66318606Sedward 		for (i = 0; i < 4; i++)
66418606Sedward 			*p++ = *s++;
6651014Sbill 		break;
66618606Sedward 	case 10:
66718606Sedward 		for (i = 0; i < 3; i++)
66818606Sedward 			*p++ = *s++;
66918606Sedward 		*p++ = '-';
67018606Sedward 		for (i = 0; i < 3; i++)
67118606Sedward 			*p++ = *s++;
67218606Sedward 		*p++ = '-';
67318606Sedward 		for (i = 0; i < 4; i++)
67418606Sedward 			*p++ = *s++;
6751014Sbill 		break;
67618606Sedward 	case 0:
67718606Sedward 		return 0;
67818606Sedward 	default:
67918606Sedward 		return (strcpy(malloc(len + 1), s));
6801014Sbill 	}
68118606Sedward 	*p++ = 0;
68218606Sedward 	return (strcpy(malloc(p - fonebuf), fonebuf));
6831014Sbill }
6841014Sbill 
68518606Sedward /*
68618606Sedward  * decode the information in the gecos field of /etc/passwd
6871014Sbill  */
68818606Sedward decode(pers)
68918606Sedward 	register struct person *pers;
6901014Sbill {
69118606Sedward 	char buffer[256];
69218606Sedward 	register char *bp, *gp, *lp;
69318606Sedward 	int alldigits;
69418606Sedward 	int hasspace;
69518606Sedward 	int len;
6961014Sbill 
69718606Sedward 	pers->realname = 0;
69818606Sedward 	pers->office = 0;
69918606Sedward 	pers->officephone = 0;
70018606Sedward 	pers->homephone = 0;
70118606Sedward 	pers->random = 0;
70218606Sedward 	if (pers->pwd == 0)
70318606Sedward 		return;
70418606Sedward 	gp = pers->pwd->pw_gecos;
70518606Sedward 	bp = buffer;
70618606Sedward 	if (*gp == ASTERISK)
7071014Sbill 		gp++;
70818606Sedward 	while (*gp && *gp != COMMA)			/* name */
70918606Sedward 		if (*gp == SAMENAME) {
71018606Sedward 			lp = pers->pwd->pw_name;
71118606Sedward 			if (islower(*lp))
71218606Sedward 				*bp++ = toupper(*lp++);
71318606Sedward 			while (*bp++ = *lp++)
71418606Sedward 				;
71518606Sedward 			bp--;
71618606Sedward 			gp++;
71718606Sedward 		} else
71818606Sedward 			*bp++ = *gp++;
71918606Sedward 	*bp++ = 0;
72018606Sedward 	if ((len = bp - buffer) > 1)
72118606Sedward 		pers->realname = strcpy(malloc(len), buffer);
72218606Sedward 	if (*gp == COMMA) {				/* office */
72318606Sedward 		gp++;
72418606Sedward 		hasspace = 0;
72518606Sedward 		bp = buffer;
72618606Sedward 		while (*gp && *gp != COMMA) {
72718606Sedward 			*bp = *gp++;
72818606Sedward 			if (*bp == ' ')
72918606Sedward 				hasspace = 1;
73018606Sedward 			/* leave 5 for Cory and Evans expansion */
73118606Sedward 			if (bp < buffer + sizeof buffer - 6)
73218606Sedward 				bp++;
7331014Sbill 		}
73418606Sedward 		*bp = 0;
73518606Sedward 		len = bp - buffer;
73618606Sedward 		bp--;			/* point to last character */
73718606Sedward 		if (hasspace || len == 0)
73818606Sedward 			len++;
73918606Sedward 		else if (*bp == CORY) {
74018606Sedward 			strcpy(bp, " Cory");
74118606Sedward 			len += 5;
74218606Sedward 		} else if (*bp == EVANS) {
74318606Sedward 			strcpy(bp, " Evans");
74418606Sedward 			len += 6;
74518606Sedward 		} else
74618606Sedward 			len++;
74718606Sedward 		if (len > 1)
74818606Sedward 			pers->office = strcpy(malloc(len), buffer);
74918606Sedward 	}
75018606Sedward 	if (*gp == COMMA) {				/* office phone */
75118606Sedward 		gp++;
75218606Sedward 		bp = buffer;
75318606Sedward 		alldigits = 1;
75418606Sedward 		while (*gp && *gp != COMMA) {
75518606Sedward 			*bp = *gp++;
75618606Sedward 			if (!isdigit(*bp))
75718606Sedward 				alldigits = 0;
75818606Sedward 			if (bp < buffer + sizeof buffer - 1)
75918606Sedward 				bp++;
7601014Sbill 		}
76118606Sedward 		*bp = 0;
76218606Sedward 		pers->officephone = phone(buffer, bp - buffer, alldigits);
76318606Sedward 	}
76418606Sedward 	if (*gp == COMMA) {				/* home phone */
7651014Sbill 		gp++;
76618606Sedward 		bp = buffer;
7671014Sbill 		alldigits = 1;
76818606Sedward 		while (*gp && *gp != COMMA) {
7691014Sbill 			*bp = *gp++;
77018606Sedward 			if (!isdigit(*bp))
77118606Sedward 				alldigits = 0;
77218606Sedward 			if (bp < buffer + sizeof buffer - 1)
7731014Sbill 				bp++;
7741014Sbill 		}
77518606Sedward 		*bp = 0;
77618606Sedward 		pers->homephone = phone(buffer, bp - buffer, alldigits);
7771014Sbill 	}
77818606Sedward 	if (pers->loggedin)
77918606Sedward 		findidle(pers);
78018606Sedward 	else
78118606Sedward 		findwhen(pers);
7821014Sbill }
7831014Sbill 
78418606Sedward /*
785*37629Sbostic  * find the last log in of a user by checking the _PATH_LASTLOG file.
78618606Sedward  * the entry is indexed by the uid, so this can only be done if
78718606Sedward  * the uid is known (which it isn't in quick mode)
7881014Sbill  */
7891014Sbill 
7901014Sbill fwopen()
7911014Sbill {
792*37629Sbostic 	if ((lf = open(_PATH_LASTLOG, 0)) < 0)
793*37629Sbostic 		fprintf(stderr, "finger: %s open error\n", _PATH_LASTLOG);
7941014Sbill }
7951014Sbill 
79618606Sedward findwhen(pers)
79718606Sedward 	register struct person *pers;
7981014Sbill {
79918606Sedward 	struct lastlog ll;
80018606Sedward 	int i;
8011014Sbill 
80218606Sedward 	if (lf >= 0) {
80318606Sedward 		lseek(lf, (long)pers->pwd->pw_uid * sizeof ll, 0);
80418606Sedward 		if ((i = read(lf, (char *)&ll, sizeof ll)) == sizeof ll) {
80518606Sedward 			bcopy(ll.ll_line, pers->tty, LMAX);
80618606Sedward 			pers->tty[LMAX] = 0;
80718606Sedward 			bcopy(ll.ll_host, pers->host, HMAX);
80818606Sedward 			pers->host[HMAX] = 0;
80918606Sedward 			pers->loginat = ll.ll_time;
81018606Sedward 		} else {
81118606Sedward 			if (i != 0)
81218606Sedward 				fprintf(stderr, "finger: %s read error\n",
813*37629Sbostic 					_PATH_LASTLOG);
81418606Sedward 			pers->tty[0] = 0;
81518606Sedward 			pers->host[0] = 0;
81618606Sedward 			pers->loginat = 0L;
81718606Sedward 		}
81818606Sedward 	} else {
81918606Sedward 		pers->tty[0] = 0;
82018606Sedward 		pers->host[0] = 0;
8211014Sbill 		pers->loginat = 0L;
8221014Sbill 	}
8231014Sbill }
8241014Sbill 
8251014Sbill fwclose()
8261014Sbill {
82718606Sedward 	if (lf >= 0)
82818606Sedward 		close(lf);
8291014Sbill }
8301014Sbill 
83118606Sedward /*
83218606Sedward  * find the idle time of a user by doing a stat on /dev/tty??,
833*37629Sbostic  * where tty?? has been gotten from _PATH_UTMP, supposedly.
8341014Sbill  */
83518606Sedward findidle(pers)
83618606Sedward 	register struct person *pers;
8371014Sbill {
83818606Sedward 	struct stat ttystatus;
839*37629Sbostic 	static char buffer[20] = _PATH_DEV;
84018606Sedward 	long t;
84118606Sedward #define TTYLEN 5
8421014Sbill 
84318606Sedward 	strcpy(buffer + TTYLEN, pers->tty);
84418606Sedward 	buffer[TTYLEN+LMAX] = 0;
84518606Sedward 	if (stat(buffer, &ttystatus) < 0) {
84618606Sedward 		fprintf(stderr, "finger: Can't stat %s\n", buffer);
84718606Sedward 		exit(4);
84818606Sedward 	}
84918606Sedward 	time(&t);
85018606Sedward 	if (t < ttystatus.st_atime)
8511014Sbill 		pers->idletime = 0L;
85218606Sedward 	else
85318606Sedward 		pers->idletime = t - ttystatus.st_atime;
85418606Sedward 	pers->writable = (ttystatus.st_mode & TALKABLE) == TALKABLE;
8551014Sbill }
8561014Sbill 
85718606Sedward /*
85818606Sedward  * print idle time in short format; this program always prints 4 characters;
85918606Sedward  * if the idle time is zero, it prints 4 blanks.
8601014Sbill  */
86118606Sedward stimeprint(dt)
86218606Sedward 	long *dt;
8631014Sbill {
86418606Sedward 	register struct tm *delta;
8651014Sbill 
86618606Sedward 	delta = gmtime(dt);
86718606Sedward 	if (delta->tm_yday == 0)
86818606Sedward 		if (delta->tm_hour == 0)
86918606Sedward 			if (delta->tm_min == 0)
87018606Sedward 				printf("    ");
87118606Sedward 			else
87218606Sedward 				printf("  %2d", delta->tm_min);
87318606Sedward 		else
87418606Sedward 			if (delta->tm_hour >= 10)
87518606Sedward 				printf("%3d:", delta->tm_hour);
87618606Sedward 			else
87718606Sedward 				printf("%1d:%02d",
87818606Sedward 					delta->tm_hour, delta->tm_min);
87918606Sedward 	else
88018606Sedward 		printf("%3dd", delta->tm_yday);
8811014Sbill }
8821014Sbill 
88318606Sedward /*
88418606Sedward  * print idle time in long format with care being taken not to pluralize
88518606Sedward  * 1 minutes or 1 hours or 1 days.
88618606Sedward  * print "prefix" first.
8871014Sbill  */
88818606Sedward ltimeprint(before, dt, after)
88918606Sedward 	long *dt;
89018606Sedward 	char *before, *after;
8911014Sbill {
89218606Sedward 	register struct tm *delta;
8931014Sbill 
89418606Sedward 	delta = gmtime(dt);
89518606Sedward 	if (delta->tm_yday == 0 && delta->tm_hour == 0 && delta->tm_min == 0 &&
89618606Sedward 	    delta->tm_sec <= 10)
89718606Sedward 		return (0);
89818606Sedward 	printf("%s", before);
89918606Sedward 	if (delta->tm_yday >= 10)
90018606Sedward 		printf("%d days", delta->tm_yday);
90118606Sedward 	else if (delta->tm_yday > 0)
90218606Sedward 		printf("%d day%s %d hour%s",
90318606Sedward 			delta->tm_yday, delta->tm_yday == 1 ? "" : "s",
90418606Sedward 			delta->tm_hour, delta->tm_hour == 1 ? "" : "s");
90518606Sedward 	else
90618606Sedward 		if (delta->tm_hour >= 10)
90718606Sedward 			printf("%d hours", delta->tm_hour);
90818606Sedward 		else if (delta->tm_hour > 0)
90918606Sedward 			printf("%d hour%s %d minute%s",
91018606Sedward 				delta->tm_hour, delta->tm_hour == 1 ? "" : "s",
91118606Sedward 				delta->tm_min, delta->tm_min == 1 ? "" : "s");
91218606Sedward 		else
91318606Sedward 			if (delta->tm_min >= 10)
91418606Sedward 				printf("%2d minutes", delta->tm_min);
91518606Sedward 			else if (delta->tm_min == 0)
91618606Sedward 				printf("%2d seconds", delta->tm_sec);
91718606Sedward 			else
91818606Sedward 				printf("%d minute%s %d second%s",
91918606Sedward 					delta->tm_min,
92018606Sedward 					delta->tm_min == 1 ? "" : "s",
92118606Sedward 					delta->tm_sec,
92218606Sedward 					delta->tm_sec == 1 ? "" : "s");
92318606Sedward 	printf("%s", after);
9241014Sbill }
9251014Sbill 
92618606Sedward matchcmp(gname, login, given)
92718606Sedward 	register char *gname;
92818606Sedward 	char *login;
92918606Sedward 	char *given;
9301014Sbill {
93118606Sedward 	char buffer[100];
93218606Sedward 	register char *bp, *lp;
93318606Sedward 	register c;
9341014Sbill 
93518606Sedward 	if (*gname == ASTERISK)
93618606Sedward 		gname++;
93718606Sedward 	lp = 0;
93818606Sedward 	bp = buffer;
93918606Sedward 	for (;;)
94018606Sedward 		switch (c = *gname++) {
94118606Sedward 		case SAMENAME:
94218606Sedward 			for (lp = login; bp < buffer + sizeof buffer
94318606Sedward 					 && (*bp++ = *lp++);)
94418606Sedward 				;
94518606Sedward 			bp--;
94618606Sedward 			break;
94718606Sedward 		case ' ':
94818606Sedward 		case COMMA:
94918606Sedward 		case '\0':
95018606Sedward 			*bp = 0;
95118606Sedward 			if (namecmp(buffer, given))
95218606Sedward 				return (1);
95318606Sedward 			if (c == COMMA || c == 0)
95418606Sedward 				return (0);
95518606Sedward 			bp = buffer;
95618606Sedward 			break;
95718606Sedward 		default:
95818606Sedward 			if (bp < buffer + sizeof buffer)
95918606Sedward 				*bp++ = c;
9601014Sbill 		}
96118606Sedward 	/*NOTREACHED*/
9621014Sbill }
9631014Sbill 
96418606Sedward namecmp(name1, name2)
96518606Sedward 	register char *name1, *name2;
9661014Sbill {
96718606Sedward 	register c1, c2;
9681014Sbill 
96918606Sedward 	for (;;) {
97018606Sedward 		c1 = *name1++;
97118606Sedward 		if (islower(c1))
97218606Sedward 			c1 = toupper(c1);
97318606Sedward 		c2 = *name2++;
97418606Sedward 		if (islower(c2))
97518606Sedward 			c2 = toupper(c2);
97618606Sedward 		if (c1 != c2)
97718606Sedward 			break;
97818606Sedward 		if (c1 == 0)
97918606Sedward 			return (1);
9801014Sbill 	}
98118606Sedward 	if (!c1) {
98218606Sedward 		for (name2--; isdigit(*name2); name2++)
98318606Sedward 			;
98418606Sedward 		if (*name2 == 0)
98518606Sedward 			return (1);
98618606Sedward 	} else if (!c2) {
98718606Sedward 		for (name1--; isdigit(*name1); name1++)
98818606Sedward 			;
98918606Sedward 		if (*name2 == 0)
99018606Sedward 			return (1);
9911014Sbill 	}
99218606Sedward 	return (0);
9931014Sbill }
9941014Sbill 
99516469Ssam netfinger(name)
99618606Sedward 	char *name;
99716469Ssam {
99816469Ssam 	char *host;
99916469Ssam 	char fname[100];
100016469Ssam 	struct hostent *hp;
100116469Ssam 	struct servent *sp;
100218606Sedward 	struct sockaddr_in sin;
100316469Ssam 	int s;
100416469Ssam 	char *rindex();
100516469Ssam 	register FILE *f;
100616469Ssam 	register int c;
100716469Ssam 	register int lastc;
100816469Ssam 
100916469Ssam 	if (name == NULL)
101018606Sedward 		return (0);
101116469Ssam 	host = rindex(name, '@');
101216469Ssam 	if (host == NULL)
101318606Sedward 		return (0);
101416469Ssam 	*host++ = 0;
101516469Ssam 	hp = gethostbyname(host);
101616469Ssam 	if (hp == NULL) {
101716469Ssam 		static struct hostent def;
101816469Ssam 		static struct in_addr defaddr;
101925240Sbloom 		static char *alist[1];
102016469Ssam 		static char namebuf[128];
102116469Ssam 		int inet_addr();
102216469Ssam 
102316469Ssam 		defaddr.s_addr = inet_addr(host);
102416469Ssam 		if (defaddr.s_addr == -1) {
102516469Ssam 			printf("unknown host: %s\n", host);
102618606Sedward 			return (1);
102716469Ssam 		}
102816469Ssam 		strcpy(namebuf, host);
102916469Ssam 		def.h_name = namebuf;
103025239Ssam 		def.h_addr_list = alist, def.h_addr = (char *)&defaddr;
103116469Ssam 		def.h_length = sizeof (struct in_addr);
103216469Ssam 		def.h_addrtype = AF_INET;
103316469Ssam 		def.h_aliases = 0;
103416469Ssam 		hp = &def;
103516469Ssam 	}
103616469Ssam 	sp = getservbyname("finger", "tcp");
103716469Ssam 	if (sp == 0) {
103816469Ssam 		printf("tcp/finger: unknown service\n");
103918606Sedward 		return (1);
104016469Ssam 	}
104116469Ssam 	sin.sin_family = hp->h_addrtype;
104216469Ssam 	bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
104316469Ssam 	sin.sin_port = sp->s_port;
104416469Ssam 	s = socket(hp->h_addrtype, SOCK_STREAM, 0);
104516469Ssam 	if (s < 0) {
104616469Ssam 		perror("socket");
104718606Sedward 		return (1);
104816469Ssam 	}
104930958Sbostic 	printf("[%s]\n", hp->h_name);
105030958Sbostic 	fflush(stdout);
105116469Ssam 	if (connect(s, (char *)&sin, sizeof (sin)) < 0) {
105216469Ssam 		perror("connect");
105316469Ssam 		close(s);
105418606Sedward 		return (1);
105516469Ssam 	}
105616469Ssam 	if (large) write(s, "/W ", 3);
105716469Ssam 	write(s, name, strlen(name));
105816469Ssam 	write(s, "\r\n", 2);
105916469Ssam 	f = fdopen(s, "r");
106016469Ssam 	while ((c = getc(f)) != EOF) {
106116469Ssam 		switch(c) {
106216469Ssam 		case 0210:
106316469Ssam 		case 0211:
106416469Ssam 		case 0212:
106516469Ssam 		case 0214:
106616469Ssam 			c -= 0200;
106716469Ssam 			break;
106816469Ssam 		case 0215:
106916469Ssam 			c = '\n';
107016469Ssam 			break;
107116469Ssam 		}
107225589Sbloom 		lastc = c;
107325589Sbloom 		if (isprint(c) || isspace(c))
107425589Sbloom 			putchar(c);
107525589Sbloom 		else
107625589Sbloom 			putchar(c ^ 100);
107716469Ssam 	}
107816469Ssam 	if (lastc != '\n')
107916469Ssam 		putchar('\n');
108025121Sbloom 	(void)fclose(f);
108118606Sedward 	return (1);
108216469Ssam }
1083