/*******************************************************************************
        ssl_form.c
        Z-World, 2003

        An example of a simple HTTP form generation and parsing
        program.  It includes an example of how to handle interdependent
        variables in the form (see the low and high temperature
        variables).

		  This program has been modified to use SSL via HTTPS. See the
        SSL comments below for more information.

	     See the SSL Walkthrough for information on creating certificates
        for SSL programs.

*******************************************************************************/
#class auto

/***********************************
 * Configuration                   *
 * -------------                   *
 * All fields in this section must *
 * be altered to match your local  *
 * network settings.               *
 ***********************************/

/*
 * Pick the predefined TCP/IP configuration for this sample.  See
 * LIB\TCPIP\TCP_CONFIG.LIB for instructions on how to set the
 * configuration.
 */
#define TCPCONFIG 1

/*
 * Web server configuration
 */

/*
 * only one socket and server are needed for a reserved port,
 * but to use HTTP and HTTPS on the same device, 2 servers
 * are needed, one for HTTP and one for HTTPS
 */
#define HTTP_MAXSERVERS 2
#define MAX_TCP_SOCKET_BUFFERS 2


// This macro determines the number of HTTP servers that will use
// SSL (HTTPS servers). In this case, we have 2 total servers, and
// this defines one of them to be HTTPS
#define HTTP_SSL_SOCKETS 1

/*
 * Size of the buffer that will be allocated to do error
 * processing during form parsing.  This buffer is allocated
 * in root RAM.  Note that it must be large enough to hold
 * the name, value, and 4 more bytes for each variable in the
 * form.
 *
 * This parameter must be defined in order to use the form
 * generation and parsing functionality.
 */
#define FORM_ERROR_BUF 256

/*
 * Define this if you do not need to use the http_flashspec array.
 * Since this program uses only the ZSERVER.LIB functionality,
 * then it does not need the http_flashspec array.
 */
#define HTTP_NO_FLASHSPEC

/*
 * This program does not need to do any DNS lookups, so it
 * disables them in order to save memory.  Note that resolve()
 * can still handle IP addresses with this option defined, but
 * it can not handle names.
 */
#define DISABLE_DNS

// SSL Stuff
// This macro tells the HTTP library to use SSL
#define USE_HTTP_SSL

// Import the certificate
#ximport "cert\mycert.dcc" SSL_CERTIFICATE


/********************************
 * End of configuration section *
 ********************************/

#memmap xmem
#use "dcrtcp.lib"
#use "http.lib"

/* the default mime type for '/' must be first */
const HttpType http_types[] =
{
   { ".html", "text/html", NULL}
};

/* The following variables will be included in the form */
int temphi;
int tempnow;
int templo;
float humidity;
char fail[21];

/* This function checks the low temperature against the new value for the
 * high temperature to make sure that the low temperature is not higher
 * than the high temperature.  To check against the new high temperature,
 * it must use the value in the error buffer. */
int checkLowTemp(int newval)
{
	auto char* var;
	auto char* value;
	auto long hightemp;

	var = http_finderrbuf("temphi");
	if (var != NULL) {
		http_nextfverr(var, NULL, &value, NULL, NULL);
		hightemp = strtol(value, NULL, 10);
		if (newval <= hightemp) {
			return 0;
		} else {
			return -1;
		}
	} else {
		if (newval <= temphi) {
			return 0;
		} else {
			return -1;
		}
	}
}

/* This function is like the above function, except that it checks the
 * high temperature. */
int checkHighTemp(int newval)
{
	auto char* var;
	auto char* value;
	auto long lowtemp;

	var = http_finderrbuf("templo");
	if (var != NULL) {
		http_nextfverr(var, NULL, &value, NULL, NULL);
		lowtemp = strtol(value, NULL, 10);
		if (newval >= lowtemp) {
			return 0;
		} else {
			return -1;
		}
	} else {
		if (newval <= templo) {
			return 0;
		} else {
			return -1;
		}
	}
}

