correct printing of \n at the end of .plan; and use fopen() not freopen()
[unix-history] / usr / src / usr.bin / finger / util.c
CommitLineData
6b8910b8
KB
1/*
2 * Copyright (c) 1989 The Regents of the University of California.
3 * All rights reserved.
4 *
6b8910b8
KB
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 */
17
18#ifndef lint
e2a72b79 19static char sccsid[] = "@(#)util.c 5.7 (Berkeley) %G%";
6b8910b8
KB
20#endif /* not lint */
21
22#include <sys/param.h>
23#include <sys/stat.h>
24#include <sys/file.h>
25#include <stdio.h>
26#include <ctype.h>
27#include <strings.h>
28#include "finger.h"
29#include "pathnames.h"
30
7619ff47
EW
31find_idle_and_ttywrite(w)
32 register WHERE *w;
6b8910b8
KB
33{
34 extern time_t now;
35 extern int errno;
36 struct stat sb;
37 char *strerror();
38
7619ff47 39 (void)sprintf(tbuf, "%s/%s", _PATH_DEV, w->tty);
6b8910b8
KB
40 if (stat(tbuf, &sb) < 0) {
41 (void)fprintf(stderr,
42 "finger: %s: %s\n", tbuf, strerror(errno));
43 exit(1);
44 }
7619ff47 45 w->idletime = now < sb.st_atime ? 0 : now - sb.st_atime;
6b8910b8
KB
46
47#define TALKABLE 0220 /* tty is writable if 220 mode */
7619ff47 48 w->writable = ((sb.st_mode & TALKABLE) == TALKABLE);
6b8910b8
KB
49}
50
51userinfo(pn, pw)
52 register PERSON *pn;
53 register struct passwd *pw;
54{
55 register char *p, *t;
56 char name[256];
57
58 pn->realname = pn->office = pn->officephone = pn->homephone = NULL;
59
60 pn->uid = pw->pw_uid;
61 pn->name = strdup(pw->pw_name);
62 pn->dir = strdup(pw->pw_dir);
63 pn->shell = strdup(pw->pw_shell);
64
65 /* why do we skip asterisks!?!? */
66 (void)strcpy(p = tbuf, pw->pw_gecos);
67 if (*p == '*')
68 ++p;
69
70 /* ampersands get replaced by the login name */
71 if (!(p = strsep(p, ",")))
72 return;
73 for (t = name; *t = *p; ++p)
74 if (*t == '&') {
75 (void)strcpy(t, pw->pw_name);
76 if (islower(*t))
77 *t = toupper(*t);
78 while (*++t);
79 }
80 else
81 ++t;
82 pn->realname = strdup(name);
e2a72b79
KB
83 pn->office = ((p = strsep((char *)NULL, ",")) && *p) ?
84 strdup(p) : NULL;
85 pn->officephone = ((p = strsep((char *)NULL, ",")) && *p) ?
86 strdup(p) : NULL;
87 pn->homephone = ((p = strsep((char *)NULL, ",")) && *p) ?
88 strdup(p) : NULL;
6b8910b8
KB
89}
90
91match(pw, user)
92 struct passwd *pw;
93 char *user;
94{
95 register char *p, *t;
96 char name[256];
97
98 /* why do we skip asterisks!?!? */
99 (void)strcpy(p = tbuf, pw->pw_gecos);
100 if (*p == '*')
101 ++p;
102
103 /* ampersands get replaced by the login name */
104 if (!(p = strtok(p, ",")))
105 return(0);
106 for (t = name; *t = *p; ++p)
107 if (*t == '&') {
108 (void)strcpy(t, pw->pw_name);
109 while (*++t);
110 }
111 else
112 ++t;
113 for (t = name; p = strtok(t, "\t "); t = (char *)NULL)
114 if (!strcasecmp(p, user))
115 return(1);
116 return(0);
117}
118
7619ff47 119enter_lastlog(pn)
6b8910b8
KB
120 register PERSON *pn;
121{
7619ff47 122 register WHERE *w;
8577119b 123 static int opened, fd;
6b8910b8 124 struct lastlog ll;
7619ff47 125 char doit = 0;
6b8910b8
KB
126 off_t lseek();
127
9fc6ea8a
KB
128 /* some systems may not maintain lastlog, don't report errors. */
129 if (!opened) {
7619ff47 130 fd = open(_PATH_LASTLOG, O_RDONLY, 0);
9fc6ea8a 131 opened = 1;
6b8910b8 132 }
9fc6ea8a
KB
133 if (fd == -1 ||
134 lseek(fd, (long)pn->uid * sizeof(ll), L_SET) !=
135 (long)pn->uid * sizeof(ll) ||
136 read(fd, (char *)&ll, sizeof(ll)) != sizeof(ll)) {
137 /* as if never logged in */
138 ll.ll_line[0] = ll.ll_host[0] = NULL;
139 ll.ll_time = 0;
140 }
7619ff47
EW
141 if ((w = pn->whead) == NULL)
142 doit = 1;
8577119b 143 else if (ll.ll_time != 0) {
7619ff47
EW
144 /* if last login is earlier than some current login */
145 for (; !doit && w != NULL; w = w->next)
146 if (w->info == LOGGEDIN && w->loginat < ll.ll_time)
147 doit = 1;
148 /*
149 * and if it's not any of the current logins
150 * can't use time comparison because there may be a small
151 * discrepency since login calls time() twice
152 */
153 for (w = pn->whead; doit && w != NULL; w = w->next)
154 if (w->info == LOGGEDIN &&
155 strncmp(w->tty, ll.ll_line, UT_LINESIZE) == 0)
156 doit = 0;
157 }
158 if (doit) {
159 w = walloc(pn);
160 w->info = LASTLOG;
161 bcopy(ll.ll_line, w->tty, UT_LINESIZE);
162 w->tty[UT_LINESIZE] = 0;
163 bcopy(ll.ll_host, w->host, UT_HOSTSIZE);
164 w->host[UT_HOSTSIZE] = 0;
165 w->loginat = ll.ll_time;
6b8910b8 166 }
6b8910b8
KB
167}
168
7619ff47 169enter_where(ut, pn)
6b8910b8
KB
170 struct utmp *ut;
171 PERSON *pn;
172{
7619ff47
EW
173 register WHERE *w = walloc(pn);
174
175 w->info = LOGGEDIN;
176 bcopy(ut->ut_line, w->tty, UT_LINESIZE);
177 w->tty[UT_LINESIZE] = 0;
178 bcopy(ut->ut_host, w->host, UT_HOSTSIZE);
179 w->host[UT_HOSTSIZE] = 0;
180 w->loginat = (time_t)ut->ut_time;
181 find_idle_and_ttywrite(w);
182}
183
184PERSON *
185enter_person(pw)
186 register struct passwd *pw;
187{
188 register PERSON *pn, **pp;
189
190 for (pp = htab + hash(pw->pw_name);
191 *pp != NULL && strcmp((*pp)->name, pw->pw_name) != 0;
192 pp = &(*pp)->hlink)
193 ;
194 if ((pn = *pp) == NULL) {
195 pn = palloc();
196 entries++;
197 if (phead == NULL)
198 phead = ptail = pn;
199 else {
200 ptail->next = pn;
201 ptail = pn;
202 }
203 pn->next = NULL;
204 pn->hlink = NULL;
205 *pp = pn;
206 userinfo(pn, pw);
207 pn->whead = NULL;
208 }
209 return(pn);
210}
211
212PERSON *
213find_person(name)
214 char *name;
215{
216 register PERSON *pn;
217
218 /* name may be only UT_NAMESIZE long and not terminated */
219 for (pn = htab[hash(name)];
220 pn != NULL && strncmp(pn->name, name, UT_NAMESIZE) != 0;
221 pn = pn->hlink)
222 ;
223 return(pn);
224}
225
226hash(name)
227 register char *name;
228{
229 register int h, i;
230
231 h = 0;
232 /* name may be only UT_NAMESIZE long and not terminated */
233 for (i = UT_NAMESIZE; --i >= 0 && *name;)
234 h = ((h << 2 | h >> HBITS - 2) ^ *name++) & HMASK;
235 return(h);
236}
237
238PERSON *
239palloc()
240{
241 PERSON *p;
242
243 if ((p = (PERSON *)malloc((u_int) sizeof(PERSON))) == NULL) {
244 (void)fprintf(stderr, "finger: out of space.\n");
245 exit(1);
246 }
247 return(p);
248}
249
250WHERE *
251walloc(pn)
252 register PERSON *pn;
253{
254 register WHERE *w;
255
256 if ((w = (WHERE *)malloc((u_int) sizeof(WHERE))) == NULL) {
257 (void)fprintf(stderr, "finger: out of space.\n");
258 exit(1);
259 }
260 if (pn->whead == NULL)
261 pn->whead = pn->wtail = w;
262 else {
263 pn->wtail->next = w;
264 pn->wtail = w;
265 }
266 w->next = NULL;
267 return(w);
6b8910b8 268}
f156ea40
KB
269
270char *
271prphone(num)
272 char *num;
273{
274 register char *p;
275 int len;
276 static char pbuf[15];
277
278 /* don't touch anything if the user has their own formatting */
279 for (p = num; *p; ++p)
280 if (!isdigit(*p))
281 return(num);
282 len = p - num;
283 p = pbuf;
284 switch(len) {
285 case 11: /* +0-123-456-7890 */
286 *p++ = '+';
287 *p++ = *num++;
288 *p++ = '-';
289 /* FALLTHROUGH */
290 case 10: /* 012-345-6789 */
291 *p++ = *num++;
292 *p++ = *num++;
293 *p++ = *num++;
294 *p++ = '-';
295 /* FALLTHROUGH */
296 case 7: /* 012-3456 */
297 *p++ = *num++;
298 *p++ = *num++;
299 *p++ = *num++;
300 break;
301 case 5: /* x0-1234 */
302 *p++ = 'x';
303 *p++ = *num++;
304 break;
305 default:
306 return(num);
307 }
308 *p++ = '-';
309 *p++ = *num++;
310 *p++ = *num++;
311 *p++ = *num++;
312 *p++ = *num++;
313 *p = '\0';
314 return(pbuf);
315}