nntp(n)

πŸ“¦
version 2.0 Β· 2 versions
, in fedora 43, fedora 44, nixos 26.05, nixpkgs unstable

✨ NAME ✨

okay bestie, listen up β€” this is nntp, the Tcl client for the NNTP protocol. πŸ’…


πŸŽ€ SYNOPSIS πŸŽ€

here's the whole vibe, character for character:

package require Tcl 8.5 9

package require nntp ?0.2.3?

::nntp::nntp ?host? ?port? ?nntpName?

nntpName method ?arg arg ...?

nntpName article ?msgid?

nntpName authinfo ?user? ?pass?

nntpName body ?msgid?

nntpName configure

nntpName configure option

nntpName configure option value ...

nntpName cget option

nntpName date

nntpName group ?group?

nntpName head ?msgid?

nntpName help

nntpName last

nntpName list

nntpName listgroup ?group?

nntpName mode_reader

nntpName newgroups since

nntpName newnews

nntpName newnews since

nntpName newnews group ?since?

nntpName next

nntpName post article

nntpName slave

nntpName stat ?msgid?

nntpName quit

nntpName xgtitle ?group_pattern?

nntpName xhdr field ?range?

nntpName xover ?range?

nntpName xpat field range ?pattern_list?

πŸ’– DESCRIPTION πŸ’–

So the nntp package gives you a simple, Tcl-only client library for the NNTP protocol. πŸ¦‹ No C extensions, no build drama, just vibes and Tcl. ✨

The way it works is lowkey iconic: it opens the standard NNTP socket on the server 🌐, and then hands you a Tcl API so you can talk to all the NNTP protocol commands like the main character you are. πŸ‘‘

And here's the part you need to know, fr fr: all server errors come back as Tcl errors (thrown) 😭 which means you must catch them with the Tcl catch command. No sneaky ignoring them, bestie β€” they will absolutely jump out and ruin your whole script if you don't catch them. πŸ’€

not me finding out the hard way that uncaught NNTP errors just... end you πŸ™ˆ catch them. periodt.

more coming in the next parts, don't go anywhere πŸ’–

🌈 COMMANDS 🌈

Okay bestie, this is the good part. Every method you can call on your nntp object lives here. Buckle up. πŸŽ€


πŸ’– Opening The Connection

  • ::nntp::nntp ?host? ?port? ?nntpName? β€” opens a socket connection to the NNTP server you point at and creates a brand new nntp object with a global Tcl command attached to it, and that command's name is nntpName. That's the handle you use to poke at all the NNTP protocol commands for this fresh connection. Default port is "119" and the default host is "news", and you can override both of those with the environment variables NNTPPORT and NNTPHOST respectively. πŸ’…
