121554Sdist /* 221554Sdist * Copyright (c) 1980 Regents of the University of California. 321554Sdist * All rights reserved. The Berkeley software License Agreement 421554Sdist * specifies the terms and conditions for redistribution. 521554Sdist */ 621554Sdist 713619Ssam #ifndef lint 821554Sdist char copyright[] = 921554Sdist "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 1021554Sdist All rights reserved.\n"; 1121554Sdist #endif not lint 121014Sbill 1321554Sdist #ifndef lint 14*25121Sbloom static char sccsid[] = "@(#)finger.c 5.4 (Berkeley) 10/09/85"; 1521554Sdist #endif not lint 1621554Sdist 1718606Sedward /* 1818606Sedward * This is a finger program. It prints out useful information about users 1918606Sedward * by digging it up from various system files. It is not very portable 2018606Sedward * because the most useful parts of the information (the full user name, 2118606Sedward * office, and phone numbers) are all stored in the VAX-unused gecos field 2218606Sedward * of /etc/passwd, which, unfortunately, other UNIXes use for other things. 231014Sbill * 2418606Sedward * There are three output formats, all of which give login name, teletype 2518606Sedward * line number, and login time. The short output format is reminiscent 2618606Sedward * of finger on ITS, and gives one line of information per user containing 2718606Sedward * in addition to the minimum basic requirements (MBR), the full name of 2818606Sedward * the user, his idle time and office location and phone number. The 2918606Sedward * quick style output is UNIX who-like, giving only name, teletype and 3018606Sedward * login time. Finally, the long style output give the same information 3118606Sedward * as the short (in more legible format), the home directory and shell 3218606Sedward * of the user, and, if it exits, a copy of the file .plan in the users 3318606Sedward * home directory. Finger may be called with or without a list of people 3418606Sedward * to finger -- if no list is given, all the people currently logged in 3518606Sedward * are fingered. 361014Sbill * 3718606Sedward * The program is validly called by one of the following: 381014Sbill * 391014Sbill * finger {short form list of users} 401014Sbill * finger -l {long form list of users} 411014Sbill * finger -b {briefer long form list of users} 421014Sbill * finger -q {quick list of users} 431014Sbill * finger -i {quick list of users with idle times} 441014Sbill * finger namelist {long format list of specified users} 451014Sbill * finger -s namelist {short format list of specified users} 461014Sbill * finger -w namelist {narrow short format list of specified users} 471014Sbill * 4818606Sedward * where 'namelist' is a list of users login names. 4918606Sedward * The other options can all be given after one '-', or each can have its 5018606Sedward * own '-'. The -f option disables the printing of headers for short and 5118606Sedward * quick outputs. The -b option briefens long format outputs. The -p 5218606Sedward * option turns off plans for long format outputs. 531014Sbill */ 541014Sbill 5518606Sedward #include <sys/types.h> 5618606Sedward #include <sys/stat.h> 5718606Sedward #include <utmp.h> 5818606Sedward #include <sys/signal.h> 5918606Sedward #include <pwd.h> 6018606Sedward #include <stdio.h> 6118606Sedward #include <lastlog.h> 6218606Sedward #include <ctype.h> 6318606Sedward #include <sys/time.h> 6418606Sedward #include <sys/socket.h> 6518606Sedward #include <netinet/in.h> 6618606Sedward #include <netdb.h> 671014Sbill 6818606Sedward #define ASTERISK '*' /* ignore this in real name */ 6918606Sedward #define COMMA ',' /* separator in pw_gecos field */ 7018606Sedward #define COMMAND '-' /* command line flag char */ 7118606Sedward #define CORY 'C' /* cory hall office */ 7218606Sedward #define EVANS 'E' /* evans hall office */ 7318606Sedward #define SAMENAME '&' /* repeat login name in real name */ 7418606Sedward #define TALKABLE 0222 /* tty is writable if 222 mode */ 751014Sbill 7618606Sedward struct utmp user; 7718606Sedward #define NMAX sizeof(user.ut_name) 7818606Sedward #define LMAX sizeof(user.ut_line) 7918606Sedward #define HMAX sizeof(user.ut_host) 801014Sbill 8118606Sedward struct person { /* one for each person fingered */ 8218606Sedward char *name; /* name */ 8318606Sedward char tty[LMAX+1]; /* null terminated tty line */ 8418606Sedward char host[HMAX+1]; /* null terminated remote host name */ 8518606Sedward long loginat; /* time of (last) login */ 8618606Sedward long idletime; /* how long idle (if logged in) */ 8718606Sedward char *realname; /* pointer to full name */ 8818606Sedward char *office; /* pointer to office name */ 8918606Sedward char *officephone; /* pointer to office phone no. */ 9018606Sedward char *homephone; /* pointer to home phone no. */ 9118606Sedward char *random; /* for any random stuff in pw_gecos */ 9218606Sedward struct passwd *pwd; /* structure of /etc/passwd stuff */ 9318606Sedward char loggedin; /* person is logged in */ 9418606Sedward char writable; /* tty is writable */ 9518606Sedward char original; /* this is not a duplicate entry */ 9618606Sedward struct person *link; /* link to next person */ 971014Sbill }; 981014Sbill 9918606Sedward char LASTLOG[] = "/usr/adm/lastlog"; /* last login info */ 10018606Sedward char USERLOG[] = "/etc/utmp"; /* who is logged in */ 10118606Sedward char PLAN[] = "/.plan"; /* what plan file is */ 10218606Sedward char PROJ[] = "/.project"; /* what project file */ 10318606Sedward 10418606Sedward int unbrief = 1; /* -b option default */ 10518606Sedward int header = 1; /* -f option default */ 10618606Sedward int hack = 1; /* -h option default */ 10718606Sedward int idle = 0; /* -i option default */ 10818606Sedward int large = 0; /* -l option default */ 10918606Sedward int match = 1; /* -m option default */ 11018606Sedward int plan = 1; /* -p option default */ 11118606Sedward int unquick = 1; /* -q option default */ 11218606Sedward int small = 0; /* -s option default */ 11318606Sedward int wide = 1; /* -w option default */ 1141014Sbill 11518606Sedward int unshort; 11618606Sedward int lf; /* LASTLOG file descriptor */ 11718606Sedward struct person *person1; /* list of people */ 11818606Sedward long tloc; /* current time */ 1191014Sbill 12018606Sedward struct passwd *pwdcopy(); 12118606Sedward char *strcpy(); 12218606Sedward char *malloc(); 12318606Sedward char *ctime(); 1241014Sbill 12518606Sedward main(argc, argv) 12618606Sedward int argc; 12718606Sedward register char **argv; 12818606Sedward { 12918606Sedward FILE *fp; 13018606Sedward register char *s; 1311014Sbill 13218606Sedward /* parse command line for (optional) arguments */ 13318606Sedward while (*++argv && **argv == COMMAND) 13418606Sedward for (s = *argv + 1; *s; s++) 13518606Sedward switch (*s) { 13618606Sedward case 'b': 13718606Sedward unbrief = 0; 13818606Sedward break; 13918606Sedward case 'f': 14018606Sedward header = 0; 14118606Sedward break; 14218606Sedward case 'h': 14318606Sedward hack = 0; 14418606Sedward break; 14518606Sedward case 'i': 14618606Sedward idle = 1; 14718606Sedward unquick = 0; 14818606Sedward break; 14918606Sedward case 'l': 15018606Sedward large = 1; 15118606Sedward break; 15218606Sedward case 'm': 15318606Sedward match = 0; 15418606Sedward break; 15518606Sedward case 'p': 15618606Sedward plan = 0; 15718606Sedward break; 15818606Sedward case 'q': 15918606Sedward unquick = 0; 16018606Sedward break; 16118606Sedward case 's': 16218606Sedward small = 1; 16318606Sedward break; 16418606Sedward case 'w': 16518606Sedward wide = 0; 16618606Sedward break; 16718606Sedward default: 16818606Sedward fprintf(stderr, "Usage: finger [-bfhilmpqsw] [login1 [login2 ...] ]\n"); 16918606Sedward exit(1); 17018606Sedward } 17118606Sedward if (unquick || idle) 17218606Sedward time(&tloc); 17318606Sedward /* 17418606Sedward * *argv == 0 means no names given 17518606Sedward */ 17618606Sedward if (*argv == 0) 17718606Sedward doall(); 17818606Sedward else 17918606Sedward donames(argv); 18024461Sedward if (person1) 18124461Sedward print(); 18218606Sedward exit(0); 18318606Sedward } 1841014Sbill 18518606Sedward doall() 1861014Sbill { 18718606Sedward register struct person *p; 18818606Sedward register struct passwd *pw; 18918606Sedward int uf; 19018606Sedward char name[NMAX + 1]; 1911014Sbill 19218606Sedward unshort = large; 19318606Sedward if ((uf = open(USERLOG, 0)) < 0) { 19418606Sedward fprintf(stderr, "finger: error opening %s\n", USERLOG); 19518606Sedward exit(2); 1961014Sbill } 19718606Sedward if (unquick) { 19818606Sedward extern _pw_stayopen; 1991014Sbill 2001014Sbill setpwent(); 20118606Sedward _pw_stayopen = 1; 2021014Sbill fwopen(); 20318606Sedward } 20418606Sedward while (read(uf, (char *)&user, sizeof user) == sizeof user) { 20518606Sedward if (user.ut_name[0] == 0) 20618606Sedward continue; 20718606Sedward if (person1 == 0) 20818606Sedward p = person1 = (struct person *) malloc(sizeof *p); 20918606Sedward else { 21018606Sedward p->link = (struct person *) malloc(sizeof *p); 2111014Sbill p = p->link; 2121014Sbill } 21318606Sedward bcopy(user.ut_name, name, NMAX); 21418606Sedward name[NMAX] = 0; 21518606Sedward bcopy(user.ut_line, p->tty, LMAX); 21618606Sedward p->tty[LMAX] = 0; 21718606Sedward bcopy(user.ut_host, p->host, HMAX); 21818606Sedward p->host[HMAX] = 0; 21918606Sedward p->loginat = user.ut_time; 22018606Sedward p->pwd = 0; 22118606Sedward p->loggedin = 1; 22218606Sedward if (unquick && (pw = getpwnam(name))) { 22318606Sedward p->pwd = pwdcopy(pw); 22418606Sedward decode(p); 22518606Sedward p->name = p->pwd->pw_name; 22618606Sedward } else 22718606Sedward p->name = strcpy(malloc(strlen(name) + 1), name); 22818606Sedward } 22918606Sedward if (unquick) { 2301014Sbill fwclose(); 2311014Sbill endpwent(); 2321014Sbill } 23318606Sedward close(uf); 23418606Sedward if (person1 == 0) { 23518606Sedward printf("No one logged on\n"); 23624461Sedward return; 23718606Sedward } 23818606Sedward p->link = 0; 23918606Sedward } 2401014Sbill 24118606Sedward donames(argv) 24218606Sedward char **argv; 24318606Sedward { 24418606Sedward register struct person *p; 24518606Sedward register struct passwd *pw; 24618606Sedward int uf; 2471014Sbill 24818606Sedward /* 24918606Sedward * get names from command line and check to see if they're 25018606Sedward * logged in 25118606Sedward */ 25218606Sedward unshort = !small; 25318606Sedward for (; *argv != 0; argv++) { 25418606Sedward if (netfinger(*argv)) 25518606Sedward continue; 25618606Sedward if (person1 == 0) 25718606Sedward p = person1 = (struct person *) malloc(sizeof *p); 25818606Sedward else { 25918606Sedward p->link = (struct person *) malloc(sizeof *p); 26018606Sedward p = p->link; 26116469Ssam } 26218606Sedward p->name = *argv; 2631014Sbill p->loggedin = 0; 26418606Sedward p->original = 1; 26518606Sedward p->pwd = 0; 26618606Sedward } 26724461Sedward if (person1 == 0) 26824461Sedward return; 26918606Sedward p->link = 0; 27018606Sedward /* 27118606Sedward * if we are doing it, read /etc/passwd for the useful info 27218606Sedward */ 27318606Sedward if (unquick) { 27418606Sedward setpwent(); 27518606Sedward if (!match) { 27618606Sedward extern _pw_stayopen; 2771014Sbill 27818606Sedward _pw_stayopen = 1; 27918606Sedward for (p = person1; p != 0; p = p->link) 28018606Sedward if (pw = getpwnam(p->name)) 28118606Sedward p->pwd = pwdcopy(pw); 28218606Sedward } else while ((pw = getpwent()) != 0) { 28318606Sedward for (p = person1; p != 0; p = p->link) { 28418606Sedward if (!p->original) 28518606Sedward continue; 28618606Sedward if (strcmp(p->name, pw->pw_name) != 0 && 28718606Sedward !matchcmp(pw->pw_gecos, pw->pw_name, p->name)) 28818606Sedward continue; 28918606Sedward if (p->pwd == 0) 29018606Sedward p->pwd = pwdcopy(pw); 29118606Sedward else { 29218606Sedward struct person *new; 29318606Sedward /* 29418606Sedward * handle multiple login names, insert 29518606Sedward * new "duplicate" entry behind 29618606Sedward */ 29718606Sedward new = (struct person *) 29818606Sedward malloc(sizeof *new); 29918606Sedward new->pwd = pwdcopy(pw); 30018606Sedward new->name = p->name; 30118606Sedward new->original = 1; 30218606Sedward new->loggedin = 0; 30318606Sedward new->link = p->link; 30418606Sedward p->original = 0; 30518606Sedward p->link = new; 30618606Sedward p = new; 30718606Sedward } 3081014Sbill } 3091014Sbill } 3101014Sbill endpwent(); 31118606Sedward } 31218606Sedward /* Now get login information */ 31318606Sedward if ((uf = open(USERLOG, 0)) < 0) { 31418606Sedward fprintf(stderr, "finger: error opening %s\n", USERLOG); 31518606Sedward exit(2); 31618606Sedward } 31718606Sedward while (read(uf, (char *)&user, sizeof user) == sizeof user) { 31818606Sedward if (*user.ut_name == 0) 31918606Sedward continue; 32018606Sedward for (p = person1; p != 0; p = p->link) { 32118606Sedward if (p->loggedin == 2) 32218606Sedward continue; 32318606Sedward if (strncmp(p->pwd ? p->pwd->pw_name : p->name, 32418606Sedward user.ut_name, NMAX) != 0) 32518606Sedward continue; 32618606Sedward if (p->loggedin == 0) { 32718606Sedward bcopy(user.ut_line, p->tty, LMAX); 32818606Sedward p->tty[LMAX] = 0; 32918606Sedward bcopy(user.ut_host, p->host, HMAX); 33018606Sedward p->host[HMAX] = 0; 33118606Sedward p->loginat = user.ut_time; 33218606Sedward p->loggedin = 1; 33318606Sedward } else { /* p->loggedin == 1 */ 33418606Sedward struct person *new; 33518606Sedward new = (struct person *) malloc(sizeof *new); 33618606Sedward new->name = p->name; 33718606Sedward bcopy(user.ut_line, new->tty, LMAX); 33818606Sedward new->tty[LMAX] = 0; 33918606Sedward bcopy(user.ut_host, new->host, HMAX); 34018606Sedward new->host[HMAX] = 0; 34118606Sedward new->loginat = user.ut_time; 34218606Sedward new->pwd = p->pwd; 34318606Sedward new->loggedin = 1; 34418606Sedward new->original = 0; 34518606Sedward new->link = p->link; 34618606Sedward p->loggedin = 2; 34718606Sedward p->link = new; 34818606Sedward p = new; 3491014Sbill } 3501014Sbill } 35118606Sedward } 35218606Sedward close(uf); 35318606Sedward if (unquick) { 3541014Sbill fwopen(); 35518606Sedward for (p = person1; p != 0; p = p->link) 35618606Sedward decode(p); 3571014Sbill fwclose(); 3581014Sbill } 35918606Sedward } 3601014Sbill 36118606Sedward print() 36218606Sedward { 36318606Sedward register FILE *fp; 36418606Sedward register struct person *p; 36518606Sedward register char *s; 36618606Sedward register c; 3671014Sbill 36818606Sedward /* 36918606Sedward * print out what we got 37018606Sedward */ 37118606Sedward if (header) { 37218606Sedward if (unquick) { 37318606Sedward if (!unshort) 37418606Sedward if (wide) 37518606Sedward printf("Login Name TTY Idle When Office\n"); 37618606Sedward else 37718606Sedward printf("Login TTY Idle When Office\n"); 37818606Sedward } else { 37918606Sedward printf("Login TTY When"); 38018606Sedward if (idle) 38118606Sedward printf(" Idle"); 38218606Sedward putchar('\n'); 3831014Sbill } 38418606Sedward } 38518606Sedward for (p = person1; p != 0; p = p->link) { 38618606Sedward if (!unquick) { 38718606Sedward quickprint(p); 38818606Sedward continue; 3891014Sbill } 39018606Sedward if (!unshort) { 39118606Sedward shortprint(p); 39218606Sedward continue; 39318606Sedward } 39418606Sedward personprint(p); 39518606Sedward if (p->pwd != 0) { 39618606Sedward if (hack) { 39718606Sedward s = malloc(strlen(p->pwd->pw_dir) + 39818606Sedward sizeof PROJ); 39918606Sedward strcpy(s, p->pwd->pw_dir); 40018606Sedward strcat(s, PROJ); 40118606Sedward if ((fp = fopen(s, "r")) != 0) { 40218606Sedward printf("Project: "); 40318606Sedward while ((c = getc(fp)) != EOF) { 40418606Sedward if (c == '\n') 40518606Sedward break; 40618606Sedward putchar(c); 40718606Sedward } 40818606Sedward fclose(fp); 40918606Sedward putchar('\n'); 4101014Sbill } 41118606Sedward free(s); 4121014Sbill } 41318606Sedward if (plan) { 41418606Sedward s = malloc(strlen(p->pwd->pw_dir) + 41518606Sedward sizeof PLAN); 41618606Sedward strcpy(s, p->pwd->pw_dir); 41718606Sedward strcat(s, PLAN); 41818606Sedward if ((fp = fopen(s, "r")) == 0) 41918606Sedward printf("No Plan.\n"); 42018606Sedward else { 42118606Sedward printf("Plan:\n"); 42218606Sedward while ((c = getc(fp)) != EOF) 42318606Sedward putchar(c); 42418606Sedward fclose(fp); 4251014Sbill } 42618606Sedward free(s); 4271014Sbill } 4281014Sbill } 42918606Sedward if (p->link != 0) 43018606Sedward putchar('\n'); 43118606Sedward } 4321014Sbill } 4331014Sbill 43418606Sedward /* 43518606Sedward * Duplicate a pwd entry. 43618606Sedward * Note: Only the useful things (what the program currently uses) are copied. 4371014Sbill */ 43818606Sedward struct passwd * 43918606Sedward pwdcopy(pfrom) 44018606Sedward register struct passwd *pfrom; 44118606Sedward { 44218606Sedward register struct passwd *pto; 4431014Sbill 44418606Sedward pto = (struct passwd *) malloc(sizeof *pto); 44518606Sedward #define savestr(s) strcpy(malloc(strlen(s) + 1), s) 44618606Sedward pto->pw_name = savestr(pfrom->pw_name); 4471014Sbill pto->pw_uid = pfrom->pw_uid; 44818606Sedward pto->pw_gecos = savestr(pfrom->pw_gecos); 44918606Sedward pto->pw_dir = savestr(pfrom->pw_dir); 45018606Sedward pto->pw_shell = savestr(pfrom->pw_shell); 45118606Sedward #undef savestr 45218606Sedward return pto; 4531014Sbill } 4541014Sbill 45518606Sedward /* 45618606Sedward * print out information on quick format giving just name, tty, login time 45718606Sedward * and idle time if idle is set. 4581014Sbill */ 45918606Sedward quickprint(pers) 46018606Sedward register struct person *pers; 4611014Sbill { 46218606Sedward printf("%-*.*s ", NMAX, NMAX, pers->name); 46318606Sedward if (pers->loggedin) { 46418606Sedward if (idle) { 46518606Sedward findidle(pers); 46618606Sedward printf("%c%-*s %-16.16s", pers->writable ? ' ' : '*', 46718606Sedward LMAX, pers->tty, ctime(&pers->loginat)); 46818606Sedward ltimeprint(" ", &pers->idletime, ""); 46918606Sedward } else 47018606Sedward printf(" %-*s %-16.16s", LMAX, 47118606Sedward pers->tty, ctime(&pers->loginat)); 47218606Sedward putchar('\n'); 47318606Sedward } else 47418606Sedward printf(" Not Logged In\n"); 4751014Sbill } 4761014Sbill 47718606Sedward /* 47818606Sedward * print out information in short format, giving login name, full name, 47918606Sedward * tty, idle time, login time, office location and phone. 4801014Sbill */ 48118606Sedward shortprint(pers) 48218606Sedward register struct person *pers; 4831014Sbill { 48418606Sedward char *p; 48518606Sedward char dialup; 4861014Sbill 48718606Sedward if (pers->pwd == 0) { 48818606Sedward printf("%-15s ???\n", pers->name); 48918606Sedward return; 4901014Sbill } 49118606Sedward printf("%-*s", NMAX, pers->pwd->pw_name); 4921014Sbill dialup = 0; 49318606Sedward if (wide) { 49418606Sedward if (pers->realname) 49518606Sedward printf(" %-20.20s", pers->realname); 49618606Sedward else 49718606Sedward printf(" ??? "); 4981014Sbill } 49918606Sedward putchar(' '); 50018606Sedward if (pers->loggedin && !pers->writable) 50118606Sedward putchar('*'); 50218606Sedward else 50318606Sedward putchar(' '); 50418606Sedward if (*pers->tty) { 50518606Sedward if (pers->tty[0] == 't' && pers->tty[1] == 't' && 50618606Sedward pers->tty[2] == 'y') { 50718606Sedward if (pers->tty[3] == 'd' && pers->loggedin) 50818606Sedward dialup = 1; 50918606Sedward printf("%-2.2s ", pers->tty + 3); 51018606Sedward } else 51118606Sedward printf("%-2.2s ", pers->tty); 51218606Sedward } else 51318606Sedward printf(" "); 51418606Sedward p = ctime(&pers->loginat); 51518606Sedward if (pers->loggedin) { 51618606Sedward stimeprint(&pers->idletime); 51718606Sedward printf(" %3.3s %-5.5s ", p, p + 11); 51818606Sedward } else if (pers->loginat == 0) 51918606Sedward printf(" < . . . . >"); 5208842Smckusick else if (tloc - pers->loginat >= 180 * 24 * 60 * 60) 52118606Sedward printf(" <%-6.6s, %-4.4s>", p + 4, p + 20); 5228842Smckusick else 52318606Sedward printf(" <%-12.12s>", p + 4); 52418606Sedward if (dialup && pers->homephone) 52518606Sedward printf(" %20s", pers->homephone); 52618606Sedward else { 52718606Sedward if (pers->office) 52818606Sedward printf(" %-11.11s", pers->office); 52918606Sedward else if (pers->officephone || pers->homephone) 53018606Sedward printf(" "); 53118606Sedward if (pers->officephone) 53218606Sedward printf(" %s", pers->officephone); 53318606Sedward else if (pers->homephone) 53418606Sedward printf(" %s", pers->homephone); 5351014Sbill } 53618606Sedward putchar('\n'); 5371014Sbill } 5381014Sbill 53918606Sedward /* 54018606Sedward * print out a person in long format giving all possible information. 54118606Sedward * directory and shell are inhibited if unbrief is clear. 5421014Sbill */ 54318606Sedward personprint(pers) 54418606Sedward register struct person *pers; 5451014Sbill { 54618606Sedward if (pers->pwd == 0) { 54718606Sedward printf("Login name: %-10s\t\t\tIn real life: ???\n", 54818606Sedward pers->name); 54918606Sedward return; 5501014Sbill } 55118606Sedward printf("Login name: %-10s", pers->pwd->pw_name); 55218606Sedward if (pers->loggedin && !pers->writable) 55318606Sedward printf(" (messages off) "); 55418606Sedward else 55518606Sedward printf(" "); 55618606Sedward if (pers->realname) 55718606Sedward printf("In real life: %s", pers->realname); 55818606Sedward if (pers->office) { 55918606Sedward printf("\nOffice: %-.11s", pers->office); 56018606Sedward if (pers->officephone) { 56118606Sedward printf(", %s", pers->officephone); 56218606Sedward if (pers->homephone) 56318606Sedward printf("\t\tHome phone: %s", pers->homephone); 56418606Sedward else if (pers->random) 56518606Sedward printf("\t\t%s", pers->random); 56618606Sedward } else 56718606Sedward if (pers->homephone) 56818606Sedward printf("\t\t\tHome phone: %s", pers->homephone); 56918606Sedward else if (pers->random) 57018606Sedward printf("\t\t\t%s", pers->random); 57118606Sedward } else if (pers->officephone) { 57218606Sedward printf("\nPhone: %s", pers->officephone); 57318606Sedward if (pers->homephone) 57418606Sedward printf(", %s", pers->homephone); 57518606Sedward if (pers->random) 57618606Sedward printf(", %s", pers->random); 57718606Sedward } else if (pers->homephone) { 57818606Sedward printf("\nPhone: %s", pers->homephone); 57918606Sedward if (pers->random) 58018606Sedward printf(", %s", pers->random); 58118606Sedward } else if (pers->random) 58218606Sedward printf("\n%s", pers->random); 58318606Sedward if (unbrief) { 58418606Sedward printf("\nDirectory: %-25s", pers->pwd->pw_dir); 58518606Sedward if (*pers->pwd->pw_shell) 58618606Sedward printf("\tShell: %-s", pers->pwd->pw_shell); 5871014Sbill } 58818606Sedward if (pers->loggedin) { 58918606Sedward register char *ep = ctime(&pers->loginat); 59018606Sedward if (*pers->host) { 59118606Sedward printf("\nOn since %15.15s on %s from %s", 59218606Sedward &ep[4], pers->tty, pers->host); 59318606Sedward ltimeprint("\n", &pers->idletime, " Idle Time"); 59418606Sedward } else { 59518606Sedward printf("\nOn since %15.15s on %-*s", 59618606Sedward &ep[4], LMAX, pers->tty); 59718606Sedward ltimeprint("\t", &pers->idletime, " Idle Time"); 5981014Sbill } 59918606Sedward } else if (pers->loginat == 0) 60018606Sedward printf("\nNever logged in."); 6018842Smckusick else if (tloc - pers->loginat > 180 * 24 * 60 * 60) { 60218606Sedward register char *ep = ctime(&pers->loginat); 60318606Sedward printf("\nLast login %10.10s, %4.4s on %s", 60418606Sedward ep, ep+20, pers->tty); 60518606Sedward if (*pers->host) 60618606Sedward printf(" from %s", pers->host); 60718606Sedward } else { 60818606Sedward register char *ep = ctime(&pers->loginat); 60918606Sedward printf("\nLast login %16.16s on %s", ep, pers->tty); 61018606Sedward if (*pers->host) 61118606Sedward printf(" from %s", pers->host); 6128842Smckusick } 61318606Sedward putchar('\n'); 6141014Sbill } 6151014Sbill 6161014Sbill /* 6171014Sbill * very hacky section of code to format phone numbers. filled with 6181014Sbill * magic constants like 4, 7 and 10. 6191014Sbill */ 62018606Sedward char * 62118606Sedward phone(s, len, alldigits) 62218606Sedward register char *s; 62318606Sedward int len; 62418606Sedward char alldigits; 6251014Sbill { 62618606Sedward char fonebuf[15]; 62718606Sedward register char *p = fonebuf; 62818606Sedward register i; 6291014Sbill 63018606Sedward if (!alldigits) 63118606Sedward return (strcpy(malloc(len + 1), s)); 63218606Sedward switch (len) { 63318606Sedward case 4: 63418606Sedward *p++ = ' '; 63518606Sedward *p++ = 'x'; 63618606Sedward *p++ = '2'; 63718606Sedward *p++ = '-'; 63818606Sedward for (i = 0; i < 4; i++) 63918606Sedward *p++ = *s++; 6401014Sbill break; 64124463Sbloom case 5: 64224463Sbloom *p++ = ' '; 64324463Sbloom *p++ = 'x'; 64424463Sbloom *p++ = *s++; 64524463Sbloom *p++ = '-'; 64624463Sbloom for (i = 0; i < 4; i++) 64724463Sbloom *p++ = *s++; 64824463Sbloom break; 64918606Sedward case 7: 65018606Sedward for (i = 0; i < 3; i++) 65118606Sedward *p++ = *s++; 65218606Sedward *p++ = '-'; 65318606Sedward for (i = 0; i < 4; i++) 65418606Sedward *p++ = *s++; 6551014Sbill break; 65618606Sedward case 10: 65718606Sedward for (i = 0; i < 3; i++) 65818606Sedward *p++ = *s++; 65918606Sedward *p++ = '-'; 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 0: 66718606Sedward return 0; 66818606Sedward default: 66918606Sedward return (strcpy(malloc(len + 1), s)); 6701014Sbill } 67118606Sedward *p++ = 0; 67218606Sedward return (strcpy(malloc(p - fonebuf), fonebuf)); 6731014Sbill } 6741014Sbill 67518606Sedward /* 67618606Sedward * decode the information in the gecos field of /etc/passwd 6771014Sbill */ 67818606Sedward decode(pers) 67918606Sedward register struct person *pers; 6801014Sbill { 68118606Sedward char buffer[256]; 68218606Sedward register char *bp, *gp, *lp; 68318606Sedward int alldigits; 68418606Sedward int hasspace; 68518606Sedward int len; 6861014Sbill 68718606Sedward pers->realname = 0; 68818606Sedward pers->office = 0; 68918606Sedward pers->officephone = 0; 69018606Sedward pers->homephone = 0; 69118606Sedward pers->random = 0; 69218606Sedward if (pers->pwd == 0) 69318606Sedward return; 69418606Sedward gp = pers->pwd->pw_gecos; 69518606Sedward bp = buffer; 69618606Sedward if (*gp == ASTERISK) 6971014Sbill gp++; 69818606Sedward while (*gp && *gp != COMMA) /* name */ 69918606Sedward if (*gp == SAMENAME) { 70018606Sedward lp = pers->pwd->pw_name; 70118606Sedward if (islower(*lp)) 70218606Sedward *bp++ = toupper(*lp++); 70318606Sedward while (*bp++ = *lp++) 70418606Sedward ; 70518606Sedward bp--; 70618606Sedward gp++; 70718606Sedward } else 70818606Sedward *bp++ = *gp++; 70918606Sedward *bp++ = 0; 71018606Sedward if ((len = bp - buffer) > 1) 71118606Sedward pers->realname = strcpy(malloc(len), buffer); 71218606Sedward if (*gp == COMMA) { /* office */ 71318606Sedward gp++; 71418606Sedward hasspace = 0; 71518606Sedward bp = buffer; 71618606Sedward while (*gp && *gp != COMMA) { 71718606Sedward *bp = *gp++; 71818606Sedward if (*bp == ' ') 71918606Sedward hasspace = 1; 72018606Sedward /* leave 5 for Cory and Evans expansion */ 72118606Sedward if (bp < buffer + sizeof buffer - 6) 72218606Sedward bp++; 7231014Sbill } 72418606Sedward *bp = 0; 72518606Sedward len = bp - buffer; 72618606Sedward bp--; /* point to last character */ 72718606Sedward if (hasspace || len == 0) 72818606Sedward len++; 72918606Sedward else if (*bp == CORY) { 73018606Sedward strcpy(bp, " Cory"); 73118606Sedward len += 5; 73218606Sedward } else if (*bp == EVANS) { 73318606Sedward strcpy(bp, " Evans"); 73418606Sedward len += 6; 73518606Sedward } else 73618606Sedward len++; 73718606Sedward if (len > 1) 73818606Sedward pers->office = strcpy(malloc(len), buffer); 73918606Sedward } 74018606Sedward if (*gp == COMMA) { /* office phone */ 74118606Sedward gp++; 74218606Sedward bp = buffer; 74318606Sedward alldigits = 1; 74418606Sedward while (*gp && *gp != COMMA) { 74518606Sedward *bp = *gp++; 74618606Sedward if (!isdigit(*bp)) 74718606Sedward alldigits = 0; 74818606Sedward if (bp < buffer + sizeof buffer - 1) 74918606Sedward bp++; 7501014Sbill } 75118606Sedward *bp = 0; 75218606Sedward pers->officephone = phone(buffer, bp - buffer, alldigits); 75318606Sedward } 75418606Sedward if (*gp == COMMA) { /* home phone */ 7551014Sbill gp++; 75618606Sedward bp = buffer; 7571014Sbill alldigits = 1; 75818606Sedward while (*gp && *gp != COMMA) { 7591014Sbill *bp = *gp++; 76018606Sedward if (!isdigit(*bp)) 76118606Sedward alldigits = 0; 76218606Sedward if (bp < buffer + sizeof buffer - 1) 7631014Sbill bp++; 7641014Sbill } 76518606Sedward *bp = 0; 76618606Sedward pers->homephone = phone(buffer, bp - buffer, alldigits); 7671014Sbill } 76818606Sedward if (pers->loggedin) 76918606Sedward findidle(pers); 77018606Sedward else 77118606Sedward findwhen(pers); 7721014Sbill } 7731014Sbill 77418606Sedward /* 77518606Sedward * find the last log in of a user by checking the LASTLOG file. 77618606Sedward * the entry is indexed by the uid, so this can only be done if 77718606Sedward * the uid is known (which it isn't in quick mode) 7781014Sbill */ 7791014Sbill 7801014Sbill fwopen() 7811014Sbill { 78218606Sedward if ((lf = open(LASTLOG, 0)) < 0) 78318606Sedward fprintf(stderr, "finger: %s open error\n", LASTLOG); 7841014Sbill } 7851014Sbill 78618606Sedward findwhen(pers) 78718606Sedward register struct person *pers; 7881014Sbill { 78918606Sedward struct lastlog ll; 79018606Sedward int i; 7911014Sbill 79218606Sedward if (lf >= 0) { 79318606Sedward lseek(lf, (long)pers->pwd->pw_uid * sizeof ll, 0); 79418606Sedward if ((i = read(lf, (char *)&ll, sizeof ll)) == sizeof ll) { 79518606Sedward bcopy(ll.ll_line, pers->tty, LMAX); 79618606Sedward pers->tty[LMAX] = 0; 79718606Sedward bcopy(ll.ll_host, pers->host, HMAX); 79818606Sedward pers->host[HMAX] = 0; 79918606Sedward pers->loginat = ll.ll_time; 80018606Sedward } else { 80118606Sedward if (i != 0) 80218606Sedward fprintf(stderr, "finger: %s read error\n", 80318606Sedward LASTLOG); 80418606Sedward pers->tty[0] = 0; 80518606Sedward pers->host[0] = 0; 80618606Sedward pers->loginat = 0L; 80718606Sedward } 80818606Sedward } else { 80918606Sedward pers->tty[0] = 0; 81018606Sedward pers->host[0] = 0; 8111014Sbill pers->loginat = 0L; 8121014Sbill } 8131014Sbill } 8141014Sbill 8151014Sbill fwclose() 8161014Sbill { 81718606Sedward if (lf >= 0) 81818606Sedward close(lf); 8191014Sbill } 8201014Sbill 82118606Sedward /* 82218606Sedward * find the idle time of a user by doing a stat on /dev/tty??, 82318606Sedward * where tty?? has been gotten from USERLOG, supposedly. 8241014Sbill */ 82518606Sedward findidle(pers) 82618606Sedward register struct person *pers; 8271014Sbill { 82818606Sedward struct stat ttystatus; 82918606Sedward static char buffer[20] = "/dev/"; 83018606Sedward long t; 83118606Sedward #define TTYLEN 5 8321014Sbill 83318606Sedward strcpy(buffer + TTYLEN, pers->tty); 83418606Sedward buffer[TTYLEN+LMAX] = 0; 83518606Sedward if (stat(buffer, &ttystatus) < 0) { 83618606Sedward fprintf(stderr, "finger: Can't stat %s\n", buffer); 83718606Sedward exit(4); 83818606Sedward } 83918606Sedward time(&t); 84018606Sedward if (t < ttystatus.st_atime) 8411014Sbill pers->idletime = 0L; 84218606Sedward else 84318606Sedward pers->idletime = t - ttystatus.st_atime; 84418606Sedward pers->writable = (ttystatus.st_mode & TALKABLE) == TALKABLE; 8451014Sbill } 8461014Sbill 84718606Sedward /* 84818606Sedward * print idle time in short format; this program always prints 4 characters; 84918606Sedward * if the idle time is zero, it prints 4 blanks. 8501014Sbill */ 85118606Sedward stimeprint(dt) 85218606Sedward long *dt; 8531014Sbill { 85418606Sedward register struct tm *delta; 8551014Sbill 85618606Sedward delta = gmtime(dt); 85718606Sedward if (delta->tm_yday == 0) 85818606Sedward if (delta->tm_hour == 0) 85918606Sedward if (delta->tm_min == 0) 86018606Sedward printf(" "); 86118606Sedward else 86218606Sedward printf(" %2d", delta->tm_min); 86318606Sedward else 86418606Sedward if (delta->tm_hour >= 10) 86518606Sedward printf("%3d:", delta->tm_hour); 86618606Sedward else 86718606Sedward printf("%1d:%02d", 86818606Sedward delta->tm_hour, delta->tm_min); 86918606Sedward else 87018606Sedward printf("%3dd", delta->tm_yday); 8711014Sbill } 8721014Sbill 87318606Sedward /* 87418606Sedward * print idle time in long format with care being taken not to pluralize 87518606Sedward * 1 minutes or 1 hours or 1 days. 87618606Sedward * print "prefix" first. 8771014Sbill */ 87818606Sedward ltimeprint(before, dt, after) 87918606Sedward long *dt; 88018606Sedward char *before, *after; 8811014Sbill { 88218606Sedward register struct tm *delta; 8831014Sbill 88418606Sedward delta = gmtime(dt); 88518606Sedward if (delta->tm_yday == 0 && delta->tm_hour == 0 && delta->tm_min == 0 && 88618606Sedward delta->tm_sec <= 10) 88718606Sedward return (0); 88818606Sedward printf("%s", before); 88918606Sedward if (delta->tm_yday >= 10) 89018606Sedward printf("%d days", delta->tm_yday); 89118606Sedward else if (delta->tm_yday > 0) 89218606Sedward printf("%d day%s %d hour%s", 89318606Sedward delta->tm_yday, delta->tm_yday == 1 ? "" : "s", 89418606Sedward delta->tm_hour, delta->tm_hour == 1 ? "" : "s"); 89518606Sedward else 89618606Sedward if (delta->tm_hour >= 10) 89718606Sedward printf("%d hours", delta->tm_hour); 89818606Sedward else if (delta->tm_hour > 0) 89918606Sedward printf("%d hour%s %d minute%s", 90018606Sedward delta->tm_hour, delta->tm_hour == 1 ? "" : "s", 90118606Sedward delta->tm_min, delta->tm_min == 1 ? "" : "s"); 90218606Sedward else 90318606Sedward if (delta->tm_min >= 10) 90418606Sedward printf("%2d minutes", delta->tm_min); 90518606Sedward else if (delta->tm_min == 0) 90618606Sedward printf("%2d seconds", delta->tm_sec); 90718606Sedward else 90818606Sedward printf("%d minute%s %d second%s", 90918606Sedward delta->tm_min, 91018606Sedward delta->tm_min == 1 ? "" : "s", 91118606Sedward delta->tm_sec, 91218606Sedward delta->tm_sec == 1 ? "" : "s"); 91318606Sedward printf("%s", after); 9141014Sbill } 9151014Sbill 91618606Sedward matchcmp(gname, login, given) 91718606Sedward register char *gname; 91818606Sedward char *login; 91918606Sedward char *given; 9201014Sbill { 92118606Sedward char buffer[100]; 92218606Sedward register char *bp, *lp; 92318606Sedward register c; 9241014Sbill 92518606Sedward if (*gname == ASTERISK) 92618606Sedward gname++; 92718606Sedward lp = 0; 92818606Sedward bp = buffer; 92918606Sedward for (;;) 93018606Sedward switch (c = *gname++) { 93118606Sedward case SAMENAME: 93218606Sedward for (lp = login; bp < buffer + sizeof buffer 93318606Sedward && (*bp++ = *lp++);) 93418606Sedward ; 93518606Sedward bp--; 93618606Sedward break; 93718606Sedward case ' ': 93818606Sedward case COMMA: 93918606Sedward case '\0': 94018606Sedward *bp = 0; 94118606Sedward if (namecmp(buffer, given)) 94218606Sedward return (1); 94318606Sedward if (c == COMMA || c == 0) 94418606Sedward return (0); 94518606Sedward bp = buffer; 94618606Sedward break; 94718606Sedward default: 94818606Sedward if (bp < buffer + sizeof buffer) 94918606Sedward *bp++ = c; 9501014Sbill } 95118606Sedward /*NOTREACHED*/ 9521014Sbill } 9531014Sbill 95418606Sedward namecmp(name1, name2) 95518606Sedward register char *name1, *name2; 9561014Sbill { 95718606Sedward register c1, c2; 9581014Sbill 95918606Sedward for (;;) { 96018606Sedward c1 = *name1++; 96118606Sedward if (islower(c1)) 96218606Sedward c1 = toupper(c1); 96318606Sedward c2 = *name2++; 96418606Sedward if (islower(c2)) 96518606Sedward c2 = toupper(c2); 96618606Sedward if (c1 != c2) 96718606Sedward break; 96818606Sedward if (c1 == 0) 96918606Sedward return (1); 9701014Sbill } 97118606Sedward if (!c1) { 97218606Sedward for (name2--; isdigit(*name2); name2++) 97318606Sedward ; 97418606Sedward if (*name2 == 0) 97518606Sedward return (1); 97618606Sedward } else if (!c2) { 97718606Sedward for (name1--; isdigit(*name1); name1++) 97818606Sedward ; 97918606Sedward if (*name2 == 0) 98018606Sedward return (1); 9811014Sbill } 98218606Sedward return (0); 9831014Sbill } 9841014Sbill 98516469Ssam netfinger(name) 98618606Sedward char *name; 98716469Ssam { 98816469Ssam char *host; 98916469Ssam char fname[100]; 99016469Ssam struct hostent *hp; 99116469Ssam struct servent *sp; 99218606Sedward struct sockaddr_in sin; 99316469Ssam int s; 99416469Ssam char *rindex(); 99516469Ssam register FILE *f; 99616469Ssam register int c; 99716469Ssam register int lastc; 99816469Ssam 99916469Ssam if (name == NULL) 100018606Sedward return (0); 100116469Ssam host = rindex(name, '@'); 100216469Ssam if (host == NULL) 100318606Sedward return (0); 100416469Ssam *host++ = 0; 100516469Ssam hp = gethostbyname(host); 100616469Ssam if (hp == NULL) { 100716469Ssam static struct hostent def; 100816469Ssam static struct in_addr defaddr; 100916469Ssam static char namebuf[128]; 101016469Ssam int inet_addr(); 101116469Ssam 101216469Ssam defaddr.s_addr = inet_addr(host); 101316469Ssam if (defaddr.s_addr == -1) { 101416469Ssam printf("unknown host: %s\n", host); 101518606Sedward return (1); 101616469Ssam } 101716469Ssam strcpy(namebuf, host); 101816469Ssam def.h_name = namebuf; 101916469Ssam def.h_addr = (char *)&defaddr; 102016469Ssam def.h_length = sizeof (struct in_addr); 102116469Ssam def.h_addrtype = AF_INET; 102216469Ssam def.h_aliases = 0; 102316469Ssam hp = &def; 102416469Ssam } 102516469Ssam printf("[%s]", hp->h_name); 102616469Ssam sp = getservbyname("finger", "tcp"); 102716469Ssam if (sp == 0) { 102816469Ssam printf("tcp/finger: unknown service\n"); 102918606Sedward return (1); 103016469Ssam } 103116469Ssam sin.sin_family = hp->h_addrtype; 103216469Ssam bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length); 103316469Ssam sin.sin_port = sp->s_port; 103416469Ssam s = socket(hp->h_addrtype, SOCK_STREAM, 0); 103516469Ssam if (s < 0) { 103616469Ssam fflush(stdout); 103716469Ssam perror("socket"); 103818606Sedward return (1); 103916469Ssam } 104016469Ssam if (connect(s, (char *)&sin, sizeof (sin)) < 0) { 104116469Ssam fflush(stdout); 104216469Ssam perror("connect"); 104316469Ssam close(s); 104418606Sedward return (1); 104516469Ssam } 104616469Ssam printf("\n"); 104716469Ssam if (large) write(s, "/W ", 3); 104816469Ssam write(s, name, strlen(name)); 104916469Ssam write(s, "\r\n", 2); 105016469Ssam f = fdopen(s, "r"); 105116469Ssam while ((c = getc(f)) != EOF) { 105216469Ssam switch(c) { 105316469Ssam case 0210: 105416469Ssam case 0211: 105516469Ssam case 0212: 105616469Ssam case 0214: 105716469Ssam c -= 0200; 105816469Ssam break; 105916469Ssam case 0215: 106016469Ssam c = '\n'; 106116469Ssam break; 106216469Ssam } 106316469Ssam putchar(lastc = c); 106416469Ssam } 106516469Ssam if (lastc != '\n') 106616469Ssam putchar('\n'); 1067*25121Sbloom (void)fclose(f); 106818606Sedward return (1); 106916469Ssam } 1070