nntp

package module
v0.2.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 27, 2026 License: BSD-3-Clause Imports: 10 Imported by: 0

README

go-newsgroups/nntp

nntp

CI Go Reference

A dependency-free, pure-Go NNTP (Usenet) read client following RFC 3977. It uses only the Go standard library (net, net/textproto, crypto/tls, ...), builds with CGO_ENABLED=0, and pulls in zero third-party dependencies.

Supported operations: connect (plaintext or implicit TLS), AUTHINFO authentication, CAPABILITIES negotiation, MODE READER, GROUP selection, OVER overview retrieval (with automatic XOVER fallback), ARTICLE fetching, and LIST ACTIVE newsgroup enumeration.

Legacy and modern servers

The client works against both ancient NNRP servers that predate RFC 3977 and modern servers such as INN. CAPABILITIES is negotiated lazily and cached (and refreshed after AUTHINFO, since a server may advertise different capabilities once authenticated). A server that rejects CAPABILITIES is driven in legacy mode rather than treated as an error, and Over transparently falls back from OVER to the legacy XOVER command when the former is unknown.

caps, _ := c.Capabilities()        // raw advertised capability lines (empty on legacy servers)
if c.Legacy() { /* pre-RFC-3977 server */ }
if c.HasCapability("OVER") { /* modern overview support */ }
_ = c.ModeReader()                 // enable reader commands where required (safe no-op elsewhere)

Install

go get github.com/go-newsgroups/nntp

Requires Go 1.26.4 or newer.

Usage

package main

import (
	"context"
	"fmt"
	"log"

	"github.com/go-newsgroups/nntp"
)

func main() {
	ctx := context.Background()

	// Dial plaintext (port 119) — use nntp.DialTLS for implicit TLS (port 563).
	c, err := nntp.Dial(ctx, "news.example.org")
	if err != nil {
		log.Fatal(err)
	}
	defer c.Close()

	// Optional authentication.
	if err := c.Authenticate("user", "pass"); err != nil {
		log.Fatal(err)
	}

	// Select a group.
	g, err := c.Group("comp.lang.go")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s: %d articles (%d-%d)\n", g.Name, g.Count, g.Low, g.High)

	// Read the overview for the last 10 articles.
	over, err := c.Over(g.High-9, g.High)
	if err != nil {
		log.Fatal(err)
	}
	for _, o := range over {
		fmt.Printf("#%d  %s  (%s)\n", o.ArticleNum, o.Subject, o.From)
	}
}

API

Method NNTP command Purpose
Dial / DialTLS Connect (plaintext / implicit TLS) and read the greeting
Authenticate AUTHINFO USER/PASS Authenticate (invalidates the cached capability set)
Capabilities CAPABILITIES Negotiate and return advertised capabilities (empty on legacy servers)
HasCapability Case-insensitive check against the negotiated capability set
Legacy Report whether the server predates CAPABILITIES (RFC 3977)
ModeReader MODE READER Switch to reader mode (tolerant no-op where unsupported)
Group GROUP Select a newsgroup
Over OVER (→ XOVER) Fetch article header summaries for a range, with legacy fallback
Article ARTICLE Fetch a full article by message-id or number
List LIST ACTIVE Enumerate newsgroups (optional wildmat filter)
Close QUIT Close the connection

License

BSD-3-Clause. See LICENSE. Copyright the go-newsgroups/nntp authors.

Documentation

Overview

Package nntp implements a dependency-free NNTP (Usenet) read client following RFC 3977. It uses only the Go standard library (CGO_ENABLED=0) and speaks the command/response protocol over net/textproto.

The client is intended for reading: connecting, authenticating, selecting groups, listing overviews, fetching articles and enumerating newsgroups.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Article

type Article struct {
	Headers map[string][]string
	Body    string
}

Article is a complete article: canonicalized headers plus the raw body.

type Conn

type Conn struct {
	// contains filtered or unexported fields
}

Conn is a connection to an NNTP server. It wraps a *textproto.Conn layered over the underlying net.Conn. A Conn is not safe for concurrent use.

Conn transparently bridges legacy NNRP servers (which predate RFC 3977 and reject CAPABILITIES) and modern servers (INN and the like). Capability negotiation is performed lazily and cached; see Capabilities, HasCapability and Legacy.

