A Norton Commander-style dual-pane FTP client for MS-DOS running on any x86 machine. The left pane shows the local DOS filesystem; the right pane connects to an FTP server via the mTCP TCP/IP stack — fully keyboard-driven in 80×25 text mode.
Download latest release here: https://github.com/Projanglez/ftp4dos/releases/latest
- Two panes, Norton Commander style: local DOS filesystem and remote FTP server (passive mode)
- Per-pane sorting (Alt+F3: name/extension/size/date/time, asc/desc) and pane swap (Ctrl+U)
- Search / jump-to-name and full-screen pane toggle for long remote names
- Large remote directories: listings are kept in XMS/EMS memory automatically, for several thousand files (
/NOEXMEMopts out)
- Copy (F5) and move (F6) in both directions, rename (Alt+F6) — recursive for whole directory trees
- Create directories (F7) and recursive delete (F8, confirmations show recursive file/directory counts and total size)
- Multiple selection with the Ins key (Norton style) for copy/move/delete
- Live transfer telemetry (current/average speed, per-file and batch ETA); pause (P) and cancel (ESC) mid-transfer
- View files with F3 (up to 32 KB; remote files via temp download); edit local text files with F4 (minimal editor)
- F3/Enter display images — BMP, PCX, GIF and PNG in 320x200 with 256 colours on any VGA, with pan and zoom
- File checksums (Alt+F9): CRC32 + MD5 for local and remote files, optionally saved to a file
- Long remote file names kept in full beyond the 8.3 / 40-column display and used for transfers; Alt+F2 "Detail" shows the complete name and size
- Long local file names (LFN) where an LFN API is available (Windows 9x DOS, MS-DOS 7.x, or DOSLFN)
- UTF-8 remote file names (RFC 2640), converted to the active DOS codepage (CP437, CP850/858, CP866) and re-encoded on upload; override with
FTP4DOS_CODEPAGEinMTCP.CFG
- Bilingual German/English UI, auto-detected from the DOS country setting (force with
FTP4DOS /L:EN) - Locale-aware number/date/time formatting; compact M/G size display for large files
- Site manager — any number of named connection profiles (host, port, user, password, start directory) in
FTP4DOS.SIT, via [Manage...] in the connect dialog - Tunable transfer buffers via
MTCP.CFGfor maximum throughput on your hardware (see Performance tuning)
- Open Watcom C/C++ (wmake, wpp, wcc, wasm, wlink)
- Windows or DOS host for cross-compilation
- Target: 16-bit real-mode DOS, Large memory model, 8086+
mTCP is an external dependency, included as a git submodule of the official repository https://github.com/mbbrutman/mTCP, pinned to the 2025-01-10 release tag. Clone with submodules and build with Open Watcom:
git clone --recursive https://github.com/Projanglez/ftp4dos.git
# or, in an existing checkout:
git submodule update --init
wmake # produces FTP4DOS.EXE
wmake clean # removes objects and build artifacts- mTCP home page: http://www.brutman.com/mTCP/mTCP.html
Note: mTCP is compiled with -0 (8086), and the application code likewise
uses -0 (compatible with 8086/286/386+). Details are in MAKEFILE and CLAUDE.md.
A packet driver for your network card and an valid mTCP configuration file are required, as well as a valid IP-adress (static or dynamic) via mTCP.
FTP4DOS.EXEFTP4DOS [/L:DE|EN] [/H:HOST] [/LASTCON] [/P:PORT] [/U:USER] [/W:PASS] [/D:DIR] [/S:ALL|NOPASS|OFF] [/SITES] [/EXMEM[:XMS|EMS]|/NOEXMEM] [/UPDATECHECK|/NOUPDATECHECK] [/Q] [/MONO|/COLOR] (or /?)
Both / and - are accepted as the flag prefix. Flags are case-insensitive;
values are passed through as-is (username and password are case-sensitive).
| Parameter | Description |
|---|---|
/L:DE / /L:EN |
Force German or English UI |
/H:HOST |
Connect to HOST automatically on startup |
/LASTCON |
Connect to the last used connection (FTP4DOS.SAV) on startup, without the dialog |
/P:PORT |
Port (default 21) |
/U:USER |
Username (default anonymous) |
/W:PASS |
Password |
/D:DIR |
FTP start directory after connect (empty = root) |
/S:ALL |
Save connection including password to FTP4DOS.SAV (default) |
/S:NOPASS |
Save connection but not the password |
/S:OFF |
Do not save this connection |
/SITES |
Open the site manager directly on startup (takes precedence over /H: and /LASTCON) |
/EXMEM |
Force a backend for large remote listings in extended/expanded memory (/EXMEM:XMS or /EXMEM:EMS); plain /EXMEM is the automatic default and no longer needed |
/NOEXMEM |
Never use XMS/EMS, stay in conventional memory |
/UPDATECHECK |
Check for a new version on startup (same as Alt+F10) |
/NOUPDATECHECK |
Skip the automatic update check for this run |
/Q |
Skip the splash screen |
/MONO |
Force monochrome display (MDA/Hercules) |
/COLOR |
Force color display (default: auto-detect) |
/? |
Show brief help |
After a successful connection, host/port/username (and optionally the password)
plus the FTP start directory are stored in FTP4DOS.SAV next to the EXE and
pre-filled on the next launch. Use /S:ALL (default), /S:NOPASS, or /S:OFF
to control what gets saved; the connect dialog offers the same three choices
interactively.
For more than one server, the site manager ([Manage...] in the connect
dialog) keeps any number of named profiles in FTP4DOS.SIT.
Security note: Stored passwords are lightly obfuscated (XOR + hex), not encrypted — and FTP transmits passwords in plain text anyway.
F3 (or Enter) on a picture shows it full-screen in 320x200 with 256 colours. The format is taken from the file's content, not its name. Pictures open fitted to the screen; the zoom level is shown in the top right corner.
| Key | Action |
|---|---|
+ / - |
Zoom: fit, 25, 50, 100, 200, 400, 800 % |
* |
1:1 |
f, Enter |
Fit to screen |
| Arrows | Pan |
| PgUp / PgDn | Pan a screen at a time |
| Home / End | Top-left / bottom-right |
Esc, q |
Close |
| Format | Decoded |
|---|---|
| BMP | 1/4/8/24/32 bpp; uncompressed, RLE8, RLE4 |
| PCX | RLE, 1/2/4/8 bpp |
| GIF | 87a and 89a, interlaced; first frame of an animation |
| PNG | greyscale, palette, RGB, RGBA, 1–16 bits |
Not decoded: JPEG, TIFF, interlaced PNG.
A picture needs about 100 KB of free conventional memory — F1 shows how much you have. Pan and zoom additionally need XMS or EMS; without it the fitted view still works.
Advanced — totally optional. FTP4DOS works fine out of the box with sensible defaults; only dig into this if you want to squeeze out more throughput on your specific hardware.
Transfer buffer sizes have a large impact on throughput, and the optimal
values are hardware-specific (disk speed, CPU, packet driver quality).
FTP4DOS reads the following optional settings from your mTCP configuration
file (MTCPCFG):
| Setting | Range | Default | Description |
|---|---|---|---|
FTP4DOS_TCP_BUFFER |
512–16384 | 16384 | TCP receive buffer (window) of the data connection |
FTP4DOS_FILE_BUFFER |
512–32768 | 8192 | File I/O buffer: received data is written to disk in blocks of this size (uploads read in the same blocks) |
FTP4DOS_CODEPAGE |
437/850/858/866 | auto | Codepage for UTF-8 file name conversion (default: active DOS codepage) |
FTP4DOS_XFERLOG |
path | off | Diagnostics: writes one line per second during a transfer (elapsed time, bytes total, bytes in the last second, receive/idle/disk-write counts, buffer fill) |
FTP4DOS_UPDHOST |
host name | the project's Worker | Host serving the update channel |
FTP4DOS_UPDPORT |
1–65535 | 80 | Port for the above |
The mTCP FTP client settings FTP_TCP_BUFFER / FTP_FILE_BUFFER are read
as fallbacks, so an already tuned MTCP.CFG works as-is; the FTP4DOS_*
keys take precedence. Experiment: larger file buffers help most machines
(especially with slow disk I/O), but some setups are faster with small ones.
Example:
FTP4DOS_TCP_BUFFER 16384
FTP4DOS_FILE_BUFFER 32768
| Key | Action |
|---|---|
| Tab | Switch active pane |
| Ctrl+U | Swap panes left/right (remembered) |
| Ctrl+A | File details (same as Alt+F2) |
| Ctrl+F | Search / jump to name (same as Alt+F7) |
| Ctrl+R | Refresh active pane (same as F9) |
| Arrow keys / PgUp PgDn | Move selection |
| Home / End | Jump to first / last entry |
| Ins | Mark entry (for multi-file copy/delete) |
| * (numpad) | Invert selection |
| + (numpad) | Mark files missing or different in the other pane |
| Enter | Enter directory / view file (same as F3) |
| Backspace | Go to parent directory |
| F1 | Help |
| F2 | FTP connect / disconnect (with site manager) |
| Alt+F2 | Detail: full name + size of the selected entry |
| F3 | View file — picture or text |
| Alt+F3 | Sort the active pane (name/extension/size/date/time, asc/desc) |
| F4 | Edit local file (minimal editor, ~32 KB, no undo/search) |
| F5 | Copy (recursive for directories) |
| F6 | Move (copy then delete source; recursive) |
| Alt+F6 | Rename (in place) |
| F7 | Create directory |
| Alt+F7 | Search / jump to the next name with a prefix |
| F8 | Delete (recursive with confirmation) |
| Alt+F8 | Full-screen the active pane |
| F9 | Refresh the active pane |
| Alt+F1 | Switch local drive |
| Alt+F9 | Checksum (CRC32 + MD5) of the selected file, optionally saved to a file |
| Alt+F10 | Check for updates |
| F10 | Quit |
FTP4DOS can update itself. Alt+F10 checks for a new version; if there is
one you get its version, date, size, SHA-256 and release notes, and nothing is
downloaded until you say so. The swap happens when FTP4DOS exits — the previous
executable is kept as FTP4DOS.BAK — and FTP4DOS can restart itself into the
new version.
An optional check at startup is off by default. Switch it on by setting
updcheck=1 in FTP4DOS.SAV; it then runs at most once a week, only ever
fetches the small manifest, and does no more than put a line in the status bar.
/NOUPDATECHECK skips it for one run, /UPDATECHECK forces a check.
mTCP has no TLS, so updates travel over plain HTTP. Authenticity does not come from the connection but from a signature:
- The manifest naming the new version and its SHA-256 is signed with RSA-2048.
- The matching public keys are compiled into FTP4DOS.
- The signature is verified before the manifest is read, and the downloaded executable must match the SHA-256 the signed manifest states.
- If either check fails the update is refused. There is no way to override it.
Nobody on the network path — and neither GitHub nor Cloudflare, which carry the files — can produce an update FTP4DOS will install. They can stop updates from arriving; but they cannot substitute one.
The SHA-256 is shown before the download and published in the release notes, so it can be compared by hand if you want to.
Updates come from a small Cloudflare Worker (tools/worker/) that reads this
repository's latest GitHub release. It exists only because no GitHub endpoint
serves files over plain HTTP: Pages enforces HTTPS on its default domain and
release assets need short-lived signed URLs. Point FTP4DOS somewhere else with
FTP4DOS_UPDHOST / FTP4DOS_UPDPORT in MTCP.CFG if you prefer to host it
yourself — the signature check applies either way.
This project is licensed under the GNU General Public License v3.0
(see LICENSE). It statically links the mTCP library, which is
also licensed under the GPLv3.
mTCP © Michael B. Brutman — official home page: http://www.brutman.com/mTCP/mTCP.html
This project builds against the official mTCP, version 2025-01-10,
unmodified, referenced as a git submodule of the official repository
https://github.com/mbbrutman/mTCP (pinned to the 2025-01-10 release
tag). That exact source, together with the source in this repository,
constitutes the complete corresponding source for any distributed binary
(GPLv3 §6). Published releases include a copy of those mTCP sources as an
additional release asset.
This software is provided without any warranty; use at your own risk. See LICENSE (GPLv3, §15–16).
This software was developed with the help of an AI coding assistant (Claude Code).
