
  Here is the complete source code for the Frontier BBS system.

  Aegis Corp releases this source under the GNU General Public License, be
  sure to read the file license.txt.

  If you plan to use any part of our work, please, get in touch with the
  author at:

  gastellu@club-internet.fr

  I would really be pleased to hear from a BBS software author who would
  like to include, let say, the PPE engine in its software.

  ==========================================================================
  ==========================================================================

  Due to the fact that Aegis is no more invoved in BBSes, we decided to
  make those sources available for any people willing to either finish the
  Frontier System, or get some parts of Frontier to include in an existing
  BBS software.

  Included in this package are:

     - Complete sources for the PowerPPL Editor v3.0 (Frontier-dedicated)
     - Complete sources for PPC, the PPE Compiler
     - Complete sources for the PPC Utilities (PPLIB, PPSTRIP)
     - Complete sources for The PPLX Decompiler v2.0
     - Complete sources for the PPE Runtime
     - Complete sources for the Fullscreen Debugger
     - Complete sources for the Frontier BBS System (unfinished)
     - Complete sources for all the Frontier PPEs


  Directories organisation:

             COM  : Frontier BBS System
             DEB  : Frontier Debugger
             DEC  : PPLX Decompiler
             DUAL : Dual-monitor functions (used by some sources)
             LANG : PPE Runtime engine
             PP   : PowerPPL editor
             PPC  : PPE Compiler

  To compile the sources, you need Borland C++ v3.01 or above. Sources are
  designed for real mode under the large memory model.

  I did my best to make all the sources easily compilable, however you *may*
  need to temper a bit with include files, in case i forget some paths
  specific to my system.

  ==========================================================================
  Some Help & warnings
  ==========================================================================

  First, let me warn you: there are many thousands lines of code and very few
  are commented! This will surely make it difficult for anybody to continue
  the project, however, if you're used to analyse someone else' code, you
  will see that not so much things still need to be coded.

  Also, you have to know the this code is a result of 2 years of work with
  a lot of small breaks during development. It results in a lot of parts
  that would need cleanup or some rewrite. For example the PPE engine could
  be rewritten with object code and surely get faster (at least it would be
  a lot easier to extend it).

  Also since a big part has never left my harddisk, there are still a lot of
  debug code, and no guarantee that it will run on your PC.

  However most of this stuff should work great, provided that you take the
  time needed to make it run.

  Note that all the sources come as they were on my HD, that means that,
  for example, in the PowerPPL sources, you even have the keyfile validation
  routines, keyfile creation sources, etc... This will surely to be removed
  if included in a whole package.


  Some hints:

  Global defines:
  ~~~~~~~~~~~~~~~

     DEBUG           will make a debuggable code (with no hotkeys, etc)
     FORTIFY         will make use of the FORTIFY allocation shell
     MINIMUM_FORTIFY will use a 'light' version of fortify (less cpu consuming)

     Don't forget to rebuild all when you change one of these.


  - To add a new function to the language runtime:
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     - Add it to the index of PPL.Y
     - Add it in the fonctions of PPL.Y
     - Add it in ARRAYS.H
     - Add a definition in FUNCS.H
     - Add a definition in EXEC.H
     - Add 1 to the #define MAXFUNCS int EXEC.H
     - Create function body in FUNCS.C

  - To add a new procedure to the language runtime:
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     - Add it in ARRAYS.H
     - Add 1 to the #define MAXPROCS in ARRAYS.H
     - Add a definition in PROCS.H
     - Add a definition in EXEC.H
     - Add 1 to the #define MAXPROCS in EXEC.H
     - Create procedure body in PROCS.C
   
  - To add a procedure or function to the Compiler
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     - Add it in check_type [file PPC.C]
          Note: type is 2000 (pay attention to S_nARG !)
     - Add it to arrays.h
          Note: 1: n arg min, 2: n arg max (usually the same as arg min)
     - Increase #define MAXPROCS or MAXFUNCS in arrays.h

  Here is a list of still unimplemented PPL functions:
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  List of functions still not implemented

  u_msgrd,u_msgwr,ansion,valcc,fmtcc,cctype,pwdhist,pwdlc,pwdtc,u_stat,mkdate,
  callnum,inconf,dbglevel,alias,confalias,useralias,defans,lastans,evttimeadj,
  isbitset,fmtreal,flagcnt,kbdbufsize,pplbufsize,kbdfilused,drivespace,
  actmsgnum,stackleft,stackerr,pcbaccount,pcbaccstat,account,scanmsghdr,
  checkrip,ripver,qwklimts,confinfo

  Total : 38 out of 309 (87.7% done)

  defcolor, prompstr,sendmodem,disptext,stop,push,pop,quest,blt,dir,kbdfile,
  broadcast,waitfor,kbdchkon,kbdchkoff,optext,newpwd,opencap,closecap,
  dbglevel,kbdstring,alias,keyflush,lastin,download,sort,mousereg,scrfile
  stackabort,account,recordusage,qwklimits,confinfo

  Total : 33 out of 268 (91.03% done)

  List of differences with PCBoard in the PPE runtime
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

