/**********************************************************************************/
/* scol v 4                                                                       */
/*                                                                                */
/* proxyhttp.c                                                                    */
/*                                                                                */
/* proxy http management (authentication, authorization, ...)                     */
/*                                                                                */
/* cryonetworks, loïc berthelot, jull 2001                                        */
/**********************************************************************************/


// Modifications History
//
//$ LB (23/08/2001) : add uname and pword fields in ProxyHttpData_t struct in order to
//                    make proxy http authentication works with the wininet lib


#include <windows.h>
#include <wininet.h>
#include <stdio.h>
#include <string.h>
#include "../include/kernel.h"
#include "../scolobj.h"
#include "../include/socket.h"
#include "../net/inet.h"
//$ LB : add base64
#include "../base64.h"
#include "../include/proxyhttp.h"
#include "../scol.h"
#include "../listlab.h"
#include "../fifo.h"
#include "../../win/resource.h"
#include "../../win/winscol.h"
#include "../../win/http.h"









#define HTTP_ERROR_PROXY_AUTHENTICATION_NEEDED "407"



#define PROXYHTTP_LOCK_FREE                0x00
#define PROXYHTTP_LOCK_PROCESSING_REQUESTS 0x01
#define PROXYHTTP_LOCK_RUNNING_DIALOG      0x02





int _PROXYHTTP_SendAuthInfos (mmachine m, int networkAPI, int scolsuper, int channel, int handle);












/*********************************************************************************************************/
/*********************************************************************************************************/
/**                                                                                                     **/
/**                                                                                                     **/
/**          D A T A                                                                                    **/
/**                                                                                                     **/
/**                                                                                                     **/
/*********************************************************************************************************/
/*********************************************************************************************************/




/****************************************/
/*                                      */
/* ProxyData_t                          */
/*                                      */
/* define the set of data needed to     */
/* manage the http authentication       */
/*                                      */
/****************************************/
typedef struct ProxyHttpData_t
{
	int  lock;                // one of the PROXYHTTP_LOCK values

	int  authorization;       // 1 if informations are already stored
	char *userid;             // proxy http authentication infos <=> base64 (uname:pword)
	char *uname;              
	char *pword;

	char firewall[256];       // proxy ip, printed in the user dialog
	char domain[256];         // proxy domain, printed in the user dialog

	mmachine mmachine;

} ProxyHttpData_t;

static ProxyHttpData_t ProxyHttpData;




/*****************************************/
/*                                       */
/* ProxyHttpRequest_t                    */
/*                                       */
/* used to store a request, waiting for  */
/* the authentication information to     */
/* come.                                 */
/*                                       */
/*****************************************/
typedef struct ProxyHttpRequest_t
{
	int  networkAPI; // PROXYHTTP_SCOL_NETWORK_API   or   PROXYHTTP_WININET_NETWORK_API
	int  scolsuper;	 // 1 if the request came from the main machine.
	int  channel;    // channel which the authorization will be given to
	int  handle;     // handle of inet object 
				     //     <=> if networkAPI == PROXYHTTP_SCOL_NETWORK_API : socket number for the request (handler system of inetobj
	                 //     <=> if networkAPI == PROXYHTTP_WININET_NETWORK_API : threadid used to identify the transfert struct of inet obj
	int  force;      // 1 if the client machine wants the main machine force the infos dialog
} ProxyHttpRequest_t;





/**************************************************************/
/*                                                            */
/* ProxyHttpFifo_t                                            */
/*                                                            */
/* list of request that are waiting for                       */
/* authentication.                                            */
/* A dialog is gonna ask the user to enter his authentication */
/* infos. Because he can valid the dialog whenever he wants,  */
/* we need to store all the request 'til we get the infos.    */
/*                                                            */
/**************************************************************/
typedef struct ProxyHttpFifo_t
{
	ProxyHttpRequest_t** requests;      // dynamic tab of request
	int size;                           // dynamic size of tab
	int processState;                   // one of the PROXYHTTP_PROCESS values
} ProxyHttpFifo_t;

static ProxyHttpFifo_t ProxyHttpFifo;





















/*********************************************************************************************************/
/*********************************************************************************************************/
/**                                                                                                     **/
/**                                                                                                     **/
/**          D A T A     I N I T I A L I Z A T I O N                                                    **/
/**                                                                                                     **/
/**                                                                                                     **/
/*********************************************************************************************************/
/*********************************************************************************************************/



