MRC Chat

February 26, 2026 · View on GitHub

MRC (Multi Relay Chat) is a real-time, multi-BBS chat network that connects users across different bulletin board systems. BinktermPHP includes a WebDoor-based MRC client that lets logged-in users join rooms and chat with users on other connected BBSes.

This feature is experimental. Protocol behaviour, configuration format, and database schema may change in future releases.

How It Works

MRC uses a persistent TCP connection from your BBS to a central MRC relay server. A background daemon (scripts/mrc_daemon.php) maintains that connection. When a user opens the MRC WebDoor in their browser, they interact with the chat through HTTP polling — the browser polls the BinktermPHP API every two seconds for new messages, and the daemon forwards outbound messages to the MRC network.

Browser ←→ BinktermPHP API ←→ mrc_daemon ←→ MRC server ←→ other BBSes

Prerequisites

  • PHP 8.x with the openssl extension (for SSL connections)
  • PostgreSQL
  • The MRC WebDoor enabled in Admin → WebDoors

MRC Servers

Server VersionProtocolEnvironmentFQDNPortSecurity
1.3.201.3Productionmrc.bottomlessabyss.net5000Plain
1.3.201.3Productionmrc.bottomlessabyss.net5001SSL
1.3.21-dev1.3Testingmrc.bottomlessabyss.net50000Plain
1.3.21-dev1.3Testingmrc.bottomlessabyss.net50001SSL

BinktermPHP ships configured for the testing server (port 50001, SSL) by default. To connect to the production server where most activity happens, update config/mrc.json or use Admin → MRC to set the port to 5000 (plain) or 5001 (SSL).

Setup

1. Configure MRC

Configuration is stored in config/mrc.json. The file is created automatically with defaults on first use. Edit it directly or use Admin → MRC to configure through the web interface.

Minimum required settings:

{
    "enabled": true,
    "server": {
        "host": "mrc.bottomlessabyss.net",
        "port": 5000,
        "use_ssl": false
    },
    "bbs": {
        "name": "My BBS",
        "sysop": "Sysop"
    }
}

Full configuration reference:

{
    "enabled": true,
    "server": {
        "host": "mrc.bottomlessabyss.net",
        "port": 5000,
        "use_ssl": false,
        "ssl_port": 5001
    },
    "bbs": {
        "name": "My BBS",
        "platform": "BINKTERMPHP/Linux64/1.3.0",
        "sysop": "Sysop"
    },
    "connection": {
        "auto_reconnect": true,
        "reconnect_delay": 30,
        "ping_interval": 60,
        "handshake_timeout": 1,
        "keepalive_timeout": 125
    },
    "rooms": {
        "default": "lobby",
        "auto_join": ["lobby"]
    },
    "messages": {
        "max_length": 140,
        "history_limit": 1000,
        "prune_after_days": 30
    },
    "info": {
        "website": "https://mybbs.example.com",
        "telnet": "mybbs.example.com:23",
        "ssh": "mybbs.example.com:22",
        "description": "A BinktermPHP BBS"
    }
}
FieldDescription
server.hostMRC relay server hostname
server.portPlain TCP port
server.use_sslUse SSL/TLS connection
server.ssl_portSSL port
bbs.nameYour BBS name as it appears on the MRC network (max 64 chars; apostrophes are stripped automatically)
bbs.platformPlatform identifier string sent during handshake
bbs.sysopSysop name
connection.reconnect_delaySeconds to wait before reconnecting after a disconnect
connection.keepalive_timeoutSeconds without a PING before treating the connection as dead
rooms.auto_joinRooms to join when a user first enters the WebDoor
messages.history_limitMaximum messages retained per room in the database
messages.prune_after_daysMessages older than this are deleted during maintenance
info.*Optional BBS contact info returned by the MRC INFO command

2. Enable the WebDoor

In Admin → WebDoors, find MRC Chat and enable it. Users can then access it via Doors → MRC Chat or directly at /games/mrc.

3. Start the daemon

php scripts/mrc_daemon.php

Options:

FlagDescription
--daemonDetach from terminal and run in the background
--pid-file=PATHWrite PID to this file (default: data/run/mrc_daemon.pid)
--debugLog raw protocol send/receive for troubleshooting
--log-level=LEVELLog verbosity level

Keeping the daemon running: crontab (preferred)

Add a @reboot entry to your crontab so the daemon starts automatically when the server boots:

crontab -e

Add this line (adjust the path):

