//
// File: inet.c
// Modification history:
//$ FA(06/06/2001): Includes baselib.h
//
//$ LB(21/06/2001): modify DINETGetUrlEx function : replaced old socks4 protocol by SOCKSconnect function call
//
//$ LB(22/08/2001): add DINETGetURLex2 function
//
//$LB (13/11/2001) : add the field Killed in the objinet, in order to correct the bug dealing with the close of the sockets, with win 2000 and xp
//
//$LB (21/02/2002) : add _rflINETisConnected scol function declaration
//
//$LB (22/05/2002) : has corrected the error code management in the ScolInetEvent callback
//

#define INET_C
#include "../include/vscol.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef VERSION_WIN
#include <windows.h>
#include <windowsx.h>
#include <winsock.h>
#include <wininet.h>
#include <io.h>
#include <direct.h>
#endif
#if defined(VERSION_X11) || defined(VERSION_NOX)
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#endif
#include "../include/kernel.h"
#include "../scolobj.h"
#include "../mainscol.h"
#include "../baselib.h"
#include "inet.h"

#include "../include/socket.h"
//$ LB : usr socks 4 and 5 interface
#include "../include/socks.h"
//



//$ LB(19/07/2001) : add PROXYHTTP function
#include "../include/proxyhttp.h"



#ifdef VERSION_WIN
int WM_INET;
#endif


char bufproxy[256];

int ObjInetType;






int InetDestroy(mmachine m, int handsys, int mobj)
{
	//  MMechostr(MSKDEBUG,"INET: %d: closed\n",handsys);
		MMstore(m,mobj>>1,OBJINET_KILLED,1);
	return SCKclose(handsys);
}
















