/*---------------------------------------------------------------------------------------------------------------------------------------------------
Program Listing for:  MySocket.cpp
Project:  socketclass
Namespace:  c++
----------------------------------------------------------------------------------------------------------------------------------------------------
*/

// MySocket.cpp: implementation of the CMySocket class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "securesock.h"
#include "MySocket.h"
#include <windows.h>
#include <winspool.h>
#include <string.h>
#include <stdio.h>
#include <mapi.h>
#include <malloc.h>
#include <winsock.h>
#include "Slot.h"
#include "MiscStuff1.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
int CMySocket::wsa_inited = 0;
char nothing[2];
volatile bool g_inconnect = false;

CMySocket::CMySocket()
{
         out_string = NULL;
         s = 0;
         bFinished = 0;
         bError = 0;
         outbuf = (char *)malloc(200);
         sockinit();

}

CMySocket::CMySocket(char *cserver, unsigned int nport)
{
         out_string = NULL;
         s = 0;
         bFinished = 0;
         bError = 0;
         outbuf = (char *)malloc(200);
         sockinit();
         sockconnect(cserver, nport);

}

CMySocket::~CMySocket()
{

         sockclose();
         if (outbuf) {            
                  free(outbuf);
                  outbuf = NULL;
         }
         if (out_string) {
                  free(out_string);
                  out_string = NULL;
         }

}

char *CMySocket::sockclose()
{

         if (outbuf) {            
                  free(outbuf);
                  outbuf = NULL;
         }
         outbuf = (char *)malloc(200);
         if (s) {

                  if (closesocket(s)) {
                           strcpy(outbuf, "Error with socket close.");
                           return (outbuf); 
                  } else {
                           //s = 0;
                           strcpy(outbuf, "  ");
                           return (outbuf);
                  }
         } else {
                  strcpy(outbuf, "invalid socket.");
                  return (outbuf);

         }
}

char *CMySocket::sockinit(void) {

         if (! wsa_inited) {

                  if (outbuf) {            
                           free(outbuf);
                           outbuf = NULL;
                  }

                  outbuf = (char *)malloc(200);

                  // using winsock 2.0
                  if (WSAStartup(MAKEWORD(2, 0), &wsaData)) {
                           strcpy(outbuf, "Trouble starting winsock");
                           return (outbuf);
                  }
                  wsa_inited = 1;

         }
         strcpy(outbuf, "  ");
         return (outbuf);

}

// for email use SMTP:user@site.com
char *CMySocket::sockconnect(char *in_string, int port)
{


         struct sockaddr_in a;
         struct hostent *h;

         if (outbuf) {            
                  free(outbuf);
                  outbuf = NULL;
         }
         if (out_string) {
                  free(out_string);
                  out_string = NULL;
         }

         outbuf = (char *)malloc(200);

         // I use g_inconnect as a sort of semaphore since connecting seems to block on the machine level
         // causing connect fails when two threads hit this function at once, so if another thread hits and
         // the first thread is still connecting, I make it wait
         while (g_inconnect) {
                  TRACE("waiting on socket");
         }

         g_inconnect = true;

         h = gethostbyname(in_string);
         if (h==NULL) {

           // try connecting to IP string if failure to connect to NAME
           int uPeer[4] ;
           uPeer[3] = uPeer[2] = uPeer[1] = uPeer[0] = 0;

      sscanf ( in_string, "%d.%d.%d.%d",
             &uPeer[0], &uPeer[1], &uPeer[2], &uPeer[3] ) ;

                    // move it into a char array for ::gethostbyaddr()
                    char cPeer[4] ;
                    cPeer[0] = uPeer[0] ;
                    cPeer[1] = uPeer[1] ;
                    cPeer[2] = uPeer[2] ;
                    cPeer[3] = uPeer[3] ;
                    char test_string[255];
                    sprintf(test_string, "%d.%d.%d.%d",  uPeer[0], uPeer[1], uPeer[2], uPeer[3] ) ;

                    //MessageBox(NULL, in_string, "", 0);
                    //MessageBox(NULL, test_string, "", 0);

   
                           // test see if it connects for a string of type "63.230.230.145"
                    h = ::gethostbyaddr( cPeer,
                                    4,
                                    PF_INET);
                      

                  if (h==NULL) {

                           //WSACleanup();
                           strcpy(outbuf, "both failed: 234 Trouble connecting: bad URL");
                           ::MessageBox(NULL, outbuf, NULL, MB_OK);
                           bError = 1;
                           g_inconnect = false;

                           return (outbuf);
                  }
         }
         

         a.sin_family = AF_INET;
         a.sin_port = htons(port);
         //a.sin_addr.s_addr = inet_addr(in_string);

         memcpy( &(a.sin_addr.s_addr), h->h_addr, sizeof(int));

         s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
         if (s==0) {
                  //WSACleanup();
                  strcpy(outbuf, "MySocket class error: Trouble creating socket");
                  ::MessageBox(NULL, outbuf, NULL, MB_OK);
                  g_inconnect = false;
                  return (outbuf);

         }
         if (connect(s, (struct sockaddr *)&a, sizeof(a))) {

                  //WSACleanup();
                  strcpy(outbuf, "1:Trouble with socket: connecting");
                  //::MessageBox(NULL, outbuf, NULL, MB_OK);
                  bError = 1;
                  g_inconnect = false;
                  return (outbuf);

         }

         u_long utemp = 1;

         if (ioctlsocket (s, FIONBIO, &utemp)) {

                  strcpy(outbuf, "MySocket class error: Trouble setting non-blocking");
                  ::MessageBox(NULL, outbuf, NULL, MB_OK);
                  bError = 1;
                  g_inconnect = false;
                  return (outbuf);
                  
         } 

         g_inconnect = false;

         strcpy(outbuf, "  ");
         return (outbuf);

}

