char *connv = "OS-9 Connect Command, 5A(06) 9 Oct 92";

/*  C K 9 C O N  --  Dumb terminal connection to remote system, for osk  */
/*
 Modified from ckucon.c by Bob Larson (blarson@ecla.usc.edu)
 Edition: 5A(01)
    by Chris Hemsing ,Aachen,   W Germany (chris@lfm.rwth-aachen.de):
    More efficient using sigmask, added character set translation
 Edition: 5A(02)
 07/25/91 Chris  Hemsing        minor bug fixes, changes for gnu (ansi) C
                                flow control on both sides
 Edition: 5A(03)
 03/04/92 Chris Hemsing		Kanji bug fix
 Edition: 5A(04)
 08/20/92 Chris Hemsing		flow control bug fix on return from local shell
 Edition: 5A(05)
 10/01/92 Chris Hemsing		added sending xon via escape character
 Edition: 5A(06)
 10/09/92 Chris Hemsing		escape back to local even on receive burst

  Author: Frank da Cruz (fdc@columbia.edu, FDCCU@CUVMA.BITNET),
  Columbia University Center for Computing Activities, January 1985.
  Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New
  York.  Permission is granted to any individual or institution to use this
  software as long as it is not sold for profit.  This copyright notice must be
  retained.  This software may not be included in commercial products without
  written permission of Columbia University.
*/

#include "ckcdeb.h"
#include "ckcker.h"
#include "ckcasc.h"
#ifndef NOCSETS
#include "ckcxla.h"                     /* Character set translation */
#endif /* NOCSETS */
#include <sgstat.h>     /* Set/Get tty modes */


extern int local, speed, escape, duplex, parity, flow, seslog, mdmtyp;
extern int errno, cmask, fmask, sosi, cmdmsk;
extern char ttname[], sesfil[];
extern struct csinfo fcsinfo[];

static int active;                  /* Variables global to this module */
static char *chstr();

#define LBUFL 200                   /* Line buffer */
CHAR lbuf[LBUFL];

/*  C O N E C T  --  Perform terminal connection  */

#ifndef NOCSETS
extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(); /* Character set xlate */
extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(); /* functions. */
extern int language;            /* Current language. */
extern struct langinfo langs[]; /* Language info. */
extern int tcsr, tcsl;          /* Terminal character sets, remote & local.*/
static int langsv;              /* Remember language */
static int tcs;                 /* Intermediate (xfer) char set */
static CHAR (*sxo)();           /* Local translation functions */
static CHAR (*rxo)();           /* for output (sending) terminal chars */
static CHAR (*sxi)();           /* and for input (receiving) terminal chars.*/
static CHAR (*rxi)();
#endif /* NOCSETS */

int shift = 0;                  /* SO/SI shift state */

static struct sgbuf opt;    /* sgtty info... */

