GBBS Pro / ACOS Message Extraction Tool

February 2026, Brian J. Bernstein

Why this project?

This is a project that I created to help in extracting messages and emails from a BBS that I ran back in the 1980s on an Apple //e with GBBS Pro. The reason for this is because I want to look at those old messages for nostalgia purposes, but unfortunately the way messages were stored in GBBS Pro was a proprietary format and thus not easily done. As such, I needed to create a tool to extract these messages on a modern computer.

Why was there a proprietary file format?

Unlike today where you could attribute a proprietary format to some kind of vendor lock-in, in this case actually a pretty clever thing to do. The Apple II is an 8-bit platform with limited storage; 5.25” floppy disks held 140K and if you had a lot of money to throw at it, you could get a 5, 10, or 20MB hard disk (HDD) the size of a large shoebox. Most people had one or two floppy drives (which were expensive enough as it was), but if someone could cough up several hundred dollars for a hard disk, you were in BBS-operating heaven. For perspective, in 1988 you could buy a Sider 20MB hard drive for an Apple II for about $600 ($1650 in 2026 dollars). Mind you, this was after years of cost reductions on HDDs for personal computers – if you looked at something like this a few years earlier, it was possibly double the cost for half the storage.

Most software on the Apple II didn’t really know how to use a hard disk, so you were either a computer enthusiast or business person to justify such an expense. People playing games, doing homework, or small business tasks would be just fine with one or two 5.25” floppy drives. However, a BBS could easily outgrow a few floppy drives, especially if you wanted to offer files that users could download (games, text files, etc.). Running a BBS was a perfect use for a HDD since floppy disks were just too limiting.

But even if you could afford a HDD for your BBS, the low-level details of how computers store files on floppies or HDDs reveal how inefficient it can be to store small messages that are only a few dozen words long. With the ProDOS operating system on the Apple II, disks were laid out to have many “sectors” to hold data, and these were each 512 bytes in size. So when you store a file, the operating system would allocate one-to-many sectors, chain them together, and put the file contents into that chain of sectors. But most messages written by people tend to be a dozen or two words long which often doesn’t even reach 512 bytes in size. As such, the shortest message being saved as an individual file would still take up one of those sectors thus wasting potentially hundreds of bytes on already small storage devices.

So the clever proprietary format that GBBS Pro used somewhat solved this inefficiency by storing multiple messages in a single file; if 4 messages were only a few dozen bytes long, they could coexist within one of those 512 byte sectors and the GBBS Pro software would know that one sector held 4 separate messages. Furthermore, it even went a step further by implementing a simple text compression algorithm which achieves a roughly 12.5% savings. So with this, running a BBS on a floppy disk was a little more feasible.

To make this proprietary format work, GBBS Pro was written in a custom BASIC-like programming language called ACOS (All-Purpose Communications Operating System) which was developed specifically for GBBS. For the parts of the BBS which worked with messages, special commands were available in the ACOS language which would transparently interact with database files in this format.

So why this project then?

As mentioned earlier, nostalgia has driven me to want to see what nonsense my friends and I from the late 1980s were going on about on the BBS. Because of the proprietary format, the only way to look at those messages would be to spend time re-learning how to stand up an Apple II with the GBBS Pro software on it and configure everything to reference those message database files. However, I’d prefer to extract those messages on a modern platform since it’s easy enough to get the message database files off of old disks. However, you can’t just load them into a text editor or Word or something like that – no software understands the format. And so this project is born…

The tool is an exercise in studying available ACOS and GBBS source code, mixed in with a little reverse engineering because the message database file format wasn’t really well documented. The goal was to be able to point the tool at a bulletin or email message file, analyze, and extract all messages from those files and save them as modern text files. As far as I’ve seen, this is the only tool of its kind and saves you from having to write custom ACOS code to do the same thing. However, it does go a step further than what an ACOS program could do, since it also attempts to extract even deleted messages.

Project features