// for email use SMTP:user@site.com
char *CMySocket::sockconnectasync(char *in_string, int port, HWND hwind, long flags, unsigned int nmsg)
{

         struct sockaddr_in a;
         struct hostent *h;

         int nret;

         if (outbuf) {            
                  free(outbuf);
                  outbuf = NULL;
         }
         if (out_string) {
                  free(out_string);
                  out_string = NULL;
         }

         outbuf = (char *)malloc(200);
         
         h = gethostbyname(in_string);
         if (h==NULL) {

           // try connecting to IP string if failure to connect to NAME
           int uPeer[4] ;
           uPeer[3] = uPeer[2] = uPeer[1] = uPeer[0] = 0;

      sscanf ( in_string, "%d.%d.%d.%d",
             &uPeer[0], &uPeer[1], &uPeer[2], &uPeer[3] ) ;

                    // move it into a char array for ::gethostbyaddr()
                    char cPeer[4] ;
                    cPeer[0] = uPeer[0] ;
                    cPeer[1] = uPeer[1] ;
                    cPeer[2] = uPeer[2] ;
                    cPeer[3] = uPeer[3] ;
                    char test_string[255];
                    sprintf(test_string, "%d.%d.%d.%d",  uPeer[0], uPeer[1], uPeer[2], uPeer[3] ) ;

                    MessageBox(NULL, in_string, "", 0);

                    MessageBox(NULL, test_string, "", 0);

   
                           // test see if it connects for a string of type "63.230.230.145"
                    h = ::gethostbyaddr( cPeer,
                                    4,
                                    PF_INET);
                      

                  if (h==NULL) {

                           //WSACleanup();
                           strcpy(outbuf, "both failed: 234 Trouble connecting: bad URL");
                           return (outbuf);
                  }
         }
         

         a.sin_family = AF_INET;
         a.sin_port = htons(port);
         //a.sin_addr.s_addr = inet_addr(in_string);

         memcpy( &(a.sin_addr.s_addr), h->h_addr, sizeof(int));

         s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
         if (s==0) {
                  //WSACleanup();
                  strcpy(outbuf, "Trouble creating socket.");
                  return (outbuf);

         }
         nret = WSAAsyncSelect(s, hwind, nmsg, flags);

         if (nret == SOCKET_ERROR) {

                  return (strcpy(outbuf, "Trouble with socket: Select function"));

         }

         nret = connect(s, (struct sockaddr *)&a, sizeof(a));
         if ( nret == SOCKET_ERROR) {

                  int lasterr = WSAGetLastError();

                  if (lasterr == WSAEWOULDBLOCK) {

                           //MessageBox(NULL,"blocking message", "", 0);
                           // blocking message is okay for now, since sometime a good connect returns this
                           // code for some reason, more testing required

                  } else {
                           
                           sprintf(outbuf, "Trouble with socket, connecting.\nError No:%d", lasterr);
                           return ( outbuf );

                  }

                  // WSACleanup();
                  // strcpy(outbuf, "2:Trouble with socket: connecting");

                  // return (outbuf);

         }

         u_long utemp = 1;

         /*
         if (ioctlsocket (s, FIONBIO, &utemp)) {

                  strcpy(outbuf, "Trouble setting non-blocking");
                  return (outbuf);
                  
         } */

         strcpy(outbuf, "");
         return (outbuf);

}