void main(void)
{
	// Declare the FormVar array to hold form variable information
	auto FormVar myform[5];
	auto int var;
	auto int form;
	// This array lists the options that are possible for the fail variable
	static const char* const fail_options[] = {
		"Email",
		"Page",
		"Email and page",
		"Nothing"
	};

	// Initialize variables
	temphi = 80;
	tempnow = 72;
	templo = 65;
	humidity = 0.3;
	strcpy(fail, "Page");

	// Add the form (array of variables)
   // Note the use of SERVER_HTTPS instead of SERVER_HTTP. This means that
   // the form declared here is only accessible from an SSL-secured HTTPS
   // socket. If you want this form to be accessible from both HTTPS and
   // HTTP clients, then the final parameter would be
   // SERVER_HTTPS | SERVER_HTTP
	form = sspec_addform("myform.html", myform, 5, SERVER_HTTPS);

	// Set the title of the form
	sspec_setformtitle(form, "ACME Thermostat Settings");

	// Add the first variable, and set it up with the form
	var = sspec_addvariable("temphi", &temphi, INT16, "%d", SERVER_HTTPS);
	var = sspec_addfv(form, var);
	sspec_setfvname(form, var, "High Temp");
	sspec_setfvdesc(form, var, "Maximum in temperature range (60 - 90 &deg;F)");
	sspec_setfvlen(form, var, 5);
	sspec_setfvrange(form, var, 60, 90);
	sspec_setfvcheck(form, var, checkHighTemp);

	// Add the second variable, and set it up with the form
	var = sspec_addvariable("tempnow", &tempnow, INT16, "%d", SERVER_HTTPS);
	var = sspec_addfv(form, var);
	sspec_setfvname(form, var, "Current Temp");
	sspec_setfvdesc(form, var, "Current temperature in &deg;F");
	sspec_setfvlen(form, var, 5);
	sspec_setfvreadonly(form, var, 1);

	// Add the third variable, and set it up with the form
	var = sspec_addvariable("templo", &templo, INT16, "%d", SERVER_HTTPS);
	var = sspec_addfv(form, var);
	sspec_setfvname(form, var, "Low Temp");
	sspec_setfvdesc(form, var, "Minimum in temperature range (50 - 80 &deg;F)");
	sspec_setfvlen(form, var, 5);
	sspec_setfvrange(form, var, 50, 80);
	sspec_setfvcheck(form, var, checkLowTemp);

	// Add the fourth variable, and set it up with the form
	var = sspec_addvariable("failure", fail, PTR16, "%s", SERVER_HTTPS);
	var = sspec_addfv(form, var);
	sspec_setfvname(form, var, "Failure Action");
	sspec_setfvdesc(form, var, "Action to take in case of air-conditioning failure");
	sspec_setfvlen(form, var, 20);
	sspec_setfvoptlist(form, var, fail_options, 4);
	sspec_setfventrytype(form, var, HTML_FORM_PULLDOWN);

	// Add the fifth variable, and set it up with the form
	var = sspec_addvariable("humidity", &humidity, FLOAT32, "%.2f", SERVER_HTTPS);
	var = sspec_addfv(form, var);
	sspec_setfvname(form, var, "Humidity");
	sspec_setfvdesc(form, var, "Target humidity (between 0.0 and 1.0)");
	sspec_setfvlen(form, var, 8);
	sspec_setfvfloatrange(form, var, 0.0, 1.0);

	// Create aliases for this form.  This allows the form to be accessed from
	// other locations.
	sspec_aliasspec(form, "index.html");
	sspec_aliasspec(form, "/");

   sock_init();
   http_init();
   tcp_reserveport(80);

	// We need to reserve the HTTPS port as well, which is TCP port 443
   tcp_reserveport(443);

   while (1) {
      http_handler();
   }
}