@reboot /usr/bin/php /path/to/binktest/scripts/mrc_daemon.php --daemon --pid-file=/path/to/binktest/data/run/mrc_daemon.pid

Keeping the daemon running: systemd

Alternatively, create /etc/systemd/system/mrc-daemon.service:

[Unit]
Description=BinktermPHP MRC Chat Daemon
After=network.target postgresql.service

[Service]
Type=simple
User=binkterm
WorkingDirectory=/path/to/binktest
ExecStart=/usr/bin/php scripts/mrc_daemon.php
Restart=always
RestartSec=15
StandardOutput=journal
StandardError=journal
SyslogIdentifier=mrc-daemon

[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable mrc-daemon
systemctl start mrc-daemon

User Guide

Joining a Room

When a user opens the MRC WebDoor (/games/mrc), the left sidebar lists available rooms. Click a room to join it. Alternatively, type a room name in the text field at the top of the sidebar and press Enter or click the arrow button.

Joining sends a NEWROOM packet to the MRC server, which broadcasts a join announcement to everyone in the room.

Sending Messages

With a room joined, type a message in the input bar at the bottom (max 140 characters) and press Enter or click Send. Messages are delivered to all users in the room across the MRC network.

Private Messages

Click a username in the Users sidebar to open a direct message conversation with that user. The chat header shows a Direct: badge while in private mode. Click the × on the badge to return to room chat.

Private unread message counts appear next to each username and in the Users header badge.

Commands

Type a slash command in the message input field:

CommandDescription
/motdRequest and display the Message of the Day for the current room

Room and User Lists

  • The Rooms sidebar shows all known rooms with their topic and user count. Rooms you have joined are highlighted with a green left border.
  • The Users sidebar lists all users currently in your joined room, with their BBS name below.
  • Join and part announcements appear inline in the message stream.

Admin Integration

MRC can be configured through Admin → MRC without editing config/mrc.json directly. The admin page covers:

  • Enable/disable MRC
  • Server connection settings (host, port, SSL)
  • BBS identification (name, sysop, platform)
  • Connection timeouts
  • Message retention settings
  • BBS info (website, telnet/SSH addresses)

Changes take effect after restarting the daemon.

The MRC connection status indicator (connected / disconnected) appears in the main navigation bar header.

Architecture

ComponentPurpose
scripts/mrc_daemon.phpLong-running daemon; maintains TCP connection to MRC server; reads/writes mrc_outbound table
public_html/webdoors/mrc/api.phpHTTP API serving the browser WebDoor; handles poll, send, join, heartbeat, command actions
public_html/webdoors/mrc/mrc.jsBrowser-side chat client; polls the API every 2 seconds
src/Mrc/MrcClient.phpLow-level MRC protocol implementation (packet framing, NEWROOM, IAMHERE, LOGOFF, etc.)
src/Mrc/MrcConfig.phpConfiguration manager for config/mrc.json

Database Tables

TablePurpose
mrc_messagesInbound messages and server announcements stored for client polling
mrc_outboundQueue of outbound packets waiting to be sent by the daemon
mrc_usersActive users per room (is_local=true for WebDoor users, false for remote)
mrc_roomsKnown rooms with topic and last activity
mrc_stateKey/value store for daemon state (connection status, last ping time)

Presence and Keepalives

  • IMALIVE — Sent by the daemon to the MRC server every ~60 seconds to keep the BBS-level connection alive.
  • IAMHERE — Sent for each local WebDoor user every ~50 seconds to keep their individual session alive on the MRC server.
  • Browser heartbeat — The browser sends a lightweight heartbeat on user activity and via the poll loop to keep the last_seen timestamp current. Users whose last_seen exceeds 10 minutes are pruned and a LOGOFF packet is sent on their behalf.

Troubleshooting

Daemon won't connect

  • Check data/logs/ or journalctl -u mrc-daemon for error messages
  • Verify the server host and port in config/mrc.json (see the server table above)
  • Ensure the port is not blocked by your firewall
  • Try --debug flag to see raw protocol output

Messages not appearing

  • Confirm the daemon is running: check data/run/mrc_daemon.pid and the mrc_state table connected key
  • Confirm the WebDoor is enabled in Admin → WebDoors
  • Check browser console for API errors

BBS name rejected by server

  • Avoid apostrophes, quotes, and tildes (~) in bbs.name — apostrophes are stripped automatically, but other special characters may still cause server-side rejection

Connection drops frequently

  • Increase keepalive_timeout in config/mrc.json if your network has high latency
  • Ensure auto_reconnect is true