ACOS / GBBS Pro message database files are like small filesystems. Just like on other filesystems, you have a directory of active files and where they live on the disk. As well, files can be deleted from the directory and their storage space marked as unused, but rarely does an operating system go through and actually wipe out every sector where the file was stored. Because of this, the tool knows how to extract not only “active” messages, but it is also capable of recovering deleted messages and/or residual fragments to varying degrees.

With all this, the tool is capable of extracting:

Special handling for email messages

In GBBS Pro, the message database files were used for two purposes: bulletins (a.k.a. boards, news groups, message bases, etc.) and email. While the format is the same, they have slightly different usage patterns (see technical documentation for details). The key difference with the email pattern is that the recipient of a message is not part of the message content, rather it uses the directory entry offset as a way to map to a user ID in the BBS. As such, a feature for email extraction allows for the use of specifying a GBBS Pro USERS file to determine the identity of the recipient.

Some notes about message database files

If you want to go into the technical weeds, read my document on the file format. It will tell you probably everything you want to know, and perhaps good to read before the next paragraph if it doesn’t make sense.

On a less-technical front, I will point out that there are size limitations for the databases. Specifically, when the sysop creates a new message board for their BBS, they specify a key thing: what is the maximum number of messages that a message board can hold.

As a way to prevent the disks on a BBS from filling up, GBBS Pro supported the feature of allowing up to a specified number of messages to be posted to a message board before purging the oldest one to make room. In other words, you could create a board for discussing people’s favorite bands that would hold up to 10 messages. If someone tried to post an 11th message, the first (oldest) message on that board would get automatically deleted.

This auto-purge mechanism was super convenient, but if you’re looking to find every message that ever existed on an old BBS, note that many sysops had this feature enabled to save disk space. As well, this is why you’ll find deleted messages and orphaned fragments; probably because that (say) 10 message limit was hit multiple times and rotated the database.

Getting your message files from your Apple II

There are two disk extraction tools which I can recommend: CiderPress II, and AppleCommander. While there are others that you can use, the key thing is that you need to extract the files in their original, non-translated forms for this gbbsmsgtool.py to work.

The files you’re interested in are typically on your “system” and/or “bulletins” disks:

Note that the USERS and DATA2 files are not required to extract messages, but they add extra fields to the output that is desirable.

Example using CiderPress II:

bash> cp2 extract gbbs_bulletins.dsk B1

…the extract command directs CiderPress to not convert the file, just extract a file called B1 from the .dsk image. Note there is also the catalog command which you can use to see what files are on the disk image.

Example using AppleCommander:

bash> ac.sh -g gbbs_bulletins.dsk B1 B1

…the -g argument directs AppleCommander to not convert the file, just extract a file called B1 (the first argument) from the .dsk image, and save it in the current directory as B1 (the second argument). Note there is also the -ll argument which you can use to see what files are on the disk image.

How to download the tool

This is a Python 3 script that doesn’t require any special libraries to be installed. As such, as long as you have python3 on your machine, this script should run without any special virtual environments or trickery like that.

You can download the script from github HERE.

How to use the tool

Running the tool from the command-line without arguments will produce a help screen:

GBBS Pro Message Database Tool v1.2.0
2026-02-05, Brian J. Bernstein  (brian@dronefone.com)

Usage:
  gbbsmsgtool.py analyze <msgdb_file> [--json]
  gbbsmsgtool.py extract <msgdb_file> [--active] [--deleted] [--orphaned] [--all] [--output-dir <path>] [--users <users_file>] [--data2 <data2_file>] [--pretty] [--json] [--force]

Commands:
  analyze    Show database statistics and block map
  extract    Extract messages from database

Extract options:
  --active       Extract active messages (default)
  --deleted      Extract deleted messages
  --orphaned     Extract orphaned blocks
  --all          Extract all types
  --output-dir   Write to directory instead of stdout
  --users        Path to USERS file (for email recipient names)
  --data2        Path to DATA2 file (for board names)
  --pretty       Format messages with readable headers (default: raw)
  --json         Output in JSON format (ignores --pretty)
  --force        Overwrite existing files (default: abort if files exist)

