/* Parlez 2.11

   Name   : Parlez
   Version: 2.11
   Date   : 23rd August 1996 / 26th July 2007 for source code release

   Purpose: BBS inter-port chatting

   Creator: Richard Murray

*/



/* Included files */

/* DeskLib 2.30 */
#include "DeskLib:WimpSWIs.h"          /* Low-level WIMP commands         */
#include "DeskLib:Window.h"            /* Window handling automation      */
#include "DeskLib:Core.h"              /* useful core functions           */
#include "DeskLib:Dialog2.h"           /* windows on menus made easy      */
#include "DeskLib:Error.h"             /* Error handler                   */
#include "DeskLib:Event.h"             /* Event despatcher                */
#include "DeskLib:EventMsg.h"          /* Wimp Message event dispatcher   */
#include "DeskLib:File.h"	       /* File handling routines	  */
#include "DeskLib:Handler.h"           /* Default/example event handlers  */
#include "DeskLib:Icon.h"              /* Icon handling automation        */
#include "DeskLib:Menu.h"              /* Menu create & show support      */
#include "DeskLib:Resource.h"          /* Handles finding resource files  */
#include "DeskLib:Screen.h"            /* Getting screen size info etc    */
#include "DeskLib:Template.h"          /* Template loading and caching    */

/* ANSI C */
#include <ctype.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

/* Acorn RISC OS */
#include "kernel.h"
#include "doorlib.h"
#include "parlez.h"
#include "setjmp.h"


/* Macro definitions */
#define CLEAR(s) ((s) [0] = '\0') /* Clear string contents macro */


/* Global variable definitions */
#define mainmenu_INFO  0
#define mainmenu_SNOOP 1
#define mainmenu_QUIT  2
#define Wimp__SendMessage 0x400E7

static icon_handle iconbaricon;
static BOOL finished = FALSE;
static window_handle snoop_window;
static window_handle userinfo_window;
static menu_ptr mainmenu = NULL;
static dialog2_block *info;

extern int  doors_connectedokay; /* for header file */
static int  port_in_use=-1;
static int  ourdoornumber=0;
static char temp_string[255];
static char ourmessage[78];
static int  junk_variable;
       int  doors_connectedokay=FALSE;
static int  servertype=255;
static int  messagetype=255;
static int  dologit=FALSE;
static char username[31];
static int  thisinuse[36]=FALSE;
static int  updateit=FALSE;
static int  sendto=254;
static int  updatenow=0;
static int  reasoncode=0;
static int  chatting=FALSE;
static int  senditasamessage=FALSE;
static int  requestingachat=FALSE;
static _kernel_swi_regs r_in, r_out;
static int  ourtime=0;
static int  theirtime=0;
static int  checktheirtime=0;
static int  nochecktheirtime=FALSE;
static int  snoop_status = FALSE;
static char *lastproc = "Undefined!";
static char *crash_last = "Undefined";
static jmp_buf posible_travectoria;
struct datum
{
   int  baudrate;        /*  4 */
   int  usernumber;      /*  8 */
   char username[31];    /* 39 */
   char doing[25];       /* 64 */
};
static struct datum userdatum[36];

typedef struct
{
  int x, y;
} position;

typedef struct
{
  int port;
  position posn;
  struct
  {
    char line[80];
  } text[10];
} wibble;

static wibble chat1, chat2;


/* Global procedure definitions (global to this program code (ie, this file)) */
static BOOL open_handler(event_pollblock *event, void *reference);
static BOOL close_handler(event_pollblock *event, void *reference);
static BOOL quitiminent(event_pollblock *event, void *reference);
static BOOL interacthelp(event_pollblock *event, void *reference);
static BOOL mainmenu_choice(event_pollblock *event, void *reference);
static BOOL show_infowindow(event_pollblock *event, void *reference);
static BOOL iconbar_handler(event_pollblock *event, void *reference);
static void info_handler(dialog2_block *dialog2);
       void poll_the_wimp(void);
static BOOL null_handler(event_pollblock *event, void *reference);
static BOOL snoop_handler(event_pollblock *event, void *reference);
static void lowercase(char string[]);
static void get_user_info(void);
static void draw_header(void);
static void get_online_users(int whichone);
static int  seekvalidity(int port);
static void plot_online_users(int whichone);
static int  get_port(void);
static void updatedisplay(void);
static void getmessage(void);
static void sendtoport(void);
static void sendmessage(void);
static void send_cav_message(void);
static void initiatechat(void);
static void drawsplitscreen(int whose);
static void getandplotit(wibble *erk, int otherport, int yshift);
static void checktimes(void);
static void patchdoingstring(void);
static void debuginfo(int whoto, int whonotto);
static void drawsnoop(void);
static int  getrandom(int maxnumber);

extern user_info* arcbbsfiler_get_status_pointer(void);
/* inline swi stuff... __swi(0x41014) user_info* arcbbsfiler_get_status_pointer(void); */

#if 1
static void logfile(char type, char message[]);
#else
/* completely disable logging :) */
#define logfile(x,y) ((void) 0)
#endif

static BOOL budgiesoft_message(event_pollblock *event, void *ref);
static void grab_user_info(int port);
static void signl_stack(int sig);
static void signl_oserr(int sig);
static void panic(int type);
static void reportfatalerror(int whoto, int type);
static void coredump(int type);




int main(int argc, char *argv[])
{
   struct tm *timepointer;
   time_t now;
   char timevar[90];

   lastproc = "main()";

   signal(SIGSTAK, signl_stack);
   signal(SIGOSERROR, signl_oserr);

   _kernel_getenv("Parlez$Log$Active",temp_string,255);
   lowercase(temp_string);
   if (strcmp(temp_string,"yes") == NULL) dologit = TRUE;

   time(&now);
   timepointer = localtime(&now);
   strftime(timevar, 60, "Parlez 2.11 initialised at %H:%Mh (%d-%B-%Y) %Z", timepointer);
   logfile('@', NULL);
   logfile('#', timevar);

#ifdef DEBUG_CODE
   logfile('+',"Debugging code active in this version.");

   Resource_Initialise("Parlez");
   Event_Initialise("Parlez [debug]");
#else
   Resource_Initialise("Parlez");
   Event_Initialise("Parlez");
#endif


   if (argc == 1)
   {
      logfile('!',"Error: No door number passed (please read help file).");
      logfile('#',"Premature shutdown.");
      Error_ReportFatal(0,"No door number passed as command line parameter");
   }

   ourdoornumber=atoi(argv[1]);

   _kernel_getenv("ArcBBS$Server$Type",temp_string,255);
   lowercase(temp_string);
   if (strcmp(temp_string,"angela") == NULL) servertype = TRUE;
   if (strcmp(temp_string,"chase") == NULL) servertype = FALSE;

   _kernel_getenv("Parlez$Message$Upload",temp_string,255);
   lowercase(temp_string);
   if (strcmp(temp_string,"yes") == NULL) messagetype = TRUE;
   if (strcmp(temp_string,"no") == NULL) messagetype = FALSE;
   if (strcmp(temp_string,"armbbs") == NULL)
   {
      messagetype = 2;
      servertype = TRUE;
   }

   if (servertype == 255)
   {
      logfile('!',"Error: Server type is unrecognised. Have you altered the !Run file?");
      logfile(' ',"       Check 'ArcBBS$Server$Type' setting.");
      logfile(' ',"       Expecting \"angela\" or \"chase\".");
      logfile('#',"Premature shutdown.");
      Error_ReportFatal(0,"Value of \'ArcBBS$Server$Type\' is unrecognised");
   }
   if (messagetype == 255)
   {
      logfile('!',"Error: Message upload type unrecognised. Have you altered the !Run file?");
      logfile(' ',"       Check 'Parlez$Message$Upload' setting.");
      logfile(' ',"       Expecting \"Yes\" or \"No\" or \"ArmBBS\".");
      logfile('#',"Premature shutdown.");
      Error_ReportFatal(0,"Value of \'Parlez$Message$Upload\' is unrecognised");
   }

   junk_variable = setjmp(posible_travectoria);
   if (junk_variable != 0) panic(junk_variable);

   Resource_LoadSprites();
   EventMsg_Initialise();
   Screen_CacheModeInfo();
   Template_Initialise();
   Template_LoadFile("Templates");

   snoop_window = Window_Create("snoop", 45);
   if (snoop_window == 0)
      Error_ReportFatal(0,"Cannot find template definition \'%s\'","snoop");
   Event_Claim(event_CLICK, snoop_window, event_ANY, snoop_handler, NULL);

   userinfo_window = Window_Create("userinfo", 45);
   if (userinfo_window == 0)
      Error_ReportFatal(0,"Cannot find template definition \'%s\'","userinfo");

   Event_Claim(event_CLOSE, event_ANY, event_ANY, close_handler, NULL);
   Event_Claim(event_REDRAW, event_ANY, event_ANY, Handler_NullRedraw, NULL);
   Event_Claim(event_OPEN, event_ANY, event_ANY, open_handler, NULL);
   EventMsg_Claim((message_action)0x16F00, event_ANY, budgiesoft_message, NULL);
   EventMsg_Claim(message_PREQUIT, event_ANY, quitiminent, NULL);
   EventMsg_Claim(message_HELPREQUEST, event_ANY, interacthelp, NULL);

   mainmenu  = Menu_New("Parlez",">Info,Snoop,Quit");
   Event_Claim(event_MENU,  event_ANY, event_ANY, mainmenu_choice, NULL);

   info = Dialog2_CreateDialogBlock("info", 42, 42, info_handler, NULL, NULL);
   Menu_Warn(mainmenu, mainmenu_INFO, TRUE, show_infowindow, info);

   iconbaricon = Icon_BarIconUser("!parlez",iconbar_RIGHT,(unsigned int *)resource_sprites);
   Event_Claim(event_CLICK, -2, iconbaricon, iconbar_handler, NULL);

   Event_Claim(event_NULL, event_ANY, event_ANY, null_handler, NULL);

   port_in_use=doors_scanconnecttimed(ourdoornumber,10);
   if (port_in_use==-1)
   {
      sprintf(temp_string,"Error: Failed to connect as door %d.",ourdoornumber);
      logfile('!',temp_string);
      logfile('#',"Shutdown after 10 seconds.");
      exit(EXIT_FAILURE);
   }

   doors_connectedokay=TRUE;

   get_user_info();
   sprintf(temp_string,"Connected successfully with \'%s\' on port %d.",username,port_in_use);
   logfile('*',temp_string);
   draw_header();
   get_online_users(254);
   plot_online_users(254);
   doors_txf(port_in_use,"\r\n\r\n\r\n\033[15;1H");

   if (strcmp(username,"Richard Murray") == NULL)
   {
      doors_txf(port_in_use, "\033[35;40mHello creator! :-)");
      logfile('-',"Welcome, creator of mine! :-)");
   }
   if (!strcmp(username,"Richard Sargeant")) doors_txf(port_in_use, "\033[35;40mThanks Ricky - but I can't compile \'in-line SWI\'s... :-)");
   if (!strcmp(username,"Steve Pursey")) doors_txf(port_in_use, "\033[35;40m:-)");
   if (!strcmp(username,"Helen Rayner")) doors_txf(port_in_use, "\033[35;40mAh! It\'s cute\'n\'furry Helen. Hello there! :-)");
   if (!strcmp(username,"Angela Rayner")) doors_txf(port_in_use, "\033[35;40mGo on, cluck for us a few times! :-)");
   if (!strcmp(username,"Emlyn Owen")) doors_txf(port_in_use, "\033[35;40mThanks for everything... :-)");

   doors_txf(port_in_use,"\033[17;1H");
   sendto = get_port();
   if (finished==FALSE) getmessage();
   if (finished==FALSE) sendtoport();
   if (senditasamessage == TRUE) sendmessage();

   doors_txf(port_in_use,"\033[32mGame over. Insert 10p to play again...\033[37m\r\n");
   doors_close(port_in_use);
   logfile('#',"Successful shutdown. Mippens closed, gone to sleep. Byeeeee!");
   Event_CloseDown();
}


