Compare commits

..

No commits in common. "master" and "v1.0.1" have entirely different histories.

3 changed files with 207 additions and 284 deletions

View file

@ -1,14 +1,3 @@
yapfaq 1.1.0 (unreleased)
* --test: Set Supersedes and don't modify Message-ID if -o is set.
* --test: Force -o if -n is not set.
* Add conversion script for old status files.
* Accept a posting-frequency of "never", too.
* Check for illegal headers and stop posting, if found.
* Disabled projects must be posted, if forced.
* Warn of unencoded 8bit characters in header or body if -d is set.
* Update POD.
* Add an option for a common headers file for all projects.
yapfaq 1.0.1 (2025-01-24) yapfaq 1.0.1 (2025-01-24)
* Add %t placeholder for Message-ID (feature parity with 0.9). * Add %t placeholder for Message-ID (feature parity with 0.9).
* Remove debugging code. * Remove debugging code.

View file

@ -19,7 +19,7 @@
# It can be redistributed and/or modified under the same terms under # It can be redistributed and/or modified under the same terms under
# which Perl itself is published. # which Perl itself is published.
my $VERSION = "1.1.0-pre"; my $VERSION = "1.0.1";
(my $NAME = $0) =~ s#^.*/##; (my $NAME = $0) =~ s#^.*/##;
use utf8; use utf8;
@ -45,8 +45,6 @@ $Config{'nntp-pass'} = ''; # password for AUTHINFO
$Config{'force-auth'} = 0; # set to 1 to force authentication $Config{'force-auth'} = 0; # set to 1 to force authentication
$Config{'starttls'} = 0; # set to 1 to use STARTTLS if possible $Config{'starttls'} = 0; # set to 1 to use STARTTLS if possible
$Config{'xtraheaders'} = ''; # path to file with extra headers
$Config{'verbose'} = 0; # set to 1 to get status messages $Config{'verbose'} = 0; # set to 1 to get status messages
$Config{'debug'} = 0; # set to 1 to get some debug output, $Config{'debug'} = 0; # set to 1 to get some debug output,
# set to 2 for NNTP debug output # set to 2 for NNTP debug output
@ -102,7 +100,6 @@ GetOptions ('p|project=s' => \$OptProject,
'nntp-pass=s' => \$Config{'nntp-pass'}, 'nntp-pass=s' => \$Config{'nntp-pass'},
'starttls!' => \$Config{'starttls'}, 'starttls!' => \$Config{'starttls'},
'force-auth!' => \$Config{'force-auth'}, 'force-auth!' => \$Config{'force-auth'},
'xtraheaders=s' => \$Config{'xtraheaders'},
'v|verbose!' => \$Config{'verbose'}, 'v|verbose!' => \$Config{'verbose'},
'd|debug!' => \$Config{'debug'}, 'd|debug!' => \$Config{'debug'},
'c|config' => \&ShowConf, 'c|config' => \&ShowConf,
@ -115,9 +112,6 @@ if ($OptSimulation) {
$Config{'verbose'} = 1; $Config{'verbose'} = 1;
} }
# -t implies -o if -n is not set
$OptOutput = 1 if $OptTest && !$OptNewsgroup;
### create list of @Projects from $Config{'datadir'} unless -p is set ### create list of @Projects from $Config{'datadir'} unless -p is set
my @Projects; my @Projects;
if (!$OptProject) { if (!$OptProject) {
@ -380,11 +374,6 @@ sub BuildPosting {
warn "W: '$BodyFile' not found.\n"; warn "W: '$BodyFile' not found.\n";
return ''; return '';
} }
my $XtraHeaderFile = $Config{'xtraheaders'} if $Config{'xtraheaders'};
if ($Config{'xtraheaders'} && not -r $XtraHeaderFile) {
warn "W: '$XtraHeaderFile' not found.\n";
return '';
}
# today (TD) # today (TD)
my $TD = DateTime->now->set_time_zone('local'); my $TD = DateTime->now->set_time_zone('local');
@ -412,10 +401,6 @@ sub BuildPosting {
print "- Reading headers ($Project.hdr) and body ($Project.txt).\n" if $Config{'debug'}; print "- Reading headers ($Project.hdr) and body ($Project.txt).\n" if $Config{'debug'};
my @Headers = path($HeaderFile)->lines; my @Headers = path($HeaderFile)->lines;
my @Body = path($BodyFile)->lines; my @Body = path($BodyFile)->lines;
if ($Config{'xtraheaders'}) {
print "- Reading extra headers ($XtraHeaderFile).\n" if $Config{'debug'};
push @Headers, path($XtraHeaderFile)->lines ;
}
my %Header = &ParseHeaders(@Headers); my %Header = &ParseHeaders(@Headers);
# check for mandatory headers # check for mandatory headers
@ -424,17 +409,6 @@ sub BuildPosting {
return ''; return '';
} }
# check for illegal headers
my $FoundIllegalHeader = 0;
foreach (qw/Date User-Agent X-Newsreader X-Mailer Injection-Date
Injection-Info NNTP-Posting-Date NNTP-Posting-Host X-Trace/) {
if ($Header{lc($_)}) {
warn "W: $_ header may not be set in '$HeaderFile'.\n";
$FoundIllegalHeader = 1;
}
}
return '' if $FoundIllegalHeader;
# add Date: # add Date:
push @Headers, 'Date: ' . $TD->strftime('%a, %d %b %Y %H:%M:%S %z') . "\n"; push @Headers, 'Date: ' . $TD->strftime('%a, %d %b %Y %H:%M:%S %z') . "\n";
# add missing Message-ID: # add missing Message-ID:
@ -442,16 +416,6 @@ sub BuildPosting {
# add User-Agent # add User-Agent
push @Headers, "User-Agent: $NAME/$VERSION\n"; push @Headers, "User-Agent: $NAME/$VERSION\n";
# check for unencoded 8bit characters in header or body in --debug mode
# taken from tinews.pl
if ($Config{'debug'}) {
print "- Raw 8-bit data in headers.\n" if (grep {/[\x80-\xff]/} @Headers);
# check for MIME headers and warn for 8bit characters in body if missing
if (!defined($Header{'mime-version'}) || !defined($Header{'content-type'})) {
print "- 8bit data in body without MIME-headers.\n" if (grep {/[\x80-\xff]/} @Body);
}
}
# parse pseudo headers from body # parse pseudo headers from body
my ($InRealBody,$LastModified,$PostingFrequency); my ($InRealBody,$LastModified,$PostingFrequency);
foreach (@Body) { foreach (@Body) {
@ -511,7 +475,7 @@ sub BuildPosting {
$_ =~ s/\%p/$$/g; $_ =~ s/\%p/$$/g;
$_ =~ s/\%t/$TimeStamp/g; $_ =~ s/\%t/$TimeStamp/g;
# add random part in test mode # add random part in test mode
if ($OptTest && !$OptOutput) { if ($OptTest) {
my $random = sprintf("%08X", rand(0xFFFFFFFF)); my $random = sprintf("%08X", rand(0xFFFFFFFF));
$_ =~ s/</<test-$random-/; $_ =~ s/</<test-$random-/;
} }
@ -527,7 +491,7 @@ sub BuildPosting {
} }
# add Supersedes: if set # add Supersedes: if set
if (/^Supersedes: /) { if (/^Supersedes: /) {
if ($LastMID && (!$OptTest or $OptOutput)) { if ($LastMID && !$OptTest) {
$_= "Supersedes: $LastMID\n"; $_= "Supersedes: $LastMID\n";
} else { } else {
$_ = ''; $_ = '';
@ -548,8 +512,8 @@ sub BuildPosting {
} }
} }
# not due if Posting-Freqency is "none" or never # not due if Posting-Freqency is "none"
if ($PostingFrequency =~ /none|never/ && !$OptForce) { if ($PostingFrequency =~ /none/) {
print "... is disabled.\n" if $Config{'verbose'} or $Config{'debug'}; print "... is disabled.\n" if $Config{'verbose'} or $Config{'debug'};
return ''; return '';
} }
@ -760,14 +724,6 @@ Use a TLS encrypted connection (via STARTTLS) if available.
You can override this option on the command line by using You can override this option on the command line by using
B<--starttls> or B<--nostarttls> accordingly. B<--starttls> or B<--nostarttls> accordingly.
=item B<xtraheaders> = I<path>
Path to a file with common headers for all project files. Those
headers will be appended to each project.
You can override this option on the command line by using
B<--xtraheaders> = I<path>.
=back =back
=head2 Project files =head2 Project files
@ -781,14 +737,7 @@ files need to be in B<datadir>.
Needs to have at least I<From:>, I<Subject:> and I<Newsgroups:> and Needs to have at least I<From:>, I<Subject:> and I<Newsgroups:> and
can contain all other headers that the posting should have. Headers can contain all other headers that the posting should have. Headers
must conform to RFC 5536 and RFC 5322 and use MIME encoded words for must conform to RFC 5536 and RFC 5322 and use MIME encoded words for
8bit characters. B<yapfaq> won't convert headers, but will warn of 8bit characters. B<yapfaq> won't convert headers.
unencoded 8bit characters in B<--debug> mode. Longer headers should
be folded; B<yapfaq> won't fold headers.
The headers file must not contain any of the following headers:
I<Date:>, I<User-Agent:>, I<X-Newsreader:>, I<X-Mailer:>,
I<Injection-Date:>, I<Injection-Info:>, I<NNTP-Posting-Date:>,
I<NNTP-Posting-Host:> or I<X-Trace:>.
I<Subject:> may contain a I<%LM> placeholder that will be replaced I<Subject:> may contain a I<%LM> placeholder that will be replaced
with the I<Last-modified:> pseudo-header from the text file with the I<Last-modified:> pseudo-header from the text file
@ -850,8 +799,7 @@ I<Last-modified:> and I<Posting-frequency> will be evaluated by
B<yapfaq>. B<yapfaq>.
If your content contains 8bit characters, you'll need suitable MIME If your content contains 8bit characters, you'll need suitable MIME
headers in your headers file. B<yapfaq> will warn of unencoded 8bit headers in your headers file.
characters with missung MIME headers in B<--debug> mode.
B<Example text file with pseudo-headers> B<Example text file with pseudo-headers>
@ -895,7 +843,7 @@ unique I<Message-ID:> (and no I<Supersedes:> header).
Don't post via NNTP, but print to STDOUT. Don't post via NNTP, but print to STDOUT.
Use B<--test> instead to avoid updating project status. Combine with B<--test> to avoid updating project status.
Intended for testing purposes or to pipe in another program like Intended for testing purposes or to pipe in another program like
I<inews> or I<tinews.pl>. If you want to pipe the output to another I<inews> or I<tinews.pl>. If you want to pipe the output to another
@ -913,18 +861,20 @@ Display this man page and exit.
=item B<-s>, B<--simulation> =item B<-s>, B<--simulation>
Simulation mode. Don't post, just show which projects would be due. Simulation mode. Don't post, just show which projects would be due.
Implies B<--test> (without B<--output>) and B<--verbose>. Implies B<--test> and B<--verbose>.
Can be combined with B<--project> to show if just one project is due. Can be combined with B<--project> to show if just one project is due.
=item B<-t>, B<--test> =item B<-t>, B<--test>
Test mode. Don't update project status (time and Message-ID of last Test mode. Don't update project status (time and Message-ID of last
posting); if project is posted to Usenet, dont' add a I<Supersedes:> posting), dont' add a I<Supersedes:> header and modify the
header and modify the I<Message-ID:> with a random part. I<Message-ID:> with a random part.
Implies B<--output> (to redirect output to STDOUT) as long as The text(s) will still be posted if due or forced by B<--force>.
B<--newsgroup> (to override the I<Newsgroups:> header) is not set.
Combine with B<--output> to redirect output to STDOUT or with
B<--newsgroup> to override the I<Newsgroups:> header.
=item B<-V>, B<--version> =item B<-V>, B<--version>
@ -961,16 +911,16 @@ that are not:
Do a test run of your I<example> text and and print it on STDOUT Do a test run of your I<example> text and and print it on STDOUT
(whether ist is due or not): (whether ist is due or not):
yapfaq.pl -t -f -p example yapfaq.pl -t -f -o -p example
(or yapfaq.pl -tfp example) (or yapfaq.pl -tfop example)
The same, with debugging output (add "-d"): The same, with debugging output (add "-d"):
yapfaq.pl -tfdp example yapfaq.pl -tfdop example
Force a test post of your I<example> text to I<alt.test>, even if Force a test post of your I<example> text to I<alt.test>, even if
the text is not due to be posted (same as before, just add the text is not due to be posted (same as before, just replace "-o"
"-n alt-test"): by "-n alt-test"):
yapfaq.pl -t -f -p example -n alt.test yapfaq.pl -t -f -p example -n alt.test

View file

@ -1,16 +0,0 @@
#! /usr/bin/perl -w
#
# Convert pre-1.0 yapfaq status file to new format
#
# Usage: convert.pl < old.txt.cfg > new.cfg
while (<>) {
if (/Lastpost/) {
$_ =~ /Lastpost:\s(\d\d?\.\d\d?\.\d\d\d\d)/;
print "Last-Posted: $1\n";
}
if (/LastMID/) {
$_ =~ /LastMID:\s(<[^>]+>)/;
print "Last-Message-ID: $1\n";
}
}