/*->c.main                     */
/* Hearsay 2.00 September 1990 */
/* (c) David Pilling           */


#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <ctype.h>
#include <time.h>
#include <locale.h>

#include "h.os"
#include "h.wimp"
#include "h.sprite"
#include "h.wimpt"
#include "h.bbc"
#include "h.akbd"
#include "h.werr"
#include "h.flex"


#include "h.wos"
#include "h.timex"
#include "h.fsx"
#include "h.trans"

#include "h.dir"

#include "h.ram"

#include "h.key"

#include "h.mym"
#include "h.pr"

#include "h.xext"

#include "h.serial"
#include "h.serialdev"
#include "h.file"
#include "h.batch"
#include "h.replay"

#include "h.vax"

#include "h.ftp"


#include "h.view"

#include "h.vtdef"
#include "h.vtwimp"
#include "h.vtselect"
#include "h.vtkey"
#include "h.vtprint"
#include "h.vtmenu"

#include "h.vxdef"
#include "h.vxwimp"
#include "h.vxbuff"
#include "h.vxsend"
#include "h.vxkey"
#include "h.vxedit"
#include "h.vxmenu"

#include "h.tek"
#include "h.term"

#include "h.script"
#include "h.xmodem"

#include "h.mnpx"
#include "h.record"

#include "h.main"

#define PROD

#ifndef PROD

#define DBUG

#endif

/*****************************************************************************/





#define MAXPATHS 12

static char * hearsaypaths[MAXPATHS]=
{
 "Hearsay$TXBatch",
 "Hearsay$RXBatch",
 "Hearsay$LogFile",
 "Hearsay$AutoRun",
 "Hearsay$Library",
 "Hearsay$TeleDir",
 "Hearsay$BatMan",
 "Hearsay$Dir",
 "HearsayRes$Dir",
 "Hearsay$PrintFile",
 "Hearsay$Driver",
 "Hearsay$Resources",
};


static char cachedpaths[MAXPATHS][256];


static void cachepaths(void)
{
 int    i;
 char * p;

 for(i=0;i<MAXPATHS;i++)
 {
  p=getenv(hearsaypaths[i]);
  if(p) strcpy(cachedpaths[i],p);
  else  cachedpaths[i][0]=0;
 }
}


static void clearpaths(void)
{
 int  i;
 char string[256];

 for(i=0;i<MAXPATHS;i++)
 {
  sprintf(string,"Unset %s",hearsaypaths[i]);
  oscli(string);
 }
}




char * path(int index)
{
 return(cachedpaths[index]);
}











void palchange(void)
{
 vtpalchange();
 vxpalchange();
 vdupalvars();
}



void setmodevars(void)
{
 /* set up mode specific things like width */

 if(wimpt_checkmode()) 
 {
  vdumodevars();
  vtmodechange();
  vxmodechange();
 }
}



void terminate(void) 
{
 keyboardoncaret(0);

 savebatch();
 dirclose();

 printclear();

 deactivatedriver();

 xexec("device_terminate",NULL,NULL,NULL);

 xexec("sys_terminate",NULL,NULL,NULL);

 wimp_taskclose(taskhandle);

 oscli("Seteval Hearsay$Case <Hearsay$Case>-1");

 if(!strcmp(getenv("Hearsay$Case"),"0"))
 {
  /* last invocation of Hearsay */
  clearpaths();
  oscli("Unset Hearsay$Case");
 }

 exit(0);
}



int termnok(void)
{
 int n;
 int code;

 n=vxbunsaved();
 if(n) code=confirm(CONDC,"%d {CONF00} %s {CONF03}",
                                  n,n==1?"{CONF01}":"{CONF02}")!=1;
 else  code=0;

 if(!code)
 {
  if(active && (online || ftpactive))
  code=confirm(CONYN,"{DEV1}")!=1; }

 if(!code)
 {
  deactivate();
  poll(TERMZERO);
 }

 return(code);
}


void terminatec(void)
{
 if(termnok()) return;
 terminate();
}


/*************************************************************************/

static int cfixtime;
static int cfixhandle;
static int cfixbuttons;
static int cfixicon;
static int cfixmx;
static int cfixmy;
static int cfixfirst;            /* flag if waiting for click */




static void cfixsave(void)
{
 cfixfirst=1;
 cfixbuttons=buttons;
 cfixhandle=ewindow;
 cfixicon=icon;
 cfixmx=mousex;
 cfixmy=mousey;
 cfixtime=clock();
 addzeroevent(CFIXZERO);
}


static void cfixload(void)
{
 micon=icon=cfixicon;
 mhandle=ewindow=cfixhandle;
 mousex=cfixmx;
 mousey=cfixmy;
 cfixfirst=0;
 remzeroevent(CFIXZERO);

 if(ewindow==whandle[VTERM]) vtclick();
 else
 if(ewindow==whandle[VDATA]) vxclick();
}