char *CMySocket::sockreceive()
{

         int back, back2;
         nothing[0] = (char)0;

         if (bFinished) {
                  ::MessageBox(NULL, "error:receive called on closed socket", NULL, MB_OK);
                  return nothing;
         }

         /*
         fd_set stReadFDS;
         FD_ZERO(&stReadFDS);
         FD_SET(s, &stReadFDS);

         struct timeval stTimeOut;
         stTimeOut.tv_sec = 0;
         stTimeOut.tv_usec = 0;

         int nselect = select(-1, &stReadFDS, NULL, NULL, &stTimeOut);

         if (nselect == SOCKET_ERROR) {
                  ::MessageBox(NULL, "error on call to select", NULL, MB_OK);
                  bError = 1;
                  return nothing;
         }

         bool bReadSet;

         bReadSet = ! (FD_ISSET(s, &stReadFDS) == 0);
         */

         /*
         if (! bReadSet )
                  return out_string; */

         myout[0] = (char)0;

         back2 = recv(s, myout, 1000, MSG_PEEK);
         back = recv(s, myout, 1000, 0);

         if (back2 > 0) {

                  //MessageBox(NULL, myout, "", 0);
                  //strncpy(out_string , myout, back);
                  //out_string[back] = (char)0;
                  myout[back] = (char)0;

         }

         // this sometimes happens when the socket isn't ready to receive yet (I think) but in that case
         // we just keep looping in getfileasstring (timeout will eventually show connection to be bad if
         // the socket never goes into a good receive mode).  this whole thing fixes an exotic error
         if (back2 == -1) {
                  //strcpy(out_string, "0: -1");
                  //::MessageBox(NULL, "socket receive error, code = -1", NULL, MB_OK);
                  //bFinished = 1;
         }

         if (back2 == 0) {
                  //strcpy(out_string, "0: 0");
                  //if (bReadSet)
                  //         bFinished = 1;
         }

         /*
         if (back2 == SOCKET_ERROR) {
                  strcpy(out_string, "0: SOCKET_ERROR with receive unknown type");
                  TRACE("error code: %i", back);
                  ::MessageBox(NULL, out_string, NULL, MB_OK);
                  bFinished = 1;
         } */


         return myout;


}

void CMySocket::GetFileAsString(char *file_name, char *host_name, CString *ret_string)
{

         CString string;
         CString reply_string;
         TRACE("entering getfileasstring\n");
         if (bError) {
                  TRACE("leaving getfileasstring\n");
                  *ret_string = "";
                  return;
         }
         string.Format("GET %s HTTP/1.1\r\nHost: %s\r\n\r\n", file_name, host_name);
         socksend(string.GetBuffer(0));
         //Sleep(100);
         if ( ::stopping_threads() ) {
                  bError = true;
                  goto end;
         }
         //Sleep(100);
         double xx;
         double xy;
         unsigned long yy;
         xx = CMiscStuff::GetSeconds();

         if (! bError) {
         
                  int cnt =2;
                  //double x1, x2;
                  MSG message;
                  int n;
                  while (1) {

                           if ( ::stopping_threads() ) {
                                    bError = true;
                                    break;
                           }

                           /*
                           for (n=0;n<1000;n++) {
                                    if (::PeekMessage(&message, NULL, 0, 0, PM_REMOVE)) {
                                             ::TranslateMessage(&message);
                                             ::DispatchMessage(&message); 
                                    } 
                           } */
                           Sleep(20);

                           char *response = sockreceive();
                           if ( response && strlen(response) > 0) {
                                    reply_string += response;
                                    xx = CMiscStuff::GetSeconds();
                                    if ( strchr(response, '^') ) {
                                             TRACE("normal socket finish\n");
                                             bFinished = 1;
                                    }
                           }

                           if (bFinished || bError)
                                    break;

                           xy = CMiscStuff::GetSeconds();
                           yy = (unsigned long)(xy - xx);

                           // 5 seconds of inactivity mean probable disconnect or failure of some kind
                           // a normal end will have a caret "^" as a normal end of message indicator
                           if (yy > 10L) {
                                    //bFinished = 1;
                                    bError = true;
                                    TRACE("five second time out reached, aborting receive\n");
                                    break;
                           }

                  }
                  //CString count;
                  //count.Format("%i tries", cnt);
                  //AfxMessageBox(count);

         } else 
                  reply_string = "";
         
end:
         TRACE("leaving getfileasstring\n");
         *ret_string = reply_string;
         return;

}

char *CMySocket::socksend(char *in_string)
{

         int nsize;
         nsize = strlen(in_string);
         if (bFinished) {
                  ::MessageBox(NULL, "error:send called on closed socket", NULL, MB_OK);
                  return "";
         }

         if (outbuf) {            
                  free(outbuf);
                  outbuf = NULL;
         }

         outbuf = (char *)malloc(200);

         if (send(s, in_string, nsize, 0) == SOCKET_ERROR) {
                  //WSACleanup();
                  strcpy(outbuf, "Trouble with socket: connecting");
                  ::MessageBox(NULL, outbuf, NULL, MB_OK);
                  bError = 1;
                  return (outbuf);

         }

         strcpy(outbuf, "  ");
         return (outbuf);

}


