			/* ------------------------------------- */
			//										 //
			//  +-+-+-+-+-+-+ +-+-+-+-+-+ +-+-+-+-+  //
			//  |S|i|m|p|l|e| |P|r|o|x|y| |2|0|0|4|  //
			//  +-+-+-+-+-+-+ +-+-+-+-+-+ +-+-+-+-+  //
			//										 //
			//										 //
			//  AUTOR : Aymeric  //
			//  DATE  : May 2004					 //
			//  FILE  : execution.c					 //
			//  DESC  : treat the message			 //
			//  									 //
			/* ------------------------------------- */


/************************************************************************/

#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#include "proxy.h"

/************************************************************************/
// FunctionName : execute
//
// Description  : treat the HTTP message passed in param.
//				  If the message is a request, determine if we can get
//				  the page from the cache (if the page exists).
//				  If the message is a response, determine if we can cache
//				  it, and send the page to the client
//
// Parameters
// [in]
//			char *buf             : HTTP message (request or response)
//			int csock             : current socket
//			char *url             : url asked by the client
//			int n                 : length of the buffer
//			struct sConfig config : used to say if we can cache or not
//			struct sLog *alog     : contain the IP connected to the socket
//									and the first line of the request
//									it will be used for the access_log file
//
// [out]
//			nothing
//
// Returns
//			bool : true if no problem
//
// Calls
//			init()           	    : initialise the structure headerHTTP
//			readHTTPHeader() 	    : to determine if it's a request or response
//							          message and set the correct parameters
//			CacheControlProcedure() : return if we can cache or not
//			PragmaProcedure()		: return if we can cache or not
//			ExpireProcedure()		: return if we can cache or not
//			checkCache()			: return if the page is cached
//			changeCache()			: modify the index file
//			saveCache()				: save the new cached file in index
//			filecache()				: put the buffer in the cached file
//			char_count()			: return the number of character
//			readFile()				: return the content of the file
//
// Globals
//			FILE *log	 	 : file id for the general log
//			FILE *access_log : file id for the access log
//			enum bool debug	 : if debug is true, we are in debug mode
//
/************************************************************************/

enum bool execute(char *buf, int csock, char *url, int n, struct sConfig config, struct sLog *alog)
{
	struct headerHTTP importantHeaders;
	struct sCache C;
	char result[50];
	struct sLog axxlog;

	init(&importantHeaders);

	/* readHTTPHeader return "requestMessage" if it's a request message
	   or responseMessage if it's a response message
	   or something else if there is an error in the message passed */
	strncpy(result,readHTTPHeader(buf,&importantHeaders,&axxlog),49);

	if (debug)
	{
		printf("[execute] RESULTAT => %s\n",result);

		if ( importantHeaders.StatusCode != 0 ) printf("[execute] StatusCode = %d\n",importantHeaders.StatusCode);
		if ( importantHeaders.URIproto != NULL ) printf("[execute] URIproto = %s\n",importantHeaders.URIproto);
		if ( importantHeaders.URIserv != NULL ) printf("[execute] URIserv = %s\n",importantHeaders.URIserv);
		if ( importantHeaders.URIpath != NULL ) printf("[execute] URIpath = %s\n",importantHeaders.URIpath);
		if ( importantHeaders.URIport != 0 ) printf("[execute] URIport = %d\n",importantHeaders.URIport);
		if ( importantHeaders.Host != NULL ) printf("[execute] Host = %s\n",importantHeaders.Host);
		if ( importantHeaders.CacheControl != NULL ) printf("[execute] CacheControl = %s\n",importantHeaders.CacheControl);
		if ( importantHeaders.MaxAge != 0 ) printf("[execute] MaxAge = %d\n",importantHeaders.MaxAge);
		if ( importantHeaders.Pragma != NULL ) printf("[execute] Pragma = %s\n",importantHeaders.Pragma);
		if ( importantHeaders.Date != 0 ) printf("[execute] Date = %d\n",importantHeaders.Date);
		if ( importantHeaders.Expires != 0 ) printf("[execute] Expires = %d\n",importantHeaders.Expires);
		if ( importantHeaders.ContentLength != 0 ) printf("[execute] ContentLength = %d\n",importantHeaders.ContentLength);
		if ( importantHeaders.Age != 0 ) printf("[execute] Age = %d\n",importantHeaders.Age);
	}

