//  This program is copyright Russell Coker.  May be freely distributed and
//  used under the terms of the GPL.
//  It's designed to be run from inetd.  It takes 2 command line parameters,
//  the first is the TCP port, the second is the IPv4 address in dotted
//  decimal.
//
//  Version 1.3.  If you want to send me patches to this then I'll include them
//  and give you credit.

#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include "pass.h"

int text2num(sockaddr_in &sa, char *pcAddr)
{
  for(int i = 0; i < int(strlen(pcAddr)); i++)
  {
    if(pcAddr[i] == ':')
    {
      pcAddr[i] = '\0';
      sa.sin_family = AF_INET;
      sa.sin_port = htons(short(atoi(&pcAddr[i+1])));
      sa.sin_addr.s_addr = inet_addr(pcAddr);
      return 1;
    }
  }
  return 0;
}

void Close(int fdWrite, int fdRead)
{
    close(fdRead);
    if(fdRead != fdWrite)
        close(fdWrite);
} // End: Close()

int pass(int fdWrite, int fdRead)
{
  fd_set fsRead, fsWrite, fsExcept;
  int nMaxFH = fdWrite;
  if(fdRead > fdWrite)
    nMaxFH = fdRead;
  nMaxFH++;

  char cReadSock[BUF_LEN], cReadIn[BUF_LEN];
  int  nReadSockInd = 0, nReadInInd = 0;
  while(1)
  {
    FD_ZERO(&fsRead);
    FD_ZERO(&fsWrite);
    FD_ZERO(&fsExcept);
    FD_SET(0, &fsExcept);
    FD_SET(1, &fsExcept);
    FD_SET(fdRead, &fsExcept);
    FD_SET(fdWrite, &fsExcept);

    if(nReadInInd == 0)
      FD_SET(0, &fsRead);
    else
      FD_SET(fdWrite, &fsWrite);

    if(nReadSockInd == 0)
      FD_SET(fdRead, &fsRead);
    else
      FD_SET(1, &fsWrite);

    int nRet = select(nMaxFH, &fsRead, &fsWrite, &fsExcept, NULL);
    if(nRet == -1)
    {
      Close(fdRead, fdWrite);
      printf("Select error.\n");
      return 0;
    }
    
    if(FD_ISSET(1, &fsExcept) || FD_ISSET(fdRead, &fsExcept)
	|| FD_ISSET(fdWrite, &fsExcept))
    {
      Close(fdRead, fdWrite);
      return 0;
    }
    if(FD_ISSET(0, &fsRead) && !nReadInInd)
    {
      nReadInInd = read(0, cReadIn, BUF_LEN);
      if(nReadInInd < 1)
      {
	Close(fdRead, fdWrite);
        return 0;
      }
    }
    if(FD_ISSET(fdRead, &fsRead) && !nReadSockInd)
    {
      nReadSockInd = read(fdRead, cReadSock, BUF_LEN);
      if(nReadSockInd < 1)
      {
         Close(fdRead, fdWrite);
         return 0;
      }
    }

    if(FD_ISSET(1, &fsWrite) && nReadSockInd)
    {
      int nWrote = write(1, cReadSock, nReadSockInd);
      if(nWrote == -1)
        return 5;
      if(nWrote != nReadSockInd)
        memmove(cReadSock, &cReadSock[nWrote], nReadSockInd - nWrote);
      nReadSockInd = 0;
    }
    if(FD_ISSET(fdWrite, &fsWrite) && nReadInInd)
    {
      int nWrote = write(fdWrite, cReadIn, nReadInInd);
      if(nWrote == -1)
        return 5;
      if(nWrote != nReadInInd)
        memmove(cReadIn, &cReadIn[nWrote], nReadInInd - nWrote);
      nReadInInd = 0;
    }
  }
  return 0;
}

