/*****
* httpget.c : simple command line interface for retrieving a HTTP page
*
* This file Version	$Revision$
*
* Creation date:		Mon Oct 27 13:44:10 MET 1997
* Last modification: 	$Date$
* By:					$Author$
* Current State:		$State$
*
* Author:				Koen D'Hondt
*
* Copyright (C) 1994-1997 by Ripley Software Development 
* All Rights Reserved
*
* This file is part of the XmHTML Widget Library.
*
* 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.
*
*****/
/*****
* ChangeLog
* $Log$
*****/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

#include <errno.h>

#include <http/HTTP.h>

/*** External Function Prototype Declarations ***/

/*** Public Variable Declarations ***/
#ifdef DEBUG
extern int http_debug;
#endif

/*** Private Datatype Declarations ****/

/*** Private Function Prototype Declarations ****/
static void emitError(const char *msg, int error);
static char *gettemp(void);

/*** Private Variable Declarations ***/
#define PLAIN		0
#define HTML		1

static int return_http_error, save_error_text = 1;
static int output_error_format = HTML, output_to_stdout, head_only = 0;
static char *output;
static char *cookiefile;

static char *usage = {"httpget: retrieve a HTTP document\n"
"\nUsage: httpget -rsiq -f[p|h] -o [file] url\n"
"Where:\n"
"\turl      : document to receive. Given as [http://]server/[document]\n"
"\t-o [file]: name of destination file. If not given stdout is used\n"
"\t-c [file]: name of cookie file. If not given no cookies are sent\n"
"\t-i       : only get document info (HEAD)\n"
"\t-s       : save HTTP error to output on failure\n"
"\t-f[p|h]  : output format for errors: plain or html\n"
"\t-t [num] : timeout in seconds, default is 5\n"
"\t-r [num] : retry count, default is 0\n"
"\t-x       : use HTTP error code as exit value\n"
#ifdef DEBUG
"\t-d       : HTTP debug mode\n"
#endif
"\t-h       : show this help.\n"};

static void
emitError(const char *msg, int error)
{
	FILE *out;

	if(save_error_text)
	{
		if(output_to_stdout)
			out = stdout;
		else
		{
			if((out = fopen(output, "w")) == NULL)
				out = stdout;
		}
	}
	else
		out = stdout;
	if(output_error_format == HTML)
	{
		fputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\">\n"
			"<HTML><HEAD><TITLE>\n", out);
		if(error)
			fprintf(out, "HTTP/1.X Error: %i\n", error);
		else
			fprintf(out, "Error\n");
		fputs("</TITLE></HEAD>\n"
			"<body text=\"#0\" bgcolor=\"#cccccc\">\n"
			"<div align=right><font face=\"arial,helvetica\" size=\"+1\">"
			"Unable to complete HTTP request&nbsp;&nbsp\n</font>\n"
			"</div><hr noshade size=\"2\"><p>\n", out);
	}
	fputs(msg, out);
	fputs("\n", out);

	if(output_error_format == HTML)
	{
		fputs("<p>\n<hr noshade size=\"2\">\n<div align=\"right\">"
			"<font size=\"-1\"><i>\n"
			"Last Updated: "
			__DATE__
			"<br>\nQuestion? Mail <a href=\"mailto:ripley@xs4all.nl\">"
			"httpget</a>\n</i></font></div>\n"
			"</BODY></HTML>\n", out);
	}
	fflush(out);
	fclose(out);

	if(return_http_error && error)
		exit(error);
	exit(EXIT_FAILURE);
}

static char*
gettemp(void)
{
	static char buf[1024];
	char *tmp;
	if((tmp = getenv("TMP")) == NULL)
		if((tmp = getenv("TMPDIR")) == NULL)
			if((tmp = getenv("TEMP")) == NULL)
				if((tmp = getenv("TEMPDIR")) == NULL)
					tmp = "/tmp";
	sprintf(buf, "%s%s%i.http_get", tmp,
		(tmp[strlen(tmp)-1] == '/' ? "" : "/"), (int)time(NULL));
	return(buf);
}