static BOOL open_handler(event_pollblock *event, void *reference)
{
   reference = reference;

   lastproc = "open_handler()";

   Wimp_OpenWindow(&event->data.openblock);

   if ((int)event->data.openblock.window == (int)snoop_window)
   {
      snoop_status = TRUE;
   }

   return(TRUE);
}


static BOOL close_handler(event_pollblock *event, void *reference)
{
   reference = reference;

   lastproc = "close_handler()";

   Wimp_CloseWindow(event->data.openblock.window);

   if ((int)event->data.openblock.window == (int)snoop_window)
   {
      snoop_status = FALSE;
   }

   return(TRUE);
}


static BOOL quitiminent(event_pollblock *event, void *reference)
{
   event = event;
   reference = reference;

   logfile('*',"Received WIMP message 8 (application prequit)");
   return(FALSE);
}

static BOOL interacthelp(event_pollblock *event, void *reference)
{
   event = event;
   reference = reference;

   logfile('*',"Received WIMP message &502 (interactive help)");
   return(FALSE);
}


static BOOL mainmenu_choice(event_pollblock *event, void *reference)
{
   mouse_block ptr;

   lastproc = "mainmenu_choice()";

   if (menu_currentopen != mainmenu) return(FALSE);

   switch(event->data.selection[0])
   {

      case mainmenu_INFO : Dialog2_OpenDialogMenuLeaf(event,(dialog2_block *)reference);
         	           break;
      case mainmenu_SNOOP: if (chatting == TRUE) Window_Show(snoop_window, open_WHEREVER);
      	   		   break;
      case mainmenu_QUIT : finished = TRUE;
                           break;
      default            : Error_ReportFatal(0,"Aaaaaaaaaaaaaaaaaaaaaaargh!");
                           break;
   }

   Wimp_GetPointerInfo(&ptr);  /* If ADJUST was used to select, then keep the menu open. */
   if (ptr.button.data.adjust) Menu_ShowLast();

   return(TRUE);
}


static BOOL show_infowindow(event_pollblock *event, void *reference)
{
   lastproc = "show_infowindow()";
   if( (menu_currentopen != mainmenu) || (event->data.message.data.menuwarn.selection[0] != mainmenu_INFO)) return(FALSE);
   Dialog2_OpenDialogMenuLeaf(event, (dialog2_block *)reference);
   return(TRUE);
}


static BOOL iconbar_handler(event_pollblock *event, void *reference)
{
   reference = reference;

   lastproc = "iconbar_handler()";

   if(event->data.mouse.button.data.menu)
      Menu_Show(mainmenu, event->data.mouse.pos.x,-1);

   if(event->data.mouse.button.data.select)
      if (chatting==TRUE) Window_Show(snoop_window, open_WHEREVER);

   return(TRUE);
}


static void info_handler(dialog2_block *dialog2)
{
   lastproc = "info_handler()";

   Icon_SetText(dialog2->window,4,"2.11 23rd August 1996");

   return;
}


static BOOL snoop_handler(event_pollblock *event, void *reference)
{
   int icon = -1;

   lastproc = "snoop_handler()";

   reference = reference;

   icon = event->data.mouse.icon;
   switch(icon)
   {
      case  0: /* One BIG fall-through structure */
      case  1:
      case  2:
      case  3:
      case  4:
      case  5:
      case  6:
      case  7:
      case  8:
      case  9:
      case 20:
      case 21: grab_user_info(port_in_use);
      	       Window_Show(userinfo_window, open_WHEREVER);
#ifdef DEBUG_CODE
       	       logfile('+',"SysOp requested userinfo window (originator).");
#endif
      	       break;
      case 10: /* And another BIG fall-through structure :-) */
      case 11:
      case 12:
      case 13:
      case 14:
      case 15:
      case 16:
      case 17:
      case 18:
      case 19:
      case 22:
      case 23: grab_user_info(sendto);
      	       Window_Show(userinfo_window, open_WHEREVER);
#ifdef DEBUG_CODE
       	       logfile('+',"SysOp requested userinfo window (destinator).");
#endif
      	       break;
      default: break;
   }

   return(TRUE);
}


void poll_the_wimp(void)
{
   lastproc = "poll_the_wimp() {0}";

   if (finished==TRUE)
   {
      if (doors_connectedokay==TRUE)
      {
         lastproc = "poll_the_wimp() {1}";
         doors_txf(port_in_use, "\033[37mCHAT FINISHED!\r\n\r\n");
         doors_close(port_in_use);
         if (chatting==TRUE)
         {
            lastproc = "poll_the_wimp() {2}";
            doors_txf(sendto, "\033[37mCHAT FINISHED!\r\n\r\n");
            doors_close(sendto);
         }
      }
      logfile('#',"Successful shutdown.");
      Event_CloseDown();
   }

   if (chatting==TRUE)
   {
      lastproc = "poll_the_wimp() {3}";
      if (doors_checkactive(port_in_use)==FALSE)
      {
         lastproc = "poll_the_wimp() {4}";
         logfile('*',"Originator lost carrier - terminating chat.");
         doors_txf(sendto, "\033[24;1H\r\n\033[1;31m%s has lost carrier.",username);
         doors_txf(sendto, "\r\n\033[33mChat finished...\r\n\r\n");
         doors_txf(sendto, "\033[32mPress [\?] or [Return] if nothing happens.\r\n\r\n");
         doors_close(sendto);
         logfile('#',"Successful shutdown.");
         Event_CloseDown();
      }

      if (doors_checkactive(sendto)==FALSE)
      {
         lastproc = "poll_the_wimp() {5}";
         logfile('*',"Destinator lost carrier - terminating chat.");
         doors_txf(port_in_use, "\033[24;1H\r\n\033[1;31m%s has lost carrier.",userdatum[sendto].username);
         doors_txf(port_in_use, "\r\n\033[33mChat finished...\r\n\r\n");
         doors_txf(port_in_use, "\033[32mPress [\?] or [Return] if nothing happens.\r\n\r\n");
         doors_close(port_in_use);
         logfile('#',"Successful shutdown.");
	 Event_CloseDown();
      }
      if (checktheirtime>99)
      {
         lastproc = "poll_the_wimp() {6}";
         checktheirtime=0;
         checktimes();
      } else
         checktheirtime++;
   } else
      if (doors_checkactive(port_in_use)==FALSE)
      {
         lastproc = "poll_the_wimp() {7}";
         logfile('*',"User dropped carrier.");
         finished=TRUE;
      }

   Wimp_Poll(event_mask, &event_lastevent);
   Event_Process(&event_lastevent);
}


static BOOL null_handler(event_pollblock *event, void *reference)
{
   reference = reference;
   event = event;

   lastproc = "null_handler()";

   if (updateit == TRUE) updatedisplay();

   return(TRUE);
}


static unsigned long int byte_to_word(unsigned char wimpblock[], int offset)
{
   /* Play around with the data block because C has no real ! and ? indirection
      system without using hacks like below. Ahem! Thanks to Acorn User for this
      code. */
   unsigned long int result = 0;
   int loop;

   lastproc = "byte_to_word()";

   offset += 3;
   result = wimpblock[offset--];
   for(loop = 0; loop < 3; loop++)
   {
      result=result<<8;
      result+=wimpblock[offset--];
   }
   return (result);
}



