xref: /csrg-svn/usr.bin/finger/finger.c (revision 18606)
113619Ssam #ifndef lint
2*18606Sedward static char sccsid[] = "@(#)finger.c	4.9 (Berkeley) 04/09/85";
313619Ssam #endif
41014Sbill 
5*18606Sedward /*
6*18606Sedward  * This is a finger program.  It prints out useful information about users
7*18606Sedward  * by digging it up from various system files.  It is not very portable
8*18606Sedward  * because the most useful parts of the information (the full user name,
9*18606Sedward  * office, and phone numbers) are all stored in the VAX-unused gecos field
10*18606Sedward  * of /etc/passwd, which, unfortunately, other UNIXes use for other things.
111014Sbill  *
12*18606Sedward  * There are three output formats, all of which give login name, teletype
13*18606Sedward  * line number, and login time.  The short output format is reminiscent
14*18606Sedward  * of finger on ITS, and gives one line of information per user containing
15*18606Sedward  * in addition to the minimum basic requirements (MBR), the full name of
16*18606Sedward  * the user, his idle time and office location and phone number.  The
17*18606Sedward  * quick style output is UNIX who-like, giving only name, teletype and
18*18606Sedward  * login time.  Finally, the long style output give the same information
19*18606Sedward  * as the short (in more legible format), the home directory and shell
20*18606Sedward  * of the user, and, if it exits, a copy of the file .plan in the users
21*18606Sedward  * home directory.  Finger may be called with or without a list of people
22*18606Sedward  * to finger -- if no list is given, all the people currently logged in
23*18606Sedward  * are fingered.
241014Sbill  *
25*18606Sedward  * The program is validly called by one of the following:
261014Sbill  *
271014Sbill  *	finger			{short form list of users}
281014Sbill  *	finger -l		{long form list of users}
291014Sbill  *	finger -b		{briefer long form list of users}
301014Sbill  *	finger -q		{quick list of users}
311014Sbill  *	finger -i		{quick list of users with idle times}
321014Sbill  *	finger namelist		{long format list of specified users}
331014Sbill  *	finger -s namelist	{short format list of specified users}
341014Sbill  *	finger -w namelist	{narrow short format list of specified users}
351014Sbill  *
36*18606Sedward  * where 'namelist' is a list of users login names.
37*18606Sedward  * The other options can all be given after one '-', or each can have its
38*18606Sedward  * own '-'.  The -f option disables the printing of headers for short and
39*18606Sedward  * quick outputs.  The -b option briefens long format outputs.  The -p
40*18606Sedward  * option turns off plans for long format outputs.
411014Sbill  */
421014Sbill 
43*18606Sedward #include <sys/types.h>
44*18606Sedward #include <sys/stat.h>
45*18606Sedward #include <utmp.h>
46*18606Sedward #include <sys/signal.h>
47*18606Sedward #include <pwd.h>
48*18606Sedward #include <stdio.h>
49*18606Sedward #include <lastlog.h>
50*18606Sedward #include <ctype.h>
51*18606Sedward #include <sys/time.h>
52*18606Sedward #include <sys/socket.h>
53*18606Sedward #include <netinet/in.h>
54*18606Sedward #include <netdb.h>
551014Sbill 
56*18606Sedward #define ASTERISK	'*'		/* ignore this in real name */
57*18606Sedward #define COMMA		','		/* separator in pw_gecos field */
58*18606Sedward #define COMMAND		'-'		/* command line flag char */
59*18606Sedward #define CORY		'C'		/* cory hall office */
60*18606Sedward #define EVANS		'E'		/* evans hall office */
61*18606Sedward #define SAMENAME	'&'		/* repeat login name in real name */
62*18606Sedward #define TALKABLE	0222		/* tty is writable if 222 mode */
631014Sbill 
64*18606Sedward struct utmp user;
65*18606Sedward #define NMAX sizeof(user.ut_name)
66*18606Sedward #define LMAX sizeof(user.ut_line)
67*18606Sedward #define HMAX sizeof(user.ut_host)
681014Sbill 
69*18606Sedward struct person {			/* one for each person fingered */
70*18606Sedward 	char *name;			/* name */
71*18606Sedward 	char tty[LMAX+1];		/* null terminated tty line */
72*18606Sedward 	char host[HMAX+1];		/* null terminated remote host name */
73*18606Sedward 	long loginat;			/* time of (last) login */
74*18606Sedward 	long idletime;			/* how long idle (if logged in) */
75*18606Sedward 	char *realname;			/* pointer to full name */
76*18606Sedward 	char *office;			/* pointer to office name */
77*18606Sedward 	char *officephone;		/* pointer to office phone no. */
78*18606Sedward 	char *homephone;		/* pointer to home phone no. */
79*18606Sedward 	char *random;			/* for any random stuff in pw_gecos */
80*18606Sedward 	struct passwd *pwd;		/* structure of /etc/passwd stuff */
81*18606Sedward 	char loggedin;			/* person is logged in */
82*18606Sedward 	char writable;			/* tty is writable */
83*18606Sedward 	char original;			/* this is not a duplicate entry */
84*18606Sedward 	struct person *link;		/* link to next person */
851014Sbill };
861014Sbill 
87*18606Sedward char LASTLOG[] = "/usr/adm/lastlog";	/* last login info */
88*18606Sedward char USERLOG[] = "/etc/utmp";		/* who is logged in */
89*18606Sedward char PLAN[] = "/.plan";			/* what plan file is */
90*18606Sedward char PROJ[] = "/.project";		/* what project file */
91*18606Sedward 
92*18606Sedward int unbrief = 1;			/* -b option default */
93*18606Sedward int header = 1;				/* -f option default */
94*18606Sedward int hack = 1;				/* -h option default */
95*18606Sedward int idle = 0;				/* -i option default */
96*18606Sedward int large = 0;				/* -l option default */
97*18606Sedward int match = 1;				/* -m option default */
98*18606Sedward int plan = 1;				/* -p option default */
99*18606Sedward int unquick = 1;			/* -q option default */
100*18606Sedward int small = 0;				/* -s option default */
101*18606Sedward int wide = 1;				/* -w option default */
1021014Sbill 
103*18606Sedward int unshort;
104*18606Sedward int lf;					/* LASTLOG file descriptor */
105*18606Sedward struct person *person1;			/* list of people */
106*18606Sedward long tloc;				/* current time */
1071014Sbill 
108*18606Sedward struct passwd *pwdcopy();
109*18606Sedward char *strcpy();
110*18606Sedward char *malloc();
111*18606Sedward char *ctime();
1121014Sbill 
113*18606Sedward main(argc, argv)
114*18606Sedward 	int argc;
115*18606Sedward 	register char **argv;
116*18606Sedward {
117*18606Sedward 	FILE *fp;
118*18606Sedward 	register char *s;
1191014Sbill 
120*18606Sedward 	/* parse command line for (optional) arguments */
121*18606Sedward 	while (*++argv && **argv == COMMAND)
122*18606Sedward 		for (s = *argv + 1; *s; s++)
123*18606Sedward 			switch (*s) {
124*18606Sedward 			case 'b':
125*18606Sedward 				unbrief = 0;
126*18606Sedward 				break;
127*18606Sedward 			case 'f':
128*18606Sedward 				header = 0;
129*18606Sedward 				break;
130*18606Sedward 			case 'h':
131*18606Sedward 				hack = 0;
132*18606Sedward 				break;
133*18606Sedward 			case 'i':
134*18606Sedward 				idle = 1;
135*18606Sedward 				unquick = 0;
136*18606Sedward 				break;
137*18606Sedward 			case 'l':
138*18606Sedward 				large = 1;
139*18606Sedward 				break;
140*18606Sedward 			case 'm':
141*18606Sedward 				match = 0;
142*18606Sedward 				break;
143*18606Sedward 			case 'p':
144*18606Sedward 				plan = 0;
145*18606Sedward 				break;
146*18606Sedward 			case 'q':
147*18606Sedward 				unquick = 0;
148*18606Sedward 				break;
149*18606Sedward 			case 's':
150*18606Sedward 				small = 1;
151*18606Sedward 				break;
152*18606Sedward 			case 'w':
153*18606Sedward 				wide = 0;
154*18606Sedward 				break;
155*18606Sedward 			default:
156*18606Sedward 				fprintf(stderr, "Usage: finger [-bfhilmpqsw] [login1 [login2 ...] ]\n");
157*18606Sedward 				exit(1);
158*18606Sedward 			}
159*18606Sedward 	if (unquick || idle)
160*18606Sedward 		time(&tloc);
161*18606Sedward 	/*
162*18606Sedward 	 * *argv == 0 means no names given
163*18606Sedward 	 */
164*18606Sedward 	if (*argv == 0)
165*18606Sedward 		doall();
166*18606Sedward 	else
167*18606Sedward 		donames(argv);
168*18606Sedward 	print();
169*18606Sedward 	exit(0);
170*18606Sedward }
1711014Sbill 
172*18606Sedward doall()
1731014Sbill {
174*18606Sedward 	register struct person *p;
175*18606Sedward 	register struct passwd *pw;
176*18606Sedward 	int uf;
177*18606Sedward 	char name[NMAX + 1];
1781014Sbill 
179*18606Sedward 	unshort = large;
180*18606Sedward 	if ((uf = open(USERLOG, 0)) < 0) {
181*18606Sedward 		fprintf(stderr, "finger: error opening %s\n", USERLOG);
182*18606Sedward 		exit(2);
1831014Sbill 	}
184*18606Sedward 	if (unquick) {
185*18606Sedward 		extern _pw_stayopen;
1861014Sbill 
1871014Sbill 		setpwent();
188*18606Sedward 		_pw_stayopen = 1;
1891014Sbill 		fwopen();
190*18606Sedward 	}
191*18606Sedward 	while (read(uf, (char *)&user, sizeof user) == sizeof user) {
192*18606Sedward 		if (user.ut_name[0] == 0)
193*18606Sedward 			continue;
194*18606Sedward 		if (person1 == 0)
195*18606Sedward 			p = person1 = (struct person *) malloc(sizeof *p);
196*18606Sedward 		else {
197*18606Sedward 			p->link = (struct person *) malloc(sizeof *p);
1981014Sbill 			p = p->link;
1991014Sbill 		}
200*18606Sedward 		bcopy(user.ut_name, name, NMAX);
201*18606Sedward 		name[NMAX] = 0;
202*18606Sedward 		bcopy(user.ut_line, p->tty, LMAX);
203*18606Sedward 		p->tty[LMAX] = 0;
204*18606Sedward 		bcopy(user.ut_host, p->host, HMAX);
205*18606Sedward 		p->host[HMAX] = 0;
206*18606Sedward 		p->loginat = user.ut_time;
207*18606Sedward 		p->pwd = 0;
208*18606Sedward 		p->loggedin = 1;
209*18606Sedward 		if (unquick && (pw = getpwnam(name))) {
210*18606Sedward 			p->pwd = pwdcopy(pw);
211*18606Sedward 			decode(p);
212*18606Sedward 			p->name = p->pwd->pw_name;
213*18606Sedward 		} else
214*18606Sedward 			p->name = strcpy(malloc(strlen(name) + 1), name);
215*18606Sedward 	}
216*18606Sedward 	if (unquick) {
2171014Sbill 		fwclose();
2181014Sbill 		endpwent();
2191014Sbill 	}
220*18606Sedward 	close(uf);
221*18606Sedward 	if (person1 == 0) {
222*18606Sedward 		printf("No one logged on\n");
223*18606Sedward 		exit(0);
224*18606Sedward 	}
225*18606Sedward 	p->link = 0;
226*18606Sedward }
2271014Sbill 
228*18606Sedward donames(argv)
229*18606Sedward 	char **argv;
230*18606Sedward {
231*18606Sedward 	register struct person *p;
232*18606Sedward 	register struct passwd *pw;
233*18606Sedward 	int uf;
2341014Sbill 
235*18606Sedward 	/*
236*18606Sedward 	 * get names from command line and check to see if they're
237*18606Sedward 	 * logged in
238*18606Sedward 	 */
239*18606Sedward 	unshort = !small;
240*18606Sedward 	for (; *argv != 0; argv++) {
241*18606Sedward 		if (netfinger(*argv))
242*18606Sedward 			continue;
243*18606Sedward 		if (person1 == 0)
244*18606Sedward 			p = person1 = (struct person *) malloc(sizeof *p);
245*18606Sedward 		else {
246*18606Sedward 			p->link = (struct person *) malloc(sizeof *p);
247*18606Sedward 			p = p->link;
24816469Ssam 		}
249*18606Sedward 		p->name = *argv;
2501014Sbill 		p->loggedin = 0;
251*18606Sedward 		p->original = 1;
252*18606Sedward 		p->pwd = 0;
253*18606Sedward 	}
254*18606Sedward 	p->link = 0;
255*18606Sedward 	/*
256*18606Sedward 	 * if we are doing it, read /etc/passwd for the useful info
257*18606Sedward 	 */
258*18606Sedward 	if (unquick) {
259*18606Sedward 		setpwent();
260*18606Sedward 		if (!match) {
261*18606Sedward 			extern _pw_stayopen;
2621014Sbill 
263*18606Sedward 			_pw_stayopen = 1;
264*18606Sedward 			for (p = person1; p != 0; p = p->link)
265*18606Sedward 				if (pw = getpwnam(p->name))
266*18606Sedward 					p->pwd = pwdcopy(pw);
267*18606Sedward 		} else while ((pw = getpwent()) != 0) {
268*18606Sedward 			for (p = person1; p != 0; p = p->link) {
269*18606Sedward 				if (!p->original)
270*18606Sedward 					continue;
271*18606Sedward 				if (strcmp(p->name, pw->pw_name) != 0 &&
272*18606Sedward 				    !matchcmp(pw->pw_gecos, pw->pw_name, p->name))
273*18606Sedward 					continue;
274*18606Sedward 				if (p->pwd == 0)
275*18606Sedward 					p->pwd = pwdcopy(pw);
276*18606Sedward 				else {
277*18606Sedward 					struct person *new;
278*18606Sedward 					/*
279*18606Sedward 					 * handle multiple login names, insert
280*18606Sedward 					 * new "duplicate" entry behind
281*18606Sedward 					 */
282*18606Sedward 					new = (struct person *)
283*18606Sedward 						malloc(sizeof *new);
284*18606Sedward 					new->pwd = pwdcopy(pw);
285*18606Sedward 					new->name = p->name;
286*18606Sedward 					new->original = 1;
287*18606Sedward 					new->loggedin = 0;
288*18606Sedward 					new->link = p->link;
289*18606Sedward 					p->original = 0;
290*18606Sedward 					p->link = new;
291*18606Sedward 					p = new;
292*18606Sedward 				}
2931014Sbill 			}
2941014Sbill 		}
2951014Sbill 		endpwent();
296*18606Sedward 	}
297*18606Sedward 	/* Now get login information */
298*18606Sedward 	if ((uf = open(USERLOG, 0)) < 0) {
299*18606Sedward 		fprintf(stderr, "finger: error opening %s\n", USERLOG);
300*18606Sedward 		exit(2);
301*18606Sedward 	}
302*18606Sedward 	while (read(uf, (char *)&user, sizeof user) == sizeof user) {
303*18606Sedward 		if (*user.ut_name == 0)
304*18606Sedward 			continue;
305*18606Sedward 		for (p = person1; p != 0; p = p->link) {
306*18606Sedward 			if (p->loggedin == 2)
307*18606Sedward 				continue;
308*18606Sedward 			if (strncmp(p->pwd ? p->pwd->pw_name : p->name,
309*18606Sedward 				    user.ut_name, NMAX) != 0)
310*18606Sedward 				continue;
311*18606Sedward 			if (p->loggedin == 0) {
312*18606Sedward 				bcopy(user.ut_line, p->tty, LMAX);
313*18606Sedward 				p->tty[LMAX] = 0;
314*18606Sedward 				bcopy(user.ut_host, p->host, HMAX);
315*18606Sedward 				p->host[HMAX] = 0;
316*18606Sedward 				p->loginat = user.ut_time;
317*18606Sedward 				p->loggedin = 1;
318*18606Sedward 			} else {	/* p->loggedin == 1 */
319*18606Sedward 				struct person *new;
320*18606Sedward 				new = (struct person *) malloc(sizeof *new);
321*18606Sedward 				new->name = p->name;
322*18606Sedward 				bcopy(user.ut_line, new->tty, LMAX);
323*18606Sedward 				new->tty[LMAX] = 0;
324*18606Sedward 				bcopy(user.ut_host, new->host, HMAX);
325*18606Sedward 				new->host[HMAX] = 0;
326*18606Sedward 				new->loginat = user.ut_time;
327*18606Sedward 				new->pwd = p->pwd;
328*18606Sedward 				new->loggedin = 1;
329*18606Sedward 				new->original = 0;
330*18606Sedward 				new->link = p->link;
331*18606Sedward 				p->loggedin = 2;
332*18606Sedward 				p->link = new;
333*18606Sedward 				p = new;
3341014Sbill 			}
3351014Sbill 		}
336*18606Sedward 	}
337*18606Sedward 	close(uf);
338*18606Sedward 	if (unquick) {
3391014Sbill 		fwopen();
340*18606Sedward 		for (p = person1; p != 0; p = p->link)
341*18606Sedward 			decode(p);
3421014Sbill 		fwclose();
3431014Sbill 	}
344*18606Sedward }
3451014Sbill 
346*18606Sedward print()
347*18606Sedward {
348*18606Sedward 	register FILE *fp;
349*18606Sedward 	register struct person *p;
350*18606Sedward 	register char *s;
351*18606Sedward 	register c;
3521014Sbill 
353*18606Sedward 	/*
354*18606Sedward 	 * print out what we got
355*18606Sedward 	 */
356*18606Sedward 	if (header) {
357*18606Sedward 		if (unquick) {
358*18606Sedward 			if (!unshort)
359*18606Sedward 				if (wide)
360*18606Sedward 					printf("Login       Name              TTY Idle    When            Office\n");
361*18606Sedward 				else
362*18606Sedward 					printf("Login    TTY Idle    When            Office\n");
363*18606Sedward 		} else {
364*18606Sedward 			printf("Login      TTY            When");
365*18606Sedward 			if (idle)
366*18606Sedward 				printf("             Idle");
367*18606Sedward 			putchar('\n');
3681014Sbill 		}
369*18606Sedward 	}
370*18606Sedward 	for (p = person1; p != 0; p = p->link) {
371*18606Sedward 		if (!unquick) {
372*18606Sedward 			quickprint(p);
373*18606Sedward 			continue;
3741014Sbill 		}
375*18606Sedward 		if (!unshort) {
376*18606Sedward 			shortprint(p);
377*18606Sedward 			continue;
378*18606Sedward 		}
379*18606Sedward 		personprint(p);
380*18606Sedward 		if (p->pwd != 0) {
381*18606Sedward 			if (hack) {
382*18606Sedward 				s = malloc(strlen(p->pwd->pw_dir) +
383*18606Sedward 					sizeof PROJ);
384*18606Sedward 				strcpy(s, p->pwd->pw_dir);
385*18606Sedward 				strcat(s, PROJ);
386*18606Sedward 				if ((fp = fopen(s, "r")) != 0) {
387*18606Sedward 					printf("Project: ");
388*18606Sedward 					while ((c = getc(fp)) != EOF) {
389*18606Sedward 						if (c == '\n')
390*18606Sedward 							break;
391*18606Sedward 						putchar(c);
392*18606Sedward 					}
393*18606Sedward 					fclose(fp);
394*18606Sedward 					putchar('\n');
3951014Sbill 				}
396*18606Sedward 				free(s);
3971014Sbill 			}
398*18606Sedward 			if (plan) {
399*18606Sedward 				s = malloc(strlen(p->pwd->pw_dir) +
400*18606Sedward 					sizeof PLAN);
401*18606Sedward 				strcpy(s, p->pwd->pw_dir);
402*18606Sedward 				strcat(s, PLAN);
403*18606Sedward 				if ((fp = fopen(s, "r")) == 0)
404*18606Sedward 					printf("No Plan.\n");
405*18606Sedward 				else {
406*18606Sedward 					printf("Plan:\n");
407*18606Sedward 					while ((c = getc(fp)) != EOF)
408*18606Sedward 						putchar(c);
409*18606Sedward 					fclose(fp);
4101014Sbill 				}
411*18606Sedward 				free(s);
4121014Sbill 			}
4131014Sbill 		}
414*18606Sedward 		if (p->link != 0)
415*18606Sedward 			putchar('\n');
416*18606Sedward 	}
4171014Sbill }
4181014Sbill 
419*18606Sedward /*
420*18606Sedward  * Duplicate a pwd entry.
421*18606Sedward  * Note: Only the useful things (what the program currently uses) are copied.
4221014Sbill  */
423*18606Sedward struct passwd *
424*18606Sedward pwdcopy(pfrom)
425*18606Sedward 	register struct passwd *pfrom;
426*18606Sedward {
427*18606Sedward 	register struct passwd *pto;
4281014Sbill 
429*18606Sedward 	pto = (struct passwd *) malloc(sizeof *pto);
430*18606Sedward #define savestr(s) strcpy(malloc(strlen(s) + 1), s)
431*18606Sedward 	pto->pw_name = savestr(pfrom->pw_name);
4321014Sbill 	pto->pw_uid = pfrom->pw_uid;
433*18606Sedward 	pto->pw_gecos = savestr(pfrom->pw_gecos);
434*18606Sedward 	pto->pw_dir = savestr(pfrom->pw_dir);
435*18606Sedward 	pto->pw_shell = savestr(pfrom->pw_shell);
436*18606Sedward #undef savestr
437*18606Sedward 	return pto;
4381014Sbill }
4391014Sbill 
440*18606Sedward /*
441*18606Sedward  * print out information on quick format giving just name, tty, login time
442*18606Sedward  * and idle time if idle is set.
4431014Sbill  */
444*18606Sedward quickprint(pers)
445*18606Sedward 	register struct person *pers;
4461014Sbill {
447*18606Sedward 	printf("%-*.*s  ", NMAX, NMAX, pers->name);
448*18606Sedward 	if (pers->loggedin) {
449*18606Sedward 		if (idle) {
450*18606Sedward 			findidle(pers);
451*18606Sedward 			printf("%c%-*s %-16.16s", pers->writable ? ' ' : '*',
452*18606Sedward 				LMAX, pers->tty, ctime(&pers->loginat));
453*18606Sedward 			ltimeprint("   ", &pers->idletime, "");
454*18606Sedward 		} else
455*18606Sedward 			printf(" %-*s %-16.16s", LMAX,
456*18606Sedward 				pers->tty, ctime(&pers->loginat));
457*18606Sedward 		putchar('\n');
458*18606Sedward 	} else
459*18606Sedward 		printf("          Not Logged In\n");
4601014Sbill }
4611014Sbill 
462*18606Sedward /*
463*18606Sedward  * print out information in short format, giving login name, full name,
464*18606Sedward  * tty, idle time, login time, office location and phone.
4651014Sbill  */
466*18606Sedward shortprint(pers)
467*18606Sedward 	register struct person *pers;
4681014Sbill {
469*18606Sedward 	char *p;
470*18606Sedward 	char dialup;
4711014Sbill 
472*18606Sedward 	if (pers->pwd == 0) {
473*18606Sedward 		printf("%-15s       ???\n", pers->name);
474*18606Sedward 		return;
4751014Sbill 	}
476*18606Sedward 	printf("%-*s", NMAX, pers->pwd->pw_name);
4771014Sbill 	dialup = 0;
478*18606Sedward 	if (wide) {
479*18606Sedward 		if (pers->realname)
480*18606Sedward 			printf(" %-20.20s", pers->realname);
481*18606Sedward 		else
482*18606Sedward 			printf("        ???          ");
4831014Sbill 	}
484*18606Sedward 	putchar(' ');
485*18606Sedward 	if (pers->loggedin && !pers->writable)
486*18606Sedward 		putchar('*');
487*18606Sedward 	else
488*18606Sedward 		putchar(' ');
489*18606Sedward 	if (*pers->tty) {
490*18606Sedward 		if (pers->tty[0] == 't' && pers->tty[1] == 't' &&
491*18606Sedward 		    pers->tty[2] == 'y') {
492*18606Sedward 			if (pers->tty[3] == 'd' && pers->loggedin)
493*18606Sedward 				dialup = 1;
494*18606Sedward 			printf("%-2.2s ", pers->tty + 3);
495*18606Sedward 		} else
496*18606Sedward 			printf("%-2.2s ", pers->tty);
497*18606Sedward 	} else
498*18606Sedward 		printf("   ");
499*18606Sedward 	p = ctime(&pers->loginat);
500*18606Sedward 	if (pers->loggedin) {
501*18606Sedward 		stimeprint(&pers->idletime);
502*18606Sedward 		printf(" %3.3s %-5.5s ", p, p + 11);
503*18606Sedward 	} else if (pers->loginat == 0)
504*18606Sedward 		printf(" < .  .  .  . >");
5058842Smckusick 	else if (tloc - pers->loginat >= 180 * 24 * 60 * 60)
506*18606Sedward 		printf(" <%-6.6s, %-4.4s>", p + 4, p + 20);
5078842Smckusick 	else
508*18606Sedward 		printf(" <%-12.12s>", p + 4);
509*18606Sedward 	if (dialup && pers->homephone)
510*18606Sedward 		printf(" %20s", pers->homephone);
511*18606Sedward 	else {
512*18606Sedward 		if (pers->office)
513*18606Sedward 			printf(" %-11.11s", pers->office);
514*18606Sedward 		else if (pers->officephone || pers->homephone)
515*18606Sedward 			printf("            ");
516*18606Sedward 		if (pers->officephone)
517*18606Sedward 			printf(" %s", pers->officephone);
518*18606Sedward 		else if (pers->homephone)
519*18606Sedward 			printf(" %s", pers->homephone);
5201014Sbill 	}
521*18606Sedward 	putchar('\n');
5221014Sbill }
5231014Sbill 
524*18606Sedward /*
525*18606Sedward  * print out a person in long format giving all possible information.
526*18606Sedward  * directory and shell are inhibited if unbrief is clear.
5271014Sbill  */
528*18606Sedward personprint(pers)
529*18606Sedward 	register struct person *pers;
5301014Sbill {
531*18606Sedward 	if (pers->pwd == 0) {
532*18606Sedward 		printf("Login name: %-10s\t\t\tIn real life: ???\n",
533*18606Sedward 			pers->name);
534*18606Sedward 		return;
5351014Sbill 	}
536*18606Sedward 	printf("Login name: %-10s", pers->pwd->pw_name);
537*18606Sedward 	if (pers->loggedin && !pers->writable)
538*18606Sedward 		printf("	(messages off)	");
539*18606Sedward 	else
540*18606Sedward 		printf("			");
541*18606Sedward 	if (pers->realname)
542*18606Sedward 		printf("In real life: %s", pers->realname);
543*18606Sedward 	if (pers->office) {
544*18606Sedward 		printf("\nOffice: %-.11s", pers->office);
545*18606Sedward 		if (pers->officephone) {
546*18606Sedward 			printf(", %s", pers->officephone);
547*18606Sedward 			if (pers->homephone)
548*18606Sedward 				printf("\t\tHome phone: %s", pers->homephone);
549*18606Sedward 			else if (pers->random)
550*18606Sedward 				printf("\t\t%s", pers->random);
551*18606Sedward 		} else
552*18606Sedward 			if (pers->homephone)
553*18606Sedward 				printf("\t\t\tHome phone: %s", pers->homephone);
554*18606Sedward 			else if (pers->random)
555*18606Sedward 				printf("\t\t\t%s", pers->random);
556*18606Sedward 	} else if (pers->officephone) {
557*18606Sedward 		printf("\nPhone: %s", pers->officephone);
558*18606Sedward 		if (pers->homephone)
559*18606Sedward 			printf(", %s", pers->homephone);
560*18606Sedward 		if (pers->random)
561*18606Sedward 			printf(", %s", pers->random);
562*18606Sedward 	} else if (pers->homephone) {
563*18606Sedward 		printf("\nPhone: %s", pers->homephone);
564*18606Sedward 		if (pers->random)
565*18606Sedward 			printf(", %s", pers->random);
566*18606Sedward 	} else if (pers->random)
567*18606Sedward 		printf("\n%s", pers->random);
568*18606Sedward 	if (unbrief) {
569*18606Sedward 		printf("\nDirectory: %-25s", pers->pwd->pw_dir);
570*18606Sedward 		if (*pers->pwd->pw_shell)
571*18606Sedward 			printf("\tShell: %-s", pers->pwd->pw_shell);
5721014Sbill 	}
573*18606Sedward 	if (pers->loggedin) {
574*18606Sedward 		register char *ep = ctime(&pers->loginat);
575*18606Sedward 		if (*pers->host) {
576*18606Sedward 			printf("\nOn since %15.15s on %s from %s",
577*18606Sedward 				&ep[4], pers->tty, pers->host);
578*18606Sedward 			ltimeprint("\n", &pers->idletime, " Idle Time");
579*18606Sedward 		} else {
580*18606Sedward 			printf("\nOn since %15.15s on %-*s",
581*18606Sedward 				&ep[4], LMAX, pers->tty);
582*18606Sedward 			ltimeprint("\t", &pers->idletime, " Idle Time");
5831014Sbill 		}
584*18606Sedward 	} else if (pers->loginat == 0)
585*18606Sedward 		printf("\nNever logged in.");
5868842Smckusick 	else if (tloc - pers->loginat > 180 * 24 * 60 * 60) {
587*18606Sedward 		register char *ep = ctime(&pers->loginat);
588*18606Sedward 		printf("\nLast login %10.10s, %4.4s on %s",
589*18606Sedward 			ep, ep+20, pers->tty);
590*18606Sedward 		if (*pers->host)
591*18606Sedward 			printf(" from %s", pers->host);
592*18606Sedward 	} else {
593*18606Sedward 		register char *ep = ctime(&pers->loginat);
594*18606Sedward 		printf("\nLast login %16.16s on %s", ep, pers->tty);
595*18606Sedward 		if (*pers->host)
596*18606Sedward 			printf(" from %s", pers->host);
5978842Smckusick 	}
598*18606Sedward 	putchar('\n');
5991014Sbill }
6001014Sbill 
6011014Sbill /*
6021014Sbill  *  very hacky section of code to format phone numbers.  filled with
6031014Sbill  *  magic constants like 4, 7 and 10.
6041014Sbill  */
605*18606Sedward char *
606*18606Sedward phone(s, len, alldigits)
607*18606Sedward 	register char *s;
608*18606Sedward 	int len;
609*18606Sedward 	char alldigits;
6101014Sbill {
611*18606Sedward 	char fonebuf[15];
612*18606Sedward 	register char *p = fonebuf;
613*18606Sedward 	register i;
6141014Sbill 
615*18606Sedward 	if (!alldigits)
616*18606Sedward 		return (strcpy(malloc(len + 1), s));
617*18606Sedward 	switch (len) {
618*18606Sedward 	case 4:
619*18606Sedward 		*p++ = ' ';
620*18606Sedward 		*p++ = 'x';
621*18606Sedward 		*p++ = '2';
622*18606Sedward 		*p++ = '-';
623*18606Sedward 		for (i = 0; i < 4; i++)
624*18606Sedward 			*p++ = *s++;
6251014Sbill 		break;
626*18606Sedward 	case 7:
627*18606Sedward 		for (i = 0; i < 3; i++)
628*18606Sedward 			*p++ = *s++;
629*18606Sedward 		*p++ = '-';
630*18606Sedward 		for (i = 0; i < 4; i++)
631*18606Sedward 			*p++ = *s++;
6321014Sbill 		break;
633*18606Sedward 	case 10:
634*18606Sedward 		for (i = 0; i < 3; i++)
635*18606Sedward 			*p++ = *s++;
636*18606Sedward 		*p++ = '-';
637*18606Sedward 		for (i = 0; i < 3; i++)
638*18606Sedward 			*p++ = *s++;
639*18606Sedward 		*p++ = '-';
640*18606Sedward 		for (i = 0; i < 4; i++)
641*18606Sedward 			*p++ = *s++;
6421014Sbill 		break;
643*18606Sedward 	case 0:
644*18606Sedward 		return 0;
645*18606Sedward 	default:
646*18606Sedward 		return (strcpy(malloc(len + 1), s));
6471014Sbill 	}
648*18606Sedward 	*p++ = 0;
649*18606Sedward 	return (strcpy(malloc(p - fonebuf), fonebuf));
6501014Sbill }
6511014Sbill 
652*18606Sedward /*
653*18606Sedward  * decode the information in the gecos field of /etc/passwd
6541014Sbill  */
655*18606Sedward decode(pers)
656*18606Sedward 	register struct person *pers;
6571014Sbill {
658*18606Sedward 	char buffer[256];
659*18606Sedward 	register char *bp, *gp, *lp;
660*18606Sedward 	int alldigits;
661*18606Sedward 	int hasspace;
662*18606Sedward 	int len;
6631014Sbill 
664*18606Sedward 	pers->realname = 0;
665*18606Sedward 	pers->office = 0;
666*18606Sedward 	pers->officephone = 0;
667*18606Sedward 	pers->homephone = 0;
668*18606Sedward 	pers->random = 0;
669*18606Sedward 	if (pers->pwd == 0)
670*18606Sedward 		return;
671*18606Sedward 	gp = pers->pwd->pw_gecos;
672*18606Sedward 	bp = buffer;
673*18606Sedward 	if (*gp == ASTERISK)
6741014Sbill 		gp++;
675*18606Sedward 	while (*gp && *gp != COMMA)			/* name */
676*18606Sedward 		if (*gp == SAMENAME) {
677*18606Sedward 			lp = pers->pwd->pw_name;
678*18606Sedward 			if (islower(*lp))
679*18606Sedward 				*bp++ = toupper(*lp++);
680*18606Sedward 			while (*bp++ = *lp++)
681*18606Sedward 				;
682*18606Sedward 			bp--;
683*18606Sedward 			gp++;
684*18606Sedward 		} else
685*18606Sedward 			*bp++ = *gp++;
686*18606Sedward 	*bp++ = 0;
687*18606Sedward 	if ((len = bp - buffer) > 1)
688*18606Sedward 		pers->realname = strcpy(malloc(len), buffer);
689*18606Sedward 	if (*gp == COMMA) {				/* office */
690*18606Sedward 		gp++;
691*18606Sedward 		hasspace = 0;
692*18606Sedward 		bp = buffer;
693*18606Sedward 		while (*gp && *gp != COMMA) {
694*18606Sedward 			*bp = *gp++;
695*18606Sedward 			if (*bp == ' ')
696*18606Sedward 				hasspace = 1;
697*18606Sedward 			/* leave 5 for Cory and Evans expansion */
698*18606Sedward 			if (bp < buffer + sizeof buffer - 6)
699*18606Sedward 				bp++;
7001014Sbill 		}
701*18606Sedward 		*bp = 0;
702*18606Sedward 		len = bp - buffer;
703*18606Sedward 		bp--;			/* point to last character */
704*18606Sedward 		if (hasspace || len == 0)
705*18606Sedward 			len++;
706*18606Sedward 		else if (*bp == CORY) {
707*18606Sedward 			strcpy(bp, " Cory");
708*18606Sedward 			len += 5;
709*18606Sedward 		} else if (*bp == EVANS) {
710*18606Sedward 			strcpy(bp, " Evans");
711*18606Sedward 			len += 6;
712*18606Sedward 		} else
713*18606Sedward 			len++;
714*18606Sedward 		if (len > 1)
715*18606Sedward 			pers->office = strcpy(malloc(len), buffer);
716*18606Sedward 	}
717*18606Sedward 	if (*gp == COMMA) {				/* office phone */
718*18606Sedward 		gp++;
719*18606Sedward 		bp = buffer;
720*18606Sedward 		alldigits = 1;
721*18606Sedward 		while (*gp && *gp != COMMA) {
722*18606Sedward 			*bp = *gp++;
723*18606Sedward 			if (!isdigit(*bp))
724*18606Sedward 				alldigits = 0;
725*18606Sedward 			if (bp < buffer + sizeof buffer - 1)
726*18606Sedward 				bp++;
7271014Sbill 		}
728*18606Sedward 		*bp = 0;
729*18606Sedward 		pers->officephone = phone(buffer, bp - buffer, alldigits);
730*18606Sedward 	}
731*18606Sedward 	if (*gp == COMMA) {				/* home phone */
7321014Sbill 		gp++;
733*18606Sedward 		bp = buffer;
7341014Sbill 		alldigits = 1;
735*18606Sedward 		while (*gp && *gp != COMMA) {
7361014Sbill 			*bp = *gp++;
737*18606Sedward 			if (!isdigit(*bp))
738*18606Sedward 				alldigits = 0;
739*18606Sedward 			if (bp < buffer + sizeof buffer - 1)
7401014Sbill 				bp++;
7411014Sbill 		}
742*18606Sedward 		*bp = 0;
743*18606Sedward 		pers->homephone = phone(buffer, bp - buffer, alldigits);
7441014Sbill 	}
745*18606Sedward 	if (pers->loggedin)
746*18606Sedward 		findidle(pers);
747*18606Sedward 	else
748*18606Sedward 		findwhen(pers);
7491014Sbill }
7501014Sbill 
751*18606Sedward /*
752*18606Sedward  * find the last log in of a user by checking the LASTLOG file.
753*18606Sedward  * the entry is indexed by the uid, so this can only be done if
754*18606Sedward  * the uid is known (which it isn't in quick mode)
7551014Sbill  */
7561014Sbill 
7571014Sbill fwopen()
7581014Sbill {
759*18606Sedward 	if ((lf = open(LASTLOG, 0)) < 0)
760*18606Sedward 		fprintf(stderr, "finger: %s open error\n", LASTLOG);
7611014Sbill }
7621014Sbill 
763*18606Sedward findwhen(pers)
764*18606Sedward 	register struct person *pers;
7651014Sbill {
766*18606Sedward 	struct lastlog ll;
767*18606Sedward 	int i;
7681014Sbill 
769*18606Sedward 	if (lf >= 0) {
770*18606Sedward 		lseek(lf, (long)pers->pwd->pw_uid * sizeof ll, 0);
771*18606Sedward 		if ((i = read(lf, (char *)&ll, sizeof ll)) == sizeof ll) {
772*18606Sedward 			bcopy(ll.ll_line, pers->tty, LMAX);
773*18606Sedward 			pers->tty[LMAX] = 0;
774*18606Sedward 			bcopy(ll.ll_host, pers->host, HMAX);
775*18606Sedward 			pers->host[HMAX] = 0;
776*18606Sedward 			pers->loginat = ll.ll_time;
777*18606Sedward 		} else {
778*18606Sedward 			if (i != 0)
779*18606Sedward 				fprintf(stderr, "finger: %s read error\n",
780*18606Sedward 					LASTLOG);
781*18606Sedward 			pers->tty[0] = 0;
782*18606Sedward 			pers->host[0] = 0;
783*18606Sedward 			pers->loginat = 0L;
784*18606Sedward 		}
785*18606Sedward 	} else {
786*18606Sedward 		pers->tty[0] = 0;
787*18606Sedward 		pers->host[0] = 0;
7881014Sbill 		pers->loginat = 0L;
7891014Sbill 	}
7901014Sbill }
7911014Sbill 
7921014Sbill fwclose()
7931014Sbill {
794*18606Sedward 	if (lf >= 0)
795*18606Sedward 		close(lf);
7961014Sbill }
7971014Sbill 
798*18606Sedward /*
799*18606Sedward  * find the idle time of a user by doing a stat on /dev/tty??,
800*18606Sedward  * where tty?? has been gotten from USERLOG, supposedly.
8011014Sbill  */
802*18606Sedward findidle(pers)
803*18606Sedward 	register struct person *pers;
8041014Sbill {
805*18606Sedward 	struct stat ttystatus;
806*18606Sedward 	static char buffer[20] = "/dev/";
807*18606Sedward 	long t;
808*18606Sedward #define TTYLEN 5
8091014Sbill 
810*18606Sedward 	strcpy(buffer + TTYLEN, pers->tty);
811*18606Sedward 	buffer[TTYLEN+LMAX] = 0;
812*18606Sedward 	if (stat(buffer, &ttystatus) < 0) {
813*18606Sedward 		fprintf(stderr, "finger: Can't stat %s\n", buffer);
814*18606Sedward 		exit(4);
815*18606Sedward 	}
816*18606Sedward 	time(&t);
817*18606Sedward 	if (t < ttystatus.st_atime)
8181014Sbill 		pers->idletime = 0L;
819*18606Sedward 	else
820*18606Sedward 		pers->idletime = t - ttystatus.st_atime;
821*18606Sedward 	pers->writable = (ttystatus.st_mode & TALKABLE) == TALKABLE;
8221014Sbill }
8231014Sbill 
824*18606Sedward /*
825*18606Sedward  * print idle time in short format; this program always prints 4 characters;
826*18606Sedward  * if the idle time is zero, it prints 4 blanks.
8271014Sbill  */
828*18606Sedward stimeprint(dt)
829*18606Sedward 	long *dt;
8301014Sbill {
831*18606Sedward 	register struct tm *delta;
8321014Sbill 
833*18606Sedward 	delta = gmtime(dt);
834*18606Sedward 	if (delta->tm_yday == 0)
835*18606Sedward 		if (delta->tm_hour == 0)
836*18606Sedward 			if (delta->tm_min == 0)
837*18606Sedward 				printf("    ");
838*18606Sedward 			else
839*18606Sedward 				printf("  %2d", delta->tm_min);
840*18606Sedward 		else
841*18606Sedward 			if (delta->tm_hour >= 10)
842*18606Sedward 				printf("%3d:", delta->tm_hour);
843*18606Sedward 			else
844*18606Sedward 				printf("%1d:%02d",
845*18606Sedward 					delta->tm_hour, delta->tm_min);
846*18606Sedward 	else
847*18606Sedward 		printf("%3dd", delta->tm_yday);
8481014Sbill }
8491014Sbill 
850*18606Sedward /*
851*18606Sedward  * print idle time in long format with care being taken not to pluralize
852*18606Sedward  * 1 minutes or 1 hours or 1 days.
853*18606Sedward  * print "prefix" first.
8541014Sbill  */
855*18606Sedward ltimeprint(before, dt, after)
856*18606Sedward 	long *dt;
857*18606Sedward 	char *before, *after;
8581014Sbill {
859*18606Sedward 	register struct tm *delta;
8601014Sbill 
861*18606Sedward 	delta = gmtime(dt);
862*18606Sedward 	if (delta->tm_yday == 0 && delta->tm_hour == 0 && delta->tm_min == 0 &&
863*18606Sedward 	    delta->tm_sec <= 10)
864*18606Sedward 		return (0);
865*18606Sedward 	printf("%s", before);
866*18606Sedward 	if (delta->tm_yday >= 10)
867*18606Sedward 		printf("%d days", delta->tm_yday);
868*18606Sedward 	else if (delta->tm_yday > 0)
869*18606Sedward 		printf("%d day%s %d hour%s",
870*18606Sedward 			delta->tm_yday, delta->tm_yday == 1 ? "" : "s",
871*18606Sedward 			delta->tm_hour, delta->tm_hour == 1 ? "" : "s");
872*18606Sedward 	else
873*18606Sedward 		if (delta->tm_hour >= 10)
874*18606Sedward 			printf("%d hours", delta->tm_hour);
875*18606Sedward 		else if (delta->tm_hour > 0)
876*18606Sedward 			printf("%d hour%s %d minute%s",
877*18606Sedward 				delta->tm_hour, delta->tm_hour == 1 ? "" : "s",
878*18606Sedward 				delta->tm_min, delta->tm_min == 1 ? "" : "s");
879*18606Sedward 		else
880*18606Sedward 			if (delta->tm_min >= 10)
881*18606Sedward 				printf("%2d minutes", delta->tm_min);
882*18606Sedward 			else if (delta->tm_min == 0)
883*18606Sedward 				printf("%2d seconds", delta->tm_sec);
884*18606Sedward 			else
885*18606Sedward 				printf("%d minute%s %d second%s",
886*18606Sedward 					delta->tm_min,
887*18606Sedward 					delta->tm_min == 1 ? "" : "s",
888*18606Sedward 					delta->tm_sec,
889*18606Sedward 					delta->tm_sec == 1 ? "" : "s");
890*18606Sedward 	printf("%s", after);
8911014Sbill }
8921014Sbill 
893*18606Sedward matchcmp(gname, login, given)
894*18606Sedward 	register char *gname;
895*18606Sedward 	char *login;
896*18606Sedward 	char *given;
8971014Sbill {
898*18606Sedward 	char buffer[100];
899*18606Sedward 	register char *bp, *lp;
900*18606Sedward 	register c;
9011014Sbill 
902*18606Sedward 	if (*gname == ASTERISK)
903*18606Sedward 		gname++;
904*18606Sedward 	lp = 0;
905*18606Sedward 	bp = buffer;
906*18606Sedward 	for (;;)
907*18606Sedward 		switch (c = *gname++) {
908*18606Sedward 		case SAMENAME:
909*18606Sedward 			for (lp = login; bp < buffer + sizeof buffer
910*18606Sedward 					 && (*bp++ = *lp++);)
911*18606Sedward 				;
912*18606Sedward 			bp--;
913*18606Sedward 			break;
914*18606Sedward 		case ' ':
915*18606Sedward 		case COMMA:
916*18606Sedward 		case '\0':
917*18606Sedward 			*bp = 0;
918*18606Sedward 			if (namecmp(buffer, given))
919*18606Sedward 				return (1);
920*18606Sedward 			if (c == COMMA || c == 0)
921*18606Sedward 				return (0);
922*18606Sedward 			bp = buffer;
923*18606Sedward 			break;
924*18606Sedward 		default:
925*18606Sedward 			if (bp < buffer + sizeof buffer)
926*18606Sedward 				*bp++ = c;
9271014Sbill 		}
928*18606Sedward 	/*NOTREACHED*/
9291014Sbill }
9301014Sbill 
931*18606Sedward namecmp(name1, name2)
932*18606Sedward 	register char *name1, *name2;
9331014Sbill {
934*18606Sedward 	register c1, c2;
9351014Sbill 
936*18606Sedward 	for (;;) {
937*18606Sedward 		c1 = *name1++;
938*18606Sedward 		if (islower(c1))
939*18606Sedward 			c1 = toupper(c1);
940*18606Sedward 		c2 = *name2++;
941*18606Sedward 		if (islower(c2))
942*18606Sedward 			c2 = toupper(c2);
943*18606Sedward 		if (c1 != c2)
944*18606Sedward 			break;
945*18606Sedward 		if (c1 == 0)
946*18606Sedward 			return (1);
9471014Sbill 	}
948*18606Sedward 	if (!c1) {
949*18606Sedward 		for (name2--; isdigit(*name2); name2++)
950*18606Sedward 			;
951*18606Sedward 		if (*name2 == 0)
952*18606Sedward 			return (1);
953*18606Sedward 	} else if (!c2) {
954*18606Sedward 		for (name1--; isdigit(*name1); name1++)
955*18606Sedward 			;
956*18606Sedward 		if (*name2 == 0)
957*18606Sedward 			return (1);
9581014Sbill 	}
959*18606Sedward 	return (0);
9601014Sbill }
9611014Sbill 
96216469Ssam netfinger(name)
963*18606Sedward 	char *name;
96416469Ssam {
96516469Ssam 	char *host;
96616469Ssam 	char fname[100];
96716469Ssam 	struct hostent *hp;
96816469Ssam 	struct servent *sp;
969*18606Sedward 	struct sockaddr_in sin;
97016469Ssam 	int s;
97116469Ssam 	char *rindex();
97216469Ssam 	register FILE *f;
97316469Ssam 	register int c;
97416469Ssam 	register int lastc;
97516469Ssam 
97616469Ssam 	if (name == NULL)
977*18606Sedward 		return (0);
97816469Ssam 	host = rindex(name, '@');
97916469Ssam 	if (host == NULL)
980*18606Sedward 		return (0);
98116469Ssam 	*host++ = 0;
98216469Ssam 	hp = gethostbyname(host);
98316469Ssam 	if (hp == NULL) {
98416469Ssam 		static struct hostent def;
98516469Ssam 		static struct in_addr defaddr;
98616469Ssam 		static char namebuf[128];
98716469Ssam 		int inet_addr();
98816469Ssam 
98916469Ssam 		defaddr.s_addr = inet_addr(host);
99016469Ssam 		if (defaddr.s_addr == -1) {
99116469Ssam 			printf("unknown host: %s\n", host);
992*18606Sedward 			return (1);
99316469Ssam 		}
99416469Ssam 		strcpy(namebuf, host);
99516469Ssam 		def.h_name = namebuf;
99616469Ssam 		def.h_addr = (char *)&defaddr;
99716469Ssam 		def.h_length = sizeof (struct in_addr);
99816469Ssam 		def.h_addrtype = AF_INET;
99916469Ssam 		def.h_aliases = 0;
100016469Ssam 		hp = &def;
100116469Ssam 	}
100216469Ssam 	printf("[%s]", hp->h_name);
100316469Ssam 	sp = getservbyname("finger", "tcp");
100416469Ssam 	if (sp == 0) {
100516469Ssam 		printf("tcp/finger: unknown service\n");
1006*18606Sedward 		return (1);
100716469Ssam 	}
100816469Ssam 	sin.sin_family = hp->h_addrtype;
100916469Ssam 	bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
101016469Ssam 	sin.sin_port = sp->s_port;
101116469Ssam 	s = socket(hp->h_addrtype, SOCK_STREAM, 0);
101216469Ssam 	if (s < 0) {
101316469Ssam 		fflush(stdout);
101416469Ssam 		perror("socket");
1015*18606Sedward 		return (1);
101616469Ssam 	}
101716469Ssam 	if (connect(s, (char *)&sin, sizeof (sin)) < 0) {
101816469Ssam 		fflush(stdout);
101916469Ssam 		perror("connect");
102016469Ssam 		close(s);
1021*18606Sedward 		return (1);
102216469Ssam 	}
102316469Ssam 	printf("\n");
102416469Ssam 	if (large) write(s, "/W ", 3);
102516469Ssam 	write(s, name, strlen(name));
102616469Ssam 	write(s, "\r\n", 2);
102716469Ssam 	f = fdopen(s, "r");
102816469Ssam 	while ((c = getc(f)) != EOF) {
102916469Ssam 		switch(c) {
103016469Ssam 		case 0210:
103116469Ssam 		case 0211:
103216469Ssam 		case 0212:
103316469Ssam 		case 0214:
103416469Ssam 			c -= 0200;
103516469Ssam 			break;
103616469Ssam 		case 0215:
103716469Ssam 			c = '\n';
103816469Ssam 			break;
103916469Ssam 		}
104016469Ssam 		putchar(lastc = c);
104116469Ssam 	}
104216469Ssam 	if (lastc != '\n')
104316469Ssam 		putchar('\n');
1044*18606Sedward 	return (1);
104516469Ssam }
1046