/*
	ZazouMiniWebServer

	Copyright (C) 2003-2011 Xavier Garreau <xavier@xgarreau.org>

	This file is part of ZazouMiniWebServer.

    ZazouMiniWebServer is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    ZazouMiniWebServer is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with ZazouMiniWebServer; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
*/
	
#include "stdafx.h"
#include "ZMWSOptParser.h"

const char* ZMWSOptParser::valid_options[] = {
							"-help                : Print this help\n",
							"-hide                : Hide the console. Console is displayed by default.\n",
							"-quiet               : Mute server. Default is to be verbose.\n",
							"-stop                : Stop server if /_stopServer.zmwsc is requested.\n",
							"-dropclients         : Kill client connections on stop.\n",
							"-closebrowser        : Close browser if /_stopServer.zmwsc is requested (use only with -stop).\n",
							"-browse              : Browse the website after server is launched. Default is disabled.\n",
							"-nolog               : Disable logging. Default is enabled.\n",
							"-logsdir <directory> : Path to logs. Default is logs/\n  * EXAMPLE: -logsdir f:/logs\n",
							"-revdns              : Enable reverse DNS. Deafult is disabled.\n",
							"-noindex             : Disable directory indexing. Default is enabled.\n",
							"-p <port>            : Port to use. Default is 80\n",
							"-sp <port>           : HTTPS Port to use. Default is 443\n",
							"-bind <IP>           : IP to listen to. Default is to listen to all.\n",
							"-allowfrom <IP|IPMASK>;<IP|IPMASK>;...\n                     : Allow from specific IPs. Default is to allow from all.\n",
							"-denyfrom <IP|IPMASK>;<IP|IPMASK>;...\n                     : Deny from specific IPs. Default is to deny from none.\n",
							"-unique-port         : If port 80 or set by option -p is in use, quit. Default is to try ports 8080 to 8089\n",
							"-conf <cnf file>     : Path to configuration file. Default is ./_config.zmwsc\n",
							"-phppath <path>      : Path to php.exe. Defaults are c:/php, c:/php4, c:/php5 php5/ and php/\n",
							"-webdir <directory>  : Path to html server docs. Default is _web.zmwsc/ or ./\n",
							"-mc				  : Max client connections. (Default: 1000)\n",
							NULL
							};

