/* -------------------------------------------------------------------- */
/* SMS Client, send messages to mobile phones and pagers		*/
/*									*/
/* http.c								*/
/*									*/
/*  Copyright (C) 1997,1998,1999 Angelo Masci				*/
/*									*/
/*  This library is free software; you can redistribute it and/or	*/
/*  modify it under the terms of the GNU Library General Public		*/
/*  License as published by the Free Software Foundation; either	*/
/*  version 2 of the License, or (at your option) any later version.	*/
/*									*/
/*  This library 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	*/
/*  Library General Public License for more details.			*/
/*									*/
/*  You should have received a copy of the GNU Library General Public	*/
/*  License along with this library; if not, write to the Free		*/
/*  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.	*/
/*									*/
/*  You can contact the author at this e-mail address:			*/
/*									*/
/*  angelo@styx.demon.co.uk						*/
/*									*/
/* -------------------------------------------------------------------- */
/* $Id$
   -------------------------------------------------------------------- */

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <ctype.h>


#include "url.h"
#include "base64.h"
#include "tcpip.h"
#include "logfile/logfile.h"
#include "common/common.h"
#include "http_tread.h"
#include "http_twrite.h"
#include "error.h"

/* -------------------------------------------------------------------- */

#define BLK_SIZE 4096
#define HTTP_WRITETIMEOUT NULL
#define HTTP_READTIMEOUT  NULL

/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
char *slurp_data(int fd, int *filelen)
{
	char 	*query_string;

	int 	total_read, 
		len, 
		max_len,
		bytes_read;


	query_string = (char *)malloc(sizeof(char) * (BLK_SIZE +1));
	if (query_string == NULL)
	{
		lprintf(LOG_ERROR, "malloc() failed\n");
		exit(EMALLOC);
	}


	total_read = 0;
	len        = BLK_SIZE;
	max_len    = BLK_SIZE;

	bytes_read = http_tread(fd, &query_string[total_read], len, HTTP_READTIMEOUT);
	if (bytes_read == -1)
	{
		free(query_string);
		return NULL;
	}

	while(bytes_read != 0)
	{	
		len        -= bytes_read;
		total_read += bytes_read;

		if (len == 0)
		{	
			query_string = (char *)realloc(query_string, sizeof(char) * (max_len + BLK_SIZE +1));
			if (query_string == NULL)
			{	return NULL;
			}

			len      = BLK_SIZE;
			max_len += BLK_SIZE;
		}

		bytes_read = http_tread(fd, &query_string[total_read], len, HTTP_READTIMEOUT);
		if (bytes_read == -1)
		{
			free(query_string);
			return NULL;
		}
	}

	*filelen = total_read;
	return query_string;
}


