/*
 * Manage the http_error_page structure.
 *
 * Author:	David Jones
 * Date:	6-MAY-1999
 * Revised:	19-JUN-1999	Initialize ACC structure for translation.
 * Revised:	27-APR-2000	Support response_code override.
 * Revised:	14-MAY-2000	Extend errorpage structure.
 */
#include <stdlib.h>

#include "session.h"
#include "ident_map.h"

#include "errorpage.h"

int http_translate_ident(char *, char *, int, access_info );
int tlog_putlog ( int, char *, ... );
int http_send_document(), http_script_execute(), http_send_error();
static void translate_error_pages ();
/*
 * Define table of keywords for the error_page entries so we can access
 * them by name.
 */
static struct { 
	char *keyword;
	http_ep_def *valptr;
} errpage_table[] = { 
	{ "PROTFAIL", &http_error_page.protfail },
	{ "OPENFAIL", &http_error_page.openfail },
	{ "RULEFAIL", &http_error_page.rulefail },
	{ "CGIPROTOCOL", &http_epage.def[3] },
	{ "CODE4", &http_epage.def[4] },
	{ "CODE5", &http_epage.def[5] },
	{ "CODE6", &http_epage.def[6] },
	{ "CODE7", &http_epage.def[7] },
	{ "CODE8", &http_epage.def[8] },
	{ "CODE9", &http_epage.def[9] },
	{ (char *) 0, (http_ep_def *) 0 }
};
static int initialized = 0;
static void init_error_page ( )
{
    int i;
    http_ep_def *ep_def;
    initialized = 1;
    for ( i = 0; errpage_table[i].keyword; i++ ) {
	ep_def = errpage_table[i].valptr;
	ep_def->type = IDENT_MAP_FAILED;
	ep_def->ident = (char *) 0;
	ep_def->munged_ident = (char *) 0;
    }
}

int http_define_error_page ( char *name, char *ident, char *rsp_code )
{
    char temp[512];
    http_ep_def *ep_def;
    int i;
    /*
     * Clear table on first call.
     */
    if ( !initialized ) init_error_page;
    /*
     * Identify error page name.
     */
    tu_strupcase ( temp, name );
    for ( i = 0; errpage_table[i].keyword; i++ ) {
	if ( tu_strncmp ( temp, errpage_table[i].keyword, 80 ) == 0 ) break;
    }
    if ( errpage_table[i].keyword ) {
	/*
	 * Match found, save ident in definition structure.
	 */
	ep_def = errpage_table[i].valptr;
	ep_def->type = 1;		/* flag as defined */
	ep_def->ident = malloc ( tu_strlen(ident) + 1 );
	if ( ep_def->ident ) {
	    tu_strcpy ( ep_def->ident, ident );
	    ep_def->munged_ident = ep_def->ident;
	} else {
	    ep_def->type = 0;		/* failure */
	    tlog_putlog ( 0, "Malloc failure defining error page" );
	}
	ep_def->response_code = "";
	if ( tu_strncmp ( rsp_code, "*", 2 ) == 0 ) {
	    ep_def->response_code = "*";	/* save a malloc call */
	} else if ( *rsp_code ) {
	    ep_def->response_code = malloc ( tu_strlen(rsp_code) + 2 );
	    if ( ep_def->response_code ) {
		tu_strcpy ( ep_def->response_code, rsp_code );
	        tu_strcpy ( &ep_def->response_code[tu_strlen(rsp_code)], " " );
	    } else {
		tlog_putlog ( 0, "Malloc failure defining error page" );
		ep_def->response_code = "";
	    }
	}
    } else return 0;

    return 1;
}
/*
 * Do final fixup of error page definitions.
 */
int http_translate_error_pages ()
{
    int i, status;
    http_ep_def *def;
    struct acc_info_struct acc;		/* dummy access protection info */
    char munged_ident[1024];

    if ( !initialized ) init_error_page;
/*    acc.uic = 0;
    acc.cache_allowed = 0;
    acc.prot_file = (char *) 0;
    tu_strcpy ( acc.rem_user, "" );
    tu_strcpy ( acc.user, "" );
    acc.port_attr = ""; */
    acc.local_address = "0.0.0.0";
    /*
     * Scan the table of known errorpage types.
     */
    for ( i = 0; errpage_table[i].keyword; i++ ) {
	/*
	 * See if config file defined an error page for this entry.
	 */
	def = errpage_table[i].valptr;
	if ( def->type && (def->ident[0] == '/') ) {
	    /*
	     * Replace munged_ident with the translated form, saving
	     * translation result in type.
	     */
	    munged_ident[0] = '\0';
	    def->type = http_translate_ident ( def->ident, munged_ident,
		sizeof(munged_ident), &acc );
	   tlog_putlog ( 6, 
		"Translating errorpage ident '!AZ', result: !SL '!AZ'!/",
		def->ident, def->type, munged_ident );
	    if ( def->type ) {
		def->munged_ident = malloc ( tu_strlen(munged_ident)+1 );
		if ( def->munged_ident ) 
			tu_strcpy ( def->munged_ident, munged_ident );
		else def->type = 1;	/* leave as is */
	    }
	}
    }
    return 1;
}
/*************************************************************************/
int http_error_page_ident ( http_ep_def *ep_def, char *ident,
 char *out, int outsize )
{
    int type, i, length;
    /*
     * Copy translated error page ident to out buffer.
     */
    tu_strnzcpy ( out, ep_def->munged_ident, outsize );
    type = ep_def->type;
    if ( type == IDENT_MAP_OK_EXEC ) {
	/*
	 * Rebuild output so ient is included as script path, change
	 *     /prefix/script*xlated*bindir 
	 * to 
	 *     /prefix/script/ident*xlated*bindir
	 */
	for ( i = 0; i < outsize; i++ ) if ( out[i] == '*' ) {
	    tu_strnzcpy ( &out[i], ident, outsize - i - 1 );
	    length = tu_strlen ( out );
	    tu_strnzcpy ( &out[length], &ep_def->munged_ident[i],
		outsize - length - 1 );
	    break;
	}
	if ( i >= outsize ) type = 0;  /* failure */
    }
    return type;
}
/*************************************************************************/
/* Process the redirect to a defined error page.
 */
int http_process_error ( session_ctx scb, http_ep_def *ep_def, 
	char *rsp_code, char *ident, char *munged_ident, int munged_size,
	char *arg, string *iobuf )
{
    int type, status;
    /*
     * Select error code to begin with.
     */
    if ( ep_def->response_code[0] == '\0' ) {	/* Take default code */
        tu_add_text ( scb->rsphdr, rsp_code, tu_strlen(rsp_code) );
    } else if ( ep_def->response_code[0] == '*' ) {
    } else {
	tu_add_text ( scb->rsphdr, ep_def->response_code,
		tu_strlen ( ep_def->response_code ) );
    }

    type = http_error_page_ident ( ep_def, ident, munged_ident, munged_size ); 
    if ( type == IDENT_MAP_FAILED ) {
	status = http_send_error ( scb, "500 oops", "Mishandled error page" );
    } else if ( type == IDENT_MAP_OK_EXEC ) {
	/*
	 * Error page is script.
	 */
	status = http_script_execute ( scb, "HTBIN", munged_ident, arg,
		iobuf );
    } else {
	/*
	 * Error page is file.
	 */
	status = http_send_document ( scb, ident, munged_ident, arg, iobuf );
    }
    return status;
}