static void word_to_byte(unsigned long int input, unsigned char wimpblock[], int offset)
{
   /* Play around with the data block (again) because C has no real ! and ? indirection
      system without using hacks like below. Ahem! Thanks to Acorn User for this
      code. */
   unsigned long int mask = 255;

   lastproc = "word_to_byte()";

   wimpblock[offset++] = (char) (input & mask);
   mask <<= 8;
   wimpblock[offset++] = (char) ((input & mask) >> 8);
   mask <<= 8;
   wimpblock[offset++] = (char) ((input & mask) >> 16);
   mask <<= 8;
   wimpblock[offset++] = (char) ((input & mask) >> 24);
   return;
}


static void lowercase(char string[])
{
   int i=0;

   lastproc = "lowercase()";

   while ( string[i] )
   {
      string[i] = tolower(string[i]);
      i++;
   }
   return;
}


static void get_user_info(void)
{
   struct dummy
   {
      char junk[187];
      char username[31];
      char remainder[38];
   };
   int  reply=-1;

   struct dummy userdata;

   lastproc = "get_user_info()";

   userdata.junk[0] = 0;
   userdata.junk[1] = 0;
   userdata.junk[2] = 0;
   userdata.junk[3] = 0;
   r_in.r[0] = port_in_use;
   r_in.r[1] = (int)&userdata;
   _kernel_swi(ARCbbsDoors_SendRequest,&r_in,&r_out);

   do
   {
      poll_the_wimp();
      r_in.r[0] = port_in_use;
      r_in.r[1] = (int)&userdata;
      _kernel_swi(ARCbbsDoors_GetReply,&r_in,&r_out);
      reply = r_out.r[0];
   } while (reply!=0);

   strcpy(username,userdata.username);
   return;
}


static void draw_header(void)
{
   lastproc = "draw_header()";

   doors_txf(port_in_use, "\033[2J\033[1;32m           BudgieSoft Parlez door - ");
   doors_txf(port_in_use, "version 2.11, by Richard Murray\r\n\r\n");
   doors_txf(port_in_use, "This door allows you to send a message (and optionally chat) ");
   doors_txf(port_in_use, "to any user\r\n");
   doors_txf(port_in_use,"currently on-line. To abort, press [^C]. ");
#ifdef DEBUG_CODE
   doors_txf(port_in_use,"[debug active]");
#endif
   doors_txf(port_in_use, "\r\n\r\n");
   doors_txf(port_in_use, "\033[44m\033[37m  # \033[36mBaudR \033[37mUser# \033[36m");
   doors_txf(port_in_use, "Username                       \033[37mWhere           ");
   doors_txf(port_in_use, "\033[40m\r\n\033[35mScanning ports...");
   return;
}


static void get_online_users(int whichone)
{
   int  offset;
   int  maxports=35;
   user_info* userdatex = arcbbsfiler_get_status_pointer();
#ifdef DEBUG_CODE
   FILE *fp;
#endif

   lastproc = "get_online_users()";

   if (servertype == FALSE) maxports = 15;

   if (whichone==254) /* All of them... */
   {
      for (offset=0; offset<=maxports; offset++)
      {
         userdatum[offset].baudrate = userdatex[offset].baudrate;
         userdatum[offset].usernumber = userdatex[offset].usernumber;
         strcpy(userdatum[offset].username, userdatex[offset].username);
         strcpy(userdatum[offset].doing, userdatex[offset].doing);
         thisinuse[offset] = 1;
         if (userdatex[offset].baudrate==-1) thisinuse[offset] = 0;
         if (strlen(userdatum[offset].doing)<1) thisinuse[offset] = 0;
         strcpy(temp_string,userdatum[offset].doing);
         if (strcmp(temp_string,"Answer") == NULL) thisinuse[offset] = 0;
         if (strcmp(temp_string,"Logging on") == NULL) thisinuse[offset] = 0;
         if (strcmp(temp_string,"New user") == NULL) thisinuse[offset] = 0;
         if (seekvalidity(offset) == 0) thisinuse[offset] = 2;
      }
   } else /* ...or a selected port. */
   {
      userdatum[whichone].baudrate = userdatex[whichone].baudrate;
      userdatum[whichone].usernumber = userdatum[whichone].usernumber;
      strcpy(userdatum[whichone].username, userdatex[whichone].username);
      strcpy(userdatum[whichone].doing, userdatex[whichone].doing);
      thisinuse[whichone] = 1;
      if (userdatex[whichone].baudrate==-1) thisinuse[whichone] = 0;
      if (strlen(userdatum[whichone].doing)<1) thisinuse[whichone] = 0;
      strcpy(temp_string,userdatum[whichone].doing);
      if (strcmp(temp_string,"Answer") == NULL) thisinuse[whichone] = 0;
      if (strcmp(temp_string,"Logging on") == NULL) thisinuse[whichone] = 0;
      if (strcmp(temp_string,"New user") == NULL) thisinuse[whichone] = 0;
      if (seekvalidity(whichone) == 0) thisinuse[whichone] = 2;
   }

#ifdef DEBUG_CODE
   if ( (fp = fopen("<Parlez$Dir>.debug_wol","a") ) == NULL)
   {
      logfile('+',"Failed to open \"debug_wol\" file.");
   }
   else
   {
      fprintf(fp, "\n");
      fprintf(fp, "Maximum number of ports    : %d (ArcBBS 1.%i", maxports, (maxports==15)?63:64);
      fprintf(fp, " or compatible).\n");
      fprintf(fp, "user_info pointer location : &%08X\n", (int)user_info);
      fprintf(fp, "Report for \"who\'s on line\"...\n");
      for (offset=0; offset<=maxports; offset++)
      {
         fprintf(fp, "  Port %2d : %-30s (#%04d) @ %5dbps %-16s {%d}\n", offset, userdatum[offset].username, userdatum[offset].usernumber, userdatum[offset].baudrate, userdatum[offset].doing, thisinuse[offset]);
      }
      fclose(fp);
   }
#endif
   return;
}


static int seekvalidity(int port)
{
   int stat=0;

   lastproc = "seekvalidity()";

   r_in.r[0] = port;
   _kernel_swi(ARCbbsDoors_ReadStatus,&r_in,&r_out);
   stat = r_out.r[0];

   if (stat!=0) return(0); /* Port has another door running... */

   return(1); /* Available. */
}


static int checkavailable(int toport)
{
   struct dummy
   {
      char leader[44];
      int  isavailable;
      char trailer[208];
   };
   int  reply=0;
   int  stat=0;

   struct dummy userdata;

   userdata.leader[0] = 0;
   userdata.leader[1] = 0;
   userdata.leader[2] = 0;
   userdata.leader[3] = 0;
   r_in.r[0] = toport;
   r_in.r[1] = (int)&userdata;
   _kernel_swi(ARCbbsDoors_SendRequest,&r_in,&r_out);
   do
   {
      poll_the_wimp();
      r_in.r[0] = toport;
      r_in.r[1] = (int)&userdata;
      _kernel_swi(ARCbbsDoors_GetReply,&r_in,&r_out);
      reply = r_out.r[0];
   } while (reply!=0);

   stat = userdata.isavailable;
   if ((stat & 0x8000000) != 0) return(FALSE);  /* No_Chat_Requests set. */

   return(TRUE);
}


static void plot_online_users(int whichone)
{
   int  recurse=0;
   int  maxports=35;
   char colourise[]="12345678901234567890";

   lastproc = "plot_online_users()";

   if (servertype == FALSE) maxports = 12;

   doors_txf(port_in_use, "\033[s\033[7;1H\033[40m");
   for (recurse = 0; recurse<=maxports; recurse++)
   {
      if (thisinuse[recurse] > 0)
      {
         if (whichone==254) /* List all normally */
         {
            sprintf(colourise,"\033[36m ");
            if (thisinuse[recurse] == 2) sprintf(colourise,"\033[35;5m!\033[0;1;31m");
            doors_txf(port_in_use, "%s%2d ",colourise,recurse);
            if (recurse<maxports-3)
               doors_txf(port_in_use, "\033[37m%5d ",userdatum[recurse].baudrate);
            else
               doors_txf(port_in_use, "\033[37mLocal ");
            doors_txf(port_in_use, "\033[36m%5d ",userdatum[recurse].usernumber);
            doors_txf(port_in_use, "\033[37m%-30s ",userdatum[recurse].username);
            doors_txf(port_in_use, "\033[36m%s\033[37m\033[K\r\n",userdatum[recurse].doing);
         }
         else /* List all blue except the one we are interested in */
         {
            sprintf(colourise,"\033[34m ");
            if (whichone==recurse)
            {
               sprintf(colourise,"\033[36m ");
               if (thisinuse[recurse] == 2) sprintf(colourise,"\033[35;5m!\033[0;1;31m");
               doors_txf(port_in_use, "%s%2d ",colourise,recurse);
               if (recurse<maxports-3)
                  doors_txf(port_in_use, "\033[37m%5d ",userdatum[recurse].baudrate);
               else
                  doors_txf(port_in_use, "\033[37mLocal ");
               doors_txf(port_in_use, "\033[36m%5d ",userdatum[recurse].usernumber);
               doors_txf(port_in_use, "\033[37m%-30s ",userdatum[recurse].username);
               doors_txf(port_in_use, "\033[36m%s\033[37m\033[K\r\n",userdatum[recurse].doing);
            } else
            {
               doors_txf(port_in_use, "%s%2d ",colourise,recurse);
               if (recurse<maxports-3)
                  doors_txf(port_in_use, "%5d ",userdatum[recurse].baudrate);
               else
                  doors_txf(port_in_use, "Local ");
               doors_txf(port_in_use, "%5d ",userdatum[recurse].usernumber);
               doors_txf(port_in_use, "%-30s ",userdatum[recurse].username);
               doors_txf(port_in_use, "%s\033[37m\033[K\r\n",userdatum[recurse].doing);
            }
         }
      }
   }
   doors_txf(port_in_use, "\033[K\r\n\033[K\033[u\033[33;44m");
   return;
}