/****************************************************************/
/*                                                              */
/* int SCOLInetEvent(mmachine m,SOCKET sck,int event,int error) */
/*                                                              */
/* network events loop                                          */
/*                                                              */ 
/****************************************************************/
int SCOLInetEvent(mmachine m,SOCKET sck,int event,int error)
{
#define BUFFER_MAX 16384
	char buffer[BUFFER_MAX];
	char *req;
	char *inbuf;
	char *token;
	int k, mobj, ppmobj, size,sent,ip,port,flags,minbuf,len,leninbuf,ppinbuf;



	//MMechostr(MSKDEBUG,"\nEvent: #%d:%d %d(%d,%d,%d,%d)\n",sck,event,error,FD_WRITE,FD_READ,FD_CLOSE,FD_CONNECT);



	//-------------------------------------------------------------//
	//                                                             //
	// network errors management (including close events....)      //
	//                                                             //
	//-------------------------------------------------------------//
	if (error)
	{

		// get the obj inet from the socket number (<=> system handler of objinet)
		if ( ((mobj=OBJfindTH(m,ObjInetType,sck))==NIL) ||
			((mobj=MMfetch(m,mobj,OFFOBJMAG)>>1)==NIL) ) 	return 0;

		// proxy need authentication from client to authorize the request
		if ((MMfetch (m, mobj, OBJINET_AUTHENTICATION))>>1)
		{
			//MMechostr (MSKDEBUG, "socket %d : the request has to be authorized by the http proxy\n", sck);

			// reset authentication tag
			MMstore (m, mobj, OBJINET_AUTHENTICATION, 0);


			// get the original request
		    req = MMstartstr (m, MMfetch (m, mobj, OBJINET_REQUEST) >> 1);

			// if the request has already been authenticated but rejected
			if (PROXYHTTP_IsAuthorizationRejected (req))
			{
				//MMechostr (MSKDEBUG, "socket %d : authentication already present in request ==> authentication rejected, force the user to authenticate again\n", sck);

				// force the user to authenticate again
				if ((k = PROXYHTTP_AskAuthInfos (m, PROXYHTTP_SCOL_NETWORK_API, (int)sck, PROXYHTTP_FORCED_MODE)))
					return k;
			}

			// never been authenticated, but the auth. infos are present
			else if (PROXYHTTP_IsAuthorized())
			{
				//MMechostr (MSKDEBUG, "socket %d : already have authentication infos : call authorization procedure\n", sck);

				// make the authorization (<=> resend request with authentication field)
				if ((k = PROXYHTTP_Authorization (m, sck)))
					return k;
			}

			else 
			{
				//MMechostr (MSKDEBUG, "socket %d : need authentication infos : ask the main machine to get them\n", sck);

				// else, never been authenticated, and need the auth. infos => ask for user authentication
				if ((k = PROXYHTTP_AskAuthInfos (m, PROXYHTTP_SCOL_NETWORK_API, (int)sck, PROXYHTTP_NORMAL_MODE)))
					return k;
			}
		}
		else

		{

		//MMechostr(MSKDEBUG,"EndHTTP: #%d:%d %d(%d,%d,%d)\n",sck,event,error,FD_WRITE,FD_READ,FD_CLOSE);
	    //$LB (22/05/2002) : changed "error = -1" to "error == -1"
		if (   (OBJbeginreflex(m, ObjInetType, sck, INET_RFL_DATA)==0)  &&   (!((MMfetch (m, mobj, OBJINET_AUTHENTICATION))>>1))   )
		{
			if ((k=MMpush(m,NIL))) return k;
			if ((k=MMpush(m,((error == -1) ? 1 : 2)<<1))) return k;
			OBJdelTH(m,ObjInetType,sck);
			if ((k=OBJcallreflex(m,2))) return k;

		}
		//MMechostr(MSKDEBUG,"ErrorEnd: #%d:%d %d(%d,%d,%d)\n",sck,event,error,FD_WRITE,FD_READ,FD_CLOSE);
		return 0;

		}
	}

	//-----------------------------------------------------//
	//                                                     //
	//-----------------------------------------------------//
	






	// get the obj inet from the socket number (<=> system handler of objinet)
	if ( ((mobj=OBJfindTH(m,ObjInetType,sck))==NIL) ||
		((mobj=MMfetch(m,mobj,OFFOBJMAG)>>1)==NIL) ) 	return 0;
	
	// store it to avoid surprises from gc
	// !!  DON'T FORGET TO PULL IT FROM THE STACK BEFORE RETURN 0  !!
	if ((k=MMpush (m, (mobj<<1)+1))) return k;
	ppmobj = MMgetPP(m);
	mobj = MMgetbase (m, ppmobj, 0) >> 1;





	
	// get the objinet data (request, size, data sent, ... )
	req = MMstartstr (m, MMfetch (m, mobj, OBJINET_REQUEST) >>1 );
	size=MMsizestr(m,MMfetch(m,mobj,OBJINET_REQUEST)>>1);
	sent=MMfetch(m,mobj,OBJINET_REQPOS)>>1;
	flags=MMfetch(m,mobj,OBJINET_FLAGS)>>1;
	minbuf=MMfetch(m,mobj,OBJINET_INBUF)>>1;









    //--------------------------------------------------------------------------------//
	//                                                                                //
	// E V E N T      W R I T E                                                       //
	//                                                                                //
	// !!  DON'T FORGET TO PULL THE MOBJ POINTER FROM THE STACK BEFORE RETURN 0  !!   //
	//                                                                                //
	//--------------------------------------------------------------------------------//
	if (event == FD_WRITE)
	{

		k = SCKsend(sck, &(req[sent]), size-sent);

		if (k<0) { 	MMpull (m); SCOLInetEvent(m,sck,0,-1);  return 0; }
		sent+=k;

		//MMechostr(MSKDEBUG,"INET: #%d: sent %d/%d\n",sck,sent,size);
		MMstore(m,mobj,OBJINET_REQPOS,sent<<1);

		if (sent>=size) SCKclrwrite(sck);

	}
	//--------------------------------------//
	//                                      //
	//--------------------------------------//







    //--------------------------------------------------------------------------------//
	//                                                                                //
	// E V E N T     R E A D                                                          //
	//                                                                                //
	// !!  DON'T FORGET TO PULL THE MOBJ POINTER FROM THE STACK BEFORE RETURN 0  !!   //
	//                                                                                //
	//--------------------------------------------------------------------------------//
	else if (event==FD_READ)
	{

		len=SCKrecv(sck,buffer,BUFFER_MAX-1,&ip,&port);
		buffer[BUFFER_MAX-1]='\0'; /* just in case... */

		//$LB (22/05/2002) : there is no more data to read, the process is over : changed error code from (-2) to (-1)
		if (len<0) { MMpull(m); SCOLInetEvent(m,sck,0,-1); return 0; }
		buffer[len]=0;

		//MMechostr(MSKDEBUG,"INET-read %d\n",len);

		mobj = MMgetbase (m, ppmobj, 0)>>1;

		if ((!(flags&INET_HEADER))&&(minbuf!=NIL)&&(len!=0))
		{

			if ((k=MMpush(m, MMfetch(m, mobj, OBJINET_INBUF)))) return k;
			if ((k=Mpushstrblocn(m,buffer,len)))                return k;
			if ((k=MBstrcat(m)))                                return k;

			mobj = MMgetbase (m, ppmobj, 0)>>1;

			MMstore(m, mobj, OBJINET_INBUF, MMget(m,0));


			inbuf = MMstartstr(m, MMget(m,0)>>1);

			if ((token=strstr(inbuf,"\r\n\r\n")))
			{

				// $ LB (11 / 07 / 2001) : detect 407 HTTP Error
				if (PROXYHTTP_IsAuthenticated (inbuf, (token+4) - inbuf))
				{
					//MMechostr (MSKDEBUG, "socket %d : a 407 Http error is detected. Put a flag on to ask authentication\n", sck);

					// put '1' (1<<1 == 2) in the object, that will indicate the
					// proxy need authentication to process the request
					MMstore (m, mobj, OBJINET_AUTHENTICATION, 2);

				}

				else
				{
		
					leninbuf=MMsizestr(m,MMget(m,0)>>1);
					if ((k=MMpush(m,(token-inbuf+4)<<1))) return k;
					if ((k=MMpush(m,leninbuf<<1)))        return k;
					if ((k=MBsubstr(m)))                  return k;


					mobj = MMgetbase(m, ppmobj, 0)>>1;

					MMstore(m, mobj, OBJINET_INBUF, NIL);

					ppinbuf=MMgetPP(m);


					if ((OBJbeginreflex(m,ObjInetType,sck,INET_RFL_DATA)==0))
					{

						//MMechostr(MSKDEBUG,"FIRSTINET: %d: received %d bytes\n",sck,len);
						if	((k=MMpush(m,MMgetbase(m,ppinbuf,0)))) return k;
						if ((k=MMpush(m,0)))                       return k;
						if ((k=OBJcallreflex(m,2)))                return k;

					}

				}
			}

			MMpull(m);
			MMpull(m);
			MMpull(m);

			return 0;
		}


		if ((len!=0)&&(OBJbeginreflex(m,ObjInetType,sck,INET_RFL_DATA)==0))
		{
			//MMechostr(MSKDEBUG,"SECONDINET: %d: received %d bytes\n",sck,len);
			if ((k=Mpushstrblocn(m,buffer,len))) return k;
			if ((k=MMpush(m,0)))                 return k;
			if ((k=OBJcallreflex(m,2)))          return k;

		}


	}
	//-------------------------------------------//
	//                                           //
	//-------------------------------------------//
	







	//----------------------------------------------------------------------------------//
	//                                                                                  //
	// E V E N T     C L O S E                                                          //
	//                                                                                  //
	// !!  DON'T FORGET TO PULL THE MOBJ POINTER FROM THE STACK BEFORE RETURN 0  !!     // 
	//                                                                                  //
	//----------------------------------------------------------------------------------//
	else if (event==FD_CLOSE)
	{

		//MMechostr(MSKDEBUG,"INET-Close socket %d, call Read\n",sck);
		k=10;
		while(  (k)  &&  (MMfetch(m,MMget(m,0)>>1,OBJINET_KILLED)==0)  &&  (!((MMfetch (m, mobj, OBJINET_AUTHENTICATION))>>1)) )	// faire des lectures jusqu'à fermeture de la socket
		{
			SCOLInetEvent(m,sck,FD_READ,0);
			k--;													// au plus 10 fois
		}


		if ((k==0) ||  ((MMfetch (m, mobj, OBJINET_AUTHENTICATION))>>1)) SCOLInetEvent(m,sck,0,-2);						// ne devrait pas se produire (on ferme d'office en provoquant une erreur)
		//MMechostr(MSKDEBUG,"INET-End Close socket %d, k=%d\n",sck,k);
		MMpull(m);
		return 0;
	}
	//----------------------------//
	//                            //
    //----------------------------//

	
	MMpull(m);
	return 0;
}