INSTRR()

   - PCBoard has a bug with the undocumented function INSTRR, it always
     returns 1 more than the value it should.

   - Frontier returns the real value

CHATSTAT()

   - PCBoard returns Chat Status from the logged user, even if a GetAltUser
     has been issued.

   - Frontier returns Chat Status from the loaded user. This means it will
     be the logged user if no GetAltUSer as been performed or if a FreAltUser
     is used to load back the logged user.

USELMRS, USELMRS()

   - PCboard allows one to specify not to load Last Message Read pointers
     when using GetAltUser, this is supposed to save memory if you don't
     need those informations.

   - Due to the memory management difference between PCboard & Frontier,
     Frontier does not need this. You'll have access to LMR wherever you
     are, not consuming more memory than usual.

     USELMR will be ignored, and USELMR() will always return TRUE

CALL

   - PCBoard's CALL statement does not support arguments
   - Frontier's CALL statement does support arguments. ie:
     CALL "C:\PP\MYPPE.PPE /O /L:3"
   - Upon returning from a CALL'ed PPE, no reset to "StartDisp FCL" is
     made. PCBoard force line couting mode each time a PPE ends, but
     this is only more difficult for PPE coders to make clean work
     (for example in frontier when the Timehook.ppe executes in the middle
     of a PPE, this PPE may assume lines couting is off. When returning
     it would issue "More?" prompts while it thinks it can rely on the
     "Startdisp FNS" it used at the beginning of itself.


  List of Frontier-specific PPE functions & statements
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


          Note: These functions & procedures are not handled by PCBoard.

                Using any of these functions & procedures will result in the
                creation of a Frontier-specific PPE file that PCBoard will
                not execute.

                However, most of these funcs & procs are designed to be used
                only with Frontier. For example LEAVE is used at the end of
                the goodbye script. Since the major difference in layout,
                PCBoard would not need it althought Frontier does. As a
                second example, ADVMESSAGE is designed to be used with the
                WRITE MAIL script. Since most of PCBoard's layout is static,
                they included an internal message editor witch is able to
                set file attachments and all other flags, but did not provide
                a PPL procedure to write message with those flags. As
                Frontier's layout is completly dynamic, we need a new proc
                that allow us to set any flag on a message (file attach,
                carbon copy lists, etc).

                PPC will autodetect the use of those funcs & procs and will
                create a Frontier PPE with a different header so PCBoard will
                refuse to try to run it.


            Procedures
            ~~~~~~~~~~


     þ ABORT yesno:boolean

          Set the ABORT SCROLL flag (for use with MORE? prompts PPE)


     þ LEAVE

          Leaves frontier. Returns to DOS. This procedure does not execute
          the goodbye script and is intended to use at the very end of the
          goodbye script.

     þ DPRINT var:anytype [, var:anytype, ...]

           Prints on the DEBUG screen

           The alternate video adapter is used. For example you could have
           both a VGA and an MDA (or Hercule) video cards. If your system
           is set to use the color adapter (VGA), then this procedure will
           write to the monochrome (MDA or Hercule) one. Typing "MODE MONO"
           at the dos prompt will revert situation.

           Note that the secondary video adapter will not handle @Xnn data
           nor PCBoard (or Frontier) @MACROS@. (To print out a macro on the
		   debug screen, use PCBVAR())

           It is safe to use this function if no debug screen is present,
           in this case, no output is sent.

      þ DPRINTLN, DCLS, DANSIPOS, DSAVESCRN, RESTSCRN

           Alternate screen IO functions for use with the debug screen.
           (Refer to DPRINT)

      þ ADVMESSAGE Conf:integer, MsgFile:string

           Send a message using a full featured message file
           (Not yet documented)

      þ SETREAD Conf:integer, MsgNum:longint, YesNo:boolean

           Set the READ attribute of a message to True or False

      þ KILLTIME

           Give up time slice to the operating system

           Use this procedure when you are waiting for a key and do
           nothing that need speed. ie:

                String K
                Boolean Quit

                While (!Quit) Do
                  While (K = "") Do
                    KillTime()       ; Since no key was pressed, give time
                    K = Inkey()      ; to other tasks
                  End While
                  Select Case K
                    Case Chr(27)
                      Quit = True
                    Case Chr(13)
                      DoSomeStuff()
                  End Select
                  K = ""
                End While

           Note: If using the automatic time slice release (see configuration
           software), KillTime is not needed but using it will be safe and
           won't change PPE speed performance.

      þ SCREENCLEARED Status:Boolean

           Set ScreenCleared status flag.

           Typically, this will be used in your main menu with parameter
           FALSE just before launching a command. When the command ends and
           the menu continues, you can then use ScreenCleared() function to
           decide whether or not you have to redraw the menu since any CLS
           will turn the flag ON. This will prevent redrawing the menu
           if only one line of text was displayed (such an invalid command
           notification for example).

      þ UNKILLMSG Conf:integer, Message:Integer

           Recover a previously killed message (with KillMsg)
           It is safe to do it on an active message.

      þ END RtrnVal:string

           Same as END alone, but sets a returns value.

           Unlike PCBoard, Frontier allows a PPE to end returning a value
		   to the calling process. Value can be retreived either with the
		   Call() function (same as Call statement except the value returned
		   by the child PPE is directly returned by the Call() function),
		   or with the LastExitValue() function (which returns the last
		   value used to exit a PPE).

           see also Call() & LastExitValue() functions

	  þ	SETCARRIER Speed:integer

           Set frontier internal carrier speed as detected in modem answer
		   when getting carrier (used in call waiting screen ppe)

      þ SETLOCAL

           Close COM if it has been opened and set node in local mode
           After this statement has been used, nothing is sent to modem until
           a new COMINIT() function is issued.

           This this only has effect after a ComInit(). However, it is safe
           to run it when COM is not initialized.

      þ SETCOMHAND ComHandshake:integer

           CAUTION! Use with Care!!

           Set COM port handshake parameters. Mask is :

				DTR		 01h
				RTS		 02h

           SetComHand RTS + DTR ; will allow data receiving.
           SetComHand RTS       ; will lower DTS and will hangup on
		                        ; most modems
           SetComHand DTR       ; will lower RTS and will prevent remote
		                        ; modem from sending data.
           SetComHand 0         ; Will lower both DTS & RTS. See above.

      þ PUTPROFILE Section:string, Entry:string, Filename:string, Value:string

           Write a profile entry. This works just as windows ini files :

              PutProfile "Setup", "SysopColor", PPEPath() + "MYCHAT.INI", @X0F

              This will result in a file called MYCHAT.INI containing:

                    [Setup]
                    SysopColor = @X0F

              Using PutProfile on an existing entry will replace its value.

           See also: GetProfile()

       þ LOADCONF Conf:integer

           Actually loads the conference data and set the current conference.
           This is ONLY used in the JOIN.PPE ... other PPE that wish to join
           a different conf will use the JOIN statement since Loadconf does
           not check any security restriction while the JOIN.PPE does.

       þ REGISTERCMD Command, Effect, Level

           Registers a command to be accessable with the COMMAND statement

              Command is the keystroke on the command line
              Effect is the PPE or keystroke effect of the command
              Level is the minimum level neede to run the command

           This is to be used ONLY in the JOIN.PPE

       þ INVALIDCMDS

           Invalid all commands registered with REGISTERCMD.

           This is to be used ONLY in the JOIN.PPE

           Once this has been issued, no command will be available, even
           typing "BYE" on the command line would not do anything. All
           commands have to be reloaded from the JOIN.PPE. See JOIN.PPS
           for details

       þ CTOKENIZE String str, String char

           Tokenize a string whoses sections are separated by the first
           character of 'char'. ie:

           A = "1,2,3,4"
           CTokenize A, ","

       þ SUSPENDCOM, RESTORECOM

           Those two statements are intended to be used ONLY in the UPLOAD
           & DOWNLOAD scripts. This unhook & restore the Frontier COM
           routines and allow one to leave them free to the called protocol.

           Use with CARE!!

       þ MACROS MacrosStatus:Boolean

           Set whether or not frontier has to translate @VARs@ & @Xnn color
           codes.

           Used typically in a message editor where you have to see the color
           codes inside the text beeing edited.

       þ SANSIPOS x, y

           Moves local cursor only

       þ PAGETEXT Text:string

           Sets the text beeing displayed in the status bar at the "Paging
           Text". This allows the user to know why the user did paged 10
           minutes ago.

       þ  BIGSHELL ViaCmdCom:Boolean, RetValue:Var, Prog:String, Args:String

	       Same as Shell except Frontier swaps out to XMS/EMS/Disk (and thus
           suspend the COM routines just like SuspendCom would)

       þ  RdPcbSys

          Reads the PCBOARD.SYS in the current directory and loads the data
          in it (user, etc...)

          User to return from a door

       þ  SetCom Com:String, Base:Int, Irq:Int

          Sets the COM parameters. Used before a call to ComInit()

       þ  SearchFileFind File:String, Flag:Boolean

          Works the same way as SearchFind, but works on a file rather than
          on a string buffer

       þ  ResetLog

          Empty LOG for this node

          Should be used only for sysop function "1 D"

	   þ  GetCom Com:String, Base:Int, Irq:Int

          Returns the current COM parameters in the 3 arguments passed.

       þ  SCls

          Clears the local screen only

       þ  WrFrtSys

          Write a FRONTIER.SYS in the current Directory

       þ  RdFrtSys

          Read data from FRONTIER.SYS in the current directory

       þ  AdjTUFiles Val:Int

          Adjust total number of uploaded files for the user

       þ  SetTTime

          Sets the total time allowed for this user. This does not include
          calculations to get the remaining time.

          For example:

             SetTTime 60

             Sets time to 60 Minutes for this user, but automatically
			 calculates that if the user already spend 10 minutes today,
             only 50 left.

       þ  SetLang LangExt:String, LangNum:Int

          Sets the language data.

          LangExt is the file extention associated with the language
          LangNum is the ID number of this language




            Functions
            ~~~~~~~~~


      þ DSCRTEXT, DGETX, DGETY

           Alternate screen IO functions for use with the debug screen.
           (Refer to DPRINT)

      þ DUALSCR() : Boolean

           Returns TRUE if an alternate screen (Debug) is present. FALSE
           if only one video adapter was detected

      þ CONFNAME(Conf:integer) : string

           Returns name of the conference number passed as argument

      þ SCREENCLEARED() : boolean

           Returns TRUE if screen was cleared by CLS since last
           "ScreenCleared FALSE" (see statement screencleared)

           Used to decide whether the menu has to be redrawn or
           not after launching a command.

      þ CALL()

           Same as CALL statement except it returns the value returned by
		   the child PPE using the END statement with a parameter.
           see also LastExitValue()

      þ LASTEXITVALUE()

           Get the last value returned by a PPE. Value is "" (empty string)
		   if END was used alone with no paramater.

      þ FREE() : integer

           Returns amount of free system memory (largest memory block
		   available from DOS to frontier.exe. Note that this may be a lot
		   smaller than the real memory available if the core is fragmented)

	  þ	COMINIT() : boolean

	       Initialize COM port with node specific parameters.

           Returns TRUE if success, FALSE if error.

      þ GETCOMSTAT() : integer

           Returns COM port status. Mask is:

                0x0100 : CTS line changed states
                0x0200 : DSR line changed states
                0x0400 : RI line changed states
                0x0800 : DCD line changed states
                0x1000 : state of CTS line
                0x2000 : state of DSR line
                0x4000 : state of RI line
                0x8000 : state of DCD line
                0x0001 : state of DTR line
                0x0002 : state of RTS line

      þ GETUARTTYPE() : integer

           Returns detected UART :

                 0 : No Uart
                 1 : INS8250-B
                 2 : INS8250A, NS16C450
                 3 : NS16550 (FIFO Bug)
                 4 : NS16550A (FIFO Ok)

      þ GETPROFILE(Section:string, Entry:string, Filename:string) String

           Retrieved a previously saved profile (ini file). See PutProfile

      þ FILEMATCH(String File, String Mask) Boolean

           Check filename against mask. ie:

               FileMatch("ABCDEFGH.123", "*.*") = 1
               FileMatch("ABCDEFGH.123", "ABC*.*") = 1
               FileMatch("ABCDEFGH.123", "*BC*.*3") = 1
               FileMatch("ABCDEFGH.123", "?BC???G?.1?3") = 1
               FileMatch("ABCDEFGH.123", "ABCDEFGH.") = 0

     þ GETNEXTMSG(Integer Conf, Integer Start, Integer Increment,
                  String From, String To, String ToAlias, String Subject,
                  String Text, String DateFrom, Boolean SeeAll) Integer


            Returns the next message in the specified conference (starting
            from 'Start') that match the specified criterias...

            If a criteria is empty (""), it will not be used.
            Purpose of Increment is to search backward (-1) or forward (1)


            ie:

            GetNextMsg(CurConf(), HiMsgNum(), -1, U_NAME(), U_Alias, "", "", "VIRUS", 0, False)

            Will return next message in current conf starting from last msg,
            searching backward, that is from current user and contains the
            word "VIRUS". Msg protection will apply.

            This allows designing a PPE to handle "R Y - TS VIRUS" command
            for example.

     þ FRTINI() String

            Returns the path to FRONTIER.INI

     þ BETA() Boolean

            Returns true if This is a beta of Frontier

	 þ HiMsgNumC(Conf:Int) : Long

            Returns the Highest message number for the specified conference

     þ LoMsgNumC(Conf:Int) : Long

            Returns the Lowest message number for the specified conference

     þ RootPath() : String

     		Returns the Frontier ROOT directory (the one that holds
			FRONTIER.INI)

	 þ ToSDate(Var:Any) : SDate

            Convert any value to SDate type

	 þ LangFile() : String

            Returns the Language string & setup files




            DATA Types
            ~~~~~~~~~~

     þ SDATE

            SDate is the same as DATE type except convertions to string
            always apply with MM.DD.YY while DATE depends on language
            selected.