static int get_port(void)
{
   int  byte = -1;
   char portnumber[3]="";
   char toport=0;
   int  temp;

   lastproc = "get_port()";

   updateit=TRUE;
   doors_txf(port_in_use, "\r\n\033[32;40mWhich port would you like to send your ");
   doors_txf(port_in_use, "message to\? \033[33;44m  \b\b");

   do
   {
      poll_the_wimp();
      byte = doors_getbyte(port_in_use);
#ifdef DEBUG_CODE
      logfile('+',"get_port input : %d", byte);
#endif
      switch(byte)
      {
         case -1 : break;
         case  3 : doors_close(port_in_use);
               	   exit(EXIT_SUCCESS);
               	   break; /* Superfluous? */
         case  5 : doors_txf(port_in_use, "\033[s\033[1;1HIDENTITY: BUDGIESOFT PARLEZ ");
                   doors_txf(port_in_use, "DOOR V2.11 [23-08-96]\033[u\a");
                   break;
         case  8 : /* Drop down */
         case 127: junk_variable=strlen(portnumber);
              	   if (junk_variable!=0)
              	   {
               	      doors_txf(port_in_use, "\b \b");
               	      portnumber[junk_variable-1]='\0';
               	   }
              	   break;
         case 21 : junk_variable = strlen(portnumber);
              	   for (temp=0; temp<=junk_variable; temp++)
              	      doors_txf(port_in_use,"\b \b");
		   portnumber[0]='\0';
		   break;
	 case 13 : break;
	 default : if (byte>47 && byte<58) /* Pass only numbers... */
	 	   {
		      if (strlen(portnumber)<2)
		      {
	 	         sprintf(portnumber,"%s%c",portnumber,byte); /* ERK! */
	 	         doors_txf(port_in_use, "%c",byte);
	 	      } else
	 	      {
	 	         doors_txf(port_in_use, "\a");
	 	      }
	 	   }
      }
   } while (byte!=13);

   doors_txf(port_in_use, "\033[37;40m\r\n");

   toport=atoi(portnumber);

   sprintf(temp_string,"User wishes to communicate with port \'%s\'...",portnumber);
   logfile('*',temp_string);

   if (strlen(portnumber)==0)          /* Was a string entered? */
   {
      doors_txf(port_in_use, "Whoops!!!\r\n\r\n");
      logfile('*',"...but that wasn't a port was it!");
      finished = TRUE;
      return 254;
   }

   if (toport > 35)                    /* Port out of range?  [note - cannot enter -ve] */
   {
      doors_txf(port_in_use,"Hmmm... How many ports do you think there are\?\?\? ;-)\r\n\r\n");
      logfile('*',"...but that port doesn't exist!");
      finished = TRUE;
      return 254;
   }

   if (toport == port_in_use)          /* Chatting to yourself? */
   {
      doors_txf(port_in_use,"Talking to yourself again? This isn't a good sign...\r\n\r\n");
      logfile('*',"...but, erm, that... is... me...! Talking to myself? Aaaaaargh!");
      finished = TRUE;
      return 254;
   }

   if (thisinuse[toport]==2)          /* Using a door? */
   {
      doors_txf(port_in_use,"Sorry, that port is currently using another door...\r\n\r\n");
      logfile('*',"...but that port is using another door.");
      finished = TRUE;
      return 254;
   }

   if (thisinuse[toport]==0)          /* Not even here!? */
   {
      doors_txf(port_in_use,"Sorry, that port is not currently on-line. Refer to the ");
      doors_txf(port_in_use,"above listing...\r\n\r\n");
      logfile('*',"...but that port is not present.");
      finished = TRUE;
      return 254;
   }

   if (checkavailable(toport) == FALSE)/* No_Chat_Requests set? */
   {
      doors_txf(port_in_use,"Sorry, that user doesn't want to be disturbed...\r\n\r\n");
      logfile('*',"...but that user wants to be antisocial!");
      finished = TRUE;
      return 254;
   }

   return(toport);
}


static void updatedisplay(void)
{
   lastproc = "updatedisplay()";

   updatenow++;
   if (updatenow < 5) return;
   updatenow=0;
   get_online_users(sendto);
   plot_online_users(sendto);
   return;
}


static void getmessage(void)
{
   int  byte;
   int  temp;

   lastproc = "getmessage()";

   updateit=TRUE;
   doors_txf(port_in_use, "\r\n\033[32;40mPlease enter your message...\r\n:\033[44m");
   for (temp=0; temp<=77; temp++)
      doors_txf(port_in_use, " ");
   for (temp=0; temp<=77; temp++)
      doors_txf(port_in_use, "\b");

   do
   {
      poll_the_wimp();
      byte = doors_getbyte(port_in_use);
#ifdef DEBUG_CODE
      logfile('+',"get_message input : %d", byte);
#endif
      switch(byte)
      {
         case -1 : break;
         case  3 : doors_close(port_in_use);
               	   exit(EXIT_SUCCESS);
               	   break; /* Superfluous? */
         case  5 : doors_txf(port_in_use, "\033[s\033[1;1HIDENTITY: BUDGIESOFT PARLEZ ");
                   doors_txf(port_in_use, "DOOR V2.11 [23-08-96]\033[u\a");
                   break;
         case  8 : /* Drop down */
         case 127: junk_variable=strlen(ourmessage);
              	   if (junk_variable!=0)
              	   {
               	      doors_txf(port_in_use, "\b \b");
               	      ourmessage[junk_variable-1]='\0';
               	   }
              	   break;
         case 21 : junk_variable = strlen(ourmessage);
              	   junk_variable--;
              	   for (temp=0; temp<=junk_variable; temp++)
              	      doors_txf(port_in_use,"\b \b");
		   ourmessage[0]='\0';
		   break;
	 case 13 : break;
	 default : if (strlen(ourmessage)<78)
		   {
	 	      sprintf(ourmessage,"%s%c",ourmessage,byte);
	 	      doors_txf(port_in_use, "%c",byte);
	 	   } else
	 	   {
	 	      doors_txf(port_in_use, "\a");
	 	   }
      }
   } while (byte!=13);

   updateit=FALSE;
   doors_txf(port_in_use, "\033[37;40m\r\n");

   logfile('*',"And our wonderful message iiiissss:");
   logfile(' ',ourmessage);

   if (strlen(ourmessage)==0)
   {
      doors_txf(port_in_use, "Um... You\'re supposed to send messages y\'know!\r\n");
      logfile(' ',"...otherwise known as <astonished blank!>.");
      finished = TRUE;
   }

   doors_txf(port_in_use, "\033[36mWould you like the option of a private chat (Y/n) \? ");

   byte=doors_yesno(port_in_use, TRUE);

   if (byte==TRUE)
   {
      requestingachat=TRUE;
      logfile('*',"Ahhh... We want a chat!");
   }

   if (byte==-1)
   {
      doors_close(port_in_use);
      exit(EXIT_SUCCESS);
   }
   return;
}

static void sendtoport(void)
{
   int  tick=0;
   int  tock=0;
   int  status=0;
   int  timedout=FALSE;

   get_online_users(sendto);

   lastproc = "sendtoport()";

   if (thisinuse[sendto]==0)                                 /* Not even here!? */
   {
      doors_txf(port_in_use,"Sorry, that port has disconnected...\r\n");
      logfile('*',"Port disconnected before message delivered.");
      reasoncode = 1;
      senditasamessage=TRUE;
      return;
   }

   if (senditasamessage==FALSE)
   {
      r_in.r[0]=sendto;
      _kernel_swi(ARCbbsDoors_ReadStatus,&r_in,&r_out);
      status=r_out.r[0];
      if (status!=0)
      {
         doors_txf(port_in_use,"Sorry, that port is running another door...\r\n");
         logfile('*',"Port entered another door before message delivered.");
         send_cav_message();
         reasoncode = 2;
         senditasamessage=TRUE;
         return;
      }
   }

   if (checkavailable(sendto) == FALSE && !senditasamessage) /* No_Chat_Requests set? */
   {
      doors_txf(port_in_use,"Sorry, that user doesn't want to be disturbed...\r\n\r\n");
      logfile('*',"User suddenly decided to be antisocial!?");
      reasoncode = 3;
      senditasamessage=TRUE;
      return;
   }

   doors_txf(port_in_use,"Attempting to send...");
   poll_the_wimp();

   _kernel_swi(0x42,&r_in,&r_out);
   tick = r_out.r[0];
   tick = tick + 500;

   r_in.r[0] = sendto;
   r_in.r[1] = ourdoornumber;
   _kernel_swi(ARCbbsDoors_WriteStatus,&r_in,&r_out);

   while (status!=255 && !timedout)
   {
      poll_the_wimp();
      r_in.r[0]=sendto;
      _kernel_swi(ARCbbsDoors_ReadStatus,&r_in,&r_out);
      status=r_out.r[0];

      _kernel_swi(0x42,&r_in,&r_out);
      tock = r_out.r[0];
      if (tick < tock) timedout=TRUE;
   }

   if (status==255)
   {
      doors_txf(sendto,"\r\n\033[40;32mMessage from %s on port %d",username,port_in_use);
      doors_txf(sendto,"...\r\n\a:\033[33;44m%s\033[37;40m\r\n",ourmessage);
      logfile('*',"Message sent.");
      if (requestingachat==FALSE) doors_close(sendto);
      doors_txf(port_in_use, "Sent!\r\n");
      if (requestingachat==TRUE)
      {
         initiatechat();
         doors_close(sendto);
      }
   } else
   {
      doors_txf(port_in_use, "\033[35mSorry, \033[37mport %d is unobtainable. ",sendto);
      doors_txf(port_in_use, "Please check and try again.\r\n");
      logfile('*',"Port unobtainable (downloading?) before message delivered.");
      reasoncode = 4;
      senditasamessage=TRUE;
   }
   return;
}


