The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

newsgroups

Construct the Newsgroups header for a message. This is the general module for this purpose, and is considerably more flexible than the simple handling built into the mailtonews module.

The guiding purpose of this module is to attempt to deal with crossposting correctly in the context of a generic mail to news gateway (where incoming mail messages may not, unlike submissions for moderated groups, already have Newsgroups headers in them). We're ambitious, though, and try to also handle the case where we do have an incoming Newsgroups header.

All of the gory details of what this module does in every circumstance are documented in the comment block at the beginning of the code. If you're really curious, I'd recommend reading that. It's far more information than most people are going to want to know. Here's the briefer summary:

The program tells this module what the primary newsgroup is. This should be the group to which we should post by default. In other words, suppose you have several different mail to news gateway addresses for several different groups which all feed into the same program. To use this module, configure such a system so that the program knows what address a given message arrived via (either by having access to the envelope recipient through using qmail, using procmail as a delivery agent, or some other method, or by having each mail to news gateway alias give the program the name of its primary newsgroup on the command line). The program tells this module what group that is by providing it as an argument to the module.

We also have a list of associations between addresses and newsgroups given to us in configuration directives. An address can either be a literal address (which will be matched exactly, albeit without regard to case) or a regex. Note that although this module wants to know about as many of those associations as possible, it can deal with not knowing about them all and will generally do the right thing. It will just tend to multipost when it could have crossposted unless it knows which addresses correspond to which newsgroups.

If the incoming message doesn't have a Newsgroups header, this module will construct one by inspecting the To and Cc headers and seeing where the message was sent. If the primary group corresponds to one of the addresses in the To and Cc headers, then it will crosspost between the groups corresponding to the recognized addresses in the To and Cc headers (with the caveat given below). Otherwise, it assumes that the address via which we received the message either is one we don't know about or was Bcc'd and posts only to the primary group.

There is one problem with this. If a message is addressed to a number of different addresses, all of which eventually gate to a newsgroup, if all of those gateways do this analysis and crosspost, the article ends up multiposted (one copy for each group crossposted to). The solution to this problem is for one of the instances of the gateway program decide to post and all of the other ones exit quietly. We support this by returning the error "Not primary instance" if the primary group is in the list formed from the To and Cc headers but isn't the first group in that list. We assume that we'll also get the mail going to the address corresponding to the first group in that list, and that instance will do the crossposting. A program using this module should probably exit silently if we return "Not primary instance".

If the message does contain a Newsgroups header, then what we do depends on whether our primary group is among the groups in that header, and whether any of the addresses in the To or Cc headers correspond to groups in that header. The exact rules are very complicated (see the source comments), but we ignore the Newsgroups header entirely if neither the primary group nor the groups corresponding to addresses in the To and Cc headers occur in it, honor it if the primary group is in it, and post only to the groups corresponding to addreses in the To and Cc headers that aren't in the Newsgroups header if some addresses in the To and Cc headers correspond to groups in the Newsgroups header but our primary group isn't in that header. We also return "Not primary instance" where appropriate to ensure that a post to a given set of newsgroups is only done once.

(Yes, this is a simplification. See the source comments for the real complexity.)

We also rename Message-ID to X-Original-Message-ID if we have some expectation that otherwise we'll clash with another post (either made by another instance of the same program or posted elsewhere). We also rename Newsgroups to X-Original-Newsgroups if we don't honor the supplied header. Note that this module goes to some length to avoid renaming Message-ID unless necessary; if you want to drop all incoming message IDs and generate new ones, you should do that using the headers module.

We take an argument specifying the primary group, and we take one configuration directive in one of three forms:

group NEWSGROUP [ ADDRESS | /PATTERN/ ]

Adds NEWSGROUP to the list of valid newsgroups and optionally associates it with either ADDRESS or PATTERN. ADDRESS is a literal string that (case-insensitively) exactly matches the address associated with NEWSGROUP. PATTERN is a Perl regex that matches addresses associated with NEWSGROUP.

group /PATTERN/

Tells this module to consider any newsgroup matching PATTERN to be valid to crosspost to. Note that this directive doesn't set up any address to group mappings, just changes what groups are allowed in a pre-existing Newsgroups header.

group FILE /PATTERN/

Tells this module to add all newsgroups matching PATTERN in the file FILE to the list of valid newsgroups for crossposts. Note that this directive doesn't set up any address to group mappings, just changes what groups are allowed in a pre-existing Newsgroups header. FILE must be an absolute path (i.e., it must begin with /).

In all of the above, the /s around PATTERN arguments are required, as they allow unambiguous parsing of the configuration file directives.

There are three possible failure messages returned by this module:

Invalid crossposted group %s

The incoming message already had a Newsgroups header which included a group that wasn't on the list of allowable newsgroups for crossposting.

Not primary instance

Although the primary group is among the groups we would normally post to, it isn't the "first" such group. This probably means that multiple copies of the message were received by different gateways and this instance should exit silently since another instance will be doing the posting.

In addition to that, there are two possible fatal errors that can occur during the parsing of the configuration file and a third at the time of parsing the incoming message. These errors are passed to the News::Gateway error() method.

Invalid regex /%s/: %s

An error occurred while compiling the given regex from a PATTERN argument to a configuration directive.

Can't open group file %s: %s

An error occurred while attempting to open a file from a FILE argument to a configuration directive.

newsgroups module missing required argument

The newsgroups module requires an argument giving the primary newsgroup, or all of the tricks we use to figure out crossposting and where to post won't work correctly.