BOOL ZMWSOptParser::Parse(int argc, char** argv, ZMWSConfig& config)
{
	int i=0;
	std::string optvar, optval;
	BOOL isError = FALSE;

	while (++i<argc) {
		optvar = std::string(argv[i]);

		// Une option commence par '-'
		if (optvar[0] != '-') {
			PrintWarning ("Ignored token "+optvar+"Maybe you should try -"+optvar+" or -help ?");
			continue;
		}
		
		optvar = std::string(argv[i]).substr(1);

/*
 * Help
 */
		if (optvar == "help") {
			WORD j=0;
			std::string tmpS  = "\n----------------------------------------\n";
			tmpS += "Command line help:\nThese options are recognized :\n";
			while (valid_options[j]) {
				tmpS += valid_options[j++];
			}
			tmpS += "\n----------------------------------------\n";
			print_dbg (tmpS.c_str());
			isError = TRUE;
			continue;
		}

/*
 * Hide Console
 */
		if (optvar == "hide") {
			config.SetHideConsole(true);
			config.SetBeQuiet(true);
			continue;
		}

/*
 * Be Quiet
 */
		if (optvar == "quiet") {
			config.SetBeQuiet(true);
			continue;
		}

/*
 * Can Stop
 */
		if (optvar == "stop") {
			config.SetCanStop(true);
			continue;
		}

/*
 * Can Close Browser
 */
		if (optvar == "closebrowser") {
			config.SetCloseBrowser(true);
			continue;
		}

/*
 * Browsing
 */
		if (optvar == "browse") {
			config.SetBrowseNow(true);
			continue;
		}

/*
 * Drop Client connections on stop
 */
		if (optvar == "dropclients") {
			config.SetDropClients(true);
			continue;
		}

/*
 * Logging
 */
		if (optvar == "nolog") {
			config.SetWriteLogs(false);
			continue;
		}

/*
 * Reverse DNS
 */
		if (optvar == "norv") {
			// Ignored, deprecated since 0.9.7
			continue;
		}
		if (optvar == "revdns") {
			config.SetReverseDNS(true);
			continue;
		}

/*
 * Indexing
 */
		if (optvar == "noindex") {
			config.SetCanIndex(false);
			continue;
		}

/*
 * Port
 */
		if (optvar == "p") {
			if (!(++i<argc)) {
				PrintError("-p", "port MUST be a valid port (a number) !\nUSAGE        : -p <port> (default is 80)");
				isError = TRUE;
				continue;
			}

			// On cherche la valeur
			optval = argv[i];
			if (optval[0] == '-') {
				PrintError("-p", "port MUST be a valid port (a number) !\nUSAGE        : -p <port> (default is 80)");
				isError = TRUE;
				continue;
			}
			if (optval=="httpsonly" || optval=="0") {
				config.SetPort(0);
			} else {
				WORD port = (WORD)(0xFFFF & strtoul(optval.c_str(), NULL, 10));
				
				if (port) {
					config.SetPort(port);
				} else {
					PrintError("-p", "port MUST be a valid port (a number) !\nUSAGE        : -p <port> (default is 80)");
					isError = TRUE;
				}
			}
			continue;
		}

/*
 * Secure Port
 */
		if (optvar == "sp") {
			if (!(++i<argc)) {
				PrintError("-sp", "port MUST be a valid port (a number) !\nUSAGE        : -sp <port> (default is 443)");
				isError = TRUE;
				continue;
			}

			// On cherche la valeur
			optval = argv[i];
			if (optval[0] == '-') {
				PrintError("-sp", "port MUST be a valid port (a number) !\nUSAGE        : -sp <port> (default is 443)");
				isError = TRUE;
				continue;
			}
			if (optval=="httponly" || optval=="0") {
				config.SetHTTPSPort(0);
			} else {
				WORD port = (WORD)(0xFFFF & strtoul(optval.c_str(), NULL, 10));
				
				if (port) {
					config.SetHTTPSPort(port);
				} else {
					PrintError("-sp", "port MUST be a valid port (a number) !\nUSAGE        : -sp <port> (default is 443)");
					isError = TRUE;
				}
			}
			continue;
		}

/*
 * Don't try other ports
 */
		if (optvar == "unique-port") {
			config.SetTry808xPorts(false);
			continue;
		}

/*
 * Max clients
 */
		if (optvar == "mc") {
			if (!(++i<argc)) {
				PrintError("-mc", "maxClients MUST be a number !\nUSAGE        : -mc <maxClients> (default is 1000)");
				isError = TRUE;
				continue;
			}

			// On cherche la valeur
			optval = argv[i];
			if (optval[0] == '-') {
				PrintError("-mc", "maxClients MUST be a number !\nUSAGE        : -mc <maxClients> (default is 1000)");
				isError = TRUE;
				continue;
			}
			DWORD mc = strtoul(optval.c_str(), NULL, 10);
			if (mc) {
				config.SetMaxClients(mc);
			} else {
				PrintError("-mc", "maxClients MUST be a number !\nUSAGE        : -mc <maxClients> (default is 1000)");
				isError = TRUE;
			}
			continue;
		}


/*
 * Config file Path
 */
		if (optvar == "conf") {
			if (!(++i<argc)) {
				PrintError("-conf", "Bad path to configuration file !\nUSAGE        : -conf <cnf file>");
				isError = TRUE;
				continue;
			}

			// On cherche la valeur
			optval = argv[i];
			if (optval[0] == '-') {
				PrintError("-conf", "Bad path to configuration file !\nUSAGE        : -conf <cnf file>");
				isError = TRUE;
				continue;
			}
			if (optval[0] == '"') {
				while ((i<argc) && (optval[optval.length()-1]!='\"')) {
					optval += argv[++i];
				}
				if (i>=argc) {
					PrintError("-conf", "Unterminated quoted string !\nUSAGE        : -conf <cnf file>");
					isError = TRUE;
					continue;
				}
				optval = optval.substr(1, optval.length()-2);
			}
			if (optval.length()) {
				if (!config.SetPathToConfigFile(optval)) {
					PrintError("-conf", "Bad path to configuration file !\nUSAGE        : -conf <cnf file>");
					isError = TRUE;
				}
			} else {
				PrintError("-conf", "Bad path to configuration file !\nUSAGE        : -conf <cnf file>");
				isError = TRUE;
			}
			continue;
		}

/*
 * PHP Path
 */
		if (optvar == "phppath") {
			if (!(++i<argc)) {
				PrintError("-phppath", "Bad path to php executable !\nUSAGE        : -phppath <path>");
				isError = TRUE;
				continue;
			}

			// On cherche la valeur
			optval = argv[i];
			if (optval[0] == '-') {
				PrintError("-phppath", "Bad path to php executable !\nUSAGE        : -phppath <path>");
				isError = TRUE;
				continue;
			}
			if (optval[0] == '"') {
				while ((i<argc) && (optval[optval.length()-1]!='\"')) {
					optval += argv[++i];
				}
				if (i>=argc) {
					PrintError("-phppath", "Unterminated quoted string !\nUSAGE        : -phppath <path>");
					isError = TRUE;
					continue;
				}
				optval = optval.substr(1, optval.length()-2);
			}
			if (optval.length()) {
				if (!config.SetPathToPHP(optval)) {
					PrintError("-phppath", "Bad path to php executable !\nUSAGE        : -phppath <path>");
					isError = TRUE;
				}
			} else {
				PrintError("-phppath", "Bad path to php executable !\nUSAGE        : -phppath <path>");
				isError = TRUE;
			}
			continue;
		}

/*
 * IP to bind to
 */
		if (optvar == "bind") {
			if (!(++i<argc)) {
				PrintError("-bind", "Bad IP !\nUSAGE        : -bind <IP>");
				isError = TRUE;
				continue;
			}

			// On cherche la valeur
			optval = argv[i];
			if (optval[0] == '-') {
				PrintError("-bind", "Bad IP !\nUSAGE        : -bind <IP>");
				isError = TRUE;
				continue;
			}
			if (optval[0] == '"') {
				while ((i<argc) && (optval[optval.length()-1]!='\"')) {
					optval += argv[++i];
				}
				if (i>=argc) {
					PrintError("-bind", "Bad IP !\nUSAGE        : -bind <IP>");
					isError = TRUE;
					continue;
				}
				optval = optval.substr(1, optval.length()-2);
			}
			if (optval.length()) {
				config.SetBindAddr(optval);
			} else {
				PrintError("-bind", "Bad IP !\nUSAGE        : -bind <IP>");
				isError = TRUE;
			}
			continue;
		}

/*
* Allowed Client IP
*/
		if (optvar == "allowfrom") {
			if (!(++i<argc)) {
				PrintError("-allowfrom", "Bad argument !\nUSAGE        : -allowfrom <IP|IPMASK>;<IP|IPMASK>;...");
				isError = TRUE;
				continue;
			}

			// On cherche la valeur
			optval = argv[i];
			if (optval[0] == '-') {
				PrintError("-allowfrom", "Bad argument !\nUSAGE        : -allowfrom <IP|IPMASK>;<IP|IPMASK>;...");
				isError = TRUE;
				continue;
			}
			if (optval[0] == '"') {
				while ((i<argc) && (optval[optval.length()-1]!='\"')) {
					optval += argv[++i];
				}
				if (i>=argc) {
					PrintError("-allowfrom", "Bad argument !\nUSAGE        : -allowfrom <IP|IPMASK>;<IP|IPMASK>;...");
					isError = TRUE;
					continue;
				}
				optval = optval.substr(1, optval.length()-2);
			}
			if (optval.length()) {
				config.SetAllowFrom(optval);
			} else {
				PrintError("-allowfrom", "Bad argument !\nUSAGE        : -allowfrom <IP|IPMASK>;<IP|IPMASK>;...");
				isError = TRUE;
			}
			continue;
		}

/*
* Denied Client IP
*/
		if (optvar == "denyfrom") {
			if (!(++i<argc)) {
				PrintError("-denyfrom", "Bad argument !\nUSAGE        : -denyfrom <IP|IPMASK>;<IP|IPMASK>;...");
				isError = TRUE;
				continue;
			}

			// On cherche la valeur
			optval = argv[i];
			if (optval[0] == '-') {
				PrintError("-denyfrom", "Bad argument !\nUSAGE        : -denyfrom <IP|IPMASK>;<IP|IPMASK>;...");
				isError = TRUE;
				continue;
			}
			if (optval[0] == '"') {
				while ((i<argc) && (optval[optval.length()-1]!='\"')) {
					optval += argv[++i];
				}
				if (i>=argc) {
					PrintError("-denyfrom", "Bad argument !\nUSAGE        : -denyfrom <IP|IPMASK>;<IP|IPMASK>;...");
					isError = TRUE;
					continue;
				}
				optval = optval.substr(1, optval.length()-2);
			}
			if (optval.length()) {
				config.SetDenyFrom(optval);
			} else {
				PrintError("-denyfrom", "Bad argument !\nUSAGE        : -denyfrom <IP|IPMASK>;<IP|IPMASK>;...");
				isError = TRUE;
			}
			continue;
		}

/*
 * Web Dir
 */
		if (optvar == "webdir") {
			if (!(++i<argc)) {
				PrintError("-webdir", "Bad path !\nUSAGE        : -webdir <dir>");
				isError = TRUE;
				continue;
			}

			// On cherche la valeur
			optval = argv[i];
			if (optval[0] == '-') {
				PrintError("-webdir", "Bad path !\nUSAGE        : -webdir <dir>");
				isError = TRUE;
				continue;
			}
			if (optval[0] == '"') {
				while ((i<argc) && (optval[optval.length()-1]!='\"')) {
					optval += argv[++i];
				}
				if (i>=argc) {
					PrintError("-webdir", "Unterminated quoted string !\nUSAGE        : -phppath <path>");
					isError = TRUE;
					continue;
				}
				optval = optval.substr(1, optval.length()-2);
			}
			if (optval.length()) {
				if (!config.SetDocumentRoot(optval)) {
					PrintError("-webdir", "Bad path !\nUSAGE        : -webdir <dir>");
					isError = TRUE;
				}
			} else {
				PrintError("-webdir", "Bad path !\nUSAGE        : -webdir <dir>");
				isError = TRUE;
			}
			continue;
		}

/*
 * Logs Dir
 */
		if (optvar == "logsdir") {
			if (!(++i<argc)) {
				PrintError("-logsdir", "Bad path !\nUSAGE        : -logsdir <dir>");
				isError = TRUE;
				continue;
			}

			// On cherche la valeur
			optval = argv[i];
			if (optval[0] == '-') {
				PrintError("-logsdir", "Bad path !\nUSAGE        : -logsdir <dir>");
				isError = TRUE;
				continue;
			}
			if (optval[0] == '"') {
				while ((++i<argc) && (optval[optval.length()-1]!='\"')) {
					optval += argv[i];
				}
				if (i>=argc) {
					PrintError("-logsdir", "Unterminated quoted string !\nUSAGE        : -phppath <path>");
					isError = TRUE;
					continue;
				}
				optval = optval.substr(1, optval.length()-2);
			}
			if (optval.length()) {
				if (!config.SetLogsDir(optval)) {
					PrintError("-logsdir", "Bad path !\nUSAGE        : -logsdir <dir>");
					isError = TRUE;
				}
			} else {
				PrintError("-logsdir", "Bad path !\nUSAGE        : -logsdir <dir>");
				isError = TRUE;
			}
			continue;
		}

/*
 * Unknown option
 */
			PrintError("-"+optvar, "Unknown option. Try -help :-)");
			isError = TRUE;
			continue;
	}
	return !isError;
}

void ZMWSOptParser::PrintError(const std::string& option, const std::string& error_text)
{
	std::string tmpS;
	tmpS  = "\n----------------------------------------\n";
	tmpS += "ERROR        : option ";
	tmpS += option;
	tmpS += "\nERROR MESSAGE: ";
	tmpS += error_text;
	tmpS += "\n----------------------------------------\n";
	print_dbg(tmpS.c_str());
}

void ZMWSOptParser::PrintWarning(const std::string& warning_text)
{
	std::string tmpS;
	tmpS  = "\n----------------------------------------\n";
	tmpS += "WARNING: ";
	tmpS += warning_text;
	tmpS += "\n----------------------------------------\n";
	print_dbg(tmpS.c_str());
}