static void cfixzero(void)
{
 if((zerotime-cfixtime)>25)
 {
  buttons=cfixbuttons;
  cfixload();
 }
}



static int clickfix(void)
{
 switch(buttons)
 {
  case    0x2:                   /* menu buttons do nothing */
  case   0x20:
  case  0x200:
              return(1);
              break;

  case   0x10:                   /* drag buttons - pass them straight on */
  case   0x40:
              cfixfirst=0;
              remzeroevent(CFIXZERO);
              return(1);
              break;

  case  0x100:
  case  0x400:
              cfixsave();
              return(0);
              break;

  case    0x1:                   /* double click */
  case    0x4:
              if(cfixfirst)      /* yes, got a double click in time */
              {
               cfixfirst=0;
               remzeroevent(CFIXZERO);
               return(1);
              }                  /* else it's a double click but timedout */
              else
              {
               return(0);
              }
              break;
 }
 return(0);
}




void decodeclick(void)
{
 buttons=wimpevent.data.but.m.bbits;
 micon=icon=wimpevent.data.but.m.i;
 mhandle=ewindow=wimpevent.data.but.m.w;
 mousex=wimpevent.data.but.m.x;
 mousey=wimpevent.data.but.m.y;

 if(ewindow==-2)                 decodeiconbar();
 else
 if(ewindow==whandle[VTERM])     {if(clickfix()) vtclick();}
 else
 if(ewindow==whandle[VDATA])     {if(clickfix()) vxclick();}
 else
 if(ewindow==whandle[TEK])       tekclick();
 else
 if(ewindow==whandle[STATUS])    statusicon(icon);
 else
 if(ewindow==whandle[REPLAY])    replayclick();
 else
 if(getview(ewindow))            viewicon();
 else
 if(ewindow==whandle[TRANBOX])   tranboxicon();
 else
 if(ewindow==whandle[SAVEFILE0]) saveicon();
 else
 if(getvxbuff(ewindow))          vxbwicon();
 else
 if(getvxtools(ewindow))         vxbtoolsicon();
 else
 if(ewindow==whandle[KEYPAD])    vxkeypadicon();
 else
 if(ewindow==whandle[SENDFRAME]) sendframeicon();
 else
 if(ewindow==whandle[PSTAT])     staticon();
 else
 if(ewindow==whandle[ZOOM])      zoomicon();
 else
 if(ewindow==whandle[MACROS])    macrosicon();
 else
 if(ewindow==whandle[CONF])      conficon();
 else
 if(ewindow==whandle[TDIR])      diricon();
 else
 if(getentry(ewindow))           entryicon();
 else
 if(ewindow==whandle[PASSWORD])  passwordicon();
 else
 if(ewindow==whandle[VXPRINT])   vxprinticon();
 else
 if(ewindow==whandle[TEKPRINT])  tekprinticon();
 else
 if(ewindow==whandle[KERMIT])    kermiticon();
 else
 if(ewindow==whandle[ASCII])     asciiicon();
 else
 if(ewindow==whandle[TXMODEM])   xmodemicon();
 else
 if(ewindow==whandle[TXMODEM1K]) xmodem1kicon();
 else
 if(ewindow==whandle[TYMODEM])   ymodemicon();
 else
 if(ewindow==whandle[TZMODEM])   zmodemicon();
 else
 if(ewindow==whandle[TCET])      ceticon();
 else
 if(ewindow==whandle[VTSET])     vtseticon();
 else
 if(ewindow==whandle[COMMSFN])   commsicon();
 else
 if(ewindow==whandle[TKEYVX])    vxkeyicon();
 else
 if(ewindow==whandle[TKEYVT])    vtkeyicon();
 else
 if(ewindow==whandle[TBATCONFIG]) batconfigicon();
 else
 if(ewindow==whandle[TCHOICES]) choicesicon();
 else
 if(ewindow==whandle[TLINKLEVEL]) linklevelicon();
 else
 if(ewindow==whandle[TDISPLAYVX]) vxdisplayicon();
 else
 if(ewindow==whandle[TDISPLAYVT]) vtdisplayicon();
 else
 if(ewindow==whandle[TDISPLAYTEK]) tekdisplayicon();
 else
 if(ewindow==whandle[TLINEMODE]) linemodeicon();
 else
 if(ewindow==whandle[TMISCVT]) miscvticon();
 else
 if(ewindow==whandle[TMISCVX]) miscvxicon();
 else
 if(ewindow==whandle[TMISCTEK]) misctekicon();
 else
 if(ewindow==whandle[TSETUP]) setupicon();
 else
 if(ewindow==whandle[TDIALOPTIONS]) dialoptionsicon();
}