	if ( strcmp(result,"requestMessage") == 0 )
	{
		/* ----- REQUEST ----- */

		alog->firstline=(char *)calloc(sizeof(char),strlen(axxlog.firstline));
		strcpy(alog->firstline,axxlog.firstline);

		if (config.cache)
		{
			char CacheProcedure[20]="";
			char PragmaProc[20]="";
			char Expires[20]="";

			strcpy(url,importantHeaders.URIserv);
			strcat(url,importantHeaders.URIpath);

			if (debug) printf("[execute] URL = %s\n",url);

			if ( importantHeaders.CacheControl != NULL )
			{
				strncpy(CacheProcedure,CacheControlProcedure(&C,importantHeaders.CacheControl,importantHeaders.MaxAge,false),19);
				if (debug) printf("[execute] CacheProcedure = %s\n",CacheProcedure);
				free(importantHeaders.CacheControl);
			}
			else if ( importantHeaders.Pragma != NULL )
			{
				strncpy(PragmaProc,PragmaProcedure(importantHeaders.Pragma,&C,false),19);
				if (debug) printf("[execute] PragmaProc = %s\n",PragmaProc);
				free(importantHeaders.Pragma);
			}
			else
			{
				strcpy(CacheProcedure,"getFromCache");
			}

			C.cache=false;
			if ( (strcmp(CacheProcedure,"getFromCache") == 0) || (strcmp(PragmaProc,"getFromCache") == 0) )
			{
				/* we can use the page in the cache */
				if (debug) printf("[execute] We check if url in cache...\n");

				if ( checkCache(url,&C) == true )
				{
					/* the page exists in the cache directory */
					char *file;
					int size;
					time_t temps_act;

					fprintf(access_log,"%s %s FROM_CACHE/200 %s\n",logtime(),alog->hostname,alog->firstline);

					C.url=(char *)calloc(sizeof(char),strlen(url)+1);
					strcpy(C.url,url);

					file=(char *)calloc(sizeof(char),strlen(C.file)+strlen(CACHEDIR)+1);
					strcpy(file,CACHEDIR);
					strcat(file,C.file);

					size=char_count(file);

					if (debug) printf("[execute] %s is in the cache so we look into the file cache %s (size=%d)\n",C.url,file,size);

					write(csock,readFile(file,size),size);

					C.last_access=time(&temps_act);
					if (debug) printf("[execute] Changing access date (%d) in indexfile\n",C.last_access);

					changeCache(C);

					free(file);
					free(importantHeaders.URIserv);
					free(importantHeaders.URIproto);
					free(importantHeaders.URIpath);
					free(importantHeaders.HTTPversion);
					free(C.url);
					if ( importantHeaders.Host != NULL ) free(importantHeaders.Host);

					return(false);
				}

				free(importantHeaders.URIserv);
				free(importantHeaders.URIproto);
				free(importantHeaders.URIpath);
				free(importantHeaders.HTTPversion);
				if ( importantHeaders.Host != NULL ) free(importantHeaders.Host);

				if (debug) printf("[execute] Not in cache or expired url\n");
				return(true);
			}
		}

		free(importantHeaders.URIserv);
		free(importantHeaders.URIproto);
		free(importantHeaders.URIpath);
		free(importantHeaders.HTTPversion);
		if ( importantHeaders.Host != NULL ) free(importantHeaders.Host);
		if ( importantHeaders.CacheControl != NULL ) free(importantHeaders.CacheControl);
		if ( importantHeaders.Pragma != NULL ) free(importantHeaders.Pragma);

		return(true);
	}