The tool features two modes of operation: analysis and extraction.

Analysis

The analyze mode will report statistics about the message database file such as what you see below. It does not do any extraction nor does it modify the file.

bash> ./gbbsmsgtool.py analyze B1
=== Database Analysis: B1 ===

Format: BULLETIN
File size: 8200 bytes

Header (MSGINFO):
  Bitmap blocks: 2 (256 bytes)
  Directory blocks: 4 (512 bytes)
  Used data blocks: 41
  Message count: 9
  New message number: 1468

File layout:
  0x000-0x007: Header (8 bytes)
  0x008-0x107: Bitmap (2 blocks)
  0x108-0x307: Directory (4 blocks, max 128 entries)
  0x308+: Data blocks

Data area: 7424 bytes
Total blocks: 58

Active messages: 9
Deleted messages: 3
Orphaned blocks: 1

Block breakdown:
  Active header blocks: 9
  Active chain blocks: 32
  Deleted header blocks: 3
  Deleted chain blocks: 12
  Orphaned blocks: 1
  Unused blocks: 1
  Total: 58

Usage: 70.7% active

=== Block Map ===
Legend: [H]=Active header, [C]=Active chain, [D]=Deleted header, [d]=Deleted chain
        [o]=Orphaned, [ ]=Unused

[H][C][C][C][C][H][C][H][C][C][C][C][C][C][C][H][C][C][C][C]  20
[C][C][C][H][C][C][C][H][C][H][C][C][H][C][C][C][D][d][d][o]  40
[ ][D][D][d][d][d][d][d][d][d][d][d][d][H][C][C][C][C]

What you see here is:

Extraction

The extract mode performs an analysis of the data file and then extracts the contents to either STDOUT (default), or to a named output directory.

When specifying an output directory, a text file for each message will be created. By default, the tool will prevent you from overwriting existing files unless you use --force. Directories will be created if they don’t already.

You need to specify at least one extraction mode option: active, deleted, orphaned, or all message types.

Output of extracted files will be to STDOUT unless you specify --output-dir.

Optional Files

USERS file: If you have the GBBS Pro user database file (typically named USERS), you can specify this with --users to: - Display recipient names for email messages (instead of just “User ID N”) - Detect when bulletin board users posted with an alias (shows both the alias and real name)

DATA2 file: If you have the GBBS Pro configuration file (typically named DATA2), you can specify this with --data2 to: - Display board names in message output (e.g., “System News” instead of just “B1”) - Only applies to bulletin board files, not email

Message Formatting

By default, messages are extracted in “raw” format, preserving the original GBBS Pro message structure. Use --pretty to format messages with more readable headers:

Raw format (default):