void redraw(void)
{ 
 ewindow=wimpevent.data.o.w;
                             
 if(ewindow==whandle[VTERM])       redrawvt();
 else
 if(ewindow==whandle[TEK])         tekredraw();
 else
 if(ewindow==whandle[VDATA])       vxredraw();
 else
 if(ewindow==whandle[KEYPAD])      vxkeypadredraw();
 else
 if(getvxbuff(ewindow))            vxbwredraw();
 else
 if(ewindow==whandle[MACROS])      macrosredraw();
 else
 if(ewindow==whandle[TDIR])        dirredraw();
 else
 if(ewindow==whandle[TRANBOX])     tranboxredraw();
 else
 if(ewindow==whandle[TDISPLAYTEK]) tekdisplayred();
 else
 if(getview(ewindow))              viewredraw();
}



void wopen(void)
{
 ewindow=wimpevent.data.o.w;

 if(ewindow==whandle[TEK])    wopentek();
 else
 if(ewindow==whandle[VTERM])  openvt();
 else
 if(ewindow==whandle[VTVERT]) openvtvert();
 else
 if(ewindow==whandle[VDATA])  openvx(&(wimpevent.data.o));
 else
 if(getview(ewindow))         openvwimp();
 else
 if(getvxbuff(ewindow))       vxbwopen();
 else
 wimp_open_wind(&(wimpevent.data.o));
}


void wclose(void)
{
 ewindow=wimpevent.data.o.w;

 if(ewindow==whandle[VTERM])  closeterm();
 else
 if(ewindow==whandle[REPLAY]) closereplay();
 else
 if(ewindow==whandle[TEK])    closeterm();
 else
 if(ewindow==whandle[VDATA])  closeterm();
 else
 if(getview(ewindow))         closevwimp();
 else
 if(getvxbuff(ewindow))       vxbwclose();
 else
 if(ewindow==whandle[KEYPAD]) vxkeypadclosew();
 else
 if(ewindow==whandle[CED])    closeced();
 else
 if(ewindow==whandle[MACROS]) macrosclose();
 else
 if(ewindow==whandle[TDIR])   dirclose();
 else
 if(getentry(ewindow))        entryclose();
 else
 closedown(ewindow);
}




void keypress(void)
{
 int key;
 int pass=1;

 key=wimpevent.data.key.chcode;
 ewindow=wimpevent.data.key.c.w;
 icon=wimpevent.data.key.c.i;

 if(keyexpand(&key,&pass))
 {
 /* dprintf(0,"%x    ",key);  */

  if(ewindow==whandle[SAVEFILE0]) savekey(&key);
  else
  if(ewindow==whandle[VDATA])     keymacro(viewkey,&key);
  else
  if(ewindow==whandle[VTERM])     keymacro(vtkey,&key);
  else
  if(ewindow==whandle[TEK])       keymacro(tekkey,&key);
  else
  if(ewindow==whandle[CED])       cedkey(&key);
  else
  if(ewindow==whandle[TDISPLAYTEK]) tekdisplaykey(&key);
  else
  if(ewindow==whandle[MACROS])    macroskey(&key);
  else
  if(ewindow==whandle[ZOOM])      zoomkey(&key);
  else
  if(getentry(ewindow))           entrykey(&key);
  else
  if(ewindow==whandle[PASSWORD])  passwordkey(&key);
  else
  if(ewindow==whandle[CONF])      confkey(&key);
  else
  if(ewindow==whandle[VXPRINT])   vxprintkey(&key);
  else
  if(ewindow==whandle[TEKPRINT])  tekprintkey(&key);
  else
  if(ewindow==whandle[KERMIT])    kermitkey(&key);
  else
  if(ewindow==whandle[ASCII])     asciikey(&key);
  else
  if(ewindow==whandle[TCET])      cetkey(&key);
  else
  if(ewindow==whandle[TBATCONFIG]) batconfigkey(&key);
  else
  if(ewindow==whandle[TMISCVX])    vxmisckey(&key);
  else
  if(ewindow==whandle[TMISCVT])    vtmisckey(&key);
  else
  if(ewindow==whandle[TDIALOPTIONS]) dialoptionskey(&key);
 }

#ifdef VICK
 key=-1;
#endif


 if(key!=-1 && pass)
 {
  if(key==0x1CC) 
  {
   keyboard_off();
   addzeroevent(FKEYFIX);
  }
  wimp_processkey(key);
 }
}


void fkeyfixzero(void)
{
 keyboardoncaret(1);
 remzeroevent(FKEYFIX);
}



/*****************************************************************************/


void startdrag(int type,int handle)
{
 draghandle=handle;
 dragtype=type;

 addzeroevent(DRAGZERO);
}



void zerodrag(void)
{
 if(dragtype==VTDRAG)   vtdragzero();
 else
 if(dragtype==VXDRAG)   vxdragzero();
 else
 if(dragtype==TEKPDRAG) tekselcoldragzero();
}



