#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <process.h>
#include <winsock.h>
#include <stdio.h>
#include <conio.h>


/*


*/

//Winsock Data block
WSADATA wi;
//Thread handles for the erm... threads?
UINT thrid_sock;
UINT thrid_console;
UINT thrid_error;
//Stdin/out handles
HANDLE stdinput;
HANDLE stdoutput;
HANDLE stderror;
// "Input" pipe for the console.
HANDLE readInput;
HANDLE writeInput;
// Console "Output" pipe.
HANDLE readOutput;
HANDLE writeOutput;
// Console stderr pipe.
HANDLE readError;
HANDLE writeError;
//Main "listen" socket.
sockaddr_in myaddr;
SOCKET sock;
//Telnet connection socket
SOCKET talk;
//"Share handles" security descriptor
SECURITY_ATTRIBUTES security = {
  sizeof(SECURITY_ATTRIBUTES),
  NULL,
  TRUE
};
//Console Process creation information
STARTUPINFO si = {
  sizeof(STARTUPINFO),
  NULL, NULL,
  "Remote Console",
  0,0,0,0,
  0,0,
  0,
  0,
  0,
  0,NULL,
  0,0,0
};
PROCESS_INFORMATION pi;


unsigned __stdcall run_sock(void*)
{
  char buffer[256];
  int read;
  DWORD writ;
  while( 0 < (read=recv(talk,buffer,256,0)))
    WriteFile( writeInput, buffer, read, &writ,NULL);

  return 0;
}

unsigned __stdcall run_console(void*)
{
  char buffer[256];
  DWORD read;
  DWORD writ;
  while(ReadFile(readOutput,buffer,256,&read,NULL))
    send(talk,buffer,read,0);

  return 0;
}

unsigned __stdcall run_error(void*)
{
  char buffer[256];
  DWORD read;
  DWORD writ;
  while(ReadFile(readError,buffer,256,&read,NULL))
    send(talk,buffer,read,0);

  return 0;
}


int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{
  // Startup Winsock
  int err = WSAStartup(0x0101,&wi);

  printf("WSAStatup returned %d\n\n", err);
  getch();

  // Create a Socket to connect to the remote doodaad...
  sock = socket(AF_INET,SOCK_STREAM,0);

  // Get our own name so we can get our IP...
  char hostname[40];
  gethostname(hostname,40);

  // Get our hostent info
  hostent* hent = gethostbyname(hostname);

  // Bind our address and the telnet port to the socket
  myaddr.sin_family = AF_INET;
  myaddr.sin_port = htons(23);
  myaddr.sin_addr.s_addr = *(DWORD*)hent->h_addr_list[0];
  if( bind(sock,(sockaddr*)&myaddr,sizeof(sockaddr)))
    return 1;

  // Listen for an incomming connections...
  listen(sock,1);

//*** Loop around here, creating new sockets on every new accept!

  // accept an incoming?
  talk = accept(sock,NULL,NULL);

  // Make a console for us to talk with...
  AllocConsole();

  // Save the "Standard" handles.
  stdinput = GetStdHandle(STD_INPUT_HANDLE);
  stdoutput = GetStdHandle(STD_OUTPUT_HANDLE);
  stderror = GetStdHandle(STD_ERROR_HANDLE);

  // Create the "Input" pipe for the console to get stuff from us
  CreatePipe(&readInput,&writeInput,&security,0);
  // Set the Default "Input" handle of the console to be this pipe
  SetStdHandle(STD_INPUT_HANDLE,readInput);

  // Create the console's "Output" pipe by which we get stuff back
  CreatePipe(&readOutput,&writeOutput,&security,0);
  // Set the "Output" handle to be this pipe.
  SetStdHandle(STD_OUTPUT_HANDLE,writeOutput);

  // Create the console's Error pipe
  CreatePipe(&readError,&writeError,&security,0);
  // Set the stderr handle to be our pipe.
  SetStdHandle(STD_ERROR_HANDLE,writeError);

  // Create a thread to handle socket input
  _beginthreadex(NULL,0,run_sock,NULL,0,&thrid_sock);

  // Create our thread to console input
  _beginthreadex(NULL,0,run_console,NULL,0,&thrid_console);

  // Create a thread to handle error input
  _beginthreadex(NULL,0,run_error,NULL,0,&thrid_error);

  // Create a test process...
  CreateProcess("C:\\WINDOWS\\COMMAND.COM",NULL,NULL,NULL,TRUE,0,NULL,NULL,&si,&pi);

  // make sure the process is dead!
  WaitForSingleObjectEx(pi.hProcess,INFINITE,FALSE);
 
  // We are done, kill the console.
  FreeConsole();

// *** Loop back and wait for another connect!
// (we are only allowed one console, so... we must wait for the current session end)

  //Cleanup the socket layer
  WSACleanup();

  return 0;
}
