efinger.el/README.md
Andros Fenollosa 324cef61d5 Add efinger: a Finger client and .plan feed reader
Efinger is a client for the Finger protocol (RFC 1288) with an
Elfeed-inspired reader.  Configure a list of accounts once and browse
their .plan files from a two-pane interface: an account list on one
side and the fingered content on the other.

Move with n/p to preview each account, RET to read one in full, l to go
back to the list and q to close both panes.  M-x efinger-finger fingers
a single account on demand.

Connections are asynchronous (:nowait) with a configurable timeout, so
Emacs never freezes when a host resolves but never answers on port 79.

The finger core is forked from GNU Emacs' net-utils.el (by Peter
Breton) and rewritten around an asynchronous connection.
2026-08-18 11:16:05 +02:00

9.1 KiB

Efinger for Emacs

A client for the Finger protocol (RFC 1288) with an Elfeed-inspired reader for Emacs.

Requires Emacs 28.1 or later.

Finger, born at Stanford in 1971, is arguably the first social network: your whole profile lives in a plain-text .plan file that anyone can read with finger you@your-host. John Carmack famously kept his DOOM/Quake development diary this way. Efinger lets you keep a list of accounts and browse their .plan files from a two-pane interface, the same way you follow feeds in Elfeed. For the story behind the protocol, see Finger: la red social de 1971.

How it works

        Emacs                          Finger servers (TCP 79)
 +---------------------+
 |  *efinger*          |   n / p       +----------------------+
 |  ------------------ |------ move -->|  happynetbox.com     |
 | >random@happynetbox |               |  thebackupbox.net    |
 |  Carmack diary      |   RET / l     |  your own fingerd    |
 |  ring@thebackupbox  |<-- enter/back |                      |
 +----------+----------+               +----------+-----------+
            |                                     |
            v  preview                            | async, :nowait
 +---------------------+                          |
 |  *efinger .plan*    |<-------------------------+
 |  the fingered text  |
 +---------------------+
  1. You keep a list of finger accounts in efinger-accounts.
  2. M-x efinger opens the account list next to a content pane.
  3. Moving with n / p fingers the account under point and previews its .plan in the other pane, asynchronously so Emacs never blocks.
  4. RET jumps into the content, l goes back to the list, q closes both panes.

Buffers

Account list + content (M-x efinger)

 Efinger — n/p move · RET open · g refresh · q quit
┌────────────────────────┬───────────────────────────────────────┐
│ random@happynetbox.com │ johnc@idsoftware.com                   │
│ Carmack diary          │ ───────────────────────────────────── │
│ ring@thebackupbox.net  │                                        │
│ me@happynetbox.com     │ -------------------------------------- │
│                        │ John Carmack's .plan for Aug 18, 1997  │
│                        │ -------------------------------------- │
│                        │                                        │
│                        │ I get asked about the DOOM source code │
│                        │ every once in a while, so here is a    │
│                        │ full status update:                    │
│                        │ ...                                    │
└────────────────────────┴───────────────────────────────────────┘

Single account (M-x efinger-finger)

 .plan — l back · n/p next/prev · g refresh · q quit
random@happynetbox.com
──────────────────────

Emily Carter
Marine biologist. Coffee, kayaks and old maps.

--- 2026-08-14 ---
Back from sampling on the coast. Three jars of plankton to review.

Features

  • Account list: keep your finger accounts in efinger-accounts and browse them in a dedicated buffer, the way Elfeed lists feeds.
  • Live preview: move with n / p and the .plan under point is fingered and shown in the content pane automatically.
  • Two-pane reader: RET enters the content pane to read and scroll, l returns to the list, q closes both.
  • Asynchronous connections: connections use :nowait, so Emacs never freezes even when a host resolves but never answers on port 79 (the common case today).
  • Connection timeout: a stalled connection is abandoned after efinger-connection-timeout seconds with a clear message, instead of hanging.
  • Graceful errors: refused or timed-out connections are reported in the content pane, never as a backtrace.
  • One-off finger: M-x efinger-finger fingers a single user@host in its own buffer.
  • Configurable layout: list on the left and content on the right (horizontal), or list on top and content below (vertical).
  • Ports and listing: targets accept an optional :port; omitting the user (host or @host) asks the server to list every user.
  • UTF-8: replies are decoded as UTF-8, so accents and box drawing render correctly.

Keymap

Account list (efinger-list-mode)

Key Description
n Move to next account and preview it
p Move to previous account and preview it
RET Enter the content pane for this account
g Re-finger the account at point
G Rebuild the list from efinger-accounts
q Close both panes

Content pane (efinger-plan-mode)

Key Description
l Back to the account list
n Preview next account (stay in content)
p Preview previous account (stay in content)
g Re-finger the current account
q Close both panes
SPC / DEL Scroll the content up / down

Installation

MELPA

M-x package-install RET efinger RET

use-package with :vc (Emacs 29+)

(use-package efinger
  :vc (:url "https://git.andros.dev/andros/efinger.el"
       :rev :newest)
  :config
  (setq efinger-accounts
        '("random@happynetbox.com"
          ("Backup Box ring" "ring@thebackupbox.net"))))

use-package with :load-path

For manual installation or Emacs < 29:

(use-package efinger
  :load-path "/path/to/efinger.el"
  :config
  (setq efinger-accounts
        '("random@happynetbox.com"
          ("Backup Box ring" "ring@thebackupbox.net"))))

Manual

Clone the repository and place the file in a directory on your load-path:

git clone https://git.andros.dev/andros/efinger.el.git

Then add to your init file:

(add-to-list 'load-path "/path/to/efinger.el")
(require 'efinger)
(setq efinger-accounts
      '("random@happynetbox.com"
        ("Backup Box ring" "ring@thebackupbox.net")))

Usage

  1. Set efinger-accounts in your init file. Each entry is either a "[user@]host[:port]" string or a (LABEL "[user@]host[:port]") list.
  2. Run M-x efinger to open the reader.
  3. Move with n / p to preview each account, RET to read one in full, l to return to the list and q to quit.
  4. Or run M-x efinger-finger to finger a single account on demand.

Public servers you can try today: random@happynetbox.com, benbrown@happynetbox.com and ring@thebackupbox.net.

Customization

Run M-x customize-group RET efinger RET to list all available options.

Key options:

  • efinger-accounts: the accounts shown in the reader.
  • efinger-port (default 79): default finger TCP port.
  • efinger-connection-timeout (default 10): seconds before a stalled connection is abandoned; nil waits indefinitely.
  • efinger-forward-host (default nil): send user@host instead of just user (finger forwarding, for old daemons).
  • efinger-layout (default horizontal): horizontal (list left, content right) or vertical (list top, content bottom).
  • efinger-list-width (default 40): list width in columns (horizontal).
  • efinger-list-height (default 12): list height in lines (vertical).

The Finger protocol

Finger is minimal: the client opens a TCP connection to port 79 of the server, sends a single line (the user name, or an empty line to list everyone) terminated by CRLF, and the server replies with plain text and closes the connection. No encryption, no headers, no sessions. You can speak it by hand:

echo "random" | nc happynetbox.com 79

Contributing

Contributions are welcome! Please see the contribution guidelines for instructions on how to submit issues or pull requests.

License

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/.