static void sendmessage(void)
{
   int  messagelength = 0;
   FILE *msgfile;
   char filename[]="<Parlez$Dir>.MsgOutput";
   unsigned char uploadblock[260];

   lastproc = "sendmessage()";

   if (messagetype == 2) return;
   logfile('*',"Attempting to upload message to user's mailbox...");
   if (messagetype == FALSE)
   {
      doors_txf(port_in_use, "\r\nThe SysOp has forbidden failed messages to be uploaded to the user's mailbox.\r\n");
      logfile('*',"...but no go. SysOp has killed this feature <sob!>.");
   }

   if (( msgfile = fopen(filename,"wb") ) == NULL)
   {
      doors_txf(port_in_use, "\r\n\033[35mErk! I can't open output message file for you!\033[37m\r\nPlease inform the SysOp of this problem.\r\n");
      logfile('!',"Error: Cannot open output message file.");
      return;
   }

   fprintf(msgfile, "%s\n", username);
   fprintf(msgfile, "0\n");
   fprintf(msgfile, "%s\n", userdatum[sendto].username);
   fprintf(msgfile, "\n");
   fprintf(msgfile, "%08X\n",userdatum[sendto].usernumber);
   fprintf(msgfile, "00000000\n");
   fprintf(msgfile, "00000000\n");
   fprintf(msgfile, "00000000\n");
   fprintf(msgfile, "Message from Parlez...\n");

   messagelength = strlen(ourmessage) + 79;

   switch (reasoncode)
   {
      case 1 : messagelength = messagelength + 58;
      	       break;
      case 2 : messagelength = messagelength + 55;
      	       break;
      case 3 : messagelength = messagelength + 98;
      	       break;
      case 4 : messagelength = messagelength + 64;
      	       break;
      default: messagelength = messagelength + 56;
      	       break;
   }

   fprintf(msgfile, "%d\n", messagelength);
   fprintf(msgfile, "The message is:\n");
   fprintf(msgfile, "\n");
   fprintf(msgfile, "%s\n", ourmessage);
   fprintf(msgfile, "\n");
   switch (reasoncode)
   {
      case 1 : fprintf(msgfile, "The message was undelivered because you had disconnected.\n");
               break;
      case 2 : fprintf(msgfile, "The message was undelivered because your port was busy\n");
      	       break;
      case 3 : fprintf(msgfile, "The message was undelivered because you don't want to be disturbed\n");
      	       fprintf(msgfile, "by on-line pagers et cetera...\n");
      	       break;
      case 4 : fprintf(msgfile, "The message was undelivered because your port was unobtainable.\n");
               break;
      default: fprintf(msgfile, "The reason for non-delivery of this message is unknown!\n");
      	       break;
   }
   fprintf(msgfile, "\n");
   fprintf(msgfile, "/* Parlez is the BudgieSoft BBS user-to-user chat door */\n");
   fprintf(msgfile, "\n");
   fclose(msgfile);
   word_to_byte(80, uploadblock, 0);
   word_to_byte(0, uploadblock, 12);
   word_to_byte(0x41029, uploadblock, 16);
   strcpy((char *) &uploadblock[20], filename);
   r_in.r[0] = 17;
   r_in.r[1] = (int)uploadblock;
   r_in.r[2] = 0;
   _kernel_swi(Wimp__SendMessage, &r_in, &r_out);
   logfile('*',"...duh-duuuuh! There it goes!");
   return;
}


static void send_cav_message(void)
{
   char text[255]="";
   unsigned char msgblock[260];

   lastproc = "send_cav_message()";

   sprintf(text, "%02d%02d%-36s%s\n", sendto, port_in_use, username, ourmessage);
   word_to_byte(220, msgblock, 0);
   word_to_byte(0, msgblock, 12);
   word_to_byte(0x16F00, msgblock, 16);
   word_to_byte(3, msgblock, 20);
   strcpy( (char *) &msgblock[24], text);
   r_in.r[0] = 17;
   r_in.r[1] = (int) msgblock;
   r_in.r[2] = 0;
   _kernel_swi(Wimp__SendMessage, &r_in, &r_out);
   return;
}


static void initiatechat(void)
{
   int  byte=-1;
   int  goforit=FALSE;
   int  tick;
   int  tock;

   lastproc = "initiatechat()";

   doors_txf(port_in_use, "\r\n\033[36mAsking if %s would like to open a private chat...",userdatum[sendto].username);
   doors_txf(sendto, "\r\n\033[36mWould you like to open a private chat with %s\?",username);
   doors_txf(sendto, "\r\nPress [Y] or [Return] to chat, anything else to decline.\r\n");

   _kernel_swi(0x42,&r_in,&r_out);
   tick = r_out.r[0];
   tick = tick + 1000;

   do
   {
      poll_the_wimp();
      r_in.r[0] = sendto;
      _kernel_swi(ARCbbsDoors_InputRead,&r_in,&r_out);
      byte = r_out.r[0];

      _kernel_swi(0x42,&r_in,&r_out);
      tock = r_out.r[0];
      if (tick < tock) byte=255;

   } while (byte == -1);

   switch (byte)
   {
      case 255 : doors_txf(port_in_use, "\r\n\033[35mChat request timed out...\r\n");
      	         doors_txf(sendto, "\r\n\033[35mChat request timed out...\r\n");
      	         logfile('*',"Chat request timed out - somebody isn't paying attention!");
      	         break;
      case  13 : goforit=TRUE;
                 break;
      case 'Y' : goforit=TRUE;
      	       	 break;
      case 'y' : goforit=TRUE;
      	       	 break;
      default  : doors_txf(port_in_use, "\r\n\033[35m%s didn't want to chat...\r\n",userdatum[sendto].username);
                 doors_txf(sendto, "\033[35mChat request declined...\r\n");
                 logfile('*',"Chat request declined.");
                 break;
   }

   if (goforit==FALSE)
   {
      doors_txf(sendto, "\033[32mPress [\?] or [Return] if nothing happens.\r\n\r\n");
      return;
   }

   chat1.port = port_in_use;
   chat2.port = sendto;

   logfile('*',"Chat begun.");

   chatting=TRUE;
   patchdoingstring();
   drawsplitscreen(port_in_use);
   drawsplitscreen(sendto);
   drawsnoop();
   checktimes();

   while (chatting==TRUE)
   {
      getandplotit(&chat1, sendto, 3);
      getandplotit(&chat2, port_in_use, 14);

      poll_the_wimp();
   }
   doors_txf(port_in_use, "\033[24;0H\r\n\r\n\033[33mChat finished...\r\n\r\n");
   doors_txf(sendto, "\033[24;0H\r\n\r\n\033[33mChat finished...\r\n\r\n");
   doors_txf(sendto, "\033[32mPress [\?] or [Return] if nothing happens.\r\n\r\n");
   chatting=FALSE;
   return;
}


static void drawsplitscreen(int whose)
{
   int loop=0;

   lastproc = "drawsplitscreen()";

   doors_txf(whose, "\033[2J\033[1;32mBudgieSoft Parlez version 2.11 [August 1996] Dedicated to Steve Pursey\r\n");
   doors_txf(whose, "\033[36mĴ\033[33m%-30s\033[36mĴ\033[33m                     \033[36m\r\n\033[37m",username);
   for (loop=0; loop<=9; loop++)
   {
      doors_txf(whose,"%s\033[K\r\n",chat1.text[loop].line);
   }
   doors_txf(whose, "\033[36mĴ\033[33m%-30s\033[36mĴ\033[33m                     \033[36m\r\n\033[37m",userdatum[sendto].username);
   for (loop=0; loop<=9; loop++)
   {
      doors_txf(whose,"%s\033[K\r\n",chat2.text[loop].line);
   }
   doors_txf(whose, "\033[32m \033[33m^C, ^D or ^X to quit \033[32m \033[33m^R to redraw \033[32m \033[33m^L to clear \033[32m");
   return;
}


