#include <exec/types.h>
#include <exec/exec.h>
#include <dos/dos.h>
#include <dos/dosextens.h>
#include <dos/filehandler.h>
#include <devices/timer.h>
#include <libraries/wwbbs.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>

#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/wwbbs.h>

#include "wwbbsaux-handler_rev.h"

struct ExecBase *SysBase;
struct DosLibrary *DOSBase;
struct Library *WorldWideBase;

char *version=VERSTAG;

void __saveds wwbbs_aux(void);
LONG __saveds input(BYTE *,BOOL,BYTE *,LONG,ULONG);
BOOL __saveds print_local(BYTE *,BYTE *,ULONG);
BOOL __saveds print_remote(BYTE *,BYTE *,ULONG);
BOOL __saveds check_panic(BYTE *,BOOL);
BOOL __saveds check_page(BYTE *,BOOL);

void __saveds wwbbs_aux()
	{
		struct Process *proc;
		struct DosPacket *dp;
		struct DeviceNode *dn;

		char id[33];
		BOOL local=FALSE;

		ULONG opencount=0;
		BOOL raw=FALSE,kg=TRUE;

		SysBase=(struct ExecBase *) 4;
		DOSBase=(struct DosLibrary *) OpenLibrary("dos.library",0);
		WorldWideBase=OpenLibrary("wwbbs.library",0);

		proc=(struct Process *) FindTask(NULL);
		dp=WaitPkt();
		dn=(struct DeviceNode *) BADDR(dp->dp_Arg3);
		dp->dp_Arg4=(LONG) &proc->pr_MsgPort;
		{
			char buff[64],*p;
			p=BADDR(dp->dp_Arg1);
			sprintf(buff,"%.*s",(*p>63) ? 63 : *p,&p[1]);
			strcpy(id,"");
			if(p=strchr(buff,':'))
				{
					p++;
					sprintf(id,"%.32s",p);
				}
		}
		ReplyPkt(dp,DOSTRUE,0);

		GetStatusTags(STTAG_Name,id,STTAG_Local,&local,TAG_END);

		while(kg)
			{
				dp=WaitPkt();
				switch(dp->dp_Type)
					{
						case ACTION_FINDUPDATE:
						case ACTION_FINDINPUT:
						case ACTION_FINDOUTPUT:
							opencount++;
							{
								struct FileHandle *fh;
								fh=(struct FileHandle *) BADDR(dp->dp_Arg1);
								fh->fh_Port=(struct MsgPort *) DOSTRUE;
							}
							ReplyPkt(dp,DOSTRUE,NULL);
							break;
						case ACTION_END:
							opencount--;
							if(!opencount)
								kg=FALSE;
							ReplyPkt(dp,DOSTRUE,NULL);
							break;
						case ACTION_READ:
							{
								BYTE *buffer=NULL;
								LONG num=0;
								LONG ret=0;
								buffer=(BYTE *) dp->dp_Arg2;
								num=dp->dp_Arg3;
								if(buffer && num)
									{
										UWORD inactivitytimelimit=0;
										GetStatusTags(STTAG_Name,id,STTAG_InactivityTimeLimit,&inactivitytimelimit,TAG_END);
										if(!check_panic(id,local))
											{
												if(raw)
													{
														BYTE stack[256];
														strcpy(stack,"");
														GetStatusTags(STTAG_Name,id,STTAG_Stack,stack,TAG_END);
														if(strlen(stack))
															{
																if(strlen(stack)>num)
																	{
																		strncpy(buffer,stack,num);
																		{
																			char buff[256];
																			strcpy(buff,&stack[num]);
																			strcpy(stack,buff);
																		}
																		ret=num;
																	}
																else
																	{
																		strncpy(buffer,stack,strlen(stack));
																		ret=strlen(stack);
																		strcpy(stack,"");
																	}
																SetStatusTags(STTAG_Name,id,STTAG_Stack,stack,TAG_END);
															}
														else
															{
																check_page(id,local);
																while(1)
																	{
																		if(ret=input(id,local,buffer,num,inactivitytimelimit*60*1000000))
																			break;
																		else
																			{
																				if(!check_page(id,local))
																					break;
																			}
																	}
															}
													}
												else
													{
														BOOL con_kg=TRUE,skip=FALSE;
														BYTE stack[256];
														strcpy(stack,"");
														GetStatusTags(STTAG_Name,id,STTAG_Stack,stack,TAG_END);
														while(con_kg && ret<num)
															{
																skip=FALSE;
																buffer[ret]=NULL;
																if(strlen(stack))
																	{
																		buffer[ret]=stack[0];
																		{
																			char buff[256];
																			strcpy(buff,&stack[1]);
																			strcpy(stack,buff);
																		}
																	}
																else
																	{
																		check_page(id,local);
																		if(!input(id,local,&buffer[ret],1,inactivitytimelimit*60*1000000))
																			{
																				if(!check_page(id,local))
																					{
																						ret=0;
																						break;
																					}
																				else
																					skip=TRUE;
																			}
																	}
																if(!skip && buffer[ret])
																	{
																		switch(buffer[ret])
																			{
																				case '\b':
																					if(ret)
																						{
																							ret--;
																							if(local)
																								print_local(id,"\b \b",-1);
																							else
																								print_remote(id,"\b \b",-1);
																						}
																					break;
																				case '\r':
																					buffer[ret]='\n';
																					if(local)
																						print_local(id,"\r\n",-1);
																					else
																						print_remote(id,"\r\n",-1);
																					ret++;
																					con_kg=FALSE;
																					break;
																				default:
																					if(isprint(buffer[ret]))
																						{
																							if(local)
																								print_local(id,&buffer[ret],1);
																							else
																								print_remote(id,&buffer[ret],1);
																							ret++;
																						}
																					break;
																			}
																	}
															}
														SetStatusTags(STTAG_Name,id,STTAG_Stack,stack,TAG_END);
													}
												if(check_panic(id,local))
													ret=0;
											}
										if(!ret)
											Signal(dp->dp_Port->mp_SigTask,SIGBREAKF_CTRL_C);
									}
								ReplyPkt(dp,ret,0);
							}
							break;
						case ACTION_WRITE:
							{
								BYTE *buffer=NULL;
								LONG num=0;
								LONG ret=0;
								buffer=(BYTE *) dp->dp_Arg2;
								num=dp->dp_Arg3;
								if(buffer && num)
									{
										if(!check_panic(id,local))
											{
												BYTE *s;
												if(s=AllocVec(sizeof(BYTE)*(num+2),MEMF_CLEAR))
													{
														if(buffer[num-1]=='\n')
															sprintf(s,"%.*s\r\n",num-1,buffer);
														else
															sprintf(s,"%.*s",num,buffer);
														{
															BYTE *p,*q;
															p=q=s;
															while(*p)
																{
																	if(q=strchr(p,'~'))
																		{
																			if(local)
																				print_local(id,p,q-p);
																			else
																				print_remote(id,p,q-p);
																			p=q;
																			p++;
																			if(*p)
																				{
																					BOOL ansi=FALSE;
																					GetStatusTags(STTAG_Name,id,STTAG_ANSI,&ansi,TAG_END);
																					if(ansi)
																						{
																							BYTE color[161],color_buff[81];
																							strcpy(color,"");
																							strcpy(color_buff,"");
																							switch(*p)
																								{
																									case 'H':
																									case 'h':
																										GetConfigTags(CFGTAG_Name,"System",SYSTAG_HeaderColor,color_buff,TAG_END);
																										break;
																									case 'I':
																									case 'i':
																										GetConfigTags(CFGTAG_Name,"System",SYSTAG_InputColor,color_buff,TAG_END);
																										break;
																									case 'O':
																									case 'o':
																										GetConfigTags(CFGTAG_Name,"System",SYSTAG_OutputColor,color_buff,TAG_END);
																										break;
																									case 'P':
																									case 'p':
																										GetConfigTags(CFGTAG_Name,"System",SYSTAG_PromptColor,color_buff,TAG_END);
																										break;
																									case 'R':
																									case 'r':
																										strcpy(color_buff,"\\e[0m");
																										break;
																									case 'S':
																									case 's':
																										GetConfigTags(CFGTAG_Name,"System",SYSTAG_SystemColor,color_buff,TAG_END);
																										break;
																								}
																							if(strlen(color_buff))
																								{
																									char *r;
																									int format=FALSE;
																									strcpy(color,"");
																									r=color_buff;
																									while(*r)
																										{
																											if(format)
																												{
																													switch(*r)
																														{
																															case 'e':
																																strcat(color,"\033");
																																break;
																															case 't':
																																strcat(color,"\t");
																																break;
																															case 'b':
																																strcat(color,"\b");
																																break;
																															case 'n':
																																strcat(color,"\r\n");
																																break;
																															case 'f':
																																strcat(color,"\f");
																																break;
																														}
																													format=FALSE;
																												}
																											else
																												{
																													switch(*r)
																														{
																															case '\\':
																																format=TRUE;
																																break;
																															default:
																																strncat(color,r,1);
																																break;
																														}
																												}
																											r++;
																										}
																									if(local)
																										print_local(id,color,strlen(color));
																									else
																										print_remote(id,color,strlen(color));
																								}
																						}
																					p++;
																				}
																		}
																	else
																		{
																			if(local)
																				print_local(id,p,strlen(p));
																			else
																				print_remote(id,p,strlen(p));
																			break;
																		}
																}
														}
														FreeVec(s);
													}
												ret=num;
											}
										else
											Signal(dp->dp_Port->mp_SigTask,SIGBREAKF_CTRL_C);
									}
								if(ret==num)
									ReplyPkt(dp,num,0);
								else
									ReplyPkt(dp,-1,ERROR_ACTION_NOT_KNOWN);
							}
							break;
						case ACTION_WAIT_CHAR:
							{
								ULONG timeout=0;
								LONG ret=DOSFALSE;
								timeout=(ULONG) dp->dp_Arg1;
								{
									if(!check_panic(id,local))
										{
											BYTE stack[256];
											strcpy(stack,"");
											GetStatusTags(STTAG_Name,id,STTAG_Stack,stack,TAG_END);
											if(timeout)
												{
													if(strlen(stack))
														ret=DOSTRUE;
													else
														{
															BYTE c;
															if(input(id,local,&c,1,timeout))
																{
																	sprintf(stack,"%c",c);
																	SetStatusTags(STTAG_Name,id,STTAG_Stack,stack,TAG_END);
																	ret=DOSTRUE;
																}
															else
																{
																	if(check_panic(id,local))
																		Signal(dp->dp_Port->mp_SigTask,SIGBREAKF_CTRL_C);
																}
														}
												}
											else
												{
													if(strlen(stack))
														ret=DOSTRUE;
													else
														{
															if(local)
																{
																	if(ConsoleCommandTags(id,CONCMD_Query,TAG_END))
																		ret=DOSTRUE;
																}
															else
																{
																	if(SerialCommandTags(id,SERCMD_Query,TAG_END))
																		ret=DOSTRUE;
																}
														}
												}
										}
									else
										Signal(dp->dp_Port->mp_SigTask,SIGBREAKF_CTRL_C);
								}
								ReplyPkt(dp,ret,(ret) ? NULL : ERROR_ACTION_NOT_KNOWN);
							}
							break;
						case ACTION_SCREEN_MODE:
							{
								LONG mode=0;
								mode=(LONG) dp->dp_Arg1;
								raw=(mode) ? TRUE : FALSE;
								ReplyPkt(dp,DOSTRUE,0);
							}
							break;
						default:
							ReplyPkt(dp,DOSFALSE,ERROR_ACTION_NOT_KNOWN);
							if(!opencount)
								kg=FALSE;
							break;
					}
			}

		CloseLibrary(WorldWideBase);
		CloseLibrary((struct Library *) DOSBase);
	}

