Release 1.3.22:
Billy G. - 2026-10-23

Upgrading:
* The upstream news server's password was written to the log (see Bug
  fixes). Check old logs, and change the password if others could read
  them.
* The active database becomes .active64 at the first start; the old
  .active is kept as .active.v1. Older versions can still open the
  spool, but drop each group's cached articles the first time they use
  it; to go back to 1.3.21, rename .active.v1 to .active again.
* "ListenTo DEFAULT" now listens on IPv6 as well as IPv4. Check your
  firewall, or use "ListenTo 0.0.0.0" for IPv4 only.
* ARTICLE, HEAD, BODY and STAT by message-ID, LISTGROUP and XPAT now
  check the Read list of the client's entry, and clients that a login
  can't help get 502 instead of 480.
* LISTGROUP answers "211 count first last group", as RFC 3977 says.
* In the prefetch file of updatenews, a line starting with ! now
  excludes groups; it used to be ignored.
* newscache -p no longer prints the upstream servers' Password; put it
  back into a config made from -p output.
* The spool databases take the disk space of their full size instead of
  being sparse files (with History on, about 8 MB more for the history),
  so that a full disk is an error instead of a crash.
* Packagers: configure.in is now configure.ac (autoconf 2.69 or later)
  and the manual doc/NewsCache.texi; the end-to-end tests need Go 1.26
  and are skipped with an older Go.

New functions:
* XPAT (RFC 2980 2.9): "XPAT header range|<message-id> pattern" lists
  the articles whose header matches the wildmat pattern, in the format of
  XHDR. Like XHDR, it sees the overview fields of every article and all
  headers of the articles in the spool; for other headers of articles
  that are only in the overview, nothing matches. XPAT is in HELP and in
  LIST EXTENSIONS ("pat").
* The prefetch file of updatenews takes wildmat patterns: a line like
  "de.*" or "comp.lang.[cg]o" prefetches every matching group of the
  active list, and a line "!pattern" (or "!group") leaves the matching
  groups out, wherever they come from in the file. Plain group names work
  as before, even for groups the active list doesn't have. Empty lines and
  lines starting with # are skipped, and each group is prefetched once.
  A line starting with ! used to be ignored; it now excludes.
* HDR and LIST HEADERS (RFC 3977 8.5, 8.6). By article number HDR reads
  the overview: Subject, From, Date, Message-ID, References, Xref and the
  metadata :bytes and :lines; other headers get 503, as the RFC asks. By
  message-ID it fetches the article, so every header is there (and
  :bytes). An article without the header gets a line with an empty value,
  and a range without articles 423.
* Articles by message-ID from the spool, with the new option
  "History on" (off by default: then NewsCache behaves as before). It
  keeps a history of the articles in its spool (the directory .history in
  the spool: 16 files of 65536 buckets, keyed by the MD5 hash of the
  Message-ID, like go-pugleaf's and INN's history), and ARTICLE, HEAD,
  BODY and STAT <message-id>, and the message-ID forms of XHDR, XPAT and
  HDR, serve an article from there. An article the spool knows only from
  its overview record is fetched by number and stored, so a crossposted
  article is fetched once (but not into a group the client may not read);
  in offline mode, or with the news server down, articles in the spool
  can be read by message-ID too. Every message-ID request used to go to
  the news server. A spool of an older version gets its entries as
  clients read its articles. newscacheclean drops the entries of groups
  whose database it removed, counts the history toward SpoolSize and
  removes it when it alone takes more than half of SpoolSize (or History
  is off); a damaged history file is renamed to .bad and started anew.
  A history written by a development build since #56 (256 buckets per
  file, "history 1") is moved aside and started anew.

Bug fixes:
* Articles bigger than about 15 KB, which NewsCache stores in their own
  .art file, were never deleted from the spool after they expired on the
  upstream server: the database entry went, the file stayed. Two bugs in
  CNewsgroup: the file name was built as .art<index>d instead of
  .art<number>, and the overview update skipped every article after a range
  it had just fetched, so it never noticed the expired ones there.
* One group name longer than 511 characters in the upstream server's
  active list made NewsCache give up reading the list: clients saw no
  groups at all (LIST empty, GROUP 411 for every group), the database
  stayed locked and the rest of the list was left unread on the
  connection. Such lines are now logged and skipped.
* XOVER and XHDR accepted a range that doesn't start with a number
  ("XOVER -5", "XHDR subject -3") and used an uninitialized first article
  number for it; such ranges now get 501. For an open range ("XOVER 3-")
  the XHDR status line showed the last number as -1, and it showed no
  header name; it now reads
  "221 subject header follows [3-18446744073709551615]".
* The login examples added in 1.3.21 (FEDORA.md and the commented entry in
  the container config) did not require a login: with "allow read post"
  and "Authentication file:", clients that don't log in still read and
  post, and a login only adds rights. The examples now use
  "allow authentication" with "List/Read/PostTo !*" and give the rights in
  the user file, whose format (user:hash:list:read:postto:allow) FEDORA.md
  showed wrongly as user:password. The shipped configs were not affected:
  they let nobody in.
* Before logging in, a client of an entry with Authentication got
  "500 What?" for commands that only a login allows, e.g. every command
  with "allow authentication", or POST with "allow read". Newsreaders wait
  for 480 before they send AUTHINFO, so they couldn't log in. Such commands
  now get "480 Authentication required". Unknown commands, and entries
  without Authentication, still get 500.
* newscache -p and the xdebug command printed "allow authentication" as a
  bare "allow" (and "allow read authentication" as "allow read"). Read
  back as a config, a bare "allow" is allow none, so a login-only entry
  copied from the -p output let nobody in.
* Started as root (by hand, from inetd or from cron), newscache,
  newscacheclean and updatenews switched to Username and Groupname but
  kept root's supplementary groups, group 0 among them; with only a
  Username, also root's primary group. They now set the supplementary
  groups to the user's (initgroups) and, without a Groupname, use the
  user's primary group. A service that systemd starts as root has no
  supplementary groups, so there only the Username-only case was affected.
* In the allow field of an auth-file line (and the last field of
  "Authentication unix:" and "pam:"), "!read", "!post" and "!debug" set
  every other right instead of removing that one: "read,!post" gave a
  logged-in user debug (XDEBUG, which shows the configuration), and "!post"
  didn't take away the post right of the Client entry. They now remove only
  the named right.
* Article numbers above 2^31 were cut down to 32 bits. RFC 3977 stops at
  2^31-1, but the big binary providers passed that long ago (alt.binaries
  groups are above 6*10^10). The numbers went wrong in the upstream
  server's GROUP reply, in OVER and ARTICLE requests to it, in the
  overview records of the spool, in ARTICLE/HEAD/BODY/STAT/XOVER/XHDR and
  in newscacheclean, so such groups showed wrong numbers or an empty
  XOVER. Article numbers are 64-bit now.
  The active database is now the file .active64. An existing .active is
  converted once at the first start (each group keeps its creation time,
  which NEWGROUPS reports) and renamed to .active.v1, which can then be
  deleted.
  A number with trailing characters ("ARTICLE 12x") or one that doesn't
  fit in 64 bits now gets 501; atoi read the leading digits or overflowed.
  On 32-bit systems the spool can't index numbers above 4294967295; such
  articles are passed through from the upstream server without caching.
* STAT with the number of an article that doesn't exist (a gap in the
  group, or past its last article) answered "223 <number>  status",
  without a Message-ID, instead of 423. And a successful STAT <number>
  didn't make that article the current one, so NEXT, LAST and a following
  HEAD or BODY without a number went on from the previous article
  (RFC 3977 6.2.4).
* XHDR copied the header name into a 512-byte buffer on the stack, but a
  command line can be 1024 characters long: a client with read access
  could overflow it with a long header name and crash its session (or
  worse, where the stack isn't protected). The name is now a string.
* An auth-file line with only user and password ("alice:$6$...") was
  refused, so that user could never log in; at least the List field had
  to follow. Such lines are valid now: fields missing at the end add
  nothing, like empty ones, so the user keeps the rights of the Client
  entry. The sample newscache.conf-dist also showed the file format
  without its List and allow fields in one place.
* "Authentication unix" never read /etc/shadow: configure's default
  (--with-shadow=auto) didn't enable shadow password support even where
  shadow.h exists, so the password was compared against the "x" in
  /etc/passwd and every login failed, silently. Shadow support is now on
  by default where shadow.h exists. Note that NewsCache checks passwords
  after it has switched to its Username (news), and only root may read
  /etc/shadow, so unix authentication still can't check local accounts;
  the same is true of PAM with pam_unix. NewsCache now logs why ("cannot
  read the shadow password", and PAM's error with a hint about pam_unix),
  and the manual, newscache.conf(5), newscache.conf-dist and FEDORA.md
  describe the limitation and what works instead: Authentication file:,
  or PAM modules that work without root (pam_sss, pam_ldap, pam_pwdfile).
* newscache -p and "xdebug dump configuration" printed the Password of
  each upstream server in plain text. -p output often ends up in bug
  reports, and xdebug sends it to the client over the network. Both now
  print "# Password set, not shown" instead. Read back as a config, that
  line is a comment, so the upstream login fails (the server answers
  AUTHINFO PASS with an error) until the password is put back.
* newscache, newscacheclean and updatenews copied the -c argument (the
  config file name) with strcpy into a buffer of MAXPATHLEN (4096)
  characters, so a longer argument wrote past its end. Such an argument is
  now refused with "configuration file name is too long" and exit status 1.
  Only whoever starts the programs controls the argument.
* A SpoolDirectory longer than the limit (MAXPATHLEN minus room for the
  longest group name, 3568 characters on Linux) passed the config check,
  and then every session ended with "terminate called after throwing an
  instance of 'AssertionError'", without a reply. It is now a config error
  ("SpoolDirectory too long"), reported at startup by newscache,
  newscacheclean and updatenews (exit status 2), and the check no longer
  depends on --enable-assertions.
* "ListenTo DEFAULT" listened on IPv4 only: the daemon took the first
  wildcard address getaddrinfo returned, which is 0.0.0.0 on Linux, so
  IPv6 clients could not connect. DEFAULT (and "DEFAULT:port") now listens
  on one IPv6 socket that accepts IPv4 clients too, and falls back to IPv4
  where the host has no IPv6. IPv4 clients are still logged, matched
  against Client entries and named in NNTP-Posting-Host by their plain
  IPv4 address. To listen on IPv4 only, use "ListenTo 0.0.0.0".
* The pid file (PidFile) was never removed: after the daemon stopped, it
  still held the old pid. newscache now removes it when it stops on
  SIGTERM or SIGINT, if it still holds its own pid. The file is written as
  root, before the switch to Username, so removing it needs a directory
  that Username can write to (e.g. /run/newscache owned by news); in /run
  itself the file is emptied instead. The configs for systemd (Debian
  package, FEDORA.md) and the container no longer set a PidFile, since the
  service manager knows the pid; without PidFile no file is written and
  nothing is logged (it used to warn "cannot open pid file").
* Overview records from the upstream server were converted with the tab
  positions in a fixed array of 256, so a record with more fields than
  that overflowed the stack. Servers replace tabs in header values with
  spaces, so only a broken or hostile upstream sends such a record. The
  conversion only runs when the upstream's overview format differs from
  NewsCache's.
* The size fields that RFC 3977 servers list as ":bytes" and ":lines" in
  LIST OVERVIEW.FMT matched none of NewsCache's fields ("Bytes:",
  "Lines:"), so with such a server the Bytes and Lines fields of XOVER
  were empty. And a field the upstream sends with its name (e.g.
  "Subject:full") lost the name but kept the colon (": text").
* LISTGROUP with a group the client may not read (Read in its Client
  entry) answered 480, but only after it had made that group the current
  one; XOVER, XHDR, ARTICLE <number> and the other commands for the
  current group then read it, so "LISTGROUP secret.group" followed by
  "XOVER" showed the group. LISTGROUP now checks first.
* ARTICLE, HEAD, BODY and STAT with a message-ID didn't check the Read
  list at all: a client that may read only some groups got any article
  whose message-ID it knew. The article must now be in at least one group
  the client may read (its Newsgroups header).
* A group or article the client may not read got 480 even when no login
  could help (no Authentication in its entry, or already logged in). It
  now gets 502, as RFC 4643 says; 480 stays for clients that can log in.
* The PostTo check split the Newsgroups header wrongly: with three or more
  groups a name was checked with the following ones appended, which
  matched only if PostTo listed the same groups in the same order, and
  the space after a comma was kept, so such posts were refused. A refused
  group now gets 441 once the client is logged in (or can't log in), not
  480.
* The first XOVER (or XHDR, LISTGROUP, STAT, NEXT, LAST) on a group made
  NewsCache synchronize the whole group, whatever range the client asked
  for: a LISTGROUP of the whole group from the upstream server, the
  overview records of every article it didn't have, a 1-byte-per-number
  table in memory and a spool index of 8 bytes for every number from the
  group's first to its last, written out in full. For a binary group with
  numbers from 60000000000 to 67486767815 that is a 57 GB index and 7.5 GB
  of memory, so such groups failed ("412 operation failed") or filled the
  disk. Groups without caching (Options not-cached) fetched the overview
  of the whole group at every GROUP.
  NewsCache now asks for the numbers a client asks for, in steps of 10000
  ("LISTGROUP group a-b", RFC 3977, then OVER for the missing records), and
  compares each step with the upstream server again only after its
  GroupTimeout. The spool's index covers what clients read, at most the
  newest 10000000 numbers of a group; articles further back are passed
  through without caching. LISTGROUP from a client passes the upstream
  server's list on as it arrives, takes a range ("LISTGROUP group 100-200")
  and answers "211 count first last group" as RFC 3977 says (it was
  "211 list of article numbers follow"). updatenews -g and -o prefetch the
  newest 10000000 numbers of each group. Spools of older versions keep
  working. Older versions open the new spools, but drop a group's cached
  articles the first time they use it (its index now starts above the
  server's first number, which they take for a renumbered group); the
  .art files of big articles stay until newscacheclean needs the space.
  When the server's last number goes down (its newest articles cancelled
  or expired, or a server farm whose frontends lag behind), only the
  cached articles above it are dropped; numbers far above, up to 2^64,
  can't make a session loop.
  An OVER/XOVER range without articles (423, or 420 from older servers)
  made NewsCache assume the upstream server has no OVER, then no XOVER,
  and give up on the overview; it now means no records.
* CAPABILITIES listed READER, POST and, for entries with Authentication,
  AUTHINFO USER to every client: also to clients without the right to
  read or post, and AUTHINFO also after the login (RFC 4643 says not
  then). It now lists only what the client can do at that moment, and
  adds HDR, OVER and LIST HEADERS for readers.
* XPAT with a message-ID ("XPAT subject <id> *") returned the header of
  any article whose message-ID the client knew, also in groups its Read
  list doesn't allow (XPAT came in this release, the Read check of
  ARTICLE <id> after it). It now checks like ARTICLE, as XHDR and HDR do.
* XHDR takes a message-ID ("XHDR subject <id>", RFC 2980 2.6); it
  answered 501. The line starts with the message-ID, and no group needs
  to be selected.
* A damaged database in the spool (a group's .db, or .active64) could
  crash NewsCache. Damage behind the header crashed every session that
  touched the group (SIGSEGV), a short or damaged .active64 aborted every
  session before the greeting, a short .db gave "412 operation failed"
  for good, and newscacheclean ended with SIGABRT at a damaged .db, before
  it had removed anything. The offsets and sizes in these files are now
  checked before they are used; a damaged file is moved to name.bad (one
  error line in the log), a new one is started and filled from the
  upstream server again, and the command that ran into it is retried.
  newscacheclean goes on with the other groups and removes the .bad
  files. A command that fails with any other unexpected error now gets a
  503 instead of ending the session (e.g. a stored article that doesn't
  parse; in inetd mode that aborted with SIGABRT).
  Processes that run into the same damaged file at once move it aside
  only once (under a lock on its directory) and all go on with the same
  new file; one could move another's new file aside, and the updates
  made there were lost. Opening a database checks it under a lock, so a
  sound file that another process is writing to is no longer taken for
  damaged. If no new file can be started (no file descriptor left, no
  space), the database answers errors until it can, instead of using
  the old mapping (a crash).
* CachePort never worked: the check of its first character was the wrong
  way round since the IPv6 support of 2008, so "CachePort nntp" listened
  on the service "ntp" read as a number and "CachePort #12000" passed the
  "#" on, and the daemon couldn't start. It also took precedence over
  ListenTo, which the documentation says it doesn't. It now takes a
  service name, a number or #number, and is ignored (with a log line)
  when ListenTo is set; newscache -p no longer adds a ListenTo line that
  would hide it.
* DATE with an argument answered "501 Syntax: group Newsgroup"; it now
  gives DATE's own syntax.
* An upstream server that returns at most so many overview records per
  OVER, whatever the range asked for, cut groups short: NewsCache asks
  for a run of up to 10000 numbers, took everything after the last record
  it got for articles without a record, and clients saw only the first
  part of the range (until the next sync, which went the same way). It
  now asks again after the last record received until the range is done.
  A server that returns whole ranges costs at most one more request
  (answered 423), when a range ends in numbers without articles.
* When the upstream server asked for the login again in the middle of a
  session (480, as servers do when a login times out), NewsCache took the
  480 to an OVER for "no OVER", then the one to XOVER for "no XOVER", and
  gave up on the overview: clients got an empty XOVER without an error
  until the session ended; other commands failed with the 480. NewsCache
  logged in only when it connected. It now logs in again (with the
  server's User and Password) and sends the command once more.
* The password of the upstream news server was written to the log:
  every command to the server is logged at level info ("RServer::issue:
  issue ..."), "authinfo pass <password>" too. With syslog that is the
  news facility, which Debian's default rsyslog also writes to
  /var/log/syslog (readable by group adm), and the systemd journal; with
  --without-syslog, newscache.log. AUTHINFO to the server is now logged
  without its arguments, as the client's AUTHINFO already was. Check old
  logs, and change the password if they were readable by others.
* Once a client had read an article (up to 15 kB, kept in the group
  database), its overview record was made from the article: :lines was
  empty when the article has no Lines header (most articles; RFC 5536
  made it obsolete), XHDR Lines gave "(none)" and HDR :lines nothing, and
  :bytes counted the dots added for dot-stuffing (RFC 3977 counts the
  article without them). :lines now counts the body lines, and :bytes
  leaves those dots out, also for HDR :bytes <message-id>.
* With several news servers, the Xref of an article lost the groups that
  another server serves (their numbers are the other server's), but the
  Xref of its overview record kept them: a newsreader that marks
  crossposts read by the overview's Xref marked articles of the other
  group that have those numbers on the other server. Overview records
  from a server now get the same Xref as its articles.
* A full spool crashed NewsCache with SIGBUS: the databases (group
  databases, the active list, the history) grow with ftruncate, which
  leaves a hole, and are written through mmap, where a hole the file
  system cannot fill is a signal, not an error. With History on it
  happened at the first history file. The space is now taken when a
  database grows (posix_fallocate, or zeros written where there is
  none; the file size limit counts too), so a full disk is an error,
  and clients hardly notice it: articles and overview records that
  can't be kept are passed on from the news server (a 423 or a cut
  XOVER before), the active list is read to its end so the connection
  to the news server stays in step, and every database lock is given
  back when the error comes (a lock left held would have kept every
  other client of that database waiting until the session ended).
  Nothing is left half written: a database record is replaced only
  after the new one is allocated, and an article whose own file (over
  15 kB) could not be written completely was kept cut off and served
  so from then on; such a file is now removed. A file that is empty
  or can't be opened (no file descriptor left) is no longer served as
  an article ("503 internal error"): the article is fetched again.
  The databases now take the disk space of their size (the history's
  16 files about 8 MB) instead of being sparse.

Other changes:
* Spool, config and log file paths are built with bounded snprintf instead
  of sprintf, group2dir() checks the group name's length, and a group whose
  spool path wouldn't leave room for its article files is refused. These
  overflows needed an extremely long SpoolDirectory or LogDirectory, so
  they were not reachable from outside. The buffers for generated
  Message-IDs are sized from the host name limit. Together this removes
  the -Wformat-overflow and -Wformat-truncation warnings.
* Debian packaging brought up to date for Debian 13 and Ubuntu 24.04:
  "dpkg-buildpackage -us -uc -b" builds a newscache package with GnuTLS
  and PAM that runs as user news under systemd, cleans the spool daily
  with a timer and ships an /etc/newscache.conf that lets nobody in. See
  debian/README.Debian.
* The info manual has a dir entry, and newscache.conf(5) a whatis line.
* The end-to-end tests use nntp-testkit 0.5.0 and need Go 1.26 or later.
  With an older Go, make check now skips them with a message, instead of
  having Go try to download a newer toolchain (which fails offline). Set
  GOTOOLCHAIN to let Go fetch one anyway. The fake upstream server can
  now behave like real servers that don't follow RFC 3977 to the letter,
  and tests/e2e/upstream_test.go runs NewsCache against them: LISTGROUP
  that rejects or ignores a range, only OVER or only XOVER, 420 or an
  empty 224 for an empty range, a last number that goes down (cancels,
  lagging frontends of a server farm), groups whose articles all expired
  ("211 0 0 0"), a connection limit, unusual message-IDs, and clients
  that pipeline their commands. tests/e2e/upstreams_test.go adds a group
  of 10^7 articles (generated on demand), an overview record whose
  Message-ID is not the article's, and two servers that number the same
  group differently; tests/e2e/spoolfull_test.go runs NewsCache with few
  file descriptors, with writes that fail (ulimit -f) and on a spool that
  fills up (a small tmpfs, where user namespaces are allowed).
* doc/websites/ holds an offline copy, from the Wayback Machine, of the
  two original NewsCache websites (Thomas Gschwind, TU Wien; Herbert
  Straub, linuxhacker.at), the 1.2rc6 tarball, patches and man pages they
  link to, and an index page in every folder so it can be served as a
  website.
* The compiler warnings are gone, apart from autoconf/automake ones and one
  that the XOVER range fix removes (GCC 16 with Fedora's flags: 56 before).
  Most were harmless (catch by value, unused variables, a never-NULL array
  checked against NULL). A few fixes change behaviour in cases that
  shouldn't happen: a corrupt active database with a broken record chain
  no longer dereferences NULL, a failed read of an upstream reply no longer
  checks an uninitialized status, updatenews no longer reads an undefined
  exit status when wait() fails, LimitGroupSize ignores a group whose
  last article number is below its first, and builds without syslog stop
  with an error if LogDirectory is too long for the log file name.
* New option AuthFailureDelay: the seconds NewsCache waits before it
  answers a failed login, multiplied by the number of failed logins in the
  connection. The default stays 15 (15, 30, 45 seconds); 0 answers at
  once, the maximum is 3600. It was fixed at 15 seconds.
* configure.in is now configure.ac and the manual doc/NewsCache.texi
  (was doc/NewsCache.texinfo), and the obsolete autoconf and automake
  macros are replaced, so autogen (autoreconf) and configure run without
  warnings (21 with autoconf 2.73 and automake 1.18 before). The version
  is set in AC_INIT now. PACKAGE and VERSION, the tarball name and the
  configure options are unchanged; config.h also defines PACKAGE_NAME,
  PACKAGE_VERSION and the like now, and configure --help names the issue
  tracker. Autoconf 2.69 or later is needed. Packagers who patch
  configure.in or refer to NewsCache.texinfo need to follow the renames.
* The release tarball has the notes in doc/ again (newscache-pam.txt,
  newscache-stunnel-ssl.txt, ...), which README.md points to, and the NNTP
  specifications there. doc/Makefile.am had no backslash after
  "EXTRA_DIST =", so its list was ignored, and it named two drafts that
  were no longer in the tree.
* Documentation: the manual's chapter "Access Control" described only
  libwrap; it now explains the AccessList (nothing is allowed by default,
  Client and Default entries, rights, groups, logins) with an example.
  The login example in newscache.conf-dist made the login optional
  ("allow read post"); it now uses "allow authentication" with the rights
  in the user file, as FEDORA.md does. debian/README.Debian still said an
  auth-file line needs the list field. newscache(8) lacked -n and what -c
  does. The FAQ says what to do after moving groups to another news
  server: remove their databases, or NewsCache may serve the old server's
  cached articles under the new server's numbers.

Release 1.3.21:
Billy G. - 2026-10-20

Upgrading:
* The shipped configs no longer let anyone in. If you copy
  newscache.conf-dist or use the container image, add a Client entry for
  your clients' addresses or networks, or an entry with Authentication
  (login), before Default.
* A Client entry with a /prefix after something that isn't an IP address
  (e.g. a host name like news.example.org/24) is now a config error, so
  such a config no longer loads. Before, the entry silently never matched.
  Check with newscache -p before restarting.

Bug fixes:
* The sample newscache.conf-dist allowed inetd clients (Client stdin, with
  debug) and clients from localhost, and the container config allowed
  loopback and all private networks. Both now only contain
  Default { allow none }, with the old entries as commented examples, so
  nobody may read or post until a Client entry (address or CIDR) or a login
  allows it. FEDORA.md does the same and shows how to allow clients.
* newscache -p and the xdebug command printed AccessList entries for an
  address or network (e.g. Client 192.168.0.0/255.255.0.0) as "Default",
  without the address; read back as a config, such an entry would have let
  every client in. They now print as Client 192.168.0.0/16.
* On hosts where getaddrinfo considers IPv6 unavailable (seen in Docker
  containers), an IPv6 Client entry such as 2001:db8::/32 was not parsed as
  an address and silently became a host name that never matched. Addresses
  are now parsed without AI_ADDRCONFIG. A /prefix after something that
  isn't an IP address (e.g. 300.1.1.1/8) is now a config error instead of
  an entry that silently never matches.

Other changes:
* Dockerfile for Docker and Podman (also Docker Desktop and Podman Desktop on
  Windows): builds on Ubuntu 24.04, runs as user news in the foreground and
  logs to the container output. Its config reads from
  news.blueworldhosting.com over TLS and lets nobody in until you mount a
  config with a Client entry or a login. CI builds the image and checks both.
* CI also builds and runs make check on Linux ARM64, Alpine 3.24 (musl),
  Debian 13 and FreeBSD.
* README.md: how to run NewsCache in a container and on Windows (WSL 2).

Release 1.3.20:
Billy G. - 2026-10-20

Upgrading: with Options ssl or starttls, NewsCache now verifies the server's
TLS certificate and drops the connection if it is invalid, expired or for
another name, or if STARTTLS is refused. Check the log after upgrading. For a
server with a private CA set TLSCAFile; Options noverify accepts any
certificate, without protection against a man-in-the-middle.

Bug fixes:
* TLS to upstream servers (Options ssl and starttls) now verifies the
  server's certificate: it must chain to a trusted CA, be valid and match the
  host name in the Server line. Before, any certificate was accepted, so
  anyone in the middle could impersonate the server.
* STARTTLS no longer falls back to plain text. If the server refused
  STARTTLS, NewsCache continued without TLS and sent User/Password in plain
  text, which anyone in the middle could force; now the connection is
  dropped. A failed TLS handshake after STARTTLS also ends the connection.
* A NewsCache built without GnuTLS ignored Options ssl and starttls and
  talked to such a server in plain text, login included. It now refuses to
  connect to it and logs why.
* TLS uses the system's trust store (it was a fixed Debian path, missing on
  Fedora and macOS), sends the host name as SNI, has a handshake timeout and
  logs why a handshake or verification failed.
* newscache -p left the server options ssl, starttls and dontgenmsgid out of
  its output, although they were parsed and used.

Other changes:
* New server settings: TLSCAFile (CA certificates for servers with a
  private CA) and Options noverify (accept any certificate, logged as a
  warning). The man page now documents ssl and starttls, and the sample
  config no longer lists not-ssl and not-starttls, which never existed.
* Bug reports and the home page point to
  https://github.com/go-while/NewsCache instead of the dead members.aon.at,
  linuxhacker.at and TU Wien sites and mailing lists: in the error messages
  that ask for a report, the man pages, README, INSTALL (whose socket++
  instructions were obsolete), the texinfo manual, doc/ and debian/.
* NVClasses: NVlist.{h,cc} is now NVListBase.{h,cc} (class NVListBase).
  NVlist.h and NVList.h clashed on case-insensitive file systems, so
  checkouts on Windows and macOS were broken. The spool format is unchanged.
* src/Config.{h,cc} is now src/NewsCacheConfig.{h,cc} (the class is still
  Config). On case-insensitive file systems, #include "config.h" in src/
  found src/Config.h instead of the header that configure generates.
* NewsCache builds on macOS: configure checks for crypt.h (macOS and the
  BSDs declare crypt() in unistd.h), and wildmat.c no longer uses a K&R
  function definition, which C23 compilers such as Xcode's clang reject.
* CI: build and make check on macOS, and a check on Windows and macOS that
  the tree checks out cleanly on a case-insensitive file system.
* The sample newscache.conf-dist and FEDORA.md use news.blueworldhosting.com
  (port 563, TLS) instead of the long-gone TU Wien servers, and README.md
  lists public news servers.
* FEDORA.md: all steps tested on Fedora 43, 44 and 45.
* Removed stamp-h.in (an automake leftover) and the TODO file from 2013;
  its still-open items are in REVIEW.md.

Release 1.3.19:
Billy G. - 2026-10-19

Bug fixes:
* NewsCache crashed at startup ("buffer overflow detected" with
  _FORTIFY_SOURCE, memory corruption without) on hosts whose fully
  qualified domain name is 64 characters or longer, as on cloud VMs such
  as GitHub's runners. The host name buffers were MAXHOSTNAMELEN (64)
  bytes, which is the kernel host name limit, not the DNS limit; they are
  now 256 bytes and the copies are bounded. Found by the new CI.

Other changes:
* CI (.github/workflows/ci.yml): make check on Ubuntu (default with the
  race detector and make distcheck, file logging with debug, and
  AddressSanitizer) and on Fedora 43, 44 and 45 with Fedora's packaging
  flags.
* README: says that NewsCache is developed on GitHub and that the
  Subversion repository is archived (SVN r81 added a note there).

Release 1.3.18:
Billy G. - 2026-10-19

Bug fixes:
* Authentication: a missing optional field was read past the end of the
  field list, and the client session crashed after a successful login.
  This happened with "Authentication unix" or "pam" without the
  ":list:read:postto:flags" fields (documented in newscache.conf(5)), and
  with auth-file lines shorter than user:password:list:read:postto:flags.
  Missing fields are now empty.
* MD5 password hashes in auth files (base64, 24 characters ending in "==")
  crashed the session on 64-bit systems. md5lib used unsigned long for its
  32-bit words, which is 64 bits there, so computing the hash overran a
  stack buffer (and gave a wrong hash). It now uses uint32_t. Affects every
  release since at least 1.2rc6 on 64-bit systems; crypt() hashes such as
  $6$ were not affected. Found by CodeQL.
* DATE and NEWGROUPS use gmtime_r/localtime_r, and NEWGROUPS checks their
  result instead of dereferencing a NULL pointer on failure.

Other changes:
* CodeQL code scanning (.github/workflows/codeql.yml) runs on pushes and
  pull requests to main and weekly.

Tests:
* End-to-end tests for file authentication: a short auth-file line, an MD5
  hash, and a wrong password.
* End-to-end tests for DATE and NEWGROUPS.

Release 1.3.17:
Billy G. - 2026-10-18

First release from https://github.com/go-while/NewsCache, which continues
NewsCache with Christof Meerwald's agreement. It is SVN trunk r80 (1.3.16)
plus the fixes and tests below.

Bug fixes:
* Access list: a Client entry with a plain IP address and no mask (for
  example "Client 10.1.2.3") had prefix length 0 and matched every client of
  that address family. It now means exactly that host. Affects 1.3.ipv6 to
  1.3.16 (since the IPv6 support); configs with a mask or a host name are not
  affected, and 1.2rc6 matched such entries by name only.
* Access list: entries for one exact host (a.b.c.d/32, /255.255.255.255,
  /128) never matched, including the example in newscache.conf(5). A prefix
  longer than the address is now a syntax error.
* SIGHUP with a broken newscache.conf no longer kills the daemon; it logs the
  error and keeps the running configuration.
* Upstream articles without an Xref header are served instead of failing with
  423/430.
* "400 too many users" is no longer followed by a NUL byte.
* "502 You have no permission to talk" ends with CRLF instead of a bare LF.
* Log file timestamps (builds without syslog) showed the previous month.
* newscacheclean: "ng == NULL | nr < firstnr" read an uninitialized variable
  (| instead of ||); the result was the same.
* The sample newscache.conf-dist loads again: BindFrom only takes numeric
  addresses since the IPv6 support, and the sample used a host name.
* make dist works again (a misspelled header name in NServer-0.9.1, there
  since 1.2rc6), and make distcheck passes: the test programs are now
  check_PROGRAMS, so make clean removes them.
* configure.in carries the release version again; it still said 1.3.ipv6,
  so 1.3.16 greeted clients with "NewsCache 1.3.ipv6".

Tests:
* make check passes again (cArticle, cNewsgroupFilter and cConfig were broken).
* New end-to-end tests in tests/e2e (Go, using
  github.com/go-while/nntp-testkit) run the real newscache binary against a
  fake upstream server. make check runs them when Go is installed and skips
  them otherwise.

Documentation:
* README.md: project history, building, and a check of the old documentation.
* FEDORA.md: building, testing and installing on Fedora, with a systemd unit
  and a cleanup timer.

Release 1.3.ipv6:
Christof Meerwald

New functions:
* IPv6 support

* new ConnectTimeout, ConnectBackoff and LimitGroupSize options

* client support for SSL connections

Release 1.2:
Herbert Straub - 2004-09-28
New functions:
* Can handle different PAM Servicenames per network, see man
  newscache.conf setcion: AccessSpec Configuration Options -> PAMServicename
  
* Only authenticated clients in a network (new option: authentication) -
  see man newscache.conf section: AccessSpec Configuration Options

* new newcache command option: -o --> print out the configurations options

* new meaning of option: updatenews -a --> force the update of the ActiveDB

* detecting corrupt database files and do a rename of this defect file. In
  such cases NewsCache logs this situation to news.err.

* newscacheclean can also handle corrupt database files. The first run renames
  the bad file and (at the moment) abort further operations. The next run of
  newscacheclean can do work without errors.

New Docus:
* doc/newscache-coredump.txt
  how i catch a coredump

* doc/newscache-debugging:
  how i debug a newscache session

* doc/newscache-pam.txt
  how i use the pam functionality

* doc/newscache-stunnel-ssl.txt
  nntps (SSL) with NewsCache and stunnel

* doc/newscache-corrupt-db-files.txt
  Curropt database files (recory)

Manual Pages:
* all configuration dependig pathes are now configured by the configuration
script.

Bugfixes:
* Compiler Error with -O3 (see Changelog for details)

* internal Command MAP handling

* xdebug dump authorization doesn't display the correct access_flags

* Fixing segfault - Don't read the newscache.conf in the right manner



Release 1.1.92:
* Bugfix Release
  Mike Harding reports a tin hang error, should be fixed with 
  this Release.

Release 1.1.90:
* Completely reworked authentication model: AUTHINFO USER/PASS supports now
	- file (plain or encrypted passwords). configuration option
	  --enable-plainpass (default=no)
	- unix; configuration options:
	  --with-md5 --with-md5auto --with-shadow
	- pam (pluggable authentication modules) confiuration option
	  --with-pam
	- pam+file same as above, but the user permission can be
	  specified in the addiational file
  file and unix authentication methods are also available in earlier
  version, but now all methods are consolidated in a uniform schema.
  All methods understand further group specification and allow 
  additional methods (example: post). Only the commands are
  displayed with the HELP command, for those are the authorization
  is granted.

* authentification errors now handled.
  a client process accepted only three wrong passwords and
  then the client is disconnected. The answer to the client
  is also time delayed. The necessary parameters are now
  fix implemented, but can be configurable in the 
  configuration file.

* extented XDEBUG command
  Now there are two supported commands:
  XDEBUG DUMP AUTHORIZATION
  XDEBUG DUMP CONFIGURATION
  This commands are only available, if the debug option is
  listed in allow parameter.

* a lot of consolidation work is done, to bring the man
  pages, the example configuration file and the source
  code in synchronization. The newscache.conf manpage
  contains only tested and verified parameters (I hope
  so). 

* all programs follows  the  usual GNU command line syntax,
  with long options starting with two dashes (`-').

* all programs options are verified and corrected and(!) a
  description is available in the man pages.
  
* many bugfixes and patches fom Tilman Linneweh (see
  Changelog for details.




Release 1.1.12:

* NewsCacheClean Enhencement: NewsCacheClean missing to purge "outdated"
article files in the spool cache. If the upstream newsserver reduce the
available articles in a newsgroup (ex. from 1-100 to 50-120), then all articles from nr 1-49 and size greater then 15kBytes, are left in the cache (.art* files). Now NewsCacheClean analyzing every Newsgroup DB and mark every outdated .art file in the internal purge table with timestamp 0 and therefore newscacheclean purges all outdated .art files. This new optimized purge method reduce the cache of my NewsCache Application from 4 to 1 GB, means 3 GB outdated articles!

* Catching "caught signal 6" error messages in news.err. This error occours with broken client or upstream server connections

* Require Socket++ 1.12.9

Release 1.1.11:

* doxygen comments in *.h files; configuration available:

* Bugfixes: if configured with --with-syslog=no (see ChangeLog for details)

* Removed: accesslog, cachestat, hoststat, hostlog

* The programs NewsCache and NewsCacheClean are now lowercase

* Bugfix: caught signal 6 (see ChangeLog for details)

* Qualifier -t removed from updatenews and newscacheclean

* A new manual page for newscacheclean 8

* Tested with RedHat Advanced Server (Itanium II) with g++ 3.2


Release 1.1:

The main goal for version 1.1 is porting the source to gcc 3.0 standards.
See documentation ftp://gcc.gnu.org/pub/gcc/libstdc++/libstdc++-doxygen-3.0.tar.gz 

NewsCache uses now the Socket++ Library Version 1.12. Please install this first. See: http://members.aon.at/Socket++/

Release 1.1.6: ready for RedHat 8.0 (tested with socket++ shared library).
RedHat 8.0 use g++ 3.2!

* New Article Spool Management for offline mode (new classes ArtSpooler,
  ObjLock).

* NewsCache, updatenews NewsCacheClean are using own names for syslog
  messages per default. In previous versions all programs are using 
  NewsCache. With ./configure --with-uniquename it is possible, to 
  switch to the old naming standard.

