//
// Copyright(C) Simon Howard
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
// IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
//
// An incredibly simple terminal device, opens a raw connection to
// a host port
//

#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <errno.h>

#define BUFSIZE 1024

int main(int argc, char *argv[])
{
     struct hostent *hent;
     struct sockaddr_in sa;
     int port;
     int sock;

     if(argc < 3) {
	  fprintf(stderr,
		  "usage:\n"
		  "%s <host> <port>\n", argv[0]);
	  exit(-1);
     }

     {
	  struct servent *serv = getservbyname(argv[2], "tcp");

	  if(serv)
	       port = serv->s_port;
	  else
	       port = htons(atoi(argv[2]));
     }

     // resolve the destination address now before
     // we start waiting for connections

     if(!(hent = gethostbyname(argv[1]))) {
	  perror("cant resolve destination address");
	  exit(-1);
     }

     // create sockaddr

     memset(&sa,0,sizeof(sa));

     sa.sin_addr.s_addr = ((struct in_addr *) hent->h_addr)->s_addr;
     sa.sin_family = AF_INET;
     sa.sin_port = port;

     // create socket

     sock = socket(AF_INET, SOCK_STREAM, 0);

     if (sock < 0) {
	  fprintf(stderr, "cant create socket");
	  perror("main");
	  return;
     }

     // connect

     if (connect(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
	  fprintf(stderr, "cant connect\n");
	  perror("main");
     } else {

	  // reused code from minibnc

	  int input_sock = 0;
	  int output_sock = sock;

	  while(1) {
	       fd_set fd_list;

	       FD_ZERO(&fd_list);
	       FD_SET(input_sock, &fd_list);
	       FD_SET(output_sock, &fd_list);

	       select((input_sock > output_sock ? input_sock :
		       output_sock) + 1,
		      &fd_list,
		      NULL, NULL, NULL);

	       if(FD_ISSET(input_sock, &fd_list)) {
		    char readbuf[BUFSIZE];
		    int r;

		    // check for closed socket or error
		    if((r = read(input_sock, readbuf, BUFSIZE)) <= 0)  {
			 if(errno)
			      perror("from input_sock");
			 break;
		    }

		    readbuf[r] = 0;
		    write(output_sock, readbuf, r);
	       }

	       if(FD_ISSET(output_sock, &fd_list)) {
		    char readbuf[BUFSIZE];
		    int r;

		    // check for closed socket or error
		    if((r = read(output_sock, readbuf, BUFSIZE)) <= 0)  {
			 if(errno)
			      perror("from output_sock");

			 break;
		    }

		    write(1, readbuf, r);
	       }
	  }
     }

}
