File areas

File areas are the BBS's download library. Each area lives on disk
under a configurable storage path.

Creating an area

Admin → File Areas → Add Area:

field purpose
tag unique key (e.g. FILES.GAMES)
name display name
description shown in the area listing
storage_path absolute path on disk where files live
upload_permission none / users / sysop
is_sysop_only hide entirely from non-admins
password optional — area lock
min_access_level minimum access level to see/browse the area (default 10 = registered users; 0 = everyone, 50 = VIP, 100 = sysop)
min_write_level minimum access level to upload, independent of upload_permission

Where files live

Each area stores binaries in its storage_path. Sysop can drop files
in directly (e.g. via SFTP) or users can upload via the web or FTP.

Migrating an existing file collection that already has a classic
FILES.BBS / FILES.BSS index? tools/bbs-files-tool.py builds the
.descriptions.json cache ANetBBS reads for an area directly from
that index, without touching the original file. See
FILEBASE-MIGRATION.md for the full
walkthrough.

FTP access

When FTP_ENABLED=true in .env (or via Admin → Settings), the
ANetBBS FTP server publishes every active FileArea as a top-level
directory. Three views are served from the same port:

  • Anonymous (anonymous / blank password) — read-only, sees only
    active areas with is_sysop_only=false. Earns you the FTN nodelist
    IFC flag once advertised.
  • Authenticated users — same login as web / telnet / SSH. Read
    everything not sysop-only, upload subject to each area's
    upload_permission (none / users / sysop).
  • Sysop — read + write everything, including is_sysop_only areas.

Uploads via FTP create the same FileUpload row a web upload would,
so they show up in the web file-area browser as well. Per-area
upload_permission is enforced post-write: a denied upload is
deleted from disk and the violation is logged.