Heads up: some commands this package supports are not part of the nntp rfc 977 (http://www.rfc-editor.org/rfc/rfc977.txt) and they will not be available (or implemented) on all nntp servers. Not every server is that girl, ok? 😭

The access command nntpName has this general shape:

nntpName method ?arg arg ...?

The method and the args decide exactly what the command does. Main character energy, honestly. ✨


πŸ¦‹ All The Methods, One By One

  • nntpName article ?msgid? β€” asks the server for article msgid out of the current group. You get the article back as a valid tcl list containing the headers, then a blank line, then the body of the article. Every element in that list is exactly one line of the article. πŸ“
  • nntpName authinfo ?user? ?pass? β€” sends authentication info (username and password) over to the server. Like showing your ID at the door. πŸ‘‘
  • nntpName body ?msgid? β€” asks the server for the body of the article msgid from the current group. Comes back as a valid tcl list, and each element in the list is one line of the body. No headers, just vibes. πŸ’œ
  • nntpName configure
  • nntpName configure option
  • nntpName configure option value ...
  • nntpName cget option β€” these query and configure the options of the nntp connection object. Right now literally only one option is supported: -binary. When you set it, articles come back as binary data instead of text. The only methods affected by this are article and body. πŸŽ€

One use case for this option would be downloading articles with yEnc encoded images. Even though they're encoded, the data is still mostly binary, and grabbing it as text will corrupt the information. So don't do that. πŸ’€

Peep the package yencode for both the encoder and decoder of that kind of data.

  • nntpName date β€” asks the server for its current date. It comes back in the format YYYYMMDDHHMMSS. Iconic little timestamp. ⭐
  • nntpName group ?group? β€” optionally sets the current group, and grabs info about the currently selected group. Returns the estimated number of articles in the group, then the number of the first article in the group, then the last article in the group, then the name of the group. In that order, no cap. 🫢
  • nntpName head ?msgid? β€” asks the server for the headers of the article msgid from the current group. Comes back as a valid tcl list, each element being one line of the headers of the article. 🌸
  • nntpName help β€” retrieves a list of the commands that are supported by the news server you're currently attached to. Server's own little menu. 😌
  • nntpName last β€” sets the current article pointer to point at the previous message (if there is one) and returns the msgid of that message. Going back a page, bestie. ⬅️
  • nntpName list β€” returns a tcl list of valid newsgroups and associated info. Each newsgroup comes back as an element in the tcl list, formatted like this:
group last first p

where <group> is the name of the newsgroup, <last> is the number of the last known article currently in that newsgroup, <first> is the number of the first article currently in the newsgroup, and <p> is either 'y' or 'n' β€” saying whether posting to this newsgroup is allowed ('y') or prohibited ('n').

The <first> and <last> fields will always be numeric. They may have leading zeros. And if the <last> field evaluates to less than the <first> field, there are no articles currently on file in the newsgroup. Empty group, we've all been there. πŸ™ˆ

  • nntpName listgroup ?group? β€” asks the server for a list of all the messages (message numbers) in the group given by the argument group, or in the current group if you didn't pass a group argument at all.
  • nntpName mode_reader β€” asks the server for its nntp 'MODE READER' response string. 🧚
  • nntpName newgroups since β€” asks the server for a list of all the new newsgroups created since the time given by the argument since. That since argument can be any time string understood by clock scan. The tcl list of newsgroups comes back in a similar form to the list of groups returned by the nntpName list command. Each element of the list looks like:
group last first p

where <group> is the name of the newsgroup, <last> is the number of the last known article currently in that newsgroup, <first> is the number of the first article currently in the newsgroup, and <p> is either 'y' or 'n' β€” whether posting to this newsgroup is allowed ('y') or prohibited ('n'). πŸ’–

  • nntpName newnews β€” asks the server for a list of new articles posted to the current group in the last day. Fresh drops only. πŸ”₯
  • nntpName newnews since β€” asks the server for a list of new articles posted to the current group since the time given by the argument since. Again, since can be any time string understood by clock scan.
  • nntpName newnews group ?since? β€” asks the server for a list of new articles posted to the group given by the argument group since the time given by the argument since (or in the past day if you didn't pass a since argument). And yes, since can be any time string understood by clock scan. ✨
  • nntpName next β€” sets the current article pointer to point at the next message (if there is one) and returns the msgid of that message. Scroll on. ➑️
  • nntpName post article β€” posts an article of the form specified in RFC 1036 (http://www.rfc-editor.org/rfc/rfc1036.txt, successor to RFC 850) to the current news group. You're a poster now. πŸ’…
  • nntpName slave β€” identifies a connection as being made from a slave nntp server. This might be used to indicate that the connection is serving multiple people and should be given priority. Actual use is entirely implementation dependent and may vary from server to server. (It's giving "your mileage may vary", fr fr.)
  • nntpName stat ?msgid? β€” the stat command is similar to the article command except that no text is returned. When you're selecting by message number within a group, stat serves to set the current article pointer without sending text. The returned acknowledgment response will contain the message-id, which may be of some value. Using stat to select by message-id is valid but of questionable value, since a selection by message-id does NOT alter the "current article pointer". Read that twice bestie. πŸ‘€
  • nntpName quit β€” gracefully closes the connection after sending a NNTP QUIT command down the socket. Leaving the party politely. πŸŽ€
  • nntpName xgtitle ?group_pattern? β€” returns a tcl list where each element is of the form:
newsgroup description

If you specify a group_pattern, then only newsgroups that match the pattern will have their name and description returned. Filtered, hun. πŸ¦‹

  • nntpName xhdr field ?range? β€” returns the specified header field value for the current message or for a list of messages from the current group. field is the title of a field in the header such as from, subject, date, etc. If range is not specified or is "" then the current message is queried. The command returns a list of elements where each element has the form of:
msgid value

Where msgid is the number of the message and value is the value set for the queried field. The range argument can be in any of the following forms:

  • "" β€” the current message is queried.
  • msgid1-msgid2 β€” all messages between msgid1 and msgid2 (including msgid1 and msgid2) are queried.
  • msgid1 msgid2 β€” all messages between msgid1 and msgid2 (including msgid1 and msgid2) are queried.
  • nntpName xover ?range? β€” returns header information for the current message or for a range of messages from the current group. The info comes back in a tcl list where each element is of the form:
msgid subject from date idstring bodysize headersize xref

If range is not specified or is "" then the current message is queried. The range argument can be in any of the following forms:

  • "" β€” the current message is queried.
  • msgid1-msgid2 β€” all messages between msgid1 and msgid2 (including msgid1 and msgid2) are queried.
  • msgid1 msgid2 β€” all messages between msgid1 and msgid2 (including msgid1 and msgid2) are queried.
  • nntpName xpat field range ?pattern_list? β€” returns the specified header field value for a specified message or for a list of messages from the current group where the messages match the pattern(s) given in the pattern_list. field is the title of a field in the header such as from, subject, date, etc. The info comes back in a tcl list where each element is of the form:
msgid value

Where msgid is the number of the message and value is the value set for the queried field. The range argument can be in any of the following forms:

  • msgid β€” the message specified by msgid is queried.
  • msgid1-msgid2 β€” all messages between msgid1 and msgid2 (including msgid1 and msgid2) are queried.
  • msgid1 msgid2 β€” all messages between msgid1 and msgid2 (including msgid1 and msgid2) are queried.

🌟 EXAMPLE 🌟

Here's a bigger example for posting a single article. Steal it, it's yours bestie 🫢

                  package require nntp
                  set n [nntp::nntp NNTP_SERVER]
                  $n post "From: USER@DOMAIN.EXT (USER_FULL)
                  Path: COMPUTERNAME!USERNAME
                  Newsgroups: alt.test
                  Subject: Tcl test post -ignore
                  Message-ID: <[pid][clock seconds]
                  @COMPUTERNAME>
                  Date: [clock format [clock seconds] -format "%a, %d %
                  b %y %H:%M:%S GMT" -gmt true]

                  Test message body"

And that's the whole posting ritual. ✨

πŸ› BUGS, IDEAS, FEEDBACK πŸ’Œ

okay bestie, real talk: this doc and the whole package it describes are gonna have bugs. Like, undoubtedly. That's just how it is. Not being shady, just being honest fr fr 😭

So if you find something broken, please report it β€” and drop it in the category nntp of the Tcllib Trackers:

http://core.tcl.tk/tcllib/reportlist

And listen, it's not just bugs okay?? If you have ideas for enhancements for the package or the docs, send those too πŸ’– We want the glow-up suggestions, not just the "this is broken" ones. Both are iconic. Both are welcome 🫢


✨ proposing code changes? read this part ✨

If you're gonna slide in with actual code changes, pls provide unified diffs β€” that's literally the output of:

diff -u

no cap, that's the format we want πŸ’…

⚠️ also!! attachments are strongly preferred over inlined patches. This is a big deal, don't skip it.

Here's how you attach, step by step, so you don't get lost:

  1. Go to the Edit form of the ticket β€” do this immediately after its creation πŸ•
  2. Then use the left-most button in the secondary navigation bar πŸŽ€

That's it. That's the whole move. slay ✨


🌸 KEYWORDS 🌸

  • news
  • nntp
  • nntpclient
  • rfc 1036
  • rfc 977

πŸ‘‘ CATEGORY πŸ‘‘

Networking β€” that's the vibe, that's the whole vibe πŸ¦‹


and that's a wrap on the whole page, bestie!! this doc was living its tcllib 0.2.3 era, version-tagged as nntp(n), and that's the tea πŸ“ go forth and read your news, you main character πŸ’œπŸ§šβ€β™€οΈ

πŸ“¦ where this page comes from