void decodedrag(void)
{
 if(getview(draghandle))            extractdragend();  
 else
 if(draghandle==whandle[SAVEFILE0]) savedragend();
 else
 if(draghandle==whandle[TBATCONFIG]) batconfigdragend();
 else
 if(dragtype==VXDRAG)               vxdragend();
 else
 if(dragtype==TEKPDRAG)             tekselcoldragend();

 remzeroevent(DRAGZERO);
}




/*****************************************************************************/

int dopollidle=0;
int zerotime;

void addzeroevent(int type)
{
 dopollidle|=type;
}


void remzeroevent(int type)
{
 dopollidle|=type;
 dopollidle^=type;
}


void zero(int zmask)
{
 int dopoll;
 zerotime=clock();

 dopoll=(dopollidle & (~zmask));

 if(dopoll & REPLAYZERO)  replayzero();
 if(dopoll & TERMZERO)    termzero();
 if(dopoll & VTZERO)      vtzero();
 if(dopoll & VXZERO)      vxzero();
 if(dopoll & TEKZERO)     tekzero();
 if(dopoll & VXEZERO)     vxeditzero();
 if(dopoll & DRAGZERO)    zerodrag();
 if(dopoll & VAXZERO)     vaxzero();
 if(dopoll & CFIXZERO)    cfixzero();
 if(dopoll & VTGAINC)     gaincsz();
 if(dopoll & FTPASEND)    ftpdoautosend();
 if(dopoll & ONZERO)      onlinezero();
 if(dopoll & FKEYFIX)     fkeyfixzero();
 if(dopoll & NDATAZERO)   newdatazero();
 if(dopoll & CALLZERO)    callzero();
 if(dopoll & PRINTERZERO) printerdemon();
 if(dopoll & ZMZERO)      zmzero();
 if(dopoll & ASCIIZERO)   asciizero();
 if(dopoll & MNPZERO)     mnpzero();
 if(dopoll & RECORDZERO)  recordzero();
 if(dopoll & VXKEYZERO)   vxkeypadzero();
 if(dopoll & SDEVZERO)    sdevzero();
 if(dopoll & BLOCKZERO)   blockzero();
}


/*****************************************************************************/



void pointerenters(void)
{
 ewindow=wimpevent.data.o.w;




}


void pointerleaves(void)
{
 ewindow=wimpevent.data.o.w;




}



void losecaret(void)
{
 ewindow=wimpevent.data.c.w;
 icon=wimpevent.data.c.i;

 if(ewindow==whandle[VTERM]) gaincs(0);

 if(ewindow==whandle[VTERM] || ewindow==whandle[VDATA] || 
    ewindow==whandle[TEK]) keyboard_off();

 else
 if(ewindow==whandle[MACROS]) macrosc(0);
}


void gaincaret(void)
{
 ewindow=wimpevent.data.c.w;
 icon=wimpevent.data.c.i;

 if(ewindow==whandle[VTERM]) gaincs(1);

 if(ewindow==whandle[VTERM] || ewindow==whandle[TEK]) keyboard_on(automode);
 else
 if(ewindow==whandle[VDATA])  keyboard_on(vxauto); 
 else
 if(ewindow==whandle[MACROS]) macrosc(1);
}


void writebootfile(void)
{
 char string[256];
 int  handle;

 handle=wimpevent.data.msg.data.words[0];
 sprintf(string,"Run %s\n",path(HSYP));
 fs_write(handle,string,strlen(string));
}


/*****************************************************************************/

/* deals with *Hearsay filename case */

int loadanyfile(char * name)
{
 fstat f;
 int code;

 stat(name,&f);

 switch(f.type)
 {
  case FRAME:
  case CEPT3:
  case CEPT2:
             code=vxbloadfile(name,f.type);
             return(code);
             break;

 case SCRIPT:
             return(runscript(name,1));
             break;

 }

 return(0);
}





int loadfile(int type,char * name,int xvolatile)
{

 if(getview(mhandle))
 {
  return(batchload(type,name,xvolatile));
 }
 else
 if(getvxbuff(mhandle) && (type==FRAME || type==CEPT2 || type==CEPT3))
 {
  return(vxbinsertfile(name,type));
 }
 else
 if(mhandle==whandle[VTERM] || mhandle==whandle[TEK] ||mhandle==whandle[VDATA])
 {
  return(termloadfile(type,name,xvolatile));
 }
 else
 if(mhandle==-2)
 {
  if(type==FRAME || type==CEPT2 || type==CEPT3)
  {
   return(vxbloadfile(name,type));
  }
  else
  {
   if(type==SCRIPT) return(runscript(name,0));
  }
 }
 else
 {
  if(getentry(mhandle)) return(entryload(name));
 }

 return(0);  /* could not load it */
}



