/*
 * Send DNETMANAGE script command to server and process result.
 * Routine assumes CGILIB was initialized with cgi_init_env() and that
 * cgi_begin_output() hasn't been called.
 *
 * Author:	David Jones
 * Revised:	26-FEB-1998
 * Revised:	28-JAN-2002		Re-order writes so CGI mode entered
 *					after first read from manage socket.
 */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef VMS
#ifndef __GNUC__
#include <unixio.h>
#include <types.h>
#else
#define caddr_t caddr_t_gcc
#define u_char u_char_gcc
#define u_long u_long_gcc
#define u_short u_short_gcc
#endif
#include <socket.h>
#include <in.h>
#else
#include <sys/uio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#endif
#include <errno.h>
#include <netdb.h>

#include "scriptlib.h"			/* net_link_* function prototypes */
#include "cgilib.h"			/* cgi_* function prototypes */

static error_abort ( char *line, char *msg )
{
    int status;
    status = cgi_begin_output(1);
    if ( (status&1) == 0 ) exit ( status );
    status = cgi_printf ( "content-type: text/plain\nstatus: %s\n\n%s\n", 
		line, msg );
    exit ( status );
}

void server_query ( char *query )
{
    int mgr_port, status, sd, i, j, timeout, rem_port, length;
    char *target, *lbrack, *rbrack;
    struct sockaddr local, remote;
    struct hostent *hostinfo;
    char *remote_host;
    char manage_arg[128], manage_rsp[256], myhost[256];
    /*
     * create a socket and bind to random port.
     */
    sd = socket ( AF_INET, SOCK_STREAM, 0 );
    if ( sd < 0 ) error_abort ( "500 error", "error creating socket" );
    for ( j = 0; j < sizeof(local.sa_data); j++ ) {
	local.sa_data[j] = remote.sa_data[j] = 0;
    }
    status = gethostname ( myhost, sizeof(myhost)-1 );
    if ( status >= 0 ) {
	hostinfo = gethostbyname(myhost);
	if ( hostinfo ) for ( j = 0; j < hostinfo->h_length; j++ ) {
	    local.sa_data[j+2] = hostinfo->h_addr_list[0][j];
	}
    }
    for ( mgr_port = 5900; mgr_port < 5950; mgr_port++ ) {
	local.sa_family = AF_INET;
	local.sa_data[0] = mgr_port >> 8;
	local.sa_data[1] = (mgr_port&255);

        status = bind ( sd, &local, sizeof(local) );
	printf ( "bind local socket: %d %d %s\n", status, mgr_port, strerror(errno) );
	if ( status >= 0 ) break;
    }
    /*
     * get host and port info from CGI variables and lookup host.
     */
    remote_host = cgi_info ( "SERVER_NAME" );
    if ( !remote_host ) remote_host = "localhost";
    hostinfo = gethostbyname ( remote_host );
    if ( !hostinfo ) error_abort ( "500 error", "error looking up hostname" );

    rem_port = atoi ( cgi_info ( "SERVER_PORT" ) );
    remote.sa_family = hostinfo->h_addrtype;
    for ( j = 0; j < hostinfo->h_length; j++ ) {
	    remote.sa_data[j+2] = hostinfo->h_addr_list[0][j];
    }
    remote.sa_data[0] = rem_port >> 8;
    remote.sa_data[1] = (rem_port&255);
    /*
     * Send <DNETMANAGE> command to make server switch managment
     * port and host.
     */
    sprintf ( manage_arg, "%d.%d.%d.%d:%d %s", local.sa_data[2]&255,
	local.sa_data[3]&255, local.sa_data[4]&255,
	local.sa_data[5]&255, mgr_port, query );
    status = net_link_write ( "<DNETMANAGE>", 12 );
    if ( (status&1) == 1 ) status = net_link_query ( manage_arg, manage_rsp,
	sizeof(manage_rsp)-1, &length );

    if ( (status&1) == 1 ) {
	/*
	 * Verify response.
	 */
	manage_rsp[length] = '\0';
	if ( 0 != strncmp ( "200 ", manage_rsp, 4 ) ) 
		error_abort ( "500 error from server", manage_rsp );
    } else {
	/* I/O error to net link */
	exit(1);
    }
    /*
     * Switch port number if included in response.
     */
    lbrack = strchr ( manage_rsp, '[' );
    rbrack = lbrack ? strchr ( lbrack, ']' ) : (char *) 0;
    if ( lbrack && rbrack ) {
	*rbrack = '\0';
	rem_port = atoi ( lbrack+1 );
	printf("alternate target port: %d\n", rem_port );
	if ( rem_port > 0 ) {
	    remote.sa_data[0] = rem_port >> 8;
	    remote.sa_data[1] = (rem_port&255);
	}
    }
    /*
     * connect to server.
     */
    status = connect ( sd, &remote, sizeof(remote) );
    if ( status != 0 ) error_abort ( "500 error", strerror(errno) );
    else {
	    int length;
	    char response[10240];
	    /*
	     * Send request followed by newline.
	     */
	    status = send ( sd, "TRIGGER\n", 8, 0 );
	    if ( status < 0 )
		fprintf(stderr,"status of write: %d %d\n", status, errno );
	    /* status = send ( sd, "\r\n\r\n", 4, 0 ); */
	    /*
	     * Read and save response.
	     */
	    if ( status > 0 ) {
		int i, j, pos, cr, output_begun;
		char ch;

		output_begun = 0;
		cr = 0;
		pos = 0;
		while (0 < (length=recv(sd, &response[pos], 1024,0))) {
		    if ( !output_begun ) {
			cgi_begin_output(1);
			output_begun = 1;
		    }
		    for ( i = 0, j = pos; i < length; i++ ) {
			ch = response[pos+i];
			if ( ch == '\r' ) {
			    if ( cr == 1 ) response[j++] = '\r';
			    cr = 1;
			} else if ( cr == 1 ) {
			    if ( ch != '\n' ) response[j++] = '\r';
			    response[j++] = ch;
			    cr = 0;
			} else {
			    response[j++] = ch;
			    cr = 0;
			}
		    }
		    response[j] = '\0';
		    pos = j;
		    if ( (pos+2048) >= sizeof(response) ) break;

		    if ( pos > 4 ) if ( 0 == strncmp ( "201 ",
			response, 4 ) ) break;
		}
		if ( !output_begun ) cgi_begin_output ( 1 );
		cgi_printf("content-type: text/plain\n\n");
		cgi_printf("Port %d response:\n", rem_port );
		cgi_printf("%s", response );
		    printf("%s", response );
		printf("\n");
	    }
    }
}
