home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Distributions / ucb / spencer_2bsd.tar.gz / 2bsd.tar / src / finger.c < prev    next >
C/C++ Source or Header  |  1980-02-17  |  30KB  |  1,322 lines

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