/***************************************************************************
 *                                                                         *
 *   PLBBS.C                                                               *
 *                                                                         *
 *   Copyright (c) 1993-1997 Galacticomm, Inc.    All Rights Reserved.     *
 *                                                                         *
 *   Routines to load and initialize DLL files in WGSERV.CFG.  Also has    *
 *   svr-specific GP report.  With support for Ring 0 GSBL tick handler.   *
 *                                                                         *
 *                                    - Robert A. Rose 02/18/92            *
 *   Ring 0                           - Robert A. Rose 06/23/92            *
 *   Was BBS-specific SCANPL.C        - Robert N. Stein 1/06/93            *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"
#include "majorbbs.h"
#include "protstuf.h"
#include "phasedbg.h"

#pragma inline

#define FILREV "$Revision: 9 $"

CHAR btrset[80];              /* parameters we're passing to Btrieve  */

INT mxrecsiz=-1;              /* maximum brequest record size              */

extern INT shdl,stthue;

INT cpu=0;                    /* cpu type=[286 | 386 | 486]                */

SEL gdtsel,idtsel;            /* LDT ring 3 selector to GDT                */
SEL gccode;

struct {                      /* Interrupt & Global Descriptor registers   */
     USHORT limit;
     ULONG base;
} idtr,gdtr;

struct {                      /* GDT selector format                       */
     USHORT limit;            /*   size of selector                        */
     USHORT base1;            /*   base of region (bits  0-15)             */
     UCHAR base2;             /*   base of region (bits 16-23)             */
     CHAR flags;              /*   DPL, P, DT, Type, etc.                  */
     SHORT rsvd;              /*   used on 386 and up only                 */
} *gdt,*ldt;

struct {                      /* IDT selector format                       */
     USHORT offset;
     USHORT seg;
     CHAR rsvd1;
     CHAR type;
     SHORT rsvd2;
} *idt;


VOID prntscn(VOID);
VOID pandb(VOID);
VOID initrng3(VOID);
VOID DosMapLDT(VOID);
VOID DosMapIDT(VOID);
VOID DosMapGDT(VOID);

VOID
setbparm(VOID)           /* read in btrieve parms                          */
{
     CHAR *s;

     btrset[0]='\0';
     if (tfsopn("wgsbtr.bat") == 1) {
          while (tfsrdl() != TFSDUN) {
               if (tfstate == TFSLIN) {
                    if (tfspfx("BREQUEST")) {
                         if ((s=strstr(tfspst,"/d:")) != NULL
                            || (s=strstr(tfspst,"/D:")) != NULL) {
                              mxrecsiz=atoi(s+3);
                         }
                         else {
                              mxrecsiz=0;
                         }
                         stzcpy(btrset,tfspst,sizeof(btrset));
                         stzcat(btrset,"(brequest)",sizeof(btrset));
                    }
                    else if (tfspfx("BTRIEVE")) {
                         stzcpy(btrset,tfspst,sizeof(btrset));
                    }
                    if (btrset[0] != '\0'
                       && (s=strstr(btrset,">NUL")) != NULL) {
                         strcpy(s,s+4);
                    }
               }
          }
     }
}

VOID
callinits(VOID)          /* set up from WGSERV.CFG file (including DLLs)   */
{
     extern INT dfalgrec;
     CHAR *fn386;

     if (tfsopn("wgserv.cfg") == 0) {
          catastro("Can't find DLL list (WGSERV.CFG)!");
     }
     while (tfsrdl() != TFSDUN) {
          if (tfstate == TFSLIN && tfspfx("DLL=")) {
               cntdir(fn386=spr("%s.386",tfspst));
               actvscn(shdl);
               sstatr(stthue);
               if (cpu >= 386 && numfils != 0) {
                    printfat(32,20,"Loading: %8.8s (386 specific)",tfspst);
                    loaddll(fn386);
               }
               else {
                    printfat(32,20,"Loading: %8.8s               ",tfspst);
                    loaddll(tfspst);
               }
          }
     }
     actvscn(shdl);
     sstatr(stthue);
     printfat(28,20,"Initializing:                        ");
     prtdnam=1;
     initdlls();
     sstatr(stthue);
     printfat(28,20,"                                     ");
     if (mxrecsiz >= 0 && dfalgrec > mxrecsiz) {
          catastro("WGSBREQ.INI maximum record size needs to be %d",dfalgrec);
     }
}

