Mark yapfaq.pl executable.
[usenet/yapfaq.git] / yapfaq.pl
old mode 100644 (file)
new mode 100755 (executable)
index 685395a..b5b59b7
--- a/yapfaq.pl
+++ b/yapfaq.pl
@@ -1,18 +1,18 @@
 #! /usr/bin/perl -W
 #
-# yapfaq Version 0.7 by Thomas Hochstein
+# yapfaq Version 0.10 by Thomas Hochstein
 # (Original author: Marc Brockschmidt)
 #
 # This script posts any project described in its config-file. Most people
 # will use it in combination with cron(8).
 # 
 # Copyright (C) 2003 Marc Brockschmidt <marc@marcbrockschmidt.de>
-# Copyright (c) 2010 Thomas Hochstein <thh@inter.net>
+# Copyright (c) 2010-2017 Thomas Hochstein <thh@inter.net>
 #
 # It can be redistributed and/or modified under the same terms under 
 # which Perl itself is published.
 
-our $VERSION = "0.8-prelease";
+our $VERSION = "0.10";
 
 # Please do not change this setting!
 # You may override the default .rc file (.yapfaqrc) by using "-c .rc file"
@@ -36,7 +36,6 @@ use strict;
 use Net::NNTP;
 use Net::Domain qw(hostfqdn);
 use Date::Calc qw(Add_Delta_YM Add_Delta_Days Delta_Days Today);
-use Fcntl ':flock'; # import LOCK_* constants
 use Getopt::Std;
 $Getopt::Std::STANDARD_HELP_VERSION = 1;
 my ($TDY, $TDM, $TDD) = Today(); #TD: Today's date
@@ -46,7 +45,7 @@ my %Options;
 getopts('Vhvpdt:f:c:s:', \%Options);
 # -V: print version / copyright information
 if ($Options{'V'}) {
-  print "$0 v $VERSION\nCopyright (c) 2003 Marc Brockschmidt <marc\@marcbrockschmidt.de>\nCopyright (c) 2010 Thomas Hochstein <thh\@inter.net>\n";
+  print "$0 v $VERSION\nCopyright (c) 2003 Marc Brockschmidt <marc\@marcbrockschmidt.de>\nCopyright (c) 2010-2017 Thomas Hochstein <thh\@inter.net>\n";
   print "This program is free software; you may redistribute it and/or modify it under the same terms as Perl itself.\n";
   exit(0);
 }
@@ -66,7 +65,7 @@ if (-f $RCFile) {
   warn "$0: W: .rc file $RCFile does not exist!\n";
 }
 
-$Options{'s'} = $Config{'Program'} if (!defined($Options{'s'}));
+$Options{'s'} = $Config{'Program'} if (defined($Config{'Program'}) && $Config{'Program'} && !defined($Options{'s'}));
 
 # read configuration (configured FAQs)
 my @Config;
