/***************************************************************************
 *                                                                         *
 *   EDITFSE.C                                                             *
 *                                                                         *
 *   Copyright (c) 1988-1997 Galacticomm, Inc.  All Rights Reserved.       *
 *                                                                         *
 *   This is the Full Screen/Line Editor module for use with email & sigs. *
 *                                                                         *
 *          Modifications for 6.0 - R. A. Rose 4/6/92                      *
 *             Full Screen Editor - R. A. Rose 11/9/90                     *
 *                    Line Editor - T. Stryker & D. Arnel 7/12/88          *
 *                                                                         *
 *   Scheme:                                                               *
 *      The line editor uses nothing but status 3s, the FSE doesn't need   *
 *   status 3s.  The Status 3 handler is the Line Editors DUNEDT routine,  *
 *   all other statuses go to the FSEs dunedt routine. INJOTHs will use    *
 *   a custom routine for FSE users, a normal INJOTH for line edit users.  *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"
#include "majorbbs.h"
#include "wgsedtm.h"
#include "filexfer.h"
#include "editfse.h"

#define FILREV "$Revision: 10 $"

static INT fseret(INT whnval);
static VOID shotxt(INT cmd);
static VOID sholn(CHAR *ptr);
static VOID pfinwin(INT msgno,INT nxtst,INT abst,INT heig,INT chq,INT millim,
              CHAR *inbuf);
static VOID promptgo(INT millim,INT nxtcmd,CHAR *inbuf);
static VOID prmptend(VOID);
static VOID fsemsg(INT msgno,INT i);
static VOID parfor(CHAR *ptr);
static INT punchk(CHAR *ptr,INT eol);
static VOID joinln(CHAR *ptr,INT wrpmar,INT spcnt);
static INT movword(CHAR *from,CHAR *to,INT maxl,INT dpad);
static VOID inschr(CHAR *ptr);
static VOID chopln(CHAR *ptr);
static VOID delblk(VOID);
static VOID delpatl(CHAR *ptr,INT nchar);
static INT delaline(CHAR *ptr);
static INT insaline(CHAR *ptr);
static VOID drawbk(VOID);
static VOID center(CHAR *ptr);
static VOID expndbuf(VOID);
static LONG lolilen(CHAR *ptr);
static INT stlawo(CHAR *ptr);
static VOID comprbuf(VOID);
static VOID zerotpc(VOID);
static VOID nulbuf(VOID);
static INT gensig(VOID);
static CHAR *begword(CHAR *ptr);
static CHAR *endword(CHAR *ptr);
static VOID profchk(VOID);
static INT starline(CHAR *ptr);
static VOID fixtop(VOID);
static VOID seteotxt(VOID);
static CHAR *leftpoint(CHAR *ptr);
static INT endline(CHAR *ptr);
static INT whatln(CHAR *ptr);
static INT whatpo(CHAR *ptr);
static VOID clear(CHAR *ptr,INT len);
static VOID procansi(register INT chan,register CHAR c);
static VOID smargn(VOID);
static INT xmtcnt(INT chan,INT numbyt,CHAR *txt);
static INT fupfse(INT fupcod);
static INT fseok(VOID);
static VOID lprofchk(VOID);

struct module fseedit={            /* module interface block               */
     "",                           /*    name used to refer to this module */
     ldunedt,                      /*    user logon supplemental routine   */
     ldunedt,                      /*    input routine if selected         */
     (VOID (*)())dunedt,           /*    status-input routine if selected  */
     fsepage,                      /*    "injoth" routine for this module  */
     ldunedt,                      /*    user logoff supplemental routine  */
     NULL,                         /*    hangup (lost carrier) routine     */
     NULL,                         /*    midnight cleanup routine          */
     NULL,                         /*    delete-account routine            */
     clsedt                        /*    finish-up (sys shutdown) routine  */
};

#define CURPOS (fseptr->begstg+(fseptr->x)-1)
#define ICRPOS (fsecpt->begstg+(fsecpt->x)-1)

#define WRPLIM 72             /* Wrap point   (72 for RelayNet compat.)    */
#define MXLNSZ 79             /* Maximum line size for replace in line ed. */

#define MAXBDP 20             /* maximum box depth for injoth() handler    */

static
INT fsestt;                   /* Editor module number                      */

static
INT  newett;                  /* new sub-state returned                    */

static
INT  fsemhi,                  /* Minimum screen height for FSE             */
     dontrepo;                /* Don't reposition cursor flag              */

struct fseusr *fseusr,        /* pointer to array of users' editor data    */
              *fseoth,        /* pointer to other guy's data               */
              *fseptr,        /* pointer to current main line users data   */
              *fsecpt;        /* pointer to current fsechi users data      */

                              /* EDITOR FLAGS 1/0 (Internal)               */
#define INSTXT        1       /*   Insert         / Overtype               */
#define W4OUEM        2       /*   FSE: If set, wait for output empty      */
#define LIN1ST        2       /*   Line: is this initial topic question?   */
#define MARKDON       4       /*   Show Marked Txt/ Marked Txt is invis    */
#define CHGTPC        8       /*   changing topic line                     */
                              /*   FSE: Is there a topic to be queried for */
#define FLFLVR       16       /*   file flavor of messages in effect       */
#define LINEMO       32       /*   Using the line editor                   */
#define DIRTYS       64       /*   Screen possibly has garbage on it       */
#define SCNISCLR    128       /*   text display area is definitely clear   */
#define EDITING     256       /*   are we using either editor???           */

                              /*   flags for uplmsg()                      */
#define UPLLIN        1       /*   uploading into the line editor          */
#define UPLCLR        2       /*   clear current message before upload     */

#define CONEDT 1              /* continue editing return value             */
#define SAVEDT 0              /* end editing and save message return value */

                              /* FSECHI states                             */
#define NORMAL      0         /*      Base state, nuthin going on          */
#define ESCRCV      1         /*      Escape character in, what's next?    */
#define ANSIN       2         /*      <ESC><[>... now what?                */
#define FKEYIN      3         /*      <ESC><O>... final part of Func. Key  */
#define CTLKIN      4         /*      CTRL-K received... what now?         */
#define LINMOD      5         /*      'line oriented mode'                 */
#define TAKONE      6         /*      wait for one character               */
#define TAKPLU      7         /*      take plus sign only                  */

#define DONTUSE     0         /* CTRL-keys to be aVOIDed in fsechi()       */

                              /* FSEUSR->CMD command values                */
#define DCOTPC      1         /*      Show Topic                           */
#define DCOTOP      2         /*      Redisplay Top Line                   */
#define DCOBOT      3         /*      Redisplay Bottom Line                */
#define DCOLIN      4         /*      Redisplay current cursor line        */
#define DCOSMA      5         /*      Display Marked Text                  */
#define DCOUMA      6         /*      'Unshow' marked text                 */
#define DCOFIL      7         /*      Fill in after a window               */
#define DCOALL      8         /*      Redisplay Entire Text Area           */
#define DCOCUD      9         /*      Show text from cursor on down        */
#define DCOFKY      10        /*      Show function keys                   */
#define INIDSP      11        /*      Initial display states               */
#define INIDS2      12        /*      Continuation of initial state        */
#define SHOOPN      13        /*      Show Opening Display                 */
#define SHOOPT      14        /*      Show Opening Display with topic      */
#define UPDALL      15        /*      Update the whole works               */
#define UPDAL2      16        /*      Update All... second part            */
#define WA4CLR      17        /*      Wait for output buffer to empty      */
#define FPGUP       18        /*      Page-Up in the file                  */
#define FPGDN       19        /*      Page-Down in the file                */
#define GOEND       20        /*      Goto End of Line                     */
#define GOTOLE      21        /*      Switch to line editor                */
#define PROFIM      22        /*      Profanity in buffer message          */
#define PROFIT      23        /*      Profanity in topic                   */
#define GOTOLET     24        /*      Switch to line with topic            */
#define DELCHR      30        /*      Delete One character at cursor       */
#define CENTER      32        /*      Center a line                        */
#define INSLNC      33        /*      Insert a line after the cursor       */
#define DELLNC      34        /*      Delete the line at the cursor        */
#define CHOPLN      35        /*      Chop a line at the cursor            */
#define JOINLN      36        /*      Join cursor line and next line       */
#define ERAEOL      37        /*      Erase from cursor to EOL             */
#define DRWFRM      50        /*      Draw a frame around object           */
#define BLKDEL      51        /*      Delete the block                     */
#define PARFOR      52        /*      Reformat paragraph                   */
#define INSCHR      53        /*      Insert a character                   */
#define ASKQUT      60        /*      Ask if sure to quit                  */
#define QUITYN      61        /*      Asked, now get the response          */
#define SAVEEX      62        /*      Save and Quit                        */
#define ASKTTY      63        /*      Ask what type of terminal            */
#define GETTTY      64        /*      Process the terminal type            */
#define ASKTPC      65        /*      Ask for the topic                    */
#define PROTPC      66        /*      Return the topic                     */
#define ASKMNO      67        /*      Ask for import message #             */
#define GETMNO      68        /*      Process the message #                */
#define NOIMPO      69        /*      Rebuff, can't import that message    */
#define SHOHLP      70        /*      Show the Help Screen                 */
#define SXTNDH      71        /*      Extended Help Screen 1               */
#define SXTND2      72        /*      Extended Help Screen 2               */
#define SXTND3      73        /*      Extended Help Screen 3               */
#define SXTND4      74        /*      Extended Help Screen 4               */
#define SXTND5      75        /*      Extended Help Screen 5               */
#define PAUREP      77        /*      Message Up, wait for any key         */
#define EXITOM      78        /*      Exit the editor to mainline now      */
#define UPLOAD      79        /*      Ask for confirmation of upload       */
#define UPLFIL      80        /*      Upload file into editor              */
#define BIGFIL      81        /*      File uploaded is bigger than buffer  */
#define BIGFIL2     82        /*      File uploaded is bigger than buffer  */

static                        /* output buffer space needed, by CMD value  */
UINT obaneed[]={5,
   350, 150, 150, 150,1840,1840,1600,1840,1840,   0,  /*  1-10 */
   400,1850, 600, 600, 600,1640,   0,1840,1840,   1,  /* 11-20 */
     0, 400,   0,   0,   0,   0,   0,   0,   0, 150,  /* 21-30 */
     0, 150,1840,1840,1840,1840, 150,   0,   0,   0,  /* 31-40 */
     0,   0,   0,   0,   0,   0,   0,   0,   0,1840,  /* 41-50 */
  1840,1840, 100,   0,   0,   0,   0,   0,   0, 500,  /* 51-60 */
  1800, 600, 500, 700, 600,1000, 500,1840, 500,1550,  /* 61-70 */
  1790,1790,1790,1790,1790,   0,1790,   0,   0,   0}; /* 71-80 */

static
HMCVFILE edtmb,               /* pointer to editor message block           */
         edfmb,               /* pointer to file description editor msg blk*/
         savmb;               /* msg block pointer saved on editor entry   */