conect() {
    register int c;               /* c is a character, but must be signed
                                   integer to pass thru -1, which is the
                                   modem disconnection signal, and is
                                   different from the character 0377 */
    register int i;
    register int csave;           /* Another copy   of c */
    char errmsg[50], *erp;
    int n,we_have_data;
    extern int ttypn;
VOID
doesc();
        if (!local) {
            printf("Sorry, you must 'set line' first\n");
            return(-2);
        }
        if (speed < 0) {
            printf("Sorry, you must 'set speed' first\n");
            return(-2);
        }
        if ((escape < 0) || (escape > 0177)) {
            printf("Your escape character is not ASCII - %d\n",escape);
            return(-2);
        }
        if (ttopen(ttname,&local,mdmtyp,0) < 0) {
            erp = errmsg;
            sprintf(erp,"Sorry, can't open %s",ttname);
            perror(errmsg);
            return(-2);
        }
        printf("Connecting thru %s, speed %d.\n",ttname,speed);
        printf("The escape character is %s (%d).\n",chstr(escape),escape);
        printf("Type the escape character followed by C to get back,\n");
        printf("or followed by ? to see other options.\n");
        if (seslog) printf("(Session logged to %s.)\n",sesfil);

/* Condition console terminal and communication line */

        if (conbin(escape) < 0) {
            printf("Sorry, can't condition console terminal\n");
            return(-2);
        }
        if (flow==1) { /*if xon/xoff you should have it running on both*/
            if (_gs_opt(0,&opt) <0)  /* Structure for restoring */
            {
              printf("Sorry, can't condition console terminal\n");
              return(-2);
            }
            opt.sg_xon = 0x11;
            opt.sg_xoff = 0x13;
            _ss_opt(0,&opt);
            _ss_opt(1,&opt);            /* set new modes . */
        }
        if (ttvt(speed,flow) < 0) {
            conres();
            printf("Sorry, Can't condition communication line\n");
            return(-2);
        }

#ifndef NOCSETS
/* Set up character set translations */

#ifdef KANJI
/* Kanji not supported yet */
    if (fcsinfo[tcsr].alphabet == AL_JAPAN ||
	fcsinfo[tcsl].alphabet == AL_JAPAN ) {
	tcs = TC_TRANSP;
    } else
#endif /* KANJI */
#ifdef CYRILLIC
      if (fcsinfo[tcsl].alphabet == AL_CYRIL) {
	  tcs = TC_CYRILL;
      } else
#endif /* CYRILLIC */
/* Set up character set translations */
	tcs = TC_1LATIN;

    if (tcsr == tcsl) {			/* Remote and local sets the same? */
	sxo = rxo = NULL;		/* If so, no translation. */
	sxi = rxi = NULL;
    } else {				/* Otherwise, set up */
	sxo = xls[tcs][tcsl];		/* translation function */
	rxo = xlr[tcs][tcsr];		/* pointers for output functions */
	sxi = xls[tcs][tcsr];		/* and for input functions. */
	rxi = xlr[tcs][tcsl];
    }
/*
  This is to prevent use of zmstuff() and zdstuff() by translation functions.
  They only work with disk i/o, not with communication i/o.  Luckily Russian
  translation functions don't do any stuffing...
*/
    langsv = language;
#ifndef NOCYRIL
    if (language != L_RUSSIAN)
#endif /* NOCYRIL */
      language = L_USASCII;
#endif /* NOCSETS */

        shift = 0;                  /* Initial shift state. */
/*
  Main loop. The treatment of the 8th bit of keyboard characters
  is governed by SET COMMAND BYTESIZE (cmdmsk).  The treatment of the 8th bit
  of characters sent to the remote is governed by SET TERMINAL BYTESIZE
  (cmask).   This distinction was introduced in edit C-Kermit 5A(164).
*/
        active = 1;
        while (active)
        {
          sigmask(1);                /* increment signal mask, signals must */
          _ss_ssig(0, SIGARB);       /* be masked between _ss_sig and sleep*/
          _ss_ssig(ttypn, SIGARB);
          sleep(0);
          _ss_rel(0, SIGARB);
          _ss_rel(ttypn, SIGARB);
          we_have_data = 1;
          while(we_have_data) /* loop while data on keybord or remote port*/
          {                   /* do check console to get characters through */
            we_have_data = 0; /* even if communication line receives a burst*/
            if(_gs_rdy(0)>0)
            {
              we_have_data = 1;
              c = coninc(0) & cmdmsk;       /* Get character from keyboard */
              csave = c;
              if ((c & 0177) == escape)
              { /* Look for escape char */
                c = coninc(0) & 0177;   /* Got esc, get its arg */
                doesc(c);               /* And process it */
                if (active == 0) break; /* immediately leave we_have_data
                                           loop to avoid burst receive */
              }
              else
              {             /* Ordinary character */
#ifndef NOCSETS
                /* Translate character sets */
                if (sxo) c = (*sxo)(c); /* From local to intermediate. */
                if (rxo) c = (*rxo)(c); /* From intermediate to remote. */
#endif /* NOCSETS */
/*
 If Shift-In/Shift-Out selected and we have a 7-bit connection,
 handle shifting here.
*/
                if (sosi)        /* Shift-In/Out selected? */
                {
                    if (cmask == 0177)  /*  In 7-bit environment? */
                    {
                        if (c & 0200)            /* 8-bit character? */
                        {
                            if (shift == 0)      /* If not shifted, */
                            {
                                ttoc(dopar(SO)); /* shift. */
                                shift = 1;
                            }
                        }
                        else
                        {
                            if (shift == 1)      /* 7-bit character */
                            {
                                ttoc(dopar(SI)); /* If shifted, */
                                shift = 0;       /* unshift. */
                            }
                        }
                    }
                    if (c == SO) shift = 1; /* User typed SO */
                    if (c == SI) shift = 0; /* User typed SI */
                }
                c &= cmask;         /* Apply Kermit-to-host mask now. */
                if (ttoc(dopar(c)) > -1)
                {
                  if (duplex)
                  {         /* Half duplex? */
                    conoc(csave);       /* Yes, also echo it. */
                    if (seslog)     /* And maybe log it. */
                    if (zchout(ZSFILE,c) < 0) seslog = 0;
                  }
                }
                else
                {
                  perror("\r\lCan't send character");
                  active = 0;
                }
              } /* end if ((c & 0177) == escape) */
            } /* end if(_gs_rdy(0)>0) */
            if ((n = ttchk()) > 0)
            {       /* Any more left in buffer? */
              we_have_data = 1;
              if (n > LBUFL) n = LBUFL;   /* Get them all at once. */
              if ((n = ttxin(n,lbuf)) > 0)
              {
                if (sosi) /* only one character at a time */
                {
                    for (i = 0; i < n; i++)
                    {
                        c = lbuf[i] & cmask;
                        if (c == SO)
                        {
                            shift = 1;
                            continue;
                        }
                        else if (c ==   SI)
                        {
                            shift = 0;
                            continue;
                        }
                        if (shift)
                          c = (c | 0200);
#ifndef NOCSETS
                        /* Translate character sets */
                        if (sxi) c = (*sxi)(c);
                        if (rxi) c = (*rxi)(c);
#endif /* NOCSETS */
                        c &= cmdmsk; /* Apply command mask. */
                        conoc(c);    /* Output to screen */
                        if (seslog) zchout(ZSFILE,c);      /* Log */
                    }
                }
                else    /* All at once */
                {
                    for (i = 0; i < n; i++)
                    {
                        c = lbuf[i] & cmask;
#ifndef NOCSETS
                        /* Translate character sets */
                        if (sxi) c = (*sxi)(c);
                        if (rxi) c = (*rxi)(c);
#endif /* NOCSETS */
                        lbuf[i] = c & cmdmsk; /* Replace in buffer. */
                        if (seslog) zchout(ZSFILE,c);      /* Log */
                    }
                    conxo(n,(char *)lbuf); /* Output whole buffer at once */
                } /* end SI/SO or not */
              }  /* end successful read on comm line */
            }  /* end data on communications line */
          }  /* end while(we_have_data) */
        }  /* end while(active) */
        conres();                       /* Reset the console. */
        printf("[Back at Local System]\n");
#ifndef NOCSETS
        language = langsv;          /* Restore language */
#endif /* NOCSETS */
        return(1);
}


/*  H C O N N E  --  Give help message for connect.  */

hconne() {
    int c;
    static char *hlpmsg[] = {"\
\r\lC to close the connection, or:\r",
"  0 (zero) to send a null\r",
"  B to send a BREAK\r",
"  H to hangup and close connection\r",
"  S for status\r",
"  X to send an XON\r",
"  ! to push to local shell\r",
"  ? for help\r",
" escape character twice to send the escape character.\r\l\r\l\r",
"" };

    conola(hlpmsg);                     /* Print the help message. */
    conol("Command>");                  /* Prompt for command. */
    c = coninc(0) & 0177;               /* Get character, strip any parity. */
    conoc(c);                           /* Echo it. */
    conoll("");
    return(c);                          /* Return it. */
}


/*  C H S T R  --  Make a printable string out of a character  */

static char *
chstr(c) int c; {
    static char s[8];

    if (c < SP) sprintf(s,"CTRL-%c",ctl(c));
    else sprintf(s,"'%c'\n",c);
    return(s);
}


/*  D O E S C  --  Process an escape character argument  */
VOID
doesc(c) char c; {
    CHAR d;
    CHAR temp[50];

    while (1) {
        if (c == escape) {              /* Send escape character */
            d = dopar(c); ttoc(d); return;
        } else                          /* Or else look it up below. */
            if (isupper(c)) c = tolower(c);

        switch (c) {

        case 'c':                       /* Close connection */
        case '\03':
            active = 0; conol("\r\l"); return;

        case 'b':                       /* Send a BREAK signal */
        case '\02':
            if (ttsndb()<0) conol("\r\nCan't send break\r\l");
            return;

        case 'h':                       /* Hangup */
        case '\010':
            tthang(); active = 0; conol("\r\l"); return;

        case '!':
            conres();
            zshcmd("");
            if (conbin(escape) < 0) {
                printf("Error returning to remote session\n");
                active = 0;
            }
            if (flow==1)
			{ /*if xon/xoff you should have it running on both*/
              if ((_ss_opt(0,&opt) < 0)||(_ss_opt(1,&opt) < 0))
              {
                printf("Error returning to remote session\n");
                active = 0;
              }
            }
            return;

        case 's':                       /* Status */
            conol("\r\lConnected thru ");
            conol(ttname);
            if (speed >= 0) {
                sprintf((char *)temp,", speed %d",speed); conol((char *)temp);
            }
            sprintf((char *)temp,", %d bits",(cmask == 0177) ? 7 : 8);
            if (parity) {
                conol(", ");
                switch (parity) {
                    case 'e': conol("even");  break;
                    case 'o': conol("odd");   break;
                    case 's': conol("space"); break;
                    case 'm': conol("mark");  break;
                }
                conol(" parity");
            }
            if (seslog) {
                conol(", logging to "); conol(sesfil);
            }
            conoll(""); return;

        case '?':                       /* Help */
            c = hconne(); continue;

		case 'x': /* send xon */
			ttoc(dopar(XON)); return;
        case '0':                       /* Send a null */
            c = '\0'; d = dopar(c); ttoc(d); return;

        case SP:                        /* Space, ignore */
            return;

        default:                        /* Other */
            conoc(BEL); return;         /* Invalid esc arg, beep */
        }
    }
}