@@ -83,7 +82,7 @@ foreach (@Config) {
   
   my ($ActName,$File,$PFreq,$Expire) =($$_{'name'},$$_{'file'},$$_{'posting-frequency'},$$_{'expires'});
   my ($From,$Subject,$NG,$Fup2)=($$_{'from'},$$_{'subject'},$$_{'ngs'},$$_{'fup2'});
-  my ($MIDF,$ReplyTo,$ExtHea)=($$_{'mid-format'},$$_{'reply-to'},$$_{'extraheader'});
+  my ($MIDF,$ReplyTo,$Charset,$ExtHea)=($$_{'mid-format'},$$_{'reply-to'},$$_{'charset'},$$_{'extraheader'});
   my ($Supersede)            =($$_{'supersede'});
 
   # -f: loop if not FAQ to post
@@ -112,7 +111,7 @@ foreach (@Config) {
     if($Options{'d'}) {
          print "$ActName: Would be posted now (but running in simulation mode [$0 -d]).\n" if $Options{'v'};
        } else {
-      postfaq(\$ActName,\$File,\$From,\$Subject,\$NG,\$Fup2,\$MIDF,\$ExtHea,\$Config{'Sender'},\$TDY,\$TDM,\$TDD,\$ReplyTo,\$SupersedeMID,\$Expire);
+      postfaq(\$ActName,\$File,\$From,\$Subject,\$NG,\$Fup2,\$MIDF,\$Charset,\$ExtHea,\$Config{'Sender'},\$TDY,\$TDM,\$TDD,\$ReplyTo,\$SupersedeMID,\$Expire);
        }
   } elsif($Options{'v'}) {
     print "$ActName: Nothing to do.\n";
@@ -195,7 +194,11 @@ sub readconfig{
     }
     unless(!$$Config[$i]{'mid-format'} || $$Config[$i]{'mid-format'} =~ /^<\S+\@(\S+\.)?\S{2,}\.\S{2,}>/) {
       warn "$0: W: The Message-ID format for your project \"$$Config[$i]{'name'}\" seems to be invalid - set to default.\n";
-      $$Config[$i]{'mid-format'} = '<%n-%d.%m.%y@'.hostfqdn.'>'; # set default if mid-format is invalid
+      $$Config[$i]{'mid-format'} = '<%n-%y-%m-%d@'.hostfqdn.'>'; # set default if mid-format is invalid
+    }
+    unless(defined($$Config[$i]{'charset'})) {
+      warn "$0: W: Your project \"$$Config[$i]{'name'}\" has no encoding defined - set to default (UTF-8).\n";
+      $$Config[$i]{'charset'} = 'UTF-8';
     }
   }
   $Error .= "-" x 25 . 'program terminated' . "-" x 25 . "\n" if $Error;
@@ -239,7 +242,7 @@ sub updatestatus {
 # It reads the data-file $File and then posts the article.
 
 sub postfaq {
-  my ($ActName,$File,$From,$Subject,$NG,$Fup2,$MIDF,$ExtraHeaders,$Sender,$TDY,$TDM,$TDD,$ReplyTo,$Supersedes,$Expire) = @_;
+  my ($ActName,$File,$From,$Subject,$NG,$Fup2,$MIDF,$Charset,$ExtraHeaders,$Sender,$TDY,$TDM,$TDD,$ReplyTo,$Supersedes,$Expire) = @_;
   my (@Header,@Body,$MID,$InRealBody,$LastModified);
 
   print "$$ActName: Preparing to post.\n" if($Options{'v'});
@@ -250,7 +253,7 @@ sub postfaq {
   my $Timestamp = time;
 
   $MID = $$MIDF;
-  $MID = '<%n-%d.%m.%y@'.hostfqdn.'>' if !defined($MID); # set to default if unset
+  $MID = '<%n-%y-%m-%d@'.hostfqdn.'>' if !defined($MID); # set to default if unset
   $MID =~ s/\%n/$$ActName/g;
   $MID =~ s/\%d/$$TDD/g;
   $MID =~ s/\%m/$$TDM/g;
@@ -263,7 +266,7 @@ sub postfaq {
     s/\r//;
     push (@Body, $_), next if $InRealBody;
     $InRealBody++ if /^$/;
-    $LastModified = $1 if /^Last-modified: (\S+)$/i;
+    $LastModified = $1 if /^Last-modified:\s*(\S+)\s*$/i;
     push @Body, $_;
   }
   close FH;
@@ -292,11 +295,21 @@ sub postfaq {
   #Replace %LM by the content of the news.answer-pseudo-header Last-modified:
   if ($LastModified) {
     $$Subject =~ s/\%LM/$LastModified/;
+  } else {
+    $$Subject =~ s/[<\[{\(]?\%LM[>\]}\)]?//;
   }
 
+  # Set Charset
+  my $ContentType = sprintf('text/plain; charset=%s',$Charset);
+
   # Test mode?
   if($Options{'t'} and $Options{'t'} !~ /console/i) {
     $$NG = $Options{'t'};
+    $MID =~ s/@/-$Timestamp-test@/g;
+    $$ExtraHeaders .= "\n" if $$ExtraHeaders;
+    $$ExtraHeaders .= "X-Supersedes: $$Supersedes\n" if $$Supersedes;
+    $$ExtraHeaders .= "X-yapfaq-Remark: This is only a test message.";
+    undef $$Supersedes;
   }
 
   #Now create the complete Header:
@@ -311,7 +324,7 @@ sub postfaq {
   push @Header, "Sender: $$Sender\n" if $$Sender;
   push @Header, "Mime-Version: 1.0\n";
   push @Header, "Reply-To: $$ReplyTo\n" if $$ReplyTo;
-  push @Header, "Content-Type: text/plain; charset=ISO-8859-15\n";
+  push @Header, "Content-Type: $ContentType\n";
   push @Header, "Content-Transfer-Encoding: 8bit\n";
   push @Header, "User-Agent: yapfaq/$VERSION\n";
   if ($$ExtraHeaders) {
@@ -509,12 +522,20 @@ C<%d> for the date the message is posted, C<%m> for the month, C<%y>
 for the year and C<%t> for a time stamp (number of seconds since the
 epoch), respectively.
 
-This setting is optional; the default is '<%n-%d.%m.%y@I<YOURHOST>>'
+This setting is optional; the default is '<%n-%y-%m-%d@I<YOURHOST>>'
 where I<YOURHOST> is the fully qualified domain name (FQDN) of the
 host B<yapfaq> is running on. Obviously that will only work if you
 have defined a reasonable hostname that the hostfqdn() function of
 Net::Domain can return.
 
+=item B<Charset> = I<encoding>  (optional)
+
+The character encoding of your FAQ. This setting is optional, but
+should match the encoding of your FAQ B<File>. Default is set to
+I<UTF-8>.
+
+This setting is copied verbatim to the I<Content-Type> header.
+
 =item B<Supersede> = I<yes>  (optional)
 
 Add Supersedes header to the message containing the Message-ID header
@@ -566,6 +587,10 @@ This setting is optional.
     # Message-ID ("%n" is $Name)
     # MID-Format = '<%n-%d.%m.%y@domain.invalid>'
     
+    # Character Encoding
+    # This setting is optional. Default: UTF-8
+    # Charset = ISO-8859-15
+    
     # Supersede last posting?
     Supersede = yes
     
@@ -696,11 +721,16 @@ update any status information.
 =item B<-t> I<newsgroup(s) | CONSOLE> (test)
 
 Don't post to the newsgroups defined in F<yqpfaq.cfg>, but to the
-newsgroups given after B<-t> as a comma-separated list or print the
-FAQs to STDOUT separated by lines of dashes if the special string
-C<CONSOLE> is given.  This can be used to preview what B<yapfaq> would
-do without embarassing yourself on Usenet.  The status files are not
-updated when this option is given.
+(test) newsgroup(s) given after B<-t> as a comma-separated list or
+print the FAQs to STDOUT separated by lines of dashes if the special
+string C<CONSOLE> is given.  This can be used to preview what
+B<yapfaq> would do without embarassing yourself on Usenet. 
+
+The status files are not updated when this option is given.
+
+When this option is used to post to some other newsgroup(s), a(nother)
+timestamp is added to the Message-ID header and the Supersedes header
+is replaced by a special X-Supersedes header.
 
 You may want to use this with the B<-f> option (see below).
 
@@ -737,6 +767,19 @@ to or load another configuration file defining (an)other FAQ(s).
 
 =back
 
+=head1 INSTALLATION
+
+Just copy the contents of the tarball in some directory and get started.
+
+You can post your first test with
+
+    yapfaq -c .yapfaqrc.sample
+
+or copy F<.yapfaqrc.sample> to F<.yapfaqrc> and F<yapfaq.cfg.sample>
+to F<yapfaq.cfg>, edit those files and get really started!
+
+=back
+
 =head1 EXAMPLES
 
 Post all FAQs that are due for posting:
@@ -807,13 +850,19 @@ the last post of that FAQ.
 
 =head1 BUGS
 
-Many, I'm sure.
+Please report any bugs or feature requests to the author or use the
+bug tracker at L<https://bugs.th-h.de/>!
 
 =head1 SEE ALSO
 
-L<http://th-h.de/download/scripts.php> will have the current
+L<https://th-h.de/net/software/yapfaq/> will have the current
 version of this program.
 
+This program is maintained using the Git version control system. You
+may clone L<git://code.th-h.de/usenet/yapfaq.git> to check out the
+current development tree or browse it on the web via
+L<https://code.th-h.de/?p=usenet/yapfaq.git>.
+
 =head1 AUTHOR
 
 Thomas Hochstein <thh@inter.net>
@@ -825,7 +874,7 @@ Marc Brockschmidt <marc@marcbrockschmidt.de>
 
 Copyright (c) 2003 Marc Brockschmidt <marc@marcbrockschmidt.de>
 
-Copyright (c) 2010 Thomas Hochstein <thh@inter.net>
+Copyright (c) 2010-2017 Thomas Hochstein <thh@inter.net>
 
 This program is free software; you may redistribute it and/or modify it
 under the same terms as Perl itself.
This page took 0.014012 seconds and 4 git commands to generate.