/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
char *get_document(char *url, int *data_len, char *method, char *data, char *authentication, char *referer)
{
	char 	send_buf[1024],
		*proxy,
		*auth,
		*mdata;

	int 	sockfd,
		proxy_connect;

	URL	tmp_url,
		proxy_url;



	lprintf(LOG_VERYVERBOSE, "----------------------------\n");
	lprintf(LOG_VERYVERBOSE, "HTTP Document request '%s'\n", url);
	lprintf(LOG_VERYVERBOSE, "METHOD:    '%s'\n", method);
	lprintf(LOG_VERYVERBOSE, "DATA:      '%s'\n", (data == NULL?"NULL":data));
	lprintf(LOG_VERYVERBOSE, "AUTH:      '%s'\n", (authentication == NULL?"NULL":authentication));
	lprintf(LOG_VERYVERBOSE, "----------------------------\n");
	
	if (parse_url(url, &tmp_url) == -1)
	{
		lprintf(LOG_ERROR, "Parsing URL '%s'\n", url);
		return NULL;
	}

	lprintf(LOG_VERYVERBOSE, "----------------------------\n");
	lprintf(LOG_VERYVERBOSE, "Decomposed URL              \n");
	lprintf(LOG_VERYVERBOSE, "----------------------------\n");
	lprintf(LOG_VERYVERBOSE, "HOST:      '%s'\n", tmp_url.host);
	lprintf(LOG_VERYVERBOSE, "PORT:      '%s'\n", tmp_url.port);
	lprintf(LOG_VERYVERBOSE, "DOCUMENT:  '%s'\n", tmp_url.document);
	lprintf(LOG_VERYVERBOSE, "DIRECTORY: '%s'\n", tmp_url.directory);
	lprintf(LOG_VERYVERBOSE, "FILENAME:  '%s'\n", tmp_url.filename);
	lprintf(LOG_VERYVERBOSE, "----------------------------\n");

	proxy_connect = FALSE;
	if ((proxy = getenv("HTTP_PROXY")) != NULL)
	{
		proxy_connect = TRUE;


		lprintf(LOG_VERBOSE, "Connecting using proxy '%s'\n", proxy);

		if (parse_url(proxy, &proxy_url) == -1)
		{
			lprintf(LOG_ERROR, "Parsing proxy URL '%s'\n", proxy);

			free_url(&tmp_url);
			return NULL;
		}


		sockfd = TCPIP_connect(proxy_url.host, atoi(proxy_url.port));
		if (sockfd == -1)
		{
			lprintf(LOG_ERROR, "Connecting to '%s:%s'\n", proxy_url.host, proxy_url.port);
			
			free_url(&tmp_url);
			free_url(&proxy_url);
			return NULL;
		}

		free_url(&proxy_url);
	}
	else
	{	sockfd = TCPIP_connect(tmp_url.host, atoi(tmp_url.port));
		if (sockfd == -1)
		{
			lprintf(LOG_ERROR, "Connecting to '%s:%s'\n", tmp_url.host, tmp_url.port);

			free_url(&tmp_url);
			return NULL;
		}
	}



	/* ------------------------------------ */
	/* Send the request for the page.	*/
	/* Using HTTP protocol version 1.0	*/


	if (proxy_connect)
	{
		sms_snprintf(send_buf, 1024, "%s http://%s:%s%s HTTP/1.0\r\n", method, tmp_url.host, tmp_url.port, tmp_url.document);
	}
	else
	{	sms_snprintf(send_buf, 1024, "%s %s HTTP/1.0\r\n", method, tmp_url.document);
	}

	http_twrite(sockfd, send_buf, strlen(send_buf), HTTP_WRITETIMEOUT);

	/* ------------------------------------ */

#if 1

/* At some point I need to build a complete	*/
/* http 1.0 compliant header.			*/
/* for now we'll skip some fields.		*/

	if (referer == NULL)
	{	sms_snprintf(send_buf, 1024, "Referer: %s\r\n", url);
	}
	else
	{	sms_snprintf(send_buf, 1024, "Referer: %s\r\n", referer);
	}

	http_twrite(sockfd, send_buf, strlen(send_buf), HTTP_WRITETIMEOUT);

	sms_snprintf(send_buf, 1024, "Proxy-Connection: %s\r\n", "Keep-Alive");
	http_twrite(sockfd, send_buf, strlen(send_buf), HTTP_WRITETIMEOUT);

	sms_snprintf(send_buf, 1024, "User-Agent: %s\r\n", "SMSClient");
	http_twrite(sockfd, send_buf, strlen(send_buf), HTTP_WRITETIMEOUT);

	if (proxy != NULL)
	{
		/* Send proxy related data.		*/

		sms_snprintf(send_buf, 1024, "Host: %s:%s\r\n", tmp_url.host, tmp_url.port);
		http_twrite(sockfd, send_buf, strlen(send_buf), HTTP_WRITETIMEOUT);
	}

	sms_snprintf(send_buf, 1024, "Accept: %s\r\n", "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*");
	http_twrite(sockfd, send_buf, strlen(send_buf), HTTP_WRITETIMEOUT);

	sms_snprintf(send_buf, 1024, "Content-type: %s\r\n", "application/x-www-form-urlencoded");
	http_twrite(sockfd, send_buf, strlen(send_buf), HTTP_WRITETIMEOUT);

#endif


	if (authentication != NULL)
	{
		/* Send Authentication.			*/
		/* Base64 Encode 'username:password' 	*/


		auth = encodeBase64(authentication);
		if (auth != NULL)
		{
			lprintf(LOG_VERBOSE, "Using Authentication Basic '%s'\n", auth);

			sms_snprintf(send_buf, 1024, "Authorization: Basic %s\r\n", auth);
			http_twrite(sockfd, send_buf, strlen(send_buf), HTTP_WRITETIMEOUT);

			free(auth);
		}
		else
		{	lprintf(LOG_ERROR, "Building authentication data\n");

			free_url(&tmp_url);
			return NULL;
		}
	}

	if (data != NULL)
	{
		/* Send data appropriate to method.	*/
		/* POST or GET				*/

		if (strcmp(method, "GET") == 0)
		{	lprintf(LOG_ERROR, "Data supplied whilst method is 'GET'\n");

			free_url(&tmp_url);
			return NULL;
		}
		else
		if (strcmp(method, "POST") == 0)
		{
			sms_snprintf(send_buf, 1024, "Content-length: %d\r\n", strlen(data));
			http_twrite(sockfd, send_buf, strlen(send_buf), HTTP_WRITETIMEOUT);
		}
		else
		{	lprintf(LOG_ERROR, "Data supplied whilst using Unsupport Method '%s'\n", method);

			free_url(&tmp_url);
			return NULL;
		}
	}

	http_twrite(sockfd, "\r\n", strlen("\r\n"), HTTP_WRITETIMEOUT);


	/* ---------------------------- */
	/* Ouput data for POST method 	*/

	if (data != NULL)
	{	http_twrite(sockfd, data, strlen(data), HTTP_WRITETIMEOUT);
	}

	/* ---------------------------- */


	mdata = slurp_data(sockfd, data_len);
	if (mdata == NULL)
	{
		lprintf(LOG_ERROR, "Receiving data from server\n");
	}


	TCPIP_disconnect(sockfd);
	free_url(&tmp_url);
	return mdata;
}


/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
char *get_simple_document(char *url, int *data_len)
{
	return get_document(url, data_len, "GET", NULL, NULL, NULL);
}


/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
char *escape_input(char *src)
{
	char 	*buf, 
		*dst,
		*table = "0123456789ABCDEF";

	int	high,
		low;



	buf = (char *)malloc(sizeof(char) * ((strlen(src) * 3) +1));
	if (buf == NULL)
	{
		lprintf(LOG_ERROR, "malloc() failed\n");
		exit(EMALLOC);
	}


	dst = buf;
	while(*src != '\0') 
	{
		if (isalnum(*src))
		{
			*dst++ = *src;
		}
		else
		if (*src == ' ')
		{
			*dst++ = '+';
		}
		else
		{	

			low  = *src % 16;
			high = ((int)(*src / 16 )) % 16;

			*dst++ = '%';
			*dst++ = table[high];
			*dst++ = table[low];
		}
		
		src++;
	}

	*dst = '\0';
	return buf;
}