#ifdef VERSION_WIN
int ScolInet(mmachine m,HWND hwnd,unsigned int msg,UINT wParam, LONG lParam,int *ret)
{
    int hSock;
    int NetEvent,NetError;
    
    hSock=(int)wParam;
    NetEvent=WSAGETSELECTEVENT(lParam);
    NetError=WSAGETSELECTERROR(lParam);
    return SCOLInetEvent(m,hSock,NetEvent,NetError);
}
#endif

/******************************************************************************/


void set_proxy()
{
	int i;
	http_proxy_host=NULL;



	if ((HTTPproxy[0])&&(strcmp(HTTPproxy,"no"))&&(strcmp(HTTPproxy,"ie")))
	{

		strcpy(bufproxy,HTTPproxy);
		i=0;
		while((bufproxy[i])&&(bufproxy[i]!=':')) i++;
		if (bufproxy[i])
		{

			bufproxy[i]=0;
			http_proxy_host=bufproxy;
			http_proxy_port=atoi(&bufproxy[i+1]);
		}
		else
		{
			http_proxy_host=bufproxy;
			http_proxy_port=80;
		}
	}

	if ((http_proxy_host)&&(!http_proxy_host[0])) 
		http_proxy_host=NULL;


	if (http_proxy_host) 
		MMechostr(1,"HTTP Connection via %s:%d\n",http_proxy_host,http_proxy_port);

	else if (strcmp(HTTPproxy,"ie")) 
		MMechostr(1,"HTTP direct Connection\n");

	else 
		MMechostr(1,"HTTP Wininet Connection\n");
}




int copyspec(char *dst,char *src)
{
	while ((*src)&&((*src)!='\"')) *(dst++)=*(src++);
	*dst=0;
	return 0;
}
int copyspec2(char *dst,char *src)
{
	while ((*src)&&((*src)!=')')) *(dst++)=*(src++);
	*dst=0;
	return 0;
}

int FindProxyN4(char *cont)
{
	char *p,*q;
	
	strcpy(autoHTTPproxy,"no");
	strcpy(autoSOCKSproxy,"no");
	if (strstr(cont,"proxy.type\", 1"))
    {
		if (p=strstr(cont,"proxy.http\", \""))
		{
			copyspec(autoHTTPproxy,p+14);
			strcat(autoHTTPproxy,":");
			if (q=strstr(cont,"proxy.http_port\", "))
				copyspec2(&autoHTTPproxy[strlen(autoHTTPproxy)],q+18);
			else strcat(autoHTTPproxy,"80");
		}
		if (p=strstr(cont,"socks_server\", \""))
		{
			copyspec(autoSOCKSproxy,p+16);
			strcat(autoSOCKSproxy,":");
			if (q=strstr(cont,"socks_serverport\", "))
				copyspec2(&autoSOCKSproxy[strlen(autoSOCKSproxy)],q+19);
			else strcat(autoSOCKSproxy,"1080");
		}
    }
	else if (strstr(cont,"proxy.type\", 2"))
    {
		strcpy(autoHTTPproxy,"ie");
    }
	return 0;
}