void loadfilepost(int type)
{
 if(mhandle==-2 && type==SCRIPT) runscriptpost();
}




/* return 1 if can load by ram transfer   */
/* return 2 if can load by scrap transfer */
/* return 3 if has to be real file        */

int goodloadtype(int type)
{

 if(getview(mhandle))
 {
  return(2);
 }
 else
 if(getvxbuff(mhandle) && (type==FRAME || type==CEPT2 || type==CEPT3))
 {
  return(1);
 }
 else
 if(mhandle==whandle[VTERM] || mhandle==whandle[TEK]||mhandle==whandle[VDATA])
 {
  return(2);
 }
 else
 if(mhandle==-2 && (type==FRAME || type==CEPT2 || type==CEPT3 || type==SCRIPT))
 {
  return(1);
 }
 else
 if(getentry(mhandle))
 {
  return(3);
 }

 return(0);
}



int goodruntype(int type)
{
 if(type==FRAME || type==CEPT2 || type==CEPT3 || type==SCRIPT) return(1);
 return(0);
}



int goodprinttype(int type)
{
 type=0;
 return(0);
}


/***************************************************************************/
                          /* Message Handling */

int         scrapref=-1;
int         sscrapref=-1;
char        scrapname[32];
wimp_msgstr scmsg;

void scrapfile(void)
{
 if(!getenv("Wimp$Scrap"))
 {
  errorbox("{WIMP00}");
  return;
 }

 wimpevent.data.msg=scmsg;

 strcpy(scrapname,wimpevent.data.msg.data.datasave.leaf);

 wimpevent.data.msg.data.datasaveok.estsize=-1;
 strcpy(wimpevent.data.msg.data.datasaveok.name,"<Wimp$Scrap>");
 wimpevent.data.msg.hdr.size=((48+12) & 0xFFFFFFFC);
 wimpevent.data.msg.hdr.your_ref=wimpevent.data.msg.hdr.my_ref;
 wimpevent.data.msg.hdr.action=2;
 wimp_sendmessage(17,&wimpevent.data.msg,wimpevent.data.msg.hdr.task);
 scrapref=wimpevent.data.msg.hdr.my_ref;
}



void sparkscrapfile(void)
{
 char tempname[256];

 if(strlen(path(TXBP))==0) return;

 makefilename(wimpevent.data.msg.data.datasave.leaf,tempname,path(TXBP),0);

 wimpevent.data.msg.data.datasaveok.estsize=-1;
 strcpy(wimpevent.data.msg.data.datasaveok.name,tempname);
 wimpevent.data.msg.hdr.size=((48+(strlen(tempname)+3)) & 0xFFFFFFFC);
 wimpevent.data.msg.hdr.your_ref=wimpevent.data.msg.hdr.my_ref;
 wimpevent.data.msg.hdr.action=2;
 wimp_sendmessage(17,&wimpevent.data.msg,wimpevent.data.msg.hdr.task);
 sscrapref=wimpevent.data.msg.hdr.my_ref;
}






void dataloadack(void)
{


}



/* something expects us to save data to it */

void savedata(void)
{
 int    saverefx;

 saverefx=wimpevent.data.msg.hdr.your_ref;
 if(saverefx!=saveref)
 {
  errorbox("{UXDS}");
  return;
 }

 if(saveref==viewsaveref) viewsave();
 else
 {
  savefile(wimpevent.data.msg.data.datasaveok.name);
  wimpfirst.data.msg.hdr.your_ref=wimpfirst.data.msg.hdr.my_ref;
  wimpfirst.data.msg.hdr.action=3;
  wimp_sendmessage(17,&wimpfirst.data.msg,wimpfirst.data.msg.hdr.task);
 }
}



void loaddata(void)
{
 int    type=wimpevent.data.msg.data.dataload.type;
 char * name=wimpevent.data.msg.data.dataload.name;
 int    xvolatile;
 int    code;

 mousex=wimpevent.data.msg.data.dataload.x;
 mousey=wimpevent.data.msg.data.dataload.y;
 micon=wimpevent.data.msg.data.dataload.i;
 mhandle=wimpevent.data.msg.data.dataload.w;

 xvolatile=((wimpfirst.data.msg.hdr.your_ref==scrapref) ||
              (wimpfirst.data.msg.hdr.your_ref==sscrapref)); 


 code=loadfile(type,name,xvolatile);

 /* saying ok, we loaded it ok */

 if(wimpfirst.data.msg.hdr.your_ref==scrapref)
 {
  oscli("delete <Wimp$Scrap>");
  scrapref=-1;
 }
 else
 if(wimpfirst.data.msg.hdr.your_ref==sscrapref && code==NOLOAD)
 {
  remove(name);
  sscrapref=-1;
 }

 if(code!=NOLOAD)
 {
  wimpfirst.data.msg.hdr.your_ref=wimpfirst.data.msg.hdr.my_ref;
  wimpfirst.data.msg.hdr.action=4;
  wimp_sendmessage(17,&wimpfirst.data.msg,wimpfirst.data.msg.hdr.task);
  loadfilepost(type);
 }

}




