

//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
//_/_/
//_/_/  This file is part of CMSDK version 2.0.0.170915_Beta4 (15 September 2017)
//_/_/  
//_/_/  developed by
//_/_/  
//_/_/  Communicative Machines Ltd. 
//_/_/    http://cmlabs.com/
//_/_/  Copyright (c) 2017
//_/_/  
//_/_/  in collaboration with 
//_/_/  
//_/_/  Icelandic Institute for Intelligent Machines ses
//_/_/    Menntavegur 1
//_/_/    101 Reykjavik
//_/_/    ICELAND
//_/_/    http://www.iiim.is/
//_/_/
//_/_/  and is released under the following
//_/_/  
//_/_/  EXTENDED BSD License
//_/_/
//_/_/  Redistribution and use in source and binary forms, with or without
//_/_/  modification, is permitted provided that the following conditions 
//_/_/  are met:
//_/_/
//_/_/  - Redistributions of source code must retain the above copyright 
//_/_/    and collaboration notice, this list of conditions and the following 
//_/_/    disclaimer.
//_/_/
//_/_/  - Redistributions in binary form must reproduce the above copyright 
//_/_/    notice, this list of conditions and the following disclaimer in the 
//_/_/    documentation and/or other materials provided with the distribution.
//_/_/
//_/_/  - Neither the name of its copyright holders nor the names of its 
//_/_/    contributors may be used to endorse or promote products derived from 
//_/_/    this software without specific prior written permission.
//_/_/
//_/_/  - CADIA Clause: The license granted in and to the software under this 
//_/_/    agreement is a limited-use license. The software may not be used in 
//_/_/    furtherance of: (i) intentionally causing bodily injury or severe 
//_/_/    emotional harm to any person; (ii) invading the personal privacy or 
//_/_/    violating the human rights of any person; or (iii) committing or 
//_/_/    preparing for any act of war. 
//_/_/
//_/_/  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
//_/_/  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
//_/_/  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
//_/_/  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 
//_/_/  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
//_/_/  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
//_/_/  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
//_/_/  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
//_/_/  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
//_/_/  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
//_/_/  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//_/_/
//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
#if !defined(_NETWORKPROTOCOLS_H_)
#define _NETWORKPROTOCOLS_H_

#pragma once

#include "DataMessage.h"
#include "NetworkConnections.h"

#define PROTOCOL_HTTP_SERVER	1
#define PROTOCOL_HTTP_CLIENT	2
#define PROTOCOL_MESSAGE		4
#define PROTOCOL_TELNET			8
#define PROTOCOL_3GCAM			16
#define ENCRYPTION_SSL			1
#define ENCRYPTION_AES			2

namespace	cmlabs{

/////////////////////////////////////////////////////////////
// Data Types
/////////////////////////////////////////////////////////////

#define HTTP_GET		1
#define HTTP_PUT		2
#define HTTP_POST		3
#define HTTP_HEAD		4
#define HTTP_DELETE		5
#define HTTP_OPTIONS	6

static char HTTP_Type[][8] =
{
"",
"GET",
"PUT",
"POST",
"HEAD",
"DELETE",
"OPTIONS"
};

// 
//GET /path/file.html HTTP/1.0
//From: someuser@jmarshall.com
//User-Agent: HTTPTool/1.0
//if-modified-since: Sat, 29 Oct 1994 19:43:31 GMT
//[blank line here]
//
//POST /path/script.cgi HTTP/1.0
//From: frog@jmarshall.com
//User-Agent: HTTPTool/1.0
//Content-Type: application/x-www-form-urlencoded
//Content-Length: 32
//
//home=Cosby&favorite+flavor=flies
//

class HTTPPostEntry {
public:
	HTTPPostEntry() { content = NULL; contentSize = 0; }
	virtual ~HTTPPostEntry() { delete [] content; }

	bool isValid() {
		return ( name.length() && content && contentSize );
	}
	bool setContent(const char* content, uint32 size) {
		if (!content) return false;
		this->contentSize = size;
		this->content = new char[size+1];
		memcpy(this->content, content, size);
		this->content[size] = 0;
		return true;
	}