#define NOTERMT 2
static                        /* Number of Function Keys per Terminal (mx8)*/
INT  noffkey[]={8,8};
static                        /* Prefix values for Function Keys           */
CHAR fktrig[]={0x06,'O'};
static                        /* Key values for Function Keys              */
CHAR fkvals[][8]={{0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38}, /* Ctrl Keys  */
                  {0x50,0x51,0x77,0x78,0x74,0x75,0x71,0x72}  /* VT102      */
};
static CHAR *fklegs[][16]={
#ifdef UNIX
/* Control */  {"^X","LINEDT","^G"," SAVE ","^C"," QUIT ","^T"," TOPIC",
#else
/* Control */  {"^X","LINEDT","^G"," SAVE ","^O"," QUIT ","^T"," TOPIC",
#endif // UNIX
                "^R"," HELP ","^U"," PgUp ","^D"," PgDn ","^Z","CONFIG"},
/* VT-102  */  {"F1","IMPORT","F2"," SAVE ","F3"," QUIT ","F4"," TOPIC",
                "F5"," HELP ","F6"," PgUp ","F7"," PgDn ","F8","CONFIG"}
};

static
INT  fkcmds[][8]={
     {GOTOLE,SAVEEX,ASKQUT,ASKTPC,SHOHLP,  FPGUP,  FPGDN,ASKTTY},
     {ASKMNO,SAVEEX,ASKQUT,ASKTPC,SHOHLP,  FPGUP,  FPGDN,ASKTTY}
};

#include "edittab.h"

static VOID (*oldhang)(VOID);      /* old hangup vector                    */

VOID EXPORT
init__wgsfse(VOID)             /* Initialize the Full Screen and line editors*/
{
     stzcpy(fseedit.descrp,gmdnam("wgsfse.mdf"),MNMSIZ);
     fsestt=register_module(&fseedit);
     fseusr=(struct fseusr *)alczer(nterms*sizeof(struct fseusr));
     edfmb=opnmsg("wgsedtf.mcv");
     edtmb=opnmsg("wgsedtm.mcv");
     fsemhi=numopt(FSEMHI,1,255);
     bgnedt=fse_bgnedt;
     edtimr=fse_edtimr;
     edtpfn=fse_edtpfn;
     inedit=fse_inedit;
     oldhang=hangups;
     hangups=fsehup;
}

VOID EXPORT
initwc__wgsfse(VOID)
{
     init__wgsfse();
}

VOID
clsedt(VOID)                       /* close editor files for shutdown      */
{
     clsmsg(edfmb);
     clsmsg(edtmb);
}

VOID
fse_edtimr(imradr)            /* set import routine address for curr user  */
GBOOL (*imradr)();
{
     fseusr[usrnum].imradr=(INT (*)())imradr;
}

VOID
fse_edtpfn(                        /* set user's profanity level           */
INT pfnlvl)
{
     fseusr[usrnum].pfnlvl=pfnlvl;
}

INT
fse_inedit(usn,exipnt)             /* is this user editing a msg right now?*/
INT usn;                           /* user number to check for             */
SHORT (*exipnt)(SHORT);            /* and is he returning to *here*?       */
{
     if (usroff(usn)->state == fsestt && fseusr[usn].exitro == exipnt) {
          return(1);
     }
     return(0);
}

INT
fse_bgnedt(siz,buf,tsiz,topic,whndun,flags) /* Start Editor                */
INT siz;                           /* Max size of text                     */
CHAR *buf;                         /* Buffer for text                      */
INT tsiz;                          /* Max size of topic                    */
CHAR *topic;                       /* Buffer for topic (NULL for none)     */
SHORT (*whndun)(SHORT);            /* ptr to exit/quit routine             */
INT flags;                         /* config flags                         */
{
     INT lcnt;
     CHAR *cp;

     fseptr=&(fseusr[usrnum]);
     if (usaptr->scnfse < 20) {
          usaptr->scnfse=20;
     }
     fseptr->scnlen=usaptr->scnfse;
     fseptr->rflags=flags;
     fseptr->exitro=whndun;
     fseptr->pfnlvl=pfceil;
     if (*buf != '\0') {
          for (lcnt=0,cp=buf ; *cp != '\0' ; cp++) {
               if (*cp == '\r') {
                    lcnt=0;
               }
               else if (*cp == '\n' || lcnt == MXLNSZ) {
                    if (*cp != '\n' && strlen(buf)+1 < siz) {
                         movmem(cp,cp+1,strlen(cp)+1);
                    }
                    *cp='\r';
                    lcnt=0;
               }
               else {
                    lcnt++;
               }
          }
     }
     if ((fseptr->rflags&ED_LINEMO)
         || !(usaptr->ansifl&ANSON) || (fseptr->scnlen < fsemhi)
         || (fseptr->signat == gensig() && (fseptr->flags&LINEMO))
         || (usaptr->usrprf&PRFLIN)) {
          stline(siz,buf,tsiz,topic);
     }
     else {
          stfse(siz,buf,tsiz,topic);
     }
     cncall();
     return(CONEDT);
}

INT
stfse(siz,buf,tsiz,topic)          /* Start the Full Screen Editor         */
INT siz,tsiz;
CHAR *buf,*topic;
{
     INT ctpc;
     CHAR *strtmp;

     ctpc=0;
     usrptr->state=fsestt;
     fseptr=&(fseusr[usrnum]);
     fseptr->flags=0;
     fseptr->topic=topic;
     if (fseptr->rflags&ED_FILESD) {
          fseptr->flags|=FLFLVR;
     }
     fseptr->flags|=EDITING;
     if (topic == NULL) {
          fseptr->tpcsiz=1;
     }
     else {
          fseptr->tpcsiz=tsiz-1;
     }
     fseptr->txtbuf=buf;
     fseptr->txtsiz=((siz-1)/80)*80;
     fseptr->endbuf=buf+fseptr->txtsiz;
     fseptr->imradr=NULL;
     fseptr->topscr=fseptr->txtbuf;
     fseptr->begstg=fseptr->txtbuf;
     fseptr->mkstart=NULL;
     fseptr->mkend=NULL;
     fseptr->x=1;
     fseptr->y=1;
     fseptr->substt=NORMAL;
     fseptr->curlin=20;
     fseptr->scnlen=usaptr->scnfse;
     clear(fseptr->tmpbuf,80);
     if (fseptr->rflags&ED_CLRTXT) {
          clear(fseptr->txtbuf,fseptr->txtsiz);
     }
     else {
          expndbuf();
     }
     if (fseptr->topic != NULL) {
          if (fseptr->rflags&ED_CLRTOP) {
               clear(fseptr->topic,fseptr->tpcsiz);
               morcnc();
               strtmp=cncall();
               if (strlen(strtmp) > 0) {
                    strcpy(fseptr->topic,strtmp);
                    ctpc=1;
                    fixtop();
                    seteotxt();
               }
          }
          else {
               fixtop();
          }
     }
     fseptr->cmd=WA4CLR;
     fseptr->stacnt=1;
     btuinj(usrnum,FSESTS);
     if (fseptr->topic != NULL && (fseptr->rflags&ED_CLRTOP) && ctpc == 0) {
          fseptr->flags|=CHGTPC;
     }
     else {
          fseptr->flags&=~CHGTPC;
     }
     if (!(fseptr->rflags&ED_CLRTXT) ||
         fseptr->txtsiz < (fseptr->scnlen-2)*80) {
          fseptr->flags|=DIRTYS;
     }
     else {
          fseptr->flags&=~DIRTYS;
     }
     fseptr->flags|=W4OUEM;             /* Make sure buffer empties        */
     clrprf();
     prf("\33[2J%c[0;1;32m",0x14);    /* Take care of system outprf      */
     outprf(usrnum);
     prf("");
     return(CONEDT);
}

INT
stline(siz,buf,tsiz,topic)         /* Start the line editor                */
INT siz,tsiz;
CHAR *buf,*topic;
{
     usrptr->state=fsestt;
     fseptr=&(fseusr[usrnum]);
     strtov(siz,buf,tsiz,topic);
     endcnc();
     ldunedt();
     return(CONEDT);
}

INT                                /* 1=done, 0=not done                   */
dunedt(VOID)                       /* Continue Editing Process             */
{
     INT i;
     LONG lonum;
     INT (*temp)();

     if (status != FSESTS) {
          if (status == OUTMT) {
               btuoes(usrnum,0);
          }
          return(1);
     }
     savmb=curmbk;
     fseptr=&(fseusr[usrnum]);
     if (!(fseptr->flags&EDITING)) {
          return(SAVEDT);
     }
     if (fseptr->flags&LINEMO) {        /* just switched to line editor    */
          return(CONEDT);               /* and FSESTS's were queued        */
     }
     setmbk(edtmb);

     dontrepo=0;
     fseptr->stacnt--;                            /* Yes, we're doing CRSTG*/
     if (fseptr->flags&W4OUEM) {                  /* Wait for empty        */
          if (btuoba(usrnum) < outbsz-1) {
               rststf();
               fseptr->stacnt++;
               btuinj(usrnum,FSESTS);
               actdet=0;
               return(CONEDT);
          }
          fseptr->flags&=~W4OUEM;
     }
     if (btuoba(usrnum) < obaneed[fseptr->cmd]) { /* Not enough room, cycle*/
          rststf();
          fseptr->stacnt++;
          btuinj(usrnum,FSESTS);
          actdet=0;
          return(CONEDT);
     }
     if (fseptr->cmd <= 10) {
          shotxt(fseptr->cmd);
          fseptr->cmd=0;
     }
     switch (fseptr->cmd) {
     case 0:
          break;
     case UPLOAD:
          pfinwin(FSEUPL,UPLFIL,0,8,0,1,fseptr->tmpbuf);
          break;
     case SHOHLP:
          pfinwin(FSEHLP2,PAUREP,PAUREP,17,0,0,fseptr->tmpbuf);
          break;
     case SXTNDH:
          pfinwin(EXTNDH,SXTND2,PAUREP,20,0,1,fseptr->tmpbuf);
          break;
     case SXTND2:
          pfinwin(EXTND2,SXTND3,PAUREP,20,1,1,fseptr->tmpbuf);
          break;
     case SXTND3:
          pfinwin(EXTND3,SXTND4,PAUREP,20,1,1,fseptr->tmpbuf);
          break;
     case SXTND4:
          pfinwin(EXTND4A,SXTND5,PAUREP,20,1,1,fseptr->tmpbuf);
          break;
     case SXTND5:
          pfinwin(EXTND5,PAUREP,PAUREP,20,1,1,fseptr->tmpbuf);
          break;
     case WA4CLR:                            /* wait for output to clear   */
          if (btuoba(usrnum) == outbsz-1) {
               btupbc(usrnum,0);
               btutsw(usrnum,0);
               btuxnf(usrnum,0,0);
               btuchi(usrnum,fsechi);
               btutru(usrnum,0);
               btucli(usrnum);
               fseptr->ech2go=255;
               btuche(usrnum,1);
               btuech(usrnum,0);
               fseptr->cmd=INIDSP;
          }
          else {
               fseptr->cmd=WA4CLR;
               actdet=0;
          }
          break;
     case INIDSP:
          clrprf();
          prfmsg(FSEHDR);
          prf("\33[?7l\33[2J\33[1;1f\33[1;%dr",fseptr->scnlen);
          prf("\n\33[0;1;32m\33[1;1f\33[1;%dr",fseptr->scnlen-2);
          outprf(usrnum);
          fseptr->cmd=INIDS2;
          break;
     case INIDS2:
          dontrepo=1;
          if (fseptr->flags&DIRTYS) {
               fseptr->flags|=SCNISCLR;
               shotxt(DCOALL);                        /* Show everything    */
          }
          i=gensig();
          if (fseptr->signat != i) {
               fseptr->signat=i;
               fseptr->cmd=SHOOPN;
               fseptr->termtyp=0;
          }
          else {
               fseptr->cmd=0;
          }
          shotxt(DCOFKY);                    /* Show function keys         */
          dontrepo=0;
          if (fseptr->flags&CHGTPC) {
               fseptr->cmd=SHOOPT;
               fseptr->flags&=~CHGTPC;
          }
          else {
               shotxt(DCOTPC);
          }
          break;
     case SHOOPN:
          pfinwin(FSEOPN1,PAUREP,PAUREP,4,0,0,fseptr->tmpbuf);
          break;
     case SHOOPT:
          if (fseptr->flags&FLFLVR) {
               pfinwin(FSEOPFN,PROTPC,PAUREP,5,0,50,fseptr->tmpbuf);
          }
          else {
               pfinwin(FSEOP21,PROTPC,PAUREP,5,0,50,fseptr->tmpbuf);
          }
          break;
     case PROFIM:
          pfinwin(FSEPRO,PAUREP,PAUREP,8,0,0,fseptr->tmpbuf);
          break;
     case PROFIT:
          pfinwin(FSEPRT,PAUREP,PAUREP,8,0,0,fseptr->tmpbuf);
          break;
     case NOIMPO:
          pfinwin(FSENIM,PAUREP,PAUREP,4,0,0,fseptr->tmpbuf);
          break;
     case ASKMNO:
          if (*(fseptr->imradr) != NULL) {
               pfinwin(FSEGMNM,GETMNO,PAUREP,3,0,10,fseptr->tmpbuf);
          }
          else {
               pfinwin(FSEIMR,PAUREP,PAUREP,4,0,0,fseptr->tmpbuf);
          }
          break;
     case ASKTTY:
          pfinwin(FSETTY,GETTTY,0,7,0,2,fseptr->tmpbuf);
          break;
     case ASKQUT:
          pfinwin(FSEQYN,QUITYN,0,4,0,3,fseptr->tmpbuf);
          break;
     case ASKTPC:
          if (fseptr->topic != NULL) {
               if (fseptr->rflags&ED_FIXTOP) {
                    pfinwin(FIXTOP,PAUREP,PAUREP,8,0,0,fseptr->tmpbuf);
               }
               else {
                    clear(fseptr->tmpbuf,80);
                    pfinwin(FSETPC,PROTPC,0,4,0,50,fseptr->tmpbuf);
               }
          }
          else {
               fseptr->cmd=0;
          }
          break;
     case QUITYN:
          if (lingyn(fseptr->tmpbuf[0]) == 'Y') {
               prf("\33[1;%dr",fseptr->scnlen);
               prf("\33[?6l");
               prf("\33[?7h\33[1;1H\33[2J");
               prfmsg(FSETRL);
               outprf(usrnum);
               comprbuf();
               if (fseptr->topic != NULL) {
                    zerotpc();
               }
               echon();
               btumil(usrnum,0);
               btuche(usrnum,0);
               btuchi(usrnum,NULL);
               btutru(usrnum,15);
               rststf();
               rstrxf();
               btutsw(usrnum,usaptr->scnwid);
               clrinp();
               return(fseret(ED_QUITEX));
          }
          prmptend();
          shotxt(DCOFIL);
          fseptr->cmd=0;
          break;
     case UPLFIL:
          switch (toupper(fseptr->tmpbuf[0])) {
          case '1':
          case '2':
               prf("\33[1;%dr",fseptr->scnlen);
               prf("\33[?6l");
               prf("\33[?7h\33[1;1H\33[2J");
               prfmsg(FSETRL);
               outprf(usrnum);
               echon();
               btumil(usrnum,0);
               btuche(usrnum,0);
               btuchi(usrnum,NULL);
               btutru(usrnum,15);
               rstrxf();
               btutsw(usrnum,usaptr->scnwid);
               clrinp();
               fseptr->substt=usrptr->substt;
               fileup("your file","?",fupfse);
               outprf(usrnum);
               return(CONEDT);
          default:
               prmptend();
               shotxt(DCOFIL);
               fseptr->cmd=0;
          }
          break;
     case GOTOLE:
          fseptr->rflags&=~ED_CLRTOP;
     case GOTOLET:
          fseptr->rflags&=~ED_CLRTXT;
          seteotxt();
          profchk();
          if (fseptr->cmd == 0) {
               btuche(usrnum,0);
               btuchi(usrnum,NULL);
               btutru(usrnum,15);
               prf("\33[1;%dr\33[?7h",fseptr->scnlen);
               prf("\33[?6l");
               outprf(usrnum);
               comprbuf();
               if (fseptr->topic != NULL) {
                    zerotpc();
               }
               pfinwin(FSE2LE,0,0,3,0,0,fseptr->tmpbuf);
               prfmsg(FSETRL);
               outprf(usrnum);
               echon();
               btumil(usrnum,0);
               rststf();
               rstrxf();
               btutsw(usrnum,usaptr->scnwid);
               temp=fseptr->imradr;
               stline(fseptr->txtsiz+1,fseptr->txtbuf,
                          fseptr->tpcsiz+1,fseptr->topic);
               fseptr->imradr=temp;
               return(CONEDT);
          }
          break;
     case SAVEEX:
          seteotxt();
          profchk();
          if (fseptr->cmd == 0) {
               btuche(usrnum,0);
               btuchi(usrnum,NULL);
               btutru(usrnum,15);
               prf("\33[1;%dr\33[?7h",fseptr->scnlen);
               prf("\33[?6l");
               comprbuf();
               if (fseptr->topic != NULL) {
                    zerotpc();
               }
               pfinwin(FSEBYE,0,0,3,0,0,fseptr->tmpbuf);
               prfmsg(FSETRL);
               outprf(usrnum);
               echon();
               btumil(usrnum,0);
               rststf();
               rstrxf();
               btutsw(usrnum,usaptr->scnwid);
               return(fseret(0));
          }
          break;
     case FPGUP:
          if (fseptr->topscr-fseptr->txtbuf > 800) {
               fseptr->topscr-=800;
          }
          else {
               fseptr->topscr=fseptr->txtbuf;
          }
          shotxt(DCOALL);
          fseptr->cmd=0;
          break;
     case FPGDN:
          fseptr->topscr+=800;
          if (fseptr->topscr > (fseptr->endbuf-((fseptr->scnlen-2)*80))) {
               fseptr->topscr=fseptr->endbuf-((fseptr->scnlen-2)*80);
          }
          shotxt(DCOALL);
          fseptr->cmd=0;
          break;
     case GOEND:
          fseptr->x=1+endline(fseptr->begstg);
          prf("\33[%d;%df",fseptr->y,fseptr->x);
          outprf(usrnum);
          fseptr->cmd=0;
          break;
     case UPDALL:
          clrprf();
          prfmsg(FSEHDR);
          prf("\33[?7l");
          prf("\33[1;1f\33[1;%dr",fseptr->scnlen);
          prf("\33[2J\n");
          outprf(usrnum);
          dontrepo=1;
          shotxt(DCOTPC);
          shotxt(DCOFKY);
          prf("\33[1;1f\33[1;%dr",fseptr->scnlen-2);
          outprf(usrnum);
          fseptr->cmd=UPDAL2;
          break;
     case UPDAL2:
          fseptr->flags|=SCNISCLR;
          shotxt(DCOALL);
          fseptr->cmd=0;
          break;
     case BIGFIL:
          clrprf();
          prfmsg(FSEHDR);
          prf("\33[?7l");
          prf("\33[1;1f\33[1;%dr",fseptr->scnlen);
          prf("\33[2J\n");
          outprf(usrnum);
          dontrepo=1;
          shotxt(DCOTPC);
          shotxt(DCOFKY);
          prf("\33[1;1f\33[1;%dr",fseptr->scnlen-2);
          outprf(usrnum);
          fseptr->cmd=BIGFIL2;
          break;
     case BIGFIL2:
          fseptr->flags|=SCNISCLR;
          shotxt(DCOALL);
          pfinwin(BIGFIL3,PAUREP,PAUREP,5,0,0,fseptr->tmpbuf);
          fseptr->cmd=0;
          break;
     case PAUREP:
          shotxt(DCOFIL);
          prmptend();
          fseptr->cmd=0;
          break;
     case GETTTY:
          nulbuf();
          i=atoi(fseptr->tmpbuf)-1;
          if ((i < NOTERMT) && (i >= 0)) {
               fseptr->termtyp=i;
          }
          dontrepo=1;
          shotxt(DCOFIL);
          dontrepo=0;
          shotxt(DCOFKY);
          prmptend();
          fseptr->cmd=0;
          break;
     case GETMNO:
          nulbuf();
          lonum=atol(fseptr->tmpbuf);
          if (lonum != 0) {
               if ((*(fseptr->imradr))(lonum)) {
                    expndbuf();
                    shotxt(DCOALL);
                    shotxt(DCOTPC);
                    fseptr->cmd=0;
               }
               else {
                    shotxt(DCOFIL);
                    fseptr->cmd=NOIMPO;
               }
          }
          else {
               shotxt(DCOFIL);
               fseptr->cmd=0;
          }
          prmptend();
          break;
     case PROTPC:
          if (fseptr->topic != NULL) {
               shotxt(DCOFIL);
               prmptend();
               if ((i=endline(fseptr->tmpbuf)) != 0) {
                    strncpy(fseptr->topic,fseptr->tmpbuf,fseptr->tpcsiz);
                    shotxt(DCOTPC);
               }
          }
          fseptr->cmd=0;
          break;
     case CENTER:
          center(CURPOS);
          shotxt(DCOLIN);
          fseptr->cmd=0;
          break;
     case INSLNC:
          insaline(CURPOS);
          shotxt(DCOCUD);
          fseptr->cmd=0;
          break;
     case DELLNC:
          delaline(CURPOS);
          shotxt(DCOCUD);
          fseptr->cmd=0;
          break;
     case INSCHR:
          inschr(CURPOS);
          shotxt(DCOLIN);
          fseptr->cmd=0;
          break;
     case DELCHR:
          delpatl(CURPOS,1);
          shotxt(DCOLIN);
          fseptr->cmd=0;
          break;
     case ERAEOL:
          if (fseptr->endbuf-leftpoint(CURPOS) >= 80) {
               prf("\33[0K");
               outprf(usrnum);
               clear(CURPOS,80-fseptr->x);
          }
          fseptr->cmd=0;
          break;
     case CHOPLN:
          chopln(CURPOS);
          shotxt(DCOCUD);
          fseptr->cmd=0;
          break;
     case JOINLN:
          joinln(CURPOS,WRPLIM,0);
          shotxt(DCOCUD);
          fseptr->cmd=0;
          break;
     case PARFOR:
          parfor(CURPOS);
          shotxt(DCOCUD);
          fseptr->cmd=0;
          break;
     case DRWFRM:
          drawbk();
          fseptr->flags&=~MARKDON;
          shotxt(DCOALL);
          fseptr->cmd=0;
          break;
     case BLKDEL:
          delblk();
          fseptr->flags&=~MARKDON;
          shotxt(DCOALL);
          fseptr->cmd=0;
          break;
     }
     seteotxt();
     rststf();
     if (fseptr->cmd != 0) {
          fseptr->stacnt++;
          btuinj(usrnum,FSESTS);
     }
     return(CONEDT);
}

static INT
fseret(whnval)                     /* return from the FSE to the caller    */
INT whnval;                        /* value to pass to whndun routine      */
{
     fseptr->flags&=~EDITING; /* in case of condex(), always do this 1st!  */
     if ((*(fseptr->exitro))(whnval)) {
          return(1);
     }
     fseptr->flags|=EDITING;
     fseptr->substt=usrptr->state;
     usrptr->state=fsestt;
     usrptr->flags|=NOGLOB;
     fseptr->cmd=EXITOM;
     btuinj(usrnum,CRSTG);
     return(0);
}

static VOID
shotxt(cmd)                        /* Put buffer up on users screen        */
INT cmd;
{
     CHAR *ptr;
     INT i,linect;
     INT y;

     clrprf();
     seteotxt();
     switch(cmd) {
     case DCOTOP:
          prf("\33[1;1f\33M");
          outprf(usrnum);
          sholn(fseptr->begstg);
          break;
     case DCOBOT:
          prf("\33[%d;1f\33D",fseptr->scnlen-2);
          outprf(usrnum);
          sholn(fseptr->begstg);
          break;
     case DCOFIL:
          for (y=0 ; y < fseptr->winheig ; y++) {
               prf("\33[%d;1f",fseptr->winstar+y);
               outprf(usrnum);
               sholn(fseptr->topscr+(80*(fseptr->winstar-1+y)));
          }
          break;
     case DCOCUD:
          for (y=fseptr->y ; y <= fseptr->scnlen-2 ; y++) {
               prf("\33[%d;1f",y);
               outprf(usrnum);
               sholn(fseptr->topscr+(80*(y-1)));
          }
          break;
     case DCOFKY:
          if (!isripu()) {
               prf("\33[1;%dr\33[0m",fseptr->scnlen);
               for (i=0 ; i < noffkey[fseptr->termtyp] ; i++) {
                    prf("\33[%d;%df\33[1;33m%s\33[0;37;7m%s\33[0;37m ",
                        fseptr->scnlen-1,(10*i),
                        fklegs[fseptr->termtyp][i*2],
                        fklegs[fseptr->termtyp][(i*2)+1]);
               }
               while (i < 8) {
                    prf("\33[%d;%df          ",fseptr->scnlen-1,(10*i));
                    i++;
               }
               prf("\33[1;1f\33[1;%dr",fseptr->scnlen-2);
               prf("\33[0;1;32m");
               outprf(usrnum);
          }
          break;
     case DCOTPC:
          if (fseptr->topic != NULL) {
               prf("\33[1;%dr\33[0m",fseptr->scnlen);
               if (fseptr->flags&FLFLVR) {
                    prf("\33[%d;1f\33[37mFilename: \33[36;1m",fseptr->scnlen);
               }
               else {
                    prf("\33[%d;1f\33[37mTopic: \33[36;1m",fseptr->scnlen);
               }
               outprf(usrnum);
               for (i=fseptr->tpcsiz ; i > 1 ; i--) {
                    if (fseptr->topic[i] != ' ') {
                         break;
                    }
               }
               xmtcnt(usrnum,i+1,fseptr->topic);
               prf("\33[K");
               prf("\33[1;1f\33[1;%dr",fseptr->scnlen-2);
               prf("\33[0;1;32m");
               outprf(usrnum);
          }
          break;
     case DCOUMA:
     case DCOSMA:
          if ((fseptr->mkstart >= fseptr->txtbuf) &&
              (fseptr->mkend >= fseptr->mkstart)) {
               for (y=(fseptr->mkstart < fseptr->topscr ? 0 :
                 whatln(fseptr->mkstart))-1 ;
                    y <= (fseptr->mkend-fseptr->topscr >
                 ((fseptr->scnlen-2)*80) ?
                 fseptr->scnlen-2 : whatln(fseptr->mkend))-1 ; y++) {
                    prf("\33[%d;1f",y+1);
                    outprf(usrnum);
                    sholn(fseptr->topscr+(y*80));
               }
          }
          break;
     case DCOLIN:
          y=whatln(CURPOS);
          prf("\33[%d;1f",y);
          outprf(usrnum);
          sholn(fseptr->begstg);
          break;
     case DCOALL:
          linect=0;
          if (fseptr->flags&SCNISCLR) {
               for (y=1,ptr=fseptr->topscr ; y <= fseptr->scnlen-2 ;
              y++,ptr+=80) {
                    if (fseptr->endbuf-ptr < 80 || endline(ptr) != 0) {
                         linect=y;
                    }
               }
          }
          else {
               linect=fseptr->scnlen-2;
          }
          xmtcnt(usrnum,3,"\33[f");
          for (y=1,ptr=fseptr->topscr ; y <= linect ; y++,ptr+=80) {
               if (y != 1) {
                    xmtcnt(usrnum,2,"\n");
               }
               sholn(ptr);
          }
          fseptr->begstg=(fseptr->y-1)*80+fseptr->topscr;
          fseptr->flags&=~SCNISCLR;
          break;
     }
     if (!dontrepo) {
          prf("\33[%d;%df",fseptr->y,fseptr->x);
          outprf(usrnum);
     }
}

static VOID
sholn(ptr)
CHAR *ptr;
{
     CHAR *smptr;

     if (ptr >= fseptr->endbuf) {
          btuxmt(usrnum,"******\33[0K");
     }
     else if (!(fseptr->flags&MARKDON) || ptr > fseptr->mkend
      || fseptr->mkstart-ptr > MXLNSZ) {
          xmtcnt(usrnum,endline(ptr),ptr);
          if (!(fseptr->flags&SCNISCLR)) {
               xmtcnt(usrnum,3,"\33[K");
          }
     }
     else {
          if (fseptr->mkstart > ptr) {
               xmtcnt(usrnum,(INT)(fseptr->mkstart-ptr),ptr);
          }
          btuxmt(usrnum,"\33[0;37;7m");
          smptr=(fseptr->mkstart > ptr ? fseptr->mkstart : ptr);
          xmtcnt(usrnum,
             min((INT)(fseptr->mkend-smptr),(INT)((ptr+MXLNSZ)-smptr)),smptr);
          btuxmt(usrnum,"\33[0;1;32m");
          if (fseptr->mkend-ptr < 80) {
               xmtcnt(usrnum,(INT)((ptr+80)-fseptr->mkend),fseptr->mkend);
          }
     }
}

static VOID
pfinwin(msgno,nxtst,abst,heig,chq,millim,inbuf)
INT msgno,                         /* 'Window Message' to Display          */
    nxtst,                         /* When done, what ->cmd to set to      */
    abst,                          /* If aborted, what ->cmd to go to      */
    heig,                          /* Height of Window in lines            */
    chq,                           /* 1=Check 'Q' abort, 0=no check        */
    millim;                        /* # of chars to take, 0='hit any key'  */
CHAR *inbuf;                       /* Buffer for inputted answer           */
{
     INT i;

     if (chq) {
          if (fseptr->tmpbuf[0] != ' ') {
               fseptr->cmd=abst;
               btuinj(usrnum,FSESTS);
               return;
          }
     }
     i=(fseptr->scnlen/2)-(heig/2);
     fsemsg(msgno,i);
     promptgo(millim,nxtst,inbuf);
     fseptr->winstar=i;
     fseptr->winheig=heig;
}

static VOID
promptgo(millim,nxtcmd,inbuf)      /* Setup for prompt box routines        */
INT millim;                        /* # of chars to take, 0='hit any'      */
INT nxtcmd;                        /* Next state to go to                  */
CHAR *inbuf;                       /* Buffer for temporary input           */
{                                  /* Cursor assumed to be prepositioned   */
     fseptr->tmpptr=inbuf;
     fseptr->nlines=millim;
     fseptr->txtlen=0;
     fseptr->rpclen=nxtcmd;
     fseptr->cmd=0;
     if (millim == 0) {
          fseptr->substt=TAKONE;
     }
     else {
          fseptr->substt=LINMOD;
     }
}

static VOID
prmptend(VOID)                     /* Recover from prompt box routine      */
{
     fseptr->substt=NORMAL;
}

INT
worlen(CHAR *ptr)                  /* find length of this word             */
{
     INT i;

     i=0;
     while (*(ptr+i) != 0 && *(ptr+i) != ' ' && *(ptr+i) != 0x0d && *(ptr+i) != 0x0a) {
          i++;
     }
     return(i);
}

GBOOL
fsepage(VOID)                      /* FSE injoth handler (uses prfbuf)     */
{
     CHAR *ourbuf;
     INT injlen,boxwid,cleft,wlen;
     INT winx,winy,heig,i;

     fseoth=&(fseusr[othusn]);
     if (fseoth->flags&LINEMO) {
          dftinj();
          return(TRUE);
     }
     if (fseoth->cmd != 0 || fseoth->substt != NORMAL || isripo(othusn)) {
          return(FALSE);
     }
     stlcpy(vdatmp,prfbuf,vdasiz);
     stpans(prfbuf);
     injlen=strlen(prfbuf);
     for (i=0 ; i < injlen ; i++) {
          if (prfbuf[i] < ' ' && prfbuf[i] != 0x0d && prfbuf[i] != 0x0a) {
               prfbuf[i]=' ';
          }
     }
     boxwid=min(injlen+2,65);           /* determine width of box...       */
     boxwid=max(boxwid,40);
     winy=4;
     winx=40-(boxwid/2);
     prfptr=&prfbuf[injlen];
     *++prfptr='\0';                      /* start creating box...           */
     strcat(prfptr,
      spr("[%d;%df[1;36mÉÍ[7m PAGE (hit '+' to continue) [0;1;36m",winy,winx));
     setmem(fseoth->tmpbuf,boxwid,'Í');
     *(fseoth->tmpbuf+boxwid-29)='\0';
     strcat(prfptr,fseoth->tmpbuf);
     strcat(prfptr,"»[B[");
     strcat(prfptr,spr("%d",boxwid+2));
     strcat(prfptr,"Dº ");
     cleft=boxwid-2;
     ourbuf=prfbuf;
     heig=1;
     while (*ourbuf != 0 && heig < MAXBDP) {
          switch (*ourbuf) {
          case 0x0a:
          case 0x0d:
               strncat(prfptr,"                                            "
                              "                        ",cleft);
               strcat(prfptr,spr(" [1;36mº[B[%dDº ",boxwid+2));
               heig++;
               ourbuf++;
               cleft=boxwid-2;
               break;
          case ' ':
               ourbuf++;
               break;
          default:
               wlen=worlen(ourbuf);
               if (wlen < cleft) {
                    strncat(prfptr,ourbuf,wlen);
                    strcat(prfptr," ");
                    ourbuf+=wlen;
                    cleft-=(wlen+1);
               }
               else if (cleft == boxwid-2) {
                    strncat(prfptr,ourbuf,cleft);
                    strcat(prfptr,spr(" [1;36mº[B[%dDº ",boxwid+2));
                    ourbuf+=cleft;
                    cleft=boxwid-2;
                    heig++;
               }
               else {
                    strncat(prfptr,"                                         "
                                   "                      ",cleft);
                    strcat(prfptr,spr(" [1;36mº[B[%dDº ",boxwid+2));
                    strncat(prfptr,ourbuf,wlen);
                    strcat(prfptr," ");
                    ourbuf+=wlen;
                    cleft=boxwid-3-wlen;
                    heig++;
               }
          }
     }
     *(prfptr+strlen(prfptr)-2)='\0';
     strcat(prfptr,"È");
     setmem(fseoth->tmpbuf,boxwid,'Í');
     *(fseoth->tmpbuf+boxwid)=0;
     strcat(prfptr,fseoth->tmpbuf);
     strcat(prfptr,"¼[0;1;32m");
     xmtcnt(othusn,strlen(prfptr),prfptr);
     clrprf();
     prf("%s",vdatmp);
     fseoth->nlines=0;
     fseoth->txtlen=0;
     fseoth->rpclen=PAUREP;
     fseoth->cmd=0;
     fseoth->substt=TAKPLU;
     fseoth->winheig=heig+1;
     fseoth->winstar=winy;
     return(TRUE);
}

static VOID
fsemsg(msgno,i)                    /* Print a fse msg (with %d parameters) */
INT msgno,i;
{
     prfmsg(msgno,i   ,i+1 ,i+2 ,i+3 ,i+4 ,i+5 ,i+6 ,i+7 ,i+8 ,i+9 ,
                  i+10,i+11,i+12,i+13,i+14,i+15,i+16,i+17,i+18,i+19,
                  i+20,i+21);
     outprf(usrnum);
}

static VOID
parfor(ptr)                   /* Reformat the paragraph                    */
CHAR *ptr;
{
     CHAR *optr;              /* Orig Ptr                                  */
     INT cfre;                /* # of chars we can move onto 1st line      */
     CHAR *from;              /* Current position we're taking from        */
     CHAR *to;                /* Current position we're writing to         */
     CHAR *topline;           /* Leftpoint of line we're writing to        */
     INT worlen;              /* Length of last word moved                 */
     INT entop;               /* End of top line                           */
     INT nolop;               /* No Loop flag                              */
     INT lnsb4;               /* # of paragraph lines before re-flow       */
     INT lnsafr;              /* # of paragraph lines after re-flow        */
     INT lnsdel;              /* # of new blk lines to delete after re-flow*/
     INT i;                   /* auxillary variable                        */

     nolop=0;
     optr=ptr;
     for (lnsb4=0,ptr=leftpoint(optr) ; ptr < fseptr->endbuf
          && endline(ptr) != 0 ; lnsb4++,ptr+=80) {
     }
     while (nolop == 0) {
          ptr=optr;
          nolop=1;
          do {
               topline=leftpoint(ptr);
               delpatl(topline,starline(topline)); /* Flush left top line */
               entop=endline(topline);
               to=topline+entop+1;
               from=topline+80;
               entop=punchk(topline,entop);
               if (from < fseptr->endbuf && endline(from) > 0) {
                    cfre=WRPLIM-entop;
                    worlen=1;
                    while (cfre > 0 && worlen > 0) {
                         worlen=movword(from,to,cfre,1);
                         if (worlen != 0) {
                              nolop=0;
                         }
                         to+=worlen;
                         cfre-=worlen;
                    }
               }
               else {
                    break;
               }
               ptr+=80;
          } while (fseptr->endbuf-from >= 80);
     }
     for (lnsafr=0,ptr=leftpoint(optr) ; ptr < fseptr->endbuf
          && endline(ptr) != 0 ; lnsafr++,ptr+=80) {
     }
     if ((lnsdel=lnsb4-lnsafr) > 0) {
          for (i=0 ; i < lnsdel && ptr < fseptr->endbuf
                     && endline(ptr) == 0 ; i++) {
               delaline(ptr);
          }
     }
     seteotxt();
}

static INT
punchk(ptr,eol)               /* check a line for punctuation spaces       */
CHAR *ptr;
INT eol;
{
     INT i,neol,teol;

     neol=eol;
     if (eol < 3) {
          teol=eol+3;
     }
     else {
          teol=eol;
     }
     for (i=0 ; i < teol-3 ; i++) {
          if (isalpha(ptr[i]) && isalpha(ptr[i+1]) &&
             (ptr[i+2] == '.' || ptr[i+2] == '!' || ptr[i+2] == '?') &&
             ptr[i+3] == ' ' && ptr[i+4] != ' ' && neol < 78) {
               inschr(ptr+i+3);
               neol++;
          }
     }
     return(neol);
}

static VOID
joinln(ptr,wrpmar,spcnt)       /* Join the line at ptr and what fits of nxt */
CHAR *ptr;                /* anywhere in first line to join (2nd is nxt line*/
INT wrpmar;                        /* rightmost character position allowed+1*/
INT spcnt;                          /* # of spaces to insert during join    */
{
     INT cfre;                 /* # of chars we can move onto 1st line      */
     CHAR *from;               /* Current position we're taking from        */
     CHAR *to;                 /* Current position we're writing to         */
     CHAR *topline;            /* Leftpoint of line we're writing to        */
     INT worlen;               /* Length of last word moved                 */
     INT entop;                /* End of top line                           */

     if (fseptr->endbuf-ptr > 80) {
          topline=leftpoint(ptr);
          entop=endline(topline);
          if ((fseptr->x-1) > entop) {
               entop=fseptr->x-1;
          }
          to=topline+entop+spcnt;
          from=topline+80;
          cfre=wrpmar-endline(topline);
          worlen=1;
          while (cfre > 0 && worlen > 0) {
               worlen=movword(from,to,cfre,0);
               to+=worlen;
               cfre-=worlen;
          }
          if (endline(from) == 0) { /* if next line is blank */
               delaline(from);
          }
          fseptr->x=entop+1;
     }
}

static INT                         /* returns length of word moved+space   */
movword(from,to,maxl,dpad)   /* Move a word from from to to incl. space@end*/
CHAR *from;
CHAR *to;
INT maxl;                          /* maximum length to move               */
INT dpad;                          /* 1=remove leading spaces, 0=no        */
{
     CHAR *frmptr;                 /* Where they're coming from            */
     CHAR *toptr;                  /* Where they're going                  */
     INT nmovd;                    /* Number of characters moved           */
     INT i,firstnsp;

     toptr=to;
     firstnsp=0;
     if (dpad) {
          for (i=0 ; i < maxl ; i++) {
               if (from[i] != ' ') {
                    firstnsp=i;
                    break;
               }
          }
     }
     for (i=0,frmptr=from+firstnsp ; i < maxl ; i++) {
          if (frmptr[i] == ' ') {
               nmovd=0;
               while ((*frmptr != ' ') && (nmovd < 40)) {
                    *(toptr++)=*(frmptr++);
                    nmovd++;
               }
               delpatl(from,firstnsp+nmovd+1);  /* +1 to inc trailing space*/
               return(nmovd+1);
          }
     }
     return(0);
}

static VOID
inschr(ptr)                   /* Insert a single character at pointer      */
CHAR *ptr;
{
     CHAR *staolin;
     INT notmov,xcord;

     staolin=leftpoint(ptr);
     xcord=whatpo(ptr);
     notmov=endline(staolin)-xcord;
     if (notmov > 0 && notmov+xcord <= 78) {
          movmem(ptr,ptr+1,notmov);
          *ptr=' ';
     }
}

static VOID
chopln(ptr)                   /* Chop the line at ptr                      */
CHAR *ptr;
{
     INT nc;
     CHAR *leftptr;

     if (!insaline(ptr)) {
          leftptr=leftpoint(ptr);
          nc=80-(INT)(ptr-leftptr);
          if (nc > 0) {
               movmem(ptr,leftptr+80,nc);
          }
          clear(ptr,nc);
     }
}

static VOID
delblk(VOID)                  /* Delete the Current Block                  */
{
     INT blength;             /* Length of block to delete                 */
     INT nfulline;            /* Number of full lines to delete            */
     INT toprag;              /* # of chars in top partial line            */
     INT botrag;              /* # of chars in bottom partial line         */
     INT i;                   /* temporary loop counter                    */
     CHAR *topline;           /* Leftpoint of top block line               */
     CHAR *botline;           /* Leftpoint to bottom block line            */

     seteotxt();
     blength=(INT)(fseptr->mkend-fseptr->mkstart);
     toprag=80-(INT)(fseptr->mkstart-leftpoint(fseptr->mkstart));
     botrag=(INT)(fseptr->mkend-leftpoint(fseptr->mkend));
     topline=leftpoint(fseptr->mkstart);
     botline=leftpoint(fseptr->mkend);
     if (fseptr->mkstart >= fseptr->txtbuf && fseptr->mkstart < fseptr->endstg
        && fseptr->mkend <= fseptr->endstg && blength > 0) {
          if (topline == botline) {       /* small area on one line        */
               delpatl(fseptr->mkstart,blength);
          }
          else {
               nfulline=(INT)(botline-topline)/80;
               for (i=1 ; i < nfulline ; i++) {
                    delaline(topline+80);
                    /* We don't inc this because delaline() will close up
                       the buffer, effectively inc'ing for us              */
               }
               delpatl(fseptr->mkstart,toprag);
               delpatl(topline+80,botrag);
               /* The 2nd delpatl() uses topline+80, because at this point
                  everything in the middle has been deleted                */
               joinln(fseptr->mkstart,73,0);
          }
     }
}


static VOID
delpatl(                           /* intraline delete                     */
CHAR *ptr,                         /* where to delete                      */
INT nchar)                         /* count to delete                      */
{
     CHAR *lasbkl;

     lasbkl=leftpoint(ptr+80);
     if ((lasbkl-ptr) >= nchar) {
          movmem(ptr+nchar,ptr,(INT)(lasbkl-ptr)-nchar);
     }
     clear(lasbkl-nchar,nchar);
}

static INT                         /* 1=if error, 0=deleted OK             */
delaline(                          /* Delete a line, and close up the buffer    */
CHAR *ptr)                         /* Pointer to line to be deleted        */
{
     CHAR *wherdel;
     CHAR *whereend;

     seteotxt();
     if (ptr < fseptr->endstg) {
          whereend=leftpoint(fseptr->endstg)-80;
          wherdel=leftpoint(ptr);
          if (whereend-wherdel > 0) {
               movmem(wherdel+80,wherdel,(INT)(whereend-wherdel));
          }
          clear(whereend,80);
          seteotxt();
          return(0);
     }
     return(1);
}

static INT                         /* 1=if error, 0=inserted OK            */
insaline(                          /* Insert a line, and shorten the buffer     */
CHAR *ptr)                         /* Insert after the line passed         */
{
     CHAR *wherins;
     CHAR *wherfro;
     UINT notomov;

     wherfro=leftpoint(fseptr->endstg);
     wherins=leftpoint(ptr+80);
     notomov=(INT)(wherfro-wherins);
     if (wherins > wherfro) {
          return(1);
     }
     if ((wherins == wherfro) &&       /* Adding at end of buffer         */
        (fseptr->endbuf-fseptr->endstg > 80)) {
          fseptr->endstg+=80;
          return(0);
     }
     if ((wherfro < fseptr->endbuf) &&
         (wherins+notomov < fseptr->endbuf)) {
          movmem(wherins,wherins+80,notomov);
          clear(wherins,80);
          seteotxt();
          return(0);
     }
     return(1);
}

static VOID
drawbk(VOID)
{
     INT lx,rx,ty,by,i;

     if ((fseptr->mkstart == NULL) || (fseptr->mkend == NULL)) {
          return;
     }
     lx=whatpo(fseptr->mkstart);
     rx=whatpo(fseptr->mkend);
     ty=(INT)(fseptr->mkstart-fseptr->txtbuf)/80;
     by=(INT)(fseptr->mkend-fseptr->txtbuf)/80;
     *(fseptr->mkstart)='É';
     *(fseptr->mkend)='¼';
     for (i=1 ; i < rx-lx ; i++) {
          if (*(fseptr->mkstart+i) == 'º') {
               *(fseptr->mkstart+i)='Î';
          }
          else {
               *(fseptr->mkstart+i)='Í';
          }
          if (*(fseptr->mkend-i) == 'º') {
               *(fseptr->mkend-i)='Î';
          }
          else {
               *(fseptr->mkend-i)='Í';
          }
     }
     for (i=1 ; i < by-ty ; i++) {
          if (*(fseptr->mkstart+(i*80)) == 'Í') {
               *(fseptr->mkstart+(i*80))='Î';
          }
          else {
               *(fseptr->mkstart+(i*80))='º';
          }
          if (*(fseptr->mkend-(i*80)) == 'Í') {
               *(fseptr->mkend-(i*80))='Î';
          }
          else {
               *(fseptr->mkend-(i*80))='º';
          }
     }
     *(fseptr->mkstart+rx-lx)='»';
     *(fseptr->mkend-rx+lx)='È';
}

static VOID
center(ptr)                   /* Center a line                             */
CHAR *ptr;
{
     INT lftmar,indent,right,length;

     ptr=leftpoint(ptr);
     lftmar=starline(ptr);
     right=endline(ptr);
     length=right-lftmar;
     if (length > 0 && right < MXLNSZ) {
          indent=40-(length/2);
          movmem(ptr+lftmar,ptr+indent,length);
          clear(ptr,indent);
          clear(ptr+indent+length,80-(indent+length));
     }
}

static VOID
expndbuf(VOID)                     /* Expand memory buffer                 */
{
     CHAR *ptr;
     INT bl;
     LONG ll;

     if (*(fseptr->txtbuf) == '\r') {
          movmem(fseptr->txtbuf+1,fseptr->txtbuf,fseptr->txtsiz-1);
     }
     ptr=fseptr->txtbuf;
     bl=fseptr->txtsiz;
     while (bl > 0) {
          ll=lolilen(ptr);
          if (ll == 40000U) {
               break;
          }
          bl-=80;                  /* We're going to eat 80, no matter what*/
          if ((ll >= 20000U) && (ll <= 20080U)) {
               ll-=20000U;
               clear(ptr+(INT)ll,bl+(80-(INT)ll));     /* Last line...     */
               break;
          }
          if (ll > 20080U) {
               ll-=20000U;
          }
          if (ll > 80) {                /* line len > 80                   */
               ll=stlawo(ptr);          /* # of chars to end of last word  */
          }
          movmem(ptr+(INT)ll+1,ptr+80,bl);   /* move to next line          */
          clear(ptr+(INT)ll,80-(INT)ll);
          ptr+=80;
     }
}

static LONG
lolilen(ptr)                       /* Long line length (not limited to <80)*/
CHAR *ptr;
{
     LONG i;

     i=0L;
     while (i < fseptr->txtsiz-1) {
          if (*(ptr+(INT)i) == '\r') {
               return(i);
          }
          else if (*(ptr+(INT)i) == '\0') {
               return(20000U+i);
          }
          i++;
     }
     return(40000U);
}

static INT
stlawo(ptr)                        /* Return # chars to start of word      */
CHAR *ptr;
{
     INT i;

     i=MXLNSZ;
     while (*(ptr+i) == ' ' && i != 0) {
          i--;
     }
     while (*(ptr+i) != ' ' && i != 0) {
          i--;
     }
     return(i);
}

static VOID
comprbuf(VOID)                     /* Compress Buffer                      */
{
     CHAR *sofar;                  /* End of last line processed+1         */
     INT bytlft;
     INT nc;                       /* Number of chars on processing line   */
     INT fl;                       /* Test flag                            */

     bytlft=(INT)(fseptr->endstg-fseptr->txtbuf);
     if (bytlft > fseptr->txtsiz) {
          *(fseptr->txtbuf)='\0';
          shocst("FSE \"COMPRBUF\" ERROR","usrnum=%d txtsiz=%d bytlft=%d",
                 usrnum,fseptr->txtsiz,bytlft);
          return;
     }
     sofar=fseptr->txtbuf;
     while (bytlft > MXLNSZ) {
          nc=endline(sofar);
          bytlft-=80;
          if (nc == 80) {
               movmem(sofar+80,sofar+81,bytlft);
               *(sofar+nc)='\r';
               bytlft--;
               fseptr->endstg++;
          }
          else {
               *(sofar+nc)='\r';        /* Terminate this line...          */
               movmem(sofar+80,sofar+nc+1,bytlft);/* close up the buffer   */
               fseptr->endstg-=(80-nc-1);
          }
          sofar=sofar+nc+1;
     }
     fl=0;
     while (sofar > fseptr->txtbuf) {
          if ((*(sofar-1) != '\r') && (*sofar == '\r')) {
               *sofar='\0';
               fl=1;
               break;
          }
          sofar--;
     }
     if (fl == 0) {
          *(fseptr->txtbuf)='\0';
     }
     if (*fseptr->txtbuf != '\r') {
          movmem(fseptr->txtbuf,fseptr->txtbuf+1,fseptr->txtsiz-1);
          *(fseptr->txtbuf)='\r';
     }
}

static VOID
zerotpc(VOID)                      /* Add trailing 0 to topic buffer       */
{
     INT i;
     CHAR *cp;

     i=fseptr->tpcsiz;
     cp=fseptr->topic+i;
     while (i > 0) {
          *cp='\0';
          cp--;
          i--;
          if (*cp != ' ') {
               break;
          }
     }
}

static VOID
nulbuf(VOID)                              /* Null the temporary buffer       */
{
     INT l;

     for (l=0 ; l < 80 ; l++) {
          if (fseptr->tmpbuf[l] == ' ') {
               fseptr->tmpbuf[l]='\0';
               break;
          }
     }
}

static INT
gensig(VOID)                       /* Hash the user's ID                     */
{
     INT i, signat;

     signat=0;
     for (i=0 ; i < UIDSIZ-1 ; i++) {
          signat^=(usaptr->userid[i]<<i);
     }
     return(signat);
}

static CHAR *
begword(ptr)                       /* reverse ptr to start of word           */
CHAR *ptr;
{
     while ((*ptr >= 'A' && *ptr <= 'Z') || (*ptr >='a' && *ptr <= 'z')) {
          ptr--;
     }
     ptr++;
     return(ptr);
}

static CHAR *
endword(ptr)                       /* bump ptr to end of word                */
CHAR *ptr;
{
     while ((*ptr >= 'A' && *ptr <= 'Z') || (*ptr >='a' && *ptr <= 'z')) {
          ptr++;
     }
     return(ptr);
}

static VOID
profchk(VOID)                      /* Check buffer for profanity (0=OK)      */
{
     CHAR *thisln;
     CHAR c;
     INT tpro;
     INT acc,y;

     fseptr->cmd=0;
     if (haskey(syskey)) {
          return;
     }
     thisln=fseptr->txtbuf;
     acc=0;
     do {
          c=*(thisln+80);
          *(thisln+80)='\0';
          if ((tpro=profan(thisln)) > fseptr->pfnlvl) {
               tpro=fseptr->pfnlvl;
          }
          if (tpro > 1) {
               acc+=tpro;
          }
          *(thisln+80)=c;
          thisln+=80;
     } while (thisln != fseptr->endbuf);
     if (acc != 0) {
/* we need to unshow marked text if there is such                          */
          if (fseptr->flags&MARKDON) {
               fseptr->flags&=~MARKDON;
               shotxt(DCOUMA);
          }
          fseptr->mkstart=begword(pfnptr);
          fseptr->mkend=endword(pfnptr);
          fseptr->flags|=MARKDON;
/* now we need to determine if this word is on the screen presently, and
   if its not hidden by the message box (yet to come).                     */
          y=whatln(leftpoint(fseptr->mkstart));
          if (y > 0 && y < fseptr->scnlen-2) {
               prf("\33[%d;1f",y);
               outprf(usrnum);
               sholn(leftpoint(fseptr->mkstart));
          }
          fseptr->cmd=PROFIM;
          return;
     }
     if (fseptr->topic != NULL) {
          *(fseptr->topic+fseptr->tpcsiz)='\0';
          if ((tpro=profan(fseptr->topic)) > fseptr->pfnlvl) {
               tpro=fseptr->pfnlvl;
          }
          if (tpro > 1) {
               acc+=tpro;
          }
     }
     if (acc != 0) {
          fseptr->cmd=PROFIT;
     }
}

static INT
starline(ptr)                      /* Return number of chars to start of line*/
CHAR *ptr;
{
     INT i;

     for (i=0 ; i <= MXLNSZ && ptr[i] == ' ' ; i++) {
     }
     return(i == 80 ? 0 : i);
}

static VOID
fixtop(VOID)                       /* Take care of topic area              */
{
     INT i;

     i=strlen(fseptr->topic);
     clear(fseptr->topic+i,fseptr->tpcsiz-i+1);
}

static VOID
seteotxt(VOID)                     /* Set the end of text buffer pointer   */
{
     CHAR *ptr;

     for (ptr=fseptr->endbuf-1 ; ptr > fseptr->txtbuf ; ptr--) {
          if ((*ptr != ' ') && (*ptr != '\0')) {
               break;
          }
     }
     fseptr->endstg=leftpoint(ptr+80);
}

static CHAR *
leftpoint(ptr)                /* Return pointer to 1st char on line        */
CHAR *ptr;
{
     return(fseptr->txtbuf+(INT)(((ptr-fseptr->txtbuf)/80)*80));
}

static INT
endline(ptr)                       /* Return column of last nonblank char  */
                                   /* 1-80, 0=all blank                    */
CHAR *ptr;                         /* ptr to beginning of line to scan     */
{
     INT i;

     for (i=MXLNSZ ; i >= 0 && ptr[i] == ' ' ; i--) {
     }
     return(i+1);
}

static INT
whatln(ptr)                   /* What line on screen is mem loc ptr        */
CHAR *ptr;
{
     return(1+((INT)(ptr-fseptr->topscr)/80));
}

static INT
whatpo(ptr)                   /* What column on screen is mem loc ptr      */
CHAR *ptr;                    /* Will return from 0-79, NOT from 1-80      */
{
     return((INT)(ptr-fseptr->topscr)%80);
}

static VOID
clear(ptr,len)                /* Clear a block to spaces                   */
CHAR *ptr;
INT len;
{
     if (len > 0) {
          setmem(ptr,len,' ');
     }
}

VOID
fsehup(VOID)                  /* FSE: user hung up                         */
{
     CHAR tmpfil[12];

     fseptr=&(fseusr[usrnum]);
     setmem(fseptr,sizeof(struct fseusr),0);
     strcpy(tmpfil,l2as(usrnum));
     strcat(tmpfil,".fse");
     unlink(tmpfil);
     if (oldhang != NULL) {
          (*oldhang)();
     }
}

/***************************************************************************
 *  Beginning of Interrupt level routines.                                 *
 ***************************************************************************/

CHAR
fsechi(chan,c)                /* BTUCHI intercept routine                  */
INT chan;
INT c;
{
     register INT x,i;
     CHAR *begwor;

     fsecpt=&(fseusr[chan]);
     if (fsecpt->stacnt > 25) {    /* Make sure we don't get a status 254  */
          return(0);
     }
     if (c == -1) {           /* Echo buffer empty, set our counter        */
          fsecpt->ech2go=255;
          return(0);
     }
     c=c&eurmsk;                   /* Make sure 7-E-1 works OK             */
     if (fsecpt->cmd != 0) {  /* Cmd in progress */
          return(0);
     }
     switch (fsecpt->substt) {
     case NORMAL:                  /* Nothing in progress                  */
          if ((fsecpt->x > WRPLIM) && (c == ' ')) {
               c='\r';
          }
          switch (c) {
          case '\r':                 /* CR  */
               if ((fsecpt->x == 3) &&
                   (*fsecpt->begstg == '/' || *fsecpt->begstg == '.') &&
                   (*(fsecpt->begstg+1) == 's' || *(fsecpt->begstg+1) == 'S')) {
                    *(fsecpt->begstg)=' ';
                    *(fsecpt->begstg+1)=' ';
                    fsecpt->cmd=SAVEEX;
                    chiinj(chan,FSESTS);
                    return(0);
               }
               chiout(chan,c);
               fsecpt->x=1;
               if (fsecpt->endbuf-fsecpt->begstg > 80) {
                    fsecpt->begstg+=80;
                    if (fsecpt->y < fsecpt->scnlen-2) {
                         fsecpt->y++;
                         chious(chan,"\33[1B");
                    }
                    else {
                         fsecpt->topscr+=80;
                         fsecpt->cmd=DCOBOT;
                         fsecpt->stacnt++;
                         chiinj(chan,FSESTS);
                         return(0);
                    }
               }
               c=0;
               break;
          case 8:                  /* Backspace */
               if ((fsecpt->x > 1) && (fsecpt->ech2go > 90)) {
                    fsecpt->x--;
                    chirmov(ICRPOS+1,ICRPOS,MXLNSZ-fsecpt->x);
                    *(ICRPOS+MXLNSZ-fsecpt->x)=' ';
                    chious(chan,"\33[D");
                    chiscon(chan);
                    fsecpt->ech2go-=90;
               }
               break;
          case 0x7f:               /* DEL */
               if (fsecpt->ech2go > 90 && fsecpt->x <= MXLNSZ) {
                    chirmov(ICRPOS+1,ICRPOS,MXLNSZ-fsecpt->x);
                    *(ICRPOS+MXLNSZ-fsecpt->x)=' ';
                    chiscon(chan);
                    fsecpt->ech2go-=90;
               }
               c=0;
               break;
          case 9:                  /* TAB */
               if (fsecpt->x < 70) {
                    fsecpt->x=(fsecpt->x+8)&0xF8;
                    chious(chan,"\33[");
                    chinum(chan,fsecpt->y);
                    chious(chan,";");
                    chinum(chan,fsecpt->x);
                    chious(chan,"f");
               }
               break;
          }
          if (c < ' ') {
               if (statjmp[c] < 0) {
                    fsecpt->substt=-statjmp[c];
                    return(0);
               }
               fsecpt->cmd=statjmp[c];
               if (fsecpt->cmd != 0) {
                    fsecpt->stacnt++;
                    chiinj(chan,FSESTS);
               }
               return(0);
          }
          if ((fsecpt->endstg <= fsecpt->begstg)
           && (fsecpt->endbuf-fsecpt->endstg >= 80)) {
               fsecpt->endstg+=80;
          }
          if ((ICRPOS+1 < fsecpt->endbuf) && (fsecpt->x < 80)) {
               *ICRPOS=c;
               if (fsecpt->x > WRPLIM) {
                    x=0;
                    for (i=1 ; i < 31 ; i++) {
                         if (*(ICRPOS-i) == ' ') {
                              begwor=ICRPOS-i;
                              x=1;                /* short word, wrap      */
                              break;
                         }
                    }
                    for (i=78 ; i > fsecpt->x-1 ; i--) {
                         if (fsecpt->begstg[i] != ' ') {
                              x=0;
                              break;
                         }
                    }
                    if (x == 1 && fsecpt->endbuf-ICRPOS >= 80) {
                         /* When we wrap, begwor=space preceeding word     */
                         x=(INT)(ICRPOS-begwor);  /* x=word length         */
                         fsecpt->x=x+1;
                         fsecpt->begstg+=80;      /* new y=next line       */
                         chimvcl(begwor+1,fsecpt->begstg,x);
                         if (x > 0) {
                              chious(chan,"\33[");
                              chinum(chan,x);
                              chious(chan,"D\33[0K");
                         }
                         if (fsecpt->y < fsecpt->scnlen-2) {
                              chious(chan,"\33[B\r");
                              chiouc(chan,fsecpt->begstg,x);
                              fsecpt->y++;
                         }
                         else {
                              fsecpt->topscr+=80;
                              chious(chan,"\33[1;");
                              chinum(chan,fsecpt->y);
                              chious(chan,"r\33[");
                              chinum(chan,fsecpt->y);
                              chious(chan,";1f\33D\33[1;");
                              chinum(chan,fsecpt->scnlen-2);
                              chious(chan,"r\33[");
                              chinum(chan,fsecpt->y);
                              chious(chan,";1f");
                              chiouc(chan,fsecpt->begstg,x);
                         }
                    }
                    else {
                         chiout(chan,c);
                         fsecpt->x++;
                    }
               }
               else {
                    chiout(chan,c);
                    fsecpt->x++;
               }
          }
          fsecpt->begstg=fsecpt->topscr+((fsecpt->y-1)*80);
          break;
     case ESCRCV:
          if (c == '[') {
               fsecpt->substt=ANSIN;
          }
          else if (c == fktrig[fsecpt->termtyp]) {
               fsecpt->substt=FKEYIN;
          }
          else {
               fsecpt->substt=NORMAL;
          }
          return(0);
     case CTLKIN:
          switch (c) {
          case 2:  /* CTRL-K CTRL-B */
               if (ICRPOS < fsecpt->endbuf) {
                    fsecpt->mkstart=ICRPOS;
                    fsecpt->flags|=MARKDON;
               }
               break;
          case 11: /* CTRL-K CTRL-K */
               if ((fsecpt->endbuf-ICRPOS) > 0) {
                    fsecpt->mkend=ICRPOS;
                    fsecpt->flags|=MARKDON;
               }
               break;
          case 8:  /* CTRL-K CTRL-H */
               fsecpt->flags&=~MARKDON;
               break;
          case 21: /* CTRL-K CTRL-U */
               fsecpt->cmd=UPLOAD;
               fsecpt->stacnt++;
               chiinj(chan,FSESTS);
               return(0);
          }
          if ((c < ' ') && (c > '\0')) {
               fsecpt->cmd=ctlkjmp[c];
          }
          fsecpt->substt=NORMAL;
          break;
     case ANSIN:
          if (!isdigit(c) && (c != ';')) {
               procansi(chan,c);
               fsecpt->substt=NORMAL;
          }
          break;
     case FKEYIN:
          fsecpt->substt=NORMAL;
          for (x=0 ; x < noffkey[fsecpt->termtyp] ; x++) {
               if (fkvals[fsecpt->termtyp][x] == c) {
                    fsecpt->cmd=fkcmds[fsecpt->termtyp][x];
                    break;
               }
          }
          break;
     case TAKPLU:
          if (c == '+') {
               fsecpt->substt=NORMAL;
               fsecpt->cmd=fsecpt->rpclen;
               fsecpt->stacnt++;
               chiinj(chan,FSESTS);
          }
          return(0);
     case TAKONE:
          fsecpt->substt=NORMAL;
          switch (c) {
          case 0x17:                    /* Ctrl-W - Help                   */
               fsecpt->cmd=SXTNDH;
               break;
          case 0x12:                    /* Ctrl-R - Help                   */
               fsecpt->cmd=SHOHLP;
               break;
          case 0x18:                    /* Ctrl-X - Goto line editor       */
               if (fsecpt->rpclen == PAUREP) {
                    fsecpt->cmd=GOTOLET;
                    break;
               }
          default:                      /* Go away...                      */
               fsecpt->cmd=fsecpt->rpclen;
               break;
          }
          fsecpt->stacnt++;
          chiinj(chan,FSESTS);
          return(0);
     case LINMOD:
          if (c == 24) {
               fsecpt->cmd=GOTOLET;
          }
          if (c == 18) {
               fsecpt->cmd=SXTNDH;
          }
          if (c == '\r') {
               fsecpt->cmd=fsecpt->rpclen;
               fsecpt->tmpptr[fsecpt->txtlen]=' ';
               fsecpt->stacnt++;
               chiinj(chan,FSESTS);
               return(0);
          }
          if (c == '\b') {
               if (fsecpt->txtlen > 0) {
                    chious(chan,"\b \b");
                    fsecpt->tmpptr[--fsecpt->txtlen]=' ';
               }
          }
          if (c >= ' ') {
               if (fsecpt->txtlen < fsecpt->nlines) {
                    fsecpt->tmpptr[fsecpt->txtlen++]=c;
                    chiout(chan,c);
               }
          }
          break;
     default:
          chious(chan,"*** FSECHI: SUBSTT ERROR ***");
          fsecpt->substt=NORMAL;
     }
     if (fsecpt->substt == NORMAL && fsecpt->cmd == 0) {
          if (fsecpt->curlin != 0) {
               fsecpt->curlin--;
          }
          else {
               fsecpt->curlin=20;
               chiinj(chan,CYCLE); /* (keep ACTIVE flag set while typing)  */
          }
     }
     if (fsecpt->cmd != 0) {
          fsecpt->stacnt++;
          chiinj(chan,FSESTS);
     }
     return('\0');
}

static VOID
procansi(                          /* process ansi command buffer of user  */
register INT chan,
register CHAR c)                   /* ANSI command to execute              */
{
     fsecpt=&(fseusr[chan]);
     switch(c) {
     case 'H':           /* ANSI Home        */
          fsecpt->x=1;
          chiout(chan,'\r');
          break;
     case 'K':           /* ANSI End         */
          fsecpt->cmd=GOEND;
          break;
     case 'A':           /* Cursor Up        */
          if (fsecpt->begstg > fsecpt->txtbuf) {
               if (fsecpt->y > 1) {
                    fsecpt->y--;
                    fsecpt->begstg-=80;
                    chious(chan,"\33[1A");
                    return;
               }
               else {
                    fsecpt->topscr-=80;
                    fsecpt->begstg=fsecpt->topscr;
                    fsecpt->cmd=DCOTOP;
                    return;
               }
          }
          break;
     case 'B':           /* Cursor Down      */
          if (fsecpt->endbuf-fsecpt->begstg > 80) {
               if (fsecpt->y < fsecpt->scnlen-2) {
                    fsecpt->y++;
                    fsecpt->begstg+=80;
                    chious(chan,"\33[1B");
                    return;
               }
               else {
                    fsecpt->topscr+=80;
                    fsecpt->begstg+=80;
                    fsecpt->cmd=DCOBOT;
                    return;
               }
          }
          break;
     case 'C':           /* Cursor Right     */
          if (fsecpt->x < 80) {
               fsecpt->x++;
               chious(chan,"\33[1C");
               return;
          }
          break;
     case 'D':           /* Cursor Left      */
          if (fsecpt->x > 1) {
               fsecpt->x--;
               chious(chan,"\33[1D");
               return;
          }
          break;
     }
}

/***************************************************************************
 *  Line editor routines.                                                  *
 ***************************************************************************/
GBOOL
ldunedt(VOID)                 /* main editor handler - Line editor         */
{
     LONG mno;
     INT (*temp)();
     CHAR *tpc;

     savmb=curmbk;
     fseptr=&(fseusr[usrnum]);
     if (!(fseptr->flags&EDITING)) {
          return(SAVEDT);
     }
     if (!(fseptr->flags&LINEMO)) {
          if (fseptr->cmd == EXITOM) {
               fseptr->flags&=~EDITING;
               usrptr->flags&=~NOGLOB;
               usrptr->state=fseptr->substt;
               return(FALSE);
          }
          return(CONEDT);
     }
     if (pfnlvl > 1) {
          usrptr->pfnacc-=pfnlvl;
          pfnlvl=0;
     }
     setmbk((fseptr->flags&FLFLVR) ? edfmb : edtmb);
     newett=fseptr->substt;
     do {
          bgncnc();
          switch (newett) {
          case 0:
               bgnmsg();
               break;
          case GETTPC:
               switch(margc) {
               case 0:
                    prfmsg(GETTPC,fseptr->tpcsiz-1);
                    cncall();
                    break;
               case 1:
                    if (sameas(margv[0],"x")) {
                         if (fseptr->flags&LIN1ST) {
                              rststf();
                              rstrxf();
                              btutsw(usrnum,usaptr->scnwid);
                              clrinp();
                              fseptr->flags&=~(EDITING+LIN1ST);
                              setmbk(edtmb);
                              prfmsg(FSETRL);
                              outprf(usrnum);
                              prf("");
                              return((*(fseptr->exitro))(ED_QUITEX));
                         }
                         else {
                              cncall();
                              margc=0;
                              edtpmt();
                              btumil(usrnum,usaptr->scnwid-1);
                         }
                         break;
                    }
                    fseptr->flags&=~LIN1ST;
               default:
                    if (profan(tpc=cncall()) >= fseptr->pfnlvl
                       && fseptr->pfnlvl > 1) {
                         prfmsg(LPROFAN);
                         prfmsg(GETTPC,fseptr->tpcsiz-1);
                         break;
                    }
                    strncpy(fseptr->topic,tpc,fseptr->tpcsiz-1);
                    if (fseptr->flags&CHGTPC) {
                         edtpmt();
                         btumil(usrnum,usaptr->scnwid-1);
                    }
                    else {
                         prfmsg(newett=ENTTXT,fseptr->txtsiz-1);
                         cncall();
                         smargn();
                    }
               }
               break;
          case INSLIN:
          case ENTTXT:
               if (procln() != CONEDT) {
                    rtfedt();
                    return(SAVEDT);
               }
               return(CONEDT);
          case EDPWKS:
          case EDTPMT2:
          case EDTPMTT:
          case EDTPMT2M:
          case EDTPMTTM:
               if (hdlecm() != CONEDT) {
                    rtfedt();
                    return(SAVEDT);
               }
               else if (!(fseptr->flags&LINEMO)) {
                    return(CONEDT);
               }
               break;
          case HLPWKS:
               hdlhcm();
               break;
          case RWCHLN:
               vldlin(REPLAC);
               break;
          case EWCHLN:
               vldlin(EDITLN);
               break;
          case DWCHLN:
               vldlin(DELLIN);
               break;
          case IWCHLN:
               vldlin(INSLIN);
               break;
          case REPLAC:
               rplcwt();
               break;
          case RPLCWW:
               rplctx();
               break;
          case EDITLN:
               fseptr->rpclen=fseptr->crllen;
               rplctx();
               break;
          case DELLIN:
               dellin();
               break;
          case NUSURB:
               if ((mno=cnclon()) != 0) {
                    if ((*(fseptr->imradr))(mno)) {
                         lstlns(0);
                         edtpmt();
                         break;
                    }
                    prfmsg(IMPNF2);
                    cncall();
               }
          case CUSURB:
               switch (cncchr()) {
               case 'C':
                    temp=fseptr->imradr;
                    setmem(fseptr->txtbuf,fseptr->txtsiz,0);
                    strtov(fseptr->txtsiz,fseptr->txtbuf,fseptr->tpcsiz,
                         fseptr->topic);
                    fseptr->imradr=temp;
                    bgnmsg();
                    break;
               case 'X':
               case 'N':
                    cncall();
                    edtpmt();
                    break;
               default:
                    prfmsg(newett);
                    cncall();
               }
               break;
          case UPLMOD:
               switch (cncyesno()) {
               case 'Y':
                    clrinp();
                    fseptr->tmpbuf[0]='1';
                    fseptr->substt=usrptr->substt;
                    fileup("your file","?",fupfse);
                    break;
               case 'N':
                    clrinp();
                    fseptr->tmpbuf[0]='2';
                    fseptr->substt=usrptr->substt;
                    fileup("your file","?",fupfse);
                    break;
               case 'X':
                    cncall();
                    edtpmt();
                    break;
               default:
                    prfmsg(newett);
                    cncall();
               }
               break;
          default:
               catastro("EDITOR SUBSTT ERROR");
          }
     } while (!endcnc());
     rtfedt();
     return(CONEDT);
}

VOID
rtfedt(VOID)                  /* prepare to return from editor to caller   */
{
     outprf(usrnum);
     fseptr->substt=newett;
     rststf();
}

VOID
rststf(VOID)                  /* set message block back to caller's mb     */
{
     cncall();
     clrprf();
     setmbk(savmb);
}

VOID
edtmnu(VOID)                  /* display editor menu (w/ or w/o topic/mode)*/
{
     prfmsg(edttpc() ? EDTMNUT : EDTMNU2);
     if (fseok()) {
          prfmsg(EDTMPMT);
     }
     fseptr->flags&=~INSTXT;
     prfmsg(newett=EDPWKS);
}

VOID
edtpmt(VOID)                  /* display editor prompt (w/ or w/o topic/mode)*/
{
     fseptr->flags&=~INSTXT;
     if (fseok()) {
          prfmsg(newett=(edttpc() ? EDTPMTTM : EDTPMT2M));
     }
     else {
          prfmsg(newett=(edttpc() ? EDTPMTT : EDTPMT2));
     }
}

VOID
hlpmnu(VOID)                  /* display editor help (w/ or w/o topic)     */
{
     prfmsg(edttpc() ? HLPAVLWT : HLPAVL);
     prfmsg(newett=HLPWKS);
}

INT
procln(VOID)                  /* process line while entering message text  */
{
     cncall();
     if (input[0] == '\0') {
          prfmsg(CNTENT);
     }
     else if (margc == 1 && (sameas(margv[0],"ok") || sameas(margv[0],"x"))) {
          btumil(usrnum,usaptr->scnwid-1);
          edtmnu();
     }
     else if (margc == 1 && (sameas(margv[0],".s") || sameas(margv[0],"/s"))) {
          btumil(usrnum,DFTIMX);
          rststf();
          fseptr->flags&=~EDITING;
          setmbk(edtmb);
          prfmsg(FSETRL);
          outprf(usrnum);
          prf("");
          return((*(fseptr->exitro))(0));
     }
     else if (profan(input) >= fseptr->pfnlvl && fseptr->pfnlvl > 1) {
          prfmsg(LPROFAN);
     }
     else {
          apndtx();
          if (morspc()) {
               rststf();
               return(CONEDT);
          }
     }
     rtfedt();
     return(CONEDT);
}

INT
morspc(VOID)                  /* check for more space left in message      */
{
     INT amtlft;

     if ((amtlft=fseptr->txtsiz-fseptr->txtlen-1) <= usaptr->scnwid) {
          if (amtlft < 4) {
               prfmsg(TOOBIG);
               edtmnu();
               btumil(usrnum,DFTIMX);
               return(0);
          }
          btumil(usrnum,amtlft-1);
     }
     return(1);
}

static VOID
smargn(VOID)                  /* set margin to 72 if 80-column screen      */
{
     btumil(usrnum,usaptr->scnwid == 79 || usaptr->scnwid == 80 ? -WRPLIM :
          -(usaptr->scnwid-1));
}

INT
hdlecm(VOID)                  /* editor menu command handler               */
{
     CHAR c;
     INT retval;
     INT (*temp)();

     if (margc == 0) {
          edtmnu();
     }
     else {
          switch (c=cncchr()) {
          case 'U':
               prfmsg(newett=UPLMOD);
               break;
          case 'S':
               rststf();
               fseptr->flags&=~EDITING;
               setmbk(edtmb);
               prfmsg(FSETRL);
               outprf(usrnum);
               retval=(*(fseptr->exitro))(0);
               clrprf();
               return(retval);
          case 'A':
               smargn();
               if (morspc()) {
                    prfmsg(CNTENT);
                    cncall();
                    newett=ENTTXT;
               }
               break;
          case 'L':
               lstlns(1);
               edtpmt();
               break;
          case 'C':
               prfmsg(newett=RWCHLN,fseptr->nlines);
               break;
          case 'R':
               prfmsg(newett=EWCHLN,fseptr->nlines);
               break;
          case 'D':
               prfmsg(newett=DWCHLN,fseptr->nlines);
               break;
          case 'I':
               if (morspc()) {
                    prfmsg(newett=IWCHLN,fseptr->nlines);
               }
               break;
          case 'N':
               prfmsg(newett=(fseptr->imradr == NULL ? CUSURB : NUSURB));
               break;
          case 'H':
               if (sameto("help",margv[0])) {
                    nxtcmd+=3;
               }
               hlpmnu();
               break;
          case '?':
               edtmnu();
               break;
          case 'X':
               rststf();
               rstrxf();
               btutsw(usrnum,usaptr->scnwid);
               clrinp();
               fseptr->flags&=~EDITING;
               setmbk(edtmb);
               prfmsg(FSETRL);
               outprf(usrnum);
               retval=(*(fseptr->exitro))(ED_QUITEX);
               clrprf();
               return(retval);
          case 'M':
          case 'T':
          case 'F':
               if (c == 'M') {
                    if (fseok()) {
                         fseptr->rflags&=~(ED_CLRTOP+ED_CLRTXT+LINEMO);
                         temp=fseptr->imradr;
                         stfse(fseptr->txtsiz,fseptr->txtbuf,fseptr->tpcsiz,fseptr->topic);
                         fseptr->imradr=temp;
                         break;
                    }
               }
               else if (edttpc()) {
                    bgntpc();
                    fseptr->flags|=CHGTPC;
                    break;
               }
          default:
               prfmsg(CNOTIL,c);
               cncall();
               edtmnu();
          }
     }
     return(CONEDT);
}

VOID
bgnmsg(VOID)                       /* begin a message                      */
{
     fseptr=&(fseusr[usrnum]);
     fseptr->flags|=LIN1ST;
     if (edttpc() && fseptr->topic[0] == '\0') {
          bgntpc();
     }
     else {
          prfmsg(newett=ENTTXT,fseptr->txtsiz-1);
          cncall();
          smargn();
     }
}

VOID
bgntpc(VOID)                       /* enter topic for message              */
{
     fseptr=&(fseusr[usrnum]);
     prfmsg(newett=GETTPC,fseptr->tpcsiz-1);
     btumil(usrnum,fseptr->tpcsiz-1);
}

VOID
hdlhcm(VOID)                       /* editor help menu command handler     */
{
     static CHAR hlpsub[]={"SALCRDINTFQ"};
     static INT hlpmsn[]={
          HLPSAV,HLPAPP,HLPLIS,HLPCHG,HLPRTY,
          HLPDEL,HLPINS,HLPNEW2,HLPTPC,HLPTPC,HLPQUT
     };
     INT i,c;

     c=cncchr();
     cncall();
     if (c == 'X') {
          edtpmt();
          return;
     }
     for (i=0 ; i < sizeof(hlpsub)-1 ; i++) {
          if (c == hlpsub[i]) {
               prfmsg(hlpmsn[i]);
               cncall();
               edtpmt();
               return;
          }
     }
     hlpmnu();
}

VOID
rplcwt(VOID)                       /* change text function                 */
{
     cncall();
     if (margc == 1 && sameas(margv[0],"x")) {
          edtpmt();
     }
     else if (input[0] == '\0') {
          prfmsg(REPLAC);
     }
     else {
          if ((fseptr->begstg=inword(input,fseptr->begstg)) != NULL) {
               fseptr->rpclen=inplen;
               prfmsg(newett=RPLCWW);
          }
          else {
               prfmsg(NOMCHF);
               edtpmt();
          }
          rstrln();
     }
}

CHAR *
inword(stg1,stg2)                  /* change text of stg2 with stg1   */
CHAR *stg1,*stg2;
{
     INT i,lw;

     lw=strlen(stg1);
     for (i=strlen(stg2) ; i >= lw && *stg2 != '\r' ; stg2++,i--) {
          if (sameto(stg1,stg2)) {
               return(stg2);
          }
     }
     return(NULL);
}

VOID
dellin(VOID)                       /* delete a line function               */
{
     switch (cncyesno()) {
     case 'Y':
          fseptr->rpclen=fseptr->crllen+1;
          if (fseptr->curlin == fseptr->nlines) {
               fseptr->begstg--;
          }
          inplen=0;
          rplctx();
          lstlns(0);
          break;
     case 'N':
          edtpmt();
          break;
     default:
          prfmsg(YORN);
          cncall();
          prfmsg(DELLIN);
     }
}

INT
chk4nl(msg,parm)                   /* check for null entry, re-echo prompt */
INT msg;
LONG parm;
{
     if (margc == 0) {
          prfmsg(msg,parm);
          return(1);
     }
     return(0);
}

VOID
apndtx(VOID)                       /* append or insert new text            */
{
     INT amtlft;

     if ((amtlft=fseptr->txtsiz-fseptr->txtlen-1) < inplen+1) {
          if (amtlft == 0) {
               return;
          }
          input[amtlft-1]='\0';
     }
     if (fseptr->flags&INSTXT) {
          insttx();
     }
     else {
          fseptr->txtbuf[fseptr->txtlen++]='\r';
          strcpy(&(fseptr->txtbuf[fseptr->txtlen]),input);
          fseptr->txtlen+=inplen;
          fseptr->nlines++;
     }
}

VOID
insttx(VOID)                       /* inserts text into current message    */
{
     movmem(fseptr->begstg,&(fseptr->begstg[inplen+1]),
            strlen(fseptr->begstg)+1);
     movmem(input,fseptr->begstg,inplen);
     fseptr->begstg[inplen]='\r';
     fseptr->txtlen+=inplen+1;
     fseptr->nlines++;
     fseptr->curlin++;
     extlin();
     rstrln();
}

VOID
lstlns(shwlines)              /* calculates text info (may also show text) */
INT shwlines;
{
     CHAR *mptr,*linptr;
     INT lineno,tmpchr;

     if (shwlines) {
          prf("\r");
          if (msgtpc()) {
               prf((fseptr->flags&FLFLVR) ? "File: %s\r\r" : "Topic: %s\r\r",
                    fseptr->topic);
          }
     }
     for (lineno=1,mptr=&(fseptr->txtbuf[1]) ; *mptr != '\0' ; ) {
          for (linptr=mptr ; *linptr != '\r' && *linptr != '\0' ; linptr++) {
          }
          tmpchr=*linptr;
          *linptr='\0';
          if (shwlines) {
               prf("%02d: %s\r",lineno,mptr);
               outprf(usrnum);
          }
          lineno++;
          if ((*linptr=tmpchr) == '\0') {
               break;
          }
          mptr=linptr+1;
     }
     fseptr->nlines=lineno-1;
     fseptr->txtlen=strlen(fseptr->txtbuf);
}

VOID
extlin(VOID)                       /* extract a specified line from text   */
{
     INT lineno;
     CHAR *bstg,*estg;

     for (lineno=1,estg=bstg=&(fseptr->txtbuf[1]) ; *bstg != '\0' ; lineno++) {
          for (estg=bstg ; *estg != '\r' && *estg != '\0' ; estg++) {
          }
          if (lineno == fseptr->curlin) {
               *estg='\0';
               fseptr->crllen=strlen(bstg);
               ASSERTM(fseptr->crllen <= MXLNSZ,spr("crllen=%d",fseptr->crllen));
               break;
          }
          if (*estg == '\0') {
               break;
          }
          bstg=estg+1;
     }
     fseptr->begstg=bstg;
     fseptr->endstg=estg;
}

INT
vldlin(msg)                        /* check for a valid line number        */
INT msg;
{
     INT lineno;

     if (toupper(*nxtcmd) == 'X') {
          cncall();
          edtpmt();
          return(0);
     }
     if (!chk4nl(newett,fseptr->nlines)) {
          if ((lineno=cncint()) > 0 && lineno <= fseptr->nlines) {
               fseptr->curlin=lineno;
               extlin();
               if (newett != IWCHLN) {
                    prfmsg(CRLRDS,fseptr->curlin,fseptr->begstg);
               }
               else {
                    fseptr->flags|=INSTXT;
                    smargn();
                    cncall();
               }
               prfmsg(newett=msg);
               rstrln();
               return(1);
          }
          else {
               cncall();
               prfmsg(INVLIN);
               edtpmt();
          }
     }
     return(0);
}

VOID
rplctx(VOID)                       /* replace re-typed line into message   */
{
     INT nll;
     INT ovrflo=0;

     cncall();
     if (!(margc == 1 && sameas(margv[0],"x"))) {
          if ((nll=(fseptr->crllen-fseptr->rpclen)+inplen) > MXLNSZ) {
               prfmsg(ovrflo=LINOVR);
               inplen-=nll-MXLNSZ;
               nll=MXLNSZ;
               input[inplen]='\0';
          }
          if ((fseptr->txtlen-fseptr->crllen)+nll > fseptr->txtsiz-1) {
               if (!ovrflo) {
                    prfmsg(LINOVR);
               }
               inplen-=((fseptr->txtlen-fseptr->crllen)+nll)-(fseptr->txtsiz-1);
               input[inplen]='\0';
          }
          strcpy(vdatmp,fseptr->txtbuf);
          if (inplen > fseptr->rpclen) {
               movmem(fseptr->begstg,&(fseptr->begstg[inplen-fseptr->rpclen]),
                               strlen(fseptr->begstg)+1);
               fseptr->txtlen+=inplen-fseptr->rpclen;
          }
          movmem(input,fseptr->begstg,inplen);
          if (inplen < fseptr->rpclen) {
               movmem(&(fseptr->begstg[fseptr->rpclen]),&(fseptr->begstg[inplen]),
                    strlen(fseptr->begstg+fseptr->rpclen)+1);
               fseptr->txtlen-=fseptr->rpclen-inplen;
               setmem(&(fseptr->txtbuf[fseptr->txtlen]),fseptr->rpclen-inplen,0);
          }
          extlin();
          if (profan(fseptr->begstg) >= fseptr->pfnlvl && fseptr->pfnlvl > 1) {
               rstrln();
               prfmsg(LPROFAN);
               strcpy(fseptr->txtbuf,vdatmp);
          }
          else {
               if (newett == RPLCWW) {
                    prfmsg(NLNRDS,fseptr->curlin,fseptr->begstg);
               }
               rstrln();
          }
          fseptr->txtlen=strlen(fseptr->txtbuf);
     }
     edtpmt();
}

VOID
rstrln(VOID)                       /* restores line after extlin()         */
{
     *(fseptr->endstg)=(fseptr->curlin == fseptr->nlines ? '\0' : '\r');
}

VOID
strtov(siz,buf,tsiz,topic)         /* start editing a message over again   */
INT siz,tsiz;
CHAR *buf,*topic;
{
     INT len,rflags,pfn;
     SHORT (*temp)(SHORT);
     INT temp2;

     fseptr=&(fseusr[usrnum]);
     rflags=fseptr->rflags;
     temp=fseptr->exitro;
     temp2=fseptr->signat;
     pfn=fseptr->pfnlvl;
     setmem(fseptr,sizeof(struct fseusr),0);
     fseptr->pfnlvl=pfn;
     fseptr->signat=temp2;
     fseptr->exitro=temp;
     fseptr->rflags=rflags;
     fseptr->flags=(LINEMO+EDITING);
     fseptr->substt=newett=0;
     if (fseptr->rflags&ED_FILESD) {
          fseptr->flags|=FLFLVR;
     }
     fseptr->txtbuf=buf;
     fseptr->txtsiz=siz;
     fseptr->topic=topic;
     fseptr->tpcsiz=tsiz;
     if ((fseptr->rflags&(ED_CLRTXT+ED_CLRTOP)) != 0) {
          if (fseptr->rflags&ED_CLRTXT) {
               setmem(buf,siz,0);
          }
          if ((fseptr->rflags&ED_CLRTOP) && msgtpc()) {
               setmem(topic,tsiz,0);
          }
     }
     else {
          len=strlen(buf);
          setmem(buf+len,siz-len,0);
          lstlns(0);
          setmbk((fseptr->flags&FLFLVR) ? edfmb : edtmb);
          edtpmt();
          rstmbk();
          fseptr->substt=newett;
     }
}

INT
msgtpc(VOID)                       /* does the message have a topic?       */
{
     return(fseptr->topic != NULL);
}

INT
edttpc(VOID)                       /* does msg have an editable topic?     */
{
     return(fseptr->topic != NULL && !(fseptr->rflags&ED_FIXTOP));
}

static INT
xmtcnt(chan,numbyt,txt)            /* pretend to be btuxct(), but in ASCII */
INT chan;                               /* channel number to output to     */
INT numbyt;                             /* number of bytes to transmit     */
CHAR *txt;                              /* pointer to text to transmit     */
{
     INT rc;
     CHAR savchr;

     savchr=txt[numbyt];
     txt[numbyt]='\0';
     rc=btuxmt(chan,txt);
     txt[numbyt]=savchr;
     return(rc);
}

static INT
fupfse(INT fupcod)              /* Handle uploads into the editor           */
{                          /* implicit inputs:  usrnum,usrptr,usaptr,vdaptr */
                                  /* return value meaning depends on fupcod */
                             /* implicit input/output in many cases: fupmsg */
                                     /* expect caller to do outprf() if any */
     INT rc=0,tmp;
     CHAR tmpfil[12];

     fseptr=&(fseusr[usrnum]);
     setmbk((fseptr->flags&FLFLVR) ? edfmb : edtmb);
     switch(fupcod) {
     case FUPBEG:                /* Begin upload, check permission, reserve */
          strcpy(ftfbuf,l2as(usrnum));
          strcat(ftfbuf,".FSE");
          ftfscb->maxbyt=(2*fseptr->txtsiz);
          rc=1;
          break;
     case FUPEND:               /* End complete upload of a file, unreserve */
          strcpy(ftfbuf,l2as(usrnum));
          strcat(ftfbuf,".FSE");
          break;
     case FUPSKP:                       /* Skip incomplete upload of a file */
          break;
     case FUPFIN:                             /* Finish file upload session */
          strcpy(tmpfil,l2as(usrnum));
          strcat(tmpfil,".FSE");
          if (fseptr->flags&LINEMO) {
               tmp=uplmsg(tmpfil,fseptr->tmpbuf[0] == '1' ? UPLLIN|UPLCLR
                                                          : UPLLIN);
               fseptr->endbuf=fseptr->txtbuf+fseptr->txtsiz;
               lprofchk();
               seteotxt();
               fseptr->substt=newett=EDPWKS;
               if (tmp == 0) {
                    prfmsg(TOOBIG2);
               }
               edtmnu();
               btumil(usrnum,DFTIMX);
          }
          else {
               tmp=uplmsg(tmpfil,fseptr->tmpbuf[0] == '1' ? UPLCLR : 0);
               usrptr->substt=fseptr->substt;
               fseptr->substt=NORMAL;
               fseptr->cmd=(tmp == 0) ? BIGFIL : UPDALL;
               btupbc(usrnum,0);
               btutsw(usrnum,0);
               btuxnf(usrnum,0,0);
               btuchi(usrnum,fsechi);
               btutru(usrnum,0);
               btucli(usrnum);
               btuche(usrnum,1);
               btuech(usrnum,0);
               fseptr->stacnt=1;
               btuinj(usrnum,FSESTS);
          }
          usrptr->state=fsestt;
          rc=1;
          break;
     case FUPHUP:                /* Finish session because user logging off */
          break;
     }
     return(rc);
}

INT
uplmsg(CHAR *afile,INT flags)     /* convert file into FSE msg    */
{
     FILE *fptr;
     INT i=0,k,offset=0,fildun=0;
     INT tmp,tmp2;

     if ((fptr=fopen(afile,FOPRB)) == NULL) {
          return(1);
     }
     if (flags&UPLCLR) {
          fseptr->x=1;
          fseptr->y=1;
          clear(fseptr->txtbuf,fseptr->txtsiz);
          if (flags&UPLLIN) {
               fseptr->txtbuf[0]='\r';  /* add initial blank line          */
               offset=1;
          }
          else {
               fseptr->begstg=fseptr->topscr=fseptr->txtbuf;
          }
     }
     else {
          if (flags&UPLLIN) {
               while (fseptr->txtbuf[i++] != '\0');
               if (i == 1) {
                    clear(fseptr->txtbuf,fseptr->txtsiz);
                    fseptr->txtbuf[0]='\r';  /* add initial blank line     */
               }
               if ((offset=max(i,1)) != 1) {
                    fseptr->txtbuf[i-1]='\r';
               }
          }
          else {
               i=fseptr->txtsiz-1;
               while (fseptr->txtbuf[i--] == ' ' && i >= 0);
               i++;
               offset=(i == 0) ? 0 : i+(79-(i%80))+1;
          }
     }
     fseptr->curlin=20;
     clear(fseptr->tmpbuf,80);
     while (!fildun && offset < fseptr->txtsiz-80) {
          for (i=0 ; i < 79 ; i++) {
               if ((tmp=fgetc(fptr)) == EOF) {
                    fildun=1;
                    break;
               }
               switch (tmp) {
               case 13:    /* carriage return */
                    if ((tmp2=fgetc(fptr)) != 10) {
                         ungetc(tmp2,fptr);
                    }
               case 10:    /* line feed       */
                    if (!(flags&UPLLIN)) {
                         offset+=(79-i);
                    }
                    i=79;
                    break;
               case '\t':  /* expand tab */
                    if (i < 75) {
                         offset+=5;
                         i+=4;
                    }
                    else {
                         if (!(flags&UPLLIN)) {
                              offset=(79-i);
                         }
                         i=79;
                         if ((tmp=fgetc(fptr)) == 13) {
                              if ((tmp2=fgetc(fptr)) != 10) {
                                   ungetc(tmp2,fptr);
                              }
                         }
                         else if (tmp != 10) {
                              ungetc(tmp,fptr);
                         }
                    }
                    break;
               case 12:    /* expand form feed */
                    if (flags&UPLLIN) {
                         for (k=0 ; k < 3 ; k++) {
                              fseptr->txtbuf[offset++]='\r';
                         }
                    }
                    else {
                         if (offset < fseptr->txtsiz-360) {
                              offset+=(79-i)+160;
                         }
                         else {
                              offset=fseptr->txtsiz-80;
                         }
                    }
                    i=79;
                    break;
               default:
                    if (tmp < 32 || tmp == 255) {
                         i--;
                         break;
                    }
                    tmp2=(tmp&eurmsk);
                    if (tmp2 > 31) {
                         fseptr->txtbuf[offset++]=tmp2;
                    }
               }
          }
          if (flags&UPLLIN) {
               fseptr->txtbuf[offset++]='\r';
          }
          else {
               offset++;
          }
     }
     if (flags&UPLLIN) {
          if (fseptr->txtbuf[offset-2] == '\r') {
               fseptr->txtbuf[offset-2]='\0';
               fseptr->txtlen=offset-2;
          }
          else {
               fseptr->txtbuf[offset-1]='\0';
               fseptr->txtlen=offset-1;
          }
     }
     fclose(fptr);
     unlink(afile);
     return(fildun);
}

static INT
fseok (VOID)                       /* in line mode, ok to switch to FSE? */
{
     return(!(fseptr->rflags&ED_LINEMO)
            && (usaptr->ansifl&ANSON)
            && !(usaptr->scnfse < fsemhi));
}

static VOID
lprofchk(VOID)                     /* check line editor buffer profanity   */
{                                  /* deletes profanities                  */
     CHAR *thisln,*s,c;

     if (haskey(syskey)) {
          return;
     }
     thisln=fseptr->txtbuf;
     do {
          for (s=thisln ; *s != '\r' && *s != '\0' ; s++) {
          }
          c=*s;
          *s='\0';
          if (profan(thisln) > fseptr->pfnlvl && fseptr->pfnlvl > 1) {
               *s=c;
               strcpy(thisln,(*s == '\r' ? s+1 : s));
          }
          else {
               *s=c;
               thisln=s+1;
          }
     } while (thisln < fseptr->endbuf);
     fseptr->txtlen=strlen(fseptr->txtbuf);
}