/*****************************************/
/*                                       */
/* Proxy Http Data Initialization        */
/*                                       */
/*****************************************/
static int ProxyHttpDataInit = 0;

void _PROXYHTTP_DATA_Init ()
{
	ProxyHttpDataInit = 1;
	ProxyHttpData.lock = 0;
	ProxyHttpData.authorization = 0;
	ProxyHttpData.userid = NULL;
	ProxyHttpData.mmachine = NULL;
	ProxyHttpData.firewall[0] = '\0';
	ProxyHttpData.domain[0] = '\0';
}




/*******************************************/
/*                                         */
/* Proxy Http Fifo Initialization          */
/*                                         */
/*******************************************/
static int ProxyHttpFifoInit = 0;

void _PROXYHTTP_FIFO_Init ()
{
	ProxyHttpFifoInit = 1;
	ProxyHttpFifo.requests = NULL;      // dynamic tab of request
	ProxyHttpFifo.size = 0;             // dynamic size of tab
	ProxyHttpFifo.processState = 0;     // one of the PROXYHTTP_PROCESS values
}





















/*********************************************************************************************************/
/*********************************************************************************************************/
/**                                                                                                     **/
/**                                                                                                     **/
/**          I N T E R N A L    B O D Y                                                                 **/
/**                                                                                                     **/
/**          REQUESTS FIFO MANAGEMENT                                                                   **/
/**                                                                                                     **/
/**                                                                                                     **/
/*********************************************************************************************************/
/*********************************************************************************************************/







/************************************************************************************************/
/*                                                                                              */
/* void _PROXYHTTP_FIFO_Add (int networkAPI, int scolsuper, int channel, int handle, int force) */
/*                                                                                              */
/* add a request to fifo, waiting for authentication                                            */
/*                                                                                              */
/************************************************************************************************/
void _PROXYHTTP_FIFO_Add (int networkAPI, int scolsuper, int channel, int handle, int force)
{
	// increase fifo size
	ProxyHttpFifo.requests = (ProxyHttpRequest_t **) realloc (ProxyHttpFifo.requests, 
															 (ProxyHttpFifo.size+1)* sizeof (ProxyHttpRequest_t *));

	// alloc mem. for the new element
	ProxyHttpFifo.requests[ProxyHttpFifo.size] = (ProxyHttpRequest_t*) malloc (sizeof (ProxyHttpRequest_t));

	// fill the new element with data
	ProxyHttpFifo.requests[ProxyHttpFifo.size]->networkAPI = networkAPI;
	ProxyHttpFifo.requests[ProxyHttpFifo.size]->scolsuper  = scolsuper;
	ProxyHttpFifo.requests[ProxyHttpFifo.size]->channel    = channel;
	ProxyHttpFifo.requests[ProxyHttpFifo.size]->handle     = handle;
	ProxyHttpFifo.requests[ProxyHttpFifo.size]->force      = force;

	// update fifo size value
	ProxyHttpFifo.size++;
}






/*********************************************************************************************************/
/*                                                                                                       */
/* void _PROXYHTTP_FIFO_Extract (int *networkAPI, int *scolsuper, int *channel, int* handle, int* force) */
/*                                                                                                       */
/* extract a request from the fifo, and store the data into the buffers                                  */
/* given as parameters.                                                                                  */
/*                                                                                                       */
/* return 0 if ok, non-zero code if error (fifo is empty...)                                             */
/*                                                                                                       */
/*********************************************************************************************************/
int _PROXYHTTP_FIFO_Extract (int *networkAPI, int *scolsuper, int *channel, int* handle, int* force)
{
int i;

	if (ProxyHttpFifo.size == 0)
		return -1;

	// update fifo size value
	ProxyHttpFifo.size--;

	// store the data
	*networkAPI = ProxyHttpFifo.requests [0]->networkAPI;
	*scolsuper  = ProxyHttpFifo.requests [0]->scolsuper;
	*channel    = ProxyHttpFifo.requests [0]->channel;
	*handle     = ProxyHttpFifo.requests [0]->handle;
	*force      = ProxyHttpFifo.requests [0]->force;

	for (i=0; i < ProxyHttpFifo.size; i++)
		*(ProxyHttpFifo.requests[i]) = *(ProxyHttpFifo.requests[i+1]);

	// free the mem.
	free (ProxyHttpFifo.requests[ProxyHttpFifo.size]);

	return 0;
}








