home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume13 / faces-1.4.5 / part01 next >
Text File  |  1990-07-02  |  52KB  |  1,552 lines

  1. Newsgroups: comp.sources.misc
  2. subject: v13i070: Faces v1.4.5: a visual list monitor for mail etc.. (Part 1 of 7).
  3. from: rburridge@Sun.COM (Rich Burridge)
  4. Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  5.  
  6. Posting-number: Volume 13, Issue 70
  7. Submitted-by: rburridge@Sun.COM (Rich Burridge)
  8. Archive-name: faces-1.4.5/part01
  9.  
  10. [** NOTE: faces v1.4 is posted to comp.sources.misc at patchlevel #5. **]
  11.  
  12. This is the third general release of a "faces" server for monitoring a
  13. list visually. Typically this is a list of incoming mail messages, jobs
  14. in the print queue or users on a system.
  15.  
  16. Included with this release, is the ability to include a face image with
  17. your mail message using an X-Face header line (plus continuation lines).
  18. Faces expects this line to be in a certain compressed format, and
  19. uncompresses it, and displays that image on-the-fly. There is also an
  20. option to automatically update the faces database with this new image.
  21.  
  22. See the README for more details.
  23.  
  24. The TODO file contains many ideas of enhancements to faces, some
  25. relatively simple, others quite a lot of work. Volunteers anyone?
  26.  
  27. Rich Burridge,          DOMAIN: richb@Aus.Sun.COM
  28. PHONE: +61 2 413 2666   ACSnet: richb@sunaus.sun.oz.au
  29.  
  30. ------CUT HERE------faces.part1------CUT HERE------
  31. #! /bin/sh
  32. # this is a shell archive, meaning:
  33. # 1. Remove everything above the #! /bin/sh line
  34. # 2. Save the resulting text in a file.
  35. # 3. Execute the file with /bin/sh to create the files:
  36. #    mon.c
  37. #    main.c
  38. #    rec.c
  39. # This archive created: Fri Jun 29 10:45:06 EST 1990
  40. #
  41. #
  42. export PATH; PATH=/bin:$PATH
  43. #
  44. if [ -f mon.c ]
  45. then
  46. echo shar: will not over-write existing file mon.c
  47. else
  48. echo shar: extracting 'mon.c',    20347 characters
  49. cat > mon.c <<'Funky_Stuff'
  50.  
  51. /*  @(#)mon.c 1.17 90/06/26
  52.  *
  53.  *  Monitoring routines used by the faces program.
  54.  * 
  55.  *  Copyright (c) Rich Burridge - Sun Microsystems Australia.
  56.  *                                All rights reserved.
  57.  *
  58.  *  Permission is given to distribute these sources, as long as the
  59.  *  copyright messages are not removed, and no monies are exchanged. 
  60.  * 
  61.  *  No responsibility is taken for any errors on inaccuracies inherent
  62.  *  either to the comments or the code of this program, but if reported
  63.  *  to me, then an attempt will be made to fix them.
  64.  */
  65.  
  66. #include <stdio.h>
  67. #include <strings.h>
  68. #include <sys/types.h>
  69. #include <sys/stat.h>
  70. #include <sys/time.h>
  71. #include <sys/file.h>
  72. #include "faces.h"
  73. #include "extern.h"
  74.  
  75.  
  76. add_face(dtype, itype, name)
  77. enum disp_type dtype ;
  78. enum icon_type itype ;
  79. char *name ;
  80. {
  81.   unsigned short buf[256] ;  /* Ikon/icon image. */
  82.  
  83.   if (itype == XFACE)
  84.     {
  85.       itype = ORDINARY ;
  86.       destroy_image(itype) ;
  87.       get_xface(face_buf, buf) ;
  88.       load_icon(itype, buf, 0) ;
  89.     }
  90.   else if (itype == ORDINARY)
  91.     {
  92.       destroy_image(itype) ;
  93.       if (get_icon(name, buf) == -1) itype = NOFACE ;
  94.       else load_icon(itype, buf, 0) ;
  95.     }
  96.  
  97.   switch (dtype)
  98.     {
  99.       case DISP_ALL   : adjust_image(DISP_NAME,  itype, row, column) ;
  100.                         adjust_image(DISP_OTHER, itype, row, column) ;
  101.                         adjust_image(DISP_ICON,  itype, 0, 0) ;
  102.                         break ;
  103.       case DISP_BOTH  : adjust_image(DISP_NAME,  itype, row, column) ;
  104.                         adjust_image(DISP_OTHER, itype, row, column) ;
  105.                         break ;
  106.       case DISP_ICON  : adjust_image(dtype, itype, 0, 0) ;
  107.                         break ;
  108.       case DISP_NAME  :
  109.       case DISP_OTHER : adjust_image(dtype, itype, row, column) ;
  110.     }
  111. }
  112.  
  113.  
  114. adjust()          /* Adjust the row and column position. */
  115. {
  116.   struct psinfo *this ;
  117.  
  118.   if (mtype != MONNEW)
  119.     {
  120.       if (++column == maxcols)
  121.         {
  122.           column = 0 ;
  123.           row++ ;
  124.         }
  125.       return ;
  126.     }
  127.   if (psrecs != NULL)           /* Adjust animation positions for MONNEW */
  128.     {
  129.       this = psrecs ;           /* Point to beginning of chain. */
  130.       while (this != NULL)
  131.         {
  132.           this->column++ ;      /* Adjust column position. */
  133.           if (facetype == NEWSTYPE && this->next == NULL)
  134.             this->column-- ;    /* Reset for brand new animate record. */
  135.           this = this->next ;
  136.         }
  137.     }
  138. }
  139.  
  140.  
  141. do_check()        /* Perform another check of the appropriate type. */
  142. {
  143.   switch (mtype)
  144.     {
  145.       case MONALL     : do_mail(MONALL) ;  /* Monitor all of the mail file. */
  146.                         break ;
  147.       case MONNEW     : do_mail(MONNEW) ;  /* Monitor new mail only. */
  148.                         break ;
  149.       case MONPRINTER : do_printer() ;     /* Monitor the print queue. */
  150.                         break ;
  151.       case MONPROG    : do_prog() ;        /* Run user supplied program. */
  152.                         break ;
  153.       case MONUSERS   : do_users() ;       /* Monitor users on a machine. */
  154.     }
  155.   firsttime = 0 ;
  156. }
  157.  
  158.  
  159. do_face_update(name, buf)   /* Send mail to update faces database. */
  160. char *name, buf[2048] ;
  161. {
  162.   FILE *fp ;                /* File descriptor for users mail spool file. */
  163.   char command[MAXLINE] ;   /* Command to send mail to special alias. */
  164.  
  165.   SPRINTF(command, UPDATEDEF, update_alias) ;
  166.   if ((fp = popen(command, "w")) == NULL)     /* Open pipe to mail process. */
  167.     {
  168.       FPRINTF(stderr,"%s: couldn't send mail to update database.\n", progname) ;
  169.       return ;
  170.     }
  171.   FPRINTF(fp, "To: %s\n", update_alias) ;
  172.   FPRINTF(fp, "Subject: %s\n\n", name) ;  /* Send icon name. */
  173.   FPRINTF(fp, "%s\n", buf) ;              /* Send ikon data. */
  174.   PCLOSE(fp) ;
  175. }
  176.  
  177.  
  178. do_mail(mtype)              /* Monitor a mail file for new or all mail. */
  179. enum mon_type mtype ;
  180. {        
  181.   FILE *fp ;                /* File descriptor for users mail spool file. */
  182.   time_t ubuf[2] ;          /* For reseting the access time on spoolfile. */
  183.  
  184.   column = row = 0 ;        /* Start in top left corner of pixrect. */
  185.   newmail = 0 ;             /* Assume no new mail. */
  186.   noicons = 0 ;
  187.  
  188.   if (mtype == MONNEW) make_pixrect(maxcols) ;
  189.   if (stat(spoolfile, &buf) == -1)
  190.     {
  191.       lastsize = 0 ;
  192.       add_face(DISP_ICON, NOMAIL, "") ;
  193.       if (mtype == MONNEW) show_display() ;   /* Show new mail. */
  194.       else make_display() ;     /* Output icons and tidyup chain of records. */
  195.       return ;
  196.     }
  197.   if (buf.st_size > lastsize) newmail = 1 ;   /* New mail found. */
  198.   if (!buf.st_size) add_face(DISP_ICON, NOMAIL, "") ;
  199.  
  200.   ubuf[0] = buf.st_atime ;                    /* Save for possible reset. */
  201.   ubuf[1] = buf.st_mtime ;
  202.  
  203.   if (mtype == MONNEW)
  204.     if (buf.st_size <= lastsize)   /* Is the size of mail folder bigger? */
  205.       if (mhflag && (buf.st_size < lastsize) && (buf.st_size != 0))
  206.         {
  207.           lastsize = 0 ;    /* User uses MH. Any shrinkage means new mail. */
  208.           newmail = 1 ;
  209.         }
  210.       else
  211.         {
  212.           lastsize = buf.st_size ;   /* No: save new size and exit. */
  213.           show_display() ;
  214.           return ;
  215.         }
  216.  
  217.   if ((fp = fopen(spoolfile, "r")) == NULL)   /* Open spoolfile. */
  218.     {
  219.       if (mtype == MONNEW) show_display() ;   /* Show new mail. */
  220.       else make_display() ;     /* Output icons and tidyup chain of records. */
  221.       return ;
  222.     }
  223.   if (mtype == MONNEW) FSEEK(fp, lastsize, 0) ;
  224.   lastsize = buf.st_size ;
  225.   while (fgets(line, MAXLINE, fp) != NULL)
  226.     {
  227.       if (EQUAL(line, "From "))
  228.         {
  229.           if (froms_found) process_info() ;  /* Process previous mail. */
  230.           process_from() ;                   /* Save new from details. */
  231.         }
  232.       else if (EQUAL(line, "From:"))  process_from() ;
  233.       else if (EQUAL(line, "X-Face")) process_face() ;
  234.       else if (doing_xface)           process_face() ;
  235.     }
  236.   FCLOSE(fp) ;
  237.  
  238.   if (!stat(spoolfile, &buf))    /* Reset access time if no change in size. */
  239.     if (buf.st_size == lastsize)
  240.       UTIME(spoolfile, ubuf) ;
  241.  
  242.   if (froms_found) process_info() ;       /* Process remaining mail item. */
  243.   if (mtype == MONNEW) show_display() ;   /* Show new mail. */
  244.   else make_display() ;     /* Output icons and tidyup chain of records. */
  245. }
  246.  
  247.  
  248. do_printer()                 /* Monitor printer queue. */
  249. {
  250.   struct recinfo *this, *next ;
  251.   FILE *fp ;                 /* File descriptor for users mail spool file. */
  252.   char command[MAXLINE] ;    /* Print status command for this printer. */
  253.   char owner[MAXLINE] ;      /* Owner of job in the print queue. */
  254.   int size ;                 /* Size of this print job in bytes. */
  255.  
  256.   noicons = 0 ;
  257.   SPRINTF(command, PRINTDEF, printer) ;
  258.   if ((fp = popen(command, "r")) == NULL)     /* Open spoolfile. */
  259.     {
  260.       FPRINTF(stderr,"%s: couldn't get printer stats.\n", progname) ;
  261.       return ;
  262.     }
  263.   column = row = 0 ;          /* Start in top left corner of pixrect. */
  264.   FGETS(nextline, MAXLINE, fp) ;
  265.   if (EQUAL(nextline, "no entries"))
  266.     {
  267.       make_pixrect(1) ;                    /* Just the "no print" icon. */
  268.       add_face(DISP_ALL, NOPRINT, "") ;    /* Set to "no print" icon. */
  269.       text(DISP_ALL, LEFT, printer) ;      /* Output printer name. */
  270.     }
  271.   else if (EQUAL(nextline, "Printer Error: may need attention!"))
  272.     {
  273.       make_pixrect(1) ;                    /* Just the "no paper" icon. */
  274.       add_face(DISP_ALL, NOPAPER, "") ;    /* Set to "no paper" icon. */
  275.       text(DISP_ALL, LEFT, printer) ;      /* Output printer name. */
  276.     }
  277.   else
  278.     {
  279.       FGETS(nextline, MAXLINE, fp) ;    /* Skip the next line. */
  280.       while (fgets(nextline, MAXLINE, fp) != NULL)
  281.         {
  282.           SSCANF(&nextline[7], "%s", owner) ;
  283.           SSCANF(&nextline[60], "%d", &size) ;
  284.           h_to_c("", community) ;
  285.           found = make_iconname(facedir, community, owner) ;
  286.           add_record("", owner, "", size) ;
  287.         }
  288.       make_pixrect(noicons) ;
  289.       this = recs ;
  290.       while (this != NULL)
  291.         {
  292.           next = this->next ;
  293.           add_face(DISP_BOTH, ORDINARY, this->iconname) ;
  294.           SPRINTF(nextline, "%1d", this->size) ;
  295.           if (!dontshowuser)
  296.             text(DISP_NAME, LEFT, this->username) ;  /* Owner. */
  297.           text(DISP_OTHER, LEFT, nextline) ;         /* Size. */
  298.           if (this == recs)
  299.             {
  300.               add_face(DISP_ICON, ORDINARY, this->iconname) ;
  301.               text(DISP_ICON, LEFT, printer) ;
  302.               SPRINTF(nextline, "%1d %s", noicons,
  303.                                          (noicons == 1 ? "job" : "jobs")) ;
  304.               text(DISP_ICON, RIGHT, nextline) ;   /* Number of jobs. */
  305.             }
  306.           adjust() ;    /* Adjust column and row. */
  307.           remove_record(this) ;
  308.           this = next ;
  309.         }
  310.       recs = last = NULL ;
  311.     }
  312.   PCLOSE(fp) ;
  313.   show_display() ;
  314. }
  315.  
  316.  
  317. do_prog()                   /* Run user supplied program or script. */
  318. {
  319.   FILE *fp ;                /* File descriptor for users command output. */
  320.   enum icon_type ftype ;    /* Type of the current face. */
  321.   char host[MAXLINE] ;      /* Pointer to host name from the "From" line. */
  322.   char ileft[MAXLINE] ;     /* Text for left side of icon display. */
  323.   char iright[MAXLINE] ;    /* Text for right side of icon display. */
  324.   char user[MAXLINE] ;      /* Pointer to user name from the "From" line. */
  325.   char wleft[MAXLINE] ;     /* Text for left side of window display. */
  326.   char wright[MAXLINE] ;    /* Text for right side of window display. */
  327.   int cols = maxcols ;      /* Maximum number of columns for display. */
  328.   int rows = 1 ;            /* Maximum number of rows for display. */
  329.  
  330.   if ((fp = popen(userprog, "r")) == NULL)   /* Connect to user program. */
  331.     {
  332.       FPRINTF(stderr,"%s: couldn't get program (%s) information.\n",
  333.               progname, userprog) ;
  334.       return ;
  335.     }
  336.   FGETS(nextline, MAXLINE, fp) ;
  337.   SSCANF(nextline, "Cols=%d Rows=%d", &cols, &rows) ;
  338.   if (cols < 1) cols = maxcols ;
  339.   if (rows < 1) rows = 1 ;
  340.  
  341.   width = cols * imagewidth ;
  342.   height = rows * imageheight ;
  343.   create_pixrects(width, height) ;
  344.  
  345.   maxcols = cols ;          /* Maximum width in columns. */
  346.   column = row = 0 ;        /* Start in top left corner of pixrect. */
  347.   while (fgets(nextline, MAXLINE, fp) != NULL)
  348.     {
  349.       nextline[80] = '\0' ;
  350.       if (sscanf(&nextline[70], "%s", iright) == EOF) iright[0] = '\0' ;
  351.       nextline[70] = '\0' ;
  352.       if (sscanf(&nextline[60], "%s", ileft)  == EOF) ileft[0] = '\0' ;
  353.       nextline[60] = '\0' ;
  354.       if (sscanf(&nextline[50], "%s", wright) == EOF) wright[0] = '\0' ;
  355.       nextline[50] = '\0' ;
  356.       if (sscanf(&nextline[40], "%s", wleft)  == EOF) wleft[0] = '\0' ;
  357.       nextline[40] = '\0' ;
  358.       if (sscanf(&nextline[20], "%s", host)   == EOF) host[0] = '\0' ;
  359.       nextline[20] = '\0' ;
  360.       if (sscanf(&nextline[ 0], "%s", user)   == EOF) user[0] = '\0' ;
  361.  
  362.       STRCPY(community, "") ;
  363.       if (!(EQUAL(user, "NOMAIL")  || EQUAL(user, "NOPAPER") ||
  364.             EQUAL(user, "NOPRINT") || EQUAL(user, "NOUSERS")))
  365.         {
  366.           h_to_c(host, community) ;   /* Turn hostname into community name. */
  367.           a_to_u(community, user, realname) ;
  368.           found = make_iconname(facedir, community, realname) ;
  369.         }
  370.            if (EQUAL(user, "NOMAIL"))  ftype = NOMAIL ;
  371.       else if (EQUAL(user, "NOPAPER")) ftype = NOPAPER ;
  372.       else if (EQUAL(user, "NOPRINT")) ftype = NOPRINT ;
  373.       else if (EQUAL(user, "NOUSERS")) ftype = NOUSERS ;
  374.       else                             ftype = ORDINARY ;
  375.       add_face(DISP_BOTH, ftype, iconname) ;
  376.       if (strlen(ileft))  text(DISP_OTHER, LEFT,  ileft) ;
  377.       if (strlen(iright)) text(DISP_OTHER, RIGHT, iright) ;
  378.       if (strlen(wleft))  text(DISP_NAME,  LEFT,  wleft) ;
  379.       if (strlen(wright)) text(DISP_NAME,  RIGHT, wright) ;
  380.       adjust() ;             /* Adjust column and row. */
  381.     }
  382.   PCLOSE(fp) ;
  383.   show_display() ;
  384. }
  385.  
  386.  
  387. do_users()                   /* Monitor users on a machine. */
  388. {
  389.   struct recinfo *this, *next ;
  390.   FILE *fp ;                 /* File descriptor for users mail spool file. */
  391.   char command[MAXLINE] ;    /* Rusers system call for this machine. */
  392.   char ts[MAXLINE] ;         /* Pointer to login time from rusers line. */
  393.   char username[MAXLINE] ;   /* Name of user logged in. */
  394.  
  395.   noicons = 0 ;
  396.   SPRINTF(command, USERSDEF, hostname) ;
  397.   if ((fp = popen(command, "r")) == NULL)    /* Connect to rusers command. */
  398.     {
  399.       FPRINTF(stderr,"%s: couldn't get user stats.\n", progname) ;
  400.       return ;
  401.     }
  402.   column = row = 0 ;          /* Start in top left corner of pixrect. */
  403.   while (fgets(nextline, MAXLINE, fp) != NULL)
  404.     {
  405.       SSCANF(&nextline[0], "%s", username) ;
  406.       SSCANF(&nextline[38], "%s", ts) ;
  407.       h_to_c("", community) ;
  408.       found = make_iconname(facedir, community, username) ;
  409.       add_record("", username, ts, 0) ;
  410.     }
  411.   if (!noicons)
  412.     {
  413.       make_pixrect(1) ;                    /* Just the "no users" icon. */
  414.       add_face(DISP_ALL, NOUSERS, "") ;    /* Set to "no users" icon. */
  415.     }
  416.   else
  417.     {
  418.       make_pixrect(noicons) ;
  419.       add_face(DISP_ICON, NOFACE, "") ;
  420.       this = recs ;
  421.       while (this != NULL)
  422.         {
  423.           next = this->next ;
  424.           add_face(DISP_BOTH, ORDINARY, this->iconname) ;
  425.           if (!dontshowtime)
  426.             text(DISP_OTHER, LEFT, this->ts) ;         /* Timestamp. */
  427.           if (!dontshowuser)
  428.             text(DISP_NAME, LEFT, this->username) ;    /* Username. */
  429.           adjust() ;    /* Adjust column and row. */
  430.           remove_record(this) ;
  431.           this = next ;
  432.         }
  433.       SPRINTF(nextline, "%1d %s", noicons, (noicons == 1 ? "user" : "users")) ;
  434.       text(DISP_ICON, RIGHT, nextline) ;   /* Number of jobs. */
  435.       recs = last = NULL ;
  436.     }
  437.   PCLOSE(fp) ;
  438.   show_display() ;
  439. }
  440.  
  441.  
  442. make_pixrect(count)   /* Make window pixrect the correct size. */
  443. int count ;
  444. {
  445.   int c, r ;          /* Size in columns and rows of window display. */
  446.  
  447.   r = ((count-1) / maxcols) + 1 ;   /* Number of rows of faces. */
  448.   c = maxcols ;                     /* Full width display. */
  449.   if (count <= 10)
  450.     {
  451.       r = 1 ;         /* One row. */
  452.       c = count ;     /* Of 'count' columns. */
  453.     }
  454.  
  455.   height = r * imageheight ;    /* Height of the icon display. */
  456.   width = c * imagewidth ;      /* Width of the icon display. */
  457.   create_pixrects(width, height) ;
  458. }
  459.  
  460.  
  461. make_display()              /* Output icons and tidyup chain of records. */
  462. {
  463.   int count ;               /* Name of faces in icon display. */
  464.   struct recinfo *this, *next ;
  465.  
  466.   count = noicons ;         /* Number of faces to display. */
  467.   if (!count) count = 1 ;   /* Always one "no mail" icon. */
  468.   make_pixrect(count) ;
  469.  
  470.   count = 0 ;
  471.   if (!noicons) add_face(DISP_ALL, NOMAIL, "") ;
  472.   else
  473.     {
  474.       this = recs ;
  475.       while (this != NULL)
  476.         {
  477.           next = this->next ;
  478.           if (!this->total)
  479.             {
  480.               this = next ;
  481.               continue ;
  482.             }
  483.           if (this->faceimage != NULL)
  484.             {
  485.               STRCPY(face_buf, (char *) this->faceimage) ;
  486.               add_face(DISP_ALL, XFACE, this->iconname) ;
  487.               if (!this->update && update)               /* Update database */
  488.                 {
  489.                   do_face_update(this->iconname, face_buf) ;
  490.                   this->update = 1 ;
  491.                 }
  492.             }
  493.           else add_face(DISP_ALL, ORDINARY, this->iconname) ;
  494.           count += this->total ;
  495.           if (!dontshowno)
  496.             {
  497.               SPRINTF(nextline, "%1d", this->total) ;
  498.               text(DISP_OTHER, RIGHT, nextline) ;
  499.             }
  500.           if (!dontshowtime) text(DISP_OTHER, LEFT, this->ts) ;
  501.           if (!dontshowuser)
  502.             {
  503.               text(DISP_NAME, LEFT, this->username) ;
  504.               text(DISP_ICON, LEFT, this->username) ;
  505.             }
  506.           adjust() ;
  507.           this = next ;
  508.         }
  509.       SPRINTF(nextline, "%1d", count) ;
  510.       text(DISP_ICON, RIGHT, nextline) ;
  511.       garbage_collect() ;                 /* Remove zero length records. */
  512.     }
  513.   show_display() ;         /* Display the latest set of faces. */
  514. }
  515.  
  516.  
  517. process_face()        /* Extract next line of face image information. */
  518. {
  519.  
  520. /*  Read in the X-Face: data. By default, the first line will contain an
  521.  *  initial X-Face: (which is ignored), followed by 72 characters of
  522.  *  compressed data. Second and subsequent lines will contain an initial
  523.  *  space (which is ignored), followed by 79 characters of compressed data.
  524.  *  The last line may contain less characters.
  525.  *
  526.  *  The trouble is that users may try to pretty up this output. In order to
  527.  *  handle that possibility, the following rules will apply:
  528.  *
  529.  *  On the initial line, the "X-Face: " will be removed, any immediate
  530.  *  whitespace (tabs and spaces) will be removed, and the remainder of
  531.  *  the line will be placed in the data buffer (minus the trailing newline).
  532.  *
  533.  *  On subsequent lines, initial whitespace will be removed, and the
  534.  *  remainder of the data appended to the data buffer (minus the trailing
  535.  *  newline).
  536.  *
  537.  *  When a blank line, or a line with the initial non whitespace character,
  538.  *  then this will signify the end of X-Face data, and the buffer will be
  539.  *  passed to the uncompression routine.
  540.  *
  541.  *  Note that this extraction process is not perfect, and it is possible that
  542.  *  more data may be appended to the face buffer then necessary. This should
  543.  *  not be a problem, because the face uncompression routine should ignore
  544.  *  that extra input data.
  545.  */
  546.  
  547.   char *ptr ;
  548.  
  549.   if (!doing_xface)
  550.     {
  551.       bzero(face_buf, 2048) ;
  552.       ptr = &line[7] ;
  553.       while (*ptr == ' ' || *ptr == '\t') ptr++ ;
  554.       STRNCPY(face_buf, ptr, strlen(ptr)-1) ;
  555.       face_buf[strlen(ptr)-1] = '\0' ;
  556.       doing_xface = 1 ;
  557.     }
  558.   else if (!strlen(line) || !(line[0] == ' ' || line[0] == '\t'))
  559.     {
  560.       doing_xface = 0 ;
  561.       if (uncompface(face_buf) < 0) return ;
  562.       x_face = 1 ;                       /* We have an "on-the-fly" face. */
  563.     }
  564.   else
  565.     {
  566.       ptr = line ;
  567.       while (*ptr == ' ' || *ptr == '\t') ptr++ ;
  568.       STRNCAT(face_buf, ptr, strlen(ptr)-1) ;
  569.     }
  570. }
  571.  
  572.  
  573. process_from()             /* Extract information from the From line. */
  574. {
  575.   char *host, *user ;
  576.   char temp[MAXLINE], ts[9] ;
  577.  
  578.   if (EQUAL(line, "From "))
  579.     {
  580.       SSCANF(line, "%s %s %s %s %s %s", temp, temp, temp, temp, temp, ts) ;
  581.       ts[5] = '\0' ;
  582.       STRCPY(face_ts, ts) ;
  583.       froms_found = 1 ;
  584.     }
  585.   else
  586.     {
  587.       if (fromc_found) return ;    /* Only process first From: line. */
  588.       fromc_found = 1 ;
  589.     }
  590.  
  591.   if (parsefrom(line, &user, &host))
  592.     {
  593.       STRCPY(face_user, strlower(user)) ;
  594.       STRCPY(face_host, host) ;
  595.     }
  596.   else FPRINTF(stderr, "%s: couldn't parse '%s'\n", progname, line) ;
  597. }
  598.  
  599.  
  600. process_info()          /* Process From line and face information. */
  601. {
  602.   struct recinfo *crec ;    /* Pointer to current mail record for updating. */
  603.  
  604.   h_to_c(face_host, community) ;    /* Turn hostname into community name. */
  605.   a_to_u(community, face_user, realname) ;
  606.   if (mtype == MONNEW)
  607.     {
  608.       if (x_face)
  609.         {
  610.           SPRINTF(iconname, "%s/%s/%s/48x48x1",
  611.                   strlen(facedir) ? facedir : defdir, community, realname) ;
  612.           add_face(DISP_ALL, XFACE, iconname) ;
  613.           if (update) do_face_update(iconname, face_buf) ;
  614.         }
  615.       else
  616.         {
  617.           if (!(found = make_iconname(facedir, community, realname)))
  618.             add_face(DISP_ALL, NOFACE, (char *) NULL) ;
  619.           else add_face(DISP_ALL, ORDINARY, iconname) ;
  620.         }
  621.  
  622.       if (!dontshowtime) text(DISP_OTHER, LEFT, face_ts) ;
  623.       if (!dontshowuser)
  624.         {
  625.           text(DISP_NAME, LEFT, realname) ;
  626.           text(DISP_ICON, LEFT, realname) ;
  627.         }
  628.       adjust() ;
  629.     }
  630.   else
  631.     {
  632.       found = make_iconname(facedir, community, realname) ;
  633.       if (x_face)
  634.         SPRINTF(iconname, "%s/%s/%s/48x48x1",
  635.                 strlen(facedir) ? facedir : defdir, community, realname) ;
  636.       if ((crec = rec_exists(community, realname)) != NULL)
  637.         {
  638.           STRCPY(crec->ts, face_ts) ;
  639.           if (!crec->total) noicons++ ;
  640.           crec->total++ ;
  641.         }
  642.       else add_record(community, realname, face_ts, 0) ;
  643.     }
  644.   fromc_found = froms_found = x_face = 0 ;  /* Reset for the next message. */
  645. }
  646. Funky_Stuff
  647. len=`wc -c < mon.c`
  648. if [ $len !=    20347 ] ; then
  649. echo error: mon.c was $len bytes long, should have been    20347
  650. fi
  651. fi # end of overwriting check
  652. if [ -f main.c ]
  653. then
  654. echo shar: will not over-write existing file main.c
  655. else
  656. echo shar: extracting 'main.c',    20038 characters
  657. cat > main.c <<'Funky_Stuff'
  658.  
  659. /*  @(#)main.c 1.16 90/06/29
  660.  *
  661.  *  Icon face server for monitoring mail and print jobs.
  662.  *  This program is based on the AT&T v8 mail face server,
  663.  *  vismon, but is not derived from vismon source.
  664.  * 
  665.  *  Copyright (c) Rich Burridge - Sun Microsystems Australia.
  666.  *                                All rights reserved.
  667.  *
  668.  *  Permission is given to distribute these sources, as long as the
  669.  *  copyright messages are not removed, and no monies are exchanged. 
  670.  * 
  671.  *  No responsibility is taken for any errors on inaccuracies inherent
  672.  *  either to the comments or the code of this program, but if reported
  673.  *  to me, then an attempt will be made to fix them.
  674.  */
  675.  
  676. #include <stdio.h>
  677. #include <strings.h>
  678. #include <sys/types.h>
  679. #include <sys/stat.h>
  680. #include <netdb.h>
  681. #include "faces.h"
  682.  
  683. unsigned short noface_image[] = {
  684. #include "noface.icon"
  685. } ;
  686.  
  687. unsigned short nomail_image[] = {
  688. #include "nomail.icon"
  689. } ;
  690.  
  691. unsigned short nopaper_image[] = {
  692. #include "nopaper.icon"
  693. } ;
  694.  
  695. unsigned short noprint_image[] = {
  696. #include "noprint.icon"
  697. } ;
  698.  
  699. unsigned short nousers_image[] = {
  700. #include "nousers.icon"
  701. } ;
  702.  
  703. char *getname() ;
  704. int do_check() ;
  705. struct recinfo *rec_exists() ;
  706.  
  707. struct comminfo *communities = NULL ;  /* Community alias/username chain. */
  708. struct comminfo *clast = NULL ;     /* End of chain of community records. */
  709. struct machinfo *machines = NULL ;  /* Known machine/communities. */
  710. struct machinfo *mlast = NULL ;     /* End of chain of machine records. */
  711. struct psinfo *psrecs = NULL ;      /* List of news.ps animation files. */
  712. struct psinfo *plast = NULL ;       /* End of chain of NeWS animation files. */
  713. struct recinfo *recs = NULL ;       /* Mail messages being monitored. */
  714. struct recinfo *last = NULL ;       /* End of the chain of mail records. */
  715. struct stat buf ;                   /* Buffer for file existence stat call. */
  716. long lastsize = 0L ;                /* Last known size of the mail folder. */
  717.  
  718. enum disp_type wdtype = DISP_NAME ; /* Current window display option. */
  719. enum gr_type gtype ;                /* Which graphics system is being used. */
  720. enum mon_type mtype = MONNEW ;      /* Type of monitoring operation to do. */
  721.  
  722. char bgicon[MAXLINE] ;           /* Alternate background pattern. */
  723. char community[MAXLINE] ;        /* Community name ("real" host name). */
  724. char defdir[MAXLINE] ;           /* The default face directory. */
  725. char display[MAXLINE] ;          /* X11 display information. */
  726. char *envmail ;             /* Pointer to MAIL environment variable value */
  727. char face_buf[2048] ;       /* Buffer for "X-Face" face images. */
  728. char face_host[MAXLINE] ;   /* Pointer to host name from the "From" line. */
  729. char face_ts[MAXLINE] ;     /* Pointer to time stamp from the "From" line. */
  730. char face_user[MAXLINE] ;   /* Pointer to user name from the "From" line. */
  731. char facedir[MAXLINE] ;          /* Alternate face image directory. */
  732. char fname[MAXTYPES][MAXLINE] ;  /* Array of various face name types. */
  733. char geometry[MAXLINE] ;    /* X11 geometry information. */
  734. char hostname[MAXLINE] ;    /* Machine name to monitor. */
  735. char iconname[MAXLINE] ;    /* Name of the icon file for this person. */
  736. char line[MAXLINE] ;        /* Next line from users mail spool file. */
  737. char machfile[MAXLINE] ;    /* Name of the machine/community file. */
  738. char nextline[MAXLINE] ;    /* Input/conversion buffer for various routines. */
  739. char peopfile[MAXLINE] ;    /* Name of the people/username file. */
  740. char printer[MAXLINE] ;     /* Printer name to monitor. */
  741. char progname[MAXLINE] ;    /* Name of this program. */
  742. char realname[MAXLINE] ;    /* Real username for this user. */
  743. char spoolfile[MAXLINE] ;   /* Full pathname of users current mail. */
  744. char update_alias[MAXLINE] ;   /* Name of mail alias for database updates. */
  745. char *username ;            /* This users name. */
  746. char userprog[MAXLINE] ;    /* User supplied program to run. */
  747.  
  748. int beeps ;             /* Number of beeps for arrival of new mail. */
  749. int column ;            /* Column number for next icon. */
  750. int doing_xface = 0 ;   /* Set if we've started to process an X-Face: */
  751. int dontshowno = 0 ;    /* Set if number of messages shouldn't be displayed. */
  752. int dontshowtime = 0 ;  /* Set if timestamp for new mail shouldn't be shown. */
  753. int dontshowuser = 0 ;  /* Set if username for new mail shouldn't be shown. */
  754.  
  755. int facetype ;          /* Type of face file found. */
  756. int firsttime = 1 ;     /* Zeroised after first mail/printer check. */
  757. int flashes ;           /* Number of flashes for arrival of new mail. */
  758. int found ;             /* Set if iconname found under username directory. */
  759. int fromc_found = 0 ;   /* Set if "From:" line found during processing. */
  760. int froms_found = 0 ;   /* Set if "From " line found during processing. */
  761. int height ;            /* Height in pixels of faces display. */
  762.  
  763. int iconheight = ICONHEIGHT ;  /* Height of an individual icon. */
  764. int iconwidth = ICONWIDTH ;    /* Width of an individual icon. */
  765. int iconic = 0 ;               /* Faces window is closed if set. */
  766. int imageheight = ICONHEIGHT ;  /* Height of an individual face image. */
  767. int imagewidth = ICONWIDTH ;    /* Width of an individual face image. */
  768. int invert = 0 ;               /* Set if to use reverse video. */
  769. int ix = 0 ;                   /* Initial X position of the icon. */
  770. int iy = 0 ;                   /* Initial Y position of the icon. */
  771. int maxcols = NO_PER_ROW ;     /* Maximum number of columns to display. */
  772.  
  773. int maxtypes ;      /* Maximum number of icon types for graphics target. */
  774. int mhflag = 0 ;    /* Set if this user uses MH to read mail. */
  775. int newmail ;       /* Set if there is new mail this time around. */
  776. int noicons ;       /* Number of faces this time around. */
  777. int old_style = 0 ; /* Set when "old" style face ikon is found. */
  778. int period = 60 ;   /* Period in seconds for new mail check. */
  779. int posspec = 0 ;   /* Set if -Wp or -g option is present (for X11) */
  780. int row ;           /* Row number for next icon. */
  781. int update = 0 ;    /* If set, send mail to update faces database. */
  782. int width ;         /* Width in pixels of faces display. */
  783. int wx = 0 ;        /* Initial X position of the window. */
  784. int wy = 0 ;        /* Initial Y position of the window. */
  785. int x_face = 0 ;    /* Set if we've extracted an "on-the-fly" face. */
  786.  
  787. /*  256-byte table for quickly reversing the bits in an unsigned 8-bit char,
  788.  *  used to convert between MSBFirst and LSBFirst image formats.
  789.  */
  790.  
  791. char revtable[256] = {
  792.         0, -128,   64,  -64,   32,  -96,   96,  -32,
  793.        16, -112,   80,  -48,   48,  -80,  112,  -16,
  794.         8, -120,   72,  -56,   40,  -88,  104,  -24,
  795.        24, -104,   88,  -40,   56,  -72,  120,   -8,
  796.         4, -124,   68,  -60,   36,  -92,  100,  -28,
  797.        20, -108,   84,  -44,   52,  -76,  116,  -12,
  798.        12, -116,   76,  -52,   44,  -84,  108,  -20,
  799.        28, -100,   92,  -36,   60,  -68,  124,   -4,
  800.         2, -126,   66,  -62,   34,  -94,   98,  -30,
  801.        18, -110,   82,  -46,   50,  -78,  114,  -14,
  802.        10, -118,   74,  -54,   42,  -86,  106,  -22,
  803.        26, -102,   90,  -38,   58,  -70,  122,   -6,
  804.         6, -122,   70,  -58,   38,  -90,  102,  -26,
  805.        22, -106,   86,  -42,   54,  -74,  118,  -10,
  806.        14, -114,   78,  -50,   46,  -82,  110,  -18,
  807.        30,  -98,   94,  -34,   62,  -66,  126,   -2,
  808.         1, -127,   65,  -63,   33,  -95,   97,  -31,
  809.        17, -111,   81,  -47,   49,  -79,  113,  -15,
  810.         9, -119,   73,  -55,   41,  -87,  105,  -23,
  811.        25, -103,   89,  -39,   57,  -71,  121,   -7,
  812.         5, -123,   69,  -59,   37,  -91,  101,  -27,
  813.        21, -107,   85,  -43,   53,  -75,  117,  -11,
  814.        13, -115,   77,  -51,   45,  -83,  109,  -19,
  815.        29,  -99,   93,  -35,   61,  -67,  125,   -3,
  816.         3, -125,   67,  -61,   35,  -93,   99,  -29,
  817.        19, -109,   83,  -45,   51,  -77,  115,  -13,
  818.        11, -117,   75,  -53,   43,  -85,  107,  -21,
  819.        27, -101,   91,  -37,   59,  -69,  123,   -5,
  820.         7, -121,   71,  -57,   39,  -89,  103,  -25,
  821.        23, -105,   87,  -41,   55,  -73,  119,   -9,
  822.        15, -113,   79,  -49,   47,  -81,  111,  -17,
  823.        31,  -97,   95,  -33,   63,  -65,  127,   -1,
  824. } ;
  825.  
  826.  
  827. main(argc, argv)
  828. int argc ;
  829. char *argv[] ;
  830. {
  831.   STRCPY(progname, argv[0]) ;   /* Save this programs name. */
  832.   initialise() ;                /* Set default values for various options. */
  833.   get_options(argc, argv) ;     /* Read and process command line options. */
  834.   read_mailrc() ;               /* Get number of flashes and beeps. */
  835.   read_machines() ;             /* Setup up the machine/community chain. */
  836.   read_aliases() ;              /* Setup the hostname alias subchains. */
  837.  
  838.   if (init_ws_type(argc, argv)) /* Determine window system type. */
  839.     {
  840.       FPRINTF(stderr,"Error initialising window system.\n") ;
  841.       exit(1) ;
  842.     }
  843.  
  844. #ifdef REVORDER
  845.   load_icon(NOFACE,  noface_image,  1) ;
  846.   load_icon(NOMAIL,  nomail_image,  1) ;
  847.   load_icon(NOPAPER, nopaper_image, 1) ;
  848.   load_icon(NOPRINT, noprint_image, 1) ;
  849.   load_icon(NOUSERS, nousers_image, 1) ;
  850. #else
  851.   load_icon(NOFACE,  noface_image,  0) ;
  852.   load_icon(NOMAIL,  nomail_image,  0) ;
  853.   load_icon(NOPAPER, nopaper_image, 0) ;
  854.   load_icon(NOPRINT, noprint_image, 0) ;
  855.   load_icon(NOUSERS, nousers_image, 0) ;
  856. #endif /*REVORDER*/
  857.   make_area(DISP_ICON, imagewidth, imageheight) ;
  858.  
  859.   make_icon() ;                 /* Create default faces icon. */
  860.   make_frame(argc, argv) ;      /* Create faces window/icon. */
  861.   do_check() ;                  /* Generate initial faces display. */
  862.   start_tool() ;                /* Start up and display the faces icon. */
  863. }
  864.  
  865.  
  866. a_to_u(community, user, realname)    /* Turn possible alias into username. */
  867. char *community, *user, *realname ;
  868. {
  869.   struct comminfo *ctemp ;
  870.   struct peopinfo *ptemp ;
  871.  
  872.   STRCPY(realname, user) ;      /* In case alias not found. */
  873.   ctemp = communities ;         /* Point to chain of communities. */
  874.   while (ctemp != NULL)
  875.     if (!strcmp(ctemp->community, community))
  876.       {
  877.         ptemp = ctemp->people ;
  878.         while (ptemp != NULL)
  879.           if (!strcmp(ptemp->alias, user))
  880.             {
  881.               STRCPY(realname, ptemp->username) ;
  882.               return ;
  883.             }
  884.           else ptemp = ptemp->next ;
  885.         return ;
  886.       }
  887.     else ctemp = ctemp->next ;
  888. }
  889.  
  890.  
  891. initialise()
  892. {
  893.   STRCPY(facedir, "") ;       /* No alternate face directory by default. */
  894.   STRCPY(display, "") ;       /* X11 display type. */
  895.   STRCPY(geometry, "") ;      /* X11 geometry information. */
  896.  
  897. #ifdef FBMONTYPE
  898.   mtype = FBMONTYPE ;         /* Type of monitoring to do. */
  899. #endif /*FBMONTYPE*/
  900.  
  901. #ifdef BACKGROUND
  902.   STRCPY(bgicon, BACKGROUND) ;          /* Alternate background pattern. */
  903. #else
  904.   STRCPY(bgicon, "") ;                  /* Default is to use root gray. */
  905. #endif /*BACKGROUND*/
  906.  
  907. #ifdef FACEDIR
  908.   STRCPY(defdir, FACEDIR) ;            /* Different directory for face icons. */
  909. #else
  910.   STRCPY(defdir,"/usr/local/faces") ;  /* Directory for face icons. */
  911. #endif /*FACEDIR*/
  912.  
  913.   SPRINTF(machfile, "%s/%s", defdir, MACHINETAB) ;
  914.   SPRINTF(peopfile, "%s/%s", defdir, PEOPLETAB) ;
  915.  
  916. #ifdef INVERT
  917.   invert = 1 ;               /* Display in reverse video. */
  918. #endif /*INVERT*/
  919.  
  920. #ifdef PERIOD
  921.   period = PERIOD ;          /* Period for new mail/print check. */
  922. #endif /*PERIOD*/
  923.  
  924. #ifdef DONTSHOWNO
  925.   dontshowno = 1 ;           /* Don't show number of messages on images. */
  926. #endif /*DONTSHOWNO*/
  927.  
  928. #ifdef SPOOLFILE
  929.   STRCPY(spoolfile, SPOOLFILE) ;   /* Alternative spoolfile to monitor. */
  930. #else
  931.   if (envmail = getenv("MAIL")) STRCPY(spoolfile, envmail) ;
  932.   else
  933.     {
  934.       username = getname() ;     /* Get users name from passwd entry. */
  935.       SPRINTF(spoolfile, "/usr/spool/mail/%s", username) ;
  936.     }
  937. #endif /*SPOOLFILE*/
  938.  
  939. #ifdef UPDATE
  940.   STRCPY(update_alias, UPDATE) ;   /* Alternate faces database update alias. */
  941. #else
  942.   STRCPY(update_alias, UPDATE_ALIAS) ;
  943. #endif /*UPDATE*/
  944.  
  945. #ifdef DONTSHOWTIME
  946.   dontshowtime = 1 ;           /* Don't show timestamp on images. */
  947. #endif /*DONTSHOWTIME*/
  948.  
  949. #ifdef DONTSHOWUSER
  950.   dontshowuser = 1 ;           /* Don't show username on images. */
  951. #endif /*DONTSHOWUSER*/
  952. }
  953.  
  954.  
  955. h_to_c(host, community)        /* Turn hostname into community name. */
  956. char *host, *community ;
  957. {
  958.   struct hostent *hp ;
  959.   struct machinfo *temp ;      /* Pointer to next machine record. */
  960.  
  961.   temp = machines ;            /* Point to list of machine/communitys. */
  962.   if (host[0] == '\0')
  963.     {
  964.       GETHOSTNAME(community, MAXLINE) ;
  965.       hp = gethostbyname(community) ;
  966.       if (hp != NULL) STRCPY(community, hp->h_name) ;
  967.     }
  968.   else STRCPY(community, host) ;   /* Copied in case machine name not found. */
  969.   while (temp != NULL)
  970.     {
  971.       if (!strcmp(temp->machine, community))
  972.         {
  973.           STRCPY(community, temp->community) ;
  974.           return ;
  975.         }
  976.       temp = temp->next ;      /* Point to next record. */
  977.     }
  978. }
  979.  
  980.  
  981. make_iconname(facedir, community, user)    /* Construct the icon name. */
  982. char *facedir, *community, *user ;
  983. {
  984.  
  985. /*  Sets up community and user based on the first successful
  986.  *  open from the following list of files:
  987.  *
  988.  *  $(FACEDIR)/community/user/[face.ps, sun.icon, 48x48x1, face.xbm]
  989.  *  $(FACEDIR)/misc./user/[face.ps, sun.icon, 48x48x1, face.xbm]
  990.  *  $(FACEDIR)/community/unknown/[face.ps, sun.icon, 48x48x1, face.xbm]
  991.  *  $(FACEDIR)/misc./unknown/[face.ps, sun.icon, 48x48x1, face.xbm]
  992.  *
  993.  *  Firstly a check is made for the "old" style; first in a possible
  994.  *  alternate face directory, then in the default directory. This is
  995.  *  where the username is not a directory but the ikon in 48x48x1
  996.  *  format.
  997.  *
  998.  *  If none of these are found, the "blank face" is returned.
  999.  */
  1000.  
  1001.   char *cptr ;
  1002.   int i ;
  1003.  
  1004.   old_style = 0 ;     /* Reset before checking this face. */
  1005.  
  1006.   if (strlen(facedir))
  1007.     for (i = -1; i < maxtypes; i++)
  1008.       for (cptr = community; cptr != NULL; cptr = index(cptr, '.'))
  1009.         {
  1010.           if (*cptr == '.') cptr++ ;
  1011.           if (i < 0)
  1012.             {
  1013.               SPRINTF(iconname, "%s/%s/%s", facedir, cptr, user) ;
  1014.               if (stat(iconname, &buf) == -1) goto mi1 ;
  1015.               if ((buf.st_mode & S_IFMT) == S_IFREG)
  1016.                 {
  1017.                   old_style = 1 ;
  1018.                   return 1 ;
  1019.                 }
  1020.             }
  1021.           else
  1022.             {
  1023.               SPRINTF(iconname, "%s/%s/%s/%s", facedir, cptr, user, fname[i]) ;
  1024.               if (stat(iconname, &buf) != -1) return 1 ;
  1025.             }
  1026.         }
  1027.  
  1028. mi1:
  1029.   for (i = -1; i < maxtypes; i++)
  1030.     for (cptr = community; cptr != NULL; cptr = index(cptr, '.'))
  1031.       {
  1032.         if (*cptr == '.') cptr++ ;
  1033.         if (i < 0)
  1034.           {
  1035.             SPRINTF(iconname, "%s/%s/%s", defdir, cptr, user) ;
  1036.             if (stat(iconname, &buf) == -1) goto mi2 ;
  1037.             if ((buf.st_mode & S_IFMT) == S_IFREG)
  1038.               {    
  1039.                 old_style = 1 ;
  1040.                 return 1 ;
  1041.               }
  1042.           } 
  1043.         else
  1044.           {
  1045.             SPRINTF(iconname, "%s/%s/%s/%s", defdir, cptr, user, fname[i]) ;
  1046.             if (stat(iconname, &buf) != -1) return 1 ;
  1047.           }
  1048.       }
  1049.  
  1050. mi2:
  1051.   if (strlen(facedir))
  1052.     for (i = -1; i < maxtypes; i++)
  1053.       if (i < 0)
  1054.         {
  1055.           SPRINTF(iconname, "%s/misc./%s", facedir, user) ;
  1056.           if (stat(iconname, &buf) == -1) goto mi3 ;
  1057.           if ((buf.st_mode & S_IFMT) == S_IFREG)
  1058.             {
  1059.               old_style = 1 ;
  1060.               return 1 ;
  1061.             }
  1062.         }    
  1063.       else
  1064.         { 
  1065.           SPRINTF(iconname, "%s/misc./%s/%s", facedir, user, fname[i]) ;
  1066.           if (stat(iconname, &buf) != -1)
  1067.             {
  1068.               if (!x_face) STRCPY(community, "misc.") ;
  1069.               return 1 ;
  1070.             }
  1071.         }
  1072.  
  1073. mi3:
  1074.   for (i = -1; i < maxtypes; i++)
  1075.     if (i < 0)
  1076.       {
  1077.         SPRINTF(iconname, "%s/misc./%s", defdir, user) ;
  1078.         if (stat(iconname, &buf) == -1) goto mi4 ;
  1079.         if ((buf.st_mode & S_IFMT) == S_IFREG)
  1080.           {
  1081.             old_style = 1 ;
  1082.             return 1 ;
  1083.           }
  1084.       }    
  1085.     else
  1086.       {
  1087.         SPRINTF(iconname, "%s/misc./%s/%s", defdir, user, fname[i]) ;
  1088.         if (stat(iconname, &buf) != -1)
  1089.           {
  1090.             if (!x_face) STRCPY(community, "misc.") ;
  1091.             return 1 ;
  1092.           }
  1093.       }
  1094.  
  1095. mi4:
  1096.   if (strlen(facedir))
  1097.     for (i = -1; i < maxtypes; i++)
  1098.       for (cptr = community; cptr != NULL; cptr = index(cptr, '.'))
  1099.         {
  1100.           if (*cptr == '.') cptr++ ;
  1101.           if (i < 0)
  1102.             {
  1103.               SPRINTF(iconname, "%s/%s/unknown", facedir, cptr) ;
  1104.               if (stat(iconname, &buf) == -1) goto mi5 ;
  1105.               if ((buf.st_mode & S_IFMT) == S_IFREG)
  1106.                 {    
  1107.                   old_style = 1 ;
  1108.                   return 1 ;
  1109.                 }
  1110.             } 
  1111.           else
  1112.             {
  1113.               SPRINTF(iconname, "%s/%s/unknown/%s", facedir, cptr, fname[i]) ;
  1114.               if (stat(iconname, &buf) != -1)
  1115.                 {
  1116.                   if (mtype == MONALL && !x_face) STRCPY(user, "unknown") ;
  1117.                   return 1 ;
  1118.                 }
  1119.             }
  1120.         }
  1121.  
  1122. mi5:
  1123.   for (i = -1; i < maxtypes; i++)
  1124.     for (cptr = community; cptr != NULL; cptr = index(cptr, '.'))
  1125.       {
  1126.         if (*cptr == '.') cptr++ ;
  1127.         if (i < 0)
  1128.           {
  1129.             SPRINTF(iconname, "%s/%s/unknown", defdir, cptr) ;
  1130.             if (stat(iconname, &buf) == -1) goto mi6 ;
  1131.             if ((buf.st_mode & S_IFMT) == S_IFREG)
  1132.               {    
  1133.                 old_style = 1 ;
  1134.                 return 1 ;
  1135.               }
  1136.           } 
  1137.         else
  1138.           {
  1139.             SPRINTF(iconname, "%s/%s/unknown/%s", defdir, cptr, fname[i]) ;
  1140.             if (stat(iconname, &buf) != -1)
  1141.               {
  1142.                 if (mtype == MONALL && !x_face) STRCPY(user, "unknown") ;
  1143.                 return 1 ;
  1144.               }
  1145.           }
  1146.       }
  1147.  
  1148. mi6:
  1149.   if (strlen(facedir))
  1150.     for (i = -1; i < maxtypes; i++)
  1151.       if (i < 0)
  1152.         {
  1153.           SPRINTF(iconname, "%s/misc./unknown", facedir) ;
  1154.           if (stat(iconname, &buf) == -1) goto mi7 ;
  1155.           if ((buf.st_mode & S_IFMT) == S_IFREG)
  1156.             {
  1157.               old_style = 1 ;
  1158.               return 1 ;
  1159.             }
  1160.         }    
  1161.       else
  1162.         {
  1163.           SPRINTF(iconname, "%s/misc./unknown/%s", facedir, fname[i]) ;
  1164.           if (stat(iconname, &buf) != -1)
  1165.             {
  1166.               if (!x_face) STRCPY(community, "misc.") ;
  1167.               if (mtype == MONALL && !x_face) STRCPY(user, "unknown") ;
  1168.               return 1 ;
  1169.             }
  1170.         }
  1171.  
  1172. mi7:
  1173.   for (i = -1; i < maxtypes; i++)
  1174.     if (i < 0)
  1175.       {
  1176.         SPRINTF(iconname, "%s/misc./unknown", defdir) ;
  1177.         if (stat(iconname, &buf) == -1) return 0 ;
  1178.         if ((buf.st_mode & S_IFMT) == S_IFREG)
  1179.           {
  1180.             old_style = 1 ;
  1181.             return 1 ;
  1182.           }  
  1183.       }    
  1184.     else
  1185.       {
  1186.         SPRINTF(iconname, "%s/misc./unknown/%s", defdir, fname[i]) ;
  1187.         if (stat(iconname, &buf) != -1)
  1188.           {
  1189.             if (!x_face) STRCPY(community, "misc.") ;
  1190.             if (mtype == MONALL && !x_face) STRCPY(user, "unknown") ;
  1191.             return 1 ;
  1192.           }
  1193.       }
  1194.  
  1195. /* Face icon not found, so the "blank face" should be used. */
  1196.  
  1197.   return 0 ;
  1198. }
  1199.  
  1200.  
  1201. read_mailrc()                /* Get number of flashes and beeps. */
  1202. {
  1203.   char mrcname[MAXLINE] ;    /* Full pathname of the .mailrc file. */
  1204.   char *ptr ;
  1205.   FILE *fd ;
  1206.  
  1207.   beeps = 0 ;     /* Defaults if .mailrc file not found. */
  1208.   flashes = 0 ;
  1209.   if (getenv("HOME"))
  1210.     {
  1211.       SPRINTF(mrcname, "%s/.mailrc", getenv("HOME")) ;
  1212.       if ((fd = fopen(mrcname, "r")) == NULL) return ;
  1213.       while (fgets(nextline, MAXLINE, fd) != NULL)
  1214.         if (EQUAL(nextline, "set"))
  1215.           {
  1216.             ptr = index(nextline, ' ') ;
  1217.             if (EQUAL(ptr+1, "flash"))
  1218.               {
  1219.                 ptr = index(nextline, '=') ;
  1220.                 SSCANF(ptr+1, "%d", &flashes) ;
  1221.               }
  1222.             else if (EQUAL(ptr+1, "bell"))
  1223.               {
  1224.                 ptr = index(nextline, '=') ;
  1225.                 SSCANF(ptr+1, "%d", &beeps) ;
  1226.               }
  1227.           }
  1228.     }
  1229.   FCLOSE(fd) ;
  1230. }
  1231. Funky_Stuff
  1232. len=`wc -c < main.c`
  1233. if [ $len !=    20038 ] ; then
  1234. echo error: main.c was $len bytes long, should have been    20038
  1235. fi
  1236. fi # end of overwriting check
  1237. if [ -f rec.c ]
  1238. then
  1239. echo shar: will not over-write existing file rec.c
  1240. else
  1241. echo shar: extracting 'rec.c',     8673 characters
  1242. cat > rec.c <<'Funky_Stuff'
  1243.  
  1244. /*  @(#)rec.c 1.10 90/06/26
  1245.  *
  1246.  *  Record handling routines used by the faces program.
  1247.  * 
  1248.  *  Copyright (c) Rich Burridge - Sun Microsystems Australia.
  1249.  *                                All rights reserved.
  1250.  *
  1251.  *  Permission is given to distribute these sources, as long as the
  1252.  *  copyright messages are not removed, and no monies are exchanged. 
  1253.  * 
  1254.  *  No responsibility is taken for any errors on inaccuracies inherent
  1255.  *  either to the comments or the code of this program, but if reported
  1256.  *  to me, then an attempt will be made to fix them.
  1257.  */
  1258.  
  1259. #include <stdio.h>
  1260. #include <strings.h>
  1261. #include "faces.h"
  1262. #include "extern.h"
  1263.  
  1264.  
  1265. char *
  1266. Malloc(n)
  1267. int n ;
  1268. {
  1269.   char *val ;
  1270.  
  1271.   if ((val = malloc((unsigned) n)) == NULL)
  1272.     FPRINTF(stderr, "%s: Out of memory.\n", progname) ;
  1273.   return val ;
  1274. }
  1275.  
  1276.  
  1277. add_alias(crec, username, alias)  /* Add new alias to hostnames' list. */
  1278. struct comminfo *crec ;
  1279. char *username, *alias ;
  1280. {
  1281.   struct peopinfo *cptemp, *ptemp ;
  1282.  
  1283.   ptemp = (struct peopinfo *) LINT_CAST(Malloc(sizeof(struct peopinfo))) ;
  1284.   ptemp->alias = (char *) Malloc(strlen(alias)+1) ;
  1285.   STRCPY(ptemp->alias, alias) ;
  1286.   ptemp->username = (char *) Malloc(strlen(username)+1) ;
  1287.   STRCPY(ptemp->username, username) ;
  1288.   ptemp->next = NULL ;
  1289.  
  1290.   if (crec->people == NULL) crec->people = ptemp ;
  1291.   else
  1292.     {
  1293.       cptemp = crec->people ;
  1294.       while (cptemp != NULL)
  1295.         if (cptemp->next == NULL)
  1296.           {
  1297.             cptemp->next = ptemp ;
  1298.             return ;
  1299.           }
  1300.         else cptemp = cptemp->next ;
  1301.     }
  1302. }
  1303.  
  1304.  
  1305. add_machine(machine, community)    /* Add new machine to list. */
  1306. char *machine, *community ;
  1307. {
  1308.   struct machinfo *temp ;
  1309.  
  1310.   temp = (struct machinfo *) LINT_CAST(Malloc(sizeof(struct machinfo))) ;
  1311.   temp->machine = (char *) Malloc(strlen(machine)+1) ;
  1312.   STRCPY(temp->machine, machine) ;
  1313.   temp->community = (char *) Malloc(strlen(community)+1) ;
  1314.   STRCPY(temp->community, community) ;
  1315.   temp->next = NULL ;
  1316.  
  1317.   if (machines == NULL) machines = mlast = temp ;   /* Start chain. */
  1318.   else if (mlast != NULL)
  1319.     {
  1320.       mlast->next = temp ;     /* Add record to existing chain. */
  1321.       mlast = temp ;           /* Point to end of chain. */
  1322.     }
  1323. }
  1324.  
  1325.  
  1326. add_ps_rec(row, column, name)  /* Add record for later animation. */
  1327. int row, column ;
  1328. char *name ;
  1329. {
  1330.   struct psinfo *temp ;
  1331.  
  1332.   temp = (struct psinfo *) LINT_CAST(Malloc(sizeof(struct psinfo))) ;
  1333.   temp->name = (char *) Malloc(strlen(name)+1) ;
  1334.   STRCPY(temp->name, name) ;
  1335.   temp->row = row ;
  1336.   temp->column = column ;
  1337.   temp->next = NULL ;
  1338.  
  1339.   if (psrecs == NULL) psrecs = plast = temp ;    /* Start chain. */
  1340.   else if (plast != NULL)
  1341.     {
  1342.       plast->next = temp ;     /* Add record to existing chain. */
  1343.       plast = temp ;
  1344.     }
  1345. }
  1346.  
  1347.  
  1348. add_record(community, username, timestamp, size)
  1349. char *community, *username, *timestamp ;
  1350. int size ;
  1351. {
  1352.   struct recinfo *temp ;
  1353.  
  1354.   temp = (struct recinfo *) LINT_CAST(Malloc(sizeof(struct recinfo))) ;
  1355.   temp->community = (char *) Malloc(strlen(community)+1) ;
  1356.   STRCPY(temp->community, community) ;
  1357.   temp->username = (char *) Malloc(strlen(username)+1) ;
  1358.   STRCPY(temp->username, username) ;
  1359.   temp->iconname = (char *) Malloc(strlen(iconname)+1) ;
  1360.   STRCPY(temp->iconname, iconname) ;
  1361.   if (x_face)
  1362.     {
  1363.       temp->faceimage = (unsigned char *) Malloc(strlen(face_buf)+1) ;
  1364.       STRCPY(temp->faceimage, face_buf) ;
  1365.     }
  1366.   else temp->faceimage = NULL ;
  1367.   STRCPY(temp->ts, timestamp) ;
  1368.   temp->size = size ;
  1369.   temp->total = 1 ;
  1370.   temp->update = 0 ;
  1371.   temp->next = NULL ;
  1372.   noicons++ ;
  1373.   if (recs == NULL) recs = last = temp ;        /* Start chain. */
  1374.   else
  1375.     {
  1376.       last->next = temp ;  /* Add record to existing chain. */
  1377.       last = temp ;        /* Point to the end of the chain. */
  1378.     }
  1379. }
  1380.  
  1381.  
  1382. check_comm(hostname, username, alias)  /* Check community list. */
  1383. char *hostname, *username, *alias ;
  1384. {
  1385.   struct comminfo *ctemp ;
  1386.  
  1387.   ctemp = communities ;      /* Try and find machine record for hostname. */
  1388.   while (ctemp != NULL)
  1389.     if (!strcmp(ctemp->community, hostname))
  1390.       {  
  1391.         add_alias(ctemp, username, alias) ;
  1392.         return ;
  1393.       }  
  1394.     else ctemp = ctemp->next ;
  1395.  
  1396.   ctemp = (struct comminfo *) LINT_CAST(Malloc(sizeof(struct comminfo))) ;
  1397.   ctemp->community = (char *) Malloc(strlen(hostname)+1) ;
  1398.   STRCPY(ctemp->community, hostname) ; 
  1399.   ctemp->people = NULL ; 
  1400.   ctemp->next = NULL ; 
  1401.  
  1402.   if (communities == NULL) communities = clast = ctemp ;  /* Start chain. */ 
  1403.   else 
  1404.     { 
  1405.       clast->next = ctemp ;   /* Add record to existing chain. */
  1406.       clast = ctemp ;         /* Point to end of chain. */
  1407.     }
  1408.   add_alias(ctemp, username, alias) ;
  1409. }
  1410.  
  1411.  
  1412. /* Remove records with zero count; zeroise count for others. */
  1413.  
  1414. garbage_collect()
  1415. {
  1416.   struct recinfo *last, *this, *next ;
  1417.  
  1418.   last = NULL ;
  1419.   this = recs ;
  1420.   while (this != NULL)
  1421.     {
  1422.       next = this->next ;
  1423.       if (!this->total)
  1424.         {
  1425.           if (last != NULL) last->next = this->next ;
  1426.           if (this == recs) recs = this->next ;
  1427.           remove_record(this) ;
  1428.         }
  1429.       else
  1430.         {
  1431.           this->total = 0 ;
  1432.           last = this ;
  1433.         }
  1434.       this = next ;
  1435.     }
  1436. }
  1437.  
  1438.  
  1439. read_aliases()     /* Setup the hostname aliases subchains. */
  1440. {
  1441.   char alias[MAXLINE] ;      /* Alias for this community/username. */
  1442.   char hostname[MAXLINE] ;   /* This records' hostname. */
  1443.   char username[MAXLINE] ;   /* This records real username. */
  1444.   char *ptr1, *ptr2 ;
  1445.   FILE *fd ;
  1446.  
  1447.   if (strlen(facedir)) SPRINTF(peopfile, "%s/PEOPLETAB", facedir) ;
  1448.   if ((fd = fopen(peopfile, "r")) == NULL)   /* Open people file. */
  1449.     {
  1450.       if (strlen(facedir))
  1451.         {
  1452.           SPRINTF(peopfile, "%s/machine.tab", defdir) ;
  1453.           fd = fopen(peopfile, "r") ;
  1454.         }
  1455.       if (fd == NULL)
  1456.         {
  1457.           FPRINTF(stderr,"%s: cannot open %s\n", progname, peopfile) ;
  1458.           return ;
  1459.         }
  1460.     }
  1461.   while (fgets(nextline, MAXLINE, fd) != NULL)
  1462.     {
  1463.       if (nextline[0] == '\n' || nextline[0] == '#') continue ;
  1464.       ptr1 = index(nextline, '/') ;
  1465.       if (((int) (ptr1-nextline)) <= 0) continue ;  /* Ignore if no length. */
  1466.       STRNCPY(hostname, nextline, (int) (ptr1-nextline)) ;
  1467.       hostname[(int) (ptr1-nextline)] = '\0' ;
  1468.       ptr2 = index(nextline, '=') ;
  1469.       if (((int) (ptr2-ptr1-1)) <= 0) continue ;    /* Ignore if no length. */
  1470.       STRNCPY(alias, ptr1+1, (int) (ptr2-ptr1-1)) ;
  1471.       alias[(int) (ptr2-ptr1-1)] = '\0' ;
  1472.       if ((strlen(ptr2)-2) <= 0) continue ;         /* Ignore if no length. */
  1473.       STRNCPY(username, ptr2+1, strlen(ptr2)-2) ;
  1474.       username[strlen(ptr2)-2] = '\0' ;
  1475.       check_comm(hostname, username, alias) ;
  1476.     }
  1477.   FCLOSE(fd) ;
  1478. }
  1479.  
  1480.  
  1481. read_machines()       /* Setup the chain of machine/community records. */
  1482. {
  1483.   char community[MAXLINE] ;   /* This records' community. */
  1484.   char machine[MAXLINE] ;     /* This records' machine name. */
  1485.   char *ptr ;
  1486.   FILE *fd ;
  1487.  
  1488.   if (strlen(facedir)) SPRINTF(machfile, "%s/MACHINETAB", facedir) ;
  1489.   if ((fd = fopen(machfile, "r")) == NULL)   /* Open machine file. */
  1490.     {
  1491.       if (strlen(facedir))
  1492.         {
  1493.           SPRINTF(machfile, "%s/machine.tab", defdir) ;
  1494.           fd = fopen(machfile, "r") ;
  1495.         }
  1496.       if (fd == NULL)
  1497.         {
  1498.           FPRINTF(stderr,"%s: cannot open %s\n", progname, machfile) ;
  1499.           return ;
  1500.         }
  1501.     }
  1502.   while (fgets(nextline, MAXLINE, fd) != NULL)
  1503.     {
  1504.       if (nextline[0] == '\n' || nextline[0] == '#') continue ;
  1505.       ptr = index(nextline, '=') ;
  1506.       if (((int) (ptr-nextline)) <= 0) continue ;  /* Ignore if no length. */
  1507.       STRNCPY(machine, nextline, (int) (ptr-nextline)) ;
  1508.       machine[(int) (ptr-nextline)] = '\0' ;
  1509.       if (strlen(ptr)-2 <= 0) continue ;           /* Ignore if no length. */
  1510.       STRNCPY(community, ptr+1, strlen(ptr)-2) ;
  1511.       community[strlen(ptr)-2] = '\0' ;
  1512.       add_machine(machine, community) ;
  1513.     }
  1514.   FCLOSE(fd) ;
  1515. }
  1516.  
  1517.  
  1518. struct recinfo *
  1519. rec_exists(community,username)    /* Check if record exists for mail item. */
  1520. char *community, *username ;
  1521. {
  1522.   struct recinfo *temp ;     /* Pointer to mail records used for chaining. */
  1523.  
  1524.   temp = recs ;
  1525.   while (temp != NULL)
  1526.     {
  1527.       if (!strcmp(temp->username, username) &&
  1528.           !strcmp(temp->community, community))
  1529.         return(temp) ;       /* Record found. */
  1530.       temp = temp->next ;    /* Point to next record. */
  1531.     }
  1532.   return(NULL) ;
  1533. }
  1534.  
  1535.  
  1536. remove_record(thisrec)        /* Remove this record from the chain. */
  1537. struct recinfo *thisrec ;
  1538. {
  1539.   if (thisrec->community != NULL) free(thisrec->community) ;
  1540.   if (thisrec->faceimage != NULL) free(thisrec->faceimage) ;
  1541.   if (thisrec->username  != NULL) free(thisrec->username) ;
  1542.   if (thisrec->iconname  != NULL) free(thisrec->iconname) ;
  1543.   free((char *) thisrec) ;
  1544. }
  1545. Funky_Stuff
  1546. len=`wc -c < rec.c`
  1547. if [ $len !=     8673 ] ; then
  1548. echo error: rec.c was $len bytes long, should have been     8673
  1549. fi
  1550. fi # end of overwriting check
  1551.  
  1552.