	std::string name;
	std::string filename;
	std::string type;
	uint32 contentSize;
	char* content;
};

class HTTPRequest {
public:
//	HTTPRequest(uint64 startRecTime = 0);
	HTTPRequest(uint64 source = 0, uint64 startRecTime = 0);
	HTTPRequest(HTTPRequest* req);
	virtual ~HTTPRequest();

	// Reading it in from a socket
	bool processHeader(const char* buffer, uint32 size, bool &isInvalid);
	bool processContent(const char* buffer, uint32 size);
	const char* getHeaderEntry(const char* entry);
	const char* getRequest();
	const char* getURI();
	const char* getProtocol();
	const char* getParameter(const char* entry);
	const char* getPostData(const char* entry, uint32& size, const char** type);
	const char* getPostData(const char* entry, uint32& size);
	const char* getPostDataType(const char* entry);
	bool parseURIParameters(const char* text);
	bool parseContentParameters(const char* content, uint32 size);
	bool parseContentChunk(const char* chunk, uint32 size);

	DataMessage* convertToMessage();

	const char* getContent(uint32& size);

	bool createRequest(uint8 type, const char* host, const char* uri, const char* content, uint32 contentSize, bool keepAlive, uint64 ifModifiedSince);
	uint32 getSize();
	
	uint8 type;
	uint64 time;
	uint64 endReceiveTime;
	uint64 source;
	uint32 headerLength;
	uint32 contentLength;
	uint64 ifModifiedSince;
	bool keepAlive;
	char* data;

	std::map<std::string, std::string> entries;
	std::map<std::string, std::string> params;
	std::map<std::string, HTTPPostEntry*> postEntries;
	std::string postBoundary;
};

#define TELNET_WINDOWS	1
#define TELNET_UNIX		2

class TelnetLine {
public:
	TelnetLine(uint64 source);
	virtual ~TelnetLine();

	bool setLine(const char* buffer, bool addCR);
	bool setLine(const char* buffer, uint32 len, bool addCR = false);
	bool giveData(char* buffer, uint32 len);
	uint32 getSize();
	bool setCR(uint8 type);

	char* data;
	char cr[3];
	uint64 time;
	uint64 source;
	uint32 size;
	uint32 user;
};

// HTTP/1.0 200 OK
// HTTP/1.0 500 Internal Server Error  <H1>Error while creating internal page</H1>
// HTTP/1.0 200 OK
// Cache-Control: No-Cache
// HTTP/1.0 404 Object Not Found   <H1>File not found</H1>
// HTTP/1.0 403 Access Forbidden   <H1>Access Denied</H1>

#define HTTP_OK						0
#define HTTP_MOVED_PERMANENTLY		1
#define HTTP_USE_LOCAL_COPY			2
#define HTTP_MALFORMED_URL			3
#define HTTP_UNAUTHORIZED			4
#define HTTP_ACCESS_DENIED			5
#define HTTP_FILE_NOT_FOUND			6
#define HTTP_INTERNAL_ERROR			7
#define HTTP_NOT_IMPLEMENTED		8
#define HTTP_SERVICE_NOT_AVAILABLE	9
#define HTTP_GATEWAY_TIMEOUT		10
#define HTTP_SERVER_UNAVAILABLE		11
#define HTTP_SERVER_NOREPLY			12
#define HTTP_SERVER_MALFORMED_REPLY	13

static char HTTP_Status[][128] =
{
"HTTP/1.1 200 OK",
"HTTP/1.1 301 Moved Permanently",
"HTTP/1.1 304 Use Local Copy",
"HTTP/1.1 400 Bad Request <H1>Malformed URL</H1>",
"HTTP/1.1 401 Unauthorized",
"HTTP/1.1 403 Access Denied",
"HTTP/1.1 404 Object Not Found",
"HTTP/1.1 500 Internal Server Error  <H1>Error while creating page</H1>",
"HTTP/1.1 501 Not Implemented  <H1>Not implemented</H1>",
"HTTP/1.1 503 Service Unavailable  <H1>Service Unavailable</H1>",
"HTTP/1.1 504 Gateway Timeout  <H1>Gateway Timeout</H1>",
"HTTP/1.1 500 Internal Server Error  <H1>Server unavailable</H1>",
"HTTP/1.1 500 Internal Server Error  <H1>No reply from server</H1>",
"HTTP/1.1 500 Internal Server Error  <H1>Malformed server reply</H1>"
};

class HTTPReply {
public:
	static HTTPReply* CreateErrorReply(uint8 type);