/************************************************/
/*                                              */
/* void _PROXYHTTP_FIFO_Process (mmachine m)    */
/*                                              */
/* process the requests fifo, and reply to all  */
/* the requests stored in it.                   */
/*                                              */
/************************************************/
void _PROXYHTTP_FIFO_Process (mmachine m)
{
int networkAPI, scolsuper, channel, handle, force;

	while (_PROXYHTTP_FIFO_Extract (&networkAPI, &scolsuper, &channel, &handle, &force) != -1)
		_PROXYHTTP_SendAuthInfos (m, networkAPI, scolsuper, channel, handle);
}






























/*********************************************************************************************************/
/*********************************************************************************************************/
/**                                                                                                     **/
/**                                                                                                     **/
/**          I N T E R N A L    B O D Y                                                                 **/
/**                                                                                                     **/
/**          PROXY HTTP AUTHENTICATION MANAGEMENT                                                       **/
/**                                                                                                     **/
/**                                                                                                     **/
/*********************************************************************************************************/
/*********************************************************************************************************/







/***************************************************************/
/* scol v 4                                                    */
/*                                                             */
/* int PROXYHTTP_Authorization (mmachine m, SOCKET scksys)     */
/*                                                             */
/* re-send the request, in adding the proxy authentication     */
/* challenge in the header.                                    */
/*                                                             */
/***************************************************************/
int PROXYHTTP_Authorization (mmachine m, SOCKET scksys)
{
char *req;     int reqSize;
char *newReq;  int mnewReq, newReqRealSize, newReqSize;
int useridSize;

char* insertIndex, *insertIndex2; int insertSize;
int k;

SOCKET sck;
int x;
int mobj, ppmobj;



	
	if ( ((mobj=OBJfindTH(m,ObjInetType, scksys))==NIL) ||
		((mobj=MMfetch(m, mobj, OFFOBJMAG)>>1)==NIL) ) return 0;

	
	if ((k=MMpush (m, (mobj<<1)+1))) return k;
	ppmobj = MMgetPP (m);

	//
	// !! DON'T FORGET TO PULL THE MOBJ POINTER FROM THE STACK BEFORE RETURN 0
	//


	// get the current request
	req     = MMstartstr (m, MMfetch (m, mobj, OBJINET_REQUEST) >> 1);
	reqSize = MMsizestr (m, MMfetch (m, mobj, OBJINET_REQUEST) >> 1);

	useridSize = strlen (ProxyHttpData.userid);
	
	// get the size needed for the new request
	newReqRealSize = reqSize + strlen (PROXYHTTP_BASIC_AUTHORIZATION_FIELD) + useridSize + 2; // '+ 2' for "\r\n" characters
	newReqSize = (newReqRealSize + 4)>>2;

	// ask scol to alloc memory for the new request
    mnewReq = MMmalloc (m, newReqSize+1, TYPEBUF); if (mnewReq==NIL) return MERRMEM;


	MMsetsizestr (m, mnewReq, newReqRealSize);

	newReq = MMstartstr (m, mnewReq);


	// helpfull to insert authorization field
	if ((insertIndex = strstr (req, PROXYHTTP_BASIC_AUTHORIZATION_FIELD)) == NULL)
		if ((insertIndex = strstr (req, "Host:")) == NULL)
		{
			// MMechostr (MSKDEBUG, "PROXY HTTP WARNING : no entry point to insert the authentication field!\n");

			MMpull(m);
			return 0;
		}
		else insertIndex2 = insertIndex;
	else insertIndex2 = strstr(insertIndex, "\r\n") + 2;





	insertSize = insertIndex - req;
	// copy the begining of header
	memcpy (newReq, req, insertSize);


	// insert the authorization field
	memcpy (newReq+insertSize, PROXYHTTP_BASIC_AUTHORIZATION_FIELD, strlen (PROXYHTTP_BASIC_AUTHORIZATION_FIELD));
	insertSize+=strlen (PROXYHTTP_BASIC_AUTHORIZATION_FIELD);


	// with the userid
	memcpy (newReq+insertSize, ProxyHttpData.userid, useridSize);
	insertSize+=useridSize;


	memcpy (newReq+insertSize, "\r\n", 2);
	insertSize+=2;



	// and copy the rest of the request
	memcpy (newReq+insertSize, insertIndex2, reqSize - (insertIndex2 - req));
	insertSize+=reqSize - (insertIndex2 - req);


	*(newReq + insertSize) = '\0';


	if ((x = inet_addr(http_proxy_host)) == INADDR_NONE)
	{
		x = mygethost(http_proxy_host);
	}

	if ( (newReq==NULL) || (*newReq==0) ||
		(x==0) ||
		((sck = socket(AF_INET, SOCK_STREAM, 0))==INVALID_SOCKET)
		)
		return DINET_GETURL_ERROR;
	



   if (DINETGetURLconnect (&sck, newReq, x, http_proxy_port) != DINET_GETURL_SUCCESS)
		return DINET_GETURL_ERROR;

    // put the new socket as the new system handler of this object
    OBJsetHandsys (m, ObjInetType, scksys, sck);

	// MMechostr (MSKDEBUG, "\nPROXY HTTP : change socket %d to socket %d in order to authenticate the request\n", scksys, sck);

	mobj = MMgetbase (m, ppmobj, 0)>>1;

    // replace the old request of the objinet, by this new one
    MMstore (m, mobj, OBJINET_REQUEST, (mnewReq<<1) + 1); 


	// and you have to send all data again
	MMstore (m, mobj, OBJINET_REQPOS, 0);


	// reset the data reception buffer
	if ((k = Mpushstrbloc(m, ""))) return k;
	mobj = MMgetbase (m, ppmobj, 0)>>1;
	MMstore(m, mobj, OBJINET_INBUF, MMpull (m));

	MMpull(m);


	return 0;
}