static void getandplotit(wibble *erk, int otherport, int yshift)
{
   int  byte=0;
   int  loop=0;
   int  ticker=0;
   char *spaceplace;
   int  posn=0;
   int  width=0;

   position *poz = &erk->posn;
   int checkport = erk->port;

   lastproc = "getandplotit()";

   while (byte != -1 || ticker < 128)
   {
      byte = doors_getbyte(checkport);
#ifdef DEBUG_CODE
      logfile('+',"getandplotit input : %d", byte);
#endif

      switch (byte)
      {
         case  3 : chatting=FALSE;
               	   break;
         case  4 : chatting=FALSE;
               	   break;
         case  5 : doors_txf(checkport, "\033[s\033[1;1HIDENTITY: BUDGIESOFT PARLEZ ");
                   doors_txf(checkport, "DOOR V2.11 [23-08-96]\033[u\a");
                   break;
         case  7 : doors_txf(checkport,"\a");
               	   doors_txf(otherport,"\a");
               	   break;
         case  8 : erk->text[poz->y].line[poz->x-1]='\0';
               	   doors_txf(checkport,"\033[%d;%dH\b \b",poz->y+yshift,poz->x+1);
               	   doors_txf(otherport,"\033[%d;%dH%c\b \b",poz->y+yshift,poz->x+1);
               	   poz->x--;
               	   if (poz->x < 0) poz->x = 0;
               	   break;
         case 10 : poz->y++;
              	   poz->x=0;
              	   if (poz->y < 10)
              	   {
              	      doors_txf(checkport,"\033[%d;%dH",poz->y+yshift,poz->x);
              	      doors_txf(otherport,"\033[%d;%dH",poz->y+yshift,poz->x);
              	   }
              	   drawsnoop();
              	   break;
         case 11 : chatting=FALSE;
	      	   break;
	 case 12 : for (loop=0; loop<=9; loop++)
	      	   {
	      	      erk->text[loop].line[0]='\0';
	      	   }
	      	   poz->x=0;
	      	   poz->y=0;
	      	   doors_txf(checkport,"\033[%d;1H\033[37m",yshift);
	      	   doors_txf(otherport,"\033[%d;1H\033[37m",yshift);
	      	   for (loop=0; loop<=9; loop++)
                   {
                      doors_txf(checkport,"%s\033[K\r\n",erk->text[loop].line);
                      doors_txf(otherport,"%s\033[K\r\n",erk->text[loop].line);
                   }
                   drawsnoop();
                   break;
         case 13 : poz->y++;
              	   poz->x=0;
              	   if (poz->y < 10)
              	   {
              	      doors_txf(checkport,"\033[%d;%dH",poz->y+yshift,poz->x);
              	      doors_txf(otherport,"\033[%d;%dH",poz->y+yshift,poz->x);
              	   }
              	   drawsnoop();
              	   break;
         case 18 : drawsplitscreen(checkport);
              	   checktimes();
              	   break;
	 case 24 : chatting=FALSE;
	      	   break;
	 case 27 : doors_txf(checkport,"\a");
	       	   break;
         case 127: erk->text[poz->y].line[poz->x-1]='\0';
               	   doors_txf(checkport,"\033[%d;%dH\b \b",poz->y+yshift,poz->x+1);
               	   doors_txf(otherport,"\033[%d;%dH\b \b",poz->y+yshift,poz->x+1);
               	   poz->x--;
               	   if (poz->x < 0) poz->x = 0;
               	   break;
         case 240: debuginfo(checkport, otherport);
              	   drawsplitscreen(checkport);
              	   drawsplitscreen(otherport);
              	   break;
         case 253: raise(SIGOSERROR);
         case 254: raise(SIGSTAK);
         default : if (byte>31)
         	   {
         	      erk->text[poz->y].line[poz->x]=byte;
         	      poz->x++;
         	      erk->text[poz->y].line[poz->x]='\0';
         	      doors_txf(checkport,"\033[%d;%dH\033[37m%c",poz->y+yshift,poz->x,byte);
         	      doors_txf(otherport,"\033[%d;%dH\033[37m%c",poz->y+yshift,poz->x,byte);
         	   }
         	   break;
      }

      if (poz->x>78)
      {
         poz->x=0;

         if (poz->y == 9)
         {
            strcpy(erk->text[0].line, erk->text[3].line);
            strcpy(erk->text[1].line, erk->text[4].line);
            strcpy(erk->text[2].line, erk->text[5].line);
            strcpy(erk->text[3].line, erk->text[6].line);
            strcpy(erk->text[4].line, erk->text[7].line);
            strcpy(erk->text[5].line, erk->text[8].line);
            strcpy(erk->text[6].line, erk->text[9].line);
            CLEAR(erk->text[7].line);
            CLEAR(erk->text[8].line);
            CLEAR(erk->text[9].line);
   	    doors_txf(checkport,"\033[%d;1H\033[37m",yshift);
	    doors_txf(otherport,"\033[%d;1H\033[37m",yshift);
            for (loop=0; loop<=9; loop++)
            {
               doors_txf(checkport,"%s\033[K\r\n",erk->text[loop].line);
               doors_txf(otherport,"%s\033[K\r\n",erk->text[loop].line);
            }
	    poz->y = 6;
         }

      	 spaceplace=strrchr(erk->text[poz->y].line,32);
         if (spaceplace!=NULL)
         {
            posn=(int)spaceplace-(int)erk->text[poz->y].line;
            posn++;
            width=strlen(erk->text[poz->y].line);
            width = width-posn;
            doors_txf(checkport, "\033[%d;%dH",poz->y+yshift,strlen(erk->text[poz->y].line)+1);
            doors_txf(otherport, "\033[%d;%dH",poz->y+yshift,strlen(erk->text[poz->y].line)+1);
            for (loop=0; loop<=width; loop++)
            {
               doors_txf(checkport,"\b \b");
               doors_txf(otherport,"\b \b");
               erk->text[poz->y+1].line[loop]=erk->text[poz->y].line[posn+loop];
            }
            erk->text[poz->y].line[posn]='\0';
            erk->text[poz->y+1].line[loop+1]='\0';
            doors_txf(checkport,"\033[%d;1H%s",poz->y+yshift+1,erk->text[poz->y+1].line);
            doors_txf(otherport,"\033[%d;1H%s",poz->y+yshift+1,erk->text[poz->y+1].line);
            poz->x=strlen(erk->text[poz->y+1].line);
         }
         poz->y++;
         drawsnoop();
      }

      if (poz->y>9)
      {
         strcpy(erk->text[0].line, erk->text[3].line);
         strcpy(erk->text[1].line, erk->text[4].line);
         strcpy(erk->text[2].line, erk->text[5].line);
         strcpy(erk->text[3].line, erk->text[6].line);
         strcpy(erk->text[4].line, erk->text[7].line);
         strcpy(erk->text[5].line, erk->text[8].line);
         strcpy(erk->text[6].line, erk->text[9].line);
         CLEAR(erk->text[7].line);
         CLEAR(erk->text[8].line);
         CLEAR(erk->text[9].line);
	 doors_txf(checkport,"\033[%d;1H\033[37m",yshift);
	 doors_txf(otherport,"\033[%d;1H\033[37m",yshift);
         for (loop=0; loop<=9; loop++)
         {
            doors_txf(checkport,"%s\033[K\r\n",erk->text[loop].line);
            doors_txf(otherport,"%s\033[K\r\n",erk->text[loop].line);
         }
         poz->y=7;
         drawsnoop();
      }
      ticker++;
   }
   return;
}


static void checktimes(void)
{
   struct dummy
   {
      char leader[172];
      int  tickertape;
      char trailer[80];
   };
   int  reply=0;

   struct dummy userdata;

   lastproc = "checktimes() {0}";

   if (nochecktheirtime==TRUE) return;

   userdata.leader[0] = 0;
   userdata.leader[1] = 0;
   userdata.leader[2] = 0;
   userdata.leader[3] = 0;
   r_in.r[0] = port_in_use;
   r_in.r[1] = (int)&userdata;
   _kernel_swi(ARCbbsDoors_SendRequest,&r_in,&r_out);
   do
   {
      poll_the_wimp();
      r_in.r[0] = port_in_use;
      r_in.r[1] = (int)&userdata;
      _kernel_swi(ARCbbsDoors_GetReply,&r_in,&r_out);
      reply = r_out.r[0];
   } while (reply!=0);
   ourtime = userdata.tickertape;

   lastproc = "checktimes() {1}";

   userdata.leader[0] = 0;
   userdata.leader[1] = 0;
   userdata.leader[2] = 0;
   userdata.leader[3] = 0;
   r_in.r[0] = sendto;
   r_in.r[1] = (int)&userdata;
   _kernel_swi(ARCbbsDoors_SendRequest,&r_in,&r_out);
   do
   {
      poll_the_wimp();
      r_in.r[0] = sendto;
      r_in.r[1] = (int)&userdata;
      _kernel_swi(ARCbbsDoors_GetReply,&r_in,&r_out);
      reply = r_out.r[0];
   } while (reply!=0);
   theirtime = userdata.tickertape;

   ourtime = ourtime / 60;
   theirtime = theirtime / 60;

   lastproc = "checktimes() {2}";

   Icon_printf(snoop_window,21,"%d minutes remaining",ourtime);
   Icon_printf(snoop_window,23,"%d minutes remaining",theirtime);

   lastproc = "checktimes() {3}";

   if (ourtime == -1)
   {
      doors_txf(port_in_use,"\033[33m\033[2;44HUnlimited time.      ");
      doors_txf(sendto,"\033[33m\033[2;44HUnlimited time.     ");
   } else
   {
      if (ourtime>2)
      {
         doors_txf(port_in_use,"\033[33m\033[2;44H%3d minutes remaining",ourtime);
         doors_txf(sendto,"\033[33m\033[2;44H%3d minutes remaining",ourtime);
      }
      if (ourtime==2)
      {
         doors_txf(port_in_use,"\033[5;35m\033[2;44HLast minute in chat! \033[0;1m");
         doors_txf(sendto,"\033[5;35m\033[2;44HLast minute in chat! \033[0;1m");
      }
      if (ourtime<2)
      {
         doors_txf(port_in_use,"\033[5;31m\033[2;44H   ** TIME OUT **    \033[0;1m");
         doors_txf(sendto,"\033[5;31m\033[2;44H   ** TIME OUT **   \033[0;1m");
         doors_txf(sendto, "!24;0H\r\n\033[32mPress [\?] or [Return] if nothing happens.\r\n\r\n");
         logfile('*',"Originator timed-out.");
         finished=TRUE;
      }
   }

   if (theirtime == -1)
   {
      doors_txf(sendto,"\033[33m\033[13;44HUnlimited time.     ");
      doors_txf(port_in_use,"\033[33m\033[13;44HUnlimited time.      ");
   } else
   {
      if (theirtime>2)
      {
         doors_txf(sendto,"\033[33m\033[13;44H%3d minutes remaining",theirtime);
         doors_txf(port_in_use,"\033[33m\033[13;44H%3d minutes remaining",theirtime);
      }
      if (theirtime==2)
      {
         doors_txf(sendto,"\033[5;35m\033[13;44HLast minute in chat! \033[0;1m");
         doors_txf(port_in_use,"\033[5;35m\033[13;44HLast minute in chat! \033[0;1m");
      }
      if (theirtime<2)
      {
         doors_txf(sendto,"\033[5;31m\033[13;44H   ** TIME OUT **   \033[0;1m");
         doors_txf(sendto, "!24;0H\r\n\033[32mPress [\?] or [Return] if nothing happens.\r\n\r\n");
         doors_txf(port_in_use,"\033[5;31m\033[13;44H   ** TIME OUT **    \033[0;1m");
         logfile('*',"Destinator timed-out.");
         finished=TRUE;
      }
   }
   return;
}


