
*** Modified files in JOE when it aborted on Sun Oct 16 12:58:33 2005
*** JOE was aborted by signal 15

*** File '(Unnamed)'
spkoff_
spkscr
spkscrrom
romln

*** File 'sbl.c'
/*
 *  suse-blinux - Braille-display support for linux
 *  Author: Marco Skambraks <marco@suse.de>
 *  SuSE GmbH Nuernberg
 *
 *
 * suse-blinux based on brltty
 * special thanks to the Brltty-Team
 * Nicolas Pitre <nico@cam.org>
 * Stphane Doyon <s.doyon@videotron.ca>
 * Nikhil Nair <nn201@cus.cam.ac.uk>
 *
 * This is free software, placed under the terms of the
 * GNU General Public License, as published by the Free Software
 * Foundation.  Please see the file COPYING for details.
*/

#define BRLTTY_C 1
#define FIFO_IN "/var/run/sbl.fifo.in"
#define FIFO_OUT "/var/run/sbl.fifo.out"

#define BRLNAME sblconf.brlname
#define BRLPORT sblconf.brlport
#define SPKNAME sblconf.spkname
#define SPKPORT sblconf.spkport
#define DEBUG sblconf.debug
#define SLEEP sblconf.sleep
#define KEYDELAY sblconf.keydelay
#define REPEATDELAY sblconf.repeatdelay
#define PROFILE1 sblconf.profile1
#define PROFILE2 sblconf.profile2
#define PROFILE3 sblconf.profile3
#define PROFILE4 sblconf.profile4
#define PROGPATH sblconf.progpath
#define BRLTBL sblconf.brltbl
#define PROFDELAY sblconf.profdelay

#define ROWS scr.rows
#define COLS scr.cols
#define COLS2 100
#include <errno.h>
#include <dirent.h>
#include <utmp.h>
/* #include "my.h"  */
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <wait.h>
#include <sys/stat.h>
#include <errno.h>
#include <linux/vt.h>
#include <sys/ioctl.h>

#include "sbllog.h"
#include "gethome.h"
#include "functions.h"
#include "proc.h"
#include "ldconf.h"
#include "config.h"
#include "selkey.h"
#include "../header/def.h"
#include "brl.h"
#include "scr.h"
#include "inskey.h"
#include "spk.h"
#include "beeps.h"
#include "cut-n-paste.h"
#include "misc.h"
/* #include "my.h" */
#include "kbd.h"

param_file env;
extern keymap_file keymap;
sbl_config sblconf;

/* defined libs */
#define USAGE
#define USAGE1 ""
#define ENV_MAGICNUM 0x4004

/*
 * Some useful macros: 
 */
#define POSX env.csrmode?attrpos.x+1:scr.posx+1
#define POSY env.csrmode?attrpos.y+1:scr.posy+1
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define BRL_ISUPPER(c) (isupper (c) || (c) == '@' || (c) == '[' || (c) == '^' \
			|| (c) == ']' || (c) == '\\')
#define TOGGLEPLAY(var) play ((var) ? snd_toggleon : snd_toggleoff)
#define TOGGLE(var) \
  (var = (keypress & VAL_SWITCHON) ? 1 \
   : (keypress & VAL_SWITCHOFF) ? 0 \
   : var ^ 1)

/*
 * Argument for usetable() 
 */
#define TBL_TEXT 0		/* use text translation table */
#define TBL_ATTRIB 1		/* use attribute translation table */

/*
 * Global variables 
 */

int sblpaus = 0, kbd_sniff_on;
int press = 0, confd, kbdfd;
int connr = 1, vtxrouting = 0;
struct vt_stat vterm;
unsigned char attrbuf[1024];
unsigned char **oldscr;
int scrx, scry;			/* current screen-size */
int upd_st_cells = 1;
int fcells = -1;		/* offset for screenfull() */
int vertdisp = 0;		/* only for fhp */

/* struct definition of settings that are saveable */
short showprof;
mask showattr;
char profile[80] = "";

struct csrxy
{
  short x, y;
}
hardcsr, attrpos;

/* struct definition for volatile parameters */
brltty_param initparam = {
  INIT_CSRTRK, TBL_TEXT, 0, 0, 0, 0
};

/* Array definition containing pointers to brltty_param structures for 
 * each screen.  Those structures are dynamically allocated when a 
 * specific screen is used for the first time.
 * Screen 0 is reserved for help screen.
 */
brltty_param *scrparam[NBR_SCR + 1];
int spk = 0, spkupdate = 0, spkmode = 0;

char spkstr[MAXSPKSTR] = "";
int fifo_ok = 1;
int jmpmark = 0;
brltty_param *p;		/* pointer to current param structure */
int curscr = 0;			/* current screen number */

/* Misc param variables */
short dispmd = LIVE_SCRN;	/* freeze screen on/off */
short infmode = 0;		/* display screen image or info */
short csr_offright;		/* used for sliding window */
short hwinshift;		/* Half window horizontal distance */
short fwinshift;		/* Full window horizontal distance */
short vwinshift;		/* Window vertical distance */
brldim brl;			/* For the Braille routines */
scrstat scr;			/* For screen statistics */

/*
 * Output translation tables - the files *.auto.h are generated at *
 * compile-time: 
 */
unsigned char texttrans[256] = {
#include "text.def"
};
unsigned char attribtrans[256] = {
#include "attrib.def"
};
unsigned char *curtbl = NULL;	/* currently active translation table */

volatile sig_atomic_t keep_going = 1;	/*

					 * controls program termination 
					 */
int tbl_fd;			/* Translation table filedescriptor */

/* -h, -l, -q and -v options */
short opt_h = 0, opt_q = 0, opt_v = 0, opt_l = 4;
char *opt_c = NULL, *opt_d = NULL, *opt_t = NULL;	/* filename options */
char home[100];
short homedir_found = 0;	/* CWD status */

unsigned int TickCount = 0;	/* incremented each cycle */

/*
 * Status cells support 
 * remark: the Papenmeier has a column with 22 cells, 
 * all other terminals use up to 5 bytes
 */
unsigned char statcells[22];	/* status cell buffer */

/* 
 * Number dot translation for status cells 
 */
const unsigned char num[10] = { 14, 1, 5, 3, 11, 9, 7, 15, 13, 6 };

/*
 * for csrjmp subprocess 
 */
volatile int csr_active = 0;
pid_t script_pid, csr_pid, spk_pid = 0;

/*
 * Function prototypes: 
 */

void getdriver ();
void chkscrsize ();
void allocoldscr ();
void cleanoldscr ();
void cpytooldscr (unsigned char *src);
void ggetproc (void);
void gtest (int *c);
int getsoftcsr (mask softcsr, range limit);
void screenfull ();
void initattr ();
void startbrl ();
void switchto (unsigned int scrno);	/* activate params for specified screen */
void csrjmp (int x, int y);	/* move cursor to (x,y) */
void csrjmp_sub (int x, int y);	/* cursor routing subprocess */
void setwinxy (int x, int y);	/* move window to include (x,y) */
void message (char *s, short silent);	/* write literal message on

					 * Braille display 
					 */
void clrbrlstat (void);
void termination_handler (int signum);	/* clean up before termination */
void stop_child (int signum);	/* called at end of cursor routing */
void usetable (int tbl);	/* set character translation table */
void configmenu (void);		/* configuration menu */
void loadconfig (void);
void saveconfig (void);
int nice (int);			/* should really be in a header file ... */

int brlcode = -1, autoprof = 1;

/* variables for fifo check */
fd_set w_fds;
int read_fd, write_fd;

int main (int argc, char *argv[])
{
  short lastkey = EOF, sel = 1;
  int ende = 0, repeat = 0;
  int keypress;			/* character received from braille display */
  int i;			/* loop counter */
  short csron = 1;		/* display cursor on (toggled during blink) */
  short csrcntr = 1;
  short oldwinx, oldwiny;

  if (argc > 2 && !strcmp (argv[1], "-f"))
    getldconf (&sblconf, argv[2]);
  else
    getldconf (&sblconf, NULL);

  sbl_open_log (DEBUG);
  getprofile (&env, PROGPATH, home, PROFILE1);
  initattr ();
  getkeymap (sblconf, env.profname, home);
  if (strncmp (SPKNAME, "none", 4))
   {
     getspkctrl (PROGPATH, SPKNAME);
/*     setspk(); */
     getspkfilter (PROGPATH, env.profname, home, env.spklang);
   }

  soundstat (env.sound);

  hardcsr.x = -1;
  hardcsr.y = -1;
  /* Open syslog */
  LogOpen (opt_l);

  /*
   * Print version and copyright information: 
   */
  puts (VERSION);
  sbl_log ("%s\n", VERSION);
  puts (COPYRIGHT);

  /*
   * Give the Braille library a chance to print start-up messages. * 
   * Pass the -d argument if present to override the default serial
   * device. 
   */

/* load lib */

  getdriver ();

  sbl_log ("sniffercmd: on1=%d on2=%d off=%d\n", keymap.kbdsniffon1.kbd,
	   keymap.kbdsniffon2.kbd, keymap.kbdsniffoff.kbd);
  kbd_sniff_on =
    open_kbd_sniff (keymap.kbdsniffon1.kbd, keymap.kbdsniffon2.kbd,
		    keymap.kbdsniffoff.kbd);
/* external speechoutput must be initialized before we fork */
if(strcmp(SPKNAME,"ttsynth"))
{
  spkinit (SPKPORT);
  lang (env.spklang);
  setspk ();
}


  {
    char tblpath[200];

    sprintf (tblpath, "%s/brltbl/%s", PROGPATH, BRLTBL);
    if ((tbl_fd = open (tblpath, O_RDONLY)) >= 0 &&
	(curtbl = (unsigned char *) malloc (256))
	&& read (tbl_fd, curtbl, 256) == 256)
      memcpy (texttrans, curtbl, 256);
    if (curtbl)
     {
       free (curtbl);
       curtbl = 0;
     }
    if (tbl_fd >= 0)
      close (tbl_fd);
  }

  /*
   * Initialize screen library 
   */
  if (initscr ())
   {
     /* initialise screen reading */
   }

  /* allocate the first screen information structures */
  p = (brltty_param *) malloc (sizeof (*p));
  if (!p)
   {
     sbl_log ("error: cannot allocate memory for screen\n");
     closescr ();
     sbl_close_log ();
     exit (-1);
   }
  *p = initparam;
  scrparam[0] = p;
  for (i = 1; i <= NBR_SCR; i++)
    scrparam[i] = 0;
  curscr = 0;

  /*
   * Become a daemon: 
   */
  switch (fork ())
   {
   case -1:			/* can't fork */
     if (!opt_q)
       perror ("fork()");
     closescr ();
     LogClose ();
     exit (3);
   case 0:			/* child, process becomes a daemon: */
     close (STDIN_FILENO);
     close (STDOUT_FILENO);
     close (STDERR_FILENO);
     sbl_log ("become a daemon\n");
     if (setsid () == -1)
      {
	/* request a new session (job control) */
	closescr ();
	sbl_log ("setsid: %s", strerror (errno));
	sbl_close_log ();
	exit (4);
      }
     break;
   default:			/* parent returns to calling process: */
     return 0;
   }

  /* Load configuration file */
  /* Initialise Braille and set text display: */
  startbrl ();


/* we have to load the ttsynth lib after fork */
if(!strcmp(SPKNAME,"ttsynth"))
{
  spkinit (SPKPORT);
  lang (env.spklang);
  setspk ();
}


  sbl_log ("braille display started\n");

  /*
   * Establish signal handler to clean up before termination: 
   */
  if (signal (SIGTERM, termination_handler) == SIG_IGN)
    signal (SIGTERM, SIG_IGN);
  signal (SIGINT, SIG_IGN);
  signal (SIGHUP, SIG_IGN);
  signal (SIGCHLD, stop_child);

  usetable (TBL_TEXT);
  sbl_log ("signals set - brltbl loaded\n");
  if (!opt_q)
   {
     message (VERSION, 0);	/* display initialisation message */
     sbl_log ("wrote version to braille\n");
     delay (DISPDEL);		/* sleep for a while */
   }

  sbl_log ("get screensatus and size\n");
  getstat (&scr);
  chkscrsize ();
  switchto (scr.no);		/* allocate current screen params */
  sbl_log ("finished - and current screen allocated\n");
  sbl_log ("set braille to xy\n");
  setwinxy (scr.posx, scr.posy);	/* set initial window position */
  oldwinx = p->winx;
  oldwiny = p->winy;
  p->cox = scr.posx;
  p->coy = scr.posy;
  sbl_log ("finished\n");
  allocoldscr ();
  sbl_log ("oldscreen allocated\n");
  /*
   * Main program loop 
   */

  confd = open ("/dev/tty0", O_RDONLY);

  openfifo ();
  sbl_log ("go into mainloop\n");
  while (keep_going)
   {
     if (lastkey == EOF)
       usleep (SLEEP);
     ioctl (confd, VT_GETSTATE, &vterm);
     if (connr != vterm.v_active)
      {

	connr = vterm.v_active;
      }
     if (autoprof)
       ggetproc ();

     soundstat (env.sound);

     TickCount++;
     /*
      * Process any Braille input  */
     env.csrvis = 1;
     if (ende > 500000)
       ende = 0;
     ende++;
     sel = 1;
     if (kbd_sniff_on)
      {
	int key = 0;

	key = get_input_event ();
	selkey (10000, key);
	key = 0;
      }
     keypress = EOF;
     keypress = braille->read (&press);
     if (keypress != EOF)
      {

      }
     if (keypress != EOF && !press)
      {
	if (brlcode == -1)
	 {
	   brlcode = -2;
	   keypress = EOF;
	 }
	else
	 {
	   lastkey = lastkey * 1000 + keypress;
	   keypress = EOF;
	 }
      }

     if (lastkey == EOF)
       lastkey = keypress;
     else if (keypress != EOF)
      {
	lastkey = lastkey * 1000 + keypress;
      }

     {
       switch (brlcode)
	{
	case 0:
	  repeat = 0;
	  if (lastkey >= 1000)
	    brlcode = -1;
	  else
	    brlcode = -2;
	  lastkey = EOF;
	  break;
	case 1:
	  repeat = 0;
	  if (ende < KEYDELAY)
	    break;
	  else
	    ende = 0;
	  brlcode = braille->read (&press);
	  if (brlcode != EOF)
	   {
	     brlcode = lastkey * 1000 + brlcode;
	     selkey (brlcode, 1);
	     lastkey = EOF;
	     brlcode = 0;
	   }
	  break;

	case 2:
	  if (!press)
	   {
	     lastkey = EOF;
	     repeat = 0;
	     brlcode = -1;
	     break;
	   }
	  repeat++;
	  if (keypress == EOF)
	    if (repeat < REPEATDELAY)
	     {
	       sel = 0;
	       break;
	     }
	    else
	     {
	       ende = 0;
	       repeat = 0;
	     }

	  else if (ende < KEYDELAY)
	    break;
	  else
	    ende = 0;
	  if (braille->read (&press) != EOF)
	    lastkey = EOF;
	  break;
	}

       if (sel)
	 brlcode = selkey (lastkey, 1);
       if (lastkey > 1000 || lastkey < -1)
	 lastkey = EOF;

     }				/* end whiel */

     /*
      * Update blink counters: 
      */
     if (env.csrblink)
       if (!--csrcntr)
	 csrcntr = (csron ^= 1) ? env.csroncnt : env.csroffcnt;
     getstat (&scr);
     chkscrsize ();
     if (!(dispmd & (HELP_SCRN | FROZ_SCRN)) && curscr != scr.no)
       switchto (scr.no);

     /* cursor tracking */
     if (p->csrtrk)
      {

	/* If cursor moves while blinking is on */
	if (env.csrblink)
	 {
	   if ((env.csrmode ? attrpos.y : scr.posy) != p->coy)
	    {
	      /* turn off cursor to see what's under it while changing lines */
	      csron = 0;
	      csrcntr = env.csroffcnt;
	    }
	   if ((env.csrmode ? attrpos.x : scr.posx) != p->cox)
	    {
	      /* turn on cursor to see it moving on the line */
	      csron = 1;
	      csrcntr = env.csroncnt;
	    }
	 }
	/* If the cursor moves in cursor tracking mode: */
	switch (env.csrmode)
	 {
	 case 0:		/* folow the systemcursor */
	   if ((scr.posx != p->cox || scr.posy != p->coy))
	    {
	      setwinxy (scr.posx, scr.posy);
	      p->cox = scr.posx;
	      p->coy = scr.posy;
	      hardcsr.x = p->cox;
	      hardcsr.y = p->coy;
	    }
	   break;
	 case 1:		/* follow attributes */
	 case 2:		/* follow systemcursor first then attributes */
/*        if(!csr_active) */
	  {
	    if ((hardcsr.x != scr.posx || hardcsr.y != scr.posy)
		&& env.csrmode == 2 && (scr.posx >= env.syscsrlimit.x1
					&& scr.posx <= env.syscsrlimit.x2)
		&& (scr.posy >= env.syscsrlimit.y1
		    && scr.posy <= env.syscsrlimit.y2))
	     {

	       setwinxy (scr.posx, scr.posy);
	       hardcsr.x = scr.posx;
	       hardcsr.y = scr.posy;
	       attrpos = hardcsr;
	       p->cox = scr.posx;
	       p->coy = scr.posy;
	     }
	    else
	     {
	       if (!getsoftcsr (env.softcsr1, env.limitcsr1))
		 if (!getsoftcsr (env.softcsr2, env.limitcsr2))
		  {
		    int dum;

		    cleanoldscr ();
		    dum = getsoftcsr (env.softcsr1, env.limitcsr1);
		  }
	       if (attrpos.x != p->cox || attrpos.y != p->coy)
		{
		  hardcsr = attrpos;
		  setwinxy (attrpos.x, attrpos.y);
		  p->cox = attrpos.x;
		  p->coy = attrpos.y;
		}
	     }			/*else */
	  }

	   break;
	 case 3:		/* follow attributes first then systemcursor */
/*      if(!csr_active) */
	  {

	    if (!getsoftcsr (env.softcsr1, env.limitcsr1))
	      if (!getsoftcsr (env.softcsr2, env.limitcsr2))
	       {
		 cleanoldscr ();
		 getsoftcsr (env.softcsr1, env.limitcsr1);
	       }
	    if (attrpos.x != p->cox || attrpos.y != p->coy)
	     {
	       setwinxy (attrpos.x, attrpos.y);
	       p->cox = attrpos.x;
	       p->coy = attrpos.y;
	     }
	    else if (hardcsr.x != scr.posx || hardcsr.y != scr.posy)
	     {
	       setwinxy (scr.posx, scr.posy);
	       hardcsr.x = scr.posx;
	       hardcsr.y = scr.posy;
	       attrpos = hardcsr;
	       p->cox = scr.posx;
	       p->coy = scr.posy;
	     }
	  }

	   break;
	 }			/* switch */
      }
     /* If attribute underlining is blinking during display movement */

     oldwinx = p->winx;
     oldwiny = p->winy;
     /* If not in info mode, get screen image: */
     if (!infmode)
      {
	/* Update the Braille display. * For the sake of displays on 
	 * which the status cells and the * main display have to be
	 * updated together, it is guaranteed * that setbrlstat() will 
	 * be called just *before* writebrl(). 
	 */
/*  if(fcells>-1) */
	{

	  statcells[0] = p->winy + 1;	/* y-pos of brailledisplay */
	  statcells[1] = POSX;	/* x-pos of current cursor */
	  statcells[2] = connr;	/* number of current console */
	}

	if (vertdisp)
	  screenfull ();

	/* update the braille-status-cells */
	if (upd_st_cells)
	  braille->setstatus (statcells);

	memset (spkstr, 0, sizeof (spkstr));	/* clean spkstr */
	getscr ((winpos)
		{

		0, p->winy, COLS, brl.y}
		, (unsigned char *) spkstr,
		p->dispmode ? SCR_ATTRIB : SCR_TEXT);
	memcpy (brl.disp, spkstr + p->winx, brl.x);
	/*
	 * Do Braille translation using current table: 
	 */
	if (env.sixdots && curtbl != attribtrans)
	  for (i = 0; i < brl.x * brl.y;
	       brl.disp[i] = curtbl[brl.disp[i]] & 0x3f, i++);
	else
	  for (i = 0; i < brl.x * brl.y;
	       brl.disp[i] = curtbl[brl.disp[i]], i++);

	/* Attribute underlining: if viewing text (not attributes), attribute
	   underlining is active and visible and we're not in help, then we
	   get the attributes for the current region and OR the underline. 
	 */
	getscr ((winpos)
		{
		0, p->winy, COLS, brl.y}
		, attrbuf, SCR_ATTRIB);

	spkline (spkcsr (0));
	if (!p->dispmode && env.attrvis)
	 {
	   for (i = p->winx; i < (p->winx + brl.x) * brl.y; i++)
	    {
	      unsigned char ma = attrbuf[i] & showattr.mask;
	      unsigned char mv = showattr.mask & showattr.val;

	      if (ma == mv)
		brl.disp[i - p->winx] |= ATTR1CHAR;
	    }

	 }

	/*
	 * If the cursor is visible and in range, and help is off: 
	 */
	if (env.csrvis && (!env.csrblink || csron))
	 {

	   if (env.csrmode
	       && (attrpos.x >= p->winx && attrpos.x < p->winx + brl.x
		   && attrpos.y >= p->winy && attrpos.y < p->winy + brl.y))
	     brl.disp[(attrpos.y - p->winy) * brl.x + attrpos.x - p->winx] |=
	       env.csrsize ? BIG_CSRCHAR : SMALL_CSRCHAR;
	   else if (scr.posx >= p->winx && scr.posx < p->winx + brl.x
		    && scr.posy >= p->winy && scr.posy < p->winy + brl.y)
	     brl.disp[(scr.posy - p->winy) * brl.x + scr.posx - p->winx] |=
	       env.csrsize ? BIG_CSRCHAR : SMALL_CSRCHAR;
	 }
	braille->write (&brl);
      }
     do
      {
	chkfifo ();
      }
     while (sblpaus);

     delay (DELAY_TIME);
   }				/* while (mainloop) */

  closefifo ();
  clrbrlstat ();
  message ("end of suse-blinux", 0);
  closescr ();

spkclose();
  /*
   * Hard-wired delay to try and stop us being killed prematurely ... 
   */
  delay (1000);
  braille->close (&brl);
  if (kbd_sniff_on)
    close_kbd_sniff ();

  play (snd_brloff);
  for (i = 0; i <= NBR_SCR; i++)
   {
     free (scrparam[i]);
     scrparam[i] = 0;
   }
  sbl_close_log ();
  return 0;
}

void startbrl ()
{
  braille->initialize (&brl, BRLPORT);
  if (brl.x == -1)
   {
     sbl_log ("Braille driver initialization failed\n");
     closescr ();
     exit (5);
   }
  fwinshift = brl.x;
  hwinshift = fwinshift / 2;
  csr_offright = brl.x / 4;
  vwinshift = 5;
  play (snd_detected);
  /*  clrbrlstat (); */
}

void switchto (unsigned int scrno)
{
  curscr = scrno;
  if (scrno > NBR_SCR)
    scrno = 0;
  if (!scrparam[scrno])		/* if not already allocated... */
   {
     if (!(scrparam[scrno] = (brltty_param *) malloc (sizeof (*p))))
       scrno = 0;		/* unable to allocate a new structure */
     else
       *scrparam[scrno] = initparam;
   }
  p = scrparam[scrno];
  usetable (p->dispmode ? TBL_ATTRIB : TBL_TEXT);
}

void setwinxy (int x, int y)
{
  if (env.slidewin)
   {
     /* Change position only if the coordonates are not already displayed */
     if (x < p->winx || x >= p->winx + brl.x ||
	 y < p->winy || y >= p->winy + brl.y)
      {
	p->winy = y < brl.y - 1 ? 0 : y - (brl.y - 1);
	if (x < brl.x)
	  p->winx = 0;
	else if (x >= scr.cols - csr_offright)
	  p->winx = scr.cols - brl.x;
	else
	  p->winx = x - (brl.x - csr_offright);
      }
   }
  else
   {
     if (x < p->winx || x >= p->winx + brl.x)
       p->winx = x >= (scr.cols / brl.x) * brl.x ? scr.cols - brl.x :
	 (x / brl.x) * brl.x;
     if (y < p->winy || y >= p->winy + brl.y)
       p->winy = y < brl.y - 1 ? 0 : y - (brl.y - 1);
   }
}

void csrjmp (int x, int y)
{
  /*
   * Fork cursor routing subprocess. * First, we must check if a
   * subprocess is already running: if so, we * send it a SIGUSR1 and
   * wait for it to die. 
   */
  signal (SIGCHLD, SIG_IGN);	/* ignore SIGCHLD for the moment */
  if (csr_active)
   {
     kill (csr_pid, SIGUSR1);
     wait (NULL);
     csr_active = 0;
   }
  signal (SIGCHLD, stop_child);	/* re-establish handler */

  csr_active = 1;
  switch (csr_pid = fork ())
   {
   case -1:			/* fork failed */
     csr_active = 0;
     break;
   case 0:			/* child, cursor routing process */
     nice (CSRJMP_NICENESS);	/* reduce scheduling priority */
     csrjmp_sub (x, y);
     exit (0);			/* terminate child process */
   default:			/* parent waits for child to return */
     break;
   }
}

void csrjmp_sub (int x, int y)
{
  int curx, cury;		/* current cursor position */
  int dif, t = 0;
  sigset_t mask;		/* for blocking of SIGUSR1 */

  /* Set up signal mask: */
  sigemptyset (&mask);
  sigaddset (&mask, SIGUSR1);

  if (vtxrouting)
   {
     unsigned char tmpstr[4] = "";

     if ((spkstr[x] >= '0' && spkstr[x] <= '9')
	 && (spkstr[x + 1] >= '0' && spkstr[x + 1] <= '9')
	 && (spkstr[x + 2] >= '0' && spkstr[x + 2] <= '9'))
      {
	strncpy (tmpstr, spkstr + x, 3);
      }
     else
       if ((spkstr[x - 1] >= '0' && spkstr[x - 1] <= '9')
	   && (spkstr[x] >= '0' && spkstr[x] <= '9')
	   && (spkstr[x + 1] >= '0' && spkstr[x + 1] <= '9'))
      {
	strncpy (tmpstr, spkstr + (x - 1), 3);
      }
     else
       if ((spkstr[x - 2] >= '0' && spkstr[x - 2] <= '9')
	   && (spkstr[x - 1] >= '0' && spkstr[x - 1] <= '9')
	   && (spkstr[x] >= '0' && spkstr[x] <= '9'))
      {
	strncpy (tmpstr, spkstr + (x - 2), 3);
      }
     if (tmpstr[0] != 0)
       inskey (tmpstr);
     return;
   }

  /* Initialise second thread of screen reading: */
  if (initscr_phys ())
    return;

  getstat_phys (&scr);
  chkscrsize ();
  /* Deal with vertical movement first, ignoring horizontal jumping ... */
  dif = y - scr.posy;
  while (dif != 0 && curscr == scr.no)
   {
     timeout_yet (0);		/* initialise stop-watch */
     sigprocmask (SIG_BLOCK, &mask, NULL);	/* block SIGUSR1 */
     inskey (dif > 0 ? (unsigned char *) DN_CSR : (unsigned char *) UP_CSR);
     sigprocmask (SIG_UNBLOCK, &mask, NULL);	/* unblock SIGUSR1 */
     do
      {
#if CSRJMP_LOOP_DELAY > 0
	delay (CSRJMP_LOOP_DELAY);	/* sleep a while ... */
#endif
	cury = scr.posy;
	curx = scr.posx;
	getstat_phys (&scr);
	chkscrsize ();
      }
     while (!(t = timeout_yet (CSRJMP_TIMEOUT)) &&
	    scr.posy == cury && scr.posx == curx);
     if (t)
       break;
     if ((scr.posy == cury && (scr.posx - curx) * dif <= 0) ||
	 (scr.posy != cury && (y - scr.posy) * (y - scr.posy) >= dif * dif))
      {
	delay (CSRJMP_SETTLE_DELAY);
	getstat_phys (&scr);
	chkscrsize ();
	if ((scr.posy == cury && (scr.posx - curx) * dif <= 0) ||
	    (scr.posy != cury
	     && (y - scr.posy) * (y - scr.posy) >= dif * dif))
	 {
	   /* We are getting farther from our target... Let's try to go back 
	    * to the previous position wich was obviously the nearest ever 
	    * reached before gibing up.
	    */
	   sigprocmask (SIG_BLOCK, &mask, NULL);	/* block SIGUSR1 */
	   inskey ((unsigned char *) (dif < 0 ? DN_CSR : UP_CSR));
	   sigprocmask (SIG_UNBLOCK, &mask, NULL);	/* unblock SIGUSR1 */
	   break;
	 }
      }
     dif = y - scr.posy;
   }

  if (x >= 0)
   {				/* don't do this for vertical-only routing (x=-1) */
     /* Now horizontal movement, quitting if the vertical position is wrong: */
     dif = x - scr.posx;
     while (dif != 0 && scr.posy == y && curscr == scr.no)
      {
	timeout_yet (0);	/* initialise stop-watch */
	sigprocmask (SIG_BLOCK, &mask, NULL);	/* block SIGUSR1 */
	inskey (dif >
		0 ? (unsigned char *) RT_CSR : (unsigned char *) LT_CSR);
	sigprocmask (SIG_UNBLOCK, &mask, NULL);	/* unblock SIGUSR1 */
	do
	 {
#if CSRJMP_LOOP_DELAY > 0
	   delay (CSRJMP_LOOP_DELAY);	/* sleep a while ... */
#endif
	   curx = scr.posx;
	   getstat_phys (&scr);
	   chkscrsize ();
	 }
	while (!(t = timeout_yet (CSRJMP_TIMEOUT)) &&
	       scr.posx == curx && scr.posy == y);
	if (t)
	  break;
	if (scr.posy != y || (x - scr.posx) * (x - scr.posx) >= dif * dif)
	 {
	   delay (CSRJMP_SETTLE_DELAY);
	   getstat_phys (&scr);
	   chkscrsize ();
	   if (scr.posy != y || (x - scr.posx) * (x - scr.posx) >= dif * dif)
	    {
	      /* We probably wrapped on a short line... or are getting farther 
	       * from our target. Try to get back to the previous position which
	       * was obviously the nearest ever reached before we exit.
	       */
	      sigprocmask (SIG_BLOCK, &mask, NULL);	/* block SIGUSR1 */
	      inskey (dif >
		      0 ? (unsigned char *) LT_CSR : (unsigned char *)
		      RT_CSR);
	      sigprocmask (SIG_UNBLOCK, &mask, NULL);	/* unblock SIGUSR1 */
	      break;
	    }
	 }
	dif = x - scr.posx;
      }
   }

  closescr_phys ();		/* close second thread of screen reading */
}

void message (char *s, short silent)
{
  int i, j, l;

  usetable (TBL_TEXT);
  memset (brl.disp, ' ', brl.x * brl.y);
  l = strlen (s);
  while (l)
   {
     j = l <= brl.x * brl.y ? l : brl.x * brl.y - 1;
     for (i = 0; i < j; brl.disp[i++] = *s++);
     if (l -= j)
       brl.disp[brl.x * brl.y - 1] = '-';
   }
  /*
   * Do Braille translation using current table. * Six-dot mode is
   * ignored, since case can be important, and * blinking caps won't 
   * work ... 
   */
  for (i = 0; i < brl.x * brl.y; brl.disp[i] = curtbl[brl.disp[i]], i++);

  braille->write (&brl);
  usetable (p->dispmode ? TBL_ATTRIB : TBL_TEXT);
}

void clrbrlstat (void)
{
  memset (statcells, 0, sizeof (statcells));
  braille->setstatus (statcells);
}

void termination_handler (int signum)
{
  keep_going = 0;
  signal (signum, termination_handler);
}

void stop_child (int signum)
{
  signal (signum, stop_child);
  wait (NULL);
  csr_active = 0;
}

void usetable (int tbl)
{
  curtbl = (tbl == TBL_ATTRIB) ? attribtrans : texttrans;
}