func Dial

func Dial(ctx context.Context, addr string) (*Conn, error)

Dial connects (plaintext) to addr ("host:port"); if no port is present the default NNTP port 119 is used. The greeting is read and validated.

func DialTLS

func DialTLS(ctx context.Context, addr string, tlsConfig *tls.Config) (*Conn, error)

DialTLS connects with implicit TLS to addr; if no port is present the default NNTPS port 563 is used. tlsConfig may be nil, in which case the platform defaults are used.

func (*Conn) Article

func (c *Conn) Article(msgIDorNum string) (*Article, error)

Article fetches a full article by message-id ("<...>") or by article number, using the ARTICLE command. Headers are split from the body on the first blank line and canonicalized.

func (*Conn) Authenticate

func (c *Conn) Authenticate(user, pass string) error

Authenticate performs AUTHINFO USER/PASS authentication.

func (*Conn) Capabilities added in v0.2.0

func (c *Conn) Capabilities() ([]string, error)

Capabilities issues the CAPABILITIES command (RFC 3977 §5.2) and returns the raw capability lines advertised by the server (for example "VERSION 2", "AUTHINFO USER", "COMPRESS DEFLATE").

Legacy servers that predate RFC 3977 reject the command with 500, 501 or 480 (authentication required first). That is not treated as an error: Capabilities then returns an empty slice with a nil error and the connection enters legacy mode (see Legacy). The negotiated set is cached and reused by HasCapability and Legacy; it is refreshed after a successful AUTHINFO exchange, since a server may advertise different capabilities once the client is authenticated.

func (*Conn) Close

func (c *Conn) Close() error

Close sends QUIT (best effort) and closes the underlying connection.

func (*Conn) Group

func (c *Conn) Group(name string) (*Group, error)

Group selects the named newsgroup and returns its estimated article count and low/high water marks, parsed from a "211 count low high name" response.

func (*Conn) HasCapability added in v0.2.0

func (c *Conn) HasCapability(name string) bool

HasCapability reports whether the server advertised the named capability (matched case-insensitively against the first token of each capability line, e.g. "OVER", "HDR", "READER", "POST", "AUTHINFO", "COMPRESS"). It negotiates lazily on first use and returns false in legacy mode or if negotiation fails.

func (*Conn) Legacy added in v0.2.0

func (c *Conn) Legacy() bool

Legacy reports whether the server does not implement CAPABILITIES (RFC 3977) and is therefore driven in legacy NNRP mode. It negotiates lazily on first use.

func (*Conn) List

func (c *Conn) List(wildmat string) ([]NewsgroupInfo, error)

List returns the available newsgroups via LIST ACTIVE. If wildmat is non-empty it is passed to the server to filter the result.

func (*Conn) ModeReader added in v0.2.0

func (c *Conn) ModeReader() error

ModeReader issues MODE READER (RFC 3977 §5.3), which some servers require before they enable reader commands. A 200 (posting allowed) or 201 (posting prohibited) reply is a success. Servers that do not implement the command answer 500/501; that is tolerated and treated as a no-op success, so calling ModeReader is always safe, including on servers that already greet in reader mode. Dial does not send MODE READER automatically, to preserve the exact on-the-wire behaviour existing callers rely on; call it explicitly when targeting a server that gates reader commands behind it.

func (*Conn) Over

func (c *Conn) Over(low, high int) ([]Overview, error)

Over returns the overview (header summaries) for the inclusive article range low-high in the currently selected group. It uses the RFC 3977 OVER command and, if the server rejects it as unknown (500/501), transparently falls back to the legacy XOVER command, which has an identical response format.

type Group

type Group struct {
	Name  string
	Count int
	Low   int
	High  int
}

Group is the result of selecting a newsgroup with GROUP.

type NewsgroupInfo

type NewsgroupInfo struct {
	Name   string
	High   int
	Low    int
	Status string
}

NewsgroupInfo describes an available newsgroup as listed by LIST ACTIVE.

type Overview

type Overview struct {
	ArticleNum int
	Subject    string
	From       string
	Date       time.Time
	MessageID  string
	References string
	Bytes      int
	Lines      int
}

Overview holds the header summary of a single article, as returned by OVER.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL