/*******************************************/
/* DESCRIPTION */

// This file contains the code to hide a data stream in a HTTP stream.


/*******************************************/
/* INCLUDES */

#ifndef __TCP_BY_HTTP_TUNNEL_H__
#define __TCP_BY_HTTP_TUNNEL_H__
#include "encap.h"
#include <ctype.h>
#include <string.h>


/*******************************************/
/* DEFINES AND ENUM */

// We use those strings to fake an HTTP session.
#define HTTP_BEGIN_STRING_C  	"GET /cgi-bin/db_query?param1=foo&param2=bar&encap_data="
#define HTTP_END_STRING_C	" HTTP/1.0\r\n"\
				"Connection: Keep-Alive\r\n"\
				"User-Agent: Mozilla (X11; I; Linux 2.0.32 i586)\r\n"\
				"Host: www.google.ca\r\n"\
				"Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*\r\n"\
				"Accept-Encoding: gzip\r\n"\
				"Accept-Language: en\r\n"\
				"Accept-Charset: iso-8859-1,*,utf-8\r\n"\
				"\r\n"

#define HTTP_BEGIN_STRING_S	"HTTP/1.1 200 OK\r\n"\
				"Server: Apache/1.3.12 (Unix) mod_perl/1.23^M\r\n"\
				"Accept-Ranges: bytes\r\n"\
				"Content-Length: "

#define HTTP_LENGTH_STRING_S	"%d\r\n"

#define HTTP_END_STRING_S	"Connection: close\r\n"\
				"Content-Type: image/jpeg\r\n"\
				"\r\n"


/*******************************************/
/* PROTOTYPES */

void http_flush_msg(char *buf, int *buf_index, int buf_size,
		    round_buf * out_rb_ptr);
int url_decode(char *source, int size);
int url_encode(const char *source, int size, char *dest);


class http_l_encoder:public data_stream_encoder {
  public:

    bool msg_to_flush;
    char *msg;
    int msg_size;
    int msg_index;

     http_l_encoder() {
	msg_to_flush = 0;
    } virtual ~ http_l_encoder() {
	if (msg_to_flush)
	    delete[]msg;
    }

    int http_l_encoder::encode(round_buf * in_rb_ptr,
			       round_buf * out_rb_ptr);
    int http_l_encoder::build_message(round_buf * in_rb_ptr,
				      round_buf * out_rb_ptr);
    int http_l_encoder::flush_msg(round_buf * out_rb_ptr);
    bool http_l_encoder::has_unflushed_data();
};


class http_l_decoder:public data_stream_decoder {
  public:

    bool msg_to_flush;
    char *buf;
    int buf_size;
    int buf_used_size;
    int msg_index;
    int encoded_data_size;

     http_l_decoder() {
	msg_to_flush = 0;
	buf_size = 10;
	buf_used_size = 0;
	msg_index = 0;
	buf = (char *) my_malloc(buf_size);
    } virtual ~ http_l_decoder() {
	free(buf);
    }

    int http_l_decoder::decode(round_buf * in_rb_ptr,
			       round_buf * out_rb_ptr);
    int http_l_decoder::build_message(round_buf * in_rb_ptr,
				      round_buf * out_rb_ptr);
    int http_l_decoder::get_header(round_buf * in_rb_ptr,
				   round_buf * out_rb_ptr);
    int http_l_decoder::get_data(round_buf * in_rb_ptr,
				 round_buf * out_rb_ptr);
    int http_l_decoder::flush_msg(round_buf * out_rb_ptr);
    bool http_l_decoder::has_unflushed_data();
};


class http_r_encoder:public data_stream_encoder {
  public:

    bool msg_to_flush;
    char *msg;
    int msg_size;
    int msg_index;

     http_r_encoder() {
	msg_to_flush = 0;
    } virtual ~ http_r_encoder() {
	if (msg_to_flush)
	    delete[]msg;
    }

    int http_r_encoder::encode(round_buf * in_rb_ptr,
			       round_buf * out_rb_ptr);
    int http_r_encoder::build_message(round_buf * in_rb_ptr,
				      round_buf * out_rb_ptr);
    int http_r_encoder::flush_msg(round_buf * out_rb_ptr);
    bool http_r_encoder::has_unflushed_data();
};


class http_r_decoder:public data_stream_decoder {
  public:

    bool msg_to_flush;
    char *buf;
    int buf_size;
    int buf_used_size;
    int msg_index;

     http_r_decoder() {
	msg_to_flush = 0;
	buf_size = 10;
	buf_used_size = 0;
	buf = (char *) my_malloc(buf_size);
    } virtual ~ http_r_decoder() {
	free(buf);
    }

    int http_r_decoder::decode(round_buf * in_rb_ptr,
			       round_buf * out_rb_ptr);
    int http_r_decoder::build_message(round_buf * in_rb_ptr,
				      round_buf * out_rb_ptr);
    int http_r_decoder::flush_msg(round_buf * out_rb_ptr);
    bool http_r_decoder::has_unflushed_data();
};


class tcp_by_http_tunnel:public tcp_by_generic_tcp {
  public:

    virtual int get_l2r_coder(data_stream_encoder ** encoder,
			      data_stream_decoder ** decoder) {
	*encoder = new http_l_encoder;
	*decoder = new http_l_decoder;

	return 0;
    } virtual int get_r2l_coder(data_stream_encoder ** encoder,
				data_stream_decoder ** decoder) {
	*encoder = new http_r_encoder;
	*decoder = new http_r_decoder;

	return 0;
    }
};

#endif
