/*
 * Copyright (c) 1999-2000 Caucho Technology.  All rights reserved.
 *
 * Caucho Technology permits redistribution, modification and use
 * of this file in source and binary form ("the Software") under the
 * Caucho Public License ("the License").  In particular, the following
 * conditions must be met:
 *
 * 1. Each copy or derived work of the Software must preserve the copyright
 *    notice and this notice unmodified.
 *
 * 2. Redistributions of the Software in source or binary form must include 
 *    an unmodified copy of the License, normally in a plain ASCII text
 *
 * 3. The names "Resin" or "Caucho" are trademarks of Caucho Technology and
 *    may not be used to endorse products derived from this software.
 *    "Resin" or "Caucho" may not appear in the names of products derived
 *    from this software.
 *
 * 4. Caucho Technology requests that attribution be given to Resin
 *    in any manner possible.  We suggest using the "Resin Powered"
 *    button or creating a "powered by Resin(tm)" link to
 *    http://www.caucho.com for each page served by Resin.
 *
 * This Software is provided "AS IS," without a warranty of any kind. 
 * ALL EXPRESS OR IMPLIED REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
 * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.

 * CAUCHO TECHNOLOGY AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES
 * SUFFERED BY LICENSEE OR ANY THIRD PARTY AS A RESULT OF USING OR
 * DISTRIBUTING SOFTWARE. IN NO EVENT WILL CAUCHO OR ITS LICENSORS BE LIABLE
 * FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
 * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
 * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
 * INABILITY TO USE SOFTWARE, EVEN IF HE HAS BEEN ADVISED OF THE POSSIBILITY
 * OF SUCH DAMAGES.
 *
 * @author Scott Ferguson
 *
 * $Id: iis_srun.cpp,v 1.8 2000/03/29 18:55:05 ferg Exp $
 */

#include <windows.h>
#include <stdio.h>
#include <httpext.h>
#include <httpfilt.h>
#include <tchar.h>
#include "iis_srun.h"
#include "../../../win32/common/common.h"
extern "C" {
#include "../common/cse.h"
}

#define ISAPI_SCRIPT "/scripts/iis_srun.dll"

extern int cse_handle_request(config_t *, EXTENSION_CONTROL_BLOCK *);
extern void log(char *fmt, ...);

static config_t *config;

static HINSTANCE g_hInstance;
static char *g_dll_name;

void die(char *msg, ...) {}

static HINSTANCE AfxGetResourceHandle()
{
	return g_hInstance;
}

static int
parseResinIni(FILE *file, char *resinConf)
{
	char key[1024];

	while (! feof(file)) {
		int ch;
		int i = 0;

		for (ch = fgetc(file); ch > 0 && ! isspace(ch); ch = fgetc(file))
			key[i++] = ch;
		key[i] = 0;
			
		for (; ch == ' ' || ch == '\t'; ch = fgetc(file)) {
		}

		i = 0;
		for (; ch > 0 && ch != '\n'; ch = fgetc(file))
			resinConf[i++] = ch;
		resinConf[i] = 0;
		for (i--; i >= 0 && isspace(resinConf[i]); i--)
			resinConf[i] = 0;

		if (! strcmp(key, "CauchoConfigFile"))
			return 1;
	}

	return 0;
}

static void
findResinConf(char *resinConf, char *pwd)
{
	sprintf(resinConf, "%s/resin.ini", pwd);

	FILE *file = fopen(resinConf, "r");
	if (file) {
		int found = parseResinIni(file, resinConf);
		fclose(file);
		if (found)
			return;
	}

	char *resin_home = get_resin_home(0, pwd);

	if (resin_home) {
		sprintf(resinConf, "%s\\conf\\resin.conf", resin_home);
		return;
	}

	int i;
	for (i = strlen(pwd) - 1; i >= 0 && pwd[i] != '/' && pwd[i] != '\\'; i--) {
	}
	if (i >= 0)
		pwd[i] = 0;

	sprintf(resinConf, "%s/resin.conf", pwd);
}

BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO* pVer)
{
	LOG(("start extension\n"));

	// Load description string
	TCHAR sz[HSE_MAX_EXT_DLL_NAME_LEN+1];
	LoadString(AfxGetResourceHandle(), IDS_SERVER, sz, HSE_MAX_EXT_DLL_NAME_LEN);
	_tcscpy(pVer->lpszExtensionDesc, sz);

	char dllName[1024];
	char resinConf[1024];
	GetModuleFileName(AfxGetResourceHandle(), dllName, sizeof(dllName));
	int i;

	if (config)
		return TRUE;

	for (i = strlen(dllName) - 1; i >= 0 && dllName[i] != '/' && dllName[i] != '\\'; i--) {
	}

	for (i--; i >= 0 && dllName[i] != '/' && dllName[i] != '\\'; i--) {
	}

	if (i < 0)
		i = 0;
	dllName[i] = 0;
	findResinConf(resinConf, dllName);

	config = (config_t *) malloc(sizeof (config_t));
	memset(config, 0, sizeof(config_t));
	//config->srun_host = 0;
	//config->srun_port = 6802;
	config->path = strdup(resinConf);

	cse_init_config(config);

	return TRUE;
}

