Automatically generate the navigation

This commit is contained in:
Nathan Byrd 2022-02-04 08:51:03 -06:00
parent 4793ad0492
commit b5b0cc3ac5
94 changed files with 236 additions and 335 deletions

View file

@ -0,0 +1,43 @@
---
layout: page
title: Administration
---
# Administration
## Keeping Up to Date
See [Updating](updating.md).
## Viewing Logs
See [Monitoring Logs](../troubleshooting/monitoring-logs.md).
## Managing Users
User management is currently handled via the [oputil CLI](oputil.md).
## Backing Up Your System
It is *highly* recommended to perform **regular backups** of your system. Nothing is worse than spending a lot of time setting up a system only to have to go away unexpectedly!
In general, simply creating a copy/archive of your system is enough for the default configuration. If you have changed default paths to point outside of your main ENiGMA½ installation take special care to ensure these are preserved as well. Database files may be in a state of flux when simply copying files. See **Database Backups** below for details on consistent backups.
### Database Backups
[SQLite's CLI backup command](https://sqlite.org/cli.html#special_commands_to_sqlite3_dot_commands_) can be used for creating database backup files. This can be performed as an additional step to a full backup to ensure the database is backed up in a consistent state (whereas simply copying the files does not make any guarantees).
As an example, consider the following Bash script that creates foo.sqlite3.backup files:
```bash
for dbfile in /path/to/enigma-bbs/db/*.sqlite3; do
sqlite3 $dbfile ".backup '/path/to/db_backup/$(basename $dbfile).backup'"
done
```
### Backup Tools
There are many backup solutions available across all platforms. Configuration of such tools is outside the scope of this documentation. With that said, the author has had great success with [Borg](https://www.borgbackup.org/).
## General Maintenance Tasks
### Vacuuming Database Files
SQLite database files become less performant over time and waste space. It is recommended to periodically vacuum your databases. Before proceeding, you should make a backup!
Example:
```bash
sqlite3 ./db/message.sqlite3 "vacuum;"
```

331
docs/_docs/admin/oputil.md Normal file
View file

@ -0,0 +1,331 @@
---
layout: page
title: oputil
---
## The oputil CLI
ENiGMA½ comes with `oputil.js` henceforth known as `oputil`, a command line interface (CLI) tool for sysops to perform general system and user administration. You likely used oputil to do the initial ENiGMA configuration.
Let's look the main help output as per this writing:
```
usage: oputil.js [--version] [--help]
<command> [<arguments>]
Global arguments:
-c, --config PATH Specify config path (default is ./config/)
-n, --no-prompt Assume defaults (don't prompt for input where possible)
--verbose Verbose output, where applicable
Commands:
user User management
config Configuration management
fb File base management
mb Message base management
```
Commands break up operations by groups:
| Command | Description |
|-----------|---------------|
| `user` | User management |
| `config` | System configuration and maintenance |
| `fb` | File base configuration and management |
| `mb` | Message base configuration and management |
Global arguments apply to most commands and actions:
* `--config`: Specify configuration directory if it is not the default of `./config/`.
* `--no-prompt`: Assume defaults and do not prompt when posisible.
Type `./oputil.js <command> --help` for additional help on a particular command. The following sections will describe them.
## User
The `user` command covers various user operations.
```
usage: oputil.js user <action> [<arguments>]
Actions:
info USERNAME Display information about a user
pw USERNAME PASSWORD Set a user's password
(passwd|password)
rm USERNAME Permanently removes user from system
(del|delete|remove)
rename USERNAME NEWNAME Rename a user
(mv)
2fa-otp USERNAME SPEC Enable 2FA/OTP for the user
(otp)
The system supports various implementations of Two Factor Authentication (2FA)
One Time Password (OTP) authentication.
Valid specs:
disable : Removes 2FA/OTP from the user
google : Google Authenticator
hotp : HMAC-Based One-Time Password Algorithm (RFC-4266)
totp : Time-Based One-Time Password Algorithm (RFC-6238)
activate USERNAME Set a user's status to "active"
deactivate USERNAME Set a user's status to "inactive"
disable USERNAME Set a user's status to "disabled"
lock USERNAME Set a user's status to "locked"
group USERNAME [+|~]GROUP Adds (+) or removes (~) user from a group
list [FILTER] List users with optional FILTER.
Valid filters:
all : All users (default).
disabled : Disabled users.
inactive : Inactive users.
active : Active (regular) users.
locked : Locked users.
info arguments:
--security Include security information in output
2fa-otp arguments:
--qr-type TYPE Specify QR code type
Valid QR types:
ascii : Plain ASCII (default)
data : HTML data URL
img : HTML image tag
svg : SVG image
--out PATH Path to write QR code to. defaults to stdout
```
| Action | Description | Examples | Aliases |
|-----------|-------------------|---------------------------------------|-----------|
| `info` | Display user information| `./oputil.js user info joeuser` | N/A |
| `pw` | Set password | `./oputil.js user pw joeuser s3cr37` | `passwd`, `password` |
| `rm` | Removes user | `./oputil.js user del joeuser` | `remove`, `del`, `delete` |
| `rename` | Renames a user | `./oputil.js user rename joeuser joe` | `mv` |
| `2fa-otp` | Manage 2FA/OTP for a user | `./oputil.js user 2fa-otp joeuser googleAuth` | `otp`
| `activate` | Activates user | `./oputil.js user activate joeuser` | N/A |
| `deactivate` | Deactivates user | `./oputil.js user deactivate joeuser` | N/A |
| `disable` | Disables user (user will not be able to login) | `./oputil.js user disable joeuser` | N/A |
| `lock` | Locks the user account (prevents logins) | `./oputil.js user lock joeuser` | N/A |
| `group` | Modifies users group membership | Add to group: `./oputil.js user group joeuser +derp`<br/>Remove from group: `./oputil.js user group joeuser ~derp` | N/A |
#### Manage 2FA/OTP
While `oputil.js` can be used to manage a user's 2FA/OTP, it is highly recommended to require users to opt-in themselves. See [Security](../configuration/security.md) for details.
## Configuration
The `config` command allows sysops to perform various system configuration and maintenance tasks.
```
usage: oputil.js config <action> [<arguments>]
Actions:
new Generate a new / default configuration
cat Write current configuration to stdout
cat arguments:
--no-color Disable color
--no-comments Strip any comments
```
| Action | Description | Examples |
|-----------|-------------------|---------------------------------------|
| `new` | Generates a new/initial configuration | `./oputil.js config new` (follow the prompts) |
| `cat` | Pretty prints current `config.hjson` configuration to stdout. | `./oputil.js config cat` |
## File Base Management
The `fb` command provides a powerful file base management interface.
```
usage: oputil.js fb <action> [<arguments>]
Actions:
scan AREA_TAG[@STORAGE_TAG] Scan specified area
May contain optional GLOB as last parameter.
Example: ./oputil.js fb scan d0pew4r3z *.zip
info CRITERIA Display information about areas and/or files
mv SRC [SRC...] DST Move matching entry(s)
(move)
Source may be any of the following:
- Filename including '*' wildcards
- SHA-1
- File ID
- Area tag with optional @storageTag suffix
Destination is area tag with optional @storageTag suffix
rm SRC [SRC...] Remove entry(s) from the system
(del|delete|remove)
Source may be any of the following:
- Filename including '*' wildcards
- SHA-1
- File ID
- Area tag with optional @storageTag suffix
desc CRITERIA Updates an file base entry's description
Launches an external editor using $VISUAL, $EDITOR, or vim/notepad.
import-areas FILEGATE.ZXX Import file base areas using FileGate RAID type format
scan arguments:
--tags TAG1,TAG2,... Specify hashtag(s) to assign to discovered entries
--desc-file [PATH] Prefer file descriptions from supplied input file
If a file description can be found in the supplied input file, prefer that description
over other sources such related FILE_ID.DIZ. Path must point to a valid FILES.BBS or
DESCRIPT.ION file.
--update Attempt to update information for existing entries
--full Perform a full scan (default is quick)
info arguments:
--show-desc Display short description, if any
remove arguments:
--phys-file Also remove underlying physical file
import-areas arguments:
--type TYPE Sets import areas type
Valid types are are "zxx" or "na".
--create-dirs Also create backing storage directories
General Information:
Generally an area tag can also include an optional storage tag. For example, the
area of 'bbswarez' stored using 'bbswarez_main': bbswarez@bbswarez_main
When performing an initial import of a large area or storage backing, --full
is the best option. If re-scanning an area for updates a standard / quick scan is
generally good enough.
File ID's are those found in file.sqlite3.
```
#### Scan File Area
The `scan` action can (re)scan a file area for new entries as well as update (`--update`) existing entry records (description, etc.). When scanning, a valid area tag must be specified. Optionally, storage tag may also be supplied in order to scan a specific filesystem location using the `@the_storage_tag` syntax. If a [GLOB](http://man7.org/linux/man-pages/man7/glob.7.html) is supplied as the last argument, only file entries with filenames matching will be processed.
##### Examples
Performing a quick scan of a specific area's storage location ("retro_warez", "retro_warez_games) matching only *.zip extensions:
```bash
# note that we must quote the wildcard to prevent shell expansion
$ ./oputil.js fb scan --quick retro_warez@retro_warez_games "*.zip"`
```
Update all entries in the "artscene" area supplying the file tags "artscene", and "textmode".
```bash
$ ./oputil.js fb scan --update --quick --tags artscene,textmode artscene`
```
Scan "oldschoolbbs" area using the description file at "/path/to/DESCRIPT.ION":
```
$ ./oputil.js fb scan --desc-file /path/to/DESCRIPT.ION oldschoolbbs
```
#### Retrieve Information
The `info` action can retrieve information about an area or file entry(s).
##### Examples
Information about a particular area:
```bash
./oputil.js fb info retro_pc
areaTag: retro_pc
name: Retro PC
desc: Oldschool / retro PC
storageTag: retro_pc_tdc_1990 => /file_base/dos/tdc/1990
storageTag: retro_pc_tdc_1991 => /file_base/dos/tdc/1991
storageTag: retro_pc_tdc_1992 => /file_base/dos/tdc/1992
storageTag: retro_pc_tdc_1993 => /file_base/dos/tdc/1993
```
Perhaps we want to fetch some information about a file in which we know piece of the filename:
```bash
./oputil.js fb info "impulse*"
file_id: 143
sha_256: 547299301254ccd73eba4c0ec9cd6ab8c5929fbb655e72c4cc842f11332792d4
area_tag: impulse_project
storage_tag: impulse_project
path: /file_base/impulse_project/impulseproject01.tar.gz
hashTags: impulse.project,8bit.music,cid
uploaded: 2018-03-10T11:36:41-07:00
dl_count: 23
archive_type: application/gzip
byte_size: 114313
est_release_year: 2015
file_crc32: fc6655d
file_md5: 3455f74bbbf9539e69bd38f45e039a4e
file_sha1: 558fab3b49a8ac302486e023a3c2a86bd4e4b948
```
### Importing FileGate RAID Style Areas
Given a FileGate "RAID" style `FILEGATE.ZXX` file, one can import areas. This format also often comes in FTN-style info packs in the form of a `.NA` file i.e.: `FILEBONE.NA`.
#### Example
```bash
./oputil.js fb import-areas FILEGATE.ZXX --create-dirs
```
-or-
```bash
# fsxNet info packs contain a FSX_FILE.NA file
./oputil.js fb import-areas FSX_FILE.NA --create-dirs --type NA
```
The above command will process FILEGATE.ZXX creating areas and backing directories. Directories created are relative to the `fileBase.areaStoragePrefix` `config.hjson` setting.
## Message Base Management
The `mb` command provides various Message Base related tools:
```
usage: oputil.js mb <action> [<arguments>]
Actions:
areafix CMD1 CMD2 ... ADDR Sends an AreaFix NetMail
NetMail is sent to supplied address with the supplied command(s). Multi-part commands
such as "%COMPRESS ZIP" should be quoted.
import-areas PATH Import areas using FidoNet *.NA or AREAS.BBS file
qwk-dump PATH Dumps a QWK packet to stdout.
qwk-export [AREA_TAGS] PATH Exports one or more configured message area to a QWK
packet in the directory specified by PATH. The QWK
BBS ID will be obtained by the final component of PATH.
import-areas arguments:
--conf CONF_TAG Conference tag in which to import areas
--network NETWORK Network name/key to associate FTN areas
--uplinks UL1,UL2,... One or more uplinks (comma separated)
--type TYPE Area import type
Valid types are "bbs" and "na".
qwk-export arguments:
--user USER User in which to export for. Defaults to the SysOp.
--after TIMESTAMP Export only messages with a timestamp later than
TIMESTAMP.
--no-qwke Disable QWKE extensions.
--no-synchronet Disable Synchronet style extensions.
```
| Action | Description | Examples |
|-----------|-------------------|---------------------------------------|
| `import-areas` | Imports areas using a FidoNet style *.NA or AREAS.BBS formatted file. Optionally maps areas to FTN networks. | `./oputil.js config import-areas /some/path/l33tnet.na` |
| `areafix` | Utility for sending AreaFix mails without logging into the system | |
| `qwk-dump` | Dump a QWK packet to stdout | `./oputil.js mb qwk-dump /path/to/XIBALBA.QWK` |
| `qwk-export` | Export messages to a QWK packet | `./oputil.js mb qwk-export /path/to/XIBALBA.QWK` |
When using the `import-areas` action, you will be prompted for any missing additional arguments described in "import-areas args".

View file

@ -0,0 +1,31 @@
---
layout: page
title: Updating
---
# Updating
Keeping your system up to date ensures you have the latest fixes, features, and general improvements. Updating ENiGMA½ can be a bit of a learning curve compared to traditional binary-release systems you may be used to, especially when running from Git cloned source.
## Updating From Source
If you have installed using Git source (if you used the `install.sh` script) follow these general steps to update your system:
1. **Back up your system**!
2. Pull down the latest source:
```bash
cd /path/to/enigma-bbs
git pull
```
3. :bulb: Review `WHATSNEW.md` and `UPDATE.md` for any specific instructions or changes to be aware of.
4. Update your dependencies:
```bash
npm install # or 'yarn'
```
4. Merge updates from `config/menu_template.hjson` to your `config/yourbbsname-menu.hjson` file (or simply use the template as a reference to spot any newly added default menus that you may wish to have on your system as well!).
5. If there are updates to the `art/themes/luciano_blocktronics/theme.hjson` file and you have a custom theme, you may want to look at them as well.
6. Finally, restart your running ENiGMA½ instance.
:information_source: Visual diff tools such as [DiffMerge](https://www.sourcegear.com/diffmerge/downloads.php) (free, works on all major platforms) can be very helpful for the tasks outlined above!
:bulb: It is recommended to [monitor logs](../troubleshooting/monitoring-logs.md) and poke around a bit after an update!

174
docs/_docs/art/general.md Normal file
View file

@ -0,0 +1,174 @@
---
layout: page
title: General Art Information
---
## General Art Information
One of the most basic elements of BBS customization is through it's artwork. ENiGMA½ supports a variety of ways to select, display, and manage art.
### Art File Locations
As a general rule, art files live in one of two places:
1. The `art/general` directory. This is where you place common/non-themed art files.
2. Within a _theme_ such as `art/themes/super_fancy_theme`.
### MCI Codes
All art can contain [MCI Codes](mci.md).
### Art in Menus
While art can be displayed programmatically such as from a custom module, the most basic and common form is via `menu.hjson` entries. This usually falls into one of two forms:
#### Standard
A "standard" entry where a single `art` spec is utilized:
```hjson
{
mainMenu: {
art: main_menu.ans
}
}
```
#### Module Specific / Multiple Art
An entry for a custom module where multiple pieces are declared and used. The second style usually takes the form of a `config.art` block with two or more entries:
```hjson
{
nodeMessage: {
config: {
art: {
header: node_msg_header
footer: node_msg_footer
}
}
}
}
```
A menu entry has a few elements that control how art is selected and displayed. First, the `art` *spec* tells the system how to look for the art asset. Second, the `config` block can further control aspects of lookup and display. The following table describes such entries:
| Item | Description|
|------|------------|
| `font` | Sets the [SyncTERM](http://syncterm.bbsdev.net/) style font to use when displaying this art. If unset, the system will use the art's embedded [SAUCE](http://www.acid.org/info/sauce/sauce.htm) record if present or simply use the current font. See Fonts below. |
| `pause` | If set to `true`, pause after displaying. |
| `baudRate` | Set a [SyncTERM](http://syncterm.bbsdev.net/) style emulated baud rate when displaying this art. In other words, slow down the display. |
| `cls` | Clear the screen before display if set to `true`. |
| `random` | Set to `false` to explicitly disable random lookup. |
| `types` | An optional array of types (aka file extensions) to consider for lookup. For example : `[ '.ans', '.asc' ]` |
| `readSauce` | May be set to `false` if you need to explicitly disable SAUCE support. |
#### Art Spec
In the section above it is mentioned that the `art` member is a *spec*. The value of a `art` spec controls how the system looks for an asset. The following forms are supported:
* `FOO`: The system will look for `FOO.ANS`, `FOO.ASC`, `FOO.TXT`, etc. using the default search path. Unless otherwise specified if `FOO1.ANS`, `FOO2.ANS`, and so on exist, a random selection will be made.
* `FOO.ANS`: By specifying an extension, only the exact match will be searched for.
* `rel/path/to/BAR.ANS`: Only match a path (relative to the system's `art` directory).
* `/path/to/BAZ.ANS`: Exact path only.
ENiGMA½ uses a fallback system for art selection. When a menu entry calls for a piece of art, the following search is made:
1. If a direct or relative path is supplied, look there first.
2. In the users current theme directory.
3. In the system default theme directory.
4. In the `art/general` directory.
#### ACS-Driven Conditionals
The [ACS](../configuration/acs.md) system can be used to make conditional art selection choices. To do this, provide an array of possible values in your art spec. As an example:
```hjson
{
fancyMenu: {
art: [
{
acs: GM[l33t]
art: leet_art.ans
}
{
// default
art: newb.asc
}
]
}
}
```
#### SyncTERM Style Fonts
ENiGMA½ can set a [SyncTERM](http://syncterm.bbsdev.net/) style font for art display. This is supported by many other popular BBS terminals as well. A common usage is for displaying Amiga style fonts for example. The system will use the `font` specifier or look for a font declared in an artworks SAUCE record (unless `readSauce` is `false`).
The most common fonts are probably as follows:
* `cp437`
* `c64_upper`
* `c64_lower`
* `c128_upper`
* `c128_lower`
* `atari`
* `pot_noodle`
* `mo_soul`
* `microknight_plus`
* `topaz_plus`
* `microknight`
* `topaz`
...and some examples:
![cp437](../assets/images/cp437.png "cp437")<br>
![pot_noodle](../assets/images/pot_noodle.png "pot_noodle")<br>
![mo_soul](../assets/images/mo_soul.png "mo_soul")<br>
![microknight_plus](../assets/images/microknight_plus.png "microknight_plus")<br>
![topaz_plus](../assets/images/topaz_plus.png "topaz_plus")<br>
![microknight](../assets/images/microknight.png "microknight")<br>
![topaz](../assets/images/topaz.png "topaz")<br>
Other "fonts" also available:
* `cp1251`
* `koi8_r`
* `iso8859_2`
* `iso8859_4`
* `cp866`
* `iso8859_9`
* `haik8`
* `iso8859_8`
* `koi8_u`
* `iso8859_15`
* `iso8859_4`
* `koi8_r_b`
* `iso8859_4`
* `iso8859_5`
* `ARMSCII_8`
* `iso8859_15`
* `cp850`
* `cp850`
* `cp885`
* `cp1251`
* `iso8859_7`
* `koi8-r_c`
* `iso8859_4`
* `iso8859_1`
* `cp866`
* `cp437`
* `cp866`
* `cp885`
* `cp866_u`
* `iso8859_1`
* `cp1131`
:information_source: See [this specification](https://github.com/protomouse/synchronet/blob/master/src/conio/cterm.txt) for more information.
#### SyncTERM Style Baud Rates
The `baudRate` member can set a [SyncTERM](http://syncterm.bbsdev.net/) style emulated baud rate. May be `300`, `600`, `1200`, `2400`, `4800`, `9600`, `19200`, `38400`, `57600`, `76800`, or `115200`. A value of `ulimited`, `off`, or `0` resets (disables) the rate.
:information_source: See [this specification](https://github.com/protomouse/synchronet/blob/master/src/conio/cterm.txt) for more information.
### Common Example
```hjson
fullLogoffSequenceRandomBoardAd: {
art: OTHRBBS
desc: Logging Off
next: logoff
config: {
baudRate: 57600
pause: true
cls: true
}
}
```
### See Also
See also the [Show Art Module](../modding/show-art.md) for more advanced art display!

238
docs/_docs/art/mci.md Normal file
View file

@ -0,0 +1,238 @@
---
layout: page
title: MCI Codes
---
## MCI Codes
ENiGMA½ supports a variety of MCI codes. Some **predefined** codes produce information about the current user, system, or other statistics while others are used to instantiate a **View**.
## General Information
MCI codes are composed of two characters and are prefixed with a percent (%) symbol.
:information_source: To explicitly tie a MCI to a specific View ID, suffix the MCI code with a number. For example: `%BN1`.
:information_source: Standard (non-focus) and focus colors are set by placing duplicate codes back to back in art files:
![Example](../assets/images/mci-example1.png "MCI Colors")
Some MCI codes have additional options that may be set directly from the code itself while others -- and more advanced options -- are controlled via the current theme.
## Relationship with Menus, Art, and Themes
A MCI code that appears in a `menu.hjson` entry corresponds to that found in it's associated art file. This same MCI code can be referenced in the `theme.hjson` in order to apply a theme.
See [Menus](../docs/configuration/menu-hjson.md) and [Themes](themes.md) for more information.
## Predefined Codes
There are many predefined MCI codes that can be used anywhere on the system (placed in any art file).
| Code | Description |
|------|--------------|
| `BN` | Board Name |
| `VL` | Version *label*, e.g. "ENiGMA½ v0.0.12-beta" |
| `VN` | Version *number*, eg.. "0.0.12-beta" |
| `SN` | SysOp username |
| `SR` | SysOp real name |
| `SL` | SysOp location |
| `SA` | SysOp affiliations |
| `SS` | SysOp sex |
| `SE` | SysOp email address |
| `UN` | Current user's username |
| `UI` | Current user's user ID |
| `UG` | Current user's group membership(s) |
| `UR` | Current user's real name |
| `LO` | Current user's location |
| `UA` | Current user's age |
| `BD` | Current user's birthday (using theme date format) |
| `US` | Current user's sex |
| `UE` | Current user's email address |
| `UW` | Current user's web address |
| `UF` | Current user's affiliations |
| `UT` | Current user's theme name |
| `UD` | Current user's *theme ID* (e.g. "luciano_blocktronics") |
| `UC` | Current user's login/call count |
| `ND` | Current user's connected node number |
| `IP` | Current user's IP address |
| `ST` | Current user's connected server name (e.g. "Telnet" or "SSH") |
| `FN` | Current user's active file base filter name |
| `DN` | Current user's number of downloads |
| `DK` | Current user's download amount (formatted to appropriate bytes/megs/etc.) |
| `UP` | Current user's number of uploads |
| `UK` | Current user's upload amount (formatted to appropriate bytes/megs/etc.) |
| `NR` | Current user's upload/download ratio |
| `KR` | Current user's upload/download *bytes* ratio |
| `MS` | Current user's account creation date (using theme date format) |
| `PS` | Current user's post count |
| `PC` | Current user's post/call ratio |
| `MD` | Current user's status/viewing menu/activity |
| `MA` | Current user's active message area name |
| `MC` | Current user's active message conference name |
| `ML` | Current user's active message area description |
| `CM` | Current user's active message conference description |
| `SH` | Current user's term height |
| `SW` | Current user's term width |
| `AC` | Current user's total achievements |
| `AP` | Current user's total achievement points |
| `DR` | Current user's number of door runs |
| `DM` | Current user's total amount of time spent in doors |
| `DT` | Current date (using theme date format) |
| `CT` | Current time (using theme time format) |
| `OS` | System OS (Linux, Windows, etc.) |
| `OA` | System architecture (x86, x86_64, arm, etc.) |
| `SC` | System CPU model |
| `NV` | System underlying Node.js version |
| `AN` | Current active node count |
| `TC` | Total login/calls to the system *ever* |
| `TT` | Total login/calls to the system *today* |
| `RR` | Displays a random rumor |
| `SD` | Total downloads, system wide |
| `SO` | Total downloaded amount, system wide (formatted to appropriate bytes/megs/etc.) |
| `SU` | Total uploads, system wide |
| `SP` | Total uploaded amount, system wide (formatted to appropriate bytes/megs/etc.) |
| `TF` | Total number of files on the system |
| `TB` | Total amount of files on the system (formatted to appropriate bytes/megs/gigs/etc.) |
| `TP` | Total messages posted/imported to the system *currently* |
| `PT` | Total messages posted/imported to the system *today* |
Some additional special case codes also exist:
| Code | Description |
|--------|--------------|
| `CF##` | Moves the cursor position forward _##_ characters |
| `CB##` | Moves the cursor position back _##_ characters |
| `CU##` | Moves the cursor position up _##_ characters |
| `CD##` | Moves the cursor position down _##_ characters |
| `XY` | A special code that may be utilized for placement identification when creating menus or to extend an otherwise empty space in an art file down the screen. |
:information_source: More are added all
the time so also check out [core/predefined_mci.js](https://github.com/NuSkooler/enigma-bbs/blob/master/core/mci_view_factory.js)
for a full listing.
:memo: Many codes attempt to pay homage to Oblivion/2, iNiQUiTY, etc.
## Views
A **View** is a control placed on a **form** that can display variable data or collect input. One example of a View is
a Vertical Menu (`%VM`): Old-school BBSers may recognize this as a lightbar menu.
| Code | Name | Description | Notes |
|------|----------------------|------------------|-------|
| `TL` | Text Label | Displays text | Static content. See [Text View](views/text_view.md) |
| `ET` | Edit Text | Collect user input | Single line entry. See [Edit Text](views/edit_text_view.md) |
| `ME` | Masked Edit Text | Collect user input using a *mask* | See [Masked Edit](views/mask_edit_text_view.md) and **Mask Edits** below. |
| `MT` | Multi Line Text Edit | Multi line edit control | Used for FSE, display of FILE_ID.DIZ, etc. See [Multiline Text Edit](views/multi_line_edit_text_view.md) |
| `BT` | Button | A button | ...it's a button. See [Button](views/button_view.md) |
| `VM` | Vertical Menu | A vertical menu | AKA a vertical lightbar; Useful for lists. See [Vertical Menu](views/vertical_menu_view.md) |
| `HM` | Horizontal Menu | A horizontal menu | AKA a horizontal lightbar. See [Horizontal Menu](views/horizontal_menu_view.md) |
| `FM` | Full Menu | A menu that can go both vertical and horizontal. | See [Full Menu](views/full_menu_view.md) |
| `SM` | Spinner Menu | A spinner input control | Select *one* from multiple options. See [Spinner Menu](views/spinner_menu_view.md) |
| `TM` | Toggle Menu | A toggle menu | Commonly used for Yes/No style input. See [Toggle Menu](views/toggle_menu_view.md)|
| `PL` | Predefined Label | Show environment information | See [Predefined Label](views/predefined_label_view.md)|
| `KE` | Key Entry | A *single* key input control | Think hotkeys |
:information_source: Peek at [/core/mci_view_factory.js](https://github.com/NuSkooler/enigma-bbs/blob/master/core/mci_view_factory.js) to see additional information.
### Mask Edits
Mask Edits (`%ME`) use the special `maskPattern` property to control a _mask_. This can be useful for gathering dates, phone numbers, so on.
`maskPattern`'s can be composed of the following characters:
* `#`: Numeric 0-9
* `A`: Alpha a-z, A-Z
* `@`: Alphanumeric (combination of the previous patterns)
* `&`: Any "printable" character
Any other characters are literals.
An example of a mask for a date may look like this: `##/##/####`.
Additionally, the following theme stylers can be applied:
* `styleSGR1`: Controls literal character colors for non-focused controls
* `styleSGR2`: Controls literal character colors for focused controls
* `styleSGR3`: Controls fill colors (characters that have not yet received input).
All of the style properties can take pipe codes such as `|00|08`.
### View Identifiers
As mentioned above, MCI codes can (and often should) be explicitly tied to a *View Identifier*. Simply speaking this is a number representing the particular view. These can be useful to reference in code, apply themes, etc.
A view ID is tied to a MCI code by specifying it after the code. For example: `%VM1` or `%SM10`.
## Properties & Theming
Predefined MCI codes and other Views can have properties set via `menu.hjson` and further *themed* via `theme.hjson`. See [Themes](themes.md) for more information on this subject.
### Common Properties
| Property | Description |
|-------------|--------------|
| `textStyle` | Sets the standard (non-focus) text style. See **Text Styles** below |
| `focusTextStyle` | Sets focus text style. See **Text Styles** below. |
| `itemSpacing` | Used to separate items in menus such as Vertical Menu and Horizontal Menu Views. |
| `height` | Sets the height of views such as menus that may be > 1 character in height |
| `width` | Sets the width of a view |
| `focus` | If set to `true`, establishes initial focus |
| `text` | (initial) text of a view |
| `submit` | If set to `true` any `accept` action upon this view will submit the encompassing **form** |
| `itemFormat` | Sets the format for a list entry. See **Entry Formatting** below |
| `focusItemFormat` | Sets the format for a focused list entry. See **Entry Formatting** below |
These are just a few of the properties set on various views. *Use the source Luke*, as well as taking a look at the default `menu.hjson` and `theme.hjson` files!
### Custom Properties
Often a module will provide custom properties that receive format objects (See **Entry Formatting** below). Custom property formatting can be declared in the `config` block. For example, `browseInfoFormat10`..._N_ (where _N_ is up to 99) in the `file_area_list` module received a fairly extensive format object that contains `{fileName}`, `{estReleaseYear}`, etc.
### Text Styles
Standard style types available for `textStyle` and `focusTextStyle`:
| Style | Description |
|----------|--------------|
| `normal` | Leaves text as-is. This is the default. |
| `upper` | ENIGMA BULLETIN BOARD SOFTWARE |
| `lower` | enigma bulletin board software |
| `title` | Enigma Bulletin Board Software |
| `first lower` | eNIGMA bULLETIN bOARD sOFTWARE |
| `small vowels` | eNiGMa BuLLeTiN BoaRD SoFTWaRe |
| `big vowels` | EniGMa bUllEtIn bOArd sOftwArE |
| `small i` | ENiGMA BULLETiN BOARD SOFTWARE |
| `mixed` | EnIGma BUlLEtIn BoaRd SOfTWarE (randomly assigned) |
| `l33t` | 3n1gm4 bull371n b04rd 50f7w4r3 |
### Entry Formatting
Various strings can be formatted using a syntax that allows width & precision specifiers, text styling, etc. Depending on the context, various elements can be referenced by `{name}`. Additional text styles can be supplied as well. The syntax is largely modeled after Python's [string format mini language](https://docs.python.org/3/library/string.html#format-specification-mini-language).
### Additional Text Styles
Some of the text styles mentioned above are also available in the mini format language:
| Style | Description |
|-------|-------------|
| `normal` | Leaves text as-is. This is the default. |
| `toUpperCase` or `styleUpper` | ENIGMA BULLETIN BOARD SOFTWARE |
| `toLowerCase` or `styleLower` | enigma bulletin board software |
| `styleTitle` | Enigma Bulletin Board Software |
| `styleFirstLower` | eNIGMA bULLETIN bOARD sOFTWARE |
| `styleSmallVowels` | eNiGMa BuLLeTiN BoaRD SoFTWaRe |
| `styleBigVowels` | EniGMa bUllEtIn bOArd sOftwArE |
| `styleSmallI` | ENiGMA BULLETiN BOARD SOFTWARE |
| `styleMixed` | EnIGma BUlLEtIn BoaRd SOfTWarE (randomly assigned) |
| `styleL33t` | 3n1gm4 bull371n b04rd 50f7w4r3 |
Additional text styles are available for numbers:
| Style | Description |
|-------------------|---------------|
| `sizeWithAbbr` | File size (converted from bytes) with abbreviation such as `1 MB`, `2.2 GB`, `34 KB`, etc. |
| `sizeWithoutAbbr` | Just the file size (converted from bytes) without the abbreviation. For example: 1024 becomes 1. |
| `sizeAbbr` | Just the abbreviation given a file size (converted from bytes) such as `MB` or `GB`. |
| `countWithAbbr` | Count with abbreviation such as `100 K`, `4.3 B`, etc. |
| `countWithoutAbbr` | Just the count |
| `countAbbr` | Just the abbreviation such as `M` for millions. |
| `durationHours` | Converts the provided *hours* value to something friendly such as `4 hours`, or `4 days`. |
| `durationMinutes` | Converts the provided *minutes* to something friendly such as `10 minutes` or `2 hours` |
| `durationSeconds` | Converts the provided *seconds* to something friendly such as `23 seconds` or `2 minutes` |
#### Examples
Suppose a format object contains the following elements: `userName` and `affils`. We could create a `itemFormat` entry that builds a item to our specifications: `|04{userName!styleFirstLower} |08- |13{affils}`. This may produce a string such as this:
![Example](../assets/images/text-format-example1.png "Text Format")
:bulb: Remember that a Python [string format mini language](https://docs.python.org/3/library/string.html#format-specification-mini-language) style syntax is available for widths, alignment, number prevision, etc. as well. A number can be made to be more human readable for example: `{byteSize:,}` may yield "1,123,456".

167
docs/_docs/art/themes.md Normal file
View file

@ -0,0 +1,167 @@
---
layout: page
title: Themes
---
## Themes
ENiGMA½ comes with an advanced theming system allowing system operators to highly customize the look and feel of their boards. A given installation can have as many themes as you like for your users to choose from.
## General Information
Themes live in `art/themes/`. Each theme (and thus it's *theme ID*) is a directory within the `themes` directory. The theme itself is simply a collection of art files, and a `theme.hjson` file that further defines layout, colors & formatting, etc.
ENiGMA½ comes with a default theme by [Luciano Ayres](http://blocktronics.org/tag/luciano-ayres/) of [Blocktronics](http://blocktronics.org/) called Mystery Skull. This theme is in `art/themes/luciano_blocktronics`, and thus it's *theme ID* is `luciano_blocktronics`.
## Art
For information on art files, see [General Art Information](general.md). In general, to theme a piece of art, create a version of it in your themes directory.
:memo: Remember that by default, the system will allow for randomly selecting art (in one of the directories mentioned above) by numbering it: `FOO1.ANS`, `FOO2.ANS`, etc.!
## Theme Sections
Themes are some important sections to be aware of:
| Config Item | Description |
|-------------|----------------------------------------------------------|
| `info` | This section describes the theme. |
| `customization` | The beef! |
### Info Block
The `info` configuration block describes the theme itself.
| Item | Required | Description |
|-------------|----------|----------------------------------------------------------|
| `name` | :+1: | Name of the theme. Be creative! |
| `author` | :+1: | Author of the theme/artwork. |
| `group` | :-1: | Group/affils of author. |
| `enabled` | :-1: | Boolean of enabled state. If set to `false`, this theme will not be available to your users. If a user currently has this theme selected, the system default will be selected for them at next login. |
### Customization Block
The `customization` block in is itself broken up into major parts:
| Item | Description |
|-------------|---------------------------------------------------|
| `defaults` | Default values to use when this theme is active. These values override system defaults, but can still be overridden themselves in specific areas of your theme. |
| `menus` | The bulk of what you theme in the system will be here. Any menu (that is, anything you find in `menu.hjson`) can be tweaked. |
| `prompts` | Similar to `menus`, this section themes `prompts`. |
#### Defaults
Override system defaults.
| Item | Description |
|-------------|---------------------------------------------------|
| `passwordChar` | Character to display in password fields. Defaults to `*` |
| `dateFormat` | Sets the [moment.js](https://momentjs.com/docs/#/displaying/) style `short` and/or `long` format for dates. |
| `timeFormat` | Sets the [moment.js](https://momentjs.com/docs/#/displaying/) style `short` and/or `long` format for times. |
| `dateTimeFormat` | Sets the [moment.js](https://momentjs.com/docs/#/displaying/) style `short` and/or `long` format for date/time combinations. |
Example:
```hjson
defaults: {
dateTimeFormat: {
short: MMM Do h:mm a
}
}
```
#### Menus Block
Each *key* in the `menus` block matches up with a key found in your `menu.hjson`. For example, consider a `matrix` menu defined in `menu.hjson`. In addition to perhaps providing a `MATRIX.ANS` in your themes directory, you can also theme other parts of the menu via a `matrix` entry in `theme.hjson`.
Major areas to override/theme:
* `config`: Override and/or provide additional theme information over that found in the `menu.hjson`'s entry. Common entries here are for further overriding date/time formats, and custom range info formats (`<someFormName>InfoFormat<num>`). See Entry Formatting in [MCI Codes](mci.md) and Custom Range Info Formatting below.
* `mci`: Set per-MCI code properties such as `height`, `width`, text styles, etc. See [MCI Codes](mci.md) for a more information.
Two formats for `mci` blocks are allowed:
* Shorthand if only a single/first form is needed.
* Verbose where a form ID(s) are supplied (required if multiple forms are used)
Example: Shorthand `mci` format:
```hjson
matrix: {
mci: {
VM1: {
itemFormat: "|03{text}"
focusItemFormat: "|11{text!styleFirstLower}"
}
}
}
```
Example: Verbose `mci` with form IDs:
```hjson
newUserFeedbackToSysOp: {
0: {
mci: {
TL1: { width: 19, textOverflow: "..." }
ET2: { width: 19, textOverflow: "..." }
ET3: { width: 19, textOverflow: "..." }
}
}
1: {
mci: {
MT1: { height: 14 }
}
}
}
```
##### Custom Range Info Formatting
Many modules support "custom range" MCI items. These are MCI codes that are left to the user to define using a format object specific to the module. For example, consider the `msg_area_list` module: This module sets MCI codes 10+ (`%TL10`, `%TL11`, etc.) as "custom range". When theming you can place these MCI codes in your artwork then define the format in `theme.hjson`:
```hjson
messageAreaChangeCurrentArea: {
config: {
areaListInfoFormat10: "|15{name}|07: |03{desc}"
}
}
```
## Creating Your Own
:warning: ***IMPORTANT!*** Do not make any customizations to the included `luciano_blocktronics' theme. Instead, create your own and make changes to that instead:
1. Copy `/art/themes/luciano_blocktronics` to `art/themes/your_board_theme`
2. Update the `info` block at the top of the theme.hjson file:
``` hjson
info: {
name: Awesome Theme
author: Cool Artist
group: Sick Group
enabled: true // default
}
```
3. If desired, you may make this the default system theme in `config.hjson` via `theme.default`. `theme.preLogin` may be set if you want this theme used for pre-authenticated users. Both of these values also accept `*` if you want the system to randomly pick.
``` hjson
theme: {
default: your_board_theme
preLogin: *
}
```
## Theming Example
Let's run through an example!
Consider the following `menu.hjson` entry:
```hjson
superFancyMenu: {
art: FANCY.ANS
// ...some other stuff...
}
```
With a file of `FANCY.ANS` in `art/themes/fancy_theme` containing the following MCI codes:
* TL1 (Generic text label)
* BN2 (Predefined: Board Name)
An entry in your `theme.hjson` could look like this:
```hjson
superFancyMenu: {
mci: {
TL1: {
// supply the full format of the TL1 View
text: |02ENiGMA|10½ |08v|03|VN
}
BN2: {
// Make Board Name l33t style
style: l33t
}
}
}
```

View file

@ -0,0 +1,57 @@
---
layout: page
title: Button View
---
## Button View
A button view supports displaying a button on a screen.
## General Information
:information_source: A button view is defined with a percent (%) and the characters BT, followed by the view number. For example: `%BT1`
:information_source: See [MCI](../mci.md) for general information on how to use views and common configuration properties available for them.
### Properties
| Property | Description |
|-------------|--------------|
| `text` | Sets the text to display on the button |
| `textStyle` | Sets the standard (non-focus) text style. See **Text Styles** in [MCI](../mci.md) |
| `focusTextStyle` | Sets focus text style. See **Text Styles** in [MCI](../mci.md)|
| `width` | Sets the width of a view to display one or more columns horizontally (default 15)|
| `focus` | If set to `true`, establishes initial focus |
| `submit` | If set to `true` any `accept` action upon this view will submit the encompassing **form** |
| `argName` | Sets the argument name for this selection in the form |
| `justify` | Sets the justification of each item in the list. Options: left (default), right, center |
| `fillChar` | Specifies a character to fill extra space longer than the text length. Defaults to an empty space |
| `textOverflow` | If the button text cannot be displayed due to `width`, set overflow characters. See **Text Overflow** below |
### Text Overflow
The `textOverflow` option is used to specify what happens when a text string is too long to fit in the `width` defined.
:information_source: If `textOverflow` is not specified at all, a button can become wider than the `width` if needed to display the text value.
:information_source: Setting `textOverflow` to an empty string `textOverflow: ""` will cause the item to be truncated if necessary without any characters displayed
:information_source: Otherwise, setting `textOverflow` to one or more characters will truncate the value if necessary and display those characters at the end. i.e. `textOverflow: ...`
## Example
![Example](../../assets/images/button_view_example1.gif "Button")
<details>
<summary>Configuration fragment (expand to view)</summary>
<div markdown="1">
```
BT1: {
submit: true
justify: center
argName: btnSelect
width: 17
focusTextStyle: upper
text: Centered button
}
```
</div>
</details>

View file

@ -0,0 +1,42 @@
---
layout: page
title: Edit Text View
---
## Edit Text View
An edit text view supports editing form values on a screen. This can be for new entry as well as editing existing values defined by the module.
## General Information
:information_source: An edit text view is defined with a percent (%) and the characters ET, followed by the view number. For example: `%ET1`. This is generally used on a form in order to allow a user to enter or edit a text value.
:information_source: See [MCI](../mci.md) for general information on how to use views and common configuration properties available for them.
### Properties
| Property | Description |
|-------------|--------------|
| `textStyle` | Sets the standard (non-focus) text style. See **Text Styles** in [MCI](../mci.md) |
| `focusTextStyle` | Sets the focus text style. See **Text Styles** in [MCI](../mci.md) |
| `width` | Sets the width of a view for the text edit (default 15)|
| `argName` | Sets the argument name for this value in the form |
| `maxLength` | Sets the maximum number of characters that can be entered |
| `focus` | Set to true to capture initial focus |
| `justify` | Sets the justification of the text entry. Options: left (default), right, center |
| `fillChar` | Specifies a character to fill extra space in the text entry with. Defaults to an empty space |
## Example
![Example](../../assets/images/edit_text_view_example1.gif "Edit Text View")
<details>
<summary>Configuration fragment (expand to view)</summary>
<div markdown="1">
```
ET1: {
maxLength: @config:users.usernameMax
argName: username
focus: true
}
```
</div>
</details>

View file

@ -0,0 +1,240 @@
---
layout: page
title: Full Menu View
---
## Full Menu View
A full menu view supports displaying a list of times on a screen in a very configurable manner. A full menu view supports either a single row or column of values, similar to Horizontal Menu (HM) and Vertical Menu (VM), or in multiple columns.
## General Information
Items can be selected on a menu via the cursor keys, Page Up, Page Down, Home, and End, or by selecting them via a `hotKey` - see ***Hot Keys*** below.
:information_source: A full menu view is defined with a percent (%) and the characters FM, followed by the view number. For example: `%FM1`
:information_source: See [MCI](../mci.md) for general information on how to use views and common configuration properties available for them.
### Properties
| Property | Description |
|-------------|--------------|
| `textStyle` | Sets the standard (non-focus) text style. See **Text Styles** in [MCI](../mci.md) |
| `focusTextStyle` | Sets focus text style. See **Text Styles** in [MCI](../mci.md)|
| `itemSpacing` | Used to separate items vertically in the menu |
| `itemHorizSpacing` | Used to separate items horizontally in the menu |
| `height` | Sets the height of views to display multiple items vertically (default 1) |
| `width` | Sets the width of a view to display one or more columns horizontally (default 15)|
| `focus` | If set to `true`, establishes initial focus |
| `submit` | If set to `true` any `accept` action upon this view will submit the encompassing **form** |
| `hotKeys` | Sets hot keys to activate specific items. See **Hot Keys** below |
| `hotKeySubmit` | Set to submit a form on hotkey selection |
| `argName` | Sets the argument name for this selection in the form |
| `justify` | Sets the justification of each item in the list. Options: left (default), right, center |
| `itemFormat` | Sets the format for a list entry. See **Entry Formatting** in [MCI](../mci.md) |
| `fillChar` | Specifies a character to fill extra space in the menu with. Defaults to an empty space |
| `textOverflow` | If a single column cannot be displayed due to `width`, set overflow characters. See **Text Overflow** below |
| `items` | List of items to show in the menu. See **Items** below.
| `focusItemFormat` | Sets the format for a focused list entry. See **Entry Formatting** in [MCI](../mci.md) |
### Hot Keys
A set of `hotKeys` are used to allow the user to press a character on the keyboard to select that item, and optionally submit the form.
Example:
```
hotKeys: { A: 0, B: 1, C: 2, D: 3 }
hotKeySubmit: true
```
This would select and submit the first item if `A` is typed, second if `B`, etc.
### Items
A full menu, similar to other menus, take a list of items to display in the menu. For example:
```
items: [
{
text: First Item
data: first
}
{
text: Second Item
data: second
}
]
```
If the list is for display only (there is no form action associated with it) you can omit the data element, and include the items as a simple list:
```
["First item", "Second item", "Third Item"]
```
### Text Overflow
The `textOverflow` option is used to specify what happens when a text string is too long to fit in the `width` defined. Note, because columns are automatically calculated, this can only occur when the text is too long to fit the `width` using a single column.
:information_source: If `textOverflow` is not specified at all, a menu can become wider than the `width` if needed to display a single column.
:information_source: Setting `textOverflow` to an empty string `textOverflow: ""` will cause the item to be truncated if necessary without any characters displayed
:information_source: Otherwise, setting `textOverflow` to one or more characters will truncate the value if necessary and display those characters at the end. i.e. `textOverflow: ...`
## Examples
### A simple vertical menu - similar to VM
![Example](../../assets/images/full_menu_view_example1.gif "Vertical menu")
<details>
<summary>Configuration fragment (expand to view)</summary>
<div markdown="1">
```
FM1: {
submit: true
argName: navSelect
width: 1
items: [
{
text: login
data: login
}
{
text: apply
data: new user
}
{
text: about
data: about
}
{
text: log off
data: logoff
}
]
}
```
</div>
</details>
### A simple horizontal menu - similar to HM
![Example](../../assets/images/full_menu_view_example2.gif "Horizontal menu")
<details>
<summary>Configuration fragment (expand to view)</summary>
<div markdown="1">
```
FM2: {
focus: true
height: 1
width: 60 // set as desired
submit: true
argName: navSelect
items: [
"prev", "next", "details", "toggle queue", "rate", "help", "quit"
]
}
```
</div>
</details>
### A multi-column navigation menu with hotkeys
![Example](../../assets/images/full_menu_view_example3.gif "Multi column menu")
<details>
<summary>Configuration fragment (expand to view)</summary>
<div markdown="1">
```
FM1: {
focus: true
height: 6
width: 60
submit: true
argName: navSelect
hotKeys: { M: 0, E: 1, D: 2 ,F: 3,!: 4, A: 5, C: 6, Y: 7, S: 8, R: 9, O: 10, L:11, U:12, W: 13, B:14, G:15, T: 16, Q:17 }
hotKeySubmit: true
items: [
{
text: M) message area
data: message
}
{
text: E) private email
data: email
}
{
text: D) doors
data: doors
}
{
text: F) file base
data: files
}
{
text: !) global newscan
data: newscan
}
{
text: A) achievements
data: achievements
}
{
text: C) configuration
data: config
}
{
text: Y) user stats
data: userstats
}
{
text: S) system stats
data: systemstats
}
{
text: R) rumorz
data: rumorz
}
{
text: O) onelinerz
data: onelinerz
}
{
text: L) last callers
data: callers
}
{
text: U) user list
data: userlist
}
{
text: W) whos online
data: who
}
{
text: B) bbs list
data: bbslist
}
{
text: G) node-to-node messages
data: nodemessages
}
{
text: T) multi relay chat
data: mrc
}
{
text: Q) quit
data: quit
}
]
}
```
</div>
</details>

View file

@ -0,0 +1,91 @@
---
layout: page
title: Horizontal Menu View
---
## Horizontal Menu View
A horizontal menu view supports displaying a list of times on a screen horizontally (side to side, in a single row) similar to a lightbox.
## General Information
Items can be selected on a menu via the cursor keys, Page Up, Page Down, Home, and End, or by selecting them via a `hotKey` - see ***Hot Keys*** below.
:information_source: A horizontal menu view is defined with a percent (%) and the characters HM, followed by the view number (if used.) For example: `%HM1`
:information_source: See [MCI](../mci.md) for general information on how to use views and common configuration properties available for them.
### Properties
| Property | Description |
|-------------|--------------|
| `textStyle` | Sets the standard (non-focus) text style. See **Text Styles** in [MCI](../mci.md) |
| `focusTextStyle` | Sets focus text style. See **Text Styles** in [MCI](../mci.md)|
| `itemSpacing` | Used to separate items horizontally in the menu |
| `width` | Sets the width of a view to display one or more columns horizontally (default 15)|
| `focus` | If set to `true`, establishes initial focus |
| `submit` | If set to `true` any `accept` action upon this view will submit the encompassing **form** |
| `hotKeys` | Sets hot keys to activate specific items. See **Hot Keys** below |
| `hotKeySubmit` | Set to submit a form on hotkey selection |
| `argName` | Sets the argument name for this selection in the form |
| `justify` | Sets the justification of each item in the list. Options: left (default), right, center |
| `itemFormat` | Sets the format for a list entry. See **Entry Formatting** in [MCI](../mci.md) |
| `fillChar` | Specifies a character to fill extra space in the menu with. Defaults to an empty space |
| `items` | List of items to show in the menu. See **Items** below.
| `focusItemFormat` | Sets the format for a focused list entry. See **Entry Formatting** in [MCI](../mci.md) |
### Hot Keys
A set of `hotKeys` are used to allow the user to press a character on the keyboard to select that item, and optionally submit the form.
Example:
```
hotKeys: { A: 0, B: 1, C: 2, D: 3 }
hotKeySubmit: true
```
This would select and submit the first item if `A` is typed, second if `B`, etc.
### Items
A horizontal menu, similar to other menus, take a list of items to display in the menu. For example:
```
items: [
{
text: First Item
data: first
}
{
text: Second Item
data: second
}
]
```
If the list is for display only (there is no form action associated with it) you can omit the data element, and include the items as a simple list:
```
["First item", "Second item", "Third Item"]
```
## Example
![Example](../../assets/images/horizontal_menu_view_example1.gif "Horizontal menu")
<details>
<summary>Configuration fragment (expand to view)</summary>
<div markdown="1">
```
HM2: {
focus: true
width: 60 // set as desired
submit: true
argName: navSelect
items: [
"prev", "next", "details", "toggle queue", "rate", "help", "quit"
]
}
```
</div>
</details>

View file

@ -0,0 +1,64 @@
---
layout: page
title: Mask Edit Text View
---
## Mask Edit Text View
A mask edit text view supports editing form values on a screen. This can be for new entry as well as editing existing values. Unlike a edit text view, the mask edit text view uses a mask pattern to specify what format the values should be entered in.
## General Information
:information_source: A mask edit text view is defined with a percent (%) and the characters ME, followed by the view number. For example: `%ME1`. This is generally used on a form in order to allow a user to enter or edit a text value.
:information_source: See [MCI](../mci.md) for general information on how to use views and common configuration properties available for them.
### Properties
| Property | Description |
|-------------|--------------|
| `textStyle` | Sets the standard (non-focus) text style. See **Text Styles** in [MCI](../mci.md) |
| `focusTextStyle` | Sets the focus text style. See **Text Styles** in [MCI](../mci.md) |
| `argName` | Sets the argument name for this value in the form |
| `maxLength` | Sets the maximum number of characters that can be entered. *Not normally useful, set the mask pattern as needed instead* |
| `focus` | Set to true to capture initial focus |
| `maskPattern` | Sets the mask pattern. See **Mask Pattern** below |
| `fillChar` | Specifies a character to fill extra space in the text entry with. Defaults to an empty space |
### Mask Pattern
A `maskPattern` must be set on a mask edit text view (not doing so will cause the view to be focusable, but no text can be input). The `maskPattern` is a set of characters used to define input, as well as optional literal characters that can be entered into the pattern that will always be entered into the input. The following mask characters are supported:
| Mask Character | Description |
|----------------|--------------|
| # | Numeric input, one of 0 through 9 |
| A | Alphabetic, one of a through z or A through Z |
| @ | Alphanumeric, matches one of either Numeric or Alphabetic above |
| & | Printable, matches one printable character including spaces |
Any value other than the entries above is treated like a literal value to be displayed in the patter. Multiple pattern characters are combined for longer inputs. Some examples could include:
| Pattern | Description |
|---------|--------------|
| `AA` | Matches up to two alphabetic characters, for example a state name (i.e. "CA") |
| `###` | Matches up to three numeric characters, for example an age (i.e. 25) |
| `###-###-####` | A pattern matching a phone number with area code |
| `##/##/####` | Matches a date of type month/day/year or day/month/year (i.e. 01/01/2000) |
| `##-AAA-####` | Matches a date of type day-month-year (i.e. 01-MAR-2010) |
| `# foot ## inches`| Matches a height in feet and inches (i.e. 6 foot 2 inches) |
## Example
![Example](../../assets/images/mask_edit_text_view_example1.gif "Masked Text Edit View")
<details>
<summary>Configuration fragment (expand to view)</summary>
<div markdown="1">
```
ME1: {
argName: height
fillChar: "#"
maskPattern: "# ft. ## in."
}
```
</div>
</details>

View file

@ -0,0 +1,53 @@
---
layout: page
title: Multi Line Edit Text View
---
## Multi Line Edit Text View
A text display / editor designed to edit or display a message.
## General Information
:information_source: A multi line edit text view is defined with a percent (%) and the characters MT, followed by the view number. For example: `%MT1`
:information_source: See [MCI](../mci.md) for general information on how to use views and common configuration properties available for them.
### Properties
| Property | Description |
|-------------|--------------|
| `text` | Sets the text to display - only useful for read-only and preview, otherwise use a specific module |
| `width` | Sets the width of a view to display horizontally (default 15) |
| `height` | Sets the height of a view to display vertically |
| `argName` | Sets the argument name for the form |
| `mode` | One of edit, preview, or read-only. See **Mode** below |
### Mode
The mode of a multi line edit text view controls how the view behaves. The following modes are allowed:
| Mode | Description |
|-------------|--------------|
| edit | edit the contents of the view |
| preview | preview the text, including scrolling |
| read-only | No scrolling or editing the view |
:information_source: If `mode` is not set, the default mode is "edit"
:information_source: With mode preview, scrolling the contents is allowed, but is not with read-only.
## Example
![Example](../../assets/images/multi_line_edit_text_view_example1.gif "Multi Line Edit Text View")
<details>
<summary>Configuration fragment (expand to view)</summary>
<div markdown="1">
```
ML1: {
width: 79
argName: message
mode: edit
}
```
</div>
</details>

View file

@ -0,0 +1,49 @@
---
layout: page
title: Predefined Label View
---
## Predefined Label View
A predefined label view supports displaying a predefined MCI label on a screen.
## General Information
:information_source: A predefined label view is defined with a percent (%) and the characters PL, followed by the view number and then the predefined MCI value in parenthesis. For example: `%PL1(VL)` to display the Version Label. *NOTE*: this is an alternate way of placing MCI codes, as the MCI can also be placed on the art page directly with the code. For example `%VL`. The difference between these is that the PL version can have additional formatting options applied to it.
:information_source: See *Predefined Codes* in [MCI](../mci.md) for the list of available MCI codes.
:information_source: See [MCI](../mci.md) for general information on how to use views and common configuration properties available for them.
### Properties
| Property | Description |
|-------------|--------------|
| `textStyle` | Sets the standard (non-focus) text style. See **Text Styles** in [MCI](../mci.md) |
| `justify` | Sets the justification of the MCI value text. Options: left (default), right, center |
| `fillChar` | Specifies a character to fill extra space in the view. Defaults to an empty space |
| `width` | Specifies the width that the value should be displayed in (default 3) |
| `textOverflow` | If the MCI is wider than width, set overflow characters. See **Text Overflow** below |
### Text Overflow
The `textOverflow` option is used to specify what happens when a predefined MCI string is too long to fit in the `width` defined.
:information_source: If `textOverflow` is not specified at all, a predefined label view can become wider than the `width` if needed to display the MCI value.
:information_source: Setting `textOverflow` to an empty string `textOverflow: ""` will cause the item to be truncated if necessary without any characters displayed
:information_source: Otherwise, setting `textOverflow` to one or more characters will truncate the value if necessary and display those characters at the end. i.e. `textOverflow: ...`
## Example
![Example](../../assets/images/predefined_label_view_example1.png "Predefined label")
<details>
<summary>Configuration fragment (expand to view)</summary>
<div markdown="1">
```
PL1: {
textStyle: upper
}
```
</div>
</details>

View file

@ -0,0 +1,104 @@
---
layout: page
title: Spinner Menu View
---
## Spinner Menu View
A spinner menu view supports displaying a set of times on a screen as a list, with one item displayed at a time. This is generally used to pick one option from a list. Some examples could include selecting from a list of states, themes, etc.
## General Information
Items can be selected on a menu via the cursor keys or by selecting them via a `hotKey` - see ***Hot Keys*** below.
:information_source: A spinner menu view is defined with a percent (%) and the characters SM, followed by the view number (if used.) For example: `%SM1`
:information_source: See [MCI](../mci.md) for general information on how to use views and common configuration properties available for them.
### Properties
| Property | Description |
|-------------|--------------|
| `textStyle` | Sets the standard (non-focus) text style. See **Text Styles** in [MCI](../mci.md) |
| `focusTextStyle` | Sets focus text style. See **Text Styles** in [MCI](../mci.md)|
| `focus` | If set to `true`, establishes initial focus |
| `width` | Sets the width of a view on the display (default 15)|
| `submit` | If set to `true` any `accept` action upon this view will submit the encompassing **form** |
| `hotKeys` | Sets hot keys to activate specific items. See **Hot Keys** below |
| `hotKeySubmit` | Set to submit a form on hotkey selection |
| `argName` | Sets the argument name for this selection in the form |
| `justify` | Sets the justification of each item in the list. Options: left (default), right, center |
| `itemFormat` | Sets the format for a list entry. See **Entry Formatting** in [MCI](../mci.md) |
| `fillChar` | Specifies a character to fill extra space in the menu with. Defaults to an empty space |
| `items` | List of items to show in the menu. See **Items** below.
| `focusItemFormat` | Sets the format for a focused list entry. See **Entry Formatting** in [MCI](../mci.md) |
### Hot Keys
A set of `hotKeys` are used to allow the user to press a character on the keyboard to select that item, and optionally submit the form.
Example:
```
hotKeys: { A: 0, B: 1, C: 2, D: 3 }
hotKeySubmit: true
```
This would select and submit the first item if `A` is typed, second if `B`, etc.
### Items
A spinner menu, similar to other menus, take a list of items to display in the menu. For example:
```
items: [
{
text: First Item
data: first
}
{
text: Second Item
data: second
}
]
```
If the list is for display only (there is no form action associated with it) you can omit the data element, and include the items as a simple list:
```
["First item", "Second item", "Third Item"]
```
## Example
![Example](../../assets/images/spinner_menu_view_example1.gif "Spinner menu")
<details>
<summary>Configuration fragment (expand to view)</summary>
<div markdown="1">
```
SM1: {
submit: true
argName: themeSelect
items: [
{
text: Light
data: light
}
{
text: Dark
data: dark
}
{
text: Rainbow
data: rainbow
}
{
text: Gruvbox
data: gruvbox
}
]
}
```
</div>
</details>

View file

@ -0,0 +1,48 @@
---
layout: page
title: Text View
---
## Text View
A text label view supports displaying simple text on a screen.
## General Information
:information_source: A text label view is defined with a percent (%) and the characters TL, followed by the view number. For example: `%TL1`
:information_source: See [MCI](../mci.md) for general information on how to use views and common configuration properties available for them.
### Properties
| Property | Description |
|-------------|--------------|
| `text` | Sets the text to display on the label |
| `textStyle` | Sets the standard (non-focus) text style. See **Text Styles** in [MCI](../mci.md) |
| `width` | Sets the width of a view to display horizontally (default 15)|
| `justify` | Sets the justification of the text in the view. Options: left (default), right, center |
| `fillChar` | Specifies a character to fill extra space in the view with. Defaults to an empty space |
| `textOverflow` | Set overflow characters to display in case the text length is less than the width. See **Text Overflow** below |
### Text Overflow
The `textOverflow` option is used to specify what happens when a text string is too long to fit in the `width` defined.
:information_source: If `textOverflow` is not specified at all, a text label can become wider than the `width` if needed to display the text value.
:information_source: Setting `textOverflow` to an empty string `textOverflow: ""` will cause the item to be truncated if necessary without any characters displayed
:information_source: Otherwise, setting `textOverflow` to one or more characters will truncate the value if necessary and display those characters at the end. i.e. `textOverflow: ...`
## Example
![Example](../../assets/images/text_label_view_example1.png "Text label")
<details>
<summary>Configuration fragment (expand to view)</summary>
<div markdown="1">
```
TL1: {
text: Text label
}
```
</div>
</details>

View file

@ -0,0 +1,83 @@
---
layout: page
title: Toggle Menu View
---
## Toggle Menu View
A toggle menu view supports displaying a list of options on a screen horizontally (side to side, in a single row) similar to a [Horizontal Menu](horizontal_menu_view.md). It is designed to present one of two choices easily.
## General Information
Items can be selected on a menu via the left and right cursor keys, or by selecting them via a `hotKey` - see ***Hot Keys*** below.
:information_source: A toggle menu view is defined with a percent (%) and the characters TM, followed by the view number (if used.) For example: `%TM1`
:information_source: See [MCI](../mci.md) for general information on how to use views and common configuration properties available for them.
### Properties
| Property | Description |
|-------------|--------------|
| `textStyle` | Sets the standard (non-focus) text style. See **Text Styles** in [MCI](../mci.md) |
| `focusTextStyle` | Sets focus text style. See **Text Styles** in [MCI](../mci.md)|
| `focus` | If set to `true`, establishes initial focus |
| `submit` | If set to `true` any `accept` action upon this view will submit the encompassing **form** |
| `hotKeys` | Sets hot keys to activate specific items. See **Hot Keys** below |
| `hotKeySubmit` | Set to submit a form on hotkey selection |
| `argName` | Sets the argument name for this selection in the form |
| `items` | List of items to show in the menu. Must include exactly two (2) items. See **Items** below. |
### Hot Keys
A set of `hotKeys` are used to allow the user to press a character on the keyboard to select that item, and optionally submit the form.
Example:
```
hotKeys: { A: 0, B: 1, Q: 1 }
hotKeySubmit: true
```
This would select and submit the first item if `A` is typed, second if `B`, etc.
### Items
A toggle menu, similar to other menus, take a list of items to display in the menu. Unlike other menus, however, there must be exactly two items in a toggle menu. For example:
```
items: [
{
text: First Item
data: first
}
{
text: Second Item
data: second
}
]
```
If the list is for display only (there is no form action associated with it) you can omit the data element, and include the items as a simple list:
```
["First item", "Second item"]
```
## Example
![Example](../../assets/images/toggle_menu_view_example1.gif "Toggle menu")
<details>
<summary>Configuration fragment (expand to view)</summary>
<div markdown="1">
```
TM2: {
focus: true
submit: true
argName: navSelect
focusTextStyle: upper
items: [ "yes", "no" ]
}
```
</div>
</details>

View file

@ -0,0 +1,106 @@
---
layout: page
title: Vertical Menu View
---
## Vertical Menu View
A vertical menu view supports displaying a list of times on a screen vertically in a single column, similar to a lightbar. This type of control is often useful for lists of items or menu controls.
## General Information
Items can be selected on a menu via the cursor keys, Page Up, Page Down, Home, and End, or by selecting them via a `hotKey` - see ***Hot Keys*** below.
:information_source: A vertical menu view is defined with a percent (%) and the characters VM, followed by the view number (if used.) For example: `%VM1`.
:information_source: See [MCI](../mci.md) for general information on how to use views and common configuration properties available for them.
### Properties
| Property | Description |
|-------------|--------------|
| `textStyle` | Sets the standard (non-focus) text style. See **Text Styles** in [MCI](../mci.md) |
| `focusTextStyle` | Sets focus text style. See **Text Styles** in [MCI](../mci.md)|
| `itemSpacing` | Used to separate items vertically in the menu |
| `height` | Sets the height of views to display multiple items vertically (default 1) |
| `focus` | If set to `true`, establishes initial focus |
| `submit` | If set to `true` any `accept` action upon this view will submit the encompassing **form** |
| `hotKeys` | Sets hot keys to activate specific items. See **Hot Keys** below |
| `hotKeySubmit` | Set to submit a form on hotkey selection |
| `argName` | Sets the argument name for this selection in the form |
| `justify` | Sets the justification of each item in the list. Options: left (default), right, center |
| `itemFormat` | Sets the format for a list entry. See **Entry Formatting** in [MCI](../mci.md) |
| `fillChar` | Specifies a character to fill extra space in the menu with. Defaults to an empty space |
| `items` | List of items to show in the menu. See **Items** below.
| `focusItemFormat` | Sets the format for a focused list entry. See **Entry Formatting** in [MCI](../mci.md) |
### Hot Keys
A set of `hotKeys` are used to allow the user to press a character on the keyboard to select that item, and optionally submit the form.
Example:
```
hotKeys: { A: 0, B: 1, C: 2, D: 3 }
hotKeySubmit: true
```
This would select and submit the first item if `A` is typed, second if `B`, etc.
### Items
A vertical menu, similar to other menus, take a list of items to display in the menu. For example:
```
items: [
{
text: First Item
data: first
}
{
text: Second Item
data: second
}
]
```
If the list is for display only (there is no form action associated with it) you can omit the data element, and include the items as a simple list:
```
["First item", "Second item", "Third Item"]
```
## Example
![Example](../../assets/images/vertical_menu_view_example1.gif "Vertical menu")
<details>
<summary>Configuration fragment (expand to view)</summary>
<div markdown="1">
```
VM1: {
submit: true
argName: navSelect
items: [
{
text: login
data: login
}
{
text: apply
data: new user
}
{
text: about
data: about
}
{
text: log off
data: logoff
}
]
}
```
</div>
</details>

View file

@ -0,0 +1,80 @@
---
layout: page
title: Access Condition System (ACS)
---
## Access Condition System (ACS)
ENiGMA½ uses an Access Condition System (ACS) that is both familiar to oldschool BBS operators and has it's own style. With ACS, SysOp's are able to control access to various areas of the system based on various conditions such as group membership, connection type, etc. Various touch points in the system are configured to allow for `acs` checks. In some cases ACS is a simple boolean check while others (via ACS blocks) allow to define what conditions must be true for certain _rights_ such as `read` and `write` (though others exist as well).
## ACS Codes
The following are ACS codes available as of this writing:
| Code | Condition |
|------|-------------|
| LC | Connection is local |
| AG<i>age</i> | User's age is >= _age_ |
| AS<i>status</i>, AS[_status_,...] | User's account status is _group_ or one of [_group_,...] |
| EC<i>encoding</i> | Terminal encoding is set to _encoding_ where `0` is `CP437` and `1` is `UTF-8` |
| GM[_group_,...] | User belongs to one of [_group_,...] |
| NN<i>node</i>, NN[_node_,...] | Current node is _node_ or one of [_node_,...] |
| NP<i>posts</i> | User's number of message posts is >= _posts_ |
| NC<i>calls</i> | User's number of calls is >= _calls_ |
| SC | Connection is considered secure (SSL, secure WebSockets, etc.) |
| TH<i>height</i> | Terminal height is >= _height_ |
| TW<i>width</i> | Terminal width is >= _width_ |
| TM[_themeId_,...] | User's current theme ID is one of [_themeId_,...] (e.g. `luciano_blocktronics`) |
| TT[_termType_,...] | User's current terminal type is one of [_termType_,...] (`ANSI-BBS`, `utf8`, `xterm`, etc.) |
| ID<i>id</i>, ID[_id_,...] | User's ID is _id_ or oen of [_id_,...] |
| WD<i>weekDay</i>, WD[_weekDay_,...] | Current day of week is _weekDay_ or one of [_weekDay_,...] where `0` is Sunday, `1` is Monday, and so on. |
| AA<i>days</i> | Account is >= _days_ old |
| BU<i>bytes</i> | User has uploaded >= _bytes_ |
| UP<i>uploads</i> | User has uploaded >= _uploads_ files |
| BD<i>bytes</i> | User has downloaded >= _bytes_ |
| DL<i>downloads</i> | User has downloaded >= _downloads_ files |
| NR<i>ratio</i> | User has upload/download count ratio >= _ratio_ |
| KR<i>ratio</i> | User has a upload/download byte ratio >= _ratio_ |
| PC<i>ratio</i> | User has a post/call ratio >= _ratio_ |
| MM<i>minutes</i> | It is currently >= _minutes_ past midnight (system time) |
| AC<i>achievementCount</i> | User has >= _achievementCount_ achievements |
| AP<i>achievementPoints</i> | User has >= _achievementPoints_ achievement points |
| AF<i>authFactor</i> | User's current *Authentication Factor* is >= _authFactor_. Authentication factor 1 refers to username + password (or PubKey) while factor 2 refers to 2FA such as One-Time-Password authentication. |
| AR<i>authFactorReq</i> | Current user **requires** an Authentication Factor >= _authFactorReq_ |
| PV[_name,_value_] | Checks that the property by _name_ for the current user is exactly _value_. This ACS allows arbitrary user property values to be checked. For example, `PV[message_conf,local]` checks that the user is currently in the "local" message conference.
## ACS Strings
ACS strings are one or more ACS codes in addition to some basic language semantics.
The following logical operators are supported:
* `!` NOT
* `|` OR
* `&` AND (this is the default)
ENiGMA½ also supports groupings using `(` and `)`. Lastly, some ACS codes allow for lists of acceptable values using `[` and `]` — for example, `GM[users,sysops]`.
### Example ACS Strings
* `NC2`: User must have called two more more times for the check to return true (to pass)
* `ID1`: User must be ID 1 (the +op)
* `GM[elite,power]`: User must be a member of the `elite` or `power` user group (they could be both)
* `ID1|GM[co-op]`: User must be ID 1 (SysOp!) or belong to the `co-op` group
* `!TH24`: Terminal height must NOT be 24
## ACS Blocks
Some areas of the system require more than a single ACS string. In these situations an *ACS block* is used to allow for finer grain control. As an example, consider the following file area `acs` block:
```hjson
acs: {
read: GM[users]
write: GM[sysops,co-ops]
download: GM[elite-users]
}
```
All `users` can read (see) the area, `sysops` and `co-ops` can write (upload), and only members of the `elite-users` group can download.
## ACS Touch Points
The following touch points exist in the system. Many more are planned:
* [Message conferences and areas](../messageareas/configuring-a-message-area.md)
* [File base areas](../filebase/first-file-area.md) and [Uploads](../filebase/uploads.md)
* Menus within [Menu HJSON (menu.hjson)](menu-hjson.md)
See the specific areas documentation for information on available ACS checks.

View file

@ -0,0 +1,57 @@
---
layout: page
title: Archivers
---
## Archivers
ENiGMA½ can detect and process various archive formats such as zip and arj for a variety of tasks from file upload processing to EchoMail bundle compress/decompression. The `archives` section of `config.hjson` is used to override defaults, add new handlers, and so on.
Archivers are manged via the `archives:archivers` configuration block of `config.hjson`. Each entry in this section defines an **external archiver** that can be referenced in other sections of `config.hjson` as and in code. Entries define how to `compress`, `decompress` (a full archive), `list`, and `extract` (specific files from an archive).
:bulb: Generally you do not need to anything beyond installing supporting binaries. No `config.hjson` editing necessary; Please see [External Binaries](external-binaries.md)!
### Archiver Configuration
Archiver entries in `config.hjson` are mostly self explanatory with the exception of `list` commands that require some additional information. The `args` member for an entry is an array of arguments to pass to `cmd`. Some variables are available to `args` that will be expanded by the system:
* `{archivePath}` (all): Path to the archive
* `{fileList}` (compress, extract): List of file(s) to compress or extract
* `{extractPath}` (decompress, extract): Path to extract *to*
For `list` commands, the `entryMatch` key must be provided. This key should provide a regular expression that matches two sub groups: One for uncompressed file byte sizes (sub group 1) and the other for file names (sub group 2). An optional `entryGroupOrder` can be supplied to change the default sub group order.
#### Example Archiver Configuration
```
7Zip: {
compress: {
cmd: 7za,
args: [ "a", "-tzip", "{archivePath}", "{fileList}" ]
}
decompress: {
cmd: 7za,
args: [ "e", "-o{extractPath}", "{archivePath}" ]
}
list: {
cmd: 7za,
args: [ "l", "{archivePath}" ]
entryMatch: "^[0-9]{4}-[0-9]{2}-[0-9]{2}\\s[0-9]{2}:[0-9]{2}:[0-9]{2}\\s[A-Za-z\\.]{5}\\s+([0-9]+)\\s+[0-9]+\\s+([^\\r\\n]+)$",
}
extract: {
cmd: 7za,
args [ "e", "-o{extractPath}", "{archivePath}", "{fileList}" ]
}
}
```
## Archive Formats
Archive formats can be defined such that ENiGMA½ can detect them by signature or extension, then utilize the correct *archiver* to process them. Formats are defined in the `archives:formats` key in `config.hjson`. Many differnet types come pre-configured (see `core/config_default.js`).
### Example Archive Format Configuration
```
zip: {
sig: "504b0304" /* byte signature in HEX */
offset: 0
exts: [ "zip" ]
handler: 7Zip /* points to a defined archiver */
desc: "ZIP Archive"
}
```

View file

@ -0,0 +1,23 @@
---
layout: page
title: Colour Codes
---
ENiGMA½ supports Renegade-style pipe colour codes for formatting strings. You'll see them used throughout your configuration, and can also be used in places like onelinerz, rumourz, full screen editor etc.
## Usage
When ENiGMA½ encounters colour codes in strings, they'll be processed in order and combined where possible.
For example:
`|15|17Example` - white text on a blue background
`|10|23Example` - light green text on a light grey background
## Colour Code Reference
:warning: Colour codes |24 to |31 are considered "blinking" or "iCE" colour codes. On terminals that support them they'll
be shown as the correct colours - for terminals that don't, or are that are set to "blinking" mode - they'll blink!
![Renegade style colour codes](../assets/images/colour-codes.png "Colour Codes")

View file

@ -0,0 +1,127 @@
---
layout: page
title: Configuration Files
---
## General Information
ENiGMA½ configuration files such as the [system config](config-hjson.md), [menus](menu-hjson.md) and [themes](../art/themes.md) are formatted in the [HJSON format](hjson.md).
## Hot-Reload
Nearly all of ENiGMA½'s configuration can be hot-reloaded. That is, a live system can have it's configuration modified and it will be loaded in place.
:bulb: [Monitoring live logs](../troubleshooting/monitoring-logs.md) is useful when making live changes. The system will complain if something is wrong!
## Common Directives
### Includes
Most configuration files offer an `includes` directive that allows users to break up large configuration files into smaller and organized parts. For example, consider a system with many menus/screens. Instead of a single `menu.hjson`, the SysOp may break this into `message-base.hjson`, `file-base.hjson`, etc.
The `includes` directive may be used the top-level scope of a configuration file:
```hjson
// menu.hjson
{
includes: [
message-base.hjson
file-base.hjson
]
menus: {
someOtherMenu: {
// ...
}
}
}
```
```hjson
// message-base.hjson
{
menus: {
someMessageMenu: {
// ...
}
}
}
```
### References
Often times in a configuration you will find that you're repeating yourself quite a bit. ENiGMA½ provides an `@reference` that can help with this in the form of `@reference:dot.path.to.section`.
Consider `actionKeys` in a menu. Often times you may show a screen and the user presses `Q` or `ESC` to fall back to the previous. Instead of repeating this in many menus, a generic block can be referenced:
```hjson
{
// note that 'recycle' here is arbitrary;
// only 'menus' and 'prompts' is reserved at this level.
recycle: {
prevMenu: [
{
keys: [ "escape" ]
action: @systemMethod:prevMenu
}
]
}
menus: {
someMenu: {
form: {
0: {
actionKeys: @reference:recycle.prevMenu
}
}
}
}
}
```
:information_source: An unresolved `@reference` will be left intact.
### Environment Variables
Especially in a container environment such as [Docker](../installation/docker.md), environment variable access in configuration files can become very handy. ENiGMA½ provides a flexible way to access variables using the `@environment` directive. The most basic form of `@environment:VAR_NAME` produces a string value. Additionally a `:type` suffix can be supplied to coerece the value to a particular type. Variables pointing to a comma separated list can be turned to arrays using an additional `:array` suffix.
Below is a table of the various forms:
| Form | Variable Value | Produces |
|------|----------------|----------|
| `@environment:SOME_VAR` | "Foo" | `"Foo"` (without quotes) |
| `@environment:SOME_VAR` | "123" | `"123"` (without quotes) |
| `@environment:SOME_VAR:string` | "Bar" | `"Bar"` (without quotes) |
| `@environment:SOME_VAR:string:array` | "Foo,Bar" | `[ 'Foo', 'Bar' ]` |
| `@environment:SOME_VAR:boolean` | "1" | `true` |
| `@environment:SOME_VAR:boolean` | "True" | `true` |
| `@environment:SOME_VAR:boolean` | "false" | `false` |
| `@environment:SOME_VAR:boolean` | "cat" | `false` |
| `@environment:SOME_VAR:boolean:array` | "True,false,TRUE" | `[ true, false, true ]` |
| `@environment:SOME_VAR:number` | "123" | `123` |
| `@environment:SOME_VAR:number:array` | "123,456" | `[ 123, 456 ]` |
| `@environment:SOME_VAR:number` | "kitten" | (invalid) |
| `@environment:SOME_VAR:object` | '{"a":"b"}' | `{ 'a' : 'b' }` |
| `@environment:SOME_VAR:object:array` | '{"a":"b"},{"c":"d"}' | `[ { 'a' : 'b' }, { 'c' : 'd' } ]` |
| `@environment:SOME_VAR:timestamp` | "2020-01-05" | A [moment](https://momentjs.com/) object representing 2020-01-05 |
| `@environment:SOME_VAR:timestamp:array` | "2020-01-05,2016-05-16T01:15:37'" | An array of [moment](https://momentjs.com/) objects representing 2020-01-05 and 2016-05-16T01:15:37 |
:bulb: `bool` may be used as an alias to `boolean`.
:bulb: `timestamp` values can be in any form that [moment can parse](https://momentjs.com/docs/#/parsing/).
:information_source: An unresolved or invalid `@environment` will be left intact.
Consider the following fragment:
```hjson
{
foo: {
bar: @environment:BAR_VAR:number
}
}
```
If the environment has `BAR_VAR=1337`, this would produce:
```hjson
{
foo: {
bar: 1337
}
}
```
## See Also
* [System Configuration](config-hjson.md)
* [Menu Configuration](menu-hjson.md)
* [The HJSON Format](hjson.md)

View file

@ -0,0 +1,50 @@
---
layout: page
title: System Configuration
---
## System Configuration
The main system configuration file, `config.hjson` both overrides defaults and provides additional configuration such as message areas. Defaults lived in `core/config_default.js`.
The default path is `/enigma-bbs/config/config.hjson` though this can be overridden using the `--config` parameter when invoking `main.js`.
:information_source: See also [Configuration Files](config-files.md). Additionally [HJSON General Information](hjson.md) may be helpful for more information on the HJSON format.
### Creating a Configuration
Your initial configuration skeleton should be created using the `oputil.js` command line utility. From your enigma-bbs root directory:
```
./oputil.js config new
```
You will be asked a series of questions to create an initial configuration.
### Overriding Defaults
The file `core/config_default.js` provides various defaults to the system that you can override via `config.hjson`. For example, the default system name is defined as follows:
```javascript
general : {
boardName : 'Another Fine ENiGMA½ System'
}
```
To override this for your own board, in `config.hjson`:
```hjson
general: {
boardName: Super Fancy BBS
}
```
(Note the very slightly [HJSON](hjson.md) different syntax. **You can use standard JSON if you wish!**)
While not everything that is available in your `config.hjson` file can be found defaulted in `core/config_default.js`, a lot is. [Poke around and see what you can find](https://github.com/NuSkooler/enigma-bbs/blob/master/core/config_default.js)!
### Configuration Sections
Below is a list of various configuration sections. There are many more, but this should get you started:
* [ACS](acs.md)
* [Archivers](archivers.md): Set up external archive utilities for handling things like ZIP, ARJ, RAR, and so on.
* [Email](email.md): System email support.
* [Event Scheduler](event-scheduler.md): Set up events as you see fit!
* [File Base](../filebase/index.md)
* [File Transfer Protocols](file-transfer-protocols.md): Oldschool file transfer protocols such as X/Y/Z-Modem!
* [Message Areas](../messageareas/configuring-a-message-area.md), [Networks](../messageareas/message-networks.md), [NetMail](../messageareas/netmail.md), etc.
* ...and a **lot** more! Explore the docs! If you can't find something, please contact us!

View file

@ -0,0 +1,14 @@
---
layout: page
title: Creating Initial Config Files
---
Configuration files in ENiGMA½ are simple UTF-8 encoded [HJSON](http://hjson.org/) files. HJSON is just like JSON but simplified and much more resilient to human error.
## Initial Configuration
Your initial configuration skeleton can be created using the `oputil.js` command line utility. From your enigma-bbs root directory:
```bash
./oputil.js config new
```
You will be asked a series of questions to create an initial configuration, which will be saved to `/enigma-bbs-install-path/config/config.hjson`. This will also produce menu files under `config/menus/`. See [Menu HJSON](menu-hjson.md) for more information.

View file

@ -0,0 +1,22 @@
---
layout: page
title: Directory Structure
---
All paths mentioned here are relative to the ENiGMA½ checkout directory.
| Directory | Description |
|---------------------|-----------------------------------------------------------------------------------------------------------|
| `/art/general` | Non-theme art - welcome ANSI, logoff ANSI, etc. See [General Art]({{ site.baseurl }}{% link _docs/art/general.md %}).
| `/art/themes` | Theme art. Themes should be in their own subdirectory and contain a theme.hjson. See [Themes]({{ site.baseurl }}{% link _docs/art/themes.md %}).
| `/config` | [config.hjson](config-hjson.md) system configuration.
| `/config/menus` | [menu.hjson](menu-hjson.md) storage.
| `/config/security` | SSL certificates and public/private keys.
| `/db` | All ENiGMA½ databases in SQLite3 format.
| `/docs` | These docs ;-)
| `/dropfiles` | Dropfiles created for [local doors]({{ site.baseurl }}{% link _docs/modding/local-doors.md %})
| `/logs` | Logs. See [Monitoring Logs]({{ site.baseurl }}{% link _docs/troubleshooting/monitoring-logs.md %})
| `/misc` | Stuff with no other home; reset password templates, common password lists, other random bits
| `/mods` | User mods. See [Modding]({{ site.baseurl }}{% link _docs/modding/existing-mods.md %})
| `/node_modules` | External libraries required by ENiGMA½, installed when you run `npm install`
| `/util` | Various tools used in running/debugging ENiGMA½
| `/www` | ENiGMA½'s built in webserver root directory

View file

@ -0,0 +1,49 @@
---
layout: page
title: Email
---
## Email Support
ENiGMA½ uses email to send password reset information to users. For it to work, you need to provide valid [Nodemailer](https://nodemailer.com/about/) compatible `email` block in your [config.hjson]({{ site.baseurl }}{% link _docs/configuration/config-hjson.md %}). Nodemailer supports SMTP in addition to many pre-defined services for ease of use. The `transport` block within `email` must be Nodemailer compatible.
Additional email support will come in the near future.
## Services
If you don't have an SMTP server to send from, [Sendgrid](https://sendgrid.com/) and [Zoho](https://www.zoho.com/mail/) both provide reliable and free services.
## Example Configurations
Example 1 - SMTP:
```hjson
email: {
defaultFrom: sysop@bbs.awesome.com
transport: {
host: smtp.awesomeserver.com
port: 587
secure: false
auth: {
user: leisuresuitlarry
pass: sierra123
}
}
}
```
Example 2 - Zoho
```hjson
email: {
defaultFrom: sysop@bbs.awesome.com
transport: {
service: Zoho
auth: {
user: noreply@bbs.awesome.com
pass: yuspymypass
}
}
}
```
## Lockout Reset
If email is available on your system and you allow email-driven password resets, you may elect to allow unlocking accounts at the time of a password reset. This is controlled by the `users.unlockAtEmailPwReset` configuration option. If an account is locked due to too many failed login attempts, a user may reset their password to remedy the situation themselves.

View file

@ -0,0 +1,79 @@
---
layout: page
title: Event Scheduler
---
## Event Scheduler
The ENiGMA½ scheduler allows system operators to configure arbitrary events that can can fire based on date and/or time, or by watching for changes in a file. Events can kick off internal handlers, custom modules, or binaries & scripts.
## Scheduling Events
To create a scheduled event, create a new configuration block in `config.hjson` under `eventScheduler.events`.
Events can have the following members:
| Item | Required | Description |
|------|----------|-------------|
| `schedule` | :+1: | A [Later style](https://bunkat.github.io/later/parsers.html#text) parsable schedule string such as `at 4:00 am`, or `every 24 hours`. Can also be (or contain) an `@watch` clause. See **Schedules** below for details. |
| `action` | :+1: | Action to perform when the schedule is triggered. May be an `@method` or `@execute` spec. See **Actions** below. |
| `args` | :-1: | An array of arguments to pass along to the method or binary specified in `action`. |
### Schedules
As mentioned above, `schedule` may contain a [Later style](https://bunkat.github.io/later/parsers.html#text) parsable schedule string and/or an `@watch` clause.
`schedule` examples:
* `every 2 hours`
* `on the last day of the week`
* `after 12th hour`
An `@watch` clause monitors a specified file for changes and takes the following form: `@watch:<path>` where `<path>` is a fully qualified path.
:bulb: If you would like to have a schedule **and** watch a file for changes, place the `@watch` clause second and separated with the word `or`. For example: `every 24 hours or @watch:/path/to/somefile.txt`.
### Actions
Events can kick off actions by calling a method (function) provided by the system or custom module in addition to executing arbritary binaries or scripts.
#### Methods
An action with a `@method` can take the following forms:
* `@method:/full/path/to/module.js:methodName`: Executes `methodName` at `/full/path/to/module.js`.
* `@method:rel/path/to/module.js:methodName`: Executes `methodName` using the *relative* path `rel/path/to/module.js`. Paths for `@method` are relative to the ENiGMA½ installation directory.
Methods are passed any supplied `args` in the order they are provided.
##### Method Signature
To create your own method, simply `export` a method with the following signature: `(args, callback)`. Methods are executed asynchronously.
Example:
```javascript
// my_custom_mod.js
exports.myCustomMethod = (args, cb) => {
console.log(`Hello, ${args[0]}!`);
return cb(null);
}
```
#### Executables
When using the `@execute` action, a binary or script can be executed. A full path or just the binary name is acceptable. If using the form without a path, the binary much be in ENiGMA½'s `PATH`.
Examples:
* `@execute:/usr/bin/foo`
* `@execute:foo`
Just like with methods, any supplied `args` will be passed along.
## Example Entries
Post a message to supplied networks every Monday night using the message post mod (see modding):
```hjson
eventScheduler: {
events: {
enigmaAdToNetworks: {
schedule: at 10:35 pm on Mon
action: @method:mods/message_post_evt/message_post_evt.js:messagePostEvent
args: [
"fsx_bot"
"/home/enigma-bbs/ad.asc"
]
}
}
}
```

View file

@ -0,0 +1,44 @@
---
layout: page
title: External Support Binaries
---
## External Support Binaries
ENiGMA½ relies on various external binaries in order to perform common tasks such as processing file archives and extracting information from uploads/file imports, some legacy transfer protocols, etc.
:correct: Before using features such as the [File Base](../filebase/index.md) or [File Transfer Protocols](../configuration/file-transfer-protocols.md) it is highly recommended to install support binaries!
## Archivers
Below is a table of pre-configured archivers. Remember that you can override settings or add new handlers! See [Archivers](archivers.md).
| Archiver (Key) | File Types | More Info | Debian/Ubuntu (apt/dep) | Red Hat (yum/rpm) | Windows |
|----------|---------|-----------|-------------------------|-------------------|---------|
| `Arj` | .arj | [Wikipedia](https://en.wikipedia.org/wiki/ARJ) | `arj` | `arj` | [ARJ](http://arj.sourceforge.net/) |
| `7Zip` | .7z, .bzip2, .gzip/.gz, etc.<br>:warning: Does not attempt to handle zip files! See `InfoZip`! | http://www.7-zip.org | `p7zip-full` | `p7zip-full` | [7-zip](http://www.7-zip.org/) |
| `InfoZip` | .zip | http://infozip.sourceforge.net <br>`zip` and `unzip` will need to be en ENiGMA's PATH | `zip` and `unzip` | `zip` and `unzip` | [InfoZip](http://infozip.sourceforge.net/) |
| `Lha` | .lza, .lzh, etc. | [Wikipedia](https://en.wikipedia.org/wiki/LHA_(file_format)) <br> https://fragglet.github.io/lhasa/ | `lhasa` | `lhasa` | [Win32 binaries](https://soulsphere.org/projects/lhasa/win32/) |
| `Lzx` | .lzx | [Amiga LZX](https://en.wikipedia.org/wiki/LZX_(algorithm)#Amiga_LZX) | `unlzx` | `unlzx` | [Source](http://xavprods.free.fr/lzx/) |
| `Rar` | .rar | [Wikipedia](https://en.wikipedia.org/wiki/RAR_(file_format)) | `unrar` | `unrar`| [RARLAB](https://www.rarlab.com/) |
| `TarGz` | .tar.gz, .gzip | [Wikipedia](https://en.wikipedia.org/wiki/Gzip) | `tar` | `tar` | [TAR.EXE](https://ss64.com/nt/tar.html)
:information_source: For more information see `core/config_default.js`
:information_source: For information on changing configuration or adding more archivers see [Archivers](archivers.md).
## File Transfer Protocols
Handlers for legacy file transfer protocols such as Z-Modem and Y-Modem.
| Handler (Key) | Protocol | More Info | Debian/Ubuntu (apt/dep) | Red Hat (yum/rpm) | Windows |
|----------|---------|-----------|-------------------------|-------------------|---------|
| `xmodemSexyz`<br>`ymodemSexyz`<br>`zmodem8kSexyz` | X-Modem, Y-Modem and Z-Modem SEXYZ | [SEXYZ](http://www.synchro.net/docs/sexyz.txt) | [x86_64 Binary](https://l33t.codes/outgoing/sexyz) | [x86_64 Binary](https://l33t.codes/outgoing/sexyz) | [Synchronet FTP](ftp://ftp.synchro.net/) |
| `zmodem8kSz` | Z-Modem 8K | [Wikipedia](https://en.wikipedia.org/wiki/ZMODEM) | `lrzsz` | `lrzsz` | Unknown |
## Information Extractors
Information extraction utilities can extract information from various file types such as PDF in order to (attempt) to come up with a good default description.
| Extractor | File Types | More Info | Debian/Ubuntu (apt/dep) | Red Hat (yum/rpm) | Windows |
|----------|---------|-----------|-------------------------|-------------------|---------|
| ExifTool | .mp3, .pdf, .mp4, .jpg, .gif, .png, many more | [ExifTool](https://www.sno.phy.queensu.ca/~phil/) | `libimage-exiftool-perl` | `perl-Image-ExifTool` | Unknown |
| XDMS | Amiga DiskMasher images | | `xdms` | `xdms` | Unknown

View file

@ -0,0 +1,51 @@
---
layout: page
title: File Transfer Protocols
---
ENiGMA½ currently relies on external executable binaries for "legacy" file transfer protocols such as X, Y, and ZModem. Remember that ENiGMA½ also support modern web (HTTP/HTTPS) downloads!
## File Transfer Protocols
File transfer protocols are managed via the `fileTransferProtocols` configuration block of `config.hjson`. Each entry defines an **external** protocol handler that can be used for uploads (recv), downloads (send), or both. Depending on the protocol and handler, batch receiving of files (uploads) may also be available.
### Predefined File Transfer Protocols
Please see [External Binaries](external-binaries.md) for a table of built in / predefined protocol handlers. You will need to have the binaries in ENiGMA's PATH.
#### SEXYZ
[SEXYZ from Synchronet](http://wiki.synchro.net/util:sexyz) offers a nice X, Y, and ZModem implementation including ZModem-8k & works under *nix and Windows based systems. As of this writing, ENiGMA½ is pre-configured to support ZModem-8k, XModem, and YModem using SEXYZ. An x86_64 Linux binary, and hopefully more in the future, [can be downloaded here](https://l33t.codes/bbs-linux-binaries/).
#### sz/rz
ZModem-8k is configured using the standard Linux [sz(1)](https://linux.die.net/man/1/sz) and [rz(1)](https://linux.die.net/man/1/rz) binaries. Note that these binaries also support XModem and YModem, and as such adding the configurations to your system should be fairly straight forward.
Generally available as `lrzsz` under Apt or Yum type packaging.
### File Transfer Protocol Configuration
The following top-level members are available to an external protocol configuration:
* `name`: Required; Display name of the protocol
* `type`: Required; Currently must be `external`. This will be expanded upon in the future with built in protocols.
* `sort`: Optional; Sort key. If not provided, `name` will be used for sorting.
For protocols of type `external` the following members may be defined:
* `sendCmd`: Required for protocols that can send (allow user downloads); The command/binary to execute.
* `sendArgs`: Required if using `sendCmd`; An array of arguments. A placeholder of `{fileListPath}` may be used to supply a path to a **file containing** a list of files to send, or `{filePaths}` to supply *1:n* individual file paths to send.
* `recvCmd`: Required for protocols that can receive (allow user uploads); The command/binary to execute.
* `recvArgs`: Required if using `recvCmd` and supporting **batch** uploads; An array of arguments. A placeholder of `{uploadDir}` may be used to supply the system provided upload directory. If `{uploadDir}` is not present, the system expects uploaded files to be placed in CWD which will be set to the upload directory.
* `recvArgsNonBatch`: Required if using `recvCmd` and supporting non-batch (single file) uploads; A placeholder of `{fileName}` may be supplied to indicate to the protocol what the uploaded file should be named (this will be collected from the user before the upload starts).
* `escapeTelnet`: Optional; If set to `true`, escape all internal Telnet related codes such as IAC's. This option is required for external protocol handlers such as `sz` and `rz` that do not escape themselves.
### Adding Your Own
Take a look a the example below as well as [core/config_default.js](/core/config_default.js).
#### Example File Transfer Protocol Configuration
```
zmodem8kSexyz : {
name : 'ZModem 8k (SEXYZ)',
type : 'external',
sort : 1,
external : {
sendCmd : 'sexyz',
sendArgs : [ '-telnet', '-8', 'sz', '@{fileListPath}' ],
recvCmd : 'sexyz',
recvArgs : [ '-telnet', '-8', 'rz', '{uploadDir}' ],
recvArgsNonBatch : [ '-telnet', '-8', 'rz', '{fileName}' ],
}
}
```

View file

@ -0,0 +1,70 @@
---
layout: page
title: HJSON Config Files
---
## JSON for Humans!
HJSON is the configuration file format used by ENiGMA½ for [System Configuration](config-hjson.md), [Menus](menu-hjson.md), etc. [HJSON](https://hjson.org/) is is [JSON](https://json.org/) for humans!
For those completely unfamiliar, JSON stands for JavaScript Object Notation. But don't let that scare you! JSON is simply a text file format with a bit of structure ― kind of like a fancier INI file. HJSON on the other hand as mentioned previously, is JSON for humans. That is, it has the following features and more:
* More resilient to syntax errors such as missing a comma
* Strings generally do not need to be quoted. Multi-line strings are also supported!
* Comments are supported (JSON doesn't allow this!): `#`, `//` and `/* ... */` style comments are allowed.
* Keys never need to be quoted
* ...much more! See [the official HJSON website](https://hjson.org/).
## Terminology
Through the documentation, some terms regarding HJSON and configuration files will be used:
* `config.hjson`: Refers to `/path/to/enigma-bbs/config/config.hjson`. See [System Configuration](config-hjson.md).
* `menu.hjson`: Refers to `/path/to/enigma-bbs/config/<yourBBSName>-menu.hjson`. See [Menus](menu-hjson.md).
* Configuration *key*: Elements in HJSON are name-value pairs where the name is the *key*. For example, provided `foo: bar`, `foo` is the key.
* Configuration *section* or *block* (also commonly called an "Object" in code): This is referring to a section in a HJSON file that starts with a *key*. For example:
```hjson
someSection: {
foo: bar
}
```
Note that `someSection` is the configuration *section* (or *block*) and `foo: bar` is within it.
## Editing HJSON
HJSON is a text file format, and ENiGMA½ configuration files **should always be saved as UTF-8**.
It is **highly** recommended to use a text editor that has HJSON support. A few (but not all!) examples include:
* [Sublime Text](https://www.sublimetext.com/) via the `sublime-hjson` package.
* [Visual Studio Code](https://code.visualstudio.com/) via the `vscode-hjson` plugin.
* [Notepad++](https://notepad-plus-plus.org) via the `npp-hjson` plugin.
See https://hjson.org/users.html for more more editors & plugins.
### Hot-Reload A.K.A. Live Editing
ENiGMA½'s configuration, menu, and theme files can edited while your BBS is running. When a file is saved, it is hot-reloaded into the running system. If users are currently connected and you change a menu for example, the next reload of that menu will show the changes.
:information_source: See also [Configuration Files](../configuration/config-files.md)
### CaSe SeNsiTiVE
Configuration keys are **case sensitive**. That means if a configuration key is `boardName` for example, `boardname`, or `BOARDNAME` **will not work**.
### Escaping
Some values need escaped. This is especially important to remember on Windows machines where file paths contain backslashes (`\`). To specify a path to `C:\foo\bar\baz.exe` for example, an entry may look like this in your configuration file:
```hjson
something: {
path: "C:\\foo\\bar\\baz.exe" // note the extra \'s!
}
```
## Tips & Tricks
### JSON Compatibility
Remember that standard JSON is fully compatible with HJSON. If you are more comfortable with JSON (or have an editor that works with JSON that you prefer) simply convert your config file(s) to JSON and use that instead!
HJSON can be converted to JSON with the `hjson` CLI:
```bash
cd /path/to/enigma-bbs
cp ./config/config.hjson ./config/config.hjson.backup
./node_modules/hjson/bin/hjson ./config/config.hjson.backup -j > ./config/config.hjson
```
You can always convert back to HJSON by omitting `-j` in the command above.
### oputil
You can easily dump out your current configuration in a pretty-printed style using oputil: ```./oputil.js config cat```

View file

@ -0,0 +1,364 @@
---
layout: page
title: Menu HSJON
---
## Menu HJSON
The core of a ENiGMA½ based BBS is it's menus driven by what will be referred to as `menu.hjson`. Throughout ENiGMA½ documentation, when `menu.hjson` is referenced, we're actually talking about `config/menus/yourboardname-*.hjson`. These files determine the menus (or screens) a user can see, the order they come in, how they interact with each other, ACS configuration, and so on. Like all configuration within ENiGMA½, menu configuration is done in [HJSON](https://hjson.org/) format.
:information_source: See also [HJSON General Information](hjson.md) for more information on the HJSON file format.
:bulb: Entries in `menu.hjson` are often referred to as *blocks* or *sections*. Each entry defines a menu. A menu in this sense is something the user can see or visit. Examples include but are not limited to:
* Classical navigation and menus such as Main, Messages, and Files.
* Art file display.
* Module driven menus such as [door launchers](../modding/local-doors.md), [Onelinerz](../modding/onelinzerz.md), and other custom mods.
Menu entries live under the `menus` section of `menu.hjson`. The *key* for a menu is it's name that can be referenced by other menus and areas of the system.
Below is a very basic menu entry called `showSomeArt` that displays some art then returns to the previous menu after the user hits a key:
```hjson
showSomeArt: {
art: someart.ans
config: { pause: true }
}
```
As you can see a menu can be very simple.
:information_source: Remember that the top level menu may include additional files using the `includes` directive. See [Configuration Files](config-files.md) for more information on this.
## Common Menu Entry Members
Below is a table of **common** menu entry members. These members apply to most entries, though entries that are backed by a specialized module (ie: `module: bbs_list`) may differ. Menus that use their own module contain a `module` declaration:
```hjson
module: some_fancy_module
```
See documentation for the module in question for particulars.
| Item | Description |
|--------|--------------|
| `desc` | A friendly description that can be found in places such as "Who's Online" or wherever the `%MD` MCI code is used. |
| `art` | An art file *spec*. See [General Art Information](../art/general.md). |
| `next` | Specifies the menu to go to next. Can be explicit or an array of possibilities dependent on ACS. See **Flow Control** in the **ACS Checks** section below. If `next` is not supplied, the next menu is this menus parent. Note that special built in methods such as `@systemMethod:logoff` can also be utilized here. |
| `prompt` | Specifies a prompt, by name, to use along with this menu. Prompts are configured in the `prompts` section. See **Prompts** for more information. |
| `submit` | Defines a submit handler when using `prompt`.
| `form` | An object defining one or more *forms* available on this menu. |
| `module` | Sets the module name to use for this menu. The system ships with many build in modules or you can build your own! |
| `config` | An object containing additional configuration. See **Config Block** below. |
### Config Block
The `config` block for a menu entry can contain common members as well as a per-module (when `module` is used) settings.
| Item | Description |
|------|-------------|
| `cls` | If `true` the screen will be cleared before showing this menu. |
| `pause` | If `true` a pause will occur after showing this menu. Useful for simple menus such as displaying art or status screens. |
| `nextTimeout` | Sets the number of **milliseconds** before the system will automatically advanced to the `next` menu. |
| `baudRate` | See baud rate information in [General Art Information](../art/general.md). |
| `font` | Sets a SyncTERM style font to use when displaying this menus `art`. See font listing in [General Art Information](../art/general.md). |
| `menuFlags` | An array of menu flag(s) controlling menu behavior. See **Menu Flags** below.
#### Menu Flags
The `menuFlags` field of a `config` block can change default behavior of a particular menu.
| Flag | Description |
|------|-------------|
| `noHistory` | Prevents the menu from remaining in the menu stack / history. When this flag is set, when the **next** menu falls back, this menu will be skipped and the previous menu again displayed instead. Example: menuA -> menuB(noHistory) -> menuC: Exiting menuC returns the user to menuA. |
| `popParent` | When *this* menu is exited, fall back beyond the parent as well. Often used in combination with `noHistory`. |
| `forwardArgs` | If set, when the next menu is entered, forward any `extraArgs` arguments to *this* menu on to it. |
## Forms
ENiGMA½ uses a concept of *forms* in menus. A form is a collection of associated *views*. Consider a New User Application using the `nua` module: The default implementation utilizes a single form with multiple EditTextView views, a submit button, etc. Forms are identified by number starting with `0`. A given menu may have mutiple forms (often associated with different states or screens within the menu).
Menus may also support more than one layout type by using a *MCI key*. A MCI key is a alpha-numerically sorted key made from 1:n MCI codes. This lets the system choose the appropriate set of form(s) based on theme or random art. An example of this may be a matrix menu: Perhaps one style of your matrix uses a vertical light bar (`VM` key) while another uses a horizontal (`HM` key). The system can discover the correct form to use by matching MCI codes found in the art to that of the available forms defined in `menu.hjson`.
For more information on views and associated MCI codes, see [MCI Codes](../art/mci.md).
## Submit Handlers
When a form is submitted, it's data is matched against a *submit handler*. When a match is found, it's *action* is performed.
### Submit Actions
Submit actions are declared using the `action` member of a submit handler block. Actions can be kick off system/global or local-to-module methods, launch other menus, etc.
| Action | Description |
|--------|-------------|
| `@menu:menuName` | Takes the user to the *menuName* menu |
| `@systemMethod:methodName` | Executes the system/global method *methodName*. See **System Methods** below. |
| `@method:methodName` | Executes *methodName* local to the calling module. That is, the module set by the `module` member of a menu entry. |
| `@method:/path/to/some_module.js:methodName` | Executes *methodName* exported by the module at */path/to/some_module.js*. |
#### Advanced Action Handling
In addition to simple simple actions, `action` may also be:
* An array of objects containing ACS checks and a sub `action` if that ACS is matched. See **Action Matches** in the ACS documentation below for details.
* An array of actions. In this case a random selection will be made. Example:
```hjson
submit: [
{
value: { command: "FOO" }
action: [
// one of the following actions will be matched:
"@menu:menuStyle1"
"@menu:menuStyle2"
]
}
]
```
#### Method Signature
Methods executed using `@method`, or `@systemMethod` have the following signature:
```
(callingMenu, formData, extraArgs, callback)
```
#### System Methods
Many built in global/system methods exist. Below are a few. See [system_menu_method](/core/system_menu_method.js) for more information.
| Method | Description |
|--------|-------------|
| `login` | Performs a standard login. |
| `login2FA_OTP` | Performs a 2-Factor Authentication (2FA) One-Time Password (OTP) check, if configured for the user. |
| `logoff` | Performs a standard system logoff. |
| `prevMenu` | Goes to the previous menu. |
| `nextMenu` | Goes to the next menu (as set by `next`) |
| `prevConf` | Sets the users message conference to the previous available. |
| `nextConf` | Sets the users message conference to the next available. |
| `prevArea` | Sets the users message area to the previous available. |
| `nextArea` | Sets the users message area to the next available. |
## Example
Let's look a couple basic menu entries:
```hjson
telnetConnected: {
art: CONNECT
next: matrix
config: { nextTimeout: 1500 }
}
```
The above entry `telnetConnected` is set as the Telnet server's first menu entry (set by `firstMenu` in the Telnet server's config). The entry sets up a few things:
* A `art` spec of `CONNECT`. (See [General Art Information](../art/general.md)).
* A `next` entry up the next menu, by name, in the stack (`matrix`) that we'll go to after `telnetConnected`.
* An `config` block containing a single `nextTimeout` field telling the system to proceed to the `next` (`matrix`) entry automatically after 1500ms.
Now let's look at `matrix`, the `next` entry from `telnetConnected`:
```hjson
matrix: {
art: MATRIX
desc: Login Matrix
form: {
0: {
//
// Here we have a MCI key of "VM". In this case we could
// omit this level since no other keys are present.
//
VM: {
mci: {
VM1: {
submit: true
focus: true
items: [ "login", "apply", "log off" ]
argName: matrixSubmit
}
}
submit: {
*: [
{
value: { matrixSubmit: 0 }
action: @menu:login
}
{
value: { matrixSubmit: 1 },
action: @menu:newUserApplication
}
{
value: { matrixSubmit: 2 },
action: @menu:logoff
}
]
}
}
//
// If we wanted, we could declare a "HM" MCI key block here.
// This would allow a horizontal matrix style when the matrix art
// loaded contained a %HM code.
//
}
}
}
```
In the above entry, you'll notice `form`. This defines a form(s) object. In this case, a single form by ID of `0`. The system is then told to use a block only when the resulting art provides a `VM` (*VerticalMenuView*) MCI entry. Some other bits about the form:
* `VM1` is then setup to `submit` and start focused via `focus: true` as well as have some menu entries ("login", "apply", ...) defined. We provide an `argName` of `matrixSubmit` for this element view.
* The `submit` object tells the system to attempt to apply provided match entries from any view ID (`*`).
* Upon submit, the first match will be executed. For example, if the user selects "login", the first entry with a value of `{ matrixSubmit: 0 }` will match (due to 0 being the first index in the list and `matrixSubmit` being the arg name in question) causing `action` of `@menu:login` to be executed (go to `login` menu).
## Prompts
Prompts are found in the `prompts` section of menu files. Prompts allow for quick user input and shorthand form requirements for menus. Additionally, prompts are often used for for multiple menus. Consider a pause prompt or menu command input for example.
TODO: additional prompt docs
## ACS Checks
Menu modules can check user ACS in order to restrict areas and perform flow control. See [ACS](acs.md) for available ACS syntax.
### Menu Access
To restrict menu access add an `acs` key to `config`. Example:
```
opOnlyMenu: {
desc: Ops Only!
config: {
acs: ID1
}
}
```
### Action Matches
Action blocks (`action`) can perform ACS checks:
```
// ...
{
action: [
{
acs: SC1
action: @menu:secureMenu
}
{
action: @menu:nonSecureMenu
}
]
}
```
### Flow Control
The `next` member of a menu may be an array of objects containing an `acs` check as well as the destination. Depending on the current user's ACS, the system will pick the appropriate target. The last element in an array without an `acs` can be used as a catch all. Example:
```
login: {
desc: Logging In
next: [
{
// >= 2 calls else you get the full login
acs: NC2
next: loginSequenceLoginFlavorSelect
}
{
next: fullLoginSequenceLoginArt
}
]
}
```
### Art Asset Selection
Another area in which you can apply ACS in a menu is art asset specs.
```hjson
someMenu: {
desc: Neato Dorito
art: [
{
acs: GM[couriers]
art: COURIERINFO
}
{
// show ie: EVERYONEELSE.ANS to everyone else
art: EVERYONEELSE
}
]
}
```
## Case Study: Adding a Sub Menu to Main
A very common task: You want to add a new menu accessible from "Main". First, let's create a new menu called "Snazzy Town"! Perhaps under the `mainMenu` entry somewhere, create a new menu:
```hjson
snazzyTown: {
desc: Snazzy Town
art: snazzy
config: {
cls: true
pause: true
}
}
```
Now let's make it accessible by "S" from the main menu. By default the main menu entry is named `mainMenu`. Within the `mainMenu`'s `submit` block you will see some existing action matches to "command". Simply add a new one pointing to `snazzyTown`:
```hjson
{
value: { command: "S" }
action: @menu:snazzyTown
}
```
That's it! When users type "S" at the main menu, they'll be sent to the Snazzy Town menu. Since we did not supply additional flow logic when they exit, they will fall back to main.
## Case Study: Adding a New User Password (NUP)
You've got a super 31337 board and want to prevent lamerz! Let's run through adding a NUP to your application flow.
Given the default menu system, two "pre" new user application menus exist due to the way Telnet vs SSH logins occur. We'll focus only on Telnet here. This menu is `newUserApplicationPre`. Let's say you want to display this preamble, but then ask for the NUP. If the user gets the password wrong, show them a `LAMER.ANS` and boot 'em.
First, let's create a new menu for the NUP:
```hjson
newUserPassword: {
art: NUP.ANS
next: newUserApplication
desc: NUP!
form: {
0: {
mci: {
ET1: {
// here we create an argument/variable of "nup"
argName: nup
focus: true
submit: true
}
}
submit: {
*: [
{
// if the user submits "nup" with the correct
// value of "nolamerz" action will send
// them to the next menu defined above --
// in our case: newUserApplication
value: { nup: "nolamerz" }
action: @systemMethod:nextMenu
}
{
// anything else will result in going to the badNewUserPassword menu
value: { nup: null }
action: @menu:badNewUserPassword
}
]
}
}
}
}
```
Looks like we'll need a `badNewUserPassword` menu as well! Let's create a very basic menu to show art then disconnect the user.
```hjson
badNewUserPassword: {
art: LAMER.ANS
// here we use a built in system method to boot them.
next: @systemMethod:logoff
config: {
// wait 2s after showing the art before kicking them
nextTimeout: 2000
}
}
```
Great, we have a couple new menus. Now let's just point to them. Remember the existing `newUserApplicationPre` menu? All that is left to do is point it's `next` to our `newUserPassword` menu:
```hjson
newUserApplicationPre: {
// easy! Just tell the system where to go next
next: newUserPassword
// note that the rest of this menu is omitted for clarity
}
```

View file

@ -0,0 +1,64 @@
---
layout: page
title: Security
---
## Security
Unlike in the golden era of BBSing, modern Internet-connected systems are prone to hacking attempts, eavesdropping, etc. While plain-text passwords, insecure data over [Plain Old Telephone Service (POTS)](https://en.wikipedia.org/wiki/Plain_old_telephone_service), and so on was good enough then, modern systems must employ protections against attacks. ENiGMA½ comes with many security features that help keep the system and your users secure — not limited to:
* Passwords are **never** stored in plain-text, but instead are stored using [Password-Based Key Derivation Function 2 (PBKDF2)](https://en.wikipedia.org/wiki/PBKDF2). Even the system operator can _never_ know your password!
* Alternatives to insecure Telnet logins are built in: [SSH](https://en.wikipedia.org/wiki/Secure_Shell) and secure [WebSockets](https://en.wikipedia.org/wiki/WebSocket) for example.
* A built in web server with [TLS](https://en.wikipedia.org/wiki/Transport_Layer_Security) support (aka HTTPS).
* Optional [Two-Factor Authentication (2FA)](https://en.wikipedia.org/wiki/Multi-factor_authentication) via [One-Time-Password (OTP)](https://en.wikipedia.org/wiki/One-time_password) for users, supporting [Google Authenticator](http://google-authenticator.com/), [Time-Based One-Time Password Algorithm (TOTP, RFC-6238)](https://tools.ietf.org/html/rfc6238), and [HMAC-Based One-Time Password Algorithm (HOTP, RFC-4266)](https://tools.ietf.org/html/rfc4226).
## Two-Factor Authentication via One-Time Password
Enabling Two-Factor Authentication via One-Time-Password (2FA/OTP) on an account adds an extra layer of security ("_something a user has_") in addition to their password ("_something a user knows_"). Providing 2FA/OTP to your users has some prerequisites:
* [A configured email gateway](../configuration/email.md) such that the system can send out emails.
* One or more secure servers enabled such as [SSH](../servers/ssh.md) or secure [WebSockets](../servers/websocket.md) (that is, WebSockets over a secure connection such as TLS).
* The [web server](../servers/web-server.md) enabled and exposed over TLS (HTTPS).
:information_source: For WebSockets and the web server, ENiGMA½ _may_ listen on insecure channels if behind a secure web proxy.
### User Registration Flow
Due to the nature of 2FA/OTP, even if enabled on your system, users must opt-in and enable this feature on their account. Users must also have a valid email address such that a registration link can be sent to them. To opt-in, users must enable the option, which will cause the system to email them a registration link. Following the link provides the following:
1. A secret for manual entry into a OTP device.
2. If applicable, a scannable QR code for easy device entry (e.g. Google Authenticator)
3. A confirmation prompt in which the user must enter a OTP code. If entered correctly, this validates everything is set up properly and 2FA/OTP will be enabled for the account. Backup codes will also be provided at this time. Future logins will now prompt the user for their OTP after they enter their standard password.
:warning: Serving 2FA/OTP registration links over insecure (HTTP) can expose secrets intended for the user and is **highly** discouraged!
:memo: +ops can also manually enable or disable 2FA/OTP for a user using [oputil](../admin/oputil.md), but this is generally discouraged.
#### Recovery
In the situation that a user loses their 2FA/OTP device (such as a lost phone with Google Auth), there are some options:
* Utilize one of their backup codes.
* Contact the SysOp.
:warning: There is no way for a user to disable 2FA/OTP without first fully logging in! This is by design as a security measure.
### ACS Checks
Various places throughout the system that implement [ACS](../configuration/acs.md) can make 2FA specific checks:
* `AR#`: Current users **required** authentication factor. `AR2` for example means 2FA/OTP is required for this user.
* `AF#`: Current users **active** authentication factor. `AF2` means the user is authenticated with some sort of 2FA (such as One-Time-Password).
See [ACS](../configuration/acs.md) for more information.
#### Example
The following example illustrates using an `AR` ACS check to require applicable users to go through an additional 2FA/OTP process during login:
```hjson
login: {
art: USERLOG
next: [
{
// users with AR2+ must first pass 2FA/OTP
acs: AR2
next: loginTwoFactorAuthOTP
}
{
// everyone else skips ahead
next: fullLoginSequenceLoginArt
}
]
// ...
}
```

View file

@ -0,0 +1,5 @@
---
layout: page
title: SysOp Setup
---
SySop privileges will be granted to the first user to log into a fresh ENiGMA½ installation. +ops belong to the `sysop` user group by default.

View file

@ -0,0 +1,31 @@
---
layout: page
title: ACS
---
## File Base ACS
[ACS Codes](../configuration/acs.md) may be used to control access to File Base areas by specifying an `acs` string in a file area's definition. If no `acs` is supplied in a file area definition, the following defaults apply to an area:
* `read` : `GM[users]`: List/view the area and it's contents.
* `write` : `GM[sysops]`: Upload.
* `download` : `GM[users]`: Download.
To override read and/or write ACS, supply a valid `acs` member.
## Example File Area Config with ACS
```hjson
areas: {
retro_pc: {
name: Retro PC
desc: Oldschool PC/DOS
storageTags: [ "retro_pc", "retro_pc_bbs" ]
acs: {
// only users of the "l33t" group or those who have
// uploaded 10+ files can download from here...
download: GM[l33t]|UP10
}
}
}
```
## See Also
[Access Condition System (ACS)](../configuration/acs.md)

View file

@ -0,0 +1,101 @@
---
layout: page
title: Configuring a File Base
---
## Configuring a File Base
ENiGMA½ offers a powerful and flexible file base. Configuration of file the file base and areas is handled via the `fileBase` section of `config.hjson`.
## ENiGMA½ File Base Key Concepts
First, there are some core concepts you should understand:
* Storage Tags
* Area Tags
### Storage Tags
*Storage Tags* define paths to physical (filesystem) storage locations that are referenced in a file *Area* entry. Each entry may be either a fully qualified path or a relative path. Relative paths are relative to the value set by the `fileBase.areaStoragePrefix` key (defaults to `/path/to/enigma-bbs/file_base`).
Below is an example defining some storage tags using the relative and fully qualified forms:
```hjson
storageTags: {
retro_pc_dos: "dos" // relative
retro_pc_bbs: "pc/bbs" // still relative!
bbs_stuff: "/path/to/bbs_stuff_storage" // fully qualified
}
```
:memo: On their own, storage tags don't do anything — they are simply pointers to storage locations on your system.
:warning: Remember that paths are case sensitive on most non-Windows systems!
### Areas
File base *Areas* are configured using the `fileBase.areas` configuration block in `config.hjson`. Each entry's block starts with an *area tag*. Valid members for an area are as follows:
| Item | Required | Description |
|--------|---------------|------------------|
| `name` | :+1: | Friendly area name. |
| `desc` | :-1: | Friendly area description. |
| `storageTags` | :+1: | An array of storage tags for physical storage backing of the files in this area. If uploads are enabled for this area, **first** storage tag location is utilized! |
| `sort` | :-1: | If present, provides the sort key for ordering. `name` is used otherwise. |
| `hashTags` | :-1: | Set to an array of strings or comma separated list to provide _default_ hash tags for this area. |
Example areas section:
```hjson
areas: {
retro_pc: { // an area tag!
name: Retro PC
desc: Oldschool PC/DOS
storageTags: [ "retro_pc_dos", "retro_pc_bbs" ]
hashTags: ["retro", "pc", "dos" ]
}
}
```
The above example defines an area called "Retro PC" which is referenced via the *area tag* of `retro_pc`. Two storage tags are used: `retro_pc_dos`, and `retro_pc_bbs`. These storage tags can be seen in the Storage Tags example above.
## Example Configuration
This combines the two concepts described above. When viewing the file areas from ENiGMA½ a user will only see the "Retro PC" area, but the files in the area are stored in the two locations defined in the `storageTags` section. We also show a uploads area. Uploads are allowed due to the [ACS](acs.md) block. See [Uploads](uploads.md) for more information.
```hjson
fileBase: {
// override the default relative location
areaStoragePrefix: /enigma-bbs/file_base
storageTags: {
retro_pc_dos: "dos"
retro_pc_bbs: "pc/bbs"
}
areas: {
retro_pc: {
name: Retro PC
desc: Oldschool PC/DOS
storageTags: [ "retro_pc_dos", "retro_pc_bbs" ]
}
uploads: {
name: Uploads
desc: User uploads
acs: {
// allow any user to upload here
write: GM[users]
}
storageTags: [ "user_uploads" ]
}
}
}
```
## Importing Areas
Areas can also be imported using [oputil](../admin/oputil.md) using proper FileGate "RAID" aka `FILEBONE.NA` style files. After importing areas, you may wish to tweak configuration such as better `desc` fields, ACS, or sorting.
## Importing Files (Scan For New Files)
A common task is to *import* existing files to area(s). Consider a collection of retro BBS files in the area "Retro PC" (tag: `retro_pc` above) under the storage tag of `retro_pc_bbs`. You might choose to scan for new files in this area (and thus import new entries) as follows with [oputil](../admin/oputil.md)'s `fb scan`:
```bash
./oputil.js fb scan --quick --tags retro,bbs,pc retro_pc@retro_pc_bbs
```
Here we have asked [oputil](../admin/oputil.md) to scan the file base area by it's tag `retro_pc` and only include the storage tag of `retro_pc_bbs`. Note that the storage tag could be omitted, and if so, all of `retro_pc` would be scanned. We have also indicated to #hashtag new entries with the tags "retro", "bbs", and "pc".
Please see [oputil](../admin/oputil.md) for more information.

View file

@ -0,0 +1,28 @@
---
layout: page
title: About File Areas
---
## About File Areas
### A Different Approach
ENiGMA½ has strayed away from the old familiar setup here and instead takes a more modern approach:
* [Gazelle](https://whatcd.github.io/Gazelle/) inspired system for searching & browsing files.
* No conferences (just areas!)
* File areas are still around but should *generally* be used less. Instead, files can have one or more tags. Think things like `dos.retro`, `pc.warez`, `games`, etc.
### Other bells and whistles
* Temporary web (http:// or https://) download links in additional to standard X/Y/Z protocol support. Batch downloads of many files can be downloaded as a single ZIP archive.
* Users can rate files & search/filter by ratings.
* Users can also create and save their own filters for later use such as "Latest Artscene Releases" or "C64 SIDs".
* A given area can span one to many physical storage locations.
* Upload processor can extract and use `FILE_ID.DIZ`/`DESC.SDI`, for standard descriptions as well as `README.TXT`, `*.NFO`, and so on for longer descriptions. The processor also attempts release year estimation by scanning aforementioned description file(s).
* Fast indexed [Full Text Search (FTS)](https://sqlite.org/fts3.html) across descriptions and filenames.
* Duplicates are checked for by cryptographically secure [SHA-256](https://en.wikipedia.org/wiki/SHA-2) hashes.
* Support for many archive and file formats. External utilities can easily be added to the configuration to extend for additional formats.
* Much, much more!
### Modding
The default ENiGMA½ approach for file areas may not be for everyone. Remember that you can mod everything your setup! Some inspirational examples:
* A more traditional set of areas and scrolling file listings.
* An S/X style integration of message areas and file areas.
* Something completely different! Some tweaks are possible without any code while others may require creating new JavaScript modules to use instead of the defaults.

View file

@ -0,0 +1,24 @@
---
layout: page
title: Network Mounts & Symlinks
---
## Network Mounts & Symlinks
With many Bulletin Board Systems running on small headless boxes such as Raspberry Pis, it may not be practical to have all files you would like to make available in your file base. One solution to this is to utilize network mounts. Add in symbolic links to make things even easier!
### A Practical Example
The scenario: A Windows box containing a lot of files you'd like in your systems file base. The BBS itself is running on a Raspberry Pi with very limited space.
To solve this problem, we can perform the following steps:
1. Create a network mount in `/mnt/windows_box_share`.
2. Next, we can create a local file base area such as `/home/enigma/file_base`
3. Within the file base directory above, create some symbolic links to areas within our share:
```
cd /home/enigma/file_base
ln -s /mnt/windows_box_share/some/long/annoying/path area1
```
What we've done here is make `/home/enigma/file_base/area1` point to the Windows share within some nested directories. Of course we could have just pointed directly to the `/mnt/windows_box_share` area, but using symbolic links has some advantages:
* We can now set `/home/enigma/file_base` as our `areaStoragePrefix`. That is, the base path of all of our file base
* Since we have `areaStoragePrefix` set, we can now make storage tags relative to that path. For example, `leet_files1: "area1/leet_files"
There are **many** ways one can achieve the mounts between various operating systems. See your distros documentation.

View file

@ -0,0 +1,101 @@
---
layout: page
title: TIC Support
---
## TIC Support
ENiGMA½ supports FidoNet-Style TIC file attachments by mapping TIC areas to local file areas.
Under a given node defined in the `ftn_bso` config section in `config.hjson` (see
[BSO Import/Export](../messageareas/bso-import-export.md)), TIC configuration may be supplied:
```hjson
{
scannerTossers: {
ftn_bso: {
nodes: {
"46:*": {
packetPassword: mypass
encoding: cp437
archiveType: zip
tic: {
password: TESTY-TEST
uploadBy: Agoranet TIC
allowReplace: true
}
}
}
}
}
}
```
You then need to configure the mapping between TIC areas you want to carry, and the file base area and storage tag for them to be tossed to. Optionally you can also add hashtags to the tossed files to assist users in searching for files:
```hjson
ticAreas: {
agn_node: {
areaTag: msgNetworks
storageTag: msg_network
hashTags: agoranet,nodelist
}
}
```
Multiple TIC areas can be mapped to a single file base area.
### Example Configuration
An example configuration linking file base areas, FTN BSO node configuration and TIC area configuration.
```hjson
fileBase: {
areaStoragePrefix: /home/bbs/file_areas/
storageTags: {
msg_network: "msg_network"
}
areas: {
msgNetworks: {
name: Message Networks
desc: Message networks news & info
storageTags: [
"msg_network"
]
}
}
}
scannerTossers: {
ftn_bso: {
nodes: {
"46:*": {
packetPassword: mypass
encoding: cp437
archiveType: zip
tic: {
password: TESTY-TEST
uploadBy: Agoranet TIC
allowReplace: true
}
}
}
}
}
ticAreas: {
agn_node: {
areaTag: msgNetworks
storageTag: msg_network
hashTags: agoranet,nodelist
}
agn_info: {
areaTag: msgNetworks
storageTag: msg_network
hashTags: agoranet,infopack
}
}
```
## See Also
[Message Networks](../messageareas/message-networks.md)

View file

@ -0,0 +1,24 @@
---
layout: page
title: Uploads
---
## Uploads
The default ACS for file areas in ENiGMA½ is to allow regular users 'read' and sysops 'read/write'. Read ACS includes listing and downloading while write allows for uploading. See [File Base ACS](acs.md) for more information.
Let's allow regular users (in the "users" group) to upload to an area:
```hjson
uploads: {
name: Uploads
desc: User Uploads
storageTags: [
"uploads"
]
acs: {
write: GM[users]
}
}
````
:information_source: Remember that uploads in a particular area are stored **using the first storage tag defined in that area.**
:bulb: Any ACS checks are allowed. See [ACS](../configuration/acs.md)

View file

@ -0,0 +1,11 @@
---
layout: page
title: Web Access
---
Temporary web HTTP(S) URLs can be used to download files using the built in web server. Temporary links
expire after `fileBase::web::expireMinutes` (default 24 hours). The full URL given to users is built
using `contentServers::web::domain` and will default to HTTPS (https://) if enabled with a fallback to
HTTP. The end result is users are given a temporary web link that may look something like this:
`https://xibalba.l33t.codes:44512/f/h7JK`
See [Web Server](../servers/web-server.md) for more information.

View file

@ -0,0 +1,72 @@
---
layout: page
title: Docker
---
**You'll need Docker installed before going any further. How to do so are out of scope of these docs, but you can find full instructions
for every operating system on the [Docker website](https://docs.docker.com/engine/install/).**
## Quick Start
prepare a folder where you are going to save your bbs files.
- Generate some config for your BBS: \
you can perform this step from anywhere - but make sure to consistently run it from the same place to retain your config inside the docker guest
```
docker run -it -p 8888:8888 \
--name " ENiGMABBS" \
-v "$(pwd)/config:/enigma-bbs/config" \
-v "$(pwd)/db:/enigma-bbs/db" \
-v "$(pwd)/logs:/enigma-bbs/logs" \
-v "$(pwd)/filebase:/enigma-bbs/filebase" \
-v "$(pwd)/art:/enigma-bbs/art" \
-v "$(pwd)/mods:/enigma-bbs/mods" \
-v "$(pwd)/mail:/mail" \
enigmabbs/enigmabbs:latest
```
- Run it: \
you can use the same command as above, just daemonize and drop interactiveness (we needed it for config but most of the time docker will run in the background)
````
docker run -d -p 8888:8888 \
--name "ENiGMABBS" \
-v "$(pwd)/config:/enigma-bbs/config" \
-v "$(pwd)/db:/enigma-bbs/db" \
-v "$(pwd)/logs:/enigma-bbs/logs" \
-v "$(pwd)/filebase:/enigma-bbs/filebase" \
-v "$(pwd)/art:/enigma-bbs/art" \
-v "$(pwd)/mods:/enigma-bbs/mods" \
-v "$(pwd)/mail:/mail" \
enigmabbs/enigmabbs:latest
````
- Restarting and Making changes\
if you make any changes to your host config folder they will persist, and you can just restart ENiGMABBS container to load any changes you've made.
```docker restart ENiGMABBS```
:bulb: Configuration will be stored in `$(pwd)/enigma-bbs/config`.
:bulb: Windows users - you'll need to switch out `$(pwd)/enigma-bbs/config` for a Windows-style path.
## Volumes
Containers by their nature are ephermeral. Meaning, stuff you want to keep (config, database, mail) needs
to be stored outside of the running container. As such, the following volumes are mountable:
| Volume | Usage |
|:------------------------|:---------------------------------------------------------------------|
| /enigma-bbs/art | Art, themes, etc |
| /enigma-bbs/config | Config such as config.hjson, menu.hjson, prompt.hjson, SSL certs etc |
| /enigma-bbs/db | ENiGMA databases |
| /enigma-bbs/filebase | Filebase |
| /enigma-bbs/logs | Logs |
| /enigma-bbs/mods | ENiGMA mods |
| /mail | FTN mail (for use with an external mailer) |
## Building your own image
Customising the Docker image is easy!
1. Clone the ENiGMA-BBS source.
2. Build the image
```
docker build -f ./docker/Dockerfile .
```

View file

@ -0,0 +1,20 @@
---
layout: page
title: Install Script
---
## Install Script
Under most Linux/UNIX like environments (Linux, BSD, OS X, ...) new users can simply execute the `install.sh` script to get everything up and running. Cut + paste the following into your terminal:
```
curl -o- https://raw.githubusercontent.com/NuSkooler/enigma-bbs/master/misc/install.sh | bash
```
:eyes: You may wish to review the [installation script](https://raw.githubusercontent.com/NuSkooler/enigma-bbs/master/misc/install.sh)
on GitHub before running it!
The script will install `nvm`, Node.js and grab the latest ENiGMA BBS from GitHub. It will also guide you through creating a basic configuration file, and recommend some packages to install.
:information_source: After installing:
* Read [External Binaries](../configuration/external-binaries.md)
* Read [Updating](../admin/updating.md)

View file

@ -0,0 +1,18 @@
---
layout: page
title: Installation Methods
---
## Installation Methods
There are multiple ways of installing ENiGMA BBS, depending on your level of experience and desire to do things manually versus have it automated for you.
| Method | Operating System Compatibility | Notes |
|--------|--------------------------------|-------|
| [Installation Script](install-script.md) | Linux, BSD, OSX | Quick and easy installation under most Linux/UNIX like environments (Linux, BSD, OS X, ...) |
| [Docker Images](docker.md) | Linux, BSD, OSX, Windows | Easy upgrades, compatible with all operating systems, no dependencies to install |
| [Manual](manual.md) | Linux, Windows, BSD (And others; YMMV!) | If you like doing things manually, or are running Windows |
## Community HOWTO's
:scroll: Check out [this awesome video on installation and basic configuration](https://youtu.be/WnN-ucVi3ZU) from Al's Geek Lab!
## Keeping Up To Date
After installing, you'll want to [keep your system updated](../admin/updating.md).

View file

@ -0,0 +1,68 @@
---
layout: page
title: Manual Installation
---
For Linux environments it's recommended you run the [install script](install-script.md). If you like to
do things manually, read on...
## Prerequisites
* [Node.js](https://nodejs.org/) version **v12.x LTS or higher** (Other versions may work but are not supported).
* :bulb: It is **highly** recommended to use [Node Version Manager (NVM)](https://github.com/creationix/nvm) to manage your Node.js installation if you're on a Linux/Unix environment.
* [Python](https://www.python.org/downloads/) for compiling Node.js packages with native extensions via `node-gyp`.
* A compiler such as Clang or GCC for Linux/UNIX systems or a recent copy of Visual Studio
([Visual Studio Express](https://www.visualstudio.com/en-us/products/visual-studio-express-vs.aspx) editions
are OK) for Windows users. Note that you **should only need the Visual C++ component**.
* [Git](https://git-scm.com/downloads) to check out the ENiGMA source code.
## Node.js
### With NVM
Node Version Manager (NVM) is an excellent way to install and manage Node.js versions on most UNIX-like environments. [Get the latest version here](https://github.com/creationix/nvm). The nvm install may look _something_ like this:
```bash
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash
```
:information_source: Do not cut+paste the above command! Visit the [NVM](https://github.com/creationix/nvm) page and run the latest version!
Next, install Node.js with NVM:
```bash
nvm install 12
nvm use 12
nvm alias default 12
```
If the above steps completed without errors, you should now have `nvm`, `node`, and `npm` installed and in your environment.
For Windows nvm-like systems exist ([nvm-windows](https://github.com/coreybutler/nvm-windows), ...) or [just download the installer](https://nodejs.org/en/download/).
## ENiGMA BBS
```bash
git clone https://github.com/NuSkooler/enigma-bbs.git
```
## Install Node Packages
```bash
cd enigma-bbs
npm install # yarn also works
```
## Other Recommended Packages
ENiGMA BBS makes use of a few packages for archive and legacy protocol support. They're not pre-requisites for running ENiGMA, but without them you'll miss certain functionality. Once installed, they should be made available on your systems `PATH`.
:information_source: Please see [External Binaries](../configuration/external-binaries.md) for information on setting these up.
:information_source: Additional information in [Archivers](../configuration/archivers.md) and [File Transfer Protocols](../configuration/file-transfer-protocols.md)
## Config Files
You'll need a basic configuration to get started. The main system configuration is handled via `config/config.hjson`. This is an [HJSON](http://hjson.org/) file (compliant JSON is also OK). See [Configuration](../configuration/) for more information.
Use `oputil.js` to generate your **initial** configuration:
```bash
./oputil.js config new
```
Follow the prompts!

View file

@ -0,0 +1,13 @@
---
layout: page
title: Network Setup
---
## Hosting an ENIGMA instance from your Home Network
If you are hosting your ENGIMA instance from inside your local network, you'll need to open your chosen ports on your router, so people outside your local area network can access the BBS.
Each router has a different way of doing this, but this [comprehensive resource](https://portforward.com/) explains how to port forward on most common brand routers.
Secondly, it is likely that your public facing server IP is a [Dynamic Address](https://support.opendns.com/hc/en-us/articles/227987827-What-is-a-Dynamic-IP-Address-) automatically provisoned to you by your ISP. You can contact your ISP and request a static IP, but in some areas this isn't available to consumers, only businesses.
Using a tool like [Duck DNS](https://www.duckdns.org/) will give you a free subdomain that automatically adjusts its records whenever your IP Address changes.

View file

@ -0,0 +1,14 @@
---
layout: page
title: OS & Hardware Specific Information
---
There are multiple ways of installing ENiGMA BBS, depending on your level of experience and desire to do things manually versus have it automated for you.
In general, please see [Installation Methods](installation-methods.md) and [Install Script](install-script.md).
Below are some special cases:
| Method | Notes |
|--------|-------|
| [Raspberry Pi](rpi.md) | All Raspberry Pi models work great with ENiGMA½! |
| [Windows](windows.md) | Compatible with all Windows Operating Systems |

View file

@ -0,0 +1,12 @@
---
layout: page
title: Production Installation
---
If you've become convinced you would like a "production" BBS running ENiGMA½ a more advanced installation
may be in order.
[PM2](https://github.com/Unitech/pm2) is an excellent choice for managing your running ENiGMA½ instances if
you've installed via the [install script](install-script.md) or [manual installation](manual.md) method.
Additionally, it is suggested that you run as a specific more locked down user (e.g. 'enigma').
If you're running ENiGMA via Docker, then process management is already handled for you!

View file

@ -0,0 +1,27 @@
---
layout: page
title: Raspberry Pi
---
All Raspberry Pi models work great with ENiGMA½! Keep in mind compiling the dependencies with
`npm install` will take some time and *may* appear to hang. It's still working - just be patient and let it
complete.
### Basic Instructions
1. Download [Raspbian Stretch Lite](https://www.raspberrypi.org/downloads/raspbian/). Follow the instructions
on the [Raspbian site](https://www.raspberrypi.org/documentation/installation/installing-images/README.md) regarding how
to get it written to an SD card.
2. Run `sudo raspi-config`, then:
1. Set your timezone (option 4, option I2)
2. Enable SSH (option 5, option P2)
3. Expand the filesystem to use the entire SD card (option 7, option A1)
3. Update & upgrade all packages: `apt-get update && apt-get upgrade`
4. Install required packages: `sudo apt install lrzsz p7zip-full`
5. Follow the [installation instructions](../installation/) to install ENiGMA½.
6. Profit!

View file

@ -0,0 +1,49 @@
---
layout: page
title: Testing Your Installation
---
Once you've completed your chosen installation method, it's time to test!
_Note that if you've used the [Docker](docker.md) installation method, you've already done this._
```bash
./main.js
```
If everything went OK:
```bash
ENiGMA½ Copyright (c) 2014-2021, Bryan Ashby
_____________________ _____ ____________________ __________\_ /
\__ ____/\_ ____ \ /____/ / _____ __ \ / ______/ // /___jp!
// __|___// | \// |// | \// | | \// \ /___ /_____
/____ _____| __________ ___|__| ____| \ / _____ \
---- \______\ -- |______\ ------ /______/ ---- |______\ - |______\ /__/ // ___/
/__ _\
<*> ENiGMA½ // HTTPS://GITHUB.COM/NUSKOOLER/ENIGMA-BBS <*> /__/
-------------------------------------------------------------------------------
System started!
```
Grab your favourite telnet client, connect to localhost:8888 and test out your installation.
To shut down the server, press Ctrl-C.
## Points of Interest
* The default port for Telnet is 8888 and 8889 for SSH.
* Note that on *nix systems port such as telnet/23 are privileged (e.g. require root). See
[this SO article](http://stackoverflow.com/questions/16573668/best-practices-when-running-node-js-with-port-80-ubuntu-linode) for some tips on using these ports on your system if desired.
* The first user you create when logging in will be automatically be added to the `sysops` group.
## Telnet Software
If you don't have any telnet software, these are compatible with ENiGMA½:
* [SyncTERM](http://syncterm.bbsdev.net/)
* [EtherTerm](https://github.com/M-griffin/EtherTerm)
* [NetRunner](http://mysticbbs.com/downloads.html)
* [MagiTerm](https://magickabbs.com/utils/)
* [VTX](https://github.com/codewar65/VTX_ClientServer) (Browser based)
* [fTelnet](https://www.ftelnet.ca/) (Browser based)

View file

@ -0,0 +1,71 @@
---
layout: page
title: Installation Under Windows
---
## Installation Under Windows
ENiGMA½ will run on both 32bit and 64bit Windows. If you want to run 16bit doors natively then you should use a 32bit Windows.
### Basic Instructions
1. Download and Install [Node.JS](https://nodejs.org/).
1. Upgrade NPM : At this time node comes with NPM 5.6 preinstalled. To upgrade to a newer version now or in the future on windows follow this method. `*Run PowerShell as Administrator`
`*Initial Install`
```Powershell
Set-ExecutionPolicy Unrestricted -Scope CurrentUser -Force
npm install -g npm-windows-upgrade
```
`*Upgrade`
```Powershell
npm-windows-upgrade
```
Note: Do not run `npm i -g npm`. Instead use `npm-windows-upgrade` to update npm going forward.
Also if you run the NodeJS installer, it will replace the node version.
2. Install [windows-build-tools for npm](https://www.npmjs.com/package/windows-build-tools)
`*This will also install python 2.7`
```Powershell
npm install --global --production windows-build-tools
```
2. Install [7zip](https://www.7-zip.org/download.html).
*Add 7zip to your path so `7z` can be called from the console
1. Right click `This PC` and Select `Properties`
2. Go to the `Advanced` Tab and click on `Environment Variables`
3. Select `Path` under `System Variables` and click `Edit`
4. Click `New` and paste the path to 7zip
5. Close your console window and reopen. You can type `7z` to make sure it's working.
(Please see [Archivers](../configuration/archivers.md) for additional archive utilities!)
3. Install [Git](https://git-scm.com/downloads) and optionally [TortoiseGit](https://tortoisegit.org/download/).
4. Clone ENiGMA½ - browse to the directory you want and run
```Powershell
git clone "https://github.com/NuSkooler/enigma-bbs.git"
```
Optionally use the TortoiseGit by right clicking the directory and selecting `Git Clone`.
5. Install ENiGMA½.
1. In the enigma directory run
```Powershell
npm install
```
2. Generate your initial configuration: `Follow the prompts!`
```Powershell
node .\oputil.js config new
```
3. Edit your configuration files in `enigma-bbs\config` with [Notepad++](https://notepad-plus-plus.org/download/) or [Visual Studio Code](https://code.visualstudio.com/Download)
4. Run ENiGMA½
```Powershell
node .\main.js
```
6. Look at [Production Installation](production.md) for maintaining ENiGMA½ when you are ready to go live.

View file

@ -0,0 +1,228 @@
---
layout: page
title: BSO Import / Export
---
## BSO Import / Export
The scanner/tosser module `ftn_bso` provides **B**inkley **S**tyle **O**utbound (BSO) import/toss and scan/export of messages EchoMail and NetMail messages. Configuration is supplied in `config.hjson` under `scannerTossers.ftn_bso`.
:information_source: ENiGMA½'s `ftn_bso` module is not a mailer and **makes no attempts to perform packet transport**! An external [mailer](http://www.filegate.net/bbsmailers.htm) such as [Binkd](https://github.com/pgul/binkd) is required for this task!
### Configuration
Let's look at some of the basic configuration:
| Config Item | Required | Description |
|-------------|----------|----------------------------------------------------------|
| `schedule` | :+1: | Sets `import` and `export` schedules. [Later style text parsing](https://bunkat.github.io/later/parsers.html#text) supported. `import` also can utilize a `@watch:<path/to/file>` syntax while `export` additionally supports `@immediate`. |
| `packetMsgEncoding` | :-1: | Override default `utf8` encoding.
| `defaultNetwork` | :-1: | Explicitly set default network (by tag found within `messageNetworks.ftn.networks`). If not set, the first found is used. |
| `nodes` | :+1: | Per-node settings. Entries (keys) here support wildcards for a portion of the FTN-style address (e.g.: `21:1/*`). See **Nodes** below.
| `paths` | :-1: | An optional configuration block that can set a additional paths or override defaults. See **Paths** below. |
| `packetTargetByteSize` | :-1: | Overrides the system *target* packet (.pkt) size of 512000 bytes (512k) |
| `bundleTargetByteSize` | :-1: | Overrides the system *target* ArcMail bundle size of 2048000 bytes (2M) |
#### Nodes
The `nodes` section defines how to export messages for one or more uplinks.
A node entry starts with a [FTN address](http://ftsc.org/docs/old/fsp-1028.001) (up to 5D) **as a key** in `config.hjson`. This key may contain wildcard(s) for net/zone/node/point/domain.
| Config Item | Required | Description |
|------------------|----------|---------------------------------------------------------------------------------|
| `packetType` | :-1: | `2`, `2.2`, or `2+`. Defaults to `2+` for modern mailer compatibility. |
| `packetPassword` | :-1: | Optional password for the packet |
| `encoding` | :-1: | Encoding to use for message bodies; Defaults to `utf-8`. |
| `archiveType` | :-1: | Specifies the archive type (by extension or MIME type) for ArcMail bundles. This should be `zip` (or `application/zip`) for most setups. Other valid examples include `arc`, `arj`, `lhz`, `pak`, `sqz`, or `zoo`. See [Archivers](../configuration/archivers.md) for more information. |
**Example**:
```hjson
{
scannerTossers: {
ftn_bso: {
nodes: {
"21:*": { // wildcard address
packetType: 2+
packetPassword: D@TP4SS
encoding: cp437
archiveType: zip
}
}
}
}
}
```
#### Paths
Paths for packet files work out of the box and are relative to your install directory. If you want to configure `reject` or `retain` to keep rejected/imported packet files respectively, set those values. You may override defaults as well.
| Key | Description | Default |
|-----|-------------|---------|
| `outbound` | *Base* path to write outbound (exported) packet files and bundles. | `enigma-bbs/mail/ftn_out/` |
| `inbound` | *Base* path to write inbound (ie: those written by an external mailer) packet files an bundles. | `enigma-bbs/mail/ftn_in/` |
| `secInbound` | *Base* path to write **secure** inbound packet files and bundles. | `enigma-bbs/mail/ftn_secin/` |
| `reject` | Path in which to write rejected packet files. | No default |
| `retain` | Path in which to write imported packet files. Useful for debugging or if you wish to archive the raw .pkt files. | No default |
### Scheduling
Schedules can be defined for importing and exporting via `import` and `export` under `schedule`. Each entry is allowed a "free form" text and/or special indicators for immediate export or watch file triggers.
* `@immediate`: A message will be immediately exported if this trigger is defined in a schedule. Only used for `export`.
* `@watch:/path/to/file`: This trigger watches the path specified for changes and will trigger an import or export when such events occur. Only used for `import`.
* Free form [Later style](https://bunkat.github.io/later/parsers.html#text) text — can be things like `at 5:00 pm` or `every 2 hours`.
See [Later text parsing documentation](http://bunkat.github.io/later/parsers.html#text) for more information.
#### Example Schedule Configuration
```hjson
{
scannerTossers: {
ftn_bso: {
schedule: {
import: every 1 hours or @watch:/path/to/watchfile.ext
export: every 1 hours or @immediate
}
}
}
}
```
### A More Complete Example
Below is a more complete example showing the sections described above.
```hjson
scannerTossers: {
ftn_bso: {
schedule: {
// Check every 30m, or whenever the "toss!.now" file is touched (ie: by Binkd)
import: every 30 minutes or @watch:/enigma-bbs/mail/ftn_in/toss!.now
// Export immediately, but also check every 15m to be sure
export: every 15 minutes or @immediate
}
// optional
paths: {
reject: /path/to/store/bad/packets/
retain: /path/to/store/good/packets/
}
// Override default FTN/BSO packet encoding. Defaults to 'utf8'
packetMsgEncoding: utf8
defaultNetwork: fsxnet
nodes: {
"21:1/100" : { // May also contain wildcards, ie: "21:1/*"
archiveType: ZIP // By-ext archive type: ZIP, ARJ, ..., optional.
encoding: utf8 // Encoding for exported messages
packetPassword: MUHPA55 // FTN .PKT password, optional
tic: {
// See TIC docs
}
}
}
netMail: {
// See NetMail docs
}
ticAreas: {
// See TIC docs
}
}
}
```
## Binkd
Since Binkd is a very common mailer, a few tips on integrating it with ENiGMA½.
### Example Binkd Configuration
Below is an **example** Binkd configuration file that may help serve as a reference.
```bash
# Number @ end is the root zone
# Note that fsxNet is our *default* FTN so we use "outbound" here!
domain fsxnet /home/enigma/enigma-bbs/mail/ftn_out/outbound 21
domain araknet /home/enigma/enigma-bbs/mail/ftn_out/araknet 10
# Our assigned addresses
address 21:1/1234@fsxnet
address 10:101/1234@araknet
# Info about our board/op
sysname "My BBS"
location "Somewhere Out There"
sysop "SysOp"
nodeinfo 115200,TCP,BINKP
try 10
hold 600
send-if-pwd
log /var/log/binkd/binkd.log
loglevel 4
conlog 4
percents
printq
backresolv
inbound /home/enigma/enigma-bbs/mail/ftn_in
temp-inbound /home/enigma/enigma-bbs/mail/ftn_in_temp
minfree 2048
minfree-nonsecure 2048
kill-dup-partial-files
kill-old-partial-files 86400
prescan
# fsxNet - Agency HUB
node 21:1/100@fsxnet -md agency.bbs.nz:24556 SOMEPASS c
# ArakNet
node 10:101/0@araknet -md whq.araknet.xyz:24556 SOMEPASS c
# our listening port (default=24554)
iport 54554
pid-file /var/run/binkd/binkd.pid
# touch a watch file when files are received to kick of toss
# ENiGMA can monitor this (see @watch information above)
flag /home/enigma/enigma-bbs/mail/ftn_in/toss!.now *.su? *.mo? *.tu? *.we? *.th? *.fr? *.sa? *.pkt *.tic
# nuke old .bsy/.csy files after 24 hours
kill-old-bsy 43200
```
### Scheduling Polls
Binkd does not have it's own scheduler. Instead, you'll need to set up an Event Scheduler entry or perhaps a cron job:
First, create a script that runs through all of your uplinks. For example:
```bash
#!/bin/bash
UPLINKS=("21:1/100@fsxnet" "80:774/1@retronet" "10:101/0@araknet")
for uplink in "${UPLINKS[@]}"
do
/usr/local/sbin/binkd -p -P $uplink /home/enigma/xibalba/misc/binkd_xibalba.conf
done
```
Now, create an Event Scheduler entry in your `config.hjson`. As an example:
```hjson
eventScheduler: {
events: {
pollWithBink: {
// execute the script above very 1 hours
schedule: every 1 hours
action: @execute:/path/to/poll_bink.sh
}
}
}
```
## Additional Resources
* [Blog entry on setting up ENiGMA + Binkd on CentOS7](https://l33t.codes/enigma-12-binkd-on-centos-7/). Note that this references an **older version**, so be wary of the `config.hjson` references!
* [Setting up FTN-style message networks with ENiGMA½ BBS](https://medium.com/@alpha_11845/setting-up-ftn-style-message-networks-with-enigma%C2%BD-bbs-709b22a1ae0d) by Alpha.

View file

@ -0,0 +1,88 @@
---
layout: page
title: Message Base
---
## General Information
In ENiGMA½, a message base is divided into two logical grouping components: **Message Conferences** and **Areas**. Message conferences are top level containers while areas are for a specific topic. Messages are always stored internally with a area tag.
## Conferences
Message Conferences are the top level container for *1:n* Message *Areas* via the `messageConferences` block in `config.hjson`. A common setup may include a local conference and one or more conferences each dedicated to a particular message network such as fsxNet, ArakNet, etc.
Each conference is represented by a entry under `messageConferences`. Each entries top level key is it's *conference tag*.
:bulb: It is **highly** recommended to use snake_case style message *conference tags* and *area tags*!
| Config Item | Required | Description |
|-------------|----------|-------------|
| `name` | :+1: | Friendly conference name |
| `desc` | :+1: | Friendly conference description. |
| `sort` | :-1: | Set to a number to override the default alpha-numeric sort order based on the `name` field. |
| `default` | :-1: | Specify `true` to make this the default conference (e.g. assigned to new users) |
| `areas` | :+1: | Container of 1:n areas described below |
| `acs` | :-1: | A standard [ACS](../configuration/acs.md) block. See **ACS** below. |
### ACS
An optional standard [ACS](../configuration/acs.md) block can be supplied with the following rules:
* `read`: ACS required to read (see) this conference. Defaults to `GM[users]`.
* `write`: ACS required to write (post) to this conference. Defaults to `GM[users]`.
### Example
```hjson
{
messageConferences: {
local: { // conference tag
name: Local
desc: Local discussion
sort: 1
default: true
acs: {
read: GM[users] // default
}
}
}
}
```
## Message Areas
Message Areas are topic specific containers for messages that live within a particular conference. The top level key for an area sets it's *area tag*. For example, "General Discussion" may live under a Local conference while an fsxNet conference may contain "BBS Discussion".
| Config Item | Required | Description |
|-------------|----------|---------------------------------------------------------------------------------|
| `name` | :+1: | Friendly area name. |
| `desc` | :+1: | Friendly area description. |
| `sort` | :-1: | Set to a number to override the default alpha-numeric sort order based on the `name` field. |
| `default` | :-1: | Specify `true` to make this the default area (e.g. assigned to new users) |
| `acs` | :-1: | A standard [ACS](../configuration/acs.md) block. See **ACS** below. |
| `autoSignatures` | :-1: | Set to `false` to disable auto-signatures in this area. |
| `realNames` | :-1: | Set to `true` to use real names in this area. |
### ACS
An optional standard [ACS](../configuration/acs.md) block can be supplied with the following rules:
* `read`: ACS required to read (see) this area. Defaults to `GM[users]`.
* `write`: ACS required to write (post) to this area. Defaults to `GM[users]`.
### Example
```hjson
messageConferences: {
local: {
// ... see above ...
areas: {
enigma_dev: { // Area tag - required elsewhere!
name: ENiGMA 1/2 Development
desc: ENiGMA 1/2 development and discussion!
sort: 1
default: true
acs: {
read: GM[users] // default
write: GM[l33t] // super elite ENiGMA 1/2 users!
}
}
}
}
}
```
## Importing
FidoNet style `.na` files as well as legacy `AREAS.BBS` files in common formats can be imported using `oputil.js mb import-areas`. See [The oputil CLI](../admin/oputil.md) for more information and usage.

View file

@ -0,0 +1,107 @@
---
layout: page
title: FidoNet-Style Networks (FTN)
---
## FidoNet-Style Networks (FTN)
[FidoNet](https://en.wikipedia.org/wiki/FidoNet) proper and other FidoNet-Style networks are supported by ENiGMA½. A bit of configuration and you'll be up and running in no time!
:scroll: Before proceeding you may wish to check [Setting up FTN-style message networks with ENiGMA½ BBS](https://medium.com/@alpha_11845/setting-up-ftn-style-message-networks-with-enigma%C2%BD-bbs-709b22a1ae0d) by Alpha. An excellent guide detailing some of the setup described here!
### Configuration
Getting a fully running FTN enabled system requires a few configuration points:
1. `messageNetworks.ftn.networks`: Declares available networks. That is, networks you wish to sync up with.
2. `messageNetworks.ftn.areas`: Establishes local area mappings (ENiGMA½ to/from FTN area tags) and per-area specific configurations.
3. `scannerTossers.ftn_bso`: General configuration for the scanner/tosser (import/export) process. This is also where we configure per-node (uplink) settings.
:information_source: ENiGMA½'s `ftn_bso` module is **not a mailer** and makes **no attempts** to perform packet transport! An external utility such as Binkd is required for this task.
#### Networks
The `networks` block is a per-network configuration where each entry's ID (or "key") may be referenced elsewhere in `config.hjson`. For example, consider two networks: ArakNet (`araknet`) and fsxNet (`fsxnet`):
```hjson
{
messageNetworks: {
ftn: {
networks: {
// it is recommended to use lowercase network tags
fsxnet: {
defaultZone: 21
localAddress: "21:1/121"
}
araknet: {
defaultZone: 10
localAddress: "10:101/9"
}
}
}
}
}
```
#### Areas
The `areas` section describes a mapping of local **area tags** configured in your `messageConferences` (see [Configuring a Message Area](configuring-a-message-area.md)) to a message network (described above), a FTN specific area tag, and remote uplink address(s). This section can be thought of similar to the *AREAS.BBS* file used by other BBS packages.
When ENiGMA½ imports messages, they will be placed in the local area that matches key under `areas` while exported messages will be sent to the relevant `network`.
| Config Item | Required | Description |
|-------------|----------|----------------------------------------------------------|
| `network` | :+1: | Associated network from the `networks` section above |
| `tag` | :+1: | FTN area tag (ie: `FSX_GEN`) |
| `uplinks` | :+1: | An array of FTN address uplink(s) for this network |
Example:
```hjson
{
messageNetworks: {
ftn: {
areas: {
// it is recommended to use lowercase area tags
fsx_general: // *local* tag found within messageConferences
network: fsxnet // that we are mapping to this network
tag: FSX_GEN // ...and this remote FTN-specific tag
uplinks: [ "21:1/100" ] // a single string also allowed here
}
}
}
}
}
```
:bulb: You can import `AREAS.BBS` or FTN style `.NA` files using [oputil](../admin/oputil.md)!
#### A More Complete Example
Below is a more complete *example* illustrating some of the concepts above:
```hjson
{
messageNetworks: {
ftn: {
networks: {
fsxnet: {
defaultZone: 21
localAddress: "21:1/121"
}
}
areas: {
fsx_general: {
network: fsxnet
// ie as found in your info packs .NA file
tag: FSX_GEN
uplinks: [ "21:1/100" ]
}
}
}
}
}
```
:information_source: Remember for a complete FTN experience, you'll probably also want to configure [FTN/BSO scanner/tosser](bso-import-export.md) settings.
#### FTN/BSO Scanner Tosser
Please see the [FTN/BSO Scanner/Tosser](bso-import-export.md) documentation for information on this area.

View file

@ -0,0 +1,24 @@
---
layout: page
title: Message Networks
---
## Message Networks
ENiGMA½ supports external networks such as FidoNet-Style (FTN) and QWK by the way of importing and exporting to/from it's own internal format. This allows for a very flexible system that can easily be extended by creating new network modules.
All message network configuration occurs under the `messageNetworks.<name>` block in `config.hjson` (where name is something such as `ftn` or `qwk`). The most basic of external message network configurations generally comprises of two sections:
1. `messageNetworks.<name>.networks`: Global/general configuration for a particular network where `<name>` is for example `ftn` or `qwk`.
2. `messageNetworks.<name>.areas`: Provides mapping of ENiGMA½ **area tags** to their external counterparts.
:information_source: A related section under `scannerTossers.<name>` may provide configuration for scanning (importing) and tossing (exporting) messages for a particular network type. As an example, FidoNet-Style networks often work with BinkleyTerm Style Outbound (BSO) and thus the [FTN/BSO scanner/tosser](bso-import-export.md) (`ftn_bso`) module.
### Currently Supported Networks
The following networks are supported out of the box. Remember that you can create modules to add others if desired!
#### FidoNet-Style (FTN)
FidoNet and FidoNet style (FTN) networks as well as a [FTN/BSO scanner/tosser](bso-import-export.md) (`ftn_bso` module) are configured via the `messageNetworks.ftn` and `scannerTossers.ftn_bso` blocks in `config.hjson`.
See [FidoNet-Style Networks](ftn.md) for more information.
#### QWK
See [QWK and QWK-Net Style Networks](qwk.md) for more information.

View file

@ -0,0 +1,35 @@
---
layout: page
title: Netmail
---
ENiGMA support import and export of Netmail from the Private Mail area. `RiPuk @ 21:1/136` and `RiPuk <21:1/136>` 'To' address formats are supported.
## Netmail Routing
A configuration block must be added to the `scannerTossers::ftn_bso` `config.hjson` section to tell the ENiGMA½ tosser where to route NetMail.
The following configuration would tell ENiGMA½ to route all netmail addressed to 21:* through 21:1/100, and all 46:* netmail through 46:1/100:
````hjson
scannerTossers: {
/* other scannerTosser config removed for clarity */
ftn_bso: {
netMail: {
routes: {
"21:*" : {
address: "21:1/100"
network: fsxnet
}
"46:*" : {
address: "46:1/100"
network: agoranet
}
}
}
}
}
````
The `network` tag must match the networks defined in `messageNetworks::ftn::networks` within `config.hjson`.

View file

@ -0,0 +1,47 @@
---
layout: page
title: QWK Support
---
## QWK and QWK-Net Style Networks
As like all other networks such as FidoNet-Style (FTN) networks, ENiGMA½ considers QWK external to the system but can import and export the format.
### Supported Standards
QWK must be considered a semi-standard as there are many implementations. What follows is a short & incomplete list of such standards ENiGMA½ supports:
* The basic [QWK packet format](http://fileformats.archiveteam.org/wiki/QWK).
* [QWKE extensions](https://github.com/wwivbbs/wwiv/blob/master/specs/qwk/qwke.txt).
* [Synchronet BBS style extensions](http://wiki.synchro.net/ref:qwk) such as `HEADERS.DAT`, `@` kludges, and UTF-8 handling.
### Configuration
QWK configuration occurs in the `messageNetworks.qwk` config block of `config.hjson`. As QWK wants to deal with conference numbers and ENiGMA½ uses area tags (conferences and conference tags are only used for logical grouping), a mapping can be made.
:information_source: During a regular, non QWK-Net exports, conference numbers can be auto-generated. Note that for QWK-Net style networks, you will need to create mappings however.
Example:
```hjson
{
messageNetworks: {
qwk: {
areas: {
general: { // local ENiGMA½ area tag
conference: 1 // conference number to map to
}
}
}
}
}
```
### oputil
The `oputil.js` utility can export packet files, dump the messages of a packet to stdout, etc. See [the oputil documentation](../admin/oputil.md) for more information.
### Offline Readers
A few of the offline readers that have been tested with QWK packet files produced by ENiGMA½:
| Software | Status | Notes |
|----------|--------|-------|
| MultiMail/Win v0.52 | Supported | Private mail seems to break even with bundles from other systems |
| SkyReader/W32 v1.00 | Supported | Works well. No QWKE or HEADERS.DAT support. Gets confused with low conference numbers. |
There are also [many other readers](https://www.softwolves.pp.se/old/2000/faq/bwprod) for various systems.

View file

@ -0,0 +1,17 @@
---
layout: page
title: User Interruptions
---
## User Interruptions
ENiGMA½ provides functionality to "interrupt" a user for various purposes such as a [node-to-node message](../modding/node-msg.md). User interruptions can be queued and displayed at the next opportune time such as when switching to a new menu, or realtime if appropriate.
## Standard Menu Behavior
Standard menus control interruption by the `interrupt` config block option, which may be set to one of the following values:
* `never`: Never interrupt the user when on this menu.
* `queued`: Queue interrupts for the next opportune time. Any queued message(s) will then be shown. This is the default.
* `realtime`: If possible, display messages in realtime. That is, show them right away. Standard menus that do not override default behavior will show the message then reload.
## See Also
See [user_interrupt_queue.js](/core/user_interrupt_queue.js) as well as usage within [menu_module.js](/core/menu_module.js).

View file

@ -0,0 +1,22 @@
---
layout: page
title: Auto Signature Editor
---
## The Auto Signature Editor
The built in `autosig_edit` module allows users to edit their auto signatures (AKA "autosig").
### Theming
The following MCI codes are available:
* MCI 1 (ie: `MT1`): Editor
* MCI 2 (ie: `BT2`): Save button
### Disabling Auto Signatures
Auto Signature support can be disabled for a particular message area by setting `autoSignatures` to false in the area's configuration block.
Example:
```hjson
my_area: {
name: My Area
autoSignatures: false
}
```

View file

@ -0,0 +1,24 @@
---
layout: page
title: BBS List
---
## The BBS List Module
The built in `bbs_list` module provides the ability for users to manage entries to other Bulletin Board Systems.
## Configuration
### Config Block
Available `config` block entries:
* `youSubmittedFormat`: Provides a format for entries that were submitted (and therefor ediable) by the current user. Defaults to `'{submitter} (You!)'`. Utilizes the same `itemFormat` object as entries described below.
### Theming
The following `itemFormat` object is provided to MCI 1 (ie: `%VM1`) (the BBS list):
* `id`: Row ID
* `bbsName`: System name. Note that `{text}` also contains this value.
* `sysOp`: System Operator
* `telnet`: Telnet address
* `www`: Web address
* `location`: System location
* `software`: System's software
* `submitter`: Username of entry submitter
* `submitterUserId`: User ID of submitter
* `notes`: Any additional notes about the system

View file

@ -0,0 +1,61 @@
---
layout: page
title: Door Servers
---
## The bbs_link Module
Native support for [BBSLink](http://www.bbslink.net/) doors is provided via the `bbs_link` module.
Configuration for a BBSLink door is straight forward. Take a look at the following example for launching Tradewars 2002:
```hjson
doorTradeWars2002BBSLink: {
desc: Playing TW 2002 (BBSLink)
module: bbs_link
config: {
sysCode: XXXXXXXX
authCode: XXXXXXXX
schemeCode: XXXXXXXX
door: tw
}
}
```
Fill in your credentials in `sysCode`, `authCode`, and `schemeCode` and that's it!
## The door_party Module
The module `door_party` provides native support for [DoorParty!](http://www.throwbackbbs.com/) Configuration is quite easy:
```hjson
doorParty: {
desc: Using DoorParty!
module: door_party
config: {
username: XXXXXXXX
password: XXXXXXXX
bbsTag: XX
}
}
```
Fill in `username`, `password`, and `bbsTag` with credentials provided to you and you should be in business!
## The CombatNet Module
The `combatnet` module provides native support for [CombatNet](http://combatnet.us/). Add the following to your menu config:
````hjson
combatNet: {
desc: Using CombatNet
module: combatnet
config: {
bbsTag: CBNxxx
password: XXXXXXXXX
}
}
````
Update `bbsTag` (in the format CBNxxx) and `password` with the details provided when you register, then
you should be ready to rock!
## The Exodus Module
TBC

View file

@ -0,0 +1,13 @@
---
layout: page
title: Existing Mods
---
Many "addon" modules exist and have been released. Below are a few:
| Name | Author | Description |
|-----------------------------|-------------|-------------|
| Married Bob Fetch Event | NuSkooler | An event for fetching the latest Married Bob ANSI's for display on you board. ACiDic release [ACD-MB4E.ZIP](https://l33t.codes/outgoing/ACD/ACD-MB4E.ZIP). Can also be [found on GitHub](https://github.com/NuSkooler/enigma-bbs-married_bob_evt) |
| Latest Files Announcement | NuSkooler | An event for posting the latest file arrivals of your board to message areas such as FTN style networks. ACiDic release [ACD-LFA1.ZIP](https://l33t.codes/outgoing/ACD/ACD-LFA1.ZIP). Also [found on GitHub](https://github.com/NuSkooler/enigma-bbs-latest_files_announce_evt) |
| Message Post Event | NuSkooler | An event for posting messages/ads to networks. ACiDic release [ACD-MP4E.ZIP](https://l33t.codes/outgoing/ACD/ACD-MP4E.ZIP) |
See also [ACiDic BBS Mods by NuSkooler](https://l33t.codes/acidic-mods-by-myself/)

View file

@ -0,0 +1,95 @@
---
layout: page
title: File Area List
---
## The File Area List Module
The built in `file_area_list` module provides a very flexible file listing UI.
## Configuration
### Config Block
Available `config` block entries:
* `art`: Sub-configuration block used to establish art files used for file browsing:
* `browse`: The main browse screen.
* `details`: The main file details screen.
* `detailsGeneral`: The "general" tab of the details page.
* `detailsNfo`: The "NFO" viewer tab of the detials page.
* `detailsFileList`: The file listing tab of the details page (ie: used for listing archive contents).
* `help`: The help page.
* `hashTagsSep`: Separator for hash entries. Defaults to ", ".
* `isQueuedIndicator`: Indicator for items that are in the users download queue. Defaults to "Y".
* `isNotQueuedIndicator`: Indicator for items that are _not_ in the users download queue. Defaults to "N".
* `userRatingTicked`: Indicator for a items current _n_/5 "star" rating. Defaults to "\*". `userRatingTicked` and `userRatingUnticked` are combined to build strings such as "***--" for 3/5 rating.
* `userRatingUnticked`: Indicator for missing "stars" in a items _n_/5 rating. Defaults to "-". `userRatingTicked` and `userRatingUnticked` are combined to build strings such as "***--" for 3/5 rating.
* `webDlExpireTimeFormat`: Presents the expiration time of a web download URL. Defaults to current theme → system `short` date/time format.
* `webDlLinkNeedsGenerated`: Text to present when no web download link is yet generated. Defaults to "Not yet generated".
* `webDlLinkNoWebserver`: Text to present when no web download is available (ie: webserver not enabled). Defaults to "Web server is not enabled".
* `notAnArchiveFormat`: Presents text for the "archive type" field for non-archives. Defaults to "Not an archive".
* `uploadTimestampFormat`: Timestamp format for `xxxxxxInfoFormat##`. Defaults to current theme → system `short` date format. See also **Custom Info Formats** below.
Remember that entries such as `isQueuedIndicator` and `userRatingTicked` may contain pipe color codes!
## Custom Info Formats
Additional `config` block entries can set `xxxxxxInfoFormat##` formatting (where xxxxxx is the page name and ## is 10...99 such as `browseInfoFormat10`) for the various available pages:
* `browseInfoFormat##` for the `browse` page. See **Browse Page** below.
* `detailsInfoFormat##` for the `details` page. See **Details Page** below.
* `detailsGeneralInfoFormat##` for the `detailsGeneral` tab. See **Details Page - General Tab** below.
* `detailsNfoInfoFormat##` for the `detialsNfo` tab. See **Details Page - NFO/README Viewer Tab** below.
* `detailsFileListInfoFormat##` for the `detailsFileList` tab. See **Details Page - Archive/File Listing Tab** below.
## Theming
### Browse Page
The browse page uses the `browse` art described above. The following MCI codes are available:
* MCI 1 (ie: `%MT1`): File's short description (user entered, FILE_ID.DIZ, etc.).
* MCI 2 (ie: `%HM2`): Navigation menu.
* MCI 10...99: Custom entires with the following format members:
* `{fileId}`: File identifier.
* `{fileName}`: File name (long).
* `{desc}`: File short description (user entered, FILE_ID.DIZ, etc.).
* `{descLong}`: File's long description (README.TXT, SOMEGROUP.NFO, etc.).
* `{uploadByUserName}`: User name of user that uploaded this file, or "N/A".
* `{uploadByUserId}`: User ID of user that uploaded this file, or "N/A".
* `{userRating}`: User rating of file as a number.
* `{userRatingString}`: User rating of this file as a string formatted with `userRatingTicked` and `userRatingUnticked` described above.
* `{areaTag}`: Area tag.
* `{areaName}`: Area name or "N/A".
* `{areaDesc}`: Area description or "N/A".
* `{fileSha256}`: File's SHA-256 value in hex.
* `{fileMd5}`: File's MD5 value in hex.
* `{fileSha1}`: File's SHA1 value in hex.
* `{fileCrc32}`: File's CRC-32 value in hex.
* `{estReleaseYear}`: Estimated release year of this file.
* `{dlCount}`: Number of times this file has been downloaded.
* `{byteSize}`: Size of this file in bytes.
* `{archiveType}`: Archive type of this file determined by system mappings, or "N/A".
* `{archiveTypeDesc}`: A more descriptive archive type based on system mappings, file extention, etc. or "N/A" if it cannot be determined.
* `{shortFileName}`: Short DOS style 8.3 name available for some scenarios such as TIC import, or "N/A".
* `{ticOrigin}`: Origin from TIC imported files "Origin" field, or "N/A".
* `{ticDesc}`: Description from TIC imported files "Desc" field, or "N/A".
* `{ticLDesc}`: Long description from TIC imported files "LDesc" field joined by a line feed, or "N/A".
* `{uploadTimestamp}`: Upload timestamp formatted with `browseUploadTimestampFormat`.
* `{hashTags}`: A string of hash tags(s) separated by `hashTagsSep` described above. "(none)" if there are no tags.
* `{isQueued}`: Indicates if a item is currently in the user's download queue presented as `isQueuedIndicator` or `isNotQueuedIndicator` described above.
* `{webDlLink}`: Web download link if generated else `webDlLinkNeedsGenerated` or `webDlLinkNoWebserver` described above.
* `{webDlExpire}`: Web download link expiration using `webDlExpireTimeFormat` described above.
### Details Page
The details page uses the `details` art described above. The following MCI codes are available:
* MCI 1 (ie: `%HM1`): Navigation menu
* `%XY2`: Info area's top X,Y position.
* `%XY3`: Info area's bottom X,Y position.
* MCI 10...99: Custom entries with the format options described above in **Browse Page** via the `detailsInfoFormat##` `config` block entry.
### Details Page - General Tab
The details page general tab uses the `detailsGeneral` art described above. The following MCI codes are available:
* MCI 10...99: Custom entries with the format options described above in **Browse Page** via the `detailsGeneralInfoFormat##` `config` block entry.
### Details Page - NFO/README Viewer Tab
The details page nfo tab uses the `detailsNfo` art described above. The following MCI codes are available:
* MCI 1 (ie: `%MT1`): NFO/README viewer using the entries `longDesc`.
* MCI 10...99: Custom entries with the format options described above in **Browse Page** via the `detailsNfoInfoFormat##` `config` block entry.
### Details Page - Archive/File Listing Tab
The details page file list tab uses the `detailsFileList` art described above. The following MCI codes are available:
* MCI 1 (ie: `%VM1`): List of entries in archive. Entries are formatted using the standard `itemFormat` and `focusItemFormat` properties of the view and have all of the format options described above in **Browse Page**.
* MCI 10...99: Custom entries with the format options described above in **Browse Page** via the `detailsFileListInfoFormat##` `config` block entry.

View file

@ -0,0 +1,23 @@
---
layout: page
title: File Base Download Manager
---
## File Base Download Manager Module
The `file_base_download_manager` module provides a download queue manager for "legacy" (X/Y/Z-Modem, etc.) downloads. Web (HTTP/HTTPS) download functionality can be optionally available when the web content server is enabled.
## Configuration
### Configuration Block
Available `config` block entries:
* `webDlExpireTimeFormat`: Sets the moment.js style format for web download expiration date/time.
* `fileTransferProtocolSelection`: Overrides the default `fileTransferProtocolSelection` target for a protocol selection menu.
* `emptyQueueMenu`: Overrides the default `fileBaseDownloadManagerEmptyQueue` target for menu to show when the users D/L queue is empty.
### Theming
The following `itemFormat` object is provided to MCI 1 (ie: `%VM1`) and MCI 10+ custom fields:
* `fileId`: File ID.
* `areaTag`: Area tag.
* `fileName`: Entry filename.
* `path`: Full file path.
* `byteSize`: Size in bytes of file.
* `webDlLink`: Web download link including [VTX style ANSI ESC sequences](https://raw.githubusercontent.com/codewar65/VTX_ClientServer/master/vtx.txt).
* `webDlExpire`: Expiration date/time for this link. Formatted using `webDlExpireTimeFormat`.

View file

@ -0,0 +1,26 @@
---
layout: page
title: File Base Web Download Manager
---
## File Base Web Download Manager Module
The `file_base_web_download_manager` module provides a download queue manager for web (HTTP/HTTPS) based downloads. This module relies on having the web server enabled at a minimum.
Web downloads can be a convienent way for users to download larger (100+ MiB) files where legacy protocols often have trouble. Additionally, batch downloads can be streamed to users in a single zip archive.
## Configuration
### Configuration Block
Available `config` block entries:
* `webDlExpireTimeFormat`: Sets the moment.js style format for web download expiration date/time.
* `emptyQueueMenu`: Overrides the default `fileBaseDownloadManagerEmptyQueue` target for menu to show when the users D/L queue is empty.
### Theming
The following `itemFormat` object is provided to MCI 1 (ie: `%VM1`) and custom range MCI 10+ custom fields:
* `fileId`: File ID.
* `areaTag`: Area tag.
* `fileName`: Entry filename.
* `path`: Full file path.
* `byteSize`: Size in bytes of file.
* `webDlLinkRaw`: Web download link.
* `webDlLink`: Web download link including [VTX style ANSI ESC sequences](https://raw.githubusercontent.com/codewar65/VTX_ClientServer/master/vtx.txt).
* `webDlExpire`: Expiration date/time for this link. Formatted using `webDlExpireTimeFormat`.

View file

@ -0,0 +1,13 @@
---
layout: page
title: File Transfer Protocol Select
---
## The Rumorz Module
The built in `file_transfer_protocol_select` module provides a way to select a legacy file transfer protocol (X/Y/Z-Modem, etc.) for upload/downloads.
## Configuration
### Theming
The following `itemFormat` object is provided to MCI 1 (ie: `%VM1`) (the protocol list):
* `name`: The name of the protocol. Each entry is +op defined in `config.hjson` with defaults found in `config_default.js`. Note that the standard `{text}` field also contains this value.

View file

@ -0,0 +1,40 @@
---
layout: page
title: Last Callers
---
## The Last Callers Module
The built in `last_callers` module provides flexible retro last callers mod.
## Configuration
### Config Block
Available `config` block entries:
* `dateTimeFormat`: [moment.js](https://momentjs.com) style format. Defaults to current theme → system `short` format.
* `user`: User options:
* `collapse`: Collapse or roll up entries that fall within the period specified. May be a string in the form of `30 minutes`, `3 weeks`, `1 hour`, etc.
* `sysop`: Sysop options:
* `collapse`: Collapse or roll up entries that fall within the period specified. May be a string in the form of `30 minutes`, `3 weeks`, `1 hour`, etc.
* `hide`: Hide all +op logins
* `actionIndicators`: Maps user events/actions to indicators. For example: `userDownload` to "D". Available indicators:
* `newUser`: User is new.
* `dlFiles`: User downloaded file(s).
* `ulFiles`: User uploaded file(s).
* `postMsg`: User posted message(s) to the message base, EchoMail, etc.
* `sendMail`: User sent _private_ mail.
* `runDoor`: User ran door(s).
* `sendNodeMsg`: User sent a node message(s).
* `achievementEarned`: User earned an achievement(s).
* `actionIndicatorDefault`: Default indicator when an action is not set. Defaults to "-".
Remember that entries such as `actionIndicators` and `actionIndicatorDefault` may contain pipe color codes!
### Theming
The following `itemFormat` object is provided to MCI 1 (ie: `%VM1`):
* `userId`: User ID.
* `userName`: Login username.
* `realName`: User's real name.
* `ts`: Timestamp in `dateTimeFormat` format.
* `location`: User's location.
* `affiliation` or `affils`: Users affiliations.
* `actions`: A string built by concatenating action indicators for a users logged in session. For example, given a indicator of `userDownload` mapped to "D", the string may be "-D----". The format was made popular on Amiga style boards.

View file

@ -0,0 +1,244 @@
---
layout: page
title: Local Doors
---
## Local Doors
ENiGMA½ has many ways to add doors to your system. In addition to the [many built in door server modules](door-servers.md), local doors are of course also supported using the ! The `abracadabra` module!
:information_source: See also [Lets add a DOS door to Enigma½ BBS](https://medium.com/retro-future/lets-add-a-dos-game-to-enigma-1-2-41f257deaa3c) by Robbie Whiting for a great writeup on adding doors!
## The abracadabra Module
The `abracadabra` module provides a generic and flexible solution for many door types. Through this module you can execute native processes & scripts directly, and perform I/O through standard I/O (stdio) or a temporary TCP server.
### Configuration
The `abracadabra` `config` block can contain the following members:
| Item | Required | Description |
|------|----------|-------------|
| `name` | :+1: | Used as a key for tracking number of clients using a particular door. |
| `dropFileType` | :-1: | Specifies the type of dropfile to generate (See **Dropfile Types** below). Can be omitted or set to `none`. |
| `cmd` | :+1: | Path to executable to launch. |
| `args` | :-1: | Array of argument(s) to pass to `cmd`. See **Argument Variables** below for information on variables that can be used here.
| `cwd` | :-1: | Sets the Current Working Directory (CWD) for `cmd`. Defaults to the directory of `cmd`. |
| `env` | :-1: | Sets the environment. Supplied in the form of an map: `{ SOME_VAR: "value" }`
| `nodeMax` | :-1: | Max number of nodes that can access this door at once. Uses `name` as a tracking key. |
| `tooManyArt` | :-1: | Art spec to display if too many instances are already in use. |
| `io` | :-1: | How to process input/output (I/O). Can be `stdio` or `socket`. When using `stdio`, I/O is handled via standard stdin/stdout. When using `socket` a temporary socket server is spawned that can be connected back to. The server listens on localhost on `{srvPort}` (See **Argument Variables** below for more information). Default value is `stdio`. |
| `encoding` | :-1: | Sets the **door's** encoding. Defaults to `cp437`. Linux binaries often produce `utf8`. |
#### Dropfile Types
Dropfile types specified by `dropFileType`:
| Value | Description |
|-------|-------------|
| `DOOR` | [DOOR.SYS](https://web.archive.org/web/20160325192739/http://goldfndr.home.mindspring.com/dropfile/doorsys.htm)
| `DOOR32` | [DOOR32.SYS](https://raw.githubusercontent.com/NuSkooler/ansi-bbs/master/docs/dropfile_formats/door32_sys.txt)
| `DORINFO` | [DORINFOx.DEF](https://web.archive.org/web/20160321190038/http://goldfndr.home.mindspring.com/dropfile/dorinfo.htm)
#### Argument Variables
The following variables may be used in `args` entries:
| Variable | Description | Example |
|----------|-------------|---------|
| `{node}` | Current node number. | `1` |
| `{dropFile}` | Dropfile _filename_ only. | `DOOR.SYS` |
| `{dropFilePath}` | Full path to generated dropfile. The system places dropfiles in the path set by `paths.dropFiles` in `config.hjson`. | `C:\enigma-bbs\drop\node1\DOOR.SYS` |
| `{userId}` | Current user ID. | `420` |
| `{userName}` | [Sanitized](https://www.npmjs.com/package/sanitize-filename) username. Safe for filenames, etc. If the full username is sanitized away, this will resolve to something like "user_1234". | `izard` |
| `{userNameRaw}` | _Raw_ username. May not be safe for filenames! | `\/\/izard` |
| `{srvPort}` | Temporary server port when `io` is set to `socket`. | `1234` |
| `{cwd}` | Current Working Directory. | `/home/enigma-bbs/doors/foo/` |
Example `args` member using some variables described above:
```hjson
args: [
"-D", "{dropFilePath}",
"-N", "{node}"
"-U", "{userId}"
]
```
### DOSEMU with abracadabra
[DOSEMU](http://www.dosemu.org/) can provide a good solution for running legacy DOS doors when running on Linux systems. For this, we will create a virtual serial port (COM1) that communicates via stdio.
As an example, here are the steps for setting up Pimp Wars:
First, create a `dosemu.conf` file with the following contents:
```
$_cpu = "80486"
$_cpu_emu = "vm86"
$_external_char_set = "utf8"
$_internal_char_set = "cp437"
$_term_updfreq = (8)
$_layout = "us"
$_rawkeyboard = (0)
$_com1 = "virtual"
```
The line `$_com1 = "virtual"` tells DOSEMU to use `stdio` as a virtual serial port on COM1.
Next, we create a virtual **X** drive for Pimp Wars to live such as `/enigma-bbs/DOS/X/PW` and map it with a custom `AUTOEXEC.BAT` file within DOSEMU:
```
@echo off
path d:\bin;d:\gnu;d:\dosemu
set TEMP=c:\tmp
prompt $P$G
REM http://www.pcmicro.com/bnu/
C:\BNU\BNU.COM /L0:57600,8N1 /F
lredir.com x: linux\fs\enigma-bbs\DOS\X
unix -e
```
Note that we also have the [BNU](http://www.pcmicro.com/bnu/) FOSSIL driver installed at `C:\BNU\\`. Another option would be to install this to X: somewhere as well.
Finally, let's create a `menu.hjson` entry to launch the game:
```hjson
doorPimpWars: {
desc: Playing PimpWars
module: abracadabra
config: {
name: PimpWars
dropFileType: DORINFO
cmd: /usr/bin/dosemu
args: [
"-quiet",
"-f",
"/path/to/dosemu.conf",
"X:\\PW\\START.BAT {dropFile} {node}"
],
nodeMax: 1
tooManyArt: DOORMANY
io: stdio
}
}
```
### Shared Socket Descriptors
Due to Node.js limitations, ENiGMA½ does not _directly_ support `DOOR32.SYS` style socket descriptor sharing (other `DOOR32.SYS` features are fully supported). However, a separate binary called [bivrost!](https://github.com/NuSkooler/bivrost) can be used. bivrost! is available for Windows and Linux x86/i686 and x86_64/AMD64. Other platforms where [Rust](https://www.rust-lang.org/) builds are likely to work as well.
#### Example configuration
Below is an example `menu.hjson` entry using bivrost! to launch a door:
```hjson
doorWithBivrost: {
desc: Bivrost Example
module: abracadabra
config: {
name: BivrostExample
dropFileType: DOOR32
cmd: "C:\\enigma-bbs\\utils\\bivrost.exe"
args: [
"--port", "{srvPort}", // bivrost! will connect this port on localhost
"--dropfile", "{dropFilePath}", // ...and read this DOOR32.SYS produced by ENiGMA½
"--out", "C:\\doors\\jezebel", // ...and produce a NEW DOOR32.SYS here.
//
// Note that the final <target> params bivrost! will use to
// launch the door are grouped here. The {fd} variable could
// also be supplied here if needed.
//
"C:\\door\\door.exe C:\\door\\door32.sys"
],
nodeMax: 1
tooManyArt: DOORMANY
io: socket
}
}
```
Please see the [bivrost!](https://github.com/NuSkooler/bivrost) documentation for more information.
#### Phenom Productions Releases
Pre-built binaries of bivrost! have been released under [Phenom Productions](https://www.phenomprod.com/) and can be found on various boards.
#### Alternative Workarounds
Alternative workarounds include [Telnet Bridge module](telnet-bridge.md) to hook up Telnet-accessible (including local) door servers -- It may also be possible bridge via [NET2BBS](http://pcmicro.com/netfoss/guide/net2bbs.html).
### QEMU with abracadabra
[QEMU](http://wiki.qemu.org/Main_Page) provides a robust, cross platform solution for launching doors under many platforms (likely anywhere Node.js is supported and ENiGMA½ can run). Note however that there is an important and major caveat: **Multiple instances of a particular door/OS image should not be run at once!** Being more flexible means being a bit more complex. Let's look at an example for running L.O.R.D. under a UNIX like system such as Linux or FreeBSD.
Basically we'll be creating a bootstrap shell script that generates a temporary node specific `GO.BAT` to launch our door. This will be called from `AUTOEXEC.BAT` within our QEMU FreeDOS partition.
#### Step 1: Create a FreeDOS image
[FreeDOS](http://www.freedos.org/) is a free mostly MS-DOS compatible DOS package that works well for running 16bit doors. Follow the [QEMU/FreeDOS](https://en.wikibooks.org/wiki/QEMU/FreeDOS) guide for creating an `freedos_c.img`. This will contain FreeDOS itself and installed BBS doors.
After this is complete, copy LORD to C:\DOORS\LORD within FreeDOS. An easy way to tranfer files from host to DOS is to use QEMU's vfat as a drive. For example:
```bash
qemu-system-i386 -localtime /home/enigma/dos/images/freedos_c.img -hdb fat:/path/to/downloads
```
With the above you can now copy files from D: to C: within FreeDOS and add the following to it's `autoexec.bat`:
```bat
CALL E:\GO.BAT
```
#### Step 2: Create a bootstrap script
Our bootstrap script will prepare `GO.BAT` and launch FreeDOS. Below is an example:
```bash
#!/bin/bash
NODE=$1
DROPFILE=D:\\$2
SRVPORT=$3
mkdir -p /home/enigma/dos/go/node$NODE
cat > /home/enigma/dos/go/node$NODE/GO.BAT <<EOF
C:
CD \FOSSIL\BNU
BNU.COM
CD \DOORS\LORD
COPY /Y $DROPFILE
CALL START.BAT $NODE
FDAPM POWEROFF
EOF
unix2dos /home/enigma/dos/go/node$NODE/GO.BAT
qemu-system-i386 -localtime /home/enigma/dos/images/freedos_c.img -chardev socket,port=$SRVPORT,nowait,host=localhost,id=s0 -device isa-serial,chardev=s0 -hdb fat:/home/enigma/xibalba/dropfiles/node$NODE -hdc fat:/home/enigma/dos/go/node$NODE -nographic
```
Note the `qemu-system-i386` line. We're telling QEMU to launch and use localtime for the clock, create a character device that connects to our temporary server port on localhost and map that to a serial device. The `-hdb` entry will represent the D: drive where our dropfile is generated, while `-hdc` is the path that `GO.BAT` is generated in (`E:\GO.BAT`). Finally we specify `-nographic` to run headless.
For doors that do not *require* a FOSSIL driver, it is recommended to not load or use one unless you are having issues.
##### Step 3: Create a menu entry
Finally we can create a `menu.hjson` entry using the `abracadabra` module:
```hjson
doorLORD: {
desc: Playing L.O.R.D.
module: abracadabra
config: {
name: LORD
dropFileType: DOOR
cmd: /home/enigma/dos/scripts/lord.sh
args: [
"{node}",
"{dropFile}",
"{srvPort}",
],
nodeMax: 1
tooManyArt: DOORMANY
io: socket
}
}
```
## See Also
* [Telnet Bridge](telnet-bridge.md)
* [Door Servers](door-servers.md)
## Additional Resources
### DOS Emulation
* [DOSEMU](http://www.dosemu.org/)
* [DOSBox-X](https://github.com/joncampbell123/dosbox-x)
### Door Downloads & Support Sites
#### General
* http://bbsfiles.com/
* http://bbstorrents.bbses.info/
#### L.O.R.D.
* http://lord.lordlegacy.com/

View file

@ -0,0 +1,14 @@
---
layout: page
title: Menu Modules
---
## Menu Modules
Menu entries found within `menu.hjson` are backed by *menu modules*.
## Creating a New Module
TODO
### Lifecycle
TODO

View file

@ -0,0 +1,17 @@
---
layout: page
title: Message Area List
---
## The Message Area List Module
The built in `msg_area_list` module provides a menu to display and change between message areas in the users current conference.
### Theming
The following `itemFormat` object is provided to MCI 1 (ie: `%VM1`):
* `index`: 1-based index into list.
* `areaTag`: Area tag.
* `name` or `text`: Display name.
* `desc`: Description.
The following additional MCIs are updated as the user changes selections in the main list:
* MCI 2 (ie: `%TL2` or `%M%2`) is updated with the area description.
* MCI 10+ (ie `%TL10`...) are custom ranges updated with the same information available above in `itemFormat`. Use `areaListItemFormat##`.

View file

@ -0,0 +1,18 @@
---
layout: page
title: Message Conference List
---
## The Message Conference List Module
The built in `msg_conf_list` module provides a menu to display and change between message conferences.
### Theming
The following `itemFormat` object is provided to MCI 1 (ie: `%VM1`):
* `index`: 1-based index into list.
* `confTag`: Conference tag.
* `name` or `text`: Display name.
* `desc`: Description.
* `areaCount`: Number of areas in this conference.
The following additional MCIs are updated as the user changes selections in the main list:
* MCI 2 (ie: `%TL2` or `%M%2`) is updated with the conference description.
* MCI 10+ (ie `%TL10`...) are custom ranges updated with the same information available above in `itemFormat`.

View file

@ -0,0 +1,41 @@
---
layout: page
title: Node to Node Messaging
---
## The Node to Node Messaging Module
The node to node messaging (`node_msg`) module allows users to send messages to one or more users on different nodes. Messages delivered to nodes follow standard [User Interruption](../misc/user-interrupt.md) rules.
## Configuration
### Config Block
Available `config` block entries:
* `dateTimeFormat`: [moment.js](https://momentjs.com) style format. Defaults to current theme → system `short` format.
* `messageFormat`: Format string for sent messages. Defaults to `Message from {fromUserName} on node {fromNodeId}:\r\n{message}`. The following format object members are available:
* `fromUserName`: Username who sent the message.
* `fromRealName`: Real name of user who sent the message.
* `fromNodeId`: Node ID where the message was sent from.
* `message`: User entered message. May contain pipe color codes.
* `timestamp`: A timestamp formatted using `dateTimeFormat` above.
* `art`: Block containing:
* `header`: Art spec for header to display with message.
* `footer`: Art spec for footer to display with message.
## Theming
### MCI Codes
1. Node selection. Must be a View that allows lists such as `SpinnerMenuView` (`%SM1`), `HorizontalMenuView` (`%HM1`), etc.
2. Message entry (`%ET2`).
3. Message preview (`%TL3`). A rendered (that is, pipe codes resolved) preview of the text in `%ET2`.
10+: Custom using `itemFormat`. See below.
### Item Format
The following `itemFormat` object is provided for MCI 1 and 10+ for the currently selected item/node:
* `text`: Node ID or "-ALL-" (All nodes).
* `node`: Node ID or `-1` in the case of all nodes.
* `userId`: User ID.
* `action`: User's action.
* `userName`: Username.
* `realName`: Real name.
* `location`: User's location.
* `affils`: Affiliations.
* `timeOn`: How long the user has been online (approx).

View file

@ -0,0 +1,19 @@
---
layout: page
title: Onelinerz
---
## The Onelinerz Module
The built in `onelinerz` module provides a retro onelinerz system.
## Configuration
### Config Block
Available `config` block entries:
* `dateTimeFormat`: [moment.js](https://momentjs.com) style format. Defaults to current theme → system `short` date format.
* `dbSuffix`: Provide a suffix that will be appended to the DB name to use onelinerz for more than one purpose (separate lists).
### Theming
The following `itemFormat` object is provided to MCI 1 (ie: `%VM1`):
* `userId`: User ID of the onliner entry.
* `userName`: Login username of the onliner entry.
* `oneliner`: The oneliner text. Note that the standard `{text}` field also contains this value.
* `ts`: Timestamp of the entry formatted with `dateTimeFormat` format described above.

View file

@ -0,0 +1,12 @@
---
layout: page
title: Rumorz
---
## The Rumorz Module
The built in `rumorz` module provides a classic interface for users to add and view rumorz!
## Configuration
### Theming
The following `itemFormat` object is provided to MCI 1 (ie: `%VM1`) (the rumor list):
* `rumor`: The rumor text. Also available in the standard `{text}` field.

View file

@ -0,0 +1,29 @@
---
layout: page
title: Set Newscan Date Module
---
## Set Newscan Date Module
The `set_newscan_date` module allows setting newscan dates (aka pointers) for message conferences and areas as well as within the file base. Users can select specific conferences/areas or all (where applicable).
## Configuration
### Configuration Block
Available `config` block entries are as follows:
* `target`: Choose from `message` for message conferences & areas, or `file` for file base areas.
* `scanDateFormat`: Format for scan date. This format must align with the **output** of the MaskEditView (`%ME1`) MCI utilized for input. Defaults to `YYYYMMDD` (which matches mask of `####/##/##`).
### Theming
#### Message Conference & Areas
When `target` is `message`, the following `itemFormat` object is provided to MCI 2 (ie: `%SM2`):
* `conf`: An object containing:
* `confTag`: Conference tag.
* `name`: Conference name. Also available in `{text}`.
* `desc`: Conference description.
* `area`: An object containing:
* `areaTag`: Area tag.
* `name`: Area name. Also available in `{text}`.
* `desc`: Area description.
When dealing with the file base, ENiGMA½ does not currently have the ability to set newscan dates for specific areas. No `%SM2` is used in this case.
### Submit Actions
Submit action should map to `@method:scanDateSubmit` and provide `scanDate` in form data. For message conf/areas (`target` of `message`), `targetSelection` should be also be provided in form data: An index to the selected conf/area.

View file

@ -0,0 +1,70 @@
---
layout: page
title: The Show Art Module
---
## The Show Art Module
The built in `show_art` module add some advanced ways in which you can configure your system to display art assets beyond what a standard menu entry can provide. For example, based on user selection of a file or message base area.
## Configuration
### Config Block
Available `config` block entries:
* `method`: Set the method in which to show art. See **Methods** below.
* `optional`: Is this art required or optional? If non-optional and we cannot show art based on `method`, it is an error.
* `key`: Used for some `method`s. See **Methods**
### Methods
#### Extra Args
When `method` is `extraArgs`, the module selects an *art spec* from a value found within `extraArgs` that were passed to `show_art` by `key`. Consider the following:
Given an `menu.hjson` entry:
```hjson
showWithExtraArgs: {
module: show_art
config: {
method: extraArgs
key: fooBaz
}
}
```
If the `showWithExtraArgs` menu was entered and passed `extraArgs` as the following:
```json
{
"fizzBang" : true,
"fooBaz" : "LOLART"
}
```
...then the system would use the *art spec* of `LOLART`.
#### Area & Conferences
Handy for inserting into File Base, Message Conferences, or Mesage Area selections selections. When `method` is `fileBaseArea`, `messageConf`, or `messageArea` the selected conf/area's associated *art spec* is utilized. Example:
Given a file base entry in `config.hjson`:
```hjson
areas: {
all_ur_base: {
name: All Your Base
desc: chown -r us ./base
art: ALLBASE
}
}
```
A menu entry may look like this:
```hjson
showFileBaseAreaArt: {
module: show_art
config: {
method: fileBaseArea
cls: true
pause: true
menuFlags: [ "popParent", "noHistory" ]
}
}
```
...if the user choose the "All Your Base" area, the *art spec* of `ALLBASE` would be selected and displayed.
The only difference for `messageConf` or `messageArea` methods are where the art is defined (which is always next to the conf or area declaration in `config.hjson`).
While `key` can be overridden, the system uses `areaTag` for message/file area selections, and `confTag` for conference selections by default.

View file

@ -0,0 +1,96 @@
---
layout: page
title: Telnet Bridge
---
## Telnet Bridge
The `telnet_bridge` module allows "bridged" Telnet connections from your board to other Telnet services (such as other BBSes!).
## Configuration
### Config Block
Available `config` entries:
* `host`: Hostname or IP address to connect to.
* `port`: Port to connect to. Defaults to the standard Telnet port of `23`.
* `font`: A SyncTERM style font. Useful for example if you would like to connect form a "DOS" style BBS to an Amiga. See [the general art documentation on SyncTERM Style Fonts](../art/general.md).
### Example
Below is an example `menu.hjson` entry that would connect to [Xibalba](https://xibalba.l33t.codes):
```hjson
{
telnetBridgeXibalba: {
desc: Xibalba BBS
module: telnet_bridge
config: {
host: xibalba.l33t.codes
port: 45510
}
}
}
```
### Using Extra Args
The `telnet_bridge` module can also accept standard `extraArgs` of the same configuration arguments described above. This can be illustrated with an example:
```hjson
telnetBridgeMenu: {
desc: Telnet Bridge
art: telnet_bridge
config: {
font: cp437
}
form: {
0: {
mci: {
VM1: {
argName: selection
items: [
{
board: BLACK Flag
soft: Mystic
data: bf
}
{
board: Xibalba
soft: ENiGMA½
data: xib
}
]
// sort by 'board' fields above
sort: board
submit: true
}
}
submit: {
*: [
{
value: { "selection" : "bf" }
action: @menu:telnetBridgeFromExtraFlags
extraArgs: {
host: blackflag.acid.org
}
}
{
value: { "selection" : "xib" }
action: @menu:telnetBridgeFromExtraFlags
extraArgs: {
host: xibalba.l33t.codes
port: 44510
}
}
]
}
}
}
}
telnetBridgeFromExtraFlags: {
desc: Telnet Bridge
module: telnet_bridge
}
```
Here we've created a lightbar menu with custom items in which we'd use `itemFormat`'s with in a theme. When the user selects an item, the `telnetBridgeFromExtraFlags` menu is instantiated using the supplied `extraArgs`.

View file

@ -0,0 +1,60 @@
---
layout: page
title: TopX
---
## The TopX Module
The built in `top_x` module allows for displaying oLDSKOOL (?!) top user stats for the week, month, etc. Ops can configure what stat(s) are displayed and how far back in days the stats are considered.
## Configuration
### Config Block
Available `config` block entries:
* `mciMap`: Supplies a mapping of MCI code to data source. See `mciMap` below.
#### MCI Map (mciMap)
The `mciMap` `config` block configures MCI code mapping to data sources. Currently the following data sources (determined by `type`) are available:
| Type | Description |
|-------------|-------------|
| `userEventLog` | Top counts or sum of values found in the User Event Log. |
| `userProp` | Top values (aka "scores") from user properties. |
##### User Event Log (userEventLog)
When `type` is set to `userEventLog`, entries from the User Event Log can be counted (ie: individual instances of a particular log item) or summed in the case of log items that have numeric values. The default is to sum.
Some current User Event Log `value` examples include `ul_files`, `dl_file_bytes`, or `achievement_earned`. See [user_log_name.js](/core/user_log_name.js) for additional information.
Example `userEventLog` entry:
```hjson
mciMap: {
1: { // e.g.: %VM1
type: userEventLog
value: achievement_pts_earned // top achievement points earned
sum: true // this is the default
daysBack: 7 // omit daysBack for all-of-time
}
}
```
#### User Properties (userProp)
When `type` is set to `userProp`, data is collected from individual user's properties. For example a `value` of `minutes_online_total_count`. See [user_property.js](/core/user_property.js) for more information.
Example `userProp` entry:
```hjson
mciMap: {
2: { // e.g.: %VM2
type: userProp
value: minutes_online_total_count // top users by minutes spent on the board
}
}
```
## Theming
Generally `mciMap` entries will point to a Vertical List View Menu (`%VM1`, `%VM2`, etc.). The following `itemFormat` object is provided:
* `value`: The value acquired from the supplied data source.
* `userName`: User's username.
* `realName`: User's real name.
* `location`: User's location.
* `affils` or `affiliation`: Users affiliations.
* `position`: Rank position (numeric).
Remember that string format rules apply, so for example, if displaying top uploaded bytes (`ul_file_bytes`), a `itemFormat` may be `{userName} - {value!sizeWithAbbr}` yielding something like "TopDude - 4 GB". See [MCI](../art/mci.md) for additional information.

View file

@ -0,0 +1,73 @@
---
layout: page
title: 2FA/OTP Config
---
## The 2FA/OTP Config Module
The `user_2fa_otp_config` module provides opt-in, configuration, and viewing of Two-Factor Authentication via One-Time-Password (2FA/OTP) settings. In order to allow users access to 2FA/OTP, the system must be properly configured. See [Security](../configuration/security.md) for more information.
:information_source: By default, the 2FA/OTP configuration menu may only be accessed by users connected securely (ACS `SC`). It is highly recommended to leave this default as accessing these settings over a plain-text connection could expose private secrets!
## Configuration
### Config Block
Available `config` block entries:
* `infoText`: Overrides default informational text string(s). See **Info Text** below.
* `statusText:` Overrides default status text string(s). See **Status Text** below.
Example:
```hjson
config: {
infoText: {
googleAuth: Google Authenticator available on mobile phones, etc.
}
statusText: {
saveError: Doh! Failed to save :(
}
}
```
#### Info Text (infoText)
Overrides default informational text relative to current selections. Available keys:
* `disabled`: Displayed when OTP switched to enabled.
* `enabled`: Displayed when OTP switched to disabled.
* `rfc6238_TOTP`: Describes TOTP.
* `rfc4266_HOTP`: Describes HOTP.
* `googleAuth`: Describes Google Authenticator OTP.
#### Status Text (statusText)
Overrides default status text for various conditions. Available keys:
* `otpNotEnabled`
* `noBackupCodes`
* `saveDisabled`
* `saveEmailSent`
* `saveError`
* `qrNotAvail`
* `emailRequired`
## Theming
The following MCI codes are available:
* MCI 1: (ie: `TM1`): Toggle 2FA/OTP enabled/disabled.
* MCI 2: (ie: `SM2`): 2FA/OTP type selection.
* MCI 3: (ie: `TM3`): Submit/cancel toggle.
* MCI 10...99: Custom entries with the following format members available:
* `{infoText}`: **Info Text** for current selection.
### Web and Email Templates
A template system is also available to customize registration emails and the landing page.
#### Emails
Multipart MIME emails are send built using template files pointed to by `users.twoFactorAuth.otp.registerEmailText` and `users.toFactorAuth.otp.registerEmailHtml` supporting the following variables:
* `%BOARDNAME%`: BBS name.
* `%USERNAME%`: Username receiving email.
* `%TOKEN%`: Temporary registration token generally used in URL.
* `%REGISTER_URL%`: Full registration URL.
#### Landing Page
The landing page template is pointed to by `users.twoFactorAuth.otp.registerPageTemplate` and supports the following variables:
* `%BOARDNAME%`: BBS name.
* `%USERNAME%`: Username receiving email.
* `%TOKEN%`: Temporary registration token generally used in URL.
* `%OTP_TYPE%`: OTP type such as `googleAuth`.
* `%POST_URL%`: URL to POST form to.
* `%QR_IMG_DATA%`: QR code in URL image data format. Not always available depending on OTP type and will be set to blank in these cases.
* `%SECRET%`: Secret for manual entry.

View file

@ -0,0 +1,21 @@
---
layout: page
title: User List
---
## The User List Module
The built in `user_list` module provides basic user list functionality.
## Configuration
### Config Block
Available `config` block entries:
* `dateTimeFormat`: [moment.js](https://momentjs.com) style format. Defaults to current theme → system `short` format.
### Theming
The following `itemFormat` object is provided to MCI 1 (ie: `%VM1`):
* `userId`: User ID.
* `userName`: Login username.
* `realName`: User's real name.
* `lastLoginTimestamp`: Full last login timestamp for formatting use.
* `lastLoginTs`: Last login timestamp formatted with `dateTimeFormat` style.
* `location`: User's location.
* `affiliation` or `affils`: Users affiliations.

View file

@ -0,0 +1,18 @@
---
layout: page
title: Who's Online
---
## The Who's Online Module
The built in `whos_online` module provides a basic who's online mod.
### Theming
The following `itemFormat` object is provided to MCI 1 (ie: `%VM1`):
* `userId`: User ID.
* `userName`: Login username.
* `node`: Node ID the user is connected to.
* `timeOn`: A human friendly amount of time the user has been online.
* `realName`: User's real name.
* `location`: User's location.
* `affiliation` or `affils`: Users affiliations.
* `action`: Current action/view in the system taken from the `desc` field of the current MenuModule they are interacting with. For example, "Playing L.O.R.D".

View file

@ -0,0 +1,65 @@
---
layout: page
title: Gopher Server
---
## The Gopher Content Server
The Gopher *content server* provides access to publicly exposed message conferences and areas over Gopher (gopher://) as well as any other content you wish to serve in your Gopher Hole!
## Configuration
Gopher configuration is found in `contentServers.gopher` in `config.hjson`.
| Item | Required | Description |
|------|----------|-------------|
| `enabled` | :+1: | Set to `true` to enable Gopher |
| `staticRoot` | :+1: | Sets the path serving as the static root path for all Gopher content. Defaults to `enigma-bbs/gopher`.<br>See also **Gophermap's** below |
| `port` | :-1: | Override the default port of `8070` |
| `publicHostname` | :+1: | Set the **public** hostname/domain that Gopher will serve to the outside world. Example: `myfancybbs.com` |
| `publicPort` | :+1: | Set the **public** port that Gopher will serve to the outside world. |
| `messageConferences` | :-1: | An map of *conference tags* to *area tags* that are publicly exposed via Gopher. See example below. |
Notes on `publicHostname` and `publicPort`:
The Gopher protocol serves content that contains host/domain and port even when referencing it's own documents. Due to this, these members must be set to your publicly addressable Gopher server!
## Gophermap's
[Gophermap's](https://en.wikipedia.org/wiki/Gopher_(protocol)#Source_code_of_a_menu) are how to build menus for your Gopher Hole. Each map is a simple text file named `gophermap` (all lowercase, no extension) with DOS style CRLF endings.
Within any directory nested within your `staticRoot` may live a `gophermap`. A template may be found in the `enigma-bbsmisc` directory.
ENiGMA will pre-process `gophermap` files replacing in following variables:
* `{publicHostname}`: The public hostname from your config.
* `{publicPort}`: The public port from your config.
:information_source: See [Wikipedia](https://en.wikipedia.org/wiki/Gopher_(protocol)#Source_code_of_a_menu) for more information on the `gophermap` format.
:information_source: See [RFC 1436](https://tools.ietf.org/html/rfc1436) for the original Gopher spec.
:bulb: Tools such as [gfu](https://rawtext.club/~sloum/gfu.html) may help you with `gophermap`'s
### Example Gophermap
An example `gophermap` living in `enigma-bbs/gopher`:
```
iWelcome to a Gopher server! {publicHostname} {publicPort}
1Public Message Area /msgarea {publicHostname} {publicPort}
.
```
### Example
Let's suppose you are serving Gopher for your BBS at `myfancybbs.com`. Your ENiGMA½ system is listening on the default Gopher `port` of 8070 but you're behind a firewall and want port 70 exposed to the public. Lastly, you want to expose some fsxNet areas:
```hjson
contentServers: {
gopher: {
enabled: true
publicHostname: myfancybbs.com
publicPort: 70
// Expose some public message conferences/areas
messageConferences: {
fsxnet: { // fsxNet's conf tag
// Areas of fsxNet we want to expose:
"fsx_gen", "fsx_bbs"
}
}
}
}
```

View file

@ -0,0 +1,67 @@
---
layout: page
title: NNTP Server
---
## The NNTP Content Server
The NNTP *content server* provides access to publicly exposed message conferences and areas over either **secure** NNTPS (NNTP over TLS or nttps://) and/or non-secure NNTP (nntp://).
## Configuration
| Item | Required | Description |
|------|----------|-------------|
| `nntp` | :-1: | Configuration block for non-secure NNTP. See Non-Secure NNTP Configuration below. |
| `nntps` | :-1: | Configuration block for secure NNTP. See Secure NNTPS Configuration below. |
| `publicMessageConferences` | :+1: | A map of *conference tags* to *area tags* that are publicly exposed over NNTP. Anonymous users will get read-only access to these areas. |
### See Non-Secure NNTP Configuration
Under `contentServers.nntp.nntp` the following configuration is allowed:
| Item | Required | Description |
|------|----------|-------------|
| `enabled` | :+1: | Set to `true` to enable non-secure NNTP access. |
| `port` | :-1: | Override the default port of `8119`. |
### Secure NNTPS Configuration
Under `contentServers.nntp.nntps` the following configuration is allowed:
| Item | Required | Description |
|------|----------|-------------|
| `enabled` | :+1: | Set to `true` to enable secure NNTPS access. |
| `port` | :-1: | Override the default port of `8565`. |
| `certPem` | :-1: | Override the default certificate file path of `./config/nntps_cert.pem` |
| `keyPem` | :-1: | Override the default certificate key file path of `./config/nntps_key.pem` |
#### Certificates and Keys
In order to use secure NNTPS, a TLS certificate and key pair must be provided. You may generate your own but most clients **will not trust** them. A certificate and key from a trusted Certificate Authority is recommended. [Let's Encrypt](https://letsencrypt.org/) provides free TLS certificates. Certificates and private keys must be in [PEM format](https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail).
##### Generating Your Own
An example of generating your own cert/key pair:
```bash
openssl req -newkey rsa:2048 -nodes -keyout ./config/nntps_key.pem -x509 -days 3050 -out ./config/nntps_cert.pem
```
### Example Configuration
```hjson
contentServers: {
nntp: {
publicMessageConferences: {
fsxnet: [
// Expose these areas of fsxNet
"fsx_gen", "fsx_bbs"
]
}
nntp: {
enabled: true
}
nntps: {
enabled: true
// These could point to Let's Encrypt provided pairs for example:
certPem: /path/to/some/tls_cert.pem
keyPem: /path/to/some/tls_private_key.pem
}
}
}
```

52
docs/_docs/servers/ssh.md Normal file
View file

@ -0,0 +1,52 @@
---
layout: page
title: SSH Server
---
## SSH Login Server
The ENiGMA½ SSH *login server* allows secure user logins over SSH (ssh://).
## Configuration
Entries available under `config.loginServers.ssh`:
| Item | Required | Description |
|------|----------|-------------|
| `privateKeyPem` | :-1: | Path to private key file. If not set, defaults to `./config/ssh_private_key.pem` |
| `privateKeyPass` | :+1: | Password to private key file.
| `firstMenu` | :-1: | First menu an SSH connected user is presented with. Defaults to `sshConnected`. |
| `firstMenuNewUser` | :-1: | Menu presented to user when logging in with one of the usernames found within `users.newUserNames` in your `config.hjson`. Examples include `new` and `apply`. |
| `enabled` | :+1: | Set to `true` to enable the SSH server. |
| `port` | :-1: | Override the default port of `8443`. |
| `address` | :-1: | Sets an explicit bind address. |
| `algorithms` | :-1: | Configuration block for SSH algorithms. Includes keys of `kex`, `cipher`, `hmac`, and `compress`. See the algorithms section in the [ssh2-streams](https://github.com/mscdex/ssh2-streams#ssh2stream-methods) documentation for details. For defaults set by ENiGMA½, see `core/config_default.js`.
| `traceConnections` | :-1: | Set to `true` to enable full trace-level information on SSH connections.
### Example Configuration
```hjson
{
loginServers: {
ssh: {
enabled: true
port: 8889
privateKeyPem: /path/to/ssh_private_key.pem
privateKeyPass: sup3rs3kr3tpa55
}
}
}
```
## Generate a SSH Private Key
To utilize the SSH server, an SSH Private Key (PK) will need generated. OpenSSL can be used for this task:
### Modern OpenSSL
```bash
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -pkeyopt rsa_keygen_pubexp:65537 | openssl rsa -out ./config/ssh_private_key.pem -aes128
```
### Legacy OpenSSL
```bash
openssl genrsa -aes128 -out ./config/ssh_private_key.pem 2048
```
Note that you may need `-3des` for every old implementations or SSH clients!

View file

@ -0,0 +1,30 @@
---
layout: page
title: Telnet Server
---
## Telnet Login Server
The Telnet *login server* provides a standard **non-secure** Telnet login experience.
## Configuration
The following configuration can be made in `config.hjson` under the `loginServers.telnet` block:
| Key | Required | Description |
|------|----------|-------------|
| `enabled` | :-1: Defaults to `true`. Set to `false` to disable Telnet |
| `port` | :-1: | Override the default port of `8888`. |
| `address` | :-1: | Sets an explicit bind address. |
| `firstMenu` | :-1: | First menu a telnet connected user is presented with. Defaults to `telnetConnected`. |
### Example Configuration
```hjson
{
loginServers: {
telnet: {
enabled: true
port: 8888
}
}
}
```

View file

@ -0,0 +1,72 @@
---
layout: page
title: Web Server
---
ENiGMA½ comes with a built in *content server* for supporting both HTTP and HTTPS. Currently the [File Bases](../modding/file-base-web-download-manager.md) registers routes for file downloads, password reset email links are handled via the server, and static files can also be served for your BBS. Other features will likely come in the future or you can easily write your own!
# Configuration
By default the web server is not enabled. To enable it, you will need to at a minimum configure two keys in the `contentServers.web` section of `config.hjson`:
```hjson
contentServers: {
web: {
domain: bbs.yourdomain.com
http: {
enabled: true
port: 8080
}
}
}
```
The following is a table of all configuration keys available under `contentServers.web`:
| Key | Required | Description |
|------|----------|-------------|
| `domain` | :+1: | Sets the domain, e.g. `bbs.yourdomain.com`. |
| `http` | :-1: | Sub configuration for HTTP (non-secure) connections. See **HTTP Configuration** below. |
| `overrideUrlPrefix` | :-1: | Instructs the system to be explicit when handing out URLs. Useful if your server is behind a transparent proxy. |
### HTTP Configuration
Entries available under `contentServers.web.http`:
| Key | Required | Description |
|------|----------|-------------|
| `enable` | :+1: | Set to `true` to enable this server.
| `port` | :-1: | Override the default port of `8080`. |
| `address` | :-1: | Sets an explicit bind address. |
### HTTPS Configuration
Entries available under `contentServers.web.https`:
| Key | Required | Description |
|------|----------|-------------|
| `enable` | :+1: | Set to `true` to enable this server.
| `port` | :-1: | Override the default port of `8080`. |
| `address` | :-1: | Sets an explicit bind address. |
| `certPem` | :+1: | Overrides the default certificate path of `/config/https_cert.pem`. Certificate must be in PEM format. See **Certificates** below. |
| `keyPem` | :+1: | Overrides the default certificate key path of `/config/https_cert_key.pem`. Key must be in PEM format. See **Certificates** below. |
#### Certificates
If you don't have a TLS certificate for your domain, a good source for a certificate can be [Let's Encrypt](https://letsencrypt.org/) who supplies free and trusted TLS certificates. A common strategy is to place another web server such as [Caddy](https://caddyserver.com/) in front of ENiGMA½ acting as a transparent proxy and TLS termination point.
:information_source: Keep in mind that the SSL certificate provided by Let's Encrypt's Certbot is by default stored in a privileged location; if your ENIGMA instance is not running as root (which it should not be!), you'll need to copy the SSL certificate somewhere else in order for ENIGMA to use it.
## Static Routes
Static files live relative to the `contentServers.web.staticRoot` path which defaults to `enigma-bbs/www`.
`index.html, favicon.ico`, and any error pages like `404.html` are accessible from the route path. Other static assets hosted by the web server must be referenced from `/static/`, for example:
```html
<a href="/static/about.html"> Example Link
```
## Custom Error Pages
Customized error pages can be created for [HTTP error codes](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_Client_Error) by providing a `<error_code>.html` file in the *static routes* area. For example: `404.html`.

View file

@ -0,0 +1,106 @@
---
layout: page
title: Web Socket / Web Interface Server
---
## WebSocket Login Server
The WebSocket Login Server provides **secure** (wss://) as well as non-secure (ws://) WebSocket login access. This is often combined with a browser based WebSocket client such as VTX or fTelnet.
# VTX Web Client
ENiGMA supports the VTX WebSocket client for connecting to your BBS from a web page. Example usage can be found at [Xibalba](https://xibalba.l33t.codes) and [fORCE9](https://bbs.force9.org/vtx/force9.html) amongst others.
## Before You Start
There are a few things out of scope of this document:
- You'll need a web server for hosting the files - this can be anywhere, but it obviously makes sense to host it
somewhere with a hostname relevant to your BBS!
- It's not required, but you should use SSL certificates to secure your website, and for supplying to ENiGMA to
secure the websocket connections. [Let's Encrypt](https://letsencrypt.org/) provide a free well-respected service.
- How you make the websocket service available on the internet is up to you, but it'll likely by forwarding ports on
your router to the box hosting ENiGMA. Use the same method you did for forwarding the telnet port.
## Setup
1. Enable the websocket in ENiGMA, by adding `webSocket` configuration to the `loginServers` block in `config.hjson` (create it if you
don't already have it defined).
````hjson
loginServers: {
webSocket : {
ws: {
// non-secure ws://
port: 8810
enabled: true
// optional bind address
address: 127.0.0.1
}
wss: {
// secure-over-tls wss://
port: 8811
enabled: true
certPem: /path/to/https_cert.pem
keyPem: /path/to/https_cert_key.pem
}
// set proxied to true to allow TLS-terminated proxied connections
// containing the "X-Forwarded-Proto: https" header to be treated
// as secure
proxied: true
}
}
````
2. Restart ENiGMA and check the logs to ensure the websocket service starts successfully, you'll see something like the
following:
````
[2017-10-29T12:13:30.668Z] INFO: ENiGMA½ BBS/30978 on force9: Listening for connections (server="WebSocket (insecure)", port=8810)
[2017-10-29T12:13:30.669Z] INFO: ENiGMA½ BBS/30978 on force9: Listening for connections (server="WebSocket (secure)", port=8811)
````
3. Download the [VTX_ClientServer](https://github.com/codewar65/VTX_ClientServer/archive/master.zip) to your
webserver, and unpack it to a temporary directory.
4. Download the example [VTX client HTML file](https://raw.githubusercontent.com/NuSkooler/enigma-bbs/master/misc/vtx/vtx.html) and save it to your webserver root.
5. Create an `assets/vtx` directory within your webserver root, so you have a structure like the following:
````text
├── assets
│   └── vtx
└── vtx.html
````
6. From the VTX_ClientServer package unpacked earlier, copy the contents of the `www` directory into `assets/vtx` directory.
7. Create a vtxdata.js file, and save it to `assets/vtx`:
````javascript
var vtxdata = {
sysName: "Your Awesome BBS",
wsConnect: "wss://your-hostname.here:8811",
term: "ansi-bbs",
codePage: "CP437",
fontName: "UVGA16",
fontSize: "24px",
crtCols: 80,
crtRows: 25,
crtHistory: 500,
xScale: 1,
initStr: "",
defPageAttr: 0x1010,
defCrsrAttr: 0x0207,
defCellAttr: 0x0007,
telnet: 1,
autoConnect: 0
};
````
8. Update `sysName` and `wsConnect` accordingly. Use `wss://` if you set up the websocket service with SSL, `ws://`
otherwise.
9. If you navigate to http://your-hostname.here/vtx.html, you should see a splash screen like the following:
![VTXClient](../assets/images/vtxclient.png "VTXClient")

View file

@ -0,0 +1,52 @@
---
layout: page
title: Monitoring Logs
---
## Monitoring Logs
ENiGMA½ does not produce much to stdout. Logs are produced by [Bunyan](https://github.com/trentm/node-bunyan) which outputs each entry as a JSON object.
Start by installing bunyan and making it available on your path:
```bash
npm install bunyan -g
```
or via Yarn:
```bash
yarn global add bunyan
```
To tail logs in a colorized and pretty format, issue the following command:
```bash
tail -F /path/to/enigma-bbs/logs/enigma-bbs.log | bunyan
```
See `bunyan --help` for more information on what you can do!
### Example
Logs _without_ Bunyan:
```bash
tail -F /path/to/enigma-bbs/logs/enigma-bbs.log
{"name":"ENiGMA½ BBS","hostname":"nu-dev","pid":25002,"level":30,"eventName":"updateFileAreaStats","action":{"type":"method","location":"core/file_base_area.js","what":"updateAreaStatsScheduledEvent","args":[]},"reason":"Schedule","msg":"Executing scheduled event action...","time":"2018-12-15T16:00:00.001Z","v":0}
{"name":"ENiGMA½ BBS","hostname":"nu-dev","pid":25002,"level":30,"module":"FTN BSO","msg":"Performing scheduled message import/toss...","time":"2018-12-15T16:00:00.002Z","v":0}
{"name":"ENiGMA½ BBS","hostname":"nu-dev","pid":25002,"level":30,"module":"FTN BSO","msg":"Performing scheduled message import/toss...","time":"2018-12-15T16:30:00.008Z","v":0}
```
Oof!
Logs _with_ Bunyan:
```bash
tail -F /path/to/enigma-bbs/logs/enigma-bbs.log | bunyan
[2018-12-15T16:00:00.001Z] INFO: ENiGMA½ BBS/25002 on nu-dev: Executing scheduled event action... (eventName=updateFileAreaStats, reason=Schedule)
action: {
"type": "method",
"location": "core/file_base_area.js",
"what": "updateAreaStatsScheduledEvent",
"args": []
}
[2018-12-15T16:00:00.002Z] INFO: ENiGMA½ BBS/25002 on nu-dev: Performing scheduled message import/toss... (module="FTN BSO")
[2018-12-15T16:30:00.008Z] INFO: ENiGMA½ BBS/25002 on nu-dev: Performing scheduled message import/toss... (module="FTN BSO")
```
Much better!