	if ( strcmp(result,"responseMessage") == 0 )
	{
		/* ----- RESPONSE ----- */

		/* if in the config file we autorize the cache */
		if (config.cache)
		{
			char CacheProcedure[20]="";
			char PragmaProc[20]="";
			char Expires[20]="";

			if (debug) printf("[execute] URL = %s (StatusCode = %d)\n",url,importantHeaders.StatusCode);
			fprintf(access_log,"%s %s MISS_CACHE/%d %s\n",logtime(),alog->hostname,importantHeaders.StatusCode,alog->firstline);

			/* we cache only pages with the 200 StatusCode */
			if ( importantHeaders.StatusCode == 200 )
			{

				if ( importantHeaders.CacheControl != NULL )
				{
					strncpy(CacheProcedure,CacheControlProcedure(&C,importantHeaders.CacheControl,importantHeaders.MaxAge,true),19);
					if (debug) printf("[execute] CacheProcedure = %s and C->cache = %d\n",CacheProcedure,C.cache);
					free(importantHeaders.CacheControl);
				}
				else if ( importantHeaders.Pragma != NULL )
				{
					strncpy(PragmaProc,PragmaProcedure(importantHeaders.Pragma,&C,true),19);
					if (debug) printf("[execute] PragmaProc = %s and C->cache = %d\n",PragmaProc,C.cache);
					free(importantHeaders.Pragma);
				}
				else
				{
					C.cache=true;
					if (debug) printf("[execute] Default action (cache) -> OK !\n");
				}

				if ( (strcmp(CacheProcedure,"") != 0) && (strcmp(importantHeaders.CacheControl,"max-age") != 0) &&
					 (importantHeaders.Expires != 0) )
				{
					strncpy(Expires,ExpiresProcedure(&C,importantHeaders.Expires),19);
					if (debug) printf("[execute] Expires = %s\n",Expires);
					C.freshness=importantHeaders.Expires;
				}

				/* if headers say that we can cache */
				if ( C.cache == true )
				{
					time_t current;
					time_t age;

					current = time(NULL);

					if (debug) printf("[execute] We can cache this page !\n");

					C.url=(char *)calloc(sizeof(char),strlen(url)+1);
					strcpy(C.url,url);

					if ( (current - importantHeaders.Date) > importantHeaders.Age )
						age = current - importantHeaders.Date;
					else
						age = importantHeaders.Age;

					current = time(NULL);

					if ( importantHeaders.MaxAge != 0 )	C.freshness = current + age;
					else if ( importantHeaders.Expires != 0 ) C.freshness = current + (importantHeaders.Expires - importantHeaders.Date);
					else C.freshness = current + age;

					if (debug) printf("[execute] C.freshness = %d and current = %d and age = %d\n",C.freshness,current,age);

					/* we check if there is already the url in the index file */
					if ( checkCache(url,&C) == true )
					{
						current = time(NULL);
						C.last_access=current;

						if (debug)
							printf("[execute] Already in indexfile, so we change the record.\n");

						changeCache(C);
					}
					else
					{
						if (debug) printf("[execute] We save the new record in the indexfile\n");
						saveCache(&C);
					}

					if (debug) printf("[execute] Save the page in %s ...\n",C.file);
					fileCache(C.file,buf,n);
				}
			}
		}
		if (debug) printf("[execute] Send to the client\n");
		write(csock,buf,n);
	}

	errorPage(csock);

	free(C.url);

	return(false);
}

/************************************************************************/
// FunctionName : errorPage
//
// Description  : send an error page to the client
//
// Parameters
// [in]
//			int csock             : current socket
//
// [out]
//			nothing
//
// Returns
//			nothing
//
// Calls
//			nothing
//
// Globals
//			none
//
/************************************************************************/

void errorPage(int csock)
{
	time_t time_of_day;
	char *timeday;
	char *err;
	char t[10];
	int length;

	timeday=(char *)calloc(sizeof(char),150);
	time_of_day = time( NULL );
	strftime( timeday, 150, "%a, %d %b %Y %H:%M:%S GMT",localtime( &time_of_day ) );

	length=763+strlen(timeday);
	sprintf(t, "%d", length);

	err=(char *)calloc(sizeof(char),2000+3*strlen(timeday));
	strcpy(err,"HTTP/1.0 400 Bad Request\r\n");
	strcat(err,"Server: Simple Proxy 2004\r\nDate: ");
	strcat(err,timeday);
	strcat(err,"\r\nContent-Type: text/html\r\nContent-Length: ");
	strcat(err,t);
	strcat(err,"\r\nExpires: ");
	strcat(err,timeday);
	strcat(err,"\r\nProxy-Connection: close\r\n\r\n");
	strcat(err,"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n");
	strcat(err,"<HTML>\n<HEAD>\n<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=iso-8859-1\">\n");
	strcat(err,"<TITLE>ERROR: The requested URL could not be retrieved</TITLE>\n</HEAD>\n<BODY>\n<H1>ERROR</H1>\n");
	strcat(err,"<H2>The requested URL could not be retrieved</H2>\n<HR noshade size=\"1px\">\n<P>\n");
	strcat(err,"The following error was encountered:\n<UL>\n<LI>\n<STRONG>\nInvalid Request\n</STRONG>\n</UL>\n<P>\n");
	strcat(err,"Some aspect of the HTTP Request is invalid.  Possible problems:\n<UL>\n<LI>Missing or unknown request method\n");
	strcat(err,"<LI>Missing URL\n<LI>Missing HTTP Identifier (HTTP/1.0)\n</UL>\n<BR clear=\"all\">\n<HR noshade size=\"1px\">\n");
	strcat(err,"<ADDRESS>\nGenerated ");
	strcat(err,timeday);
	strcat(err,"(Simple Proxy 2004)\n</ADDRESS>\n</BODY>\n</HTML>\n");

	write(csock,err,strlen(err));

	free(err);
}