/********************************************************/
/*                                                      */
/* int _PROXYHTTP_AccessDenied (mmachine m, int socket) */
/*                                                      */
/* the user has canceled authentication infos input.    */
/* http buffer with 407 error is returned to the        */
/* objinet callback.                                    */
/*                                                      */
/********************************************************/
int _PROXYHTTP_AccessDenied (mmachine m, int socket)
{
int k, mobj, leninbuf, ppinbuf;
char* inbuf;
char* token;
	



	// get inet object
	if ( ((mobj=OBJfindTH(m,ObjInetType,socket))==NIL) ||
			((mobj=MMfetch(m,mobj,OFFOBJMAG)>>1)==NIL) ) return 0;

	if ((k = MMpush (m, (mobj<<1)+1))) return k;
	if ((k = MMpush (m, MMfetch (m, MMget (m, 0) >> 1, OBJINET_INBUF)))) return k;


	inbuf = MMstartstr(m, MMget(m,0)>>1);

	if ((token = strstr (inbuf, "\r\n\r\n")))
	{
		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=MMget(m,1)>>1;
	}

    ppinbuf=MMgetPP(m);


	// make the 407 http error appear in inet callback
	if (OBJbeginreflex(m, ObjInetType, socket, INET_RFL_DATA) == 0)
	{
		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);


	// end of transmission
	if (OBJbeginreflex(m, ObjInetType, socket, INET_RFL_DATA) == 0)
	{
		if ((k = MMpush(m, NIL))) return k;
		if ((k = MMpush(m, 1<<1))) return k;
		OBJdelTH(m, ObjInetType, socket);
		if ((k = OBJcallreflex(m, 2))) return k;
	}



	return 0;
}








/*********************************************************/
/*                                                       */
/* int PROXYHTTP_SetAuthInfos (mmachine m, char* defcom) */
/*                                                       */
/* client machine receives authentication infos from     */
/* the main machine.                                     */
/*                                                       */
/*********************************************************/
int PROXYHTTP_SetAuthInfos (mmachine m, char* defcom)
{
int networkAPI, handle, processState;
char tmp[512];

	// get defcom data
	sscanf (defcom, "%s\t%d\t%d\t%d\t", &(tmp[0]), &networkAPI, &handle, &processState);


	// the user gave authentication infos
	if (processState == PROXYHTTP_PROCESS_AUTHORIZED)
	{
	char userid[256], uname[256], pword[256];

		sscanf (defcom, "%s\t%d\t%d\t%d\t%s\t%s\t%s\t", &(tmp[0]), &networkAPI, &handle, &processState, &(userid[0]), &(uname[0]), &(pword[0]));

		// store authentication infos
		if (ProxyHttpData.userid) free (ProxyHttpData.userid);
		ProxyHttpData.userid = (char*) malloc ((strlen(userid) + 1) * sizeof(char));
		strcpy (ProxyHttpData.userid, userid);

		if (ProxyHttpData.uname) free (ProxyHttpData.uname);
		ProxyHttpData.uname = (char*) malloc ((strlen(uname) + 1) * sizeof(char));
		strcpy (ProxyHttpData.uname, uname);

		if (ProxyHttpData.pword) free (ProxyHttpData.pword);
		ProxyHttpData.pword = (char*) malloc ((strlen(pword) + 1) * sizeof(char));
		strcpy (ProxyHttpData.pword, pword);

		// ok, authentication infos are now present on this machine
		ProxyHttpData.authorization = 1;
	}



	if (networkAPI == PROXYHTTP_SCOL_NETWORK_API)
	{
		if (processState == PROXYHTTP_PROCESS_AUTHORIZED)
		{
			SCKclose ((SOCKET)handle);
			PROXYHTTP_Authorization (m, (SOCKET)handle);
		}
		else 
			_PROXYHTTP_AccessDenied (m, (SOCKET)handle);
	}
	else if (networkAPI == PROXYHTTP_WININET_NETWORK_API)
			HTTPThreadAuthorization ((DWORD)handle, processState);


	return 0;
}








