/*         		    					     HTListen.c
**	SOCKET LISTEN TOOL
**
**	(c) COPRIGHT MIT 1995.
**	Please first read the full copyright statement in the file COPYRIGH.
**
**  Authors:
**	HFN		Henrik Frystyk Nielsen (frystyk@w3.org)
**
**  History:
**	Nov 24 95	First version
*/

#include "WWWLib.h"			      /* Global Library Include file */
#include "WWWTrans.h"
#include "WWWInit.h"
#include "WWWApp.h"
#include "HTListen.h"					 /* Implemented here */

#ifndef W3C_VERSION
#define W3C_VERSION		"unspecified"
#endif

#define APP_NAME		"W3CListenTool"
#define APP_VERSION		W3C_VERSION

/* Default page for "-help" command line option */
#define HELP	"http://www.w3.org/pub/WWW/Listen/User/CommandLine.html"

#define DEFAULT_PORT		80

#define DEFAULT_FORMAT		WWW_RAW

#define DEFAULT_BACKLOG		HT_BACKLOG

#if defined(__svr4__)
#define CATCH_SIG
#endif

typedef struct _ListenTool {
    HTRequest *		request;
    SOCKET		port;
    int			backlog;		       /* Backlog for listen */
} ListenTool;


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

/*	Standard (non-error) Output
**	---------------------------
*/
PUBLIC int OutputData(const char  * fmt, ...)
{
    int ret;
    va_list pArgs;
    va_start(pArgs, fmt);
    ret = vfprintf(stdout, fmt, pArgs);
    va_end(pArgs);
    return ret;
}

/*	Create a Listen Tool Object
**	---------------------------
*/
PRIVATE ListenTool * ListenTool_new (void)
{
    ListenTool * me;
    if ((me = (ListenTool *) HT_CALLOC(1, sizeof(ListenTool))) == NULL)
	HT_OUTOFMEM("ListenTool_new");
    me->request = HTRequest_new();
    me->port = DEFAULT_PORT;
    me->backlog = DEFAULT_BACKLOG;
    HTRequest_setPreemptive(me->request, YES);
    HTRequest_setOutputFormat(me->request, DEFAULT_FORMAT);
    HTRequest_setOutputStream(me->request,
			      HTFWriter_new(me->request, OUTPUT, YES));
    return me;
}

/*	Delete a Listen Tool Object
**	---------------------------
*/
PRIVATE BOOL ListenTool_delete (ListenTool * me)
{
    if (me) {
	HTRequest_delete(me->request);
	HT_FREE(me);
	return YES;
    }
    return NO;
}

PRIVATE void Cleanup (ListenTool * me, int status)
{
    ListenTool_delete(me);
    HTEventTerminate();
    HTLibTerminate();
#ifdef VMS
    exit(status ? status : 1);
#else
    exit(status ? status : 0);
#endif
}

#ifdef CATCH_SIG
#include <signal.h>
/*								    SetSignal
**  This function sets up signal handlers. This might not be necessary to
**  call if the application has its own handlers.
*/
PRIVATE void SetSignal (void)
{
    /* On some systems (SYSV) it is necessary to catch the SIGPIPE signal
    ** when attemting to connect to a remote host where you normally should
    ** get `connection refused' back
    */
    if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
	if (WWWTRACE) HTTrace("HTSignal.... Can't catch SIGPIPE\n");
    } else {
	if (WWWTRACE) HTTrace("HTSignal.... Ignoring SIGPIPE\n");
    }
}
#endif /* CATCH_SIG */

PRIVATE void VersionInfo (void)
{
    OutputData("\n\nW3C Reference Software\n\n");
    OutputData("\tW3C W3C Listen Tool (%s) version %s.\n",
	       APP_NAME,APP_VERSION);
    OutputData("\tW3C Reference Library version %s.\n\n",HTLib_version());
    OutputData("Please send feedback to <libwww@w3.org>\n");
}

/* ------------------------------------------------------------------------- */
/*				  MAIN PROGRAM				     */
/* ------------------------------------------------------------------------- */

int main (int argc, char ** argv)
{    
    int	arg;
    ListenTool * ms = ListenTool_new();

    /* Set up the application's event loop. We use the 
       example event loop that comes with the Library.  */
    HTEventInit();

    /* Initiate W3C Reference Library */
    HTLibInit(APP_NAME, APP_VERSION);
    HTMIMEInit();

    /* Scan command Line for parameters */
    for (arg=1; arg<argc ; arg++) {
	if (*argv[arg] == '-') {

	    /* server port */
	    if (!strncmp(argv[arg], "-p", 2)) { 
		ms->port = (arg+1 < argc && *argv[arg+1] != '-') ?
		    atoi(argv[++arg]) : DEFAULT_PORT;

	    /* backlog for listen() */
	    } else if (!strcmp(argv[arg], "-backlog")) { 
		ms->backlog = (arg+1 < argc && *argv[arg+1] != '-') ?
		    atoi(argv[++arg]) : DEFAULT_BACKLOG;

	    /* Print version and exit */
	    } else if (!strcmp(argv[arg], "-version")) { 
		VersionInfo();
		Cleanup(ms, 0);
		
#ifdef WWWTRACE
	    /* trace flags */
	    } else if (!strncmp(argv[arg], "-v", 2)) {
		HTSetTraceMessageMask(argv[arg]+2);
#endif
	    } else {
		if (WWWTRACE) HTTrace("Bad Argument (%s)\n",argv[arg]);
	    }
        } else {
	    if (WWWTRACE) HTTrace("Bad Argument (%s)\n",argv[arg]);
	}
    }
	
#ifdef CATCH_SIG
    SetSignal();
#endif

    /* Set up a tool to listen on this port */
    if (ms->port >= 0) {

	/* Create a Net object */
	HTNet * net = HTNet_new(ms->port, ms->request);

	/* This is the "accepted" Net object */
	HTNet * accepted = NULL;

	/* Register the transport protocol for our listen tool */
	HTTransport_add("tcp", HT_TP_SINGLE, HTReader_new, NULL);

	/* Register the "noop" application layer protocol for reading */
	HTProtocol_add("noop", "tcp", YES, NULL, HTLoadSocket);

	/* Start listening on the socket */
 	if (net &&
	    HTDoListen(net, ms->port, INVSOC, ms->backlog) == HT_OK &&
	    HTDoAccept(net, &accepted) == HT_OK) {
	    HTNet_newServer(ms->request, accepted, "noop");
	} else {
	    if (WWWTRACE) HTTrace("Can't listen on port %d\n",ms->port);
	    Cleanup(ms, -1);
	}
    }
    Cleanup(ms, 0);
    return 0;
}
