#include <sys/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <functions.h>
#include "consolefun.h"
#include "const.h"

extern char *mktemp();
extern char *malloc();

/* functions from handlers.c */
extern void handle_console_read(struct MsgPort *, char *);
extern void handle_window(struct Window *, int *);

char *connect(char *, char *, char *);
void print_to_screen(char *, int, int *);
int send_to_host(struct MsgPort *, char *, int);
void setup_console(void);
void cleanup(void);


/* external variables */
struct Library	*IntuitionBase = NULL;
struct Window	*window = NULL;
struct IOStdReq	*writeReq = NULL;
struct MsgPort	*writePort = NULL;
struct IOStdReq	*readReq = NULL;
struct MsgPort	*con_read_port = NULL;
BOOL OpenedConsole = FALSE;

struct MsgPort *read_port = NULL;
char *read_port_name = NULL;

char *write_port_name = NULL;

struct MsgPort *wait_port = NULL;
int local_echo = 1;


struct NewWindow nw = {
    0,10, 640,100, -1,-1, CLOSEWINDOW, WINDOWDEPTH|WINDOWSIZING|
    WINDOWDRAG|WINDOWCLOSE|SMART_REFRESH|ACTIVATE, NULL, NULL,
    (UBYTE*)"Telnet", NULL, NULL, 100,45, 640,256, WBENCHSCREEN
};


/* send a string, return 0 if not succeeded */
int send_to_host(waitport, string, length)
    struct MsgPort *waitport;
    char *string;
    int length;
{
    /* a line was typed, send it to the mud .. */
    struct data_message *msg;	
    ULONG signal;
    char *data;
    int i;

#ifdef DEBUG
printf("sending :%d :'", length);
for(i=0;i<length;i++) {
    if(string[i] >= 'a' && string[i] <= 'z')
	printf("%c", string[i]);
    else
	printf("<%d>", string[i]);
    }
printf("'\n");
#endif

    msg = (struct data_message *) malloc(sizeof(struct data_message));
    if(!msg)
	return 0;
    msg->Msg.mn_Node.ln_Type = NT_MESSAGE;
    msg->Msg.mn_Length = sizeof(struct data_message);
    msg->Msg.mn_ReplyPort = waitport;

    data = malloc(length+1);
    for(i=0;i<length;i++)
	data[i] = string[i];
    data[i] = '\0';

    msg->buffer = data;
    msg->length = length;

    if(!SafePutToPort( (struct Message*)msg, write_port_name))
	return 0;
    return 1;
}


/* print a received string to the console, filter escape sequences */
void print_to_screen(buffer, length, exit)
    char *buffer;
    int length;
    int *exit;
{
    int i, new = 0;
    char *new_buffer;

    new_buffer = malloc(length);

    for(i=0;i<length;i++) {
	if((buffer[i] == -1) && (buffer[i+1] == -5) && (buffer[i+2]== 1)) {
	    local_echo = 0;
	    i += 2;
	    continue;
	}
	if((buffer[i] == -1) && (buffer[i+1] == -4) && (buffer[i+2]== 1)) {
	    local_echo = 1;
	    i += 2;
	    continue;
	}
	if((buffer[i] == -1) && (buffer[i+1] == -3) && (buffer[i+2]== 1)) {
	    *exit = 1;
	    i += 2;
	    continue;
	}
	new_buffer[new] = buffer[i];
	new++;
    }
    ConWrite(writeReq, new_buffer, new);
    free(new_buffer);
}


/*  try to get a port at host. Give the name of our port as an argument.
 *  Succeeded    : return portname
 *  Failed	 : return NULL ( no name )
 */
char *connect(hostname, portname, our_port_name)
    char *hostname, *portname;
    char *our_port_name;
{
    struct MsgPort *reply_port;
    struct connect_message *connect, *reply;
    ULONG portsig, signal;

    connect = (struct connect_message *)
		AllocMem(sizeof(struct connect_message), MEMF_PUBLIC);
    if(!connect)
	return NULL;

    reply_port = FindPort(our_port_name);
    if(!reply_port)
	return NULL;

    connect->Msg.mn_Node.ln_Type = NT_MESSAGE;
    connect->Msg.mn_Length = sizeof(struct connect_message);
    connect->Msg.mn_ReplyPort = reply_port;
    connect->port_name = our_port_name;

    if(!(SafePutToPort((struct Message *)connect, portname) )) {
	FreeMem(connect, sizeof(struct connect_message));
	return NULL;
    }

    portsig = 1L << reply_port->mp_SigBit;

    while(1) {
	signal = Wait( SIGBREAKF_CTRL_E | portsig);
	if(signal & portsig) {	/* got a signal at the msgport */
	    if(reply = (struct connect_message *) GetMsg(reply_port))
		{
		char *tmp;
		tmp = malloc(strlen(reply->port_name)+1);
		strcpy(tmp, reply->port_name);
		FreeMem(connect, sizeof(struct connect_message));
		return tmp;
		}
	    }
	if(signal & SIGBREAKF_CTRL_E) {
	    ConPuts(writeReq, "User Abort\n");
	    return NULL;
	    }
	} /* einde while-loop */
}