/*****************************************************************************************************/
/*                                                                                                   */
/* int _PROXYHTTP_SendAuthInfos (mmachine m, int networkAPI, int scolsuper, int channel, int handle) */
/*                                                                                                   */
/* dialog callback. get the informations the user entered.                                           */
/*                                                                                                   */
/*****************************************************************************************************/
int _PROXYHTTP_SendAuthInfos (mmachine m, int networkAPI, int scolsuper, int channel, int handle)
{
char defcom [1024];
char tmp [512];
int p,k;
char *c;



	// build defcom
	sprintf (defcom, "%s\t%d\t%d\t%d\t", PROXYHTTP_DEFCOM_AUTHENTICATION, networkAPI, handle, ProxyHttpFifo.processState);

	

	if (ProxyHttpFifo.processState == PROXYHTTP_PROCESS_AUTHORIZED)
	{
		sprintf (tmp, "%s\t%s\t%s\t", ProxyHttpData.userid, ProxyHttpData.uname, ProxyHttpData.pword);
		strcat (defcom, tmp);
	}

	if (scolsuper)
		PROXYHTTP_SetAuthInfos(m, defcom);

	else
	{
		// save the current channel
		if (MMpush (m, MMgetglobal (m, OFFSCCUR))) return MERRMEM;
		k=0;

		// select the master channel
		MMsetglobal (m, OFFSCCUR, channel);

		// fill the buffer with defcom and data
		if (Mpushstring(m, defcom)) return MERRMEM;
		c    = (char*)MMstart(m, MMget(m,0)>>1);
		p    = strlen(c)+1;
		c[0] = (p-2)&255;
		c[1] = ((p-2)>>8)&255;


		// send the defcom
		k    = SCsendpile(m);


		// get the saved channel
		MMsetglobal(m,OFFSCCUR,MMpull(m));	
	}

	return 0;
}






void PROXYHTTP_ProcessAuthInfos()
{

	// indicate the dialog has returned and that the requests fifo is going to be processed
	// <=> DON'T WRITE IN OR EXTRACT FROM THE FIFO WHEN THIS LOCK IS PUT ON (well, indeed, that's the use of this lock value! :)
	ProxyHttpData.lock = PROXYHTTP_LOCK_PROCESSING_REQUESTS;

	// process fifo, and reply to all defcom stored in it
	_PROXYHTTP_FIFO_Process(ProxyHttpData.mmachine);

	// all right, now we can do it again, if it's necessary
	ProxyHttpData.lock = PROXYHTTP_LOCK_FREE;
}










