/**************************************************/
/* scol v 4                                       */
/*                                                */
/* inet.cpp                                       */
/*                                                */
/* scol inet, windows part                        */
/*                                                */
/* Loïc Berthelot, CryoNetworks, mars 2002        */
/**************************************************/


//
// Modifications History
//
//$LB (21/02/2002) : add threaded version of INETisConnected function
//
//$LB (03/04/2002) : corrected rflINETisConnected function
//



#include <windows.h>
#include <wininet.h>



extern "C"
{
#include "scol.h"
#include "common/kernel.h"
#include "mainscol.h"
#include "vm/mbytec.h"
#include "OS_specific/windows/winscol.h"

}


//#include "../../kernel/include/inet.h"
#include "common/inetconnect.h"







int ObjInetConnectType;
int ObjInetConnectHandle = 0;





int InetConnectDestroy(mmachine m, int handsys, int mobj)
{
	return 0;
}




















/*******************************************************************************************************************************/
/*******************************************************************************************************************************/
/**                                                                                                                           **/
/**             INETisConnected, synchronous version                                                                          **/
/**                                                                                                                           **/
/*******************************************************************************************************************************/
/*******************************************************************************************************************************/





//$ LB (17/07/2001) : add SCINETisConnected function
/*************************************************/
/*                                               */
/* int INETisConnected (char* url)               */
/*                                               */
/* returns 1 if physically connected to the net, */
/* 0 if not.                                     */
/* the parameter is the url on which the user    */
/* wants to test the connexion.                  */
/*                                               */
/*************************************************/
int INETisConnected (char* url)
{
HINTERNET hNet;
HINTERNET hUrl;
LPDWORD lpdwFlags = NULL;




	// open internet session
	if (HTTPproxy[0] == '\0') 
		hNet = InternetOpen ("SCOL INETisConnected", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
	else if (!strcmp (HTTPproxy, "no")) 
		hNet = InternetOpen("SCOL INETisConnected", INTERNET_OPEN_TYPE_DIRECT, NULL,NULL, 0);
	else hNet = InternetOpen("SCOL INETisConnected", INTERNET_OPEN_TYPE_PROXY, HTTPproxy, NULL, 0);


    if (!hNet)
	{ InternetCloseHandle (hNet); return 0; }


	// check the system connexion state
	if (!InternetGetConnectedState (lpdwFlags, 0))
	{	InternetCloseHandle (hNet);	return 0; }


	// check the connexion, physically speaking...
	if (!(hUrl = InternetOpenUrl (hNet, url, NULL, 0, 0, 0)))
	{
     	InternetCloseHandle (hUrl);
		InternetCloseHandle (hNet);
		return 0;
	}



	InternetCloseHandle (hUrl);
	InternetCloseHandle (hNet);
	return 1;
}













/*************************************************/
/*                                               */
/* int SCINETisConnected (mmachine m)            */
/*                                               */
/* scol interface of INETisConnected             */
/*                                               */
/* returns 1 if physically connected to the net, */
/* 0 if not.                                     */
/* the parameter is the url on which the user    */
/* wants to test the connexion.                  */
/*                                               */
/* fun [S] I                                     */
/*************************************************/
int SCINETisConnected (mmachine m)
{
int murl;
char* url;

	murl = MMpull (m)>>1;
	url = (murl == NIL) ? NULL : MMstartstr (m, murl);

	if (url == NULL)
	{
		MMechostr (MSKFOO, "INETisConnected url NULL\n");
		return MMpush(m,NIL);
	}

	return MMpush (m, (INETisConnected (url))<<1);
}












/*******************************************************************************************************************************/
/*******************************************************************************************************************************/
/**                                                                                                                           **/
/**             _rflINETisConnected, threaded version of INETisConnected                                                      **/
/**                                                                                                                           **/
/*******************************************************************************************************************************/
/*******************************************************************************************************************************/









/****************************************/
/*                                      */
/* RflInetIsConnectedData_t             */
/*                                      */
/* define the set of data needed to     */
/* manage the threaded version of       */
/* INETisConnected function             */
/*                                      */
/****************************************/
//
// defined in inetconnect.h
//
/*
typedef struct RflInetIsConnectedData_t
{
	mmachine machine;         
	int      handle;
	
} RflInetIsConnectedData_t;
*/





/********************************************************/
/*                                                      */
/* int SCrflINETisConnected_TerminateProcess            */
/*                                                      */
/* called by receiving a WN_USER message, with          */
/* RFL_INET_IS_CONNECTED_MSG as parameter.              */
/* execute the scol callback of _rflINETisConnected.    */
/*                                                      */
/********************************************************/

int SCrflINETisConnected_TerminateProcess (RflInetIsConnectedData_t * data)
{
  mmachine m = data->machine;
  int mobj, spobj, mscolobj, spscolobj , k;
  
  //$BB lock GC since the thread change the scol stack
  m->lckdGC = 1;

	// retreive the object
	if ((mobj=OBJfindTH(m, ObjInetConnectType, data->handle))==NIL)
		{ if (data) free (data); return 0; }

	if (MMpush (m, mobj))                           return MERRMEM;
	spobj = MMgetPP(m);


	// retreive the INETCONNECT object
	if ((mscolobj = MMfetch(m, MMgetbase(m, spobj, 0), OFFOBJMAG)>>1)==NIL) 
		{ if (data) free (data); return 0; }


	if (MMpush (m, mscolobj))                       return MERRMEM;
	spscolobj = MMgetPP(m);





	//$LB
	// here is an equivalent to the OBJbeginreflex function.
	// we decided no to use OBJbeginreflex directly, because it pushes the scol object in the stack
	// in order to be given as the first parameter of the scol callback.
	// We decided that INETCONNECT objects are for internal use only, so the user doesn't have 
	// to manipulate it in the scol callback.
	// Then, the code is the same as in OBJbeginreflex and OBJcallreflex, but we push the tested url instead of 
	// pushing the scol object, as the first parameter of the scol callback.




    /**************************************************************************/
	/*                                                                        */
	/* equivalent OBJbeginreflex                                              */
	/*                                                                        */
    /**************************************************************************/

	// is there a callback assigned to the object?
    if (MMfetch(m, MMgetbase(m, spobj, 0), OFFOBJREF0 + INETCONNECT_RFL_RESULT*2)==NIL)
	{ if (data) free (data); return 0;}




  /**************************************************************************/
	/*                                                                        */
	/* equivalent OBJpreparereflex                                            */
	/*                                                                        */
  /**************************************************************************/

	// set the current channel 
	MMsetglobal(m, OFFSCCUR, MMfetch(m, MMgetbase(m, spobj, 0), OFFOBJCHN));
	// push it 
	if (MMpush (m, MMgetglobal (m, OFFSCCUR)))                                  return MERRMEM;

	// push the callback pointer
	if (MMpush (m, MMfetch (m, MMgetbase(m, spobj, 0), OFFOBJREF0 + INETCONNECT_RFL_RESULT*2)))   return MERRMEM;

	// push the tested url instead of pushing the object !!!
	if (MMpush (m, MMfetch (m, MMgetbase(m, spscolobj, 0), OBJINETCONNECT_URL)))                                              return MERRMEM;

	// and push the user parameter
	if (MMpush (m, MMfetch (m, MMgetbase(m, spobj, 0), OFFOBJREF0 + INETCONNECT_RFL_RESULT*2+1))) return MERRMEM;


	//
	// before OBJcallreflex,
	//
	// push the last parameter : result of the inet test
	if ((MMpush(m, MMfetch (m, MMgetbase(m, spscolobj, 0), OBJINETCONNECT_RESULT))))                  return MERRMEM;
	// suppr the object (we don't need it anymore)
    OBJdelTH(m, ObjInetConnectType, data->handle);



	if ((k=OBJcallreflex(m,1))) return k;


	// pull the 2 stack pointers pushed in the begining
	MMpull(m); MMpull(m);

	if (data) free (data);

  //$BB unlock GC
  m->lckdGC = 0;

	return 0;	
}






/********************************************************/
/*                                                      */
/* DWORD WINAPI SCrflINETisConnected_LaunchProcess      */
/*                                                      */
/* threaded function                                    */
/*                                                      */
/* execute the INETisConnected test inside a thread     */
/* and post a Windows message to make the father thread */
/* execute the scol callback.                           */
/*                                                      */
/********************************************************/

DWORD WINAPI SCrflINETisConnected_LaunchProcess (RflInetIsConnectedData_t * data)
{
int mobj, murl, result;
int k;
char* url;
mmachine m = data->machine;


	// retreive the INETCONNECT object
	if ( ((mobj=OBJfindTH(m, ObjInetConnectType, data->handle))==NIL) ||
		((mobj=MMfetch(m,mobj,OFFOBJMAG)>>1)==NIL) )

	{
	   if (data) free (data);
	   ExitThread(0);
	   return 0;
	}

	// get the url to test from the object
    murl = MMfetch (m, mobj, OBJINETCONNECT_URL)>>1;
	url = (murl == NIL) ? NULL : MMstartstr (m, murl);

	if (url == NULL)
	{
	   if (data) free (data);
	   ExitThread(0);
	   return 0;
	}



	// test net connection
	result = INETisConnected (url);


	// retreive the INETCONNECT object to store the result.
	// we're in a thread ==> a gc could have been launched since the last time we retreived it...
	if ( ((mobj=OBJfindTH(m, ObjInetConnectType, data->handle))==NIL) ||
		((mobj=MMfetch(m,mobj,OFFOBJMAG)>>1)==NIL) )

	{
	   if (data) free (data);
	   ExitThread(0);
	   return 0;
	}


	// store the result of the test
	MMstore (m, mobj, OBJINETCONNECT_RESULT, result<<1);


	// Post a message to terminate the process, giving the data struct as parameter
	k = PostMessage( hscol, WM_USER, RFL_INET_IS_CONNECTED_MSG, (LONG)data);


	// exit thread
	ExitThread(0);
	return 0;	
}








//$LB (21/02/2002) : add threaded version of INETisConnected function
/*************************************************/
/*                                               */
/* int SCrflINETisConnected (mmachine m)         */
/*                                               */
/* create a thread and run INETisConnected in it.*/
/* the result of INETisConnected is returned in  */
/* using the callback pointer the user gave as   */
/* parameter.                                    */
/* the result is 1 if physically connected to    */
/* the net, 0 if not.                            */
/*                                               */
/* fun [S fun [S u0 I] u1 u0] I                  */
/*                                               */
/* parameters :                                  */
/*   - S : url on which the user wants to test   */
/*         the connexion.                        */
/*                                               */
/*   - fun [S u0 I] u1 : callback to check the   */
/*                       result of the test.     */
/*                       - S  : url tested       */
/*                       - u0 : user parameter   */
/*                       - I  : test result      */
/*                                               */
/*   - u0 : user parameter                       */
/*                                               */
/*************************************************/

int SCrflINETisConnected (mmachine m)
{
RflInetIsConnectedData_t * data;
int murl, mcbk, muserparam, k;
char* url;
DWORD dwThreadId;


	muserparam = MMget(m, 0);
	mcbk       = MMget(m, 1);
	murl       = MMget(m, 2);

	url = (murl == NIL) ? NULL : MMstartstr (m, murl>>1);


	if (url == NULL)
	{
		MMechostr (MSKFOO, "_rflINETisConnected url NULL\n");
		SEDROP(m, 2);
		MMset(m, 0, NIL);
		return 0;
	}

	if (mcbk == NIL)
	{
		MMechostr (MSKFOO, "_rflINETisConnected  : a callback has to be assigned!\n");
		SEDROP(m, 2);
		MMset(m, 0, NIL);
		return 0;

	}



	// INETCONNECT object creation
	ObjInetConnectHandle++;
    if ((k = MMpush (m, MMgetglobal (m, OFFSCCUR)))) return k; /* current channel                */
	if ((k = MMpush (m, MMget(m, 3))))						 return k; /* url                            */
	if ((k = MMpush(m, 0)))                          return k; /* result of INETisConnected test */
	if ((k = MMpush(m, OBJINETCONNECT_SIZE<<1)))     return k; /* size of INETCONNECT object     */
	if ((k = MBdeftab(m)))                           return k;
	if ((k = OBJcreate(m, ObjInetConnectType, ObjInetConnectHandle, NIL, NIL))) return k;

	/* add reflex */
	if ((k = MMpush(m, MMget(m, 2))))                      return k;  /* mcbk */
	if ((k = MMpush(m, MMget(m, 2))))                return k; /* muserparam */
	if ((k = OBJaddreflex(m, ObjInetConnectType, INETCONNECT_RFL_RESULT))) return k;


	// pull the object created, 'cause it's for an internal use only...
	MMpull(m);



	// alloc memory to store informations for the thread
	data = (RflInetIsConnectedData_t *) malloc (sizeof (RflInetIsConnectedData_t));
	// store values
	data->machine = m;
	data->handle = ObjInetConnectHandle;



	// Launch Thread, giving data as parameter
	
	if (CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) SCrflINETisConnected_LaunchProcess, 
			data, 0, &dwThreadId) == NULL) 
	{
		MMechostr (MSKFOO, "thread error\n");
		SEDROP(m, 2);
		MMset (m, 0, NIL);
		return 0;
	}
	


	SEDROP(m,2);
	MMset(m,0,0);
	return 0;
}


















