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. .