VOID
appgprept(VOID)                    /* server-specific GP report            */
{                                  /* (called from PROTSTUF.C)             */
     CHAR uid[UIDSIZ];
     FILE *gpdst;                  /* File handle for GP dumps             */
     INT usrval=0;
     CHAR *catfix2(VOID);

     if ((gpdst=fopen(dstname,FOPAA)) == NULL) {
          return;
     }
     fprintf(gpdst,"\n%s  (%s)\nServer Version: %d.%02d%s\n",
                   bbsttl,bturno,BBSVER/100,BBSVER%100,BBSIRV);
     fprintf(gpdst,"User %d of %d",usrnum,nterms);
     if (0 <= usrnum && usrnum < nterms) {
          if (goodptr(&channel[usrnum])) {
               fprintf(gpdst,"  channel %02X",channel[usrnum]);
          }
     }
     if (goodstg(usaptr->userid) && isprint(usaptr->userid[0])) {
          movmem(usaptr->userid,uid,UIDSIZ-1);
          uid[UIDSIZ-1]='\0';
          fprintf(gpdst,"  User-ID \"%s\"",uid);
     }
     fprintf(gpdst,"  status %d\n",status);
     if (goodblk(usrptr,sizeof(struct user)) == sizeof(struct user)) {
          usrval=1;
          fprintf(gpdst,"Online level %d, state %d, substate %d\n",
                        usrptr->usrcls,
                        usrptr->state,
                        usrptr->substt);
     }
     if (goodptr(curmbk)) {
          fprintf(gpdst,"%s\n",catfix2());
     }
     if (usrval
      && usrptr->state >= 0
      && usrptr->state < nmods
      && goodstg(module[usrptr->state]->descrp)) {
          fprintf(gpdst,"Module \"%s\"\n",module[usrptr->state]->descrp);
     }
     if (input[0] == '\0' || isprint(input[0])) {
          input[INPSIZ-1]='\0';
          fprintf(gpdst,"Input \"%s\"\n",input);
     }
     else {
          fprintf(gpdst,"Input unprintable (starts with %02X)\n",input[0]);
     }
#ifdef DEBUG
     fprintf(gpdst,"\n");
     rptphs(gpdst);
#endif // DEBUG
     fclose(gpdst);
}

VOID
appgprecd(VOID)                        /* svr-specific GP recording of info */
{
     extern INT lastusrnu;                          /* (used in MAJORBBS.C) */

     lastusrnu=usrnum;
}

VOID
initrng3(VOID)                /* Initialize and put our fifo code in ring 0*/
{
     INT tidx,i;
     VOID pl0rti(VOID);

     DosMapGDT();
     DosMapLDT();
     gccode=0;
     for (i=1 ; i < 48 ; i++) {
          if (gdt[i].flags == 0) {
               gccode=i;
               break;
          }
     }
     if (gccode == 0) {
          catastro("GDT is full!");
     }
     tidx=(INT)((LONG)pl0rti>>19)&0xFFFF;
     gdt[gccode].flags=ldt[tidx].flags;
     gdt[gccode].base1=ldt[tidx].base1;
     gdt[gccode].base2=ldt[tidx].base2;
     gdt[gccode].limit=ldt[tidx].limit;
     gdt[gccode].rsvd=0;
     gdt[gccode].flags=0x9A;
     DosMapIDT();
     DosBlockIntr();
     idt[8].offset=FP_OFF(pl0rti);
     idt[8].seg=gccode*8;
     DosUnblockIntr();
}

VOID
DosMapLDT(VOID)               /* Return a selector mapped over the LDT     */
{
     SEL ldtsel;
     ULONG linadr;

/* asm  sldt ax */
asm  db 0x0f,0x00,0xc0
asm  mov  ldtsel,ax

     linadr=(ULONG)(gdt[ldtsel>>3].base1+((LONG)(gdt[ldtsel>>3].base2)<<16));
     DosMapLinSeg(linadr,(ULONG)(gdt[ldtsel>>3].limit),&ldtsel);
     ldt=MK_FP(ldtsel,0);
}

VOID
DosMapIDT(VOID)               /* Return a selector mapped over the IDT     */
{
/* asm sidt idtr */
asm  mov  bx,offset idtr
asm  db   0x0f,0x01,0x0f

     DosMapLinSeg(idtr.base,idtr.limit,&idtsel);
     idt=MK_FP(idtsel,0);
}

VOID
DosMapGDT(VOID)               /* Return a selector mapped over the GDT     */
{
/* asm  sgdt gdtr */
asm  mov  bx,offset gdtr
asm  db   0x0f,0x01,0x07

     DosMapLinSeg(gdtr.base,gdtr.limit,&gdtsel);
     gdt=MK_FP(gdtsel,0);
}

#ifdef GCDOS

ULONG
hrtval(VOID)                  /* return safe btuhrt                        */
{
     extern ULONG btuhrt;
     ULONG retval;

     dsairp();
     retval=btuhrt;
     enairp();
     return(retval);
}

USHORT
btuTicker(VOID)               /* return ticker                             */
{
     extern USHORT ticker;

     return(ticker);
}

#endif