LONG __saveds input(BYTE *id,BOOL local,BYTE *buffer,LONG num,ULONG timeout)
	{
		LONG ret=0;
		struct MsgPort *TimerMP;
		struct timerequest *TimerIO;
		if(TimerMP=CreateMsgPort())
			{
				if(TimerIO=(struct timerequest *) CreateIORequest(TimerMP,sizeof(struct timerequest)))
					{
						if(!OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *) TimerIO,0))
							{
								ULONG mask=NULL;
								if(timeout)
									{
										TimerIO->tr_node.io_Command=TR_ADDREQUEST;
										TimerIO->tr_time.tv_secs=timeout/1000000;
										TimerIO->tr_time.tv_micro=timeout%1000000;
										SendIO((struct IORequest *) TimerIO);
										mask|=1 << TimerMP->mp_SigBit;
									}
								if(local)
									{
										ULONG c;
										if(c=ConsoleCommandTags(id,CONCMD_Wait,CONWAITTAG_WaitMask,mask,TAG_END))
											{
												buffer[0]=c;
												ret=1;
												while( (ret<num) && (c=ConsoleCommandTags(id,CONCMD_Read,TAG_END)) )
													{
														buffer[ret]=c;
														ret++;
													}
											}
									}
								else
									ret=SerialCommandTags(id,SERCMD_Wait,SERWAITTAG_Buffer,buffer,SERWAITTAG_Size,num,SERWAITTAG_WaitMask,mask,TAG_END);
								if(!CheckIO((struct IORequest *) TimerIO))
									{
										AbortIO((struct IORequest *) TimerIO);
										WaitIO((struct IORequest *) TimerIO);
									}
								CloseDevice((struct IORequest *) TimerIO);
							}
						DeleteIORequest(TimerIO);
					}
				DeleteMsgPort(TimerMP);
			}
		return(ret);
	}