void opendata(void)
{
 int code=0;
 int type=wimpevent.data.msg.data.dataopen.type;

 if(goodruntype(type))
 {
  /* one of ours so load it */
  /*  double click on file  */

  switch(type)
  {
   case FRAME:
   case CEPT3:
   case CEPT2:
              if(vxbloadfile(wimpevent.data.msg.data.dataload.name,
                             wimpevent.data.msg.data.dataopen.type)==NOLOAD)
                                                                        return;
              break;

  case SCRIPT:             /* absorb these, or else it runs another Hearsay */
              code=runscript(wimpevent.data.msg.data.dataload.name,0);
              break;
  }

  /* saying ok, we loaded it ok */

  wimpfirst.data.msg.hdr.your_ref=wimpfirst.data.msg.hdr.my_ref;
  wimpfirst.data.msg.hdr.action=4;
  wimp_sendmessage(17,&wimpfirst.data.msg,wimpfirst.data.msg.hdr.task);

  if(code && type==SCRIPT) runscriptpost();
 }
}




void ramfetch(void)
{
 int saverefx;

 /* this is the first we know about it if something */
 /* else is trying to load a file                   */
 /* next comes a datasaveack -> scrap file          */

 /* means destination wants stuff saving to RAM */

 saverefx=wimpevent.data.msg.hdr.your_ref;
 if(saverefx!=saveref)
 {
  errorbox("{UXRM}");
  return;
 }
 if(saveref!=viewsaveref)  /* no ram tran on viewers */
 {
  ramnextwritefile();
  savefile(NULL); 
  ramoff();
 }
}







/* a drag from the filer, has ended on a printer driver          */
/* up to us to load and print the file if we can and then say so */

void printfileodd(void)
{
 int type=wimpevent.data.msg.data.print.type;
 char * name=wimpevent.data.msg.data.print.name;

 if(goodprinttype(type))
 {
  wimpfirst.data.msg.hdr.your_ref=wimpfirst.data.msg.hdr.my_ref;
  wimpfirst.data.msg.hdr.action=0x80146;
  wimp_sendmessage(17,&wimpfirst.data.msg,wimpfirst.data.msg.hdr.task);
  /* printdoc(name); */  name=NULL;
 }
}


/****************************************************************************/

int active;

int activate(void)
{
 int code; 
 static int norecurse;

 code=0;

 if(!norecurse)
 {
  norecurse=1;

  if((code=activatedriver())==0) /* sets active to 1 */
  {
   sethearsayicon(0);
  }

  norecurse=0;
 }

 return(code);
} 


void deactivate(void)
{
 static int norecurse;

 if(!norecurse)
 {
  norecurse=1;

  deactivatedriver();
  setnewdata(0);
  sethearsayicon(2);
  active=0;

  norecurse=0;
 }
}



void toggleactive(void)
{
 if(!active)
 {
  if(activate()==1) errorbox("{MODEM}");
 }
 else
 if(!online && !ftpactive) deactivate();
}



void setstate(int fp)
{
 if(stack[fp]) activate();
 else          deactivate();
}


/**************************************************************************/

static int devicemajor;
static int deviceminor;
static int deviceref;
static int devicedone;

/* we have received a message trying to claim a device */

void deviceclaim(void)
{
 int major;
 int minor;

 major=wimpevent.data.msg.data.device.major;
 minor=wimpevent.data.msg.data.device.minor;

 if(wimpevent.data.msg.hdr.task!=taskhandle)
 {
  if(active && major==devicemajor && minor==deviceminor)
  {
   if(online || ftpactive)
   {
    wimpfirst.data.msg.hdr.your_ref=wimpfirst.data.msg.hdr.my_ref;
    wimpfirst.data.msg.hdr.action=12;
    strcpy(wimpfirst.data.msg.data.device.information,transtoken("DEV0"));
    wimp_sendmessage(17,&wimpfirst.data.msg,wimpfirst.data.msg.hdr.task);
   }
   else
   {
    deactivate();
   }
  }
 }
}


void deviceack(void)
{
 devicedone=1;
}


void devicebusy(void)
{
 if(wimpevent.data.msg.hdr.your_ref==deviceref)
 {
  werr(0,"{ACTIVE}%s",wimpevent.data.msg.data.device.information);
  devicedone=-1;
 }
}


void trytoclaimdevice(int major,int minor)
{
 wimp_msgstr msg;

 /* assumes mhandle etc. are valid here */

 msg.hdr.size=((48+12) & 0xFFFFFFFC);
 msg.hdr.task=taskhandle;
 msg.hdr.your_ref=0;
 msg.hdr.action=11;

 msg.data.device.major=major;
 msg.data.device.minor=minor;
 strcpy(msg.data.device.information,"Hearsay");

 wimp_sendmessage(18,&msg,0);

 deviceref=msg.hdr.my_ref;
}