/*******************************************************************************************************************************/
/*******************************************************************************************************************************/
/**                                                                                                                           **/
/**             package definition                                                                                            **/
/**                                                                                                                           **/
/*******************************************************************************************************************************/
/*******************************************************************************************************************************/





//$ LB (17/07/2001) : add INETisConnected function
//$LB (21/02/2002) : add _rflINETisConnected function
#define INETCONNECT_PKG_NB 2

char* INETCONNECT_name[INETCONNECT_PKG_NB]={
		"INETisConnected", "_rflINETisConnected"
};

int (*INETCONNECT_fun[INETCONNECT_PKG_NB])(mmachine m)={
		SCINETisConnected, SCrflINETisConnected
};

int INETCONNECT_narg[INETCONNECT_PKG_NB]={
		1, 3
};

char* INETCONNECT_type[INETCONNECT_PKG_NB]={
		"fun [S] I", "fun [S fun [S u0 I] u1 u0] I"
};




extern "C"
{

int SCOLloadINETCONNECT (mmachine m)
{
	//$LB (05/03/02) : add the INETCONNECT type for a internal use.
	//                  usefull to manage the threaded version of INETisConnected function (_rflINETisConnected)
	ObjInetConnectType = OBJregister(INETCONNECT_RFL_NB, 0, InetConnectDestroy, "INETCONNECT");
	
	return PKhardpak(m, "INETCONNECT.pkg", INETCONNECT_PKG_NB, INETCONNECT_name, INETCONNECT_fun, INETCONNECT_narg, INETCONNECT_type);
}

}