#ifdef VERSION_WIN
int FindProxybis(char *name,int timemin)
{
	long h;
	struct _finddata_t fileinfo;
	FILE *f;
	char cont[16*1024+1];
	int n;
	
	//	MessageBox(NULL,name,"file to test",0);
	
	h=_findfirst(name,&fileinfo );
	if (h==-1) return timemin;
	if (fileinfo.time_write>timemin)
    {
		if (f=fopen(name,"rb"))
		{
			timemin=fileinfo.time_access;
			n=fread(cont,1,1024*16,f);
			fclose(f);
			_findclose(h);
			cont[n]=0;
			FindProxyN4(cont);
			return timemin;
		}
    }
	_findclose(h);
	return timemin;
}

int FindProxy(char *path)
{
	int res;
	long h;
	struct _finddata_t fileinfo;
	char buf[512];
	char bufpath[512];
	int timemin=0;
	int n,p;
	HKEY key;
	
	//	MessageBox(NULL,path,"FindProxy",0);
	sprintf(path,"%s\\Users",path);
	sprintf(bufpath,"%s\\*.*",path);
	h=_findfirst(bufpath,&fileinfo );
	res=h;
	while(res!=-1)
    {
		sprintf(buf,"%s\\%s",path,fileinfo.name);
		if ((fileinfo.attrib&16)&&(strcmp(fileinfo.name,"."))&&(strcmp(fileinfo.name,"..")))
		{
			sprintf(buf,"%s\\prefs.js",buf);
			timemin=FindProxybis(buf,timemin);
		}
		res=_findnext(h,&fileinfo );
    }
	if (h!=-1) _findclose(h);
	if (timemin) return 0;
	
	if (RegOpenKeyEx(HKEY_CURRENT_USER,"Software\\Netscape\\Netscape Navigator\\Proxy Information",0,KEY_ALL_ACCESS,&key)!=ERROR_SUCCESS)
		return 0;
	n=512;
	if (RegQueryValueEx(key,"HTTP_Proxy",0,NULL,buf,&n)==ERROR_SUCCESS)
	{
		n=sizeof(int);
		if (RegQueryValueEx(key,"HTTP_ProxyPort",0,NULL,(char*)&p,&n)==ERROR_SUCCESS)
			sprintf(autoHTTPproxy,"%s:%d",buf,p);
	}
	RegCloseKey(key);
	return 0;
}

int TestNetscape()
{
	char html[1024];
	char comm[1024];
	int n,i;
	
	n=1024;
	if (RegQueryValue(HKEY_CLASSES_ROOT,".htm",html,&n)!=ERROR_SUCCESS) return 0;
	sprintf(html,"%s\\shell\\open\\command",html);
	n=1024;
	if (RegQueryValue(HKEY_CLASSES_ROOT,html,comm,&n)!=ERROR_SUCCESS) return 0;
	n=strlen(comm);
	for(i=0;i<n;i++) if (!strnicmp(&comm[i],"netscape",8))
    {
		comm[i+8]=0;
		strcpy(autoHTTPproxy,"no");
		FindProxy(comm);
		return 1;
    }
	return 0;
}

int getproxies(char *http,char *socks,char *src)
{
	char *p;
	char *q;
	
	socks[0]=0;
	http[0]=0;
	if ((strstr(src,";")==NULL)&&(strstr(src,"=")==NULL))
    {
		strcpy(http,src);
		return 1;
    }
	if (p=strstr(src,"http="))
    {
		if ((q=strstr(p,";")))
		{
			*q=0;
			strcpy(http,p+5);
			*q=';';
		}
		else strcpy(http,p+5);
    }
	if (p=strstr(src,"socks="))
    {
		if ((q=strstr(p,";")))
		{
			*q=0;
			strcpy(socks,p+6);
			*q=';';
		}
		else strcpy(socks,p+6);
    }
	return 1;
}