Hello World!!
0,All
1,Drone (#1)
Date : 01/08/88  05:23:05 PM

[message body]

Pretty format (with --pretty):

Board: System News (B1)
Subject: Hello World!!
To: All
From: Drone (#1)
Date : 01/08/88  05:23:05 PM

[message body]

When a user posts with an alias (detected via USERS file), the pretty format shows:

From: DRONE: THE OWNER AND SYSOP (#2-Shortround)

This indicates user #2 (Shortround) posted using the alias “DRONE: THE OWNER AND SYSOP”.

Note: The pretty format parser is based on standard GBBS Pro message headers. If your BBS uses customized headers, you may need to modify the prettify_message() function in the tool (see comments in the code for customization points).

JSON Format

Use --json to output structured JSON instead of text. This is useful for programmatic consumption of the data. When --json is used, the --pretty flag is ignored since JSON output always includes parsed/structured fields.

For analyze, the JSON output contains the database statistics:

bash> ./gbbsmsgtool.py analyze B1 --json
{
  "source_file": "B1",
  "format": "bulletin",
  "file_size": 8200,
  "bitmap_blocks": 2,
  "directory_blocks": 4,
  "used_data_blocks": 41,
  "message_count": 9,
  "total_blocks": 58,
  "active_count": 9,
  "deleted_count": 3,
  "orphaned_count": 1,
  "block_breakdown": {
    "active_header": 9,
    "active_chain": 32,
    "deleted_header": 3,
    "deleted_chain": 12,
    "orphaned": 1,
    "unused": 1
  },
  "usage_percent": 70.7
}

For extract, the JSON output includes analysis stats plus arrays of messages with structured fields:

bash> ./gbbsmsgtool.py extract B1 --all --json
{
  "analysis": { ... },
  "active": [
    {
      "number": 1,
      "entry": 0,
      "block": 54,
      "subject": "Hello World!!",
      "to": "All",
      "to_id": 0,
      "from": "Drone",
      "from_id": 1,
      "from_alias": null,
      "date": "01/08/88 05:23:05 PM",
      "board": "System News",
      "body": "message text here...",
      "raw": "full raw message text"
    }
  ],
  "deleted": [ ... ],
  "orphaned": [ ... ]
}

Each message object includes: - subject, to, to_id, from, from_id: Parsed header fields - from_alias: Real username if poster used an alias (requires USERS file), otherwise null - date: Parsed date string - board: Board name (requires DATA2 file), otherwise null - body: Message body text only - raw: Complete original message text as stored in the database - number: Message sequence number - block: Starting data block number - entry: Directory entry number (active bulletin messages only)

When using --output-dir with --json, a single JSON file is written to the output directory, named after the input file (e.g., B1.json for input file B1):

bash> ./gbbsmsgtool.py extract B1 --all --json --output-dir out
bash> ls out
B1.json

Note: The JSON field parser is based on standard GBBS Pro message headers. If your BBS uses customized headers (e.g., “From->” instead of “From :”), you may need to modify the parse_message_fields() function in the tool (see CUSTOMIZATION comments in the code).

Example usage:

bash> ./gbbsmsgtool.py extract B1 --all --output-dir out
bash> ls -l out
total 104
-rw-r--r--@ 1 brianb  staff     98 Dec 27  1987 Deleted-0001.txt
-rw-r--r--@ 1 brianb  staff  1,478 Jan  5  1988 Deleted-0002.txt
-rw-r--r--@ 1 brianb  staff    404 Jan 26  1988 Deleted-0003.txt
-rw-r--r--@ 1 brianb  staff    434 Jan  8  1988 Msg-0001.txt
-rw-r--r--@ 1 brianb  staff    654 Jan  8  1988 Msg-0002.txt
-rw-r--r--@ 1 brianb  staff    258 Jan  9  1988 Msg-0003.txt
-rw-r--r--@ 1 brianb  staff  1,127 Jan 13  1988 Msg-0004.txt
-rw-r--r--@ 1 brianb  staff  1,066 Jan 13  1988 Msg-0005.txt
-rw-r--r--@ 1 brianb  staff    220 Feb  6 13:49 Orphan-0040.txt

Note that the numbers used for active messages (Msg-0000.txt) correspond to their message number as they would exist in the BBS (since messages were referenced by number). Deleted messages, however, are simply a sequence in order of their discovery, but with an attempt to be chronological. Orphaned blocks’ number refers to the block number it was found in.

The timestamps of the extracted files are determined by the timestamp found within the message.

Questions, Comments, Support

If you find this tool helpful, let me know! I am happy to help you with recovering your BBS nostalgia. I only briefly ran GBBS Pro while I was developing my own software (Compunet BBS), but I helped a number of people code in ACOS back in the day.

If there is something you need fixed, added, or whatever, raise a ticket on the github page or email me at brian-removethispart at dronefone.com . You can also find information about this on my website at http://dronefone.com/gbbs

License

I’m releasing this as GPL 3 (see LICENSE file). If you want to include it or my documentation, I prefer if you reference my site, but at a minimum please retain my name in credits.