/* -*- c -*-
 *
 * Author:      James Brister <brister@vix.com> -- berkeley-unix --
 * Start Date:  Fri, 13 Jun 1997 17:08:31 +0200
 * Project:     INN 
 * File:        ident.c
 * RCSId:       $Id: ident.c,v 1.2 1997/07/23 13:45:52 brister Exp $
 * Description: Query the ident server of the machine on the other end of
 *		the given fd (see RFC1413).
 * 
 */

#if ! defined (lint)
static const char *rcsid = "$Id: ident.c,v 1.2 1997/07/23 13:45:52 brister Exp $" ;
static void use_rcsid (const char *rid) {   /* Never called */
  use_rcsid (rcsid) ; use_rcsid (rid) ;
}
#endif

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include "configdata.h"
#include "clibrary.h"

#if defined (WANT_MAIN)
static char inputBuffer[256] ;
#endif

/* timeout is in seconds. Should be > 0 to give remote time to respond. */
char *identInfo (int fd, int timeout)
{
  struct sockaddr_in us ;
  struct sockaddr_in them ;
  struct sockaddr_in cxn ;
  struct servent *idservice ;
  int uslen = sizeof (us) ;
  int themlen = sizeof (them) ;
  int cxnfd ;
  int cxnlen ;
  char buffer [80];
  char field1 [10] ;
  char field2 [80] ;
  char *ptr ;
  static char idname [80] ;
  int i, j, k, inport1, inport2 ;
  FDSET wr_set ;
  FDSET rd_set ;
  struct timeval tout ;


#if ! defined (WANT_MAIN)

  if (getsockname (fd,(struct sockaddr *) &us, (int *) &uslen) != 0)
      return NULL ;

  if (getpeername (fd, (struct sockaddr *) &them, (int *) &themlen) != 0)
      return NULL ;
  
  if ((cxnfd  = socket (AF_INET,SOCK_STREAM,0)) < 0)
      return NULL ;

  memset (&cxn,0,sizeof(cxn)) ;
  cxn.sin_family = AF_INET ;
  cxn.sin_addr.s_addr = them.sin_addr.s_addr ;
  cxnlen = sizeof(cxn) ;

  if ((idservice = getservbyname ("ident","tcp")) == NULL)
    cxn.sin_port = htons (113) ;
  else
    cxn.sin_port = idservice->s_port ;

  SetNonBlocking (cxnfd,1) ;
  
  if (connect (cxnfd,(struct sockaddr *) &cxn, cxnlen) < 0) {
      close (cxnfd) ;
      return NULL ;
  }

  memset (&wr_set,0,sizeof (wr_set)) ;
  tout.tv_sec = timeout ;
  tout.tv_usec = 0 ;
  FD_SET(cxnfd,&wr_set) ;
  if ((i = select (cxnfd + 1,0,&wr_set,0,&tout)) != 1) {
      close (cxnfd) ;
      return NULL ;
  }
  
  snprintf (buffer,sizeof(buffer),"%d, %d\r\n",
            (int)ntohs(them.sin_port),(int)ntohs(us.sin_port)) ;

  memset (&rd_set,0,sizeof (rd_set)) ;
  memset (&wr_set,0,sizeof (wr_set)) ;

  tout.tv_sec = timeout ;
  tout.tv_usec = 0 ;
  FD_SET(cxnfd,&wr_set) ;
  
  if ((i = select (cxnfd + 1,0,&wr_set,0,&tout)) != 1) {
      close (cxnfd) ;
      return NULL ;
  }

  if ((i = write (cxnfd,buffer,strlen(buffer))) != strlen (buffer)) {
      close (cxnfd) ;
      return NULL ;
  }

  tout.tv_sec = timeout ;
  tout.tv_usec = 0 ;
  FD_SET(cxnfd,&rd_set) ;
  
  if ((i = select (cxnfd + 1,&rd_set,0,0,&tout)) != 1) {
      close (cxnfd) ;
      return NULL ;
  }
  
  i = read (cxnfd,buffer,sizeof(buffer) - 1) ;

  close (cxnfd) ;

  if (i < 0) {
      return NULL ;
  }

  buffer [i] = '\0' ;


  /* NOW parse the line. Format is:

     6193, 23 : USERID : UNIX : stjohns

     but some systems don't have all the spaces here and simple scanf
     doesn't work on others so we do the ugliness below.
   */

#else
  
  strcpy (buffer,inputBuffer) ;

#endif
  
  ptr = buffer ;

  /* grab first integer  */
  ptr += strspn (buffer," \t") ;
  if (*ptr == '\0')
      return NULL ;
  if ((inport1 = atol (ptr)) == 0)
      return NULL ;
  ptr += strspn (ptr,"0123456789") ;

  /* check for comma */
  ptr += strspn (ptr," \t") ;
  if (*ptr != ',')
      return NULL ;

  /* grab second integer */
  ptr++ ;
  ptr += strspn (ptr," \t") ;
  if ((inport2 = atol(ptr)) == 0)
      return NULL ;
  ptr += strspn (ptr,"0123456789") ;

  /* check for colon */
  ptr += strspn (ptr," \t") ;
  if (*ptr != ':')
      return NULL ;

  /* grab response type */
  ptr++ ;
  ptr += strspn (ptr," \t") ;
  if ((i = strcspn (ptr," :")) == 0)
      return NULL ;
  strncpy (field1,ptr,(i < sizeof (field1) - 1 ? i : sizeof (field1) - 1));
  field1[sizeof(field1)-1] = '\0' ;
  if (strcmp (field1,"USERID") != 0)
      return NULL ;
  ptr += i ;

  /* check for next colon */
  ptr += strspn (ptr," \t") ;
  if (*ptr != ':')
      return NULL ;
  ptr ++ ;

  /* grab opsys field */
  ptr += strspn (ptr," \t") ;
  i = strcspn (ptr,":") ;
  if (i == 0 || *(ptr + i) == '\0')
      return NULL ;
  strncpy (field2,ptr,(i < sizeof (field2) - 1 ? i : sizeof(field2) - 1)) ;
  ptr += i + 1 ;

  /* now, finally, grab id */
  ptr += strspn (ptr," \t") ;
  if ((i = strcspn (ptr," \t")) == 0)
      return NULL ;
  if (i > sizeof (idname) - 1)
      return NULL ;

  /* strip out any illegal characters */
  for (j = k = 0 ; j < i ; j++) {
      if (isprint (ptr[j]) && !isspace (ptr [j]) && ptr [j] != ':')
          idname [k++] = ptr [j] ;
  }
  idname [k] = '\0' ;

  return (idname[0] == '\0' ? NULL : idname) ; 
}


#if defined (WANT_MAIN)
int main (int argc, char **argv) 
{
    if (argc < 2)
        return ;
    
    strcpy (inputBuffer,argv[1]) ;
    printf ("%s\n",identInfo (0,0)) ;
}
#endif