int getdevice(int fp)
{
 int major;
 int minor;

 major=stack[fp];
 minor=stack[fp+1];

 trytoclaimdevice(major,minor);
 devicedone=0;
 while(!devicedone) poll(0);

 if(devicedone>=0)
 {
  devicemajor=major;
  deviceminor=minor;
 }

 return(devicedone>=0);
}


/*****************************************************************************/



static int  datasaveref;

void ramtransmit(void)
{
 int    type;
 char * name;

 type=scmsg.data.datasave.type;
 name=wimpevent.data.msg.data.datasave.leaf;

 ramloadbuffer();
 armfetch(&wimpevent.data.msg);

 /* means destination wants us to load stuff from RAM */

 loadfile(type,name,0);
 loadfilepost(type);
}



/* something is trying to send us a file */

void datasave(void)
{
 int type;
 int code;

 mousex=wimpevent.data.msg.data.datasave.x;
 mousey=wimpevent.data.msg.data.datasave.y;
 micon=wimpevent.data.msg.data.datasave.i;
 mhandle=wimpevent.data.msg.data.datasave.w;

 scmsg=wimpevent.data.msg;
 type=scmsg.data.datasave.type;

 code=goodloadtype(type);

 if(code==1)
 {
  /* OK, we can load this filetype this way */
  /* send a ram fetch message               */
  ramnextreadfile();
  datasaveref=readmyref; /* so ack goes through routine above */
  readmyref=-1;
 }
 else
 if(code==2)
 {
  sparkscrapfile();
 }
}



void prequit(void)
{
 int origtask;
 int cblock[7];
 int norestart;

#ifndef VICK

 if(!vxbunsaved() && (!active || (!online && !ftpactive))) return;

 origtask=wimpfirst.data.msg.hdr.task;
 wimp_get_caret_pos((wimp_caretstr *)cblock);
#endif

 if(wimpfirst.data.msg.hdr.size>=24) 
                       norestart=wimpfirst.data.msg.data.words[0] & 0x1;
 else                  norestart=0;



 wimpfirst.data.msg.hdr.your_ref=wimpfirst.data.msg.hdr.my_ref;
 wimp_sendmessage(19,&wimpfirst.data.msg,wimpfirst.data.msg.hdr.task);


#ifndef VICK
 if(!termnok())
 {
  vxbclearunsaved();
  if(!norestart)
  {
   cblock[6]=0x1FC;
   wimp_sendmessage(8,(wimp_msgstr *)cblock,origtask);
  }
  else
  {
   terminate();
  }
 }
#endif
}



void menumessage(void)
{
 int m1,m2,m3,m4;
 int x,y;
 int submenu;

 submenu=wimpevent.data.msg.data.words[0];
       x=wimpevent.data.msg.data.words[1];
       y=wimpevent.data.msg.data.words[2];
      m1=wimpevent.data.msg.data.words[3];
      m2=wimpevent.data.msg.data.words[4];
      m3=wimpevent.data.msg.data.words[5];
      m4=wimpevent.data.msg.data.words[6];

 dynamicmenu(submenu,x,y,m1,m2,m3,m4);
}



void setslotsize(void)
{
 int size;

 size=wimpevent.data.msg.data.words[0];
/* if(size>=0) setmem(size); */

 if(wimpevent.e==18) 
   {
    wimpfirst.data.msg.hdr.your_ref=wimpfirst.data.msg.hdr.my_ref;
    wimp_sendmessage(19,&wimpfirst.data.msg,wimpfirst.data.msg.hdr.task);
   }
}


/* type 19 messages */

void acknowledged(void)
{
 /* note references work the other way around here */

 if(wimpevent.data.msg.hdr.my_ref==datasaveref)
 {
  ramoff();
  scrapfile();
 }
 else
 if(wimpevent.data.msg.hdr.my_ref==readmyref)   readack();
 else
 if(wimpevent.data.msg.hdr.my_ref==writemyref)  writeack();
 else
 if(wimpevent.data.msg.hdr.my_ref==viewopenref) viewack();
 else
 if(wimpevent.data.msg.hdr.my_ref==deviceref)   deviceack();
}




/* type 17 & 18 messages */