/************************************************/
/*                                              */
/* LRESULT CALLBACK _PROXYHTTP_ReadAuthInfos    */
/*                                              */
/* dialog callback. get the informations the    */
/* user entered.                                */
/*                                              */
/************************************************/
LRESULT CALLBACK _PROXYHTTP_ReadAuthInfos (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{

	switch (msg)
	{
		// dialog initialization
		case WM_INITDIALOG:
			// set texts
			SetDlgItemText (hDlg, IDC_Firewall, (LPCTSTR)ProxyHttpData.firewall);
			SetDlgItemText (hDlg, IDC_Domain, (LPCTSTR)ProxyHttpData.domain);
			
			//SetFocus (hDlg);
			//SetForegroundWindow (hDlg);
			SetFocus (hDlg);
			return TRUE;

		// dialog validation
		case WM_COMMAND:
			if (LOWORD(wParam) == IDOK)
			{
			char uname[256];
			char pword[256];
			char tmp[512];
			int useridSize;


				// get the values the user entered
				GetDlgItemText (hDlg, IDC_Uname, (LPTSTR)uname, 255);
				GetDlgItemText (hDlg, IDC_Pword, (LPTSTR)pword, 255);

				// encode and store the informations
				sprintf (tmp, "%s:%s", uname, pword);
				useridSize = _base64_getEncodedSize (strlen(tmp));

				//$ LB (23/08/2001) : store the uname field
				if (ProxyHttpData.uname) free (ProxyHttpData.uname);
				ProxyHttpData.uname = (char*) malloc ((strlen (uname)+1) * sizeof(char));
				strcpy (ProxyHttpData.uname, uname);

				//$ LB (23/08/2001) : store the pword field
				if (ProxyHttpData.pword) free (ProxyHttpData.pword);
				ProxyHttpData.pword = (char*) malloc ((strlen (pword)+1) * sizeof(char));
				strcpy (ProxyHttpData.pword, pword);


				if (ProxyHttpData.userid) free (ProxyHttpData.userid);
				ProxyHttpData.userid = (char*) malloc ((useridSize+1) * sizeof(char));
				if (base64_encode (ProxyHttpData.userid, &useridSize, tmp, strlen (tmp)) != BASE64_SUCCESS)
					return FALSE;

				* (ProxyHttpData.userid + useridSize) = '\0';

				ProxyHttpData.authorization = 1;
				ProxyHttpFifo.processState = PROXYHTTP_PROCESS_AUTHORIZED;

				EndDialog(hDlg, 1);
			}
			else if (LOWORD(wParam) == IDCANCEL)
			{
				ProxyHttpFifo.processState = PROXYHTTP_PROCESS_CANCELED;
				EndDialog(hDlg, 0);
			}

			return TRUE;
			break;
	}
    return FALSE;

}









/*******************************************/
/*                                         */
/* int _PROXYHTTP_DialogAuthInfos          */
/*                                         */
/* ask the user for the informations about */
/* proxy http authentication (dialog box)  */
/*                                         */
/*******************************************/
DWORD WINAPI _PROXYHTTP_DialogAuthInfos (mmachine m)
{


	// open dialog box
	DialogBox (scolDllInstance, MAKEINTRESOURCE(IDD_PROXYHTTP_AUTHENTICATION), NULL, (DLGPROC) _PROXYHTTP_ReadAuthInfos);


	
	ProxyHttpData.mmachine = m;
	PostMessage( hscol, WM_USER, PROXYHTTP_PROCESS_AUTHORIZATIONS, 0);

    ExitThread(0);
	return 0;	
}










/*****************************************************/
/*                                                   */
/* PROXYHTTP_GetAuthInfos (mmachine m, char *defcom) */
/*                                                   */
/* asks the user the http authentication infos,      */
/* if needed, and send them onto the master ch.      */
/*                                                   */
/*****************************************************/
int PROXYHTTP_GetAuthInfos (mmachine m, char *defcom)
{
DWORD dwThreadId; 
int channel, networkAPI, scolsuper, handle, force;
char defcomName[512];
char tmp[512];



	if (!ProxyHttpDataInit)
		_PROXYHTTP_DATA_Init();

	if (!ProxyHttpFifoInit)
		_PROXYHTTP_FIFO_Init();


	channel = MMgetglobal (m, OFFSCCUR);


	// get defcom data
	sscanf (defcom, "%s\t%d\t%d\t%d\t%d\t", (char*) defcomName, &networkAPI, &scolsuper, &handle, &force);
	sprintf (tmp, "%s\t%d\t%d\t%d\t%d\t", (char*) defcomName, networkAPI, scolsuper, handle, force);
	{
	char* data = defcom + strlen (tmp);
	char* ptr = strstr (data, "\t");

		// store the proxy ip (only to print it on the dialog)
		memcpy (ProxyHttpData.firewall, data, ptr - data);
		ProxyHttpData.firewall[ptr - data] = '\0';

		data = ptr+1;
		ptr = strstr (data, "\t");

		//store the proxy domain name (only to print it on the dialog)
		memcpy (ProxyHttpData.domain, data, ptr- data);
		ProxyHttpData.domain[ptr - data] = '\0';
	}




	

	// if another defcom has engage the dialog, wait for it
	if (ProxyHttpData.lock == PROXYHTTP_LOCK_RUNNING_DIALOG)
		_PROXYHTTP_FIFO_Add ( networkAPI, scolsuper, channel, handle, force);


	// if the user force the demand, or if the demand has never been done, 
	// engage dialog process, but wait for the previous one to end
	else
	if ((force) || (!force && !PROXYHTTP_IsAuthorized()))
	{
		// wait for previous thread to end
		while (ProxyHttpData.lock != PROXYHTTP_LOCK_FREE)
		{
			Sleep (500);
		}



		// store the defcom data
		_PROXYHTTP_FIFO_Add (networkAPI, scolsuper, channel, handle, force);

		// indicate you engage dialog <=> no other dialog could be engage then
		ProxyHttpData.lock = PROXYHTTP_LOCK_RUNNING_DIALOG;

		// dialog in a thread
		if (CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) _PROXYHTTP_DialogAuthInfos, 
				m, 0, &dwThreadId) == NULL) 
		{

			ProxyHttpData.lock = PROXYHTTP_LOCK_FREE;
			return -1;		
		}
		
	}

	// else send directly the infos
	else
		_PROXYHTTP_SendAuthInfos (m, networkAPI, scolsuper, channel, handle);

	
	return 0;
}