int TestIE()
{
	char buf[512];
	int n,p;
	HKEY key;
	if (RegOpenKeyEx(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings",0,KEY_ALL_ACCESS,&key)!=ERROR_SUCCESS)
		return 0;
	n=512;
	if (RegQueryValueEx(key,"AutoConfigURL",0,NULL,buf,&n)==ERROR_SUCCESS)
    {
		if (strlen(buf))
		{
			strcpy(autoHTTPproxy,"ie");
			RegCloseKey(key);
			return 0;
		}
    }
	
	n=512;
	if (RegQueryValueEx(key,"ProxyServer",0,NULL,buf,&n)==ERROR_SUCCESS)
	{
		n=sizeof(int);
		if (RegQueryValueEx(key,"ProxyEnable",0,NULL,(char*)&p,&n)==ERROR_SUCCESS)
		{
			if (p) return getproxies(autoHTTPproxy,autoSOCKSproxy,buf);
		}
	}
	RegCloseKey(key);
	return 0;
}
#endif











#if defined(VERSION_X11) || defined(VERSION_NOX)
int TestNetscape()
{
	char filename[1024];
	char *home, *quote, *begin, *end;
	FILE *f;
	char cont[16*1024+1];
	int n;
	
	if ((home=getenv("HOME"))==NULL) return;
	snprintf(filename,1023,"%s/.netscape/preferences.js",home);
	filename[1023]=0;
	if ((f=fopen(filename,"r"))==NULL) return;
	n=fread(cont,1,1024*16,f);
	fclose(f);
	cont[n]=0;
	FindProxyN4(cont);
	return 0;
}
#endif











int SCdefinesocks2(char *socks,char *mask);


void auto_detect_proxy()
{
	http_proxy_host=NULL;
	autoHTTPproxy[0]=0;
	autoSOCKSproxy[0]=0;
#ifdef VERSION_WIN
	if (!TestNetscape()) TestIE();
#endif
#if defined(VERSION_X11) || defined(VERSION_NOX)
	TestNetscape();
#endif
	if (!autoHTTPproxy[0]) strcpy(autoHTTPproxy,"no");
	if (!autoSOCKSproxy[0]) strcpy(autoSOCKSproxy,"no");
	MMechostr(MSKDEBUG,"autoHTTPproxy=%s\n",autoHTTPproxy);
	MMechostr(MSKDEBUG,"autoSOCKSproxy=%s\n",autoSOCKSproxy);
	
	if (HTTPproxy[0]==0) strcpy(HTTPproxy,autoHTTPproxy);
   
	set_proxy();
	SCdefinesocks2(autoSOCKSproxy,NULL);
}

/******************************************************************************/




/* http://host[:port]/toto/ -> 'host', 'toto/', port[80]
*  the first '/' of the path has to be added by the user
*  returns (-1) if error
*/
int decode_url(char *url, char **host, char **path, int *port)
{
	char *s;
	
	if (strnicmp(url,"http://",7)) return (-1);
	*host=&(url[7]);
	
	/* delimitate host[:port] */
	if ((s=strchr(*host,'/')))
	{ 
		*s=0;
		*path=&(s[1]);
	}
	else
		*path=&(url[strlen(url)]);
	if ((s=strchr(*host,':')))
	{
		*s=0;
		*port=atoi(&(s[1]));
	}
	else
		*port=80;
	if ((**host)==0) return (-1);
	return 0;
}


/******************************************************************************/

char cachegethost[256];
int cachegethostx;

int mygethost(char *host)
{
	struct hostent *hp;
	int x;
	if (!strcmp(host,cachegethost))
	{
		x=cachegethostx;
	}
	else if ((hp=gethostbyname(host)))
	{
		x=cachegethostx=*((int *) (hp->h_addr));
		strcpy(cachegethost,host);
	}
	else x=0;
	return x;
}

int testlocalip(int x)
{
	if ((x&inet_addr("255.255.255.0"))==(localscolIP&inet_addr("255.255.255.0"))) return 1;
	return 0;
}














/****************************************************************************************************/










/*******************************************************/
/* scol v 4                                            */
/*                                                     */
/* int DINETGetURLconnect ( ... )                      */
/*                                                     */
/* C code from old DINETGetURLex function              */
/*                                                     */
/* connect the socket in order to send the http request*/
/*******************************************************/
int DINETGetURLconnect (SOCKET* sck, char* request, int x, int port)
{
SOCKADDR_IN address;
long argp=1;

	if ((proxyIp==0)||
		(x==(int)inet_addr("127.0.0.1"))||
		((proxyIp&proxyMask)==(x&proxyMask)))
	{
		address.sin_port=htons((short)port);
		address.sin_family=AF_INET;
		address.sin_addr.s_addr=x;
		
#ifdef VERSION_WIN
		if (WSAAsyncSelect(*sck, hscol, WM_INET, (FD_CONNECT|FD_READ|FD_WRITE|FD_CLOSE))==SOCKET_ERROR)
			return DINET_GETURL_ERROR;
#endif
#if defined(VERSION_X11) || defined(VERSION_NOX)
		// passage en non bloquant 
		ioctl (*sck, FIONBIO, &argp);
#endif
		if ( (connect(*sck,(struct sockaddr *)&address,sizeof(address))!=0)&&
#ifdef VERSION_WIN
			(WSAGetLastError()!=WSAEWOULDBLOCK) )
#endif
#if defined(VERSION_X11) || defined(VERSION_NOX)
			(errno!=EINPROGRESS) )
#endif
			return DINET_GETURL_ERROR;
	}
	else
	{
		//$ LB : replace old socks4 protocol by SOCKSconnect function call
        if (SOCKSconnect (*sck, x, htons((short)port)) != SOCKS_SUCCESS)
			MMechostr (MSKDEBUG, "DINETGetURLconnect : error connecting socket %d\n", *sck);
		//else MMechostr (MSKDEBUG, "DINETGetURLconnect : socket %d connected\n", *sck);

#ifdef VERSION_WIN
		if (WSAAsyncSelect(*sck, hscol, WM_INET, (FD_CONNECT|FD_READ|FD_WRITE|FD_CLOSE))==SOCKET_ERROR)
			return DINET_GETURL_ERROR;
#endif
#if defined(VERSION_X11) || defined(VERSION_NOX)
		/* passage en non bloquant */
		ioctl (*sck, FIONBIO, &argp);
#endif
	}

	return DINET_GETURL_SUCCESS;
}










/*******************************************************/
/* scol v 4                                            */
/*                                                     */
/* int DINETGetURLengine ( ... )                       */
/*                                                     */
/* C code from old DINETGetURLex function              */
/*                                                     */
/* process a InetGetUrl request                        */
/*******************************************************/
int DINETGetURLengine (char* url, char* verb, char* headerAdds, char* postdata, int sizepost, int flags, /*out*/SOCKET *sck, /*out*/char *request, /*out*/int *sizereq)
{
char *host, *path;
int port;
int x;
long argp=1;
char bufurl[1024];
int useproxy;
char* headerAdds2 = NULL;
int haSize;
char* defaultHeaderAdds = "User-Agent: SCOL\r\nPragma: no-cache\r\n";
int dhaSize = strlen (defaultHeaderAdds);





	if ((url==NULL) || (*url==0) || (strlen(url)>=1024))
		return DINET_GETURL_ERROR;


	strcpy(bufurl,url);


	
	if ((verb==NULL) || (*verb==0) ||
		(decode_url(bufurl,&host,&path,&port)<0))
		return DINET_GETURL_ERROR;


	//  MMechostr(MSKDEBUG,"INET: requesting %s [%s][:%d][/%s] (postdata=%d)\n",
	//  verb,host,port,path,(postdata ? strlen(postdata) : 0));

	useproxy=0;
	if ((x=inet_addr(host))==INADDR_NONE)
	{

		if (strstr(host,".")==NULL)
		{
			x=mygethost(host);

			if ((http_proxy_host)&&((x==0)||(!testlocalip(x))))
				useproxy=1;
		}
		else 
			if (http_proxy_host) 
				useproxy=1;
		else 
			x=mygethost(host);
	}
	else
	{
		if ((http_proxy_host)&&(strcmp(host,"127.0.0.1"))&&(!testlocalip(x)))
			useproxy=1;
	}




	if (headerAdds != NULL)
	{

		haSize = strlen (headerAdds);
		if ((headerAdds[haSize-2] == '\r') && (headerAdds[haSize-1] == '\n'))
		{
			headerAdds2 = malloc ((haSize+1) * sizeof(char));
			strcpy (headerAdds2, headerAdds);
		}
		else
		{
			headerAdds2 = (char*) malloc ((haSize+3) * sizeof(char));
			memcpy (headerAdds2, headerAdds, haSize);
			headerAdds2[haSize] = '\r';
			headerAdds2[haSize+1] = '\n';
			headerAdds2[haSize+2] = '\0';
		}
	}
	else if (!useproxy)
	{
		headerAdds2 = (char*) malloc ((dhaSize + 1) * sizeof(char));
		memcpy (headerAdds2, defaultHeaderAdds, dhaSize);
		headerAdds2[dhaSize] = '\0';
	}



	

	//$LB (11 / 07 / 2001) : headerAdds is now included in the request.
	//                       it could be "User-agent : Scol...Pragma: no-cache..." if the 
	//                       user called InetGetUrlEx function or
	//                       it could be whatever the user wants in calling the InetGetUrlEx2 function
	if (useproxy)
	{

		if (PROXYHTTP_IsAuthorized())
		{
			sprintf(request,
			"%s http://%s:%d/%s HTTP/1.0\r\n"
			"%s%s\r\n"
			"Host: %s\r\n",verb, host, port, path,PROXYHTTP_BASIC_AUTHORIZATION_FIELD, PROXYHTTP_GetUserID(),  host);

		}
		else if (headerAdds != NULL)
		{
			sprintf(request,
				"%s http://%s:%d/%s HTTP/1.0\r\n"
				"%s"
				"Host: %s\r\n",verb, host, port, path, headerAdds2, host);
		}
		else
		{
			sprintf(request,
				"%s http://%s:%d/%s HTTP/1.0\r\n"
				"Host: %s\r\n",verb, host, port, path, host);
		}




		host=http_proxy_host;
		port=http_proxy_port;
		if ((x=inet_addr(host))==INADDR_NONE)
		{
			x=mygethost(host);
		}

	}
	else
	{
		sprintf(request,
			"%s /%s HTTP/1.0\r\n"
			"%s"
			"Host: %s\r\n",verb, path, headerAdds2, host);

	}


	if (postdata)
	{
		sprintf(request+strlen(request),
			"Content-length: %d\r\n\r\n",sizepost);
		*sizereq = strlen(request)+sizepost;
		memcpy(request+strlen(request),postdata,sizepost);

	}
	else
	{
		strcpy(request+strlen(request),"\r\n");
		*sizereq = strlen(request);
	}




	

//	MMechostr(MSKDEBUG,"** connecting to %s:%d, request:\n%s",host,port,request);
	
	
	if ( (request==NULL) || (*request==0) ||
		(x==0) ||
#ifdef VERSION_WIN
		((*sck = socket(AF_INET, SOCK_STREAM, 0))==INVALID_SOCKET)
#endif
#if defined(VERSION_X11) || defined(VERSION_NOX)
		((*sck = socket(AF_INET, SOCK_STREAM, 0))<0) ||
		(SCKaddsock(*sck, SC_TYPINET))
#endif
		)
	{
		if (headerAdds2) free (headerAdds2);
		return DINET_GETURL_ERROR;
	}
	
	//MMechostr(MSKDEBUG,"** connecting to %s:%d, socket %d, request:\n%s",host,port,*sck,request);


    if (DINETGetURLconnect (sck, request, x, port) != DINET_GETURL_SUCCESS)
	{
		if (headerAdds2) free (headerAdds2);
		return DINET_GETURL_ERROR;
	}

	if (headerAdds2) free (headerAdds2);
	return DINET_GETURL_SUCCESS;
}








//$ LB(22/08/2001) : add DINETGetURLex2
/*********************************************************/
/* scol v 4                                              */
/*                                                       */
/* int DINETGetURLex2(mmachine m)                        */
/*                                                       */
/* same as DINETGetURLex, but the 4th param. is a        */
/* string containing fields to add to the request header */
/*                                                       */
/* fun [Chn S S S S I fun [INET u0 S I] u1 u0] INET      */
/*********************************************************/
int DINETGetURLex2 (mmachine m)
{
	SOCKET sck;
	char *url, *request, *verb, *headerAdds, *postdata;
	int murl,mverb, mheaderAdds, mdata, k, flags;
	int sizepost;
	int sizereq;



	mverb       = MMget(m, 6) >>1;
	murl        = MMget(m, 5) >>1;
	mheaderAdds = MMget(m, 4) >>1;
	mdata       = MMget(m, 3) >>1;
	flags       = MMget(m, 2) >>1;
	url        = (murl == NIL)  ? NULL       : MMstartstr(m,murl);
	verb       = (mverb == NIL) ? NULL       : MMstartstr(m,mverb);
	headerAdds = (mheaderAdds == NIL) ? NULL : MMstartstr(m, mheaderAdds);
	postdata   = (mdata == NIL) ? NULL       : MMstartstr(m,mdata);
	sizepost   = (mdata == NIL) ? 0          : MMsizestr(m,mdata);
	if ((postdata) && (*postdata==0)) postdata=NULL;
	//MMechostr(MSKDEBUG,"INET: requesting %s %s\n",verb,url);


	request = (char*) malloc ((1024+sizepost) * sizeof(char));
	
	if (DINETGetURLengine (url, verb, headerAdds, postdata, sizepost, flags, &sck, request, &sizereq) != DINET_GETURL_SUCCESS)
	{
		SCKclose (sck);

		if (request)
			free (request);

		m->pp+=8;
		return MMpush(m,NIL);
	}

	


//  MMechostr(MSKDEBUG,"** creating scol object\n");
	
	/* once connected, build INET object                                       */
	if ((k = MMpush(m, MMget(m, 7))))             return k; /* channel         */
	if ((k = MMpush(m, 0)))						  return k; /* authentication  */
	if ((k = Mpushstrblocn(m, request, sizereq))) return k; /* OBJINET_REQUEST */
	if (request)
		free(request);
	if ((k = MMpush(m, 0)))                       return k; /* OBJINET_REQPOS  */
	if ((k = MMpush(m, flags<<1)))                return k; /* flags           */
	if ((k = Mpushstrbloc(m, "")))                return k; /* INBUF           */
	if ((k = MMpush(m, 0)))				          return k; /* KILLED */
	if ((k = MMpush(m, OBJINET_SIZE<<1)))         return k; /* size of objinet */
	if ((k = MBdeftab(m)))                        return k;
	if ((k = OBJcreate(m, ObjInetType, sck, NIL, NIL))) return k;
	
	/* add reflex */
	if ((k = MMpush(m, MMget(m, 2))))                      return k;
	if ((k = MMpush(m, MMget(m, 2))))                      return k;
	if ((k = OBJaddreflex(m, ObjInetType, INET_RFL_DATA))) return k;
	
	/*  MMechostr(MSKDEBUG,"INET: connected on #%d\n",sck);*/
	
	k = MMpull(m); /* save INET object */
	m->pp+=8;
	return MMpush(m,k);
}










/*******************************************************/
/* scol v 4                                            */
/*                                                     */
/* int DINETGetURLex(mmachine m)                       */
/*                                                     */
/* same as old DINETGetURLex function, but the C code  */
/* is now managing by DINETGetURLengine                */
/*                                                     */
/* fun [Chn S S S I fun [INET u0 S I] u1 u0] INET      */
/*******************************************************/
int DINETGetURLex(mmachine m)
{
	SOCKET sck;
	char *url, *request, *verb, *postdata;
	int murl,mverb,mdata,k,flags;
	int sizepost;
	int sizereq;
	char* headerAdds = "User-Agent: SCOL\r\nPragma: no-cache\r\n";




	mverb    = MMget(m, 5)>>1;
	murl     = MMget(m, 4)>>1;
	mdata    = MMget(m, 3)>>1;
	flags    = MMget(m, 2)>>1;
	url      = (murl==NIL)  ? NULL : MMstartstr(m,murl);
	verb     = (mverb==NIL) ? NULL : MMstartstr(m,mverb);
	postdata = (mdata==NIL) ? NULL : MMstartstr(m,mdata);
	sizepost = (mdata==NIL) ? 0    : MMsizestr(m,mdata);
	if ((postdata) && (*postdata==0)) postdata=NULL;
	//MMechostr(MSKDEBUG,"INET: requesting %s %s\n",verb,url);


	request = (char*) malloc ((1024+sizepost) * sizeof(char));
	
	// $ LB (11 / 07 / 2001) : now the C code is in this function.... 
	if (DINETGetURLengine (url, verb, headerAdds, postdata, sizepost, flags, &sck, request, &sizereq) != DINET_GETURL_SUCCESS)
	{
		SCKclose (sck);

		if (request)
			free (request);

		m->pp+=7;
		return MMpush(m,NIL);
	}

	


	//  MMechostr(MSKDEBUG,"** creating scol object\n");
	
	/* once connected, build INET object                                       */
	if ((k = MMpush(m, MMget(m, 6))))             return k; /* channel         */
	//$ LB (13/07/2001) : add socket into objinet
	if ((k = MMpush(m, 0)))						  return k; /* authentication  */
	if ((k = Mpushstrblocn(m, request, sizereq))) return k; /* OBJINET_REQUEST */
	if (request)
		free(request);
	if ((k = MMpush(m, 0)))                       return k; /* OBJINET_REQPOS  */
	if ((k = MMpush(m, flags<<1)))                return k; /* flags           */
	if ((k = Mpushstrbloc(m, "")))                return k; /* INBUF           */
	if ((k = MMpush(m, 0)))				          return k; /* KILLED */
	if ((k = MMpush(m, OBJINET_SIZE<<1)))         return k; /* size of objinet */
	if ((k = MBdeftab(m)))                        return k;
	if ((k = OBJcreate(m, ObjInetType, sck, NIL, NIL))) return k;
	
	/* add reflex */
	if ((k = MMpush(m, MMget(m, 2))))                      return k;
	if ((k = MMpush(m, MMget(m, 2))))                      return k;
	if ((k = OBJaddreflex(m, ObjInetType, INET_RFL_DATA))) return k;
	
	/*  MMechostr(MSKDEBUG,"INET: connected on #%d\n",sck);*/
	
	k = MMpull(m); /* save INET object */
	m->pp+=7;
	return MMpush(m,k);
}










/* fun [Chn S I fun [INET u0 S I] u1 u0] INET */
int DINETGetURL(mmachine m)
{
	char verb_get[]="GET";
	int k;

	if ((k=MMpush(m,MMget(m,4)))) return k;        /* Channel   */
	if ((k=Mpushstrbloc(m,verb_get))) return k;    /* verb      */
	if ((k=MMpush(m,MMget(m,5)))) return k;        /* URL       */
	if ((k=MMpush(m,NIL))) return k;               /* post data */
	if ((k=MMpush(m,MMget(m,6)))) return k;        /* flag      */
	if ((k=MMpush(m,MMget(m,6)))) return k;        /* callback  */
	if ((k=MMpush(m,MMget(m,6)))) return k;        /* user var  */
	DINETGetURLex(m);
	k=MMpull(m);
	m->pp+=5;

	k = MMpush(m,k);

	return k;
}










/* fun [INET] INET */
int DINETStopURL(mmachine m)
{
	int k;
	
	if ((k=OBJdelTM(m,ObjInetType,MMget(m,0)))) return k;
	MMset(m,0,NIL);
	return 0;
}

/* fun [] I*/
int DINETdisableProxy(mmachine m)
{
	strcpy(HTTPproxy,"no");
	set_proxy();
	return MMpush(m,NIL);
}

/* fun [S] S */
int INETsetProxy(mmachine m)
{
	int p;
	p=MMget(m,0)>>1;
	if ((p==NIL)||(MMsizestr(m,p)>=256)) strcpy(HTTPproxy,"");
	else strcpy(HTTPproxy,MMstartstr(m,p));
	set_proxy();
	return 0;
}

/* fun [] S */
int INETgetProxy(mmachine m)
{
	char buf[1024];
	if (http_proxy_host)
	{
		sprintf(buf,"%s:%d",http_proxy_host,http_proxy_port);
		return Mpushstrbloc(m,buf);
	}
	return MMpush(m,NIL);
}
























/**************************************************************************************/



//$ LB (17/07/2001) : add INETisConnected function
//$LB (21/02/2002) : add _rflINETisConnected function
//$LB (05/03/2002) : INETisConnected and _rflINETisConnected have been moved to win_inet.cpp (nox_inet.cpp, x11_inet.cpp)
#define INET_PKG_NB 9

char* INET_name[INET_PKG_NB]={
	"INET", "INETGetURL", "INETGetURLex", "INETGetURLex2", 
		"INETStopURL", "INET_HEADER","INETsetProxy","INETgetProxy","INETdisableProxy"
};

int (*INET_fun[INET_PKG_NB])(mmachine m)={
	NULL, DINETGetURL, DINETGetURLex, DINETGetURLex2, 
		DINETStopURL, (void*)(int)(INET_HEADER<<1),INETsetProxy,INETgetProxy,DINETdisableProxy
};

int INET_narg[INET_PKG_NB]={
	TYPTYPE, 5, 7, 8, 1,
		TYPVAR,1,0,0
};

char* INET_type[INET_PKG_NB]={
	NULL,"fun [Chn S I fun [INET u0 S I] u1 u0] INET","fun [Chn S S S I fun [INET u0 S I] u1 u0] INET","fun [Chn S S S S I fun [INET u0 S I] u1 u0] INET",
		"fun [INET] INET",	"I","fun [S] S","fun [] S","fun [] I"
};








#ifdef VERSION_WIN
extern HINTERNET session;
int SCOLloadHTTPbis(mmachine m);
#endif

int SCOLloadHTTP(mmachine m)
{
	http_proxy_host=NULL;
	auto_detect_proxy();
#ifdef VERSION_WIN
	if (!strcmp(HTTPproxy,"ie"))
	{
		strcpy(HTTPproxy,"");
		return SCOLloadHTTPbis(m);
	}
#endif
	/* auto-detect can be overriden by user params in usm.ini */
	ObjInetType=OBJregister(INET_RFL_NB,0,InetDestroy,"INET");
#ifdef VERSION_WIN
	WM_INET=OBJgetUserEvent();
	OBJdefEvent(WM_INET,ScolInet);
	session=0;
	
#endif
	cachegethost[0]=0;
	
	return PKhardpak(m,"INET.pkg",INET_PKG_NB,INET_name,INET_fun,INET_narg,INET_type);
}