void chkscrsize ()
{
  if ((scrx != COLS) || (scry != ROWS))
   {
     sbl_log ("oldx=%i oldy=%i newx=%i newy=%i\n", scrx, scry, COLS, ROWS);
     scrx = COLS;
     scry = ROWS;
     free (oldscr);
     oldscr = 0;
     sbl_log ("free oldscr\n");
     allocoldscr ();
     sbl_log ("new alloc oldscr\n");
   }

}
void allocoldscr ()
{
  int i;

  oldscr = malloc (sizeof (unsigned char *) * ROWS);

  for (i = 0; i < ROWS; i++)
   {
     oldscr[i] = (unsigned char *) malloc (COLS);
     memset (oldscr[i], 0, COLS);
   }

}

void cpytooldscr (unsigned char *src)
{
  int y;

  for (y = 0; y < ROWS; y++)
    memcpy (oldscr[y], src + y * COLS, COLS);
}

void cleanoldscr ()
{

  int i;

  for (i = 0; i < ROWS; i++)
   {
     sbl_log ("#%i# %s \n", i, oldscr[i]);
     memset (oldscr[i], 0, COLS);
   }

}

int getsoftcsr (mask softcsr, range limit)
{
  short int i, hit = 0, j;
  unsigned char line[ROWS][COLS];
  unsigned char tmpline[COLS * ROWS];

  if (limit.y1 > ROWS)
    limit.y1 = ROWS;
  if (limit.y2 > ROWS)
    limit.y2 = ROWS;
  if (limit.x1 > COLS)
    limit.x1 = COLS;
  if (limit.x2 > COLS)
    limit.x2 = COLS;

  getscr ((winpos)
	  {
	  0, 0, COLS, ROWS}
	  , tmpline, SCR_ATTRIB);
  memcpy (line, tmpline, sizeof (line));
  for (i = limit.y1; i < limit.y2; i++)
    for (j = limit.x1; j < limit.x2; j++)
      if (oldscr[i][j] != line[i][j])
       {
	 unsigned char ma = line[i][j] & softcsr.mask;
	 unsigned char mv = softcsr.mask & softcsr.val;
	 short t;

	 hit = 1;
	 if (ma == mv)
	  {
	    attrpos.y = i;
	    for (t = j;
		 t > limit.x1
		 && (line[i][t] & softcsr.mask) ==
		 (softcsr.mask & softcsr.val); t--);
	    if (t == limit.x1
		&& (line[i][t] & softcsr.mask) ==
		(softcsr.mask & softcsr.val))
	      attrpos.x = t;
	    else
	      attrpos.x = t + 1;
	    cpytooldscr (line[0]);
	    return 1;
	  }
       }

/*    memcpy(oldscr,line,scr)); */
  if (hit)
    return 0;
  else
    return 1;

}

void screenfull ()
{
  int dots1[] = { 64, 4, 2, 1 };
  int dots2[] = { 128, 32, 16, 8 };
  char line[22];
  int i, y, parts, cell = 0, celldisp = 0;

  line[21] = 0;
  for (y = 0; y < scr.rows; y++)
   {

     if (!(y % 2))
      {
	cell++;
	celldisp = 0;
      }
     for (parts = 0; parts < 4; parts++)
      {
	celldisp = 0;

	line[0] = 0;
	getscr ((winpos)
		{
		20 * parts, y, 20, 1}
		, (unsigned char *) line, SCR_TEXT);
	for (i = 0; i <= 20 && strlen (line); i++)
	  if (line[i] > 32)
	   {
	     if (!(y % 2))
	       celldisp += dots1[parts];
	     else
	       celldisp += dots2[parts];
	     i = 21;
	   }

      }
/*   statcells[-1+cell]=celldisp; */
     statcells[fcells + cell] = celldisp;
   }

}

void initattr ()
{
  switch (env.attrnr)
   {
   case 1:
     showattr = env.attr1;
     break;
   case 2:
     showattr = env.attr2;
     break;
   case 3:
     showattr = env.attr3;
     break;
   case 4:
     showattr = env.attr4;
   }
}

void ggetproc (void)
{
  char str[100] = "";
  static int i = 0;

  i++;
  if (i < PROFDELAY)
    return;
  i = 0;
  getfgproc (str, connr);
  if (!strcmp (str, env.profname))
    return;
  sbl_log ("applicatoon changed on console=%i\n", connr);

  gethome (home, connr);
  sbl_log ("home=%s ", home);

  getprofile (&env, PROGPATH, home, str);
  sbl_log ("application=%s profile=%s \n", env.profname, str);
  getkeymap (sblconf, env.profname, home);
  setspk ();
  getspkfilter (PROGPATH, env.profname, home, env.spklang);

  initattr ();

}

void getdriver ()
{
  static char lib[100];
  struct brlinfo info;
  DIR *dirp;
  struct dirent *entry;
  char pathstr[200];

  sprintf (pathstr, "%s/lib", PROGPATH);

  dirp = opendir (pathstr);
  while ((entry = readdir (dirp)))
   {
     if (!strncmp (entry->d_name, "libsbl", 6))
      {
	sprintf (lib, "%s/%s", pathstr, entry->d_name);
	braille_libname = lib;
	load_braille_driver ();
	info = braille->identify (BRLNAME, BRLPORT);
	sbl_log ("%s cols=%d\n", lib, info.cols);
	if (info.cols != 0)
	  break;
	else
	  unload_braille_driver ();
      }				/* if */

   }				/* while */
  closedir (dirp);
  braille->identifier = BRLNAME;
  if (info.st_cells > 1)
    upd_st_cells = 1;
  else
    upd_st_cells = 0;
}

void openfifo ()
{
  read_fd = open (FIFO_IN, O_NDELAY);
  write_fd = open (FIFO_OUT, O_RDWR);

  if (read_fd < 0 || write_fd < 0)
   {
     fifo_ok = 0;
     sbl_log ("fifo error: read=%d write=%d\n", read_fd, write_fd);
     return;
   }
  FD_ZERO (&w_fds);
  FD_SET (write_fd, &w_fds);

}				/* openfifo */

void chkfifo ()
{
  int len;			/* length of input-string */
  char writebuf[100];		/* writebuffer */
  char readbuf[100];		/* input-buffer */

  if (!fifo_ok)
    return;
  len = read (read_fd, readbuf, 80);
  if (len > 1)
   {
     readbuf[len - 1] = 0;
     fifocommands (writebuf, readbuf);
     readbuf[0] = 0;

     write (write_fd, writebuf, strlen (writebuf));
   }				/* if */
}				/* chkfifo */

