home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / mint / init_5 / finger.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-03  |  34.4 KB  |  1,490 lines

  1. /*
  2.  * This finger program is public domain, written by Mr A.N.Onymous at
  3.  * Imperial College London Dept. of Computing.
  4.  */
  5.  
  6. #ifndef lint
  7. static char SccsId[] = "@(#)finger.c    1.3 (IC DoC) 1/28/86";
  8. #endif
  9.  
  10. /*  This is a finger program.  It prints out useful information about users
  11.  *  by digging it up from various system files.  It is not very portable
  12.  *  because the most useful parts of the information (the full user name,
  13.  *  office, and phone numbers) are all stored in the VAX-unused gecos field
  14.  *  of /etc/passwd, which, unfortunately, other UNIXes use for other things.
  15.  *
  16.  *  There are three output formats, all of which give login name, teletype
  17.  *  line number, and login time.  The short output format is reminiscent
  18.  *  of finger on ITS, and gives one line of information per user containing
  19.  *  in addition to the minimum basic requirements (MBR), the full name of
  20.  *  the user, his idle time and office location and phone number.  The
  21.  *  quick style output is UNIX who-like, giving only name, teletype and
  22.  *  login time.  Finally, the long style output give the same information
  23.  *  as the short (in more legible format), the home directory and shell
  24.  *  of the user, and, if it exits, a copy of the file .plan in the users
  25.  *  home directory.  Finger may be called with or without a list of people
  26.  *  to finger -- if no list is given, all the people currently logged in
  27.  *  are fingered.
  28.  *
  29.  *  The program is validly called by one of the following:
  30.  *
  31.  *    finger            {short form list of users}
  32.  *    finger -l        {long form list of users}
  33.  *    finger -b        {briefer long form list of users}
  34.  *    finger -q        {quick list of users}
  35.  *    finger -i        {quick list of users with idle times}
  36.  *    finger namelist        {long format list of specified users}
  37.  *    finger -s namelist    {short format list of specified users}
  38.  *    finger -w namelist    {narrow short format list of specified users}
  39.  *
  40.  *  where 'namelist' is a list of users login names.
  41.  *  The other options can all be given after one '-', or each can have its
  42.  *  own '-'.  The -f option disables the printing of headers for short and
  43.  *  quick outputs.  The -b option briefens long format outputs.  The -p
  44.  *  option turns off plans for long format outputs.
  45.  */
  46.  
  47. #include    <sys/types.h>
  48. #include    <sys/stat.h>
  49. #include    <sgtty.h>
  50. #include    <utmp.h>
  51. #include    <signal.h>
  52. #include    <pwd.h>
  53. #include    <stdio.h>
  54. #include    <lastlog.h>
  55. #include    <time.h>
  56.  
  57. #define UTMP_FILE    "/etc/utmp"
  58.  
  59. struct    utmp    utmp;    /* for sizeof */
  60. #define NMAX sizeof(utmp.ut_name)
  61. #define LMAX sizeof(utmp.ut_line)
  62.  
  63. #define        ASTERISK    '*'    /* ignore this in real name */
  64. #define        BLANK        ' '    /* blank character (i.e. space) */
  65. #define        CAPITALIZE    0137&    /* capitalize character macro */
  66. #define        COMMA        ','    /* separator in pw_gecos field */
  67. #define        COMMAND        '-'    /* command line flag char */
  68. #ifdef ICDOC
  69. #ifdef    ERCC
  70. #define        JCMB        'J'    /* J.C.M.B. */
  71. #endif ERCC
  72. #define        HUXLEY        'H'    /* huxley building */
  73. #endif ICDOC
  74. #define        CORY        'C'    /* cory hall office */
  75. #define        EVANS        'E'    /* evans hall office */
  76. #define        LINEBREAK    012    /* line feed */
  77. #define        NULLSTR        ""    /* the null string, opposed to NULL */
  78. #define        SAMENAME    '&'    /* repeat login name in real name */
  79. #define        TALKABLE    0222    /* tty is writeable if 222 mode */
  80.  
  81. struct  person  {            /* one for each person fingered */
  82.     char        name[NMAX+1];    /* login name */
  83.     char        tty[LMAX+1];    /* NULL terminated tty line */
  84.     long        loginat;    /* time of login (possibly last) */
  85.     long        idletime;    /* how long idle (if logged in) */
  86.     short int    loggedin;    /* flag for being logged in */
  87.     short int    writeable;    /* flag for tty being writeable */
  88.     char        *realname;    /* pointer to full name */
  89.     char        *office;    /* pointer to office name */
  90.     char        *officephone;    /* pointer to office phone no. */
  91.     char        *homephone;    /* pointer to home phone no. */
  92.     char        *random;    /* for any random stuff in pw_gecos */
  93.     struct  passwd    *pwd;        /* structure of /etc/passwd stuff */
  94.     struct  person    *link;        /* link to next person */
  95. };
  96.  
  97. struct  passwd            *NILPWD = 0;
  98. struct  person            *NILPERS = 0;
  99.  
  100. int        persize        = sizeof( struct person );
  101. int        pwdsize        = sizeof( struct passwd );
  102.  
  103. #define HAVE_LASTLOG
  104. #ifdef HAVE_LASTLOG
  105. char        LASTLOG[]    = "/var/adm/lastlog";    /* last login info */
  106. #endif
  107. #ifdef UTMP_FILE
  108. char        USERLOG[]    = UTMP_FILE;        /* who is logged in */
  109. #else
  110. char        USERLOG[]    = "/etc/utmp";        /* who is logged in */
  111. #endif
  112. char        outbuf[BUFSIZ];                /* output buffer */
  113. char        *ctime();
  114.  
  115. int        unbrief        = 1;        /* -b option default */
  116. int        header        = 1;        /* -f option default */
  117. int        hack        = 1;        /* -h option default */
  118. int        idle        = 0;        /* -i option default */
  119. int        large        = 0;        /* -l option default */
  120. int        match        = 1;        /* -m option default */
  121. int        plan        = 1;        /* -p option default */
  122. int        unquick        = 1;        /* -q option default */
  123. int        small        = 0;        /* -s option default */
  124. int        wide        = 1;        /* -w option default */
  125.  
  126. int        lf;
  127. int        llopenerr;
  128.  
  129. long        tloc;                /* current time */
  130.  
  131.  
  132.  
  133. main( argc, argv )
  134.  
  135.     int        argc;
  136.     char    *argv[];
  137.  
  138. {
  139.     FILE            *fp,  *fopen();        /* for plans */
  140.     struct  passwd        *getpwent();        /* read /etc/passwd */
  141.     struct  person        *person1,  *p,  *pend;    /* people */
  142.     struct  passwd        *pw;            /* temporary */
  143.     struct  utmp        user;            /*   ditto   */
  144.     char            *malloc();
  145.     char            *s,  *pn,  *ln;
  146.     char            c;
  147.     char            *PLAN = "/.plan";    /* what plan file is */
  148.     char            *PROJ = "/.project";    /* what project file */
  149.     int            PLANLEN = strlen( PLAN );
  150.     int            PROJLEN = strlen( PROJ );
  151.     int            numnames = 0;
  152.     int            orgnumnames;
  153.     int            uf;
  154.     int            usize = sizeof user;
  155.     int            unshort;
  156.     int            i, j;
  157.     int            fngrlogin;
  158.  
  159.  
  160.     setbuf( stdout, outbuf );            /* buffer output */
  161.  
  162.     /*  parse command line for (optional) arguments */
  163.  
  164.     i = 1;
  165.     if(  strcmp( *argv, "sh" )  )  {
  166.         fngrlogin = 0;
  167.         while( i++ < argc  &&  (*++argv)[0] == COMMAND )  {
  168.         for( s = argv[0] + 1; *s != NULL; s++ )  {
  169.             switch  (*s)  {
  170.  
  171.                 case 'b':
  172.                     unbrief = 0;
  173.                     break;
  174.  
  175.                 case 'f':
  176.                     header = 0;
  177.                     break;
  178.  
  179.                 case 'h':
  180.                     hack = 0;
  181.                     break;
  182.  
  183.                 case 'i':
  184.                     idle = 1;
  185.                     unquick = 0;
  186.                     break;
  187.  
  188.                 case 'l':
  189.                     large = 1;
  190.                     break;
  191.  
  192.                 case 'm':
  193.                     match = 0;
  194.                     break;
  195.  
  196.                 case 'p':
  197.                     plan = 0;
  198.                     break;
  199.  
  200.                 case 'q':
  201.                     unquick = 0;
  202.                     break;
  203.  
  204.                 case 's':
  205.                     small = 1;
  206.                     break;
  207.  
  208.                 case 'w':
  209.                     wide = 0;
  210.                     break;
  211.  
  212.                 default:
  213.                 fprintf( stderr, "finger: Usage -- 'finger [-bfhilmpqsw] [login1 [login2 ...] ]'\n" );
  214.                 exit( 1 );
  215.             }
  216.         }
  217.         }
  218.     }
  219.     else  {
  220.         fngrlogin = 1;
  221.     }
  222.     if( unquick )  {
  223.         time( &tloc );
  224.     }
  225.     else  {
  226.         if( idle )  {
  227.         time( &tloc );
  228.         }
  229.     }
  230.  
  231.     /*  i > argc means no login names given so get them by reading USERLOG */
  232.  
  233.     if(  (i > argc)  ||  fngrlogin  )  {
  234.         unshort = large;
  235.         if(  ( uf = open(USERLOG, 0) ) >= 0  )  {
  236. #ifdef USER_PROCESS
  237.         user.ut_type = EMPTY;
  238.         while( user.ut_type != USER_PROCESS )
  239. #else
  240.         user.ut_name[0] = NULL;
  241.         while( user.ut_name[0] == NULL )
  242. #endif
  243.         {
  244.             if( read( uf, (char *) &user, usize ) != usize )  {
  245.             printf( "\nNo one logged on\n" );
  246.             exit( 0 );
  247.             }
  248.         }
  249. #ifdef DEBUG
  250.         printf("name = %s, line = %s\n", user.ut_name, user.ut_line);
  251. #endif
  252.         person1 = (struct person  *) malloc( persize );
  253.         for( j = 0; j < NMAX; j++ )  {
  254.             person1->tty[j] = user.ut_line[j];
  255.             person1->name[j] = user.ut_name[j];
  256.         }
  257.         person1->name[NMAX] = NULL;
  258.         person1->tty[NMAX] = NULL;
  259.         person1->loginat = user.ut_time;
  260.         person1->pwd = NILPWD;
  261.         person1->loggedin = 1;
  262.         numnames++;
  263.         p = person1;
  264.         while( read( uf, (char *) &user, usize ) == usize )  {
  265. #ifdef USER_PROCESS
  266.             if( user.ut_type != USER_PROCESS )  continue;
  267. #else
  268.             if( user.ut_name[0] == NULL )  continue;
  269. #endif
  270.             p->link = (struct person  *) malloc( persize );
  271.             p = p->link;
  272.             for( j = 0; j < NMAX; j++ )  {
  273.             p->tty[j] = user.ut_line[j];
  274.             p->name[j] = user.ut_name[j];
  275.             }
  276.             p->name[NMAX] = NULL;
  277.             p->tty[NMAX] = NULL;
  278.             p->loginat = user.ut_time;
  279.             p->pwd = NILPWD;
  280.             p->loggedin = 1;
  281.             numnames++;
  282.         }
  283.         p->link = NILPERS;
  284.         close( uf );
  285.         }
  286.         else  {
  287.         fprintf( stderr, "finger: error opening %s\n", USERLOG );
  288.         exit( 2 );
  289.         }
  290.  
  291.         /*  if we are doing it, read /etc/passwd for the useful info */
  292.  
  293.         if( unquick )  {
  294.         setpwent();
  295.         fwopen();
  296.         i = numnames;
  297.         while(  ( (pw = getpwent()) != NILPWD )  &&  ( i > 0 )  )  {
  298.             p = person1;
  299.             do  {
  300.             if( p->pwd == NILPWD )  {
  301.                 if(  strcmp( p->name, pw->pw_name ) == 0  )  {
  302.                 p->pwd = (struct passwd  *) malloc( pwdsize );
  303.                 pwdcopy( p->pwd, pw );
  304.                 decode( p );
  305.                 i--;
  306.                 }
  307.             }
  308.             p = p->link;
  309.             }  while( p != NILPERS );
  310.         }
  311.         fwclose();
  312.         endpwent();
  313.         }
  314.     }
  315.  
  316.     /* get names from command line and check to see if they're  logged in */
  317.  
  318.     else  {
  319.         unshort = ( small == 1 ? 0 : 1 );
  320.         i++;
  321.         person1 = (struct person  *) malloc( persize );
  322.         strcpy(  person1->name, (argv++)[ 0 ]  );
  323.         person1->loggedin = 0;
  324.         person1->pwd = NILPWD;
  325.         numnames++;
  326.         p = person1;
  327.         while( i++ <= argc )  {
  328.         p->link = (struct person  *) malloc( persize );
  329.         p = p->link;
  330.         strcpy(  p->name, (argv++)[ 0 ]  );
  331.         p->loggedin = 0;
  332.         p->pwd = NILPWD;
  333.         numnames++;
  334.         }
  335.         p->link = NILPERS;
  336.         pend = p;
  337.  
  338.         /*  if we are doing it, read /etc/passwd for the useful info */
  339.  
  340.         orgnumnames = numnames;
  341.         if( unquick )  {
  342.         setpwent();
  343.         while(  ( pw = getpwent() ) != NILPWD  )  {
  344.             p = person1;
  345.             i = 0;
  346.             do  {
  347.             if( strcmp( p->name, pw->pw_name ) == 0    ||
  348.                 matchcmp( pw->pw_gecos, pw->pw_name, p->name ) )  {
  349.                 if( p->pwd == NILPWD )  {
  350.                 p->pwd = (struct passwd  *) malloc( pwdsize );
  351.                 pwdcopy( p->pwd, pw );
  352.                 }
  353.                 else  {    /* handle multiple logins -- append new
  354.                        "duplicate" entry to end of list */
  355.                 pend->link = (struct person  *) malloc(persize);
  356.                 pend = pend->link;
  357.                 pend->link = NILPERS;
  358.                 strcpy( pend->name, p->name );
  359.                 pend->pwd = (struct passwd  *) malloc(pwdsize);
  360.                 pwdcopy( pend->pwd, pw );
  361.                 numnames++;
  362.                 }
  363.             }
  364.             p = p->link;
  365.             }  while( ++i < orgnumnames );
  366.         }
  367.         endpwent();
  368.         }
  369.  
  370.         /*  Now get login information */
  371.  
  372.         if(  ( uf = open(USERLOG, 0) ) >= 0  )  {
  373.         while( read( uf, (char *) &user, usize ) == usize )  {
  374. #ifdef USER_PROCESS
  375.             if( user.ut_type != USER_PROCESS )  continue;
  376. #else
  377.             if( user.ut_name[0] == NULL )  continue;
  378. #endif
  379.             p = person1;
  380.             do  {
  381.             pw = p->pwd;
  382.             if( pw == NILPWD )  {
  383.                 i = ( strcmp( p->name, user.ut_name ) ? 0 : NMAX );
  384.             }
  385.             else  {
  386.                 i = 0;
  387.                 while(  (i < NMAX)  &&
  388.                     ( pw->pw_name[i] == user.ut_name[i])  )  {
  389.                 if( pw->pw_name[i] == NULL )  {
  390.                     i = NMAX;
  391.                     break;
  392.                 }
  393.                 i++;
  394.                 }
  395.             }
  396.             if( i == NMAX )  {
  397.                 if( p->loggedin == 1 )  {
  398.                 pend->link = (struct person  *) malloc(persize);
  399.                 pend = pend->link;
  400.                 pend->link = NILPERS;
  401.                 strcpy( pend->name, p->name );
  402.                 for( j = 0; j < NMAX; j++ )  {
  403.                     pend->tty[j] = user.ut_line[j];
  404.                 }
  405.                 pend->tty[ NMAX ] = NULL;
  406.                 pend->loginat = user.ut_time;
  407.                 pend->loggedin = 2;
  408.                 if(  pw == NILPWD  )  {
  409.                     pend ->pwd = NILPWD;
  410.                 }
  411.                 else  {
  412.                     pend->pwd = (struct passwd  *) malloc(pwdsize);
  413.                     pwdcopy( pend->pwd, pw );
  414.                 }
  415.                 numnames++;
  416.                 }
  417.                 else  {
  418.                 if( p->loggedin != 2 )  {
  419.                     for( j = 0; j < NMAX; j++ )  {
  420.                     p->tty[j] = user.ut_line[j];
  421.                     }
  422.                     p->tty[ NMAX ] = NULL;
  423.                     p->loginat = user.ut_time;
  424.                     p->loggedin = 1;
  425.                 }
  426.                 }
  427.             }
  428.             p = p->link;
  429.             }  while( p != NILPERS );
  430.         }
  431.         fwopen();
  432.         p = person1;
  433.         while( p != NILPERS )  {
  434.             if( p->loggedin == 2 )  {
  435.             p->loggedin = 1;
  436.             }
  437.             decode( p );
  438.             p = p->link;
  439.         }
  440.         fwclose();
  441.         close( uf );
  442.         }
  443.         else  {
  444.         fprintf( stderr, "finger: error opening %s\n", USERLOG );
  445.         exit( 2 );
  446.         }
  447.     }
  448.  
  449.     /* print out what we got */
  450.  
  451.     if( header )  {
  452.         if( unquick )  {
  453.         if( !unshort )  {
  454.             if( wide )  {
  455.             printf(
  456. "Login       Name              TTY Idle    When            Office\n" );
  457.             }
  458.             else  {
  459.             printf(
  460. "Login    TTY Idle    When            Office\n" );
  461.             }
  462.         }
  463.         }
  464.         else  {
  465.         printf( "Login      TTY            When" );
  466.         if( idle )  {
  467.             printf( "             Idle" );
  468.         }
  469.         printf( "\n" );
  470.         }
  471.     }
  472.     p = person1;
  473.     do  {
  474.         if( unquick )  {
  475.         if( unshort )  {
  476.             personprint( p );
  477.             if( p->pwd != NILPWD )  {
  478.             if( hack )  {
  479.                 s = malloc(strlen((p->pwd)->pw_dir) + PROJLEN + 1 );
  480.                 strcpy(  s, (p->pwd)->pw_dir  );
  481.                 strcat( s, PROJ );
  482.                 if(  ( fp = fopen( s, "r") )  != NULL  )  {
  483.                 printf( "Project: " );
  484.                 while(  ( c = getc(fp) )  !=  EOF  )  {
  485.                     if( c == LINEBREAK )  {
  486.                     break;
  487.                     }
  488.                     putc( c, stdout );
  489.                 }
  490.                 fclose( fp );
  491.                 printf( "\n" );
  492.                 }
  493.             }
  494.             if( plan )  {
  495.                 s = malloc( strlen( (p->pwd)->pw_dir ) + PLANLEN + 1 );
  496.                 strcpy(  s, (p->pwd)->pw_dir  );
  497.                 strcat( s, PLAN );
  498. #ifndef MINT
  499.                 if(  ( fp = fopen( s, "r") )  == NULL  )  {
  500. #else
  501.                 if(  ( fp = fopen( s, "rb") )  == NULL  )  {
  502. #endif
  503.                 printf( "No Plan.\n" );
  504.                 }
  505.                 else  {
  506.                 printf( "Plan:\n" );
  507.                 while(  ( c = getc(fp) )  !=  EOF  )  {
  508.                     putc( c, stdout );
  509.                 }
  510.                 fclose( fp );
  511.                 }
  512.             }
  513.             }
  514.             if( p->link != NILPERS )  {
  515.             printf( "\n" );
  516.             }
  517.         }
  518.         else  {
  519.             shortprint( p );
  520.         }
  521.         }
  522.         else  {
  523.         quickprint( p );
  524.         }
  525.         p = p->link;
  526.     }  while( p != NILPERS );
  527.     exit(0);
  528. }
  529.  
  530.  
  531. /*  given a pointer to a pwd (pfrom) copy it to another one, allocating
  532.  *  space for all the stuff in it.  Note: Only the useful (what the
  533.  *  program currently uses) things are copied.
  534.  */
  535.  
  536. pwdcopy( pto, pfrom )        /* copy relevant fields only */
  537.  
  538.     struct  passwd        *pto,  *pfrom;
  539. {
  540.     pto->pw_name = malloc(  strlen( pfrom->pw_name ) + 1  );
  541.     strcpy( pto->pw_name, pfrom->pw_name );
  542.     pto->pw_uid = pfrom->pw_uid;
  543.     pto->pw_gecos = malloc(  strlen( pfrom->pw_gecos ) + 1  );
  544.     strcpy( pto->pw_gecos, pfrom->pw_gecos );
  545.     pto->pw_dir = malloc(  strlen( pfrom->pw_dir ) + 1  );
  546.     strcpy( pto->pw_dir, pfrom->pw_dir );
  547.     pto->pw_shell = malloc(  strlen( pfrom->pw_shell ) + 1  );
  548.     strcpy( pto->pw_shell, pfrom->pw_shell );
  549. }
  550.  
  551.  
  552. /*  print out information on quick format giving just name, tty, login time
  553.  *  and idle time if idle is set.
  554.  */
  555.  
  556. quickprint( pers )
  557.  
  558.     struct  person        *pers;
  559. {
  560.     int            idleprinted;
  561.  
  562.     printf( "%-*.*s", NMAX, NMAX, pers->name );
  563.     printf( "  " );
  564.     if( pers->loggedin )  {
  565.         if( idle )  {
  566.         findidle( pers );
  567.         if( pers->writeable )  {
  568.             printf(  " %-*.*s %-16.16s", LMAX, LMAX, 
  569.             pers->tty, ctime( &pers->loginat )  );
  570.         }
  571.         else  {
  572.             printf(  "*%-*.*s %-16.16s", LMAX, LMAX, 
  573.             pers->tty, ctime( &pers->loginat )  );
  574.         }
  575.         printf( "   " );
  576.         idleprinted = ltimeprint( &pers->idletime );
  577.         }
  578.         else  {
  579.         printf(  " %-*.*s %-16.16s", LMAX, LMAX, 
  580.             pers->tty, ctime( &pers->loginat )  );
  581.         }
  582.     }
  583.     else  {
  584.         printf( "          Not Logged In" );
  585.     }
  586.     printf( "\n" );
  587. }
  588.  
  589.  
  590. /*  print out information in short format, giving login name, full name,
  591.  *  tty, idle time, login time, office location and phone.
  592.  */
  593.  
  594. shortprint( pers )
  595.  
  596.     struct  person    *pers;
  597.  
  598. {
  599.     struct  passwd        *pwdt = pers->pwd;
  600.     char            buf[ 26 ];
  601.     int            i,  len,  offset,  dialup;
  602.  
  603.     if( pwdt == NILPWD )  {
  604.         printf( "%-*.*s", NMAX, NMAX,  pers->name );
  605.         printf( "       ???\n" );
  606.         return;
  607.     }
  608.     printf( "%-*.*s", NMAX, NMAX,  pwdt->pw_name );
  609.     dialup = 0;
  610.     if( wide )  {
  611.         if(  strlen( pers->realname ) > 0  )  {
  612.         printf( " %-20.20s", pers->realname );
  613.         }
  614.         else  {
  615.         printf( "        ???          " );
  616.         }
  617.     }
  618.     if( pers->loggedin )  {
  619.         if( pers->writeable )  {
  620.         printf( "  " );
  621.         }
  622.         else  {
  623.         printf( " *" );
  624.         }
  625.     }
  626.     else  {
  627.         printf( "  " );
  628.     }
  629.     if(  strlen( pers->tty ) > 0  )  {
  630.       strcpy( buf, pers->tty );
  631.       if(  (buf[0] == 's')  &&  (buf[1] == 'x')  &&  (buf[2] == 't')  )  {
  632.          printf( "lx " );
  633.       }
  634.       else {
  635.         if(  (buf[0] == 't')  &&  (buf[1] == 't')  &&  (buf[2] == 'y')  )  {
  636.         offset = 3;
  637.         for( i = 0; i < 2; i++ )  {
  638.             buf[i] = buf[i + offset];
  639.         }
  640.         }
  641.         if(  (buf[0] == 'd')  &&  pers->loggedin  )  {
  642.         dialup = 1;
  643.         }
  644.         printf( "%-2.2s ", buf );
  645.       }
  646.     }
  647.     else  {
  648.         printf( "   " );
  649.     }
  650.     strcpy(buf, ctime(&pers->loginat));
  651.     if( pers->loggedin )  {
  652.         stimeprint( &pers->idletime );
  653.         offset = 7;
  654.         for( i = 4; i < 19; i++ )  {
  655.         buf[i] = buf[i + offset];
  656.         }
  657.         printf( " %-9.9s ", buf );
  658.     }
  659.     else if (pers->loginat == 0)
  660.         printf(" < .  .  .  . >");
  661.     else if (tloc - pers->loginat >= 180 * 24 * 60 * 60)
  662.         printf( " <%-6.6s, %-4.4s>", buf+4, buf+20 );
  663.     else
  664.         printf(" <%-12.12s>", buf+4);
  665.     len = strlen( pers->homephone );
  666.     if(  dialup  &&  (len > 0)  )  {
  667.         if( len == 8 )  {
  668.         printf( "             " );
  669.         }
  670.         else  {
  671.         if( len == 12 )  {
  672.             printf( "         " );
  673.         }
  674.         else {
  675.             for( i = 1; i <= 21 - len; i++ )  {
  676.             printf( " " );
  677.             }
  678.         }
  679.         }
  680.         printf( "%s", pers->homephone );
  681.     }
  682.     else  {
  683.         if(  strlen( pers->office ) > 0  )  {
  684.         printf( " %-11.11s", pers->office );
  685.         if(  strlen( pers->officephone ) > 0  )  {
  686.             printf( " %8.8s", pers->officephone );
  687.         }
  688.         else  {
  689.             if( len == 8 )  {
  690.             printf( " %8.8s", pers->homephone );
  691.             }
  692.         }
  693.         }
  694.         else  {
  695.         if(  strlen( pers->officephone ) > 0  )  {
  696.             printf( "             %8.8s", pers->officephone );
  697.         }
  698.         else  {
  699.             if( len == 8 )  {
  700.             printf( "             %8.8s", pers->homephone );
  701.             }
  702.             else  {
  703.             if( len == 12 )  {
  704.                 printf( "         %12.12s", pers->homephone );
  705.             }
  706.             }
  707.         }
  708.         }
  709.     }
  710.     printf( "\n" );
  711. }
  712.  
  713.  
  714. /*  print out a person in long format giving all possible information.
  715.  *  directory and shell are inhibited if unbrief is clear.
  716.  */
  717.  
  718. personprint( pers )
  719.  
  720.     struct  person    *pers;
  721. {
  722.     struct  passwd        *pwdt = pers->pwd;
  723.     int            idleprinted;
  724.  
  725.     if( pwdt == NILPWD )  {
  726.         printf( "Login name: %-10s", pers->name );
  727.         printf( "            " );
  728.         printf( "In real life: ???\n");
  729.         return;
  730.     }
  731.     printf( "Login name: %-10s", pwdt->pw_name );
  732.     if( pers->loggedin )  {
  733.         if( pers->writeable )  {
  734.         printf( "            " );
  735.         }
  736.         else  {
  737.         printf( "    (messages off)    " );
  738.         }
  739.     }
  740.     else  {
  741.         printf( "            " );
  742.     }
  743.     if(  strlen( pers->realname ) > 0  )  {
  744.         printf( "In real life: %-s", pers->realname );
  745.     }
  746.     if(  strlen( pers->office ) > 0  )  {
  747.         printf( "\nOffice: %-.11s", pers->office );
  748.         if(  strlen( pers->officephone ) > 0  )  {
  749.         printf( ", %s", pers->officephone );
  750.         if(  strlen( pers->homephone ) > 0  )  {
  751.             printf( "        Home phone: %s", pers->homephone );
  752.         }
  753.         else  {
  754.             if(  strlen( pers->random ) > 0  )  {
  755.             printf( "    %s", pers->random );
  756.             }
  757.         }
  758.         }
  759.         else  {
  760.         if(  strlen( pers->homephone ) > 0  )  {
  761.             printf("            Home phone: %s",pers->homephone);
  762.         }
  763.         if(  strlen( pers->random ) > 0  )  {
  764.             printf( "            %s", pers->random );
  765.         }
  766.         }
  767.     }
  768.     else  {
  769.         if(  strlen( pers->officephone ) > 0  )  {
  770.         printf( "\nPhone: %s", pers->officephone );
  771.         if(  strlen( pers->homephone ) > 0  )  {
  772.             printf( "\n, %s", pers->homephone );
  773.             if(  strlen( pers->random ) > 0  )  {
  774.             printf( ", %s", pers->random );
  775.             }
  776.         }
  777.         else  {
  778.             if(  strlen( pers->random ) > 0  )  {
  779.             printf( "\n, %s", pers->random );
  780.             }
  781.         }
  782.         }
  783.         else  {
  784.         if(  strlen( pers->homephone ) > 0  )  {
  785.             printf( "\nPhone: %s", pers->homephone );
  786.             if(  strlen( pers->random ) > 0  )  {
  787.             printf( ", %s", pers->random );
  788.             }
  789.         }
  790.         else  {
  791.             if(  strlen( pers->random ) > 0  )  {
  792.             printf( "\n%s", pers->random );
  793.             }
  794.         }
  795.         }
  796.     }
  797.     if( unbrief )  {
  798.         printf( "\n" );
  799.         printf( "Directory: %-25s", pwdt->pw_dir );
  800.         if(  strlen( pwdt->pw_shell ) > 0  )  {
  801.         printf( "    Shell: %-s", pwdt->pw_shell );
  802.         }
  803.     }
  804.     if( pers->loggedin )  {
  805.         register char *ep = ctime( &pers->loginat );
  806.         printf("\nOn since %15.15s on %-*.*s    ", &ep[4], LMAX, LMAX, pers->tty );
  807.         idleprinted = ltimeprint( &pers->idletime );
  808.         if( idleprinted )  {
  809.         printf( " Idle Time" );
  810.         }
  811.     }
  812.     else if (pers->loginat == 0)
  813. #ifdef HAVE_LASTLOG
  814.         printf("\nNever logged in.");
  815. #else
  816.         printf("\nNot logged in.");
  817. #endif
  818.     else if (tloc - pers->loginat > 180 * 24 * 60 * 60) {
  819.         register char *ep = ctime( &pers->loginat );
  820.         printf("\nLast login %10.10s, %4.4s on %.*s", ep, ep+20, LMAX, pers->tty);
  821.     }
  822.     else  {
  823.         register char *ep = ctime( &pers->loginat );
  824.         printf("\nLast login %16.16s on %.*s", ep, LMAX, pers->tty );
  825.     }
  826.     printf( "\n" );
  827. }
  828.  
  829.  
  830. /*
  831.  *  very hacky section of code to format phone numbers.  filled with
  832.  *  magic constants like 4, 7 and 10.
  833.  */
  834.  
  835. char  *phone( s, len )
  836.  
  837.     char        *s;
  838.     int            len;
  839. {
  840.     char        *strsave();
  841.     char        fonebuf[ 15 ];
  842.     int        i;
  843.  
  844.     switch(  len  )  {
  845.  
  846.         case  4:
  847. #ifdef ICDOC
  848.         fonebuf[ 0 ] = ' ';
  849.         fonebuf[ 1 ] = 'x';
  850.         for( i = 0; i <= 3; i++ )  {
  851.             fonebuf[ 2 + i ] = *s++;
  852.         }
  853.         fonebuf[ 6 ] = NULL;
  854. #else
  855.         fonebuf[ 0 ] = ' ';
  856.         fonebuf[ 1 ] = 'x';
  857.         fonebuf[ 2 ] = '2';
  858.         fonebuf[ 3 ] = '-';
  859.         for( i = 0; i <= 3; i++ )  {
  860.             fonebuf[ 4 + i ] = *s++;
  861.         }
  862.         fonebuf[ 8 ] = NULL;
  863. #endif
  864.         return( strsave( &fonebuf[0] ) );
  865.         break;
  866.  
  867.         case  7:
  868.         for( i = 0; i <= 2; i++ )  {
  869.             fonebuf[ i ] = *s++;
  870.         }
  871. #ifdef ICDOC
  872.         fonebuf[ 3 ] = ' ';        /* BT plc standard! */
  873. #else
  874.         fonebuf[ 3 ] = '-';
  875. #endif
  876.         for( i = 0; i <= 3; i++ )  {
  877.             fonebuf[ 4 + i ] = *s++;
  878.         }
  879.         fonebuf[ 8 ] = NULL;
  880.         return( strsave( &fonebuf[0] ) );
  881.         break;
  882.  
  883.         case 10:
  884.         for( i = 0; i <= 2; i++ )  {
  885.             fonebuf[ i ] = *s++;
  886.         }
  887.         fonebuf[ 3 ] = '-';
  888.         for( i = 0; i <= 2; i++ )  {
  889.             fonebuf[ 4 + i ] = *s++;
  890.         }
  891.         fonebuf[ 7 ] = '-';
  892.         for( i = 0; i <= 3; i++ )  {
  893.             fonebuf[ 8 + i ] = *s++;
  894.         }
  895.         fonebuf[ 12 ] = NULL;
  896.         return( strsave( &fonebuf[0] ) );
  897.         break;
  898.  
  899.         default:
  900.         fprintf( stderr, "finger: error in phone numbering\n" );
  901.         return( strsave(s) );
  902.         break;
  903.     }
  904. }
  905.  
  906.  
  907. /*  decode the information in the gecos field of /etc/passwd
  908.  *  another hacky section of code, but given the format the stuff is in...
  909.  */
  910.  
  911. decode( pers )
  912.  
  913.     struct  person    *pers;
  914.  
  915. {
  916.     struct  passwd        *pwdt = pers->pwd;
  917.     char            buffer[ 256 ],  *bp,  *gp,  *lp;
  918.     char            *phone();
  919.     int            alldigits;
  920.     int            len;
  921.     int            i;
  922.  
  923.     pers->realname = NULLSTR;
  924.     pers->office = NULLSTR;
  925.     pers->officephone = NULLSTR;
  926.     pers->homephone = NULLSTR;
  927.     pers->random = NULLSTR;
  928.     if(  pwdt != NILPWD )  {
  929.         gp = pwdt->pw_gecos;
  930. #ifdef DEBUG
  931. fprintf(stderr, "gecos = %s\n", gp);
  932. #endif
  933.         bp = &buffer[ 0 ];
  934.         if( *gp == ASTERISK )  {
  935.         gp++;
  936.         }
  937.         while(  (*gp != NULL)  &&  (*gp != COMMA)  )  {    /* name */
  938.         if( *gp == SAMENAME )  {
  939.             lp = pwdt->pw_name;
  940.             *bp++ = CAPITALIZE(*lp++);
  941.             while( *lp != NULL )  {
  942.             *bp++ = *lp++;
  943.             }
  944.         }
  945.         else  {
  946.             *bp++ = *gp;
  947.         }
  948.         gp++;
  949.         }
  950.         *bp = NULL;
  951.         pers->realname = malloc( strlen( &buffer[0] ) + 1 );
  952.         strcpy( pers->realname, &buffer[0] );
  953. #ifdef DEBUG
  954. fprintf(stderr, "name = %s\n", pers->realname);
  955. #endif
  956.         if( *gp++ == COMMA )  {            /* office, supposedly */
  957. #ifdef DEBUG
  958. fprintf(stderr, "office...");
  959. #endif
  960.         alldigits = 1;
  961.         bp = &buffer[ 0 ];
  962.         while(  (*gp != NULL)  &&  (*gp != COMMA)  )  {
  963.             *bp = *gp++;
  964.             alldigits = alldigits && ('0' <= *bp) && (*bp <= '9');
  965.             bp++;
  966.         }
  967.         *bp = NULL;
  968.         len = strlen( &buffer[0] );
  969. #ifdef DEBUG
  970. fprintf(stderr, "got %s...", buffer);
  971. #endif
  972. #ifdef ICDOC
  973.         if( buffer[ len - 1 ]  ==  HUXLEY )  {
  974. #ifdef    ERCC
  975.             strcpy( &buffer[ len - 1 ], " JCMB" );
  976. #else
  977.             strcpy( &buffer[ len - 1 ], " Huxley" );
  978. #endif    ERCC
  979.             pers->office = malloc( len + 5 );
  980.             strcpy( pers->office, &buffer[0] );
  981.         } else {
  982. #endif
  983.         if( buffer[ len - 1 ]  ==  CORY )  {
  984.             strcpy( &buffer[ len - 1 ], " Cory" );
  985.             pers->office = malloc( len + 5 );
  986.             strcpy( pers->office, &buffer[0] );
  987.         }
  988.         else  {
  989.             if( buffer[ len - 1 ] == EVANS )  {
  990.             strcpy( &buffer[ len - 1 ], " Evans" );
  991.             pers->office = malloc( len + 6 );
  992.             strcpy( pers->office, &buffer[0] );
  993.             }
  994.             else  {
  995.             if( buffer[ len - 1 ] == 'L' )  {
  996.                 strcpy( &buffer[ len - 1 ], " LBL" );
  997.                 pers->office = malloc( len + 4 );
  998.                 strcpy( pers->office, &buffer[0] );
  999.             }
  1000.             else  {
  1001.                 if( alldigits )  {
  1002.                 if( len == 4 )  {
  1003.                     pers->officephone = phone(&buffer[0], len);
  1004.                 }
  1005.                 else  {
  1006.                     if(  (len == 7) || (len == 10)  )  {
  1007.                     pers->homephone = phone(&buffer[0],len);
  1008.                     }
  1009.                 }
  1010.                 }
  1011.                 else  {
  1012.                 pers->random = malloc( len + 1 );
  1013.                 strcpy( pers->random, &buffer[0] );
  1014.                 }
  1015.             }
  1016.             }
  1017.         }
  1018. #ifdef ICDOC
  1019. /*}*/
  1020. #endif
  1021. #ifdef DEBUG
  1022. fprintf(stderr, "ended up with %s\n", pers->office);
  1023. #endif
  1024.         if( *gp++ == COMMA )  {        /* office phone, theoretically */
  1025. #ifdef DEBUG
  1026. fprintf(stderr, "Processing %s\n", gp);
  1027. #endif
  1028.             bp = &buffer[ 0 ];
  1029.             alldigits = 1;
  1030.             while(  (*gp != NULL)  &&  (*gp != COMMA)  )  {
  1031.             *bp = *gp++;
  1032.             alldigits = alldigits && ('0' <= *bp) && (*bp <= '9');
  1033.             bp++;
  1034.             }
  1035.             *bp = NULL;
  1036. #ifdef DEBUG
  1037. fprintf(stderr, "Got %s...", buffer);
  1038. #endif
  1039.             len = strlen( &buffer[0] );
  1040.             if( alldigits )  {
  1041.             if(  len != 4  )  {
  1042.                 if(  (len == 7) || (len == 10)  )  {
  1043.                 pers->homephone = phone( &buffer[0], len );
  1044.                 }
  1045.                 else  {
  1046.                 pers->random = malloc( len + 1 );
  1047.                 strcpy( pers->random, &buffer[0] );
  1048.                 }
  1049.             }
  1050.             else  {
  1051. #ifdef DEBUG
  1052. fprintf(stderr, "len == 4, so officephone\n");
  1053. #endif
  1054.                 pers->officephone = phone( &buffer[0], len );
  1055.             }
  1056.             }
  1057.             else  {
  1058.             pers->random = malloc( len + 1 );
  1059.             strcpy( pers->random, &buffer[0] );
  1060.             }
  1061.             if( *gp++ == COMMA )  {        /* home phone?? */
  1062. #ifdef DEBUG
  1063. fprintf(stderr, "looking for home phone in %s\n", gp);
  1064. #endif
  1065.             bp = &buffer[ 0 ];
  1066.             alldigits = 1;
  1067.                 while(  (*gp != NULL)  &&  (*gp != COMMA)  )  {
  1068.                 *bp = *gp++;
  1069.                 alldigits = alldigits && ('0' <= *bp) &&
  1070.                             (*bp <= '9');
  1071.                 bp++;
  1072.                 }
  1073.             *bp = NULL;
  1074.             len = strlen( &buffer[0] );
  1075.             if( alldigits  &&  ( (len == 7) || (len == 10) )  )  {
  1076.                 if( *pers->homephone != NULL )  {
  1077.                 pers->officephone = pers->homephone;
  1078.                 }
  1079.                 pers->homephone = phone( &buffer[0], len );
  1080.             }
  1081.             else  {
  1082.                 pers->random = malloc( strlen( &buffer[0] ) + 1 );
  1083.                 strcpy( pers->random, &buffer[0] );
  1084.             }
  1085.             }
  1086.         }
  1087.         }
  1088.         if( pers->loggedin == 0 )  {
  1089.         findwhen( pers );
  1090.         }
  1091.         else  {
  1092.         findidle( pers );
  1093.         }
  1094.     }
  1095. }
  1096.  
  1097.  
  1098. /*  find the last log in of a user by checking the LASTLOG file.
  1099.  *  the entry is indexed by the uid, so this can only be done if
  1100.  *  the uid is known (which it isn't in quick mode)
  1101.  */
  1102.  
  1103. fwopen()
  1104. {
  1105. #ifdef HAVE_LASTLOG
  1106.     if(  ( lf = open(LASTLOG, 0) ) >= 0  )  {
  1107.         llopenerr = 0;
  1108.     }
  1109.     else  {
  1110.         fprintf( stderr, "finger: lastlog open error\n" );
  1111.         llopenerr = 1;
  1112.     }
  1113. #else
  1114.     llopenerr = 1;
  1115. #endif
  1116. }
  1117.  
  1118.  
  1119. findwhen( pers )
  1120.  
  1121.     struct  person    *pers;
  1122. {
  1123. #ifdef HAVE_LASTLOG
  1124.     struct  passwd        *pwdt = pers->pwd;
  1125.     struct  lastlog        ll;
  1126.     int            llsize = sizeof ll;
  1127.     int            i;
  1128.  
  1129.     if( !llopenerr )  {
  1130.         lseek( lf, pwdt->pw_uid*llsize, 0 );
  1131.         if ((i = read( lf, (char *) &ll, llsize )) == llsize) {
  1132.             for( i = 0; i < LMAX; i++ )  {
  1133.             pers->tty[ i ] = ll.ll_line[ i ];
  1134.             }
  1135.             pers->tty[ LMAX ] = NULL;
  1136.             pers->loginat = ll.ll_time;
  1137.         }
  1138.         else  {
  1139.         if (i != 0)
  1140.             fprintf(stderr, "finger: lastlog read error\n");
  1141.         pers->tty[ 0 ] = NULL;
  1142.         pers->loginat = 0L;
  1143.         }
  1144.     }
  1145.     else  {
  1146.         pers->tty[ 0 ] = NULL;
  1147.         pers->loginat = 0L;
  1148.     }
  1149. #else
  1150.     pers->tty[ 0 ] = NULL;
  1151.     pers->loginat = 0L;
  1152. #endif
  1153. }
  1154.  
  1155.  
  1156. fwclose()
  1157. {
  1158.     if( !llopenerr )  {
  1159.         close( lf );
  1160.     }
  1161. }
  1162.  
  1163.  
  1164. /*  find the idle time of a user by doing a stat on /dev/histty,
  1165.  *  where histty has been gotten from USERLOG, supposedly.
  1166.  */
  1167.  
  1168. findidle( pers )
  1169.  
  1170.     struct  person    *pers;
  1171. {
  1172.     struct  stat        ttystatus;
  1173.     struct  passwd        *pwdt = pers->pwd;
  1174.     char            buffer[ 20 ];
  1175.     char            *TTY = "/dev/";
  1176.     int            TTYLEN = strlen( TTY );
  1177.     int            i;
  1178.  
  1179.     strcpy( &buffer[0], TTY );
  1180.     i = 0;
  1181.     do  {
  1182.         buffer[ TTYLEN + i ] = pers->tty[ i ];
  1183.     }  while( ++i <= LMAX );
  1184.     if(  stat( &buffer[0], &ttystatus ) >= 0  )  {
  1185.         time( &tloc );
  1186.         if( tloc < ttystatus.st_atime )  {
  1187.         pers->idletime = 0L;
  1188.         }
  1189.         else  {
  1190.         pers->idletime = tloc - ttystatus.st_atime;
  1191.         }
  1192.         if(  (ttystatus.st_mode & TALKABLE) == TALKABLE  )  {
  1193.         pers->writeable = 1;
  1194.         }
  1195.         else  {
  1196.         pers->writeable = 0;
  1197.         }
  1198.     }
  1199.     else  {
  1200.         fprintf( stderr, "finger: error STATing %s\n", &buffer[0] );
  1201.         exit( 4 );
  1202.     }
  1203. }
  1204.  
  1205.  
  1206. /*  print idle time in short format; this program always prints 4 characters;
  1207.  *  if the idle time is zero, it prints 4 blanks.
  1208.  */
  1209.  
  1210. stimeprint( dt )
  1211.  
  1212.     long    *dt;
  1213. {
  1214.     struct  tm        *gmtime();
  1215.     struct  tm        *delta;
  1216.  
  1217.     delta = gmtime( dt );
  1218.     if( delta->tm_yday == 0 )  {
  1219.         if( delta->tm_hour == 0 )  {
  1220.         if( delta->tm_min >= 10 )  {
  1221.             printf( " %2.2d ", delta->tm_min );
  1222.         }
  1223.         else  {
  1224.             if( delta->tm_min == 0 )  {
  1225.             printf( "    " );
  1226.             }
  1227.             else  {
  1228.             printf( "  %1.1d ", delta->tm_min );
  1229.             }
  1230.         }
  1231.         }
  1232.         else  {
  1233.         if( delta->tm_hour >= 10 )  {
  1234.             printf( "%3.3d:", delta->tm_hour );
  1235.         }
  1236.         else  {
  1237.             printf( "%1.1d:%02.2d", delta->tm_hour, delta->tm_min );
  1238.         }
  1239.         }
  1240.     }
  1241.     else  {
  1242.         printf( "%3dd", delta->tm_yday );
  1243.     }
  1244. }
  1245.  
  1246.  
  1247. /*  print idle time in long format with care being taken not to pluralize
  1248.  *  1 minutes or 1 hours or 1 days.
  1249.  */
  1250.  
  1251. ltimeprint( dt )
  1252.  
  1253.     long    *dt;
  1254. {
  1255.     struct  tm        *gmtime();
  1256.     struct  tm        *delta;
  1257.     int            printed = 1;
  1258.  
  1259.     delta = gmtime( dt );
  1260.     if( delta->tm_yday == 0 )  {
  1261.         if( delta->tm_hour == 0 )  {
  1262.         if( delta->tm_min >= 10 )  {
  1263.             printf( "%2d minutes", delta->tm_min );
  1264.         }
  1265.         else  {
  1266.             if( delta->tm_min == 0 )  {
  1267.             if( delta->tm_sec > 10 )  {
  1268.                 printf( "%2d seconds", delta->tm_sec );
  1269.             }
  1270.             else  {
  1271.                 printed = 0;
  1272.             }
  1273.             }
  1274.             else  {
  1275.             if( delta->tm_min == 1 )  {
  1276.                 if( delta->tm_sec == 1 )  {
  1277.                 printf( "%1d minute %1d second",
  1278.                     delta->tm_min, delta->tm_sec );
  1279.                 }
  1280.                 else  {
  1281.                 printf( "%1d minute %d seconds",
  1282.                     delta->tm_min, delta->tm_sec );
  1283.                 }
  1284.             }
  1285.             else  {
  1286.                 if( delta->tm_sec == 1 )  {
  1287.                 printf( "%1d minutes %1d second",
  1288.                     delta->tm_min, delta->tm_sec );
  1289.                 }
  1290.                 else  {
  1291.                 printf( "%1d minutes %d seconds",
  1292.                     delta->tm_min, delta->tm_sec );
  1293.                 }
  1294.             }
  1295.             }
  1296.         }
  1297.         }
  1298.         else  {
  1299.         if( delta->tm_hour >= 10 )  {
  1300.             printf( "%2d hours", delta->tm_hour );
  1301.         }
  1302.         else  {
  1303.             if( delta->tm_hour == 1 )  {
  1304.             if( delta->tm_min == 1 )  {
  1305.                 printf( "%1d hour %1d minute",
  1306.                 delta->tm_hour, delta->tm_min );
  1307.             }
  1308.             else  {
  1309.                 printf( "%1d hour %2d minutes",
  1310.                 delta->tm_hour, delta->tm_min );
  1311.             }
  1312.             }
  1313.             else  {
  1314.             if( delta->tm_min == 1 )  {
  1315.                 printf( "%1d hours %1d minute",
  1316.                 delta->tm_hour, delta->tm_min );
  1317.             }
  1318.             else  {
  1319.                 printf( "%1d hours %2d minutes",
  1320.                 delta->tm_hour, delta->tm_min );
  1321.             }
  1322.             }
  1323.         }
  1324.         }
  1325.     }
  1326.     else  {
  1327.         if( delta->tm_yday >= 10 )  {
  1328.             printf( "%2d days", delta->tm_yday );
  1329.         }
  1330.         else  {
  1331.             if( delta->tm_yday == 1 )  {
  1332.             if( delta->tm_hour == 1 )  {
  1333.                 printf( "%1d day %1d hour",
  1334.                 delta->tm_yday, delta->tm_hour );
  1335.             }
  1336.             else  {
  1337.                 printf( "%1d day %2d hours",
  1338.                 delta->tm_yday, delta->tm_hour );
  1339.             }
  1340.             }
  1341.             else  {
  1342.             if( delta->tm_hour == 1 )  {
  1343.                 printf( "%1d days %1d hour",
  1344.                 delta->tm_yday, delta->tm_hour );
  1345.             }
  1346.             else  {
  1347.                 printf( "%1d days %2d hours",
  1348.                 delta->tm_yday, delta->tm_hour );
  1349.             }
  1350.             }
  1351.         }
  1352.     }
  1353.     return( printed );
  1354. }
  1355.  
  1356.  
  1357. matchcmp( gname, login, given )
  1358.  
  1359.     char        *gname;
  1360.     char        *login;
  1361.     char        *given;
  1362. {
  1363.     char        buffer[ 20 ];
  1364.     char        c;
  1365.     int        flag,  i,  unfound;
  1366.  
  1367.     if( !match )  {
  1368.         return( 0 );
  1369.     }
  1370.     else  {
  1371.         if(  namecmp( login, given )  )  {
  1372.         return( 1 );
  1373.         }
  1374.         else if (*gname == '\0')
  1375.         return (0);
  1376.         else  {
  1377.         if( *gname == ASTERISK )  {
  1378.             gname++;
  1379.         }
  1380.         flag = 1;
  1381.         i = 0;
  1382.         unfound = 1;
  1383.         while(  unfound  )  {
  1384.             if( flag )  {
  1385.             c = *gname++;
  1386.             if( c == SAMENAME )  {
  1387.                 flag = 0;
  1388.                 c = *login++;
  1389.             }
  1390.             else  {
  1391.                 unfound = (*gname != COMMA)  &&  (*gname != NULL);
  1392.             }
  1393.             }
  1394.             else {
  1395.             c = *login++;
  1396.             if( c == NULL )  {
  1397.                 if(  (*gname == COMMA)  ||  (*gname == NULL)  )  {
  1398.                 break;
  1399.                 }
  1400.                 else  {
  1401.                 flag = 1;
  1402.                 continue;
  1403.                 }
  1404.             }
  1405.             }
  1406.             if( c == BLANK )  {
  1407.             buffer[i++] = NULL;
  1408.             if(  namecmp( buffer, given )  )  {
  1409.                 return( 1 );
  1410.             }
  1411.             i = 0;
  1412.             flag = 1;
  1413.             }
  1414.             else  {
  1415.             buffer[ i++ ] = c;
  1416.             }
  1417.         }
  1418.         buffer[i++] = NULL;
  1419.         if(  namecmp( buffer, given )  )  {
  1420.             return( 1 );
  1421.         }
  1422.         else  {
  1423.             return( 0 );
  1424.         }
  1425.         }
  1426.     }
  1427. }
  1428.  
  1429.  
  1430. namecmp( name1, name2 )
  1431.  
  1432.     char        *name1;
  1433.     char        *name2;
  1434. {
  1435.     char        c1,  c2;
  1436.  
  1437.     c1 = *name1;
  1438.     if( (('A' <= c1) && (c1 <= 'Z')) || (('a' <= c1) && (c1 <= 'z')) )  {
  1439.         c1 = CAPITALIZE( c1 );
  1440.     }
  1441.     c2 = *name2;
  1442.     if( (('A' <= c2) && (c2 <= 'Z')) || (('a' <= c2) && (c2 <= 'z')) )  {
  1443.         c2 = CAPITALIZE( c2 );
  1444.     }
  1445.     while( c1 == c2 )  {
  1446.         if( c1 == NULL )  {
  1447.         return( 1 );
  1448.         }
  1449.         c1 = *++name1;
  1450.         if( (('A'<=c1) && (c1<='Z')) || (('a'<=c1) && (c1<='z')) )  {
  1451.         c1 = CAPITALIZE( c1 );
  1452.         }
  1453.         c2 = *++name2;
  1454.         if( (('A'<=c2) && (c2<='Z')) || (('a'<=c2) && (c2<='z')) )  {
  1455.         c2 = CAPITALIZE( c2 );
  1456.         }
  1457.     }
  1458.     if( *name1 == NULL )  {
  1459.         while(  ('0' <= *name2)  &&  (*name2 <= '9')  )  {
  1460.         name2++;
  1461.         }
  1462.         if( *name2 == NULL )  {
  1463.         return( 1 );
  1464.         }
  1465.     }
  1466.     else  {
  1467.         if( *name2 == NULL )  {
  1468.         while(  ('0' <= *name1)  &&  (*name1 <= '9')  )  {
  1469.             name1++;
  1470.         }
  1471.         if( *name1 == NULL )  {
  1472.             return( 1 );
  1473.         }
  1474.         }
  1475.     }
  1476.     return( 0 );
  1477. }
  1478.  
  1479.  
  1480. char  *strsave( s )
  1481.  
  1482.     char        *s;
  1483. {
  1484.     char        *malloc();
  1485.     char        *p;
  1486.  
  1487.     p = malloc( strlen( s ) + 1 );
  1488.     strcpy( p, s );
  1489. }
  1490.