BOOL __saveds print_local(BYTE *id,BYTE *buffer,ULONG size)
	{
		BOOL ret=FALSE;
		if(ConsoleCommandTags(id,CONCMD_Write,CONWRITETAG_Buffer,buffer,CONWRITETAG_Size,size,TAG_END))
			ret=TRUE;
		return(ret);
	}

BOOL __saveds print_remote(BYTE *id,BYTE *buffer,ULONG size)
	{
		BOOL ret=FALSE;
		ConsoleCommandTags(id,CONCMD_Write,CONWRITETAG_Buffer,buffer,CONWRITETAG_Size,size,TAG_END);
		if(SerialCommandTags(id,SERCMD_Write,SERWRITETAG_Buffer,buffer,SERWRITETAG_Size,size,TAG_END))
			ret=TRUE;
		return(ret);
	}

BOOL __saveds check_panic(BYTE *id,BOOL local)
	{
		BOOL ret=FALSE;
		BOOL panic=FALSE;
		GetStatusTags(STTAG_Name,id,STTAG_Panic,&panic,TAG_END);
		if(panic)
			ret=TRUE;
		else
			{
				if(!local)
					{
						if(!SerialCommandTags(id,SERCMD_Carrier,TAG_END))
							{
								SetStatusTags(STTAG_Name,id,STTAG_Panic,TRUE,TAG_END);
								ret=TRUE;
							}
					}
			}
		return(ret);
	}

BOOL __saveds check_page(BYTE *id,BOOL local)
	{
		BOOL pagereceived=FALSE;
		GetStatusTags(STTAG_Name,id,STTAG_PageReceived,&pagereceived,TAG_END);
		if(pagereceived)
			{
				{
					BPTR fh;
					BYTE filename[64],s[128];
					sprintf(filename,"T:wwbbs_page.%s",id);
					if(fh=Open(filename,MODE_OLDFILE))
						{
							if(local)
								print_local(id,"\n",1);
							else
								print_remote(id,"\n",1);
							while(FGets(fh,s,126))
								{
									s[strlen(s)-1]=NULL;
									strcat(s,"\r\n");
									if(local)
										print_local(id,s,strlen(s));
									else
										print_remote(id,s,strlen(s));
								}
							Close(fh);
							DeleteFile(filename);
							SetStatusTags(STTAG_Name,id,STTAG_PageReceived,FALSE,TAG_END);
						}
				}
			}
		return(pagereceived);
	}