void fifocommands (char *out, char *cmd)
{
  if (!strcmp (cmd, "vtxon"))
   {
     vtxrouting = 1;
     sprintf(out,"01: vtxon\n");
     return;
   }
   else
     if (!strcmp (cmd, "nextvol"))
   {
   char tmpstr[80]="ammec 1 2 3";
     nextvol();
     spkwrite(tmpstr);
     sprintf(out,"01: nextvol\n");
     return;
   }
   else
    if (!strcmp (cmd, "prevvol"))
   {
   char tmpstr[80]="ammec 1 2 3";
     prevvol();
     spkwrite(tmpstr);
     sprintf(out,"01: prevvol\n");
     return;
   }
   else
       if (!strcmp (cmd, "prevspd"))
   {
      char tmpstr[80]="ammec 1 2 3";
     prevspd();
     spkwrite(tmpstr);
     sprintf(out,"01: prevspd\n");
     return;
   }
   else
       if (!strcmp (cmd, "nextspd"))
   {
      char tmpstr[80]="ammec 1 2 3";
     nextspd();
      spkwrite(tmpstr);
     sprintf(out,"01: nextspd\n");
     return;
   }
   else
   if (!strcmp (cmd, "spkscrfromln"))
   {
   spkmode=SPKNORM;
     spkscrfromln();
     sprintf(out,"01: spkscrfromln\n");
     return;
   }
  else if (!strcmp (cmd, "vtxoff"))
   {
     vtxrouting = 0;
     sprintf(out,"01: vtxoff\n");
     return;
   }
  else if (!strcmp (cmd, "lnup"))
   {
     lnup ();
     sprintf (out, "01: %s done\n", cmd);
     return;
   }
  else if (!strcmp (cmd, "lndn"))
   {
     lndn ();
     sprintf (out, "01: %s done\n", cmd);
     return;
   }
  else if (!strcmp (cmd, "lnlft"))
   {
     lnlft ();
     sprintf (out, "01: %s done\n", cmd);
     return;
   }
  else if (!strcmp (cmd, "lnrgt"))
   {
     lnrgt ();
     sprintf (out, "01: %s done\n", cmd);
     return;
   }
  else if (!strcmp (cmd, "botleft"))
   {
     botleft ();
     sprintf (out, "01: %s done\n", cmd);
     return;
   }
  else if (!strcmp (cmd, "topleft"))
   {
     topleft ();
     sprintf (out, "01: %s done\n", cmd);
     return;
   }
  else if (!strcmp (cmd, "spkcurln"))
   {
     spkcurln ();
     sprintf (out, "01: %s done\n", cmd);
     return;
   }
  else if (!strcmp (cmd, "csrtrk"))
   {
     csrtrk ();
     sprintf (out, "01: %s done\n", cmd);
     return;
   }
  else if (!strcmp (cmd, "csrblink on"))
   {
     env.csrblink = 1;
     sprintf (out, "01: %s done\n", cmd);
     return;
   }

  if (!strcmp (cmd, "csrblink off"))
   {
     env.csrblink = 0;
     sprintf (out, "01: %s done\n", cmd);
     return;
   }
  if (!strncmp (cmd, "resetbrl", 8))
   {
     resetbrl ();
     sprintf (out, "01: %s done\n", cmd);
     return;
   }
  if (!strncmp (cmd, "sblpaus", 7))
   {
     braille->close (&brl);
     play (snd_brloff);
     sprintf (out, "01: %s done\n", cmd);
     sblpaus = 1;
     return;
   }
  if (!strncmp (cmd, "sblresume", 9) && sblpaus)
   {
     startbrl ();
     sprintf (out, "01: %s done\n", cmd);
     sblpaus = 0;
     return;
   }
  if (!strncmp (cmd, "setline", 7))
   {
   int nr=atoi(cmd+7);
   if(nr>=0 && nr<ROWS)
   {
   p->winy=nr;
   }
   sprintf(out,"01: setline\n");
   return;
   } else
     if (!strncmp (cmd, "spkoff_setline", 14))
   {
   int nr=atoi(cmd+14);
   if(nr>=0 && nr<ROWS)
   {
   p->winy=nr;
//   spkmode=SPKOFF;
   }
   sprintf(out,"01: spkoff_setline\n");
   return;
   } else
     if (!strncmp (cmd, "spkoff", 6))
     {
     spkmode=SPKOFF;
        sprintf(out,"01: spkoff\n");
        return;
     } else
       if (!strncmp (cmd, "spktoggle", 6))
     {
     if(spkmode==SPKOFF)
     spkmode=SPKNORM;
     else
     spkmode=SPKOFF;
        sprintf(out,"01: spktoggle\n");
        return;
     }
     else
       if (!strncmp (cmd, "spkon", 5))
       {
       spkmode=SPKNORM;
          sprintf(out,"01: spkon\n");
          return;
       } else
  if (!strncmp (cmd, "insert", 6))
   {
     if (strlen (cmd) > 7)
      {
	inskey ((unsigned char *) cmd + 7);
	sprintf (out, "01: %s done\n", cmd);
      }
     else
       sprintf (out, "02: %s failed\n", cmd);
     return;
   }
  if (!strcmp (cmd, "getcurline"))
   {

     sprintf (out, "01: %s\n", spkstr);
     return;
   }
  if (!strncmp (cmd, "getline", 7))
   {
     int number = 0;
     char linestr[COLS + 1];

     memset (linestr, 0, sizeof (linestr));
     if (strlen (cmd) < 8)
      {
	sprintf (out, "03: %s failed\n", cmd);
	return;
      }

     if (!(number = atoi (cmd + 8)))
      {
	sprintf (out, "04: %s failed %s %i\n", cmd, cmd + 8, atoi (cmd + 8));
	return;
      }

     if (number == 0 || number > ROWS)
      {
	sprintf (out, "02: line number %i not in 1..%i\n", number, ROWS);
	return;
      }
     getscr ((winpos)
	     {
	     0, number - 1, COLS, 1}
	     , (unsigned char *) linestr, SCR_TEXT);
     sprintf (out, "01: %s\n", linestr);
     return;
   }

  else
    sprintf (out, "02: error %s is not a sbl command\n", cmd);
  return;
}				/* fifo commands */

void closefifo ()
{

  close (read_fd);
  close (write_fd);
}

void start_script (char *script)
{
  static int script_active = 0;

  sbl_log ("trying to start script %s\n", script);
  signal (SIGCHLD, SIG_IGN);	/* ignore SIGCHLD for the moment */
  if (script_active)
   {
     kill (script_pid, SIGUSR1);
     wait (NULL);
     script_active = 0;
   }

  signal (SIGCHLD, stop_child);	/* re-establish handler */

  script_active = 1;
  switch (script_pid = fork ())
   {
   case -1:			/* fork failed */
     sbl_log ("fork for scripting failed\n");
     script_active = 0;
     break;
   case 0:			/* child, script process */
/* reduce scheduling priority
   nice (CSRJMP_NICENESS);
*/
     system ("/root/lnup");
     exit (0);			/* terminate child process */
   default:			/* parent waits for child to return */
     break;
   }				/* switch */

}				/* start script */

/* functions for navigation */

void autoprofonoff ()
{

  if (autoprof)
   {
     play (snd_toggleoff);
     autoprof = 0;
   }
  else
   {
     play (snd_toggleon);
     autoprof = 1;
   }
}

void resetbrl ()
{
  braille->close (&brl);
  play (snd_brloff);
  startbrl ();
}

void line01 ()
{
  p->winy = 0;
}

void topleft ()
{
  p->winy = 0;
  p->winx = 0;
}

void botleft ()
{
  p->winy = scr.rows - brl.y;
  p->winx = 0;
}

void winup ()
{
  if (p->winy == 0)
    play (snd_bounce);
  p->winy = MAX (p->winy - vwinshift, 0);
}

void windn ()
{
  if (p->winy == scr.rows - brl.y)
    play (snd_bounce);
  p->winy = MIN (p->winy + vwinshift, scr.rows - brl.y);
}

void lnlft ()
{
  if (p->winx)
   {
     if (p->winx >= brl.x)
       p->winx -= brl.x;
     else
       p->winx = 0;
   }
  else if (p->winy)
   {
     p->winy--;
     p->winx = COLS - brl.x;
   }
}

void lnrgt ()
{
  if (p->winx < (COLS - brl.x))
   {
     if ((p->winx + brl.x) <= (COLS - brl.x))
       p->winx += brl.x;
     else
       p->winx = COLS - brl.x;
   }
  else if (p->winy < ROWS - brl.y)
   {
     p->winy++;
     p->winx = 0;
   }
}
void lnup ()
{
  spk = 1;
  if (p->winy == 0)
    play (snd_bounce);

  else
    p->winy--;
}

void lndn ()
{
  spk = 1;
  if (p->winy == scr.rows - brl.y)
    play (snd_bounce);
  else
    p->winy++;
}

void csrtrk ()
{

  spkcsr (1);
  switch (env.csrmode)
   {
   case 0:
     setwinxy (scr.posx, scr.posy);
     break;
   case 1:
   case 2:
   case 3:
     setwinxy (attrpos.x, attrpos.y);
     break;
   }
  p->csrtrk = 1;
}

void syscsr ()
{
  env.csrmode = 0;
  p->csrtrk = 1;
}

void softcsr ()
{
  env.csrmode = 1;
  p->csrtrk = 1;
}

void chrlft ()
{
  if (p->winx == 0)
    play (snd_bounce);
  p->winx = MAX (p->winx - 1, 0);
}

void chrrgt ()
{
  if (p->winx == scr.cols - brl.x)
    play (snd_bounce);
  p->winx = MIN (p->winx + 1, scr.cols - brl.x);
}

void hwinlft ()
{
  if (p->winx == 0)
    play (snd_bounce);
  p->winx = MAX (p->winx - hwinshift, 0);
}

