/* -*- 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.1 1997/07/17 21:51:36 brister Exp $
 * Description: Query the ident server of the machine on the other end of
 *		the given fd.
 * 
 */

#if ! defined (lint)
static const char *rcsid = "$Id: ident.c,v 1.1 1997/07/17 21:51:36 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"

/* 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 idport ;
  int cxnfd ;
  int cxnlen ;
  char buffer [80];
  char field1 [10] ;
  char field2 [80] ;
  static char idname [80] ;
  int i, inport1, inport2 ;
  char *p, *q ;
  FDSET wr_set ;
  FDSET rd_set ;
  struct timeval tout ;


  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 ;

  if (connect (cxnfd,(struct sockaddr *) &cxn, cxnlen) < 0) {
      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' ;
  
  if (sscanf (buffer,"%d , %d : %10s : %79s : %79s",
              &inport1,&inport2,&field1,&field2,&idname) != 5)
      return NULL ;
  else if (strcmp (field1,"ERROR") == 0)
      return NULL ;

  return idname ;
}
