home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1993 #3 / NN_1993_3.iso / spool / alt / sources / 3102 < prev    next >
Encoding:
Text File  |  1993-01-28  |  29.5 KB  |  1,140 lines

  1. Newsgroups: alt.sources
  2. Path: sparky!uunet!UB.com!pacbell.com!sgiblab!munnari.oz.au!bruce.cs.monash.edu.au!monu6!rjh
  3. From: rjh@pixel.maths.monash.edu.au (Plagued by Penguins)
  4. Subject: xrwho - an X version of rwho
  5. Message-ID: <1993Jan27.050758.9565@monu6.cc.monash.edu.au>
  6. Keywords: rwho, X11
  7. Sender: rjh@pixel.maths.monash.edu.au (Mr Robin J Humble)
  8. Organization: Dept of Maths, Monash Uni, Melbourne, Australia
  9. Date: Wed, 27 Jan 1993 05:07:58 GMT
  10. Lines: 1128
  11.  
  12.                              xrwho
  13.  
  14.                An X Window based version of rwho.
  15.  
  16.           By Andrew Herbert  andrewh@cs.monash.edu.au
  17.                              andrew@werple.apana.org.au
  18.          and Robin Humble    rjh@pixel.maths.monash.edu.au
  19.  
  20. xrwho displays the users logged into hosts on the local network.  It
  21. creates a window in which the names of local machines and the users
  22. that are on these machines are displayed.  Each host machine has its
  23. own box in which the users logged onto this machine are shown.
  24.  
  25. xrwho uses the X Toolkit and Athena widgets.  It requires X11R4 or later.
  26. Check out the man page for info on all the groovy features in xrwho.
  27.  
  28.  
  29. #! /bin/sh
  30. # This is a shell archive.  Remove anything before this line, then unpack
  31. # it by saving it into a file and typing "sh file".  To overwrite existing
  32. # files, type "sh file -c".  You can also feed this as standard input via
  33. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  34. # will see the following message at the end:
  35. #        "End of shell archive."
  36. # Contents:  README xrwho.c xrwho.man Imakefile Makefile.easy
  37. #   Xrwho.apps
  38. # Wrapped by andrewh@molly.cs.monash.edu.au on Wed Jan 27 15:56:23 1993
  39. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  40. if test -f README -a "${1}" != "-c" ; then 
  41.   echo shar: Will not over-write existing file \"README\"
  42. else
  43. echo shar: Extracting \"README\" \(1500 characters\)
  44. sed "s/^X//" >README <<'END_OF_README'
  45. X
  46. X                             xrwho
  47. X
  48. X               An X Window based version of rwho.
  49. X
  50. X          By Andrew Herbert  andrewh@cs.monash.edu.au
  51. X                             andrew@werple.apana.org.au
  52. X         and Robin Humble    rjh@pixel.maths.monash.edu.au
  53. X
  54. Xxrwho displays the users logged into hosts on the local network.  It
  55. Xcreates a window in which the names of local machines and the users
  56. Xthat are on these machines are displayed.  Each host machine has its
  57. Xown box in which the users logged onto this machine are shown.
  58. X
  59. Xxrwho uses the X Toolkit and Athena widgets.  It requires X11R4 or later.
  60. XCheck out the man page for info on all the groovy features in xrwho.
  61. X
  62. XYou can use the Imakefile to build xrwho by:
  63. X
  64. X      xmkmf
  65. X      make depend
  66. X      make
  67. X
  68. Xor a simple
  69. X
  70. X      gcc -o xrwho xrwho.c -lXaw -lXmu -lXt -lX11
  71. X
  72. Xshould suffice.  "cc" is okay on most machines too.
  73. X
  74. XA sample "Xrwho.apps" file is included which can be customised to your
  75. Xcolour, font, size and shape preferences and then added to your
  76. XX resources (~/.Xdefaults) file.  xrwho will work fine without having
  77. Xto do this though.
  78. X
  79. Xxrwho can be compiled with "-DDebug" if you really want lots of junk
  80. Xall over your screen.  However, if xrwho crashes and burns on your
  81. Xmachine then please set the Debug flag, recompile, attempt to
  82. Xreproduce the error, and then mail us the results.
  83. X
  84. XComments and suggestions for improvement are welcome as long as we're
  85. Xnot too close to some damn conference submission date or something...
  86. X
  87. XEnjoy!
  88. END_OF_README
  89. if test 1500 -ne `wc -c <README`; then
  90.     echo shar: \"README\" unpacked with wrong size!
  91. fi
  92. # end of overwriting check
  93. fi
  94. if test -f xrwho.c -a "${1}" != "-c" ; then 
  95.   echo shar: Will not over-write existing file \"xrwho.c\"
  96. else
  97. echo shar: Extracting \"xrwho.c\" \(19344 characters\)
  98. sed "s/^X//" >xrwho.c <<'END_OF_xrwho.c'
  99. X/*
  100. X * xrwho 1.0
  101. X *
  102. X * By Andrew Herbert                and Robin Humble
  103. X *   <andrewh@cs.monash.edu.au>        <rjh@pixel.maths.monash.edu.au>
  104. X *   <andrew@werple.apana.org.au>
  105. X *
  106. X * Jan '93.
  107. X *
  108. X * build with: gcc -O -s -o xrwho xrwho.c -lXaw -lXmu -lXt -lX11
  109. X *
  110. X */
  111. X
  112. X#include <stdio.h>
  113. X#include <fcntl.h>
  114. X#include <string.h>
  115. X#include <stdlib.h>
  116. X#include <unistd.h>
  117. X#include <dirent.h>
  118. X#include <utmp.h>
  119. X#include <limits.h>
  120. X#include <errno.h>
  121. X#include <time.h>
  122. X#include <protocols/rwhod.h>
  123. X#include <sys/types.h>
  124. X#include <sys/stat.h>
  125. X#include <X11/Intrinsic.h>
  126. X#include <X11/StringDefs.h>
  127. X#include <X11/Xaw/Command.h>    
  128. X#include <X11/Xaw/Label.h>    
  129. X#include <X11/Xaw/Box.h>    
  130. X#include <X11/Xaw/Cardinals.h>    
  131. X#include <X11/Xaw/Viewport.h>    
  132. X
  133. X#ifdef sun
  134. Xextern char *sys_errlist[];
  135. X#define strerror(e) (sys_errlist[e])
  136. X#endif
  137. X
  138. X#ifdef __386BSD__
  139. X#define RWHODIR        "/var/rwho"
  140. X#else
  141. X#define RWHODIR        "/usr/spool/rwho"
  142. X#endif
  143. X#define MaxSnoops    32    /* maximum snoop users */
  144. X#define MaxUtmpEntries    64    /* maximum users for localhost */
  145. X#define InsensitiveIdleTime    300    /* one minute max idle time*/
  146. X#define OldUserIdleTime    3600    /* one hour user idle time max unless -a specified */
  147. X#define HostDeadTime    300    /* time before a host is considered dead */
  148. X#define RefreshRate    60000    /* refresh every minute (rate in ms) */
  149. X
  150. X#define MIN(x, y)  ((x)<(y)?(x):(y))
  151. X
  152. X#ifdef Debug
  153. X#define Die abort()
  154. X#else
  155. X#define Die exit(1)
  156. X#endif
  157. X
  158. X#ifndef UTMP_FILE
  159. X#ifdef _PATH_UTMP
  160. X#define UTMP_FILE _PATH_UTMP
  161. X#else
  162. X#define UTMP_FILE "/etc/utmp"
  163. X#endif /* _PATH_UTMP */
  164. X#endif /* UTMP_FILE */
  165. X
  166. X#ifdef R3_INTRINSICS
  167. Xtypedef void*    XtPointer;
  168. Xextern Widget XtAppInitialize();
  169. X#endif
  170. X
  171. Xextern int gethostname(char *, int);
  172. X
  173. Xtypedef enum { local, rwho } userinfo_source_t;
  174. X
  175. X/* per-user information */
  176. Xtypedef struct user_struct {
  177. X    char name[9];    /* username */
  178. X    int    idle;        /* minimum of all the idles for this user */
  179. X    int still_here;    /* flag to say the user is still logged in */
  180. X    Widget label;    /* the label widget for this user */
  181. X    struct user_struct *next;    /* next user */
  182. X} user_t;
  183. X
  184. X/* per-host information */
  185. Xtypedef struct {
  186. X    Widget box;        /* box widget to contain the labels for this host */
  187. X    char host_name[32];
  188. X    userinfo_source_t host_file_type;
  189. X    char host_filename[256];
  190. X    Widget title;    /* the label widget for this host */
  191. X    user_t *head;    /* pointer to userlist on this host */
  192. X} userinfo_t;
  193. X
  194. X/* temp filename info */
  195. Xtypedef struct host_filestruct {
  196. X    char name[256];
  197. X    struct host_filestruct *next, *prev;
  198. X} host_t;
  199. X
  200. XString fallbacks[] = { 
  201. X    "*Label*borderWidth:    0",    /* no border around host or usernames */
  202. X    "*vSpace:            2",    /* pack usernames fairly tightly */
  203. X    "*host.foreground:        blue",    /* hostname colour */
  204. X    "*snoop.foreground:        red",    /* snoop user colour */
  205. X    "*font:            -*-helvetica-medium-r-*-*-*-120-*-*-*-*-*-*",
  206. X    "*host.font:        -*-helvetica-medium-o-*-*-*-120-*-*-*-*-*-*",
  207. X                    /* smallish font */
  208. X    "*Viewport*allowVert:    True",
  209. X    NULL
  210. X};
  211. X
  212. Xstatic XrmOptionDescRec options[] = {
  213. X    {"-hostfg",        "*host.foreground",        XrmoptionSepArg, NULL},
  214. X    {"-hostbg",        "*host.background",        XrmoptionSepArg, NULL},
  215. X    {"-hostfont",   "*host.font",        XrmoptionSepArg, NULL},
  216. X    {"-font",        "*font",            XrmoptionSepArg, NULL},
  217. X    {"-highlight",  "*snoop.foreground",    XrmoptionSepArg, NULL},
  218. X};
  219. X
  220. XWidget    toplevel, box;
  221. Xint    no_of_hosts;    /* number of remote hosts being monitored */
  222. Xint    list_long, show_all_hosts, empty_boxes, num_snoops, ring_bell;
  223. Xchar    snoop_user[MaxSnoops][9];
  224. Xuserinfo_t *host_userinfo;
  225. X
  226. Xvoid sort(host_t *);
  227. Xvoid init_rwho(Widget);
  228. Xvoid process_rwho(void);
  229. Xvoid refresh_rwho(XtPointer, XtIntervalId *);
  230. Xint search_for_user(userinfo_t *, char *, user_t **);
  231. Xint read_utmp(struct utmp [], int);
  232. Xint read_rwho(char *, struct whod *);
  233. Xvoid remove_tail(char *string);
  234. Xvoid syntax(XtAppContext, char *);
  235. Xvoid main(int, char **);
  236. X
  237. Xvoid main(int argc, char **argv)
  238. X{
  239. X    int i;
  240. X    XtAppContext app_con;
  241. X    Widget viewport;
  242. X
  243. X    toplevel = XtAppInitialize(&app_con, "Xrwho", options, XtNumber(options),
  244. X       (Cardinal *)&argc, argv, fallbacks, NULL, ZERO);
  245. X
  246. X#ifdef Debug
  247. X/* don't work too well boss:
  248. XXtAppSetErrorHandler(app_con, abort);
  249. X*/
  250. X#endif
  251. X
  252. X    list_long = 0;
  253. X    show_all_hosts = 0;
  254. X    empty_boxes = 0;
  255. X    num_snoops = 0;
  256. X    ring_bell = 0;
  257. X
  258. X    /*
  259. X     * parse optional arguments
  260. X     */
  261. X    for (i = 1; i < argc; i++) {
  262. X    if (!strcmp(argv[i], "-a"))
  263. X        list_long = 1;
  264. X    else if (!strcmp(argv[i], "-l"))
  265. X        show_all_hosts = 1;
  266. X    else if (!strcmp(argv[i], "-b"))
  267. X        empty_boxes = 1;
  268. X    else if (!strcmp(argv[i], "-bell"))
  269. X        ring_bell = 1;
  270. X    else if (!strcmp(argv[i], "-snoop")) {
  271. X        char *name;
  272. X
  273. X            while (i+1 < argc && argv[i+1][0] != '-') {
  274. X        name = strtok(argv[++i], ",");
  275. X        do {
  276. X            strncpy(snoop_user[num_snoops], name, 8);
  277. X            snoop_user[num_snoops][8] = 0;    /* 8 chars max for usernames */
  278. X            num_snoops++;
  279. X        } while ((name = strtok(NULL, ",")) && (num_snoops < MaxSnoops));
  280. X        }
  281. X    }
  282. X    else
  283. X        syntax(app_con, argv[0]);
  284. X    }
  285. X
  286. X    viewport = XtCreateManagedWidget("viewport", viewportWidgetClass, toplevel, NULL, ZERO);
  287. X    box = XtCreateManagedWidget("box", boxWidgetClass, viewport, NULL, ZERO);
  288. X
  289. X    init_rwho(box);    /* initialise the rwho stuff */
  290. X    process_rwho();    /* create label widgets for all current users */
  291. X
  292. X    XtRealizeWidget(toplevel);
  293. X    XtAppAddTimeOut(XtWidgetToApplicationContext(toplevel), RefreshRate,
  294. X    refresh_rwho, NULL);
  295. X
  296. X    XtAppMainLoop(app_con);
  297. X} /* end of main() */
  298. X
  299. X
  300. Xvoid init_rwho(Widget top_box)
  301. X{
  302. X    DIR        *dir;
  303. X    struct dirent *dirent;
  304. X    int        i, host_in_whod;
  305. X    char hostname[64], filename[256];
  306. X    Arg        args[1];
  307. X    userinfo_t    *hui;
  308. X    host_t *head, *file, *tmp;
  309. X
  310. X
  311. X    if (gethostname(hostname, 64)) {
  312. X    /* no hostname, downer */
  313. X        perror("xrwho - hostname()");
  314. X    exit(1);
  315. X    }
  316. X    remove_tail(hostname);
  317. X
  318. X    /* move to rwhod spool area so we can read files in later on */
  319. X    if (chdir(RWHODIR)) {
  320. X    char *msg;
  321. X
  322. X    if (errno == EACCES)
  323. X        /* the directory exists, but we can't read it */
  324. X        msg = "ho hum";
  325. X    else
  326. X        msg = "check the RWHODIR #define";
  327. X
  328. X    fprintf(stderr, "xrwho - can't cd to %s (%s) - %s\n",
  329. X        RWHODIR, strerror(errno), msg);
  330. X
  331. X    if (errno != EACCES)
  332. X        exit(1);
  333. X    }
  334. X
  335. X    dir = opendir(".");
  336. X    if (!dir) {
  337. X#ifdef sun
  338. X    fprintf(stderr, "xrwho: can't open %s\n", RWHODIR);
  339. X#else
  340. X    fprintf(stderr, "xrwho: can't open %s (%s)\n", RWHODIR, strerror(errno));
  341. X#endif
  342. X    exit(1);
  343. X    }
  344. X
  345. X    i = 0;
  346. X    host_in_whod = 0;
  347. X
  348. X    /* init linked list for filenames */
  349. X    head = (host_t *)NULL;
  350. X
  351. X    while (dirent = readdir(dir))
  352. X    if (!strncmp(dirent->d_name, "whod.", 5)) {
  353. X        struct stat    stat_info;
  354. X        int        stat_failed;
  355. X
  356. X#ifdef Debug
  357. Xprintf("host rwho file %d: %s\n", i, file->name);
  358. X#endif
  359. X        strcpy(filename, dirent->d_name + 5);
  360. X        remove_tail(filename);
  361. X
  362. X        /* check whether we can read it, etc */
  363. X        stat_failed = stat(dirent->d_name, &stat_info);
  364. X
  365. X        /* search for hostname in whod files, and check whether the file
  366. X           has been updated in the past 12 hours - otherwise indicative
  367. X           of a dead entry for the host we're running on */
  368. X        if (!strcmp(hostname, filename)) {
  369. X        if (stat_failed && stat_info.st_mtime > (time(NULL) - 60*60*12))
  370. X            host_in_whod = 1;    /* rwho file is OK */
  371. X        else
  372. X            continue;        /* too old to be valid, so ignore */
  373. X        }
  374. X        if (stat_failed)
  375. X        continue;
  376. X
  377. X        /* malloc space for whod filename */
  378. X        if (head == (host_t *)NULL) {
  379. X        head = (host_t *)malloc(sizeof(host_t));
  380. X        if (head == NULL) {
  381. X            fprintf(stderr, "xrwho: can't malloc\n");
  382. X            Die;
  383. X        }
  384. X        file = head;
  385. X        file->prev = (host_t *)NULL;
  386. X        file->next = (host_t *)NULL;
  387. X        }
  388. X        else {
  389. X        file->next = (host_t *)malloc(sizeof(host_t));
  390. X        if (file->next == NULL) {
  391. X            fprintf(stderr, "xrwho: can't malloc\n");
  392. X            Die;
  393. X        }
  394. X        file->next->prev = file;
  395. X        file->next->next = (host_t *)NULL;
  396. X        file = file->next;
  397. X        }
  398. X
  399. X        /* read filename */
  400. X        strcpy(file->name, dirent->d_name);
  401. X
  402. X        i++;
  403. X    }
  404. X    closedir(dir);
  405. X    no_of_hosts = i;
  406. X
  407. X    /*
  408. X     * sort hostnames into alphabetical order
  409. X     */
  410. X    if (no_of_hosts)
  411. X    sort(head);
  412. X
  413. X    /*
  414. X     * if host machine not in whod list then use utmp instead
  415. X     */
  416. X    if (!host_in_whod)
  417. X    no_of_hosts++;
  418. X
  419. X#ifdef Debug
  420. Xif (!host_in_whod)
  421. X    printf("No rwho file for localhost - using utmp instead\n");
  422. X#endif
  423. X
  424. X    /*
  425. X     * allocate and zero the userinfo array
  426. X     * assume number of hosts isn't going to change that often
  427. X     */
  428. X    host_userinfo = (userinfo_t *)malloc(no_of_hosts*sizeof(userinfo_t));
  429. X    if (host_userinfo == NULL) {
  430. X    fprintf(stderr, "xrwho: can't malloc\n");
  431. X    Die;
  432. X    }
  433. X
  434. X    /*
  435. X     * create enclosing boxes for each host, and set hostnames as labels
  436. X     */
  437. X    i = 0;
  438. X    for (file = head; file != (host_t *)NULL; file = file->next) {
  439. X
  440. X    hui = &(host_userinfo[i]);
  441. X    hui->host_file_type = rwho;
  442. X    hui->head = (user_t *)NULL;
  443. X
  444. X    /* set the host file name */
  445. X    strcpy(hui->host_filename, file->name);
  446. X
  447. X    /* set the hostname, removing trailing dots */
  448. X    strcpy(hui->host_name, hui->host_filename + 5);
  449. X    remove_tail(hui->host_name);
  450. X
  451. X    hui->box = XtCreateManagedWidget(hui->host_name,
  452. X        boxWidgetClass, top_box, NULL, ZERO);
  453. X
  454. X    hui->title = XtCreateManagedWidget("host",
  455. X        labelWidgetClass, hui->box, NULL, ZERO);
  456. X    XtSetArg(args[0], XtNlabel, hui->host_name);
  457. X    XtSetValues(hui->title, args, ONE);
  458. X
  459. X    i++;
  460. X    }
  461. X
  462. X    /*
  463. X     * add a widget for localhost if it's not in the whod files
  464. X     */
  465. X    if (!host_in_whod) {
  466. X    hui = &(host_userinfo[no_of_hosts - 1]);
  467. X    hui->host_file_type = local;
  468. X    hui->head = (user_t *)NULL;
  469. X
  470. X    strcpy(hui->host_name, hostname);
  471. X
  472. X    hui->box = XtCreateManagedWidget(hui->host_name,
  473. X        boxWidgetClass, top_box, NULL, ZERO);
  474. X
  475. X    hui->title = XtCreateManagedWidget("host",
  476. X        labelWidgetClass, hui->box, NULL, ZERO);
  477. X    XtSetArg(args[0], XtNlabel, hui->host_name);
  478. X    XtSetValues(hui->title, args, ONE);
  479. X    }
  480. X
  481. X    /* free tmp filename info */
  482. X    file = head;
  483. X    while (file != (host_t *)NULL) {
  484. X    tmp = file->next;
  485. X    free(file);
  486. X    file = tmp;
  487. X    }
  488. X} /* end of init_rwho() */
  489. X
  490. X
  491. X/*
  492. X * Remove trailing part of a string of the form "a.b.c.d", leaving just "a"
  493. X */
  494. X
  495. Xvoid remove_tail(char *string)
  496. X{
  497. X    if (string = strchr(string, '.'))
  498. X    *string = '\0';
  499. X}
  500. X
  501. X
  502. X/*
  503. X * search_for_user
  504. X *    Scans a host's userlist for a particular name, returning the
  505. X *    array index if found, or -1 if not.
  506. X */
  507. X
  508. Xint search_for_user(userinfo_t *hui, char *name, user_t **found)
  509. X{
  510. X    user_t *i;
  511. X
  512. X    for (i = hui->head; i != (user_t *)NULL; i = i->next)
  513. X    if (!strcmp(name, i->name)) {
  514. X        *found = i;
  515. X        return 0;
  516. X    }
  517. X
  518. X    *found = (user_t *)NULL;
  519. X    return -1;
  520. X}
  521. X
  522. X
  523. X/*
  524. X * sort
  525. X *     sort filenames into alphabetical order by straight insertion
  526. X */
  527. Xvoid sort(host_t *head) {
  528. X    host_t *i, *j;
  529. X    char a[256];
  530. X
  531. X    for (j = head->next; j != (host_t *)NULL; j = j->next) {
  532. X
  533. X    strcpy(a, j->name);
  534. X
  535. X    i = j->prev;
  536. X    while ((i->prev != (host_t *)NULL) && (strcmp(i->name, a) > 0)) {
  537. X        strcpy(i->next->name, i->name);
  538. X        i = i->prev;
  539. X    }
  540. X
  541. X    if ((i == head) && (strcmp(i->name, a) > 0)) {
  542. X        strcpy(i->next->name, i->name);
  543. X        strcpy(i->name, a);
  544. X    }
  545. X    else
  546. X        strcpy(i->next->name, a);
  547. X    }
  548. X
  549. X#ifdef Debug
  550. Xprintf("\nhosts in order:\n");
  551. Xfor (j = head; j != (host_t *)NULL; j = j->next)
  552. X    printf("  %s", j->name);
  553. Xprintf("\n");
  554. X#endif
  555. X
  556. X}
  557. X
  558. X
  559. X/*
  560. X * read_utmp
  561. X *    Read in a utmp file; returns the number of users in the file.
  562. X */
  563. X
  564. Xint read_utmp(struct utmp utmp[], int max_entries)
  565. X{
  566. X    int fd, bytes;
  567. X
  568. X    fd = open(UTMP_FILE, O_RDONLY);
  569. X    if (fd < 0) {
  570. X#ifdef Debug
  571. X    fprintf(stderr, "xrwho: can't open %s\n", UTMP_FILE);
  572. X#endif
  573. X    return 0;
  574. X    }
  575. X    bytes = read(fd, utmp, max_entries*sizeof(struct utmp));
  576. X    close(fd);
  577. X    return bytes/sizeof(struct utmp);
  578. X}
  579. X
  580. X
  581. X/*
  582. X * read_rwho
  583. X *    Read in a whod file; returns the number of users in the file.
  584. X */
  585. X
  586. Xint read_rwho(char *filename, struct whod *who)
  587. X{
  588. X    int fd, bytes;
  589. X
  590. X    fd = open(filename, O_RDONLY);
  591. X    if (fd < 0) {
  592. X#ifdef Debug
  593. X    fprintf(stderr, "xrwho: can't open %s/%s\n", RWHODIR, filename);
  594. X#endif
  595. X    return 0;
  596. X    }
  597. X    bytes = read(fd, who, sizeof(struct whod));
  598. X    close(fd);
  599. X
  600. X    if ((time(NULL) - who->wd_recvtime) > HostDeadTime) {
  601. X    /* we haven't heard from host for too long so ignore it */
  602. X    return 0;
  603. X    }
  604. X
  605. X    return (bytes - 60)/sizeof(struct whoent);    /* number of whoent records */
  606. X}
  607. X
  608. X
  609. Xvoid process_rwho(void)
  610. X{
  611. X    int        i, n;
  612. X    struct whod    who;
  613. X    struct utmp    utmp[MaxUtmpEntries];
  614. X    Arg        args[1];
  615. X    int        j;
  616. X    user_t    *k, *prev;
  617. X    time_t    time_now = time(NULL);
  618. X
  619. X    /* add labels to the box, one per remote user */
  620. X    for (i = 0; i < no_of_hosts; i++) {
  621. X    userinfo_t    *hui = &(host_userinfo[i]);
  622. X
  623. X    switch (hui->host_file_type) {
  624. X        case local: n = read_utmp(utmp, MaxUtmpEntries); break;
  625. X        case rwho:    n = read_rwho(hui->host_filename, &who); break;
  626. X    }
  627. X
  628. X    /*
  629. X     * set all idle times to infinity, and still_here to false
  630. X     * so that the following update works correctly
  631. X     */
  632. X    for (k = hui->head; k != (user_t *)NULL; k = k->next) {
  633. X        k->idle = INT_MAX;
  634. X        k->still_here = 0;
  635. X    }
  636. X
  637. X    /*
  638. X     * scan through the utmp-style array for the host, updating idle times
  639. X     * and checking whether users are still logged on
  640. X     */
  641. X    for (j = 0; j < n; j++) {
  642. X        char *name;
  643. X        int    idle;
  644. X
  645. X        switch (hui->host_file_type) {
  646. X        case local: {
  647. X            char    tmp[64];
  648. X            struct stat    stat_info;
  649. X#ifdef USER_PROCESS
  650. X            /* SYSV-style utmp */
  651. X            if (utmp[j].ut_type != USER_PROCESS)
  652. X            continue;    /* ignore everything else */
  653. X            name = utmp[j].ut_user;
  654. X#else
  655. X            if (!utmp[j].ut_name)
  656. X            continue;
  657. X            name = utmp[j].ut_name;
  658. X#endif
  659. X            /* check how long it's been since the user last accessed
  660. X               their tty */
  661. X            strcpy(tmp, "/dev/");
  662. X            if (!stat(strcat(tmp, utmp[j].ut_line), &stat_info))
  663. X            idle = time_now - stat_info.st_atime;
  664. X            else {
  665. X#ifdef Debug
  666. X            fprintf(stderr, "can't stat %s\n", tmp);
  667. X#endif
  668. X            idle = 0;    /* ignore */
  669. X            }
  670. X            break;
  671. X        }
  672. X        case rwho:
  673. X            name = who.wd_we[j].we_utmp.out_name;
  674. X            idle = who.wd_we[j].we_idle;
  675. X            break;
  676. X        }
  677. X
  678. X        /* handle 8-char usernames */
  679. X        name[8] = 0;
  680. X
  681. X#ifdef Debug
  682. Xprintf("checking %s in %s (idle %d seconds)\n", name,
  683. X    hui->host_filename, idle);
  684. X#endif
  685. X
  686. X        /* check host_userinfo for this name */
  687. X        if (search_for_user(hui, name, &k) != -1) {
  688. X        /* matched existing user */
  689. X
  690. X#ifdef Debug
  691. Xprintf("user %s matched (idle %d)\n", k->name, k->idle);
  692. X#endif
  693. X        k->idle = MIN(k->idle, idle);
  694. X        k->still_here++;
  695. X        }
  696. X        else {
  697. X        /* new user */
  698. X
  699. X        /* check whether idle is too long */
  700. X        if (list_long || idle < OldUserIdleTime) {
  701. X            int m, snoop;
  702. X
  703. X            if (hui->head == (user_t *)NULL) {
  704. X            /* this is 1st user for this host */
  705. X            hui->head = (user_t *)malloc(sizeof(user_t));
  706. X            if (hui->head == NULL) {
  707. X                fprintf(stderr, "xrwho: can't malloc\n");
  708. X                Die;
  709. X            }
  710. X            k = hui->head;
  711. X            k->next = (user_t *)NULL;
  712. X            }
  713. X            else {
  714. X            k = (user_t *)malloc(sizeof(user_t));
  715. X            if (k == NULL) {
  716. X                fprintf(stderr, "xrwho: can't malloc\n");
  717. X                Die;
  718. X            }
  719. X            k->next = hui->head;
  720. X            hui->head = k;
  721. X            }
  722. X
  723. X            /*
  724. X             * add user to list
  725. X             */
  726. X            strcpy(k->name, name);
  727. X            k->idle = idle;
  728. X            k->still_here = 1;
  729. X
  730. X            /*
  731. X             * see if the user is snooped upon
  732. X             */
  733. X            snoop = 0;
  734. X            for (m = 0; m < num_snoops; m++) {
  735. X            if (!strcmp(snoop_user[m], k->name)) {
  736. X                snoop++;
  737. X#ifdef Debug
  738. Xprintf("created snoop user %s from %s\n", snoop_user[m], hui->host_filename);
  739. X#endif
  740. X                k->label = XtCreateManagedWidget("snoop",
  741. X                labelWidgetClass, hui->box, NULL, ZERO);
  742. X                XtSetArg(args[0], XtNlabel, k->name);
  743. X                XtSetValues(k->label, args, ONE);
  744. X                if (ring_bell)
  745. X                XBell(XtDisplay(toplevel), 1);
  746. X            }
  747. X                }
  748. X
  749. X            if (!snoop) {
  750. X            k->label = XtCreateManagedWidget(k->name,
  751. X                labelWidgetClass, hui->box, NULL, ZERO);
  752. X#ifdef Debug
  753. Xprintf("created %s from %s\n", k->name, hui->host_filename);
  754. X#endif
  755. X            }
  756. X        }
  757. X        }
  758. X    }
  759. X
  760. X    /* check whether any of the users has logged out, or idle is too long */
  761. X    k = hui->head;
  762. X    prev = (user_t *)NULL;
  763. X    while (k != (user_t *)NULL) {
  764. X        if (!(k->still_here) || (!list_long && (k->idle > OldUserIdleTime))) {
  765. X#ifdef Debug
  766. Xprintf("removed %s from %s\n", k->name, hui->host_name);
  767. X#endif
  768. X        XtDestroyWidget(k->label);
  769. X
  770. X        /* unlink k from the list */
  771. X        if (prev == (user_t *)NULL) {
  772. X            /* user is head of list */
  773. X            hui->head = k->next;
  774. X            free(k);
  775. X            k = hui->head;
  776. X        }
  777. X        else {
  778. X            prev->next = k->next;
  779. X            free(k);
  780. X            k = prev->next;
  781. X        }
  782. X        }
  783. X        else {
  784. X        prev = k;
  785. X        k = k->next;
  786. X        }
  787. X    }
  788. X
  789. X    /* set each user as insensitive or sensitive, according to idle time */
  790. X    for (k = hui->head; k != (user_t *)NULL; k = k->next) {
  791. X
  792. X#ifdef Debug
  793. Xprintf("user %s: %s\n", k->name,
  794. X    k->idle < InsensitiveIdleTime ? "active" : "inactive");
  795. X#endif
  796. X        XtSetArg(args[0], XtNsensitive,
  797. X        k->idle < InsensitiveIdleTime ? True : False);
  798. X        XtSetValues(k->label, args, ONE);
  799. X    }
  800. X
  801. X    /*
  802. X     * want to hide machine title (and possibly box) if there are no users,
  803. X     * and display it again if there are some.
  804. X     */
  805. X    if (!show_all_hosts) {
  806. X        Widget wid = empty_boxes ? hui->title : hui->box;
  807. X
  808. X        if (hui->head != (user_t *)NULL) {
  809. X        if (!XtIsManaged(wid)) {
  810. X            XtManageChild(wid);
  811. X#ifdef Debug
  812. Xprintf("has users: adding management to %s\n", hui->host_name);
  813. X#endif
  814. X        }
  815. X        }
  816. X        else {
  817. X            if (XtIsManaged(wid)) {
  818. X            XtUnmanageChild(wid);
  819. X#ifdef Debug
  820. Xprintf("no users: removing management from %s\n", hui->host_name);
  821. X#endif
  822. X        }
  823. X        }
  824. X    }
  825. X    } /* end of host loop */
  826. X
  827. X#ifdef Debug
  828. X{
  829. X    int i;
  830. X
  831. X    printf("at end of loop -- status:\n");
  832. X    for (i = 0; i < no_of_hosts; i++) {
  833. X    userinfo_t    *hui = &(host_userinfo[i]);
  834. X        user_t *k;
  835. X
  836. X        if (hui->head != (user_t *)NULL)
  837. X            printf("%s (%s) wid: %ld\n", hui->host_name,
  838. X        XtIsManaged(hui->title) ? "managed" : "not managed", hui->title);
  839. X
  840. X        for (k = hui->head; k != (user_t *)NULL; k = k->next) {
  841. X       printf("   %s - idle %d %s (%d) wid: %ld\n", k->name, k->idle,
  842. X        k->still_here > 0 ? "here" : "not here", k->still_here, k->label);
  843. X        }
  844. X    }
  845. X}
  846. X#endif
  847. X
  848. X}
  849. X
  850. X
  851. X/*
  852. X * refresh_rwho
  853. X *    Refresh the rwho display after an interval has expired.
  854. X */
  855. X
  856. Xvoid refresh_rwho(XtPointer client_data, XtIntervalId *id)
  857. X{
  858. X    /* set it up again */
  859. X    XtAppAddTimeOut(XtWidgetToApplicationContext(toplevel), RefreshRate,
  860. X    refresh_rwho, NULL);
  861. X
  862. X    /* check what has changed since last time */
  863. X    process_rwho();
  864. X}
  865. X
  866. X
  867. Xvoid syntax(XtAppContext app_con, char *call)
  868. X{
  869. X    XtDestroyApplicationContext(app_con);
  870. X    fprintf(stderr, "Usage: %s [-a] [-l | -b] [-snoop <user1>,<user2>,... [-bell] ]\n", call);
  871. X    fprintf(stderr, "             [-font <font>] [-hostfont <font>]\n");
  872. X    fprintf(stderr, "             [-hostfg <color>] [-hostbg <color>]\n");
  873. X    fprintf(stderr, "             [-highlight <color>]\n");
  874. X    fprintf(stderr, "           + usual X options.\n");
  875. X    fprintf(stderr, "   -a   shows users with long idle times also.\n");
  876. X    fprintf(stderr, "   -l   shows hostnames when no users are logged in.\n");
  877. X    fprintf(stderr, "   -b   shows empty boxes when no users are logged in.\n");
  878. X    fprintf(stderr, "   -snoop <user1>,<user2>,...  highlights particular users.\n");
  879. X    fprintf(stderr, "   -bell   beeps when a snooped user arrives.\n");
  880. X    fprintf(stderr, "   -highlight   sets the colour of a snooped user (default red).\n");
  881. X    exit(1);
  882. X}
  883. X
  884. END_OF_xrwho.c
  885. if test 19344 -ne `wc -c <xrwho.c`; then
  886.     echo shar: \"xrwho.c\" unpacked with wrong size!
  887. fi
  888. # end of overwriting check
  889. fi
  890. if test -f xrwho.man -a "${1}" != "-c" ; then 
  891.   echo shar: Will not over-write existing file \"xrwho.man\"
  892. else
  893. echo shar: Extracting \"xrwho.man\" \(3708 characters\)
  894. sed "s/^X//" >xrwho.man <<'END_OF_xrwho.man'
  895. X.TH XRWHO 1 "October 1992" "X Version 11"
  896. X.SH NAME
  897. Xxrwho - display of who is logged into local machines for X
  898. X.SH SYNOPSIS
  899. X.B xrwho
  900. X[ -toolkitoption ] [-option ...]
  901. X.SH DESCRIPTION
  902. X.I xrwho
  903. Xdisplays the users logged into hosts on the local network.
  904. X.I xrwho
  905. Xruns under the
  906. X.I X
  907. Xwindow system.
  908. X.I xrwho
  909. Xcreates a window in which the names of local machines
  910. Xand the users that are on these machines are displayed.
  911. XEach host machine has its own box in which the users
  912. Xlogged onto this machine are shown.
  913. X.PP
  914. X.I xrwho
  915. Xacts in most respects like
  916. X.I rwho(1).
  917. XUsers that have been idle for more than 5 minutes are
  918. Xdisplayed as shaded, rather than full intensity. Users
  919. Xwho have been idle for more than one hour, and host machines
  920. Xthat have no users logged in, are usually not shown.
  921. XIf nothing has been heard from a machine for 5 minutes
  922. Xthen the host is assumed to be down and no information
  923. Xis displayed for that machine.
  924. X.PP
  925. X.I xrwho
  926. Xuses the
  927. X.I X Toolkit
  928. Xto display the windows, and so accepts options like 
  929. X.B \-geometry, \-fg
  930. Xcolour and
  931. X.B \-display \fIhost:display.\fP
  932. XIn addition to these standard
  933. X.I Xt
  934. Xflags, 
  935. X.I xrwho
  936. Xunderstands the following options:
  937. X.PP
  938. X.TP 8
  939. X.B \-a
  940. Xdisplays users with idle times over one hour
  941. X.TP 8
  942. X.B \-l
  943. Xdisplay host names and boxes even when no users are logged in
  944. X.TP 8
  945. X.B \-b
  946. Xshows a tiny box when a host has no users (only one of
  947. X.B \-b
  948. Xand
  949. X.B \-l
  950. Xmay be used).
  951. X.TP 8
  952. X.B \-snoop \fI<user1>,<user2>,...\fP
  953. Xhighlight particular users using a different colour.
  954. X.TP 8
  955. X.B \-bell
  956. Xring the console bell when a snooped user arrives.
  957. X.TP 8
  958. X.B \-font \fIfontname\fP
  959. Xuser names will be displayed in the specified font (if none
  960. Xis specified, this defaults to helvetica).
  961. X.TP 8
  962. X.B \-hostfont \fIfontname\fP
  963. Xhost names will be displayed in the specified font (if none
  964. Xis specified, this defaults to helvetica oblique).
  965. X.TP 8
  966. X.B \-hostfg \fIcolour\fP
  967. Xhost names will be displayed in the specified colour (default blue)
  968. X.TP 8
  969. X.B \-hostbg \fIcolour\fP
  970. Xhost names will be displayed in a box of the specified colour.
  971. X.TP 8
  972. X.B \-highlight \fIcolour\fP
  973. Xsnoop users will be displayed in the specified colour (default red)
  974. X.PP
  975. X.SH X DEFAULTS
  976. XThe widget classes used by 
  977. X.I xrwho
  978. Xare:
  979. X.PP
  980. X.RS
  981. X.nf
  982. XBox
  983. XLabel
  984. XViewport
  985. X.fi
  986. X.PP
  987. X.RE
  988. XSome of the X resources used by
  989. X.I xrwho
  990. Xare:
  991. X.PP
  992. X.TP 20
  993. X.B font
  994. Xset the font for user names.
  995. X.TP 20
  996. X.B host.font
  997. Xset the font for the hostname.
  998. X.TP 20
  999. X.B foreground
  1000. Xset the window foreground colour
  1001. X.TP 20
  1002. X.B background
  1003. Xset the window background colour
  1004. X.TP 20
  1005. X.B host.foreground
  1006. Xset the host label foreground colour
  1007. X.TP 20
  1008. X.B host.background
  1009. Xset the host box background colour
  1010. X.TP 20
  1011. X.B snoop.foreground
  1012. Xset the colour that snoop users appear in
  1013. X.TP 20
  1014. X.B Label*borderWidth
  1015. Xset the width of the border in pixels around the labels (default 0)
  1016. X.TP 20
  1017. X.B vSpace
  1018. Xset the vertical spacing in pixels between host boxes (default 1)
  1019. X.PP
  1020. XFor example, the following could be put into your ~/.Xdefaults file:
  1021. X.PP
  1022. X.EX
  1023. X.nf
  1024. Xxrwho*foreground:        black
  1025. Xxrwho*background:        white
  1026. Xxrwho*host.foreground:   white
  1027. Xxrwho*host.background:   blue
  1028. Xxrwho*snoop.foreground:  red
  1029. Xxrwho*Label*borderWidth: 0
  1030. Xxrwho*borderColor:       black
  1031. Xxrwho*vSpace:            1
  1032. Xxrwho*font:      -*-helvetica-*-r-*-*-*-100-*-*-*-*-*-*
  1033. Xxrwho*host.font: -*-helvetica-*-*-*-*-*-100-*-*-*-*-*-*
  1034. X.fi
  1035. X.EE
  1036. X.PP
  1037. X.SH ENVIRONMENT
  1038. XDISPLAY - to get the default host and display number.
  1039. X.PP
  1040. X.SH SEE ALSO
  1041. XX(1), xrdb(1), rwho(1C), rwhod(1M)
  1042. X.PP
  1043. X.SH FILES
  1044. X/usr/spool/rwho/*
  1045. X.PP
  1046. X.SH DIAGNOSTICS
  1047. XVarious X errors.
  1048. X.PP
  1049. X.SH BUGS
  1050. XThere is currently a maximum of 32 snoop users.
  1051. X.PP
  1052. X.SH AUTHORS
  1053. X.nf
  1054. X.TP 20
  1055. XAndrew Herbert
  1056. Xandrewh@cs.monash.edu.au
  1057. Xandrew@werple.apana.org.au
  1058. X.fi
  1059. X.TP 20
  1060. XRobin Humble
  1061. Xrjh@pixel.maths.monash.edu.au
  1062. END_OF_xrwho.man
  1063. if test 3708 -ne `wc -c <xrwho.man`; then
  1064.     echo shar: \"xrwho.man\" unpacked with wrong size!
  1065. fi
  1066. # end of overwriting check
  1067. fi
  1068. if test -f Imakefile -a "${1}" != "-c" ; then 
  1069.   echo shar: Will not over-write existing file \"Imakefile\"
  1070. else
  1071. echo shar: Extracting \"Imakefile\" \(195 characters\)
  1072. sed "s/^X//" >Imakefile <<'END_OF_Imakefile'
  1073. X# xrwho - an X windows display of users on local machines
  1074. X
  1075. XPROGRAMS = xrwho
  1076. XLOCAL_LIBRARIES = $(XAWLIB) $(XMULIB) $(XTOOLLIB) $(XLIB)
  1077. X
  1078. XSRCS = xrwho.c
  1079. X
  1080. XOBJS = xrwho.o
  1081. X
  1082. XComplexProgramTarget(xrwho)
  1083. END_OF_Imakefile
  1084. if test 195 -ne `wc -c <Imakefile`; then
  1085.     echo shar: \"Imakefile\" unpacked with wrong size!
  1086. fi
  1087. # end of overwriting check
  1088. fi
  1089. if test -f Makefile.easy -a "${1}" != "-c" ; then 
  1090.   echo shar: Will not over-write existing file \"Makefile.easy\"
  1091. else
  1092. echo shar: Extracting \"Makefile.easy\" \(218 characters\)
  1093. sed "s/^X//" >Makefile.easy <<'END_OF_Makefile.easy'
  1094. X
  1095. X# gcc is better if you're got it
  1096. XCC = gcc
  1097. XCFLAGS = -O
  1098. X
  1099. X#sgi
  1100. XCLIBS = -lXaw -lXmu -lXt_s -lX11_s -lmalloc -lc_s
  1101. X
  1102. X#dec/386bsd/sun
  1103. XCLIBS = -lXaw -lXmu -lXt -lX11
  1104. X
  1105. Xxrwho: xrwho.o
  1106. X    $(CC) $(CFLAGS) xrwho.o $(CLIBS) -o xrwho
  1107. END_OF_Makefile.easy
  1108. if test 218 -ne `wc -c <Makefile.easy`; then
  1109.     echo shar: \"Makefile.easy\" unpacked with wrong size!
  1110. fi
  1111. # end of overwriting check
  1112. fi
  1113. if test -f Xrwho.apps -a "${1}" != "-c" ; then 
  1114.   echo shar: Will not over-write existing file \"Xrwho.apps\"
  1115. else
  1116. echo shar: Extracting \"Xrwho.apps\" \(329 characters\)
  1117. sed "s/^X//" >Xrwho.apps <<'END_OF_Xrwho.apps'
  1118. X
  1119. X! xrwho
  1120. X
  1121. Xxrwho*foreground:        black
  1122. Xxrwho*background:        white
  1123. Xxrwho*borderColor:        black
  1124. Xxrwho*host.foreground:        white
  1125. Xxrwho*host.background:        blue
  1126. Xxrwho*Label*borderWidth:    0
  1127. Xxrwho*vSpace:            1
  1128. Xxrwho*font:            -*-helvetica-*-r-*-*-*-100-*-*-*-*-*-*
  1129. Xxrwho*host.font:        -*-helvetica-*-*-*-*-*-100-*-*-*-*-*-*
  1130. Xxrwho*snoop.foreground:        red
  1131. END_OF_Xrwho.apps
  1132. if test 329 -ne `wc -c <Xrwho.apps`; then
  1133.     echo shar: \"Xrwho.apps\" unpacked with wrong size!
  1134. fi
  1135. # end of overwriting check
  1136. fi
  1137. echo shar: End of shell archive.
  1138. exit 0
  1139.  
  1140.