void hwinrgt ()
{
  if (p->winx == scr.cols - brl.x)
    play (snd_bounce);
  p->winx = MIN (p->winx + hwinshift, scr.cols - brl.x);
}

void fwinlft ()
{
  if (p->winx == 0 && p->winy > 0)
   {
     p->winx = scr.cols - brl.x;
     p->winy--;
     play (snd_wrap_up);
   }
  else if (p->winx == 0 && p->winy == 0)
    play (snd_bounce);
  else
    p->winx = MAX (p->winx - fwinshift, 0);
}

void fwinrgt ()
{
  if (p->winx == scr.cols - brl.x && p->winy < scr.rows - brl.y)
   {
     p->winx = 0;
     p->winy++;
     play (snd_wrap_down);
   }
  else if (p->winx == scr.cols - brl.x && p->winy == scr.rows - brl.y)
    play (snd_bounce);
  else
    p->winx = MIN (p->winx + fwinshift, scr.cols - brl.x);
}

void csrjump ()
{
  if ((dispmd & HELP_SCRN) != HELP_SCRN)
    csrjmp (p->winx, p->winy);
}

void csrjmpvert ()
{
  if ((dispmd & HELP_SCRN) != HELP_SCRN)
    csrjmp (-1, p->winy);
}

void keyup ()
{
  if ((dispmd & HELP_SCRN) != HELP_SCRN)
    inskey ((unsigned char *) UP_CSR);
}

void keydn ()
{
  if ((dispmd & HELP_SCRN) != HELP_SCRN)
    inskey ((unsigned char *) DN_CSR);
}

void keyrgt ()
{
  if ((dispmd & HELP_SCRN) != HELP_SCRN)
    inskey ((unsigned char *) RT_CSR);
}

void keylft ()
{
  if ((dispmd & HELP_SCRN) != HELP_SCRN)
    inskey ((unsigned char *) LT_CSR);
}

void keyenter ()
{
  if ((dispmd & HELP_SCRN) != HELP_SCRN)
    inskey ((unsigned char *) KEY_RETURN);
}

void keyesc ()
{
  char esc[2];

  sprintf (esc, "%c", 27);
  if ((dispmd & HELP_SCRN) != HELP_SCRN)
    inskey (esc);
}

void csrvisoff ()
{
  spkstop ();
  env.csrvis = 0;
}

void jmpmark1 ()
{
  p->winy = env.mark1 - 1;
}

void jmpmark2 ()
{
  p->winy = env.mark2 - 1;
}

void jmpmark3 ()
{
  p->winy = env.mark3 - 1;
}

void jmpmark4 ()
{
  p->winy = env.mark4 - 1;
  env.csrvis = 1;
}

void attr1 ()
{
  env.attrvis = 1;
  showattr = env.attr1;
}

void attr2 ()
{
  env.attrvis = 1;
  showattr = env.attr2;
}

void attr3 ()
{
  env.attrvis = 1;
  showattr = env.attr3;
}

void attr4 ()
{
  env.attrvis = 1;
  showattr = env.attr4;
}

void csrtrkoff ()
{
  p->csrtrk = 0;
  play (snd_toggleoff);
}

void prof1 ()
{
  int snd[] = { 1000, 80, 0 };

  autoprof = 0;
  getprofile (&env, PROGPATH, home, PROFILE1);
  initattr ();
  getkeymap (sblconf, env.profname, home);
  setspk ();
  getspkfilter (PROGPATH, env.profname, home, env.spklang);

  play (snd);

}

void prof2 ()
{
  int snd[] = { 1000, 80, 1, 40, 1000, 80, 0 };

  autoprof = 0;
  getprofile (&env, PROGPATH, home, PROFILE2);
  initattr ();
  getkeymap (sblconf, env.profname, home);

  setspk ();
  getspkfilter (PROGPATH, env.profname, home, env.spklang);

  play (snd);
}

void prof3 ()
{
  int snd[] = { 1000, 80, 1, 40, 1000, 80, 1, 40, 1000, 80, 0 };

  autoprof = 0;
  getprofile (&env, PROGPATH, home, PROFILE3);
  initattr ();
  getkeymap (sblconf, env.profname, home);
  setspk ();
  getspkfilter (PROGPATH, env.profname, home, env.spklang);

  play (snd);
}

void prof4 ()
{
  int snd[] = { 1000, 80, 1, 40, 1000, 80,
    1, 40, 1000, 80, 1, 40, 1000, 80, 0
  };

  autoprof = 0;
  getprofile (&env, PROGPATH, home, PROFILE4);
  initattr ();
  getkeymap (sblconf, env.profname, home);
  setspk ();
  getspkfilter (PROGPATH, env.profname, home, env.spklang);

  play (snd);
}

void attroff ()
{
  env.attrvis = 0;
}

void attrmodonoff ()
{
  if (p->dispmode)
   {
     usetable (TBL_TEXT);
     p->dispmode = 0;
   }
  else
   {
     usetable (TBL_ATTRIB);
     p->dispmode = 1;
   }
}

void sixdotsonoff ()
{
  if (env.sixdots)
    env.sixdots = 0;
  else
    env.sixdots = 1;
}

void csrblinkonoff ()
{
  if (env.csrblink)
    env.csrblink = 0;
  else
    env.csrblink = 1;
}

void csrblockonoff ()
{
  if (env.csrsize)
    env.csrsize = 0;
  else
    env.csrsize = 1;
}

void cutbegin ()
{
  cut_begin (p->winx, p->winy);
}

void cutend ()
{
  cut_end (p->winx + brl.x - 1, p->winy + brl.y - 1);
}

void paste ()
{
  if ((dispmd & HELP_SCRN) != HELP_SCRN)
    cut_paste ();
}

int linerouting (int key)
{
  int val = -1;

/* is it a lineroutingkey */
  if (key >= keymap.lineroutbeg && key <= keymap.lineroutend)
    val = key - keymap.lineroutbeg;

/* is val in range of linrouting */
  if (val >= 0 && val <= 13)
   {
     if (p->winy != val * 2 || val == 13)
       p->winy = val * 2;
     else
       p->winy = val * 2 + 1;
     if (p->winy > ROWS)
       p->winy = ROWS;
     return 1;
   }

  return 0;
}

int csrrouting (int key)
{
  int val = -1;

/* is key a csrroutingkey */
  if (key >= keymap.csrroutbeg && key <= keymap.csrroutend)
    val = key - keymap.csrroutbeg;

/* is val in range of csrjmp */
  if (val >= 0 && val <= brl.x)
   {
     csrjmp (p->winx + val, p->winy);
     return 1;
   }

  return 0;

}

void loadkeymap ()
{
  play (snd_toggleon);
  getkeymap (sblconf, env.profname, home);
}

void soundonoff ()
{
  if (env.sound)
   {
     play (snd_toggleoff);
     env.sound = 0;
   }
  else
   {
     env.sound = 1;
     soundstat (env.sound);
     play (snd_toggleon);
   }
}

void spkline (int spk)
{
  static int y = 0;

  if (y == p->winy)
    return;
  y = p->winy;
  if (spk)
    return;
  spkwrite (spkstr);
}

void spkmod ()
{
  if (spkmode == SPKNORM)
    spkmode = SPKSPELL;
  else
    spkmode = SPKNORM;

  play (snd_toggleon);

}

void spkoff ()
{
  spkmode = SPKOFF;
  play (snd_toggleoff);
}