void setup_console(void)
{
    if(!(IntuitionBase=OpenLibrary("intuition.library",0))) cleanup();

    if(!(window = OpenWindow(&nw))) cleanup();

    /* create reply port and io block for writing to console */
    if(!(writePort = CreatePort("RKM.console.write",0))) cleanup();

    if(!(writeReq = (struct IOStdReq *) 
	CreateExtIO(writePort, (long)sizeof(struct IOStdReq))))	cleanup();

    /* create reply port and io block for reading from console */
    if(!(con_read_port = CreatePort("RKM.console.read",0))) cleanup();

    if(!(readReq = (struct IOStdReq *)
	CreateExtIO(con_read_port, (LONG)sizeof(struct IOStdReq)))) cleanup();

    /* now, attach a console to the window */
    if(OpenConsole(writeReq, readReq, window)) cleanup();

    OpenedConsole = TRUE;
}


void cleanup()
{
    Delay(250);

    if(OpenedConsole)	CloseConsole(writeReq);

    if(writeReq)	DeleteExtIO((struct IORequest*) writeReq);
    if(writePort)	DeletePort(writePort);

    if(readReq)		DeleteExtIO((struct IORequest*) readReq);
    if(con_read_port)	DeletePort(con_read_port);

    if(read_port)	DeletePort(read_port);
    if(read_port_name)  free(read_port_name);

    if(write_port_name) free(write_port_name);

    if(wait_port)	DeletePort(wait_port);

    if(window)		CloseWindow(window);
    if(IntuitionBase)	CloseLibrary(IntuitionBase);
    exit(0);
}


int main()
{
    char ibuf;	/* the char we last read */
    ULONG signals, conreadsig, windowsig, readsig, waitsig;
    int abort = FALSE;
    struct data_message *receive;
    struct data_message *msg;

    setup_console();
    Forbid();
    read_port_name = mktemp("telnetXXXXXXXX");	/* X's will be replaced by pid */
    if(!read_port_name) {
	Permit();
	ConPuts(writeReq, "Couldn't create read_port_name\n");
	cleanup();
    }

    if(!(read_port = CreatePort(read_port_name, 0))) {
	Permit();
	ConPuts(writeReq, "Couldn't create replyport\n");
	cleanup();
    }
    Permit();
    ConPuts(writeReq, "Trying ....\n");

    if(!(write_port_name = connect("exodus", "8888", read_port_name))) {
	ConPuts(writeReq, "Connection refused by host\n");
	cleanup();
    }
    if(!(wait_port = CreatePort(0, 0))) {
	ConPuts(writeReq, "Couldn't create wait_port\n");
	cleanup();
    }
    ConPuts(writeReq, "Connected\n");

    QueueRead(readReq, &ibuf);

    conreadsig = 1L << con_read_port->mp_SigBit;
    windowsig = 1L << window->UserPort->mp_SigBit;

    readsig = 1L << read_port->mp_SigBit;
    waitsig = 1L << wait_port->mp_SigBit;

    while(!abort) {
	signals = Wait(SIGBREAKF_CTRL_E | windowsig | conreadsig | readsig | waitsig);

	if(signals & readsig) {	/* got a signal at the msgport */
	    while( (receive = (struct data_message *)
		GetMsg((struct MsgPort*) read_port))) {
		    print_to_screen(receive->buffer, receive->length, &abort);
		    ReplyMsg((struct Message *) receive);
		}
	}

	if(signals & waitsig) {
	    while(msg = (struct data_message *) GetMsg(wait_port)) {
		free(msg->buffer);
		free((char*)msg);
	    }
	}

	if(signals & windowsig)
	    handle_window(window, &abort);

	if(signals & conreadsig)
	    handle_console_read(con_read_port, &ibuf);

	if(signals & SIGBREAKF_CTRL_E) {
	    ConPuts(writeReq, "User abort\n");
	    abort = 1;
	    }
    }

    ConPuts(writeReq, "\nconnection closed\n");

    if(!(CheckIO((struct IORequest*) readReq)))
	AbortIO((struct IORequest*) readReq);
    WaitIO((struct IORequest*) readReq);

    cleanup();
}