int CMySocket::sockcleanup(void)
{

         if (out_string) {
                  free(out_string);
                  out_string = NULL;
         }
         if (outbuf) {            
                  free(outbuf);
                  outbuf = NULL;
         }
         // we may or may not want to close socket library, and sometimes this also
         // causes GPF's.
         //WSACleanup();
         return 1;

}

void CMySocket::sockwsacleanup(void)
{

         WSACleanup();

}


// for email use SMTP:user@site.com
char *CMySocket::gettextback(char *in_string, int nsleep)
{


         struct sockaddr_in a;
         struct hostent *h;
         WSADATA wsaData;

         if (outbuf) {            
                  free(outbuf);
         }
         if (out_string) {
                  free(out_string);
                  out_string = NULL;
         }

         outbuf = (char *)malloc(200);
         

         if (WSAStartup(0x101, &wsaData)) {
                  strcpy(outbuf, "Trouble starting winsock");
                  return (outbuf);
         }

         h = gethostbyname("www.sboe.state.az.us");
         if (h==NULL) {
                  WSACleanup();
                  strcpy(outbuf, "Trouble connecting");
                  return (outbuf);
         }

         a.sin_family = AF_INET;
         a.sin_port = htons(80);
         memcpy( &(a.sin_addr.s_addr), h->h_addr, sizeof(int));


         s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
         if (s==0) {
                  WSACleanup();
                  strcpy(outbuf, "Trouble creating socket");
                  return (outbuf);

         }
         if (connect(s, (struct sockaddr *)&a, sizeof(a))) {

                  WSACleanup();
                  strcpy(outbuf, "Trouble with socket: connecting");
                  return (outbuf);

         }
         
         int nsize;
         nsize = strlen(in_string);

         if (send(s, in_string, nsize, 0) == SOCKET_ERROR) {
                  WSACleanup();
                  strcpy(outbuf, "Trouble with socket: connecting");
                  return (outbuf);

         }

         if (out_string) {
                  free(out_string);
                  out_string = NULL;
         }
         char myout[1001];
         char *offset;
         offset = myout;
         int back;
         int back2;
         out_string = (char *)malloc(1001);

         Sleep(nsleep);

         back2 = recv(s, myout, 1000, MSG_PEEK);

         back = recv(s, myout, 1000, 0);

         /*
         sprintf(mout, "back:%i", back);
         MessageBox(NULL, mout, "", 0);


         sprintf(mout, "back2:%i", back2);
         MessageBox(NULL, mout, "", 0);


                  if (back2>0) {
                           myout[back2] = '\0';
                  }

                  MessageBox(NULL, myout, "", 0);

*/

                  //myout[back] = '\0';

                  if (back2 > 0) {

                           //MessageBox(NULL, myout, "", 0);
                           strncpy(out_string , myout, back);
                           out_string[back] = (char)0;

                  }
                  if (back == -1) {
                           strcpy(out_string, "0: -1");
                  }

                  if (back == 0) {
                           strcpy(out_string, "0: 0");
                  }

                  if (back == SOCKET_ERROR) {
                           strcpy(out_string, "0: SOCKET_ERROR");
                  }


         return out_string;


}


char *CMySocket::nextone(void)
{

         char myout[1001];
         int back2, back;

         if (out_string) {
                  free(out_string);
                  out_string = NULL;
         }
         out_string = (char *)malloc(1001);
         back2 = recv(s, myout, 1000, MSG_PEEK);

         back = recv(s, myout, 1000, 0);

/*
         sprintf(mout, "back:%i", back);
         MessageBox(NULL, mout, "", 0);


         sprintf(mout, "back2:%i", back2);
         MessageBox(NULL, mout, "", 0);

                  sprintf(mout, "back:%i", back);
                  MessageBox(NULL, mout, "", 0);

                  sprintf(mout, "back2:%i", back2);
                  MessageBox(NULL, mout, "", 0);

                  if (back2>0) {
                           myout[back2] = '\0';
                  }

                  MessageBox(NULL, myout, "", 0);

*/

                  //myout[back] = '\0';

                  if (back2 > 0) {

                           strncpy(out_string , myout, back);
                           out_string[back] = (char)0;

                  }
                  if (back2 == -1) {
                           strcpy(out_string, "0: -1");
                  }

                  if (back2 == 0) {
                           strcpy(out_string, "0: 0");
                  }

                  if (back2 == SOCKET_ERROR) {
                           strcpy(out_string, "0: SOCKET_ERROR");
                  }


         return out_string;


}

int CMySocket::cleanup(void)
{

         if (out_string) {
                  free(out_string);
                  out_string = NULL;
         }

         WSACleanup();
         return 1;

}