///////////////////////////////////////////////////////////////////////
// CIis_srunExtension command handlers

DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *pECB)
{
	if (cse_handle_request(config, pECB))
		return HSE_STATUS_SUCCESS;
	else
		return HSE_STATUS_ERROR;
}

BOOL WINAPI TerminateExtension(DWORD dwFlags)
{
	LOG(("terminate\n"));

	return TRUE;
}


BOOL WINAPI GetFilterVersion(HTTP_FILTER_VERSION *pVer)
{
	LOG(("start filter\n"));

	TCHAR sz[SF_MAX_FILTER_DESC_LEN+1];
	LoadString(AfxGetResourceHandle(), IDS_SERVER, sz, SF_MAX_FILTER_DESC_LEN);
	_tcscpy(pVer->lpszFilterDesc, sz);

	pVer->dwFilterVersion = HTTP_FILTER_REVISION;

	pVer->dwFlags = SF_NOTIFY_ORDER_DEFAULT|SF_NOTIFY_PREPROC_HEADERS|SF_NOTIFY_LOG;

	char dllName[1024];
	GetModuleFileName(AfxGetResourceHandle(), dllName, sizeof(dllName));
	int i;

	if (config)
		return TRUE;

	for (i = strlen(dllName) - 1; i >= 0 && dllName[i] != '/' && dllName[i] != '\\'; i--) {
	}

	if (i < 0)
		i = 0;
	dllName[i] = 0;
	char resinConf[4096];

	findResinConf(resinConf, dllName);
	LOG(("loading %s as config %x\n", resinConf, config));

	config = (config_t *) malloc(sizeof (config_t));
	memset(config, 0, sizeof(config_t));
	config->path = strdup(resinConf);

	cse_init_config(config);

	return TRUE;
}

DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc, DWORD notificationType, LPVOID pvNotification)
{
	char url[8192];
	unsigned long size = sizeof(url);

	char query = 0;
	unsigned int query_index = 0;
	HTTP_FILTER_PREPROC_HEADERS *headers;

	switch (notificationType) {
	case SF_NOTIFY_PREPROC_HEADERS:
		headers = (HTTP_FILTER_PREPROC_HEADERS *) pvNotification;

        if (! pfc->pFilterContext) {
			pfc->pFilterContext = pfc->AllocMem(pfc, 8192, 0);
			if (! pfc->pFilterContext ) {
				SetLastError(ERROR_NOT_ENOUGH_MEMORY);
				return SF_STATUS_REQ_ERROR;
			}
		}
		if (pfc->pFilterContext)
			((char *) pfc->pFilterContext)[0] = 0;

		if (headers->GetHeader(pfc, "URL", url, &size) && size > 0) {
			url[size] = 0;

			if (! strncmp(url, ISAPI_SCRIPT, strlen(ISAPI_SCRIPT)))
				return SF_STATUS_REQ_NEXT_NOTIFICATION;
	
			for (unsigned int query_index = 0; query_index < size; query_index++) {
				if (url[query_index] == '?') {
					query = url[query_index];
					url[query_index] = 0;
					break;
				}
			}

			if (cse_match_request(config, "", 0, url) ||
				! config->disable_caucho_status &&
				! strcmp(url, "/caucho-status")) {
				char newurl[8192];
	
				url[query_index] = query;
				strcpy(newurl, ISAPI_SCRIPT);
				strcat(newurl, url);
				headers->SetHeader(pfc, "URL", newurl);  

				strcpy((char *) pfc->pFilterContext, url);
				((char *) pfc->pFilterContext)[query_index] = 0;
			}
		}
		break;
	
	case SF_NOTIFY_LOG:
		if (pfc->pFilterContext && ((char *) pfc->pFilterContext)[0]) {
			char *pch = (char *) pfc->pFilterContext;
			HTTP_FILTER_LOG *pLog = (HTTP_FILTER_LOG *) pvNotification;
			
			pLog->pszTarget = pch;
		}
		break;
	}

	return SF_STATUS_REQ_NEXT_NOTIFICATION;
}

BOOL WINAPI DllMain(HINSTANCE hInst, ULONG ulReason, LPVOID lpReserved)
{
	if (ulReason == DLL_PROCESS_ATTACH) {
		g_hInstance = hInst;
	}

	return TRUE;
}