/*************************************************************************************/
/*                                                                                   */
/* int PROXYHTTP_AskAuthInfos (mmachine m, int networkAPI, int handle, int force)    */
/*                                                                                   */
/* make the client machine ask the main machine the informations                     */
/* about http authentication.                                                        */
/*                                                                                   */
/* char* networkAPI <=> PROXYHTTP_SCOL_NETWORK_API or PROXYHTTP_WININET_NETWORK_API  */
/*                                                                                   */
/* int handle       <=> if PROXYHTTP_SCOL_NETWORK_API                                */
/*                         <=> SOCKET sck                                            */
/*					else if PROXYHTTP_WININET_NETWORK_API                            */
/*						   <=> DWORD threadid                                        */
/*                                                                                   */
/* int force   <=> 1 to make the scol engine force the dialog,                       */
/*                 0 let it determine if the dialog is necessary                     */
/*                                                                                   */
/*************************************************************************************/
int PROXYHTTP_AskAuthInfos (mmachine m, int networkAPI, int handle, int force)
{
int p,k;
char defcom[512];
char *c;


	// defcom
	sprintf(defcom, "%s\t%d\t%d\t%d\t%d\t%s\t%s\t", PROXYHTTP_DEFCOM_AUTHENTICATION_REQUEST, networkAPI, ScolSuper, handle, force, ProxyHttpData.firewall, ProxyHttpData.domain);


	if (ScolSuper)
		PROXYHTTP_GetAuthInfos (m, defcom);

	else
	{
		// save the current channel
		if (MMpush (m, MMgetglobal (m, OFFSCCUR))) return MERRMEM;
		k=0;

		// select the master channel
		if (!SCselectcanal(m, socklife))
		{
			// fill the buffer with defcom and data
			if (Mpushstring(m, defcom)) return MERRMEM;
			c    = (char*)MMstart(m, MMget(m,0)>>1);
			p    = strlen(c)+1;
			c[0] = (p-2)&255;
			c[1] = ((p-2)>>8)&255;


			// send the defcom
			k    = SCsendpile(m);
		} 

		// get the saved channel
		MMsetglobal(m,OFFSCCUR,MMpull(m));	
	}

	return 0;
}






/******************************************************************/
/*                                                                */
/* int PROXYHTTP_IsAuthorized ()                                  */
/*                                                                */
/* returns 1 if the scol machine has already got the http         */
/* authentication infos, 0 if not                                 */ 
/*                                                                */
/******************************************************************/
int PROXYHTTP_IsAuthorized ()
{
	if (!ProxyHttpDataInit)
		_PROXYHTTP_DATA_Init();

	if (!ProxyHttpFifoInit)
		_PROXYHTTP_FIFO_Init();

	return ProxyHttpData.authorization;
}





/******************************************************************/
/*                                                                */
/* int PROXYHTTP_IsAuthorizationRejected (char* request)          */
/*                                                                */
/* returns 1 if the scol machine has already got the http         */
/* authentication infos, 0 if not                                 */ 
/*                                                                */
/******************************************************************/
int PROXYHTTP_IsAuthorizationRejected (char* request)
{
	if (strstr (request, PROXYHTTP_BASIC_AUTHORIZATION_FIELD) != NULL)
		return 1;

	return 0;
}