void spkstop ()
{
  spkwrite ("");
}
int spkcsr (int mode)
{

#define SPK_MOVE_NORM 1
#define SPK_MOVE_BS 2
#define SPK_MOVE_DEL 4
  int i, j = 0;
  char str[MAXSPKSTR];
  int move = 0;
  char ch = 0;

  static unsigned char oldstr[500] = "";
  static int x = 0, y = 0;
  mask spkattr;

  if (mode || (memcmp (oldstr, spkstr, COLS) && p->winy == p->coy)
      || p->cox != x || p->coy != y)
   {
     if (memcmp (oldstr, spkstr, COLS))
      {
	move = SPK_MOVE_NORM;
// check for char left from cursor ist deleted (backspace) 
	if (p->cox + 1 == x)

	  if (!memcmp (oldstr, spkstr, p->cox)
	      && !memcmp (oldstr + x, spkstr + p->cox, COLS - x))
	   {
	     move = SPK_MOVE_BS;
	     ch = oldstr[p->cox];
	   }

	if (x == p->cox)
	  if (!memcmp (oldstr, spkstr, x)
	      && !memcmp (oldstr + x + 1, spkstr + x, COLS - x - 1))
	   {
	     move = SPK_MOVE_DEL;
	     ch = oldstr[x];
	   }

	if (x + 1 == p->cox)
	  if (!memcmp (oldstr, spkstr, x)
	      && !memcmp (oldstr + x, spkstr + x + 1, COLS - x - 1))
	   {
	     move = SPK_MOVE_DEL;
	     ch = spkstr[x];
	   }
      }

     memcpy (oldstr, spkstr, COLS);
     x = p->cox;
     if (x < 0)
       x = 0;
     if (y != p->coy)
       move = SPK_MOVE_NORM;
     y = p->coy;
   }

  else
   {
     memcpy (oldstr, spkstr, COLS);
     return 0;
   }

  memset (str, 0, MAXSPKSTR);
  if (env.spkcharmod)
   {
//   if(move) sbl_log("charmod: %d\n",move);
     switch (move)
      {
      case 0:
	strncpy (str, spkstr + p->cox, 1);
	spkpunctuation (1);
	if (str[0] >= 'A' && str[0] <= 'Z')
	  frq (8);
	spkwrite (str);
	if (str[0] >= 'A' && str[0] <= 'Z')
	  frq (env.spkfrq);
	spkpunctuation (0);
	return 1;
      case SPK_MOVE_NORM:
	break;
      case SPK_MOVE_BS:
      case SPK_MOVE_DEL:
	sprintf (str, "%c\n", ch);
	spkpunctuation (1);
	if (str[0] >= 'A' && str[0] <= 'Z')
	  frq (8);
	spkwrite (str);
	if (str[0] >= 'A' && str[0] <= 'Z')
	  frq (env.spkfrq);
	spkpunctuation (0);
	return 1;
      }
   }

  if ((attrbuf[x] & env.attr1.mask) == (env.attr1.mask & env.attr1.val))
    spkattr = env.attr1;
  else if ((attrbuf[x] & env.attr2.mask) == (env.attr2.mask & env.attr2.val))
    spkattr = env.attr2;
  else if ((attrbuf[x] & env.attr3.mask) == (env.attr3.mask & env.attr3.val))
    spkattr = env.attr3;
  else if ((attrbuf[x] & env.attr4.mask) == (env.attr4.mask & env.attr4.val))
    spkattr = env.attr4;

  if (env.spkcharmod && move)
   {
     spkwrite (spkstr);
     return 1;
   }

  for (i = x; i < COLS; i++)
   {
     unsigned char ma = attrbuf[i] & spkattr.mask;
     unsigned char mv = spkattr.mask & spkattr.val;

     if (ma == mv)
      {
	str[j] = spkstr[i];
	j++;
      }
   }

  spkwrite (str);
  return 1;
}

void setmark ()
{

  jmpmark = p->winy;
  play (snd_toggleon);
}

void jmptomark ()
{

  p->winy = jmpmark;
}

void nextfrq ()
{
  spkstop ();
  if (frq (env.spkfrq + 1))
   {
     env.spkfrq++;
   }

}

void prevfrq ()
{
  spkstop ();
  if (frq (env.spkfrq - 1))
   {
     env.spkfrq--;
   }
}
void nextspd ()
{
  spkstop ();
  if (speed (env.spkspd + 1))
   {
     env.spkspd++;
   }
}

void prevspd ()
{
  spkstop ();
  if (speed (env.spkspd - 1))
   {
     env.spkspd--;
   }
}

void nextlang ()
{
  spkstop ();
  if (lang (env.spklang + 1))
   {
     env.spklang++;
     setspk ();
     getspkfilter (PROGPATH, env.profname, home, env.spklang);
   }
}

void nextvol ()
{
  spkstop ();
  if (volume (env.spkvolume + 1))
   {
     env.spkvolume++;
   }
}
void nextvoice ()
{
  spkstop ();
  if (voice (env.spkvoice + 1))
   {
     env.spkvoice++;
   }
}
void nextspec ()
{
  spkstop ();
  if (special (env.spkspec + 1))
   {
     env.spkspec++;
   }
}
void prevlang ()
{

  spkstop ();
  if (env.spklang > 0)
    if (lang (env.spklang - 1))
     {
       env.spklang--;
       setspk ();
       getspkfilter (PROGPATH, env.profname, home, env.spklang);
     }
}

void prevvol ()
{

  spkstop ();
  if (env.spkvolume > 0)
    if (volume (env.spkvolume - 1))
     {
       env.spkvolume--;
     }
}

void prevvoice ()
{

  spkstop ();
  if (env.spkvoice > 0)
    if (voice (env.spkvoice - 1))
     {
       env.spkvoice--;
     }
}

void prevspec ()
{

  spkstop ();
  if (env.spkspec > 0)
    if (special (env.spkspec - 1))
     {
       env.spkspec--;
     }
}

void spkcurln ()
{
  spkwrite (spkstr);
}

void spkscrtocsr ()
{
  char tmpstr[COLS * ROWS];

  memset (tmpstr, 0, COLS * ROWS);
  getscr ((winpos)
	  {
	  0, 0, COLS, p->coy + 1}
	  , (unsigned char *) tmpstr, SCR_TEXT);
/*  tmpstr[strlen (tmpstr) - (COLS - p->cox)] = 0; */
  spkwrite (tmpstr);
}

void spkscrfromcsr ()
{
  char tmpstr[(COLS + 1) * (ROWS + 1)];

spkstop();
spkscrfromln();
return;
  memset (tmpstr, 0, (COLS + 1) * (ROWS + 1));
  getscr ((winpos)
	  {
	  0, 0, COLS, ROWS}
	  , (unsigned char *) tmpstr, SCR_TEXT);
  spkwrite (tmpstr + (p->coy * COLS) + p->cox);
}

void spkscrfromln ()
{
  char tmpstr[(COLS + 1) * (ROWS + 1)];
  int i=0;

  memset (tmpstr, 0, (COLS + 1) * (ROWS + 1));
  getscr ((winpos)
	  {
	  0, 0, COLS, ROWS-1}
	  , (unsigned char *) tmpstr, SCR_TEXT);
  spkwrite (tmpstr + (p->winy * COLS));
}

void spkcharmod ()
{
  if (env.spkcharmod)
   {
     play (snd_toggleoff);
     env.spkcharmod = 0;
   }
  else
   {
     play (snd_toggleon);
     env.spkcharmod = 1;
   }
}

void spktocsr ()
{

  char str[MAXSPKSTR];

  memset (str, 0, MAXSPKSTR);
  memcpy (str, spkstr, p->cox);
  spkwrite (str);
}

void spkfromcsr ()
{
  char str[MAXSPKSTR];

  memset (str, 0, MAXSPKSTR);
  memcpy (str, spkstr + p->cox, (COLS - p->cox));
  spkwrite (str);
}

void setspk ()
{
  static int nr = -1;

  sbl_log ("setspk\n");
  spkstop ();
  if (nr != env.spklang)
   {
     nr = env.spklang;
     sbl_log ("lang changed to %d\n", nr);
     lang (env.spklang);
   }

/* use voice and volume in this order
 * with some synths voice will overwrite the volume setting
 */
  voice (env.spkvoice);
  volume (env.spkvolume);
  spkmode = env.spkmod;
  speed (env.spkspd);
  frq (env.spkfrq);
  special (env.spkspec);
  sbl_log ("finished setspk\n");
}

int spkchar ()
{
  char tmp[10] = "";
  static int pos = 0, ch = 0;

  if (pos == (POSX) && spkstr[pos] == ch)
   {
     sbl_log ("speak true\n");
     return 1;
   }
  pos = (POSX);
  sbl_log ("speak: %d\n", pos);
  tmp[0] = spkstr[pos - 1];
  tmp[1] = '\n';
  tmp[2] = 0;
  spkwrite (tmp);

  return 0;
}