/*****
* Name:
* Return Type:
* Description:
* In:
*
* Returns:
*
*****/
int
main(int argc, char **argv)
{
	HTTPRequest *req = NULL;
	int i, j;
	char *url = NULL;
	char msg[1024];
	int timeout = 5, retry = 0;
	HTTPCookieCache *cc = NULL;
	HTTPCookieRequest *cookieReq = NULL;

	if(argc == 1)
	{
		fprintf(stderr, "%s", usage);
		exit(EXIT_FAILURE);
	}

	/* parse command line */
	for(i = 1; i < argc; i++)
	{
		if(argv[i][0] == '-')
		{
			for(j = 1; j < strlen(argv[i]); j++)
			{
				switch(argv[i][j])
				{
#ifdef DEBUG
					case 'd':
						http_debug = 1;
						break;
#endif
					case 'i':
						head_only = i;
						break;
					case 'h':
						fprintf(stderr, "%s", usage);
						exit(EXIT_FAILURE);
					case 'c':
						if(i+1 != argc)
						{
							if(argv[i+1][0] != '-')
								cookiefile = argv[i+1];
							j = strlen(argv[i+1]);
							i++;
						}
						else
						{
							if(i+1 == argc)
								emitError("missing arg for -c", 0);
						}
						break;
					case 'o':
						if(i+1 != argc)
						{
							if(argv[i+1][0] != '-')
								output = argv[i+1];
							j = strlen(argv[i+1]);
							i++;
						}
						else
						{
							if(i+1 == argc)
								emitError("missing arg for -o", 0);
						}
						break;
					case 'x':
						return_http_error = 1;
						break;
					case 's':
						save_error_text = 1;
						break;
					case 'f':
						if(j+1 == strlen(argv[i]))
							emitError("missing flag to -f", 0);

						if(argv[i][j+1] == 'p')
							output_error_format = PLAIN;
						else if(argv[i][j+1] == 'h')
							output_error_format = HTML;
						else
							emitError("unknown flag to -f", 0);
						j++;
						break;
					case 't':
						if(i+1 != argc)
						{
							if(argv[i+1][0] != '-')
								timeout = atoi(argv[i+1]);
							else
								emitError("bad argument for -t", 0);
							j = strlen(argv[++i]);
						}
						else
						{
							if(i+1 == argc)
								emitError("missing flag to -t", 0);
						}
						break;
					case 'r':
						if(i+1 != argc)
						{
							if(argv[i+1][0] != '-')
								retry = atoi(argv[i+1]);
							else
								emitError("bad argument for -r", 0);
							j = strlen(argv[++i]);
						}
						else
						{
							if(i+1 == argc)
								emitError("missing flag to -t", 0);
						}
						break;
					default:
						fprintf(stderr, "Unknown option: %c\n", argv[i][j]);
						fprintf(stderr, "%s", usage);
						exit(EXIT_FAILURE);
						break;
				}
			}
		}
		else
		{
			if(url == NULL)
				url = argv[i];
		}
	}
	if(url == NULL)
		emitError("missing url: don't know what to fetch!", 0);

	if(output == NULL)
	{
		output = gettemp();
		output_to_stdout = 1;
	}

	if(cookiefile != NULL)
	{
		printf("using '%s' as the cookie file\n",cookiefile);
		cc = loadCookieFileToCache(cookiefile, NetscapeCookieFile);
	}
	
#ifdef NEED_SOCKS
	SOCKSinit("httpget");
#endif

	if((req = newHTTPRequest()) == NULL)
		emitError("Out of memory: can't allocate a new HTTP request!", 0);

	req->type   = HTTPLoadToFile;
	req->method = head_only ? HTTPHEAD : HTTPGET;
	req->in_data = strdup(output);
	req->retry = retry;
	req->timeout = timeout;

	/* no http:// given */
	if(!HTTPAbsoluteURL(url))
	{
		req->url = (char*)calloc(8 + strlen(url), sizeof(char));
		strcpy(req->url, "http://");
		strcat(req->url, url);
	}
	else
		req->url = strdup(url);
	
	if(cc)
		cookieReq = getCookieFromCache(cc, req->url);

	loadHTTPURL(NULL, req, (void *) cookieReq );
	
	/*****
	* This is a one shot operation so we don't need to store the returned
	* cookie in the cache 
	* In an extended application case we'd need to free the request after
	* every loadHTTPURL() 
	*****/	
	if(cookieReq)
		freeCookieRequest(cookieReq);
	
	/* destroy the cookieCache */	
	if(cc)
		freeCookieCache(cc, 1);

	if(req->ret < 199 || req->ret > 399)
	{
		int error = (int)req->ret;
		unlink(output);
		sprintf(msg, "%s: %s", req->url,
			HTTPErrorString((HTTPRequestReturn)error));
		deleteHTTPRequest(req);
		emitError(msg, error);
	}
	if(req->ret != HTTPSuccess)
		printf("%s: %s\n", req->url,
			HTTPErrorString(req->ret));

	if(output_to_stdout)
	{
		FILE *in;
		int c;

		if((in = fopen(output, "r")) == NULL)
		{
			sprintf(msg, "Can't open temporary file %s for reading: %s",
				output, strerror(errno));
			emitError(msg, 0);
		}

		/* literal copy to stdout */
		while((c = fgetc(in)) != EOF)
			putc(c, stdout);
		fclose(in);
		unlink(output);
	
	}
	return(EXIT_SUCCESS);
}

