/*---------------------------------------------------------------------+
|                Copyright (c) 1995, SAS Institute Inc.                |
|                  Unpublished - All Rights Reserved                   |
|                      S A S / C   S A M P L E                         |
|                                                                      |
|         NAME: FINGER                                                 |
|     LANGUAGE: C                                                      |
|      PURPOSE: This is a sample FINGER client. The client queries the |
|               finger server on the remote host. The finger server    |
|               returns information about currently logged on users.   |
|               This is a complete sample using: gethostbyname(),      |
|               getservbyname(), socket(), connect(), write(), and     |
|               close(). The syntax of the command is:                 |
|               finger [-l] host_name                                  |
|        NOTES: -l is optional, and produces additional output.        |
|   MVS -                                                              |
|      COMPILE, LINK, EXECUTE: SUBMIT prefix.SAMPLE.AUX(LC370CLG)      |
|        NOTES: "prefix" is the SAS/C installation defined high-level  |
|               qualifier.                                             |
|        NOTES: on the EXEC statement add a: ,PARM.GO='host_name'      |
|               Where "host_name" is the host running a "fingerd".     |
|   TSO -                                                              |
|      COMPILE: LC370 CLIST                                            |
|         LINK: CLK370 CLIST                                           |
|      EXECUTE: CALL 'your.load.lib(FINGER)' 'host_name' asis          |
|               Where "host_name" is the host running a "fingerd".     |
|   CMS -                                                              |
|      COMPILE: LC370                                                  |
|         LINK: CLINK FINGER  (GENMOD                                  |
|      EXECUTE: FINGER  host_name                                      |
|               Where "host_name" is the host running a "fingerd".     |
+---------------------------------------------------------------------*/
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>

/* No need to translate characters on ASCII systems. */
#ifndef  __SASC__
#define ntohcs(c) (c)
#define htoncs(c) (c)
#endif

/* Define some useful constants. */
#define FALSE 0
#define TRUE 1
#define READ_BLOCK_SIZE 256
#define OUTBUF_SIZE 2
#define FINGER_PORT 79
#define ASCII_CR 0x0D
#define ASCII_LF 0x0A

main(int argc, char *argv[])
{
   int n,i;

   /* Socket descriptor for communication with the */
   /*   finger server. */
   int s;

   /* Socket address for server. */
   struct sockaddr_in sa;

   /* Use to send ASCII CR and LF characters required by */
   /*   the protocol. */
   char cr = ASCII_CR, lf = ASCII_LF;

   /* Buffers. */
   char in[READ_BLOCK_SIZE];
   char out[OUTBUF_SIZE];

   /* Option status. */
   int longlist = FALSE;
   char *op;

   /* Will contain information about the finger service. */
   struct servent *serv;
   /* Will contain information about the remote host. */
   struct hostent *host;


   /* Argument processing. */
   if (*++argv && *argv[0] == '-')
   {
      op = *argv;
      if (op[1]=='l')
         longlist = 1;
      else
         printf("finger: unsupported option \"%c\"",op[1]);
      argv++;
   }
   if (!*argv)
   {
      printf("finger: hostname missing");
      exit(EXIT_FAILURE);
   }
   /* Assume *argv now points to hostname. */

   /* Find the IP address for the requested host.         */
   host = gethostbyname(*argv);
   if (host==NULL)
   {
       printf("finger: Host %s is unknown.\n",*argv);
       exit(EXIT_FAILURE);
   }

   /* Find the port for the finger service. If the        */
   /*   services file is not available, we will use the   */
   /*   standard number. We specify "tcp" as the protocol.*/
   /* This call will attempt to find the services file.   */
   serv = getservbyname("finger", "tcp");

   /* Prepare a socket address for the server. We need an */
   /*   IP address (corresponding to the given hostname)  */
   /*   and a port number (corresponding to the "finger"  */
   /*   service.                                          */
   memset(&sa,'\0',sizeof(sa));
   sa.sin_family = AF_INET;
   memcpy(&sa.sin_addr,host->h_addr,sizeof(sa.sin_addr));
   sa.sin_port = serv ? serv->s_port : htons(FINGER_PORT);

   /* Get a socket of the proper type. We use SOCK_STREAM */
   /*   because we want to communicate using TCP          */
   /*   (we want a reliable protocol).                    */
   s = socket(AF_INET, SOCK_STREAM, 0);
   if (s == -1)
   {
      perror("finger - socket() failed");
      exit(EXIT_FAILURE);
   }

   /* Connect to the host and port.                       */
   if (connect(s, &sa, sizeof(sa)) == -1)
   {
      perror("finger - connect() failed");
      return(EXIT_FAILURE);
   }

   /* read() and write() are the most convenient calls   */
   /*   for transmitting and receiving data over stream  */
   /*   sockets.                                         */

   /* Write to server. */
   /* If long option specified, pass that first. */
   if (longlist)
   {
      out[0] = htoncs('/');
      out[1] = htoncs('W');
      write(s,out,2);
   }
   /* Terminate msg with CR-LF. */
   write(s,&cr,1);
   write(s,&lf,1);

   /* Server should respond. */
   /* Read until EOF indicated. */
   while (n=read(s,in,READ_BLOCK_SIZE))
   {
      for (i=0; i<n ; i++)
      {
         if (in[i]==ASCII_CR) continue; /* Presume part of CR-LF pair */
         putchar(ntohcs(in[i]));
      }
   }

   /* Close the socket. */
   close(s);

}