Ports to open on the firewall: 21/tcp (control) and the configured
FTP_PASV_PORTS range (default 40000-40050, data channels). See
docs/PORTS.md for the full table. Optional FTPS by setting
FTP_TLS_CERTFILE + FTP_TLS_KEYFILE (reuse your nginx
Let's Encrypt cert).

Daily download quota

Admin → File System → Download Quotas (/admin/file-quotas) caps
how much a user can download per day, scaled by access level — so one
user can't tag-leech the whole file base overnight.

Configure a list of (minimum access level, daily quota in MB) tiers.
A user gets whichever tier has the highest access level they still
qualify for — e.g. tiers at level 50 and 100 give a level-75 user the
level-50 quota, not the level-100 one. A level with no tier configured
at or below it downloads unlimited. Admins always bypass.

Enforced everywhere a file can be downloaded: the web file-area and
file-gallery routes, ANSI telnet/SSH (Zmodem/Ymodem/Xmodem, single and
batch), PETSCII (Xmodem), and FTP (RETR) — anonymous FTP logins and
QWK-node FTP sessions are exempt (no local account to attribute usage
to, or out of scope respectively). Usage resets at Eastern midnight.

Upload moderation queue

Set FILE_MOD_QUEUE_ENABLED=true in .env to require sysop approval
for non-admin uploads.

When on:
- User uploads → file lands in data/file-queue/, a
FileQueueEntry row marks it pending.
- Admin → File Queue (/admin/file-queue/) lets sysop approve
(moves to area storage_path) or reject (deletes).

Upload safety checks

Two checks run automatically on every upload, before it's accepted:

  • Archive integrity test — zip/tar/7z/rar archives are opened and
    verified; a corrupt archive is rejected outright instead of sitting
    in the file base as a broken download.
  • Content-hash dedup check — a SHA-256 hash of the file's content
    (not its filename) is compared against everything already in the
    file base. A near-identical re-upload under a different name gets
    flagged instead of silently duplicating storage.

File ratios

Mystic/Synchronet-style ratio control:

RATIO_MIN=0.05    # require uploads to be at least 5% of downloads

When set:
- Each download bumps bytes_downloaded on FileRatio per user.
- Each upload bumps bytes_uploaded.
- A new download is blocked if the user's projected ratio
(after the download) is below RATIO_MIN. Sysops always exempt.

Set RATIO_MIN=0 (default) to disable.

Hatched files (TIC)

TIC ("Ticket File") is FidoNet's file-echo distribution mechanism —
the file-area equivalent of echomail. It runs in both directions:

Inbound

If you've subscribed to file echos via FidoNet, the TIC processor
(anetbbs/echomail/tic.py) auto-files incoming .tic packets into the
matching area. Audit at Admin → TIC In Log (/admin/tic-log) — its
outbound counterpart, TIC Out Log (/admin/hatch-log), covers the
queue described below.

Outbound — automatic, no manual step

This is the part that's easy to miss: uploading a file to any file
area that has a network attached (network_id is not None) queues
that file for outbound distribution to every peer subscribed to that
file echo — automatically, with no extra action.
This includes all
9 of the bundled ANN.FILES.* areas (see doc 6 —
Echomail
for the full list) as well as any custom
file-echo area you attach to a network yourself.

Concretely: _hatch_if_network_area() in anetbbs/web/file_areas.py
runs after every successful upload — the regular Upload form, the
sysop's Manage → Upload, and Smart Upload all call it, as does
the moderation queue's Approve action in
anetbbs/web/file_queue.py (so a queued upload only hatches out once
a sysop actually approves it, not the moment a user submits it). It
calls hatch_local_file() in tic.py, which queues one HatchQueue
row per subscribed peer (FileEchoSubscription) with a fresh CRC32
and size — the same fan-out process_tic() does for a TIC that
arrived from elsewhere, except this file is the origin hop, so there's
no prior SEEN-BY/PATH to inherit.

In short: if you upload to a network-attached area, you are
broadcasting that file to every peer on that file echo, not just
filing it locally.
Purely local file areas (network_id is None)
are unaffected — nothing is queued for those.

Delivery happens on the next BinkP poll per peer. A sysop running this
BBS as a network hub can see the outbound queue's current
pending/failed counts on the TIC / File Distribution tab of Admin
→ Echomail Networks → Hub Management
(/admin/echomail/hub/), which
links through to the TIC Out Log (/admin/hatch-log) for the full
per-item detail (which file, which peer, retry count, last error) — see
doc 6 for the full Hub Management writeup. That
dashboard view is hub-operator-only (gated by REGISTRY_MODE_ENABLED);
the plain Admin → TIC In/Out Log audit pages above are available on
every install.

FileFix — subscription requests from peers

FileFix is the file-echo counterpart to AreaFix (see
doc 6 — Echomail) — it lets a downstream peer manage
their own file-echo subscriptions by sending a netmail instead of the
hub sysop doing it by hand. It lives in anetbbs/echomail/filefix.py
and reuses AreaFix's exact command grammar.

A peer addresses a netmail to FileFix (also recognized:
File Fix, FileMgr) at your hub address, with the AreaFix/FileFix
password in the Subject line
(per FTS-0024 — NOT in the body, same
convention as AreaFix) and one command per line in the body:

+FILES.GAMES        subscribe to a file echo
-FILES.GAMES        unsubscribe from a file echo
+ALL / -ALL         subscribe / unsubscribe to everything available
%LIST (or %QUERY)   reply with current subscriptions
%HELP               reply with a help/command summary

The bot replies with a netmail confirming what changed. If the
requester's FTN address matches a BinkPNode this BBS hosts as a hub
peer, the change is scoped to that peer's own FileEchoSubscription
rows (keyed by peer address, not a BinkPNode foreign key — a real
structural difference from AreaFix's EchoAreaNode) instead of the
global FileArea.is_subscribed flag.

Password: FileFix shares the same network-level password fields as
AreaFix — there's no separate filefix_password. Set areafix_password
(or leave it blank to fall back to binkp_password) on the network's
edit page; it covers both bots.

The sysop side of outbound FileFix requests (subscribe/unsubscribe
buttons on file-area management pages) queues the same kind of netmail
automatically — see send_areafix_request(..., robot_name='FileFix')
in areafix.py (FileFix reuses AreaFix's outbound sender directly).
Traffic is logged on the same Admin → Echomail Networks → AreaFix
Log
page AreaFix uses (/admin/echomail/areafix_log) — a Bot
column and an AreaFix/FileFix filter distinguish the rows.

Shareable links

Any user can mint an expiring share link for a file in an area they
have access to. Tools → My File Shares.