/************************************************************************/
/*                                                                      */
/* int PROXYHTTP_WININET_IsAuthenticated (HANDLE h)                     */
/*                                                                      */
/* check if a 407 HTTP error is contained in the header of proxy        */
/* http message.                                                        */
/*                                                                      */
/* returns 1 if 407 error and basic authentication needed,              */
/* 0 if not.                                                            */
/*                                                                      */
/************************************************************************/
int PROXYHTTP_WININET_IsAuthenticated (HANDLE h)
{
DWORD dwStatus;
DWORD dwStatusSize = sizeof(dwStatus);
char method [1024];
int methodSize = sizeof(method);
char* index, *index2;
int basicChallengeSize;
int realmSize;

	
	HttpQueryInfo ((HINTERNET)h, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE, &dwStatus, &dwStatusSize, NULL);

	// proxy authentication needed
	if (dwStatus == HTTP_STATUS_PROXY_AUTH_REQ)
	{
		HttpQueryInfo ((HINTERNET)h, HTTP_QUERY_PROXY_AUTHENTICATE, &method, &methodSize, NULL);

		// we only manage basic authentication challenge
		if ((index = strstr (method, PROXYHTTP_BASIC_CHALLENGE)))
		{
			// store the realm domain
			basicChallengeSize = strlen (PROXYHTTP_BASIC_CHALLENGE);
			index2 = strstr (index + basicChallengeSize, "\"");
			realmSize = index2 - index - basicChallengeSize;
			memcpy (&(ProxyHttpData.domain[0]), index + basicChallengeSize, realmSize);
			ProxyHttpData.domain[realmSize] = '\0';

			// don't know how to get the proxy ip with wininet... shame on me :(
			sprintf (ProxyHttpData.firewall, "WinInet Library");

			return 1;
		}
	}

	return 0;
}






/******************************************************************/
/*                                                                */
/* int PROXYHTTP_IsAuthenticated (char* header, int headerSize)   */
/*                                                                */
/* check if a 407 HTTP error is contained in the header of proxy  */
/* http message.                                                  */
/*                                                                */
/* returns 1 if 407 error, 0 if not.                              */
/*                                                                */
/******************************************************************/
int PROXYHTTP_IsAuthenticated (char* header, int headerSize)
{
char* index, *index2;
char errorCode[4];
int challengeSize, domainSize;
char challenge[1024];

	sprintf (challenge, "%s%s", PROXYHTTP_AUTHENTICATION_CHALLENGE_FIELD, PROXYHTTP_BASIC_CHALLENGE);


	// get the HTTP code
	index = strstr (header, " ");

	if (index >= header+headerSize)
		return 0;

	memcpy (errorCode, index+1, 3);
	errorCode[3] = '\0';

	// it's a 407 error code
	if (!strcmp (errorCode, HTTP_ERROR_PROXY_AUTHENTICATION_NEEDED))
	{
		// we only manage the Basic authentication challenge
		if ((index = strstr (header, challenge)))
			if (index < (header+headerSize))
				if ((index2 = strstr (index, "\r\n")))
				{
					// store the proxy domain name included in the request header
					challengeSize = strlen(challenge);
					domainSize = index2 - index - challengeSize;
					memcpy (&(ProxyHttpData.domain[0]), index + challengeSize, domainSize);
					if (ProxyHttpData.domain[domainSize - 1] == '\"')
						ProxyHttpData.domain[domainSize - 1] = '\0';
						else ProxyHttpData.domain[domainSize] = '\0';


					// store the proxy host name
					strcpy (&(ProxyHttpData.firewall[0]), http_proxy_host);
				}
				return 1;
	}			
	
	return 0;
}





char* PROXYHTTP_GetUname ()
{
	if (!PROXYHTTP_IsAuthorized())
		return NULL;

	return ProxyHttpData.uname;
}


char* PROXYHTTP_GetPword ()
{
	if (!PROXYHTTP_IsAuthorized())
		return NULL;

	return ProxyHttpData.pword;
}



char* PROXYHTTP_GetUserID()
{
	if (!PROXYHTTP_IsAuthorized())
		return NULL;

	return ProxyHttpData.userid;
}