	HTTPReply(uint64 source = 0);
	HTTPReply(HTTPReply* reply);
	virtual ~HTTPReply();
	
	// Reading it in from a socket
	bool processHeader(const char* buffer, uint32 size, bool &isInvalid);
	bool processContent(const char* buffer, uint32 size);
	const char* getHeaderEntry(const char* entry);
	const char* getProtocol();

	const char* getContent(uint32& size);

	// Generating the data
	bool createPage(uint8 status, uint64 time, const char* serverName,
		uint64 lastMod, bool keepAlive, bool cache, const char* contentType,
		const char* content, uint32 contentSize = 0);

	bool createFromFile(uint64 time, const char* serverName,
		uint64 ifLastMod, bool keepAlive, bool cache,
		const char* filename);

	bool createOptionsResponse(uint8 status, uint64 time, const char* serverName, bool keepAlive, const char* origin, const char* operations);
	bool createErrorPage(uint8 status, uint64 time, const char* serverName, bool keepAlive);

	uint32 getSize();

	uint8  type;
	uint64 time;
	uint64 source;
	uint32 headerLength;
	uint32 contentLength;
	bool keepAlive;
	char* data;

	std::map<std::string, std::string> entries;
	std::map<std::string, std::string> params;
};


/////////////////////////////////////////////////////////////
// Auto Detect Protocols
/////////////////////////////////////////////////////////////

class NetworkProtocol {
public:
	uint8 protocol;
	NetworkProtocol() {protocol = 0;}
	static bool CheckBufferForCompatibility(const char* buffer, uint32 length) {return false;};
	static bool InitialiseConversation(NetworkConnection* con) {return false;};
};

class HTTPProtocol : public NetworkProtocol
{
public:
	HTTPProtocol() {protocol = PROTOCOL_HTTP_SERVER;}
	static bool CheckBufferForCompatibility(const char* buffer, uint32 length);
	static bool InitialiseConversation(NetworkConnection* con);
	static bool SendHTTPReply(NetworkConnection* con, HTTPReply* reply);
	static HTTPReply* ReceiveHTTPReply(NetworkConnection* con, uint32 timeout);
	static bool SendHTTPRequest(NetworkConnection* con, HTTPRequest* req);
	static HTTPRequest* ReceiveHTTPRequest(NetworkConnection* con, uint32 timeout);
};

class HTTPClientProtocol : public NetworkProtocol
{
public:
	HTTPClientProtocol() {protocol = PROTOCOL_HTTP_CLIENT;}
	static bool CheckBufferForCompatibility(const char* buffer, uint32 length);
	static bool InitialiseConversation(NetworkConnection* con);
	static bool SendHTTPReply(NetworkConnection* con, HTTPReply* reply);
	static HTTPReply* ReceiveHTTPReply(NetworkConnection* con, uint32 timeout);
	static bool SendHTTPRequest(NetworkConnection* con, HTTPRequest* req);
	static HTTPRequest* ReceiveHTTPRequest(NetworkConnection* con, uint32 timeout);
};

class MessageProtocol : public NetworkProtocol
{
public:
	MessageProtocol() {protocol = PROTOCOL_MESSAGE;}
	static bool CheckBufferForCompatibility(const char* buffer, uint32 length);
	static bool InitialiseConversation(NetworkConnection* con);
	static bool SendMessage(NetworkConnection* con, DataMessage* msg, uint64 receiver = 0);
	static DataMessage* ReceiveMessage(NetworkConnection* con, uint32 timeout);
};

class TelnetProtocol : public NetworkProtocol
{
public:
	TelnetProtocol() {protocol = PROTOCOL_TELNET;}
	static bool CheckBufferForCompatibility(const char* buffer, uint32 length);
	static bool InitialiseConversation(NetworkConnection* con);
	static bool SendTelnetLine(NetworkConnection* con, TelnetLine* line);
	static TelnetLine* ReceiveTelnetLine(NetworkConnection* con, uint32 timeout);
	static TelnetLine* ReceiveTelnetLine(NetworkConnection* con, uint32 timeout, uint32 size);
};

}

#endif // _NETWORKPROTOCOLS_H_