static void patchdoingstring(void)
{
   int  maxports=35;
   user_info* userdatex = arcbbsfiler_get_status_pointer();

   lastproc = "patchdoingstring()";

   if (servertype == FALSE) maxports = 12;

   sprintf(userdatex[port_in_use].doing,"Parlez with %d.",sendto);
   sprintf(userdatex[sendto].doing,"Parlez with %d.",port_in_use);

   return;
}


static void debuginfo(int whoto, int whonotto)
{
   int byte=-1;
   int nicekey=0;

   nochecktheirtime = TRUE;

   lastproc = "debuginfo()";

   logfile('*',"Somebody is reading the debugging info! :-)");

   doors_txf(whonotto, "\r\n\033[35mHmmm... %cuess who's %ceing naughty! PLEASE WAIT!\r\n",'G','b');
   doors_txf(whoto, "\033[2J\033[1;37mDebugging information ; Parlez 2.11 [Friday, 23rd August 1996].\r\n\r\n");
   doors_txf(whoto, "\033[36mThis version of Parlez is written in C (Acorn/Norcroft C release 4).\r\n\r\n");
   doors_txf(whoto, "Thanks to Richard Sargeant for help and Steve Pursey for testing...\r\n\r\n");
   doors_txf(whoto, "This code is linked with C 'stubs' and DeskLib v2.30.\r\n");
   doors_txf(whoto, "Parlez 2 uses the BudgieSoft DoorLib.\r\n\r\n");
   doors_txf(whoto, "[snstat = %d]\r\n", snoop_status);
   doors_txf(whoto, "\033[32mChat originator : \033[33m%s \033[32mon port \033[33m%d\033[32m.\r\n",username,port_in_use);
   doors_txf(whoto, "\033[32mChat destinator : \033[33m%s \033[32mon port \033[33m%d\033[32m.\r\n\r\n",userdatum[sendto].username,sendto);
   doors_txf(whoto, "The BBS server in use has been identified as ");
   switch (servertype)
   {
      case TRUE : doors_txf(whoto, "\033[33mArcBBS 1.64 \033[32mwith \033[33m32 \033[32mports.\r\n");
                  break;
      case FALSE: doors_txf(whoto, "\033[33mArcBBS 1.63 \033[32mwith \033[33m12 \033[32mports.\r\n");
                  break;
      default   : doors_txf(whoto, "\033[31mERROR! Not identified!\?\r\n\033[32m");
                  break;
   }
   switch (messagetype)
   {
      case TRUE : doors_txf(whoto, "The SysOp wants failed messages to be uploaded.\r\n\r\n");
                  break;
      case FALSE: doors_txf(whoto, "The SysOp does NOT want failed messages to be uploaded.\r\n\r\n");
                  break;
      case    2 : doors_txf(whoto, "Failed messages cannot be uploaded (ArmBBS mode)...\r\n\r\n");
                  break;
      default   : doors_txf(whoto, "\033[31mEh!? Failure in \'Parlez$Message$Upload\' code... :-(%\r\n\r\n");
                  break;
   }
   doors_txf(whoto, "\033[37mHave you any good ideas for Parlez? Contact \'\033[36mrmurray@arcticbb.demon.co.uk\033[37m\'.\r\n\r\n");
   doors_txf(whoto, "\033[34mParlez is (C) Copyright 1996 %cichard %curray.\r\n",'R','M');
   doors_txf(whoto, "A BudgieSoft release.\r\n\r\n\r\n");

   nicekey = getrandom(26) + '@';
   doors_txf(whoto, "\033[33mPlease press an interesting looking key... How about the \'\033[35m%c\033[33m\' key? :-)\r\n",nicekey);

   do
   {
      poll_the_wimp();
      r_in.r[0] = whoto;
      _kernel_swi(ARCbbsDoors_InputRead,&r_in,&r_out);
      byte = r_out.r[0];
   } while (byte == -1);

   r_in.r[0] = whonotto;
   _kernel_swi(ARCbbsDoors_ClearInput,&r_in,&r_out);

   nochecktheirtime = FALSE;
}


static void drawsnoop(void)
{
   lastproc = "drawsnoop()";
   Icon_SetText(snoop_window,20,username);
   Icon_printf(snoop_window,21,"%d minutes remaining",ourtime);
   Icon_SetText(snoop_window,0,chat1.text[0].line);
   Icon_SetText(snoop_window,1,chat1.text[1].line);
   Icon_SetText(snoop_window,2,chat1.text[2].line);
   Icon_SetText(snoop_window,3,chat1.text[3].line);
   Icon_SetText(snoop_window,4,chat1.text[4].line);
   Icon_SetText(snoop_window,5,chat1.text[5].line);
   Icon_SetText(snoop_window,6,chat1.text[6].line);
   Icon_SetText(snoop_window,7,chat1.text[7].line);
   Icon_SetText(snoop_window,8,chat1.text[8].line);
   Icon_SetText(snoop_window,9,chat1.text[9].line);
   Icon_SetText(snoop_window,22,userdatum[sendto].username);
   Icon_printf(snoop_window,23,"%d minutes remaining",theirtime);
   Icon_SetText(snoop_window,10,chat2.text[0].line);
   Icon_SetText(snoop_window,11,chat2.text[1].line);
   Icon_SetText(snoop_window,12,chat2.text[2].line);
   Icon_SetText(snoop_window,13,chat2.text[3].line);
   Icon_SetText(snoop_window,14,chat2.text[4].line);
   Icon_SetText(snoop_window,15,chat2.text[5].line);
   Icon_SetText(snoop_window,16,chat2.text[6].line);
   Icon_SetText(snoop_window,17,chat2.text[7].line);
   Icon_SetText(snoop_window,18,chat2.text[8].line);
   Icon_SetText(snoop_window,19,chat2.text[9].line);

   return;
}


static int getrandom(int maxnumber)
{
   lastproc = "getrandom()";
   return (int)(((float)rand()/(float)RAND_MAX)*maxnumber)+1;
}


#ifndef logfile
static void logfile(char xtype, char xmessage[])
{
   if (dologit)
   {
      FILE *fp = fopen("<Parlez$Dir>.LogFile","a");
      if (fp)
      {
         if (xmessage)
         {
            fprintf(fp, "%c : %s\n", xtype, xmessage);
         }
         else
         {
            fprintf(fp, "\n\n");
         }
         fclose(fp);
      }
   }
   return;
}
#endif


static BOOL budgiesoft_message(event_pollblock *event, void *ref)
{
   char fromport[3];
   int  from;
   char toport[3];
   int  to;
   char uname[31];
   char umsg[256];
   int  actioncode;
   char *messagepointer = event->data.message.data.bytes;

   ref=ref;

   lastproc = "budgiesoft_message()";

   if ( ! (doors_connectedokay==TRUE) ) return TRUE; /* claimed */

   actioncode = (int)byte_to_word((void *)messagepointer,0);

   if (actioncode != 3) return TRUE; /* claimed */

   fromport[0] = messagepointer[4];
   fromport[1] = messagepointer[5];
   fromport[2] = '\0';
   from = atoi(fromport);
   toport[0] = messagepointer[6];
   toport[1] = messagepointer[7];
   toport[2] = '\0';
   to = atoi(toport);

   strncpy(uname, (char *)&messagepointer[8],31);
   strncpy(umsg, (char *)&messagepointer[44],180);

   if (to == port_in_use)
   {
      if (chatting == TRUE)
      {
         doors_txf(port_in_use,"\033[1;40;35m\033[3;1HInbound message (from port #%d) for you from %s\033[K",from,uname);
         doors_txf(port_in_use,"\033[4;1HMessage reads:\033[K");
         doors_txf(port_in_use,"\033[6;1H\033[K");
         doors_txf(port_in_use,"\033[5;1H%s\033[K",umsg);
         doors_txf(port_in_use,"\033[32m\033[7;1HPress ^R to redraw screen...\033[K\033[37m");
      }
      else
      {
         doors_txf(port_in_use,"\033[1;40;35m\033[14;1HInbound message (from port #%d) for you from %s\033[K",from,uname);
         doors_txf(port_in_use,"\033[15;1HMessage reads:\033[K");
         doors_txf(port_in_use,"\033[17;1H\033[K");
         doors_txf(port_in_use,"\033[16;1H%s\033[K",umsg);
         doors_txf(port_in_use, "\033[K\r\n\033[K\033[u\033[33;44m");
      }
      sprintf(temp_string,"Message to port %d (%s) from port %d (%s).",port_in_use,username,from,uname);
      logfile('*',temp_string);
   }
   if (to == sendto)
   {
      if (chatting == TRUE)
      {
         doors_txf(sendto,"\033[1;35m\033[14;1HInbound message (from port #%d) for you from %s\033[K",from,uname);
         doors_txf(sendto,"\033[15;1HMessage reads:\033[K");
         doors_txf(sendto,"\033[17;1H\033[K");
         doors_txf(sendto,"\033[16;1H%s\033[K",umsg);
         doors_txf(sendto,"\033[32m\033[18;1HPress ^R to redraw screen...\033[K\033[37m");
      }
      else
      {
         doors_txf(sendto,"\033[1;40;35m\033[1;1HInbound message (from port #%d) for you from %s\033[K",from,uname);
         doors_txf(sendto,"\033[2;1HMessage reads:\033[K");
         doors_txf(sendto,"\033[4;1H\033[K");
         doors_txf(sendto,"\033[3;1H%s\033[K",umsg);
      }
      sprintf(temp_string,"Message to port %d (%s) from port %d (%s).",sendto,userdatum[sendto].username,from,uname);
      logfile('*',temp_string);
   }

   return TRUE; /* claimed */
}