void message(void)
{
  wimpfirst=wimpevent;

/* dprintf(0,"mess=%x",wimpevent.data.msg.hdr.action);  */

  if(wimpevent.data.msg.hdr.your_ref==writemyref) writemess();
  else
  if(wimpevent.data.msg.hdr.your_ref==readmyref)  readmess();
  else
  switch(wimpevent.data.msg.hdr.action)
  {
   case         0: terminate();
                   break;
   case         1: datasave();    /* data save */
                   break;
   case         2: savedata();    /* data save ack */
                   break;
   case         3: loaddata();    /* data load */
                   break;
   case         4: dataloadack(); /* data load ack */
                   break;
   case         5: opendata();    /* data open */
                   break;
   case         6: ramfetch();    /* ram fetch */
                   break;
   case         7: ramtransmit(); /* ram transmit */
                   break;
   case         8: prequit();
                   break;
   case         9: palchange();
                   break;
   case        10: writebootfile();
                   break;

   case        11:
                   deviceclaim();
                   break;
   case        12:
                   devicebusy();
                   break;


   case   0x400C0: /* dynamic menus */
                   menumessage();
                   break;
   case   0x400C1: setmodevars();
                   break;
   case   0x400C5: setslotsize();
                   break;

   case   0x80147: setprinterdriver();
                   break;
   case   0x80143: printinitdriver();
                   break;

   case   0x80140: printfilepd();
                   break;

   case   0x80145: printfileodd();
                   break;

   case   0x80144:
                   break;

   case SPARKMESS:
                   filelinkin();
                   break;


  default        :
                   break;

  }
}





void pollexit(void)
{
#ifdef XDBUG
 fx(229,1,0);
 fx(224,0,0);
#endif

 if(vtopen && (vtpendredraw || vtpendscrolly || vtpendshift || vtpendsubs))
                                                                     vtzero();
}



void pollenter(void)
{
#ifdef XDBUG
 fx(229,0,0);
#endif
}



/***************************************************************************/

int poll(int zflags)
{
 int    code;
 static int zmask;
 int    oldzmask;

 /* leaves here */

 pollexit();

 if(dopollidle || zflags) wimp_poll(wimp_ENULL,&wimpevent);
 else
 {
  timeout=monotonic()+6000;
  wimp_pollidle(wimp_ENULL,&wimpevent,timeout);
 }

 pollenter();

 /* returns here */

 code=wimpevent.e;

 oldzmask=zmask;
 zmask|=zflags;

 switch(code)
 {
       case  0: zero(zmask); 
                break; 

       case  1: redraw(); 
                break;            /* redraw window request */

       case  2: wopen(); 
                break;            /* open window request  */

       case  3: wclose(); 
                break;            /* close window request */

       case  4: pointerleaves();
                break;            /* poi. leaving window  */

       case  5: pointerenters();
                break;            /* poi. entering window */

       case  6: decodeclick();
                break;            /* mouse click          */

       case  7: decodedrag();
                break;            /* user drag box        */

       case  8: keypress();
                break;            /* key press            */

       case  9: decodemen();
                break;            /* menu select          */

       case 10: 
                break;            /* scroll request       */

       case 11: losecaret();
                break;

       case 12: gaincaret();
                break;

       case 17:
       case 18:
                message();
                break;

       case 19: 
                acknowledged();
                break;
 }

 zmask=oldzmask;

 return(code);
}



/* a version for when you only want returns on zero polls */
/* and you don't want any terminal reading                */

void pollzt(void)
{
 while(poll(TERMZERO)!=0);
}

void pollt(void)
{
 poll(TERMZERO);
}


void pollz(void)
{
 while(poll(0)!=0);
}




#ifdef NEVER

#include "h.bf"

static void dotest(void)
{
 buffer bf;
 int    ex;
 int    write;
 char * string="Hello World";

 bf_open("xx",'u',0x1000,&bf);

 bf_seek(&bf,0,SEEK_END);

 bf_writen(&bf,string,strlen(string),&write);

 bf_close(&bf,NULL);
}

#endif



int main(int argc,char * argv[])
{ 
 setlocale(LC_ALL,"ISO8859-1");

 cachepaths();

 wimp_version=wimpt_init("Hearsay");   /* boots task */

 starttask();             /* does checks and retrieves task handle */

 flex_init();

 setosversions();
 loadsprites();
 vdumodevars();             
 vdupalvars();
 loadtemps();             /* do this after load sprites */


 inittrans();
 bootkermit();            /* this is first flex_alloc               */
 bootfile();              /* would like this to be first flex alloc */
 bootbatch();             /* must be after bootfile                 */

 seticonbar();
 setupmenus();

 vtinit();
 vxinit();
 vxbuffboot();
 tekinit();
 bootxlat();

 serialset();

 rosprintinit();
 printboot();

 macrosboot();
 dirboot();

 onlinestart();

 scriptstart();        /* better be last so that you don't */
                       /* init something not set up        */

 timeout=monotonic()+6000;

 if(argc==3)              /* check that called with '-Print' */
 {
/*  printdoc(argv[2]);  */
 }
 else
 if(argc==2)
 {
  loadanyfile(argv[1]);
 }

 while(1) poll(0);

 return(0);
}