static void grab_user_info(int port)
{
   struct geninfo
   {
      int  _usernumber;
      int  _firstlogon;
      int  _lastlogon;
      int  _privatemail;
      int  _startmail;
      int  _endmail;
      int  _messagelastread;
      int  _filelastread;
      int  _terminaltype;
      int  _messageflags;
      int  _fileflags;
      int  _userflags;
      int  _ratio;
      int  _userlevel;
      int  _logons;
      int  _uploads;
      int  _downloads;
      int  _timeallowedtoday;
      int  _timeusedtoday;
      int  _fidocredit;
      int  _fidoflags;
      int  _currentmessagearea;
      int  _currentfilearea;
      int  _outboxstart;
      int  _outboxend;
      int  _outboxcount;
      char _confjoined[64];
      int  _timeusedthiscall;
      int  _timeleftthiscall;
      int  _timeallocatedthiscall;
      int  _connectspeed;
      char _arqinuse[1];
      char _callrate[1];
      char _pagelength[1];
      char _username[31];
      char _remainder[38];
   };
   struct addrinfo
   {
      char _uusername[31];
      char _realname[31];
      char _address1[31];
      char _address2[31];
      char _address3[31];
      char _address4[31];
      char _postcode[11];
      char _telephone[31];
      char _uremainder[28];
   };
   int  reply=-1;
   int  minute=0;
   int  second=0;
   struct geninfo userdata;
   struct addrinfo userdata2;

   lastproc = "grabuserinfo()";

   userdata._usernumber = 0;
   r_in.r[0] = port;
   r_in.r[1] = (int)&userdata;
   _kernel_swi(ARCbbsDoors_SendRequest,&r_in,&r_out);
   do
   {
      poll_the_wimp();
      r_in.r[0] = port;
      r_in.r[1] = (int)&userdata;
      _kernel_swi(ARCbbsDoors_GetReply,&r_in,&r_out);
      reply = r_out.r[0];
   } while (reply!=0);

   reply = -1;

   userdata2._uusername[0] = 1;
   userdata2._uusername[1] = 0;
   userdata2._uusername[2] = 0;
   userdata2._uusername[3] = 0;
   r_in.r[0] = port;
   r_in.r[1] = (int)&userdata2;
   _kernel_swi(ARCbbsDoors_SendRequest,&r_in,&r_out);
   do
   {
      poll_the_wimp();
      r_in.r[0] = port;
      r_in.r[1] = (int)&userdata2;
      _kernel_swi(ARCbbsDoors_GetReply,&r_in,&r_out);
      reply = r_out.r[0];
   } while (reply!=0);

   Icon_SetText(userinfo_window,12,userdata2._uusername);
   Icon_printf(userinfo_window,13,"%d",userdata._usernumber);
   Icon_printf(userinfo_window,14,"%X",userdata._userlevel);
   Icon_SetText(userinfo_window,15,userdata2._realname);
   Icon_SetText(userinfo_window,16,userdata2._address1);
   Icon_SetText(userinfo_window,17,userdata2._address2);
   Icon_SetText(userinfo_window,18,userdata2._address3);
   Icon_printf(userinfo_window,19,"%s.  %s",userdata2._address4,userdata2._postcode);
   Icon_SetText(userinfo_window,20,userdata2._telephone);
   Icon_printf(userinfo_window,21,"%d",userdata._logons);
   Icon_printf(userinfo_window,22,"%d",userdata._privatemail);
   Icon_printf(userinfo_window,23,"%d",userdata._ratio);
   Icon_printf(userinfo_window,24,"%d",userdata._uploads);
   Icon_printf(userinfo_window,25,"%d",userdata._downloads);
   Icon_printf(userinfo_window,26,"%d",userdata._connectspeed);
   switch(userdata._arqinuse[0])
   {
      case 0 : Icon_SetText(userinfo_window,27,"No");
      	       break;
      case 1 : Icon_SetText(userinfo_window,27,"Yes");
      	       break;
      default: Icon_SetText(userinfo_window,27,"???");
      	       break;
   }
   switch(userdata._terminaltype)
   {
      case 0 : Icon_SetText(userinfo_window,37,"TTY");
      	       break;
      case 1 : Icon_SetText(userinfo_window,37,"VT52");
      	       break;
      case 2 : Icon_SetText(userinfo_window,37,"VT100");
      	       break;
      case 3 : Icon_SetText(userinfo_window,37,"ANSI");
      	       break;
      case 16: Icon_SetText(userinfo_window,37,"MTerm");
      	       break;
      default: Icon_SetText(userinfo_window,37,"???");
      	       break;
   }

   minute = userdata._timeleftthiscall / 60;
   second = userdata._timeleftthiscall % 60;
   Icon_printf(userinfo_window,39,"%02d:%02d",minute,second);

   return;
}


static void signl_stack(int sig)
{
   sig = sig;
   crash_last = lastproc;
   longjmp(posible_travectoria, SIGSTAK);
}


static void signl_oserr(int sig)
{
   _kernel_oserror *last_error;
   char *errmsg = "Error condition unknown";
   sig = sig;
   last_error = /*(_kernel_oserror*)*/ _kernel_last_oserror();
   if (last_error) errmsg = last_error->errmess;
   crash_last = errmsg;
   longjmp(posible_travectoria, SIGOSERROR);
}


static void panic(int type)
{
   if (doors_connectedokay==TRUE)
   {
      reportfatalerror(port_in_use, type);
      doors_close(port_in_use);
      if (chatting==TRUE)
      {
         reportfatalerror(sendto, type);
         doors_close(sendto);
      }
   }
   coredump(type);
   logfile('!', "Panic! Fatal error trapped, coredump created.");
   exit(EXIT_FAILURE);
}


static void reportfatalerror(int whoto, int type)
{
   doors_txf(whoto, "\a\033[0;1;37;40m\033[2J\a\033[33m\a");
   doors_txf(whoto, "Unfortunately it appears that Parlez has suffered a fatal error\r\n");
   doors_txf(whoto, "and must therefore exit immediately.\r\n\r\n");
   doors_txf(whoto, "\033[32m   Last procedure        : %s\r\n", crash_last);
   if (type==SIGOSERROR)
      doors_txf(whoto, "   Error type            : SIGOSERROR (OS error)\r\n");
   else
      doors_txf(whoto, "   Error type            : SIGSTAK (stack error)\r\n");
   doors_txf(whoto, "   Temp variable         : %d\r\n", junk_variable);
   doors_txf(whoto, "   Temporary string      : \"%s\"\r\n", temp_string);
   doors_txf(whoto, "   Last SWI registers    :\r\n");
   doors_txf(whoto, "      IN  : R0 %d, R1 %d, R2 %d, R3 %d, R4 %d, R5 %d.\r\n", r_in.r[0], r_in.r[1], r_in.r[2], r_in.r[3], r_in.r[4], r_in.r[5]);
   doors_txf(whoto, "      OUT : R0 %d, R1 %d, R2 %d, R3 %d, R4 %d, R5 %d.\r\n", r_out.r[0], r_out.r[1], r_out.r[2], r_out.r[3], r_out.r[4], r_out.r[5]);
   doors_txf(whoto, "   Core dump will be produced.\r\n\r\n");
   doors_txf(whoto, "\033[35;5mPLEASE INFORM THE SYSOP QUOTING THE ABOVE.\033[0;1;33m\r\n\r\n");
   doors_txf(whoto, "Sorry for any inconvenience caused...\r\n\r\n\r\n");
   return;
}


static void coredump(int type)
{
   FILE *f;
   int current;

   remove("<Parlez$Dir>.!COREDUMP!");
   f = fopen("<Parlez$Dir>.!COREDUMP!", "wb");
   if (!f) return;
   setbuf(f, NULL);
   fprintf(f, "   Last procedure        : %s\n", crash_last);
   if (type==SIGOSERROR)
      fprintf(f, "   Error type            : SIGOSERROR (OS error)\n");
   else
      fprintf(f, "   Error type            : SIGSTAK (stack error)\n");
   fprintf(f, "   Temp variable         : %d\n", junk_variable);
   fprintf(f, "   Temporary string      : \"%s\"\n", temp_string);
   fprintf(f, "   Last SWI registers    :\n");
   fprintf(f, "      IN  : R0 %d, R1 %d, R2 %d, R3 %d, R4 %d, R5 %d.\n", r_in.r[0], r_in.r[1], r_in.r[2], r_in.r[3], r_in.r[4], r_in.r[5]);
   fprintf(f, "      OUT : R0 %d, R1 %d, R2 %d, R3 %d, R4 %d, R5 %d.\n", r_out.r[0], r_out.r[1], r_out.r[2], r_out.r[3], r_out.r[4], r_out.r[5]);
   fprintf(f, "\n\n   Core dump follows:\n\n");
   r_in.r[0] = -1;
   r_in.r[1] = -1;
   _kernel_swi(0x400EC, &r_in, &r_out); /* Wimp_SlotSize */
   current = r_out.r[0];
   fwrite((void *)0x8000, current, 1, f);
   fclose(f);
   return;
}
