#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.6.1).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `#!/bin/sh' line above, then type `sh FILE'.
#
lock_dir=_sh22536
# Made on 2007-01-16 12:20 EST by <jik@jik2.kamens.brookline.ma.us>.
# Source directory was `/home/jik/src/move-newsrc'.
#
# Existing files will *not* be overwritten, unless `-c' is specified.
#
# This shar contains:
# length mode       name
# ------ ---------- ------------------------------------------
#   1655 -r--r--r-- README
#   4302 -r--r--r-- move-newsrc.1
#   2510 -r-xr-xr-x merge-newsrcs.pl
#   4568 -r-xr-xr-x message-id-to-newsrc.pl
#   3739 -r-xr-xr-x newsrc-to-message-id.pl
#   5588 -r--r--r-- nntp.pl
#
MD5SUM=${MD5SUM-md5sum}
f=`${MD5SUM} --version | egrep '^md5sum .*(core|text)utils'`
test -n "${f}" && md5check=true || md5check=false
${md5check} || \
  echo 'Note: not verifying md5sums.  Consider installing GNU coreutils.'
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=FAILED
locale_dir=FAILED
first_param="$1"
for dir in $PATH
do
  if test "$gettext_dir" = FAILED && test -f $dir/gettext \
     && ($dir/gettext --version >/dev/null 2>&1)
  then
    case `$dir/gettext --version 2>&1 | sed 1q` in
      *GNU*) gettext_dir=$dir ;;
    esac
  fi
  if test "$locale_dir" = FAILED && test -f $dir/shar \
     && ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
  then
    locale_dir=`$dir/shar --print-text-domain-dir`
  fi
done
IFS="$save_IFS"
if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED
then
  echo=echo
else
  TEXTDOMAINDIR=$locale_dir
  export TEXTDOMAINDIR
  TEXTDOMAIN=sharutils
  export TEXTDOMAIN
  echo="$gettext_dir/gettext -s"
fi
if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null
then if (echo -n test; echo 1,2,3) | grep n >/dev/null
     then shar_n= shar_c='
'
     else shar_n=-n shar_c= ; fi
else shar_n= shar_c='\c' ; fi
f=shar-touch.$$
st1=200112312359.59
st2=123123592001.59
st2tr=123123592001.5 # old SysV 14-char limit
st3=1231235901

if touch -am -t ${st1} ${f} >/dev/null 2>&1 && \
   test ! -f ${st1} && test -f ${f}; then
  shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'

elif touch -am ${st2} ${f} >/dev/null 2>&1 && \
   test ! -f ${st2} && test ! -f ${st2tr} && test -f ${f}; then
  shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'

elif touch -am ${st3} ${f} >/dev/null 2>&1 && \
   test ! -f ${st3} && test -f ${f}; then
  shar_touch='touch -am $3$4$5$6$2 "$8"'

else
  shar_touch=:
  echo
  ${echo} 'WARNING: not restoring timestamps.  Consider getting and'
  ${echo} 'installing GNU `touch'\'', distributed in GNU File Utilities...'
  echo
fi
rm -f ${st1} ${st2} ${st2tr} ${st3} ${f}
#
if test ! -d ${lock_dir}
then : ; else ${echo} 'lock directory '${lock_dir}' exists'
  exit 1
fi
if mkdir ${lock_dir}
then ${echo} 'x - created lock directory `'${lock_dir}\''.'
else ${echo} 'x - failed to create lock directory `'${lock_dir}\''.'
  exit 1
fi
# ============= README ==============
if test -f 'README' && test "$first_param" != -c; then
  ${echo} 'x -SKIPPING README (file already exists)'
else
${echo} 'x - extracting README (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'README' &&
X  These scripts can be used to transfer a .newsrc file from one NNTP
server to another, preserving (as much as possible) the status
information in the file.
X
X  Newsrc-to-message-id.pl reads file in .newsrc format and converts it
into a file that lists Message-ID's instead of article numbers, by
talking to the NNTP server to figure out the Message-ID's.
X
X  Message-id-to-newsrc.pl does the reverse transformation, presumably
on a different NNTP server.
X
X  Merge-newsrcs.pl isn't directly related to this conversion process,
but I found it useful anyway.  It reads multiple .newsrc files and
merges the lists of read articles for the various newsgroups in the
various files.  I used it to merge my converted UCSC .newsrc back into
my MIT .newsrc from before the summer.
X
X  Nntp.pl is a library file used by newsrc-to-message-id and
message-id-to-nesrc.  It is borrowed from a Perl news package by
ishii@hexard.co.jp, with some modifications by me, and some fixes by
Dave Lawrence <tale@uunet.uu.net>.  I'm sure there are newer NNTP
implementations in CPAN, but I initially wrote this package long ago,
before CPAN existed, and I don't have the time to convert it now.
X
X  You may have to modify the #! line at the top of the scripts.  Also,
you will need to change the setting of @INC near the top of
message-id-to-newsrc.pl and newsrc-to-message-id.pl if you want to put
nntp.pl in a different directory.
X
X  The move-newsrc.1 man page documents newsrc-to-message-id.pl and
message-id-to-newsrc.pl.
X
X  If you have any suggestions or improvements, please let me know.
X
X	Jonathan Kamens
X	jik@kamens.brookline.ma.us
X        Release date / version: 2007-01-16
SHAR_EOF
  (set 20 07 01 16 12 19 20 'README'; eval "$shar_touch") &&
  chmod 0444 'README'
if test $? -ne 0
then ${echo} 'restore of README failed'
fi
  if ${md5check}
  then (
       ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'README: MD5 check failed'
       ) << SHAR_EOF
8412b08ec0fb4614f2d243965f23c108  README
SHAR_EOF
  else
test `LC_ALL=C wc -c < 'README'` -ne 1655 && \
  ${echo} 'restoration warning:  size of README is not 1655'
  fi
fi
# ============= move-newsrc.1 ==============
if test -f 'move-newsrc.1' && test "$first_param" != -c; then
  ${echo} 'x -SKIPPING move-newsrc.1 (file already exists)'
else
${echo} 'x - extracting move-newsrc.1 (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'move-newsrc.1' &&
X.TH MOVE-NEWSRC 1 "October 28, 1992"
X.SH NAME
newsrc-to-message-id.pl, message-id-to-newsrc.pl \- convert .newsrc files to/from a server-independent format
X.SH SYNOPSIS
X.B newsrc-to-message-id.pl
[
X.BI \-server " server"
] [
X.BI \-out " file"
] [
X.B +|\-ticks
] [
X.B +|\-nntp_debug
] [
X.B +|\-buffered
] [
X.B +|\-unsubbed
] [
X.I file ...
]
X.PP
X.B message-id-to-newsrc.pl
[
X.BI \-server " server"
] [
X.BI \-out " file"
] [
X.B +|\-ticks
] [
X.B +|\-nntp_debug
] [
X.B +|\-buffered
] [
X.B +|\-upto
] [
X.I file ...
]
X.SH DESCRIPTION
The
X.I newsrc-to-message-id.pl
script, written in
X.IR perl (1),
converts a
NetNews
X.I .newsrc
file into a format that records messages by Message ID rather than by
message number, so that the information in the new file is independent
of the NNTP server being used to read news.  The
X.I message-id-to-newsrc.pl
script, also written in
X.IR perl ,
converts the server-independent file back into a
X.I .newsrc
file so that it can be used to read News.
X.PP
These arguments are accepted by both scripts:
X.TP
X.BI \-server " server"
Specifies the NNTP server to which to connect.  If not specified, the
NNTPSERVER environment variable is used.  If neither is present, the
program aborts.
X
When running
X.IR newsrc-to-message-id.pl ,
the server specified should be the server to which the 
X.I .newsrc
file being converted corresponds.  When running
X.IR message-id-to-newsrc.pl ,
the server specified should be the server with which the new
X.I .newsrc
file is going to be used.
X.TP
X.BI \-out " file"
Specifies the file to which output should be directed.  If not
specified, output is directed to the standard output.
X.TP
X.B +|\-ticks
Enables or disables the printing of tick marks to the standard error
for each newsgroup processed.  Enabled by default.
X.TP
X.B +|\-nntp_debug
Enables or disables NNTP debugging.  If enabled, all data send to or
received from the NNTP server is printed to the standard error.
Disabled by default.
X.TP
X.B +|\-buffered
Enables or disables buffered output to the output file.  It is useful
to disable buffered output if if
you want to direct output to a file but be able to monitor exactly how
far the script has progressed in writing it.  Enabled by default.
X.PP
The following arguments are accepted only by
X.IR newsrc-to-message-id.pl :
X.TP
X.B +|\-unsubbed
Enables or disables the processing of read articles in unsubscribed
newsgroups.  If disabled, information about articles in unsubscribed
newsgroups is not transferred to the server-independent file.  This
speeds up the conversion process, but throws away data (which most
people will not need, anyway).  Enabled by default, so that no data is
lost, but most people will probably want to disable it.
X.PP
The following arguments are accepted only by
X.IR message-id-to-newsrc.pl :
X.TP
X.B +|\-upto
Enables or disables the marking of all messages up to the first found
message read in processed newsgroups.  For example, if the script is
able to determine that messages 502 and 503 through 520 were read and
this option is enabled, then it will mark messages 1 through 502 and
503 through 520 read in the
X.I .newsrc
file it produces, rather than just marking 502 and 503 through 520.
Disabled by default, so that messages are not missed accidentally, but
most people will probably want to enable it.
X.PP
If input file(s) is/are not specified on the command line, input is taken
from the standard input.  Multiple input files are supported (this is
just the perl <> construct, after all), but it's unlikely that
functionality will be used very often.
X.PP
When switching from one NNTP server to another, users will probably
want to (a) read all new articles in all subscribed newsgroups on the
old server; (b) immediately convert the
X.I .newsrc
for the old server into a server-independent file and then into a
X.I .newsrc
file for the new server; and (c) read news immediately with the new
server in order to manually synchronize any unavoidable errors in the
transition.
X.SH SEE ALSO
perl(1), rn(1), xrn(1), GNU Emacs GNUS info file
X.SH DIAGNOSTICS
Should be self-explanatory.
X.SH BUGS
Some information is bound to be lost in the transfer from one NNTP
server to another.  There is no way to avoid this.  These scripts do
their best to make the transition seamless, but can't always
completely succeed.
SHAR_EOF
  (set 19 99 03 25 06 39 00 'move-newsrc.1'; eval "$shar_touch") &&
  chmod 0444 'move-newsrc.1'
if test $? -ne 0
then ${echo} 'restore of move-newsrc.1 failed'
fi
  if ${md5check}
  then (
       ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'move-newsrc.1: MD5 check failed'
       ) << SHAR_EOF
a95bbdb566b152f12382fc89fb8525bd  move-newsrc.1
SHAR_EOF
  else
test `LC_ALL=C wc -c < 'move-newsrc.1'` -ne 4302 && \
  ${echo} 'restoration warning:  size of move-newsrc.1 is not 4302'
  fi
fi
# ============= merge-newsrcs.pl ==============
if test -f 'merge-newsrcs.pl' && test "$first_param" != -c; then
  ${echo} 'x -SKIPPING merge-newsrcs.pl (file already exists)'
else
${echo} 'x - extracting merge-newsrcs.pl (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'merge-newsrcs.pl' &&
#!/usr/bin/perl -w
X
# "merge-newsrcs.pl"
# 
# Copyright (c) 1991,2002 by Jonathan Kamens (jik@kamens.brookline.ma.us).
# 
# This file may be freely redistributed as long as this entire
# comment (up to the first blank line below) stays on it, and as long
# as you don't try to make any money distributing it.
# 
# Furthermore, if you make any changes to it and then redistribute
# it, please mark in some ways the changes you have made my version,
# and, if possible, forward the changes back to me.
# 
# $Id: merge-newsrcs.pl,v 1.15 2007/01/16 17:17:34 jik Exp $
X
# This program reads .newsrc files and merges the lists of read
# articles in each newsgroup in each file.
# 
# If a newsgroup is subscribed in one file and unsubscribed in
# another, the subscription wins out.
X
%assoc = ();
%assocsub = ();
@ordered = ();
$ticks = 1;
X
$usage = "Usage: $0 [ +/-ticks ] [ -- ] [ file [ ... ] ]\n";
X
while (@ARGV && ($_ = $ARGV[0]) && /^[+-]/) {
X    shift;
X    if (/^([+-])ticks$/) {
X	$ticks = (($1 eq "+") ? 1 : 0);
X	next;
X    }
X    if (/^--$/) {
X	last;
X    }
X    die "Unknown argument \"$_\".\n$usage";
}
X
while (<>) {
X    if ($ticks) {
X	if (++$counter % 10 == 0) {
X	    print STDERR $counter;
X	}
X	else {
X	    print STDERR ".";
X	}
X    }
X    next if (! /^(.*)([:!]) *(.*)$/);
X    chop;
X    if (! defined($assoc{$1})) {
X	$assoc{$1} = $3;
X	$assocsub{$1} = $2;
X	push(@ordered, $1);
X	next;
X    }
X    elsif ($3 ne "") {
X	$assocsub{$1} = $2 if ($2 eq ":"); # subscribed wins over unsubscribed
X	$assoc{$1} = &merge($assoc{$1}, $3);
X    }
}
X
while ($group = shift @ordered) {
X    if ($assoc{$group} ne "") {
X	printf "$group$assocsub{$group} $assoc{$group}\n";
X    }
X    else {
X	printf "$group$assocsub{$group}\n";
X    }
}
X
sub merge {
X    local(@ranges, $range, $merged, $last, $new, $newer);
X    $merged = "";
X
X    @ranges = split(/,/, $_[0]);
X    push(@ranges, split(/,/, $_[1]));
X
X    foreach $range (@ranges) {
X	if ($range =~ /-/) {
X	    $range = sprintf("%7d-%7d", $`, $');
X	}
X	else {
X	    $range = sprintf("%7d-%7d", $range, $range);
X	}
X    }
X
X    @ranges = sort @ranges;
X
X    $merged .= shift @ranges;
X
X    while ($range = shift @ranges) {
X	($merged =~ /.......$/) && ($last = $&);
X	($range =~ /-/) && (($new, $newer) = ($`, $'));
X	if ($new <= $last + 1) {
X	    if ($newer > $last) {
X		$merged =~ s/.......$//;
X		$range =~ s/^........//;
X		$merged = $merged . $range;
X	    }
X	}
X	else {
X	    $merged = $merged . "," . $range;
X	}
X    }
X
X    $merged =~ s/(.......)-\1/$1/g;
X    $merged =~ s/ //g;
X    
X    $merged;
}
SHAR_EOF
  (set 20 07 01 16 12 17 34 'merge-newsrcs.pl'; eval "$shar_touch") &&
  chmod 0555 'merge-newsrcs.pl'
if test $? -ne 0
then ${echo} 'restore of merge-newsrcs.pl failed'
fi
  if ${md5check}
  then (
       ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'merge-newsrcs.pl: MD5 check failed'
       ) << SHAR_EOF
bef31ef5d66455d692708a709a01c0b4  merge-newsrcs.pl
SHAR_EOF
  else
test `LC_ALL=C wc -c < 'merge-newsrcs.pl'` -ne 2510 && \
  ${echo} 'restoration warning:  size of merge-newsrcs.pl is not 2510'
  fi
fi
# ============= message-id-to-newsrc.pl ==============
if test -f 'message-id-to-newsrc.pl' && test "$first_param" != -c; then
  ${echo} 'x -SKIPPING message-id-to-newsrc.pl (file already exists)'
else
${echo} 'x - extracting message-id-to-newsrc.pl (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'message-id-to-newsrc.pl' &&
#!/usr/bin/perl -w
X
# "message-id-to-newsrc.pl"
# 
# Copyright (c) 1991,2002 by Jonathan Kamens (jik@kamens.brookline.ma.us).
# 
# This file may be freely redistributed as long as this entire
# comment (up to the first blank line below) stays on it, and as long
# as you don't try to make any money distributing it.
# 
# Furthermore, if you make any changes to it and then redistribute
# it, please mark in some ways the changes you have made my version,
# and, if possible, forward the changes back to me.
# 
# $Id: message-id-to-newsrc.pl,v 1.18 2002/04/19 16:22:47 jik Exp $
X
# This script reads the output of the 'newsrc-to-message-id.pl'
# script and turns it back into a .newsrc file.
# 
# The server to use to convert Message-ID's back into article numbers
# can be specified using $NNTPSERVER or the '-server' command line
# flag.
X
# $opt_D = 1;
# $find_debug = 1;
X
# Defaults
X
$opt_D = 0;
$ticks = 1;
$unbuffered = 0;
undef $outfile;
$server = $ENV{"NNTPSERVER"};
$upto = 0;
X
push(@INC, "$ENV{'HOME'}/lib/perl");
X
require 'nntp.pl';
X
$usage = "Usage: $0 [ -server server ] [ -out outfile ] [ +/-buffered ]
X	[ +/-ticks ] [ +/-nntp_debug ] [ +/-upto ] [ -- ] [ file [ ... ] ]\n";
X
while (@ARGV && ($_ = $ARGV[0]) && /^[-+]/) {
X    shift;
X    if (/^-server$/) {
X	die "Missing argument to \"$_\".\n" if (@ARGV == 0);
X	$server = shift;
X	next;
X    }
X    if (/^-out$/) {
X	die "Missing argument to \"$_\".\n" if (@ARGV == 0);
X	$outfile = shift;
X	next;
X    }
X    if (/^(\+|-)buffered$/) {
X	$unbuffered = ($1 eq "+") ? 0 : 1;
X	next;
X    }
X    if (/^(\+|-)ticks$/) {
X	$ticks = ($1 eq "+") ? 1 : 0;
X	next;
X    }
X    if (/^(\+|-)nntp_debug/) {
X	$opt_D = ($1 eq "+") ? 1 : 0;
X	next;
X    }
X    if (/^(\+|-)upto/) {
X	$upto = ($1 eq "+") ? 1 : 0;
X	next;
X    }
X    if (/^--$/) {
X	last;
X    }
X    die "Unknown argument \"$_\".\n$usage";
}
X
if ($outfile) {
X    close(STDOUT);
X    open(STDOUT, ">$outfile") || die "Opening $outfile for write: $!.\n";
X    select(STDOUT);
}
X
if ($unbuffered) {
X    $| = 1;
}
X
die "No NNTP server specified!\n$usage" if (! $server);
X
&news_open($server);
X
%byid = ();
$newsgroup = undef;
$subbed = undef;
@articles = ();
@stats = ();
$in_xhdr = 0;
X
while (<>) {
X    if (/^(.*)([:!])$/) {
X
X	# This is a new group.
X	# If there's an old current group, deal with it.
X
X	&output() if $newsgroup;
X	if ($in_xhdr) {
X	    while ((($xhdr_tag, $xhdr_val) = &news_xhdr_next()) == 2) {
X		# Empty.
X	    }
X	}
X	undef $in_xhdr;
X	$newsgroup = $1;
X	$subbed = $2;
X	($newsgroup_regex = $newsgroup) =~ s/(\W)/\\$1/g;
X	@articles = ();
X	%byid = ();
X	@stats = &news_select_ng($newsgroup);
X	if (@stats != 3) {
X	    print STDERR "\nBogus newsgroup \"$newsgroup\" on server \"$server\"\n";
X	    $subbed = "!";
X	    @stats = ();
X	}
X
X	next;
X    }
X
X    next if (! @stats);
X
X    chop;
X
X    if (defined($byid{$_})) {
X	print STDERR "Found $_ in table.\n" if ($find_debug);
X	push(@articles, $byid{$_});
X	next;
X    }
X    elsif (! defined($in_xhdr) &&
X	   (&news_xhdr_init('xref', $_)) &&
X	   ((($xhdr_tag, $xhdr_val) = &news_xhdr_next()) == 2)) {
X	&news_xhdr_next();	# Flush the dot at the end.
X	if ($xhdr_val =~ / $newsgroup_regex:([^ ]+)/) {
X	    print STDERR "Found xref in $_.\n" if ($find_debug);
X	    push(@articles, $1);
X	    next;
X	}
X    }
X    else {
X	next if (! ($in_xhdr || 
X		    (! defined($in_xhdr) &&
X		     ++$in_xhdr &&
X		     &news_xhdr_init('message-id', "$stats[0]-$stats[1]"))));
X	print STDERR "Building table to find $_.\n" if ($find_debug);
X	while ((($xhdr_tag, $xhdr_val) = &news_xhdr_next()) == 2) {
X	    $byid{$xhdr_val} = $xhdr_tag;
X	    if ($xhdr_val eq $_) {
X		print STDERR "Found $_ in built table.\n" if ($find_debug);
X		push(@articles, $xhdr_tag);
X		last;
X	    }
X	}
X	$in_xhdr = 0 if (!$xhdr_val || ($xhdr_val ne $_));
X    }
}
X
&output() if $newsgroup;
X
print STDERR "\n" if ($ticks);
X
sub output {
X    print "$newsgroup$subbed ";
X    if (@articles) {
X	local($first, $last, $new);
X	@articles = sort byval @articles;
X	$first = $last = shift @articles;
X	if ($upto) {
X	    $first = 1;
X	}
X	while ($new = shift @articles) {
X	    if ($new > $last + 1) {
X		if ($last > $first) {
X		    print "$first-$last,";
X		}
X		else {
X		    print "$first,";
X		}
X		$first = $last = $new;
X		next;
X	    }
X	    else {
X		$last = $new;
X		next;
X	    }
X	}
X	if ($last > $first) {
X	    print "$first-$last\n";
X	}
X	else {
X	    print "$first\n";
X	}
X    }
X    else {
X	print "\n";
X    }
X    if ($ticks) {
X	if (++$counter % 10 == 0) {
X	    print STDERR $counter;
X	}
X	else {
X	    print STDERR ".";
X	}
X	if ($counter % 50 == 0) {
X	    print STDERR "\n";
X	}
X    }
}
X    
sub byval { $a <=> $b; }
SHAR_EOF
  (set 20 02 04 19 12 22 47 'message-id-to-newsrc.pl'; eval "$shar_touch") &&
  chmod 0555 'message-id-to-newsrc.pl'
if test $? -ne 0
then ${echo} 'restore of message-id-to-newsrc.pl failed'
fi
  if ${md5check}
  then (
       ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'message-id-to-newsrc.pl: MD5 check failed'
       ) << SHAR_EOF
99bdcfd0c0649b7b7112062e5b5d04da  message-id-to-newsrc.pl
SHAR_EOF
  else
test `LC_ALL=C wc -c < 'message-id-to-newsrc.pl'` -ne 4568 && \
  ${echo} 'restoration warning:  size of message-id-to-newsrc.pl is not 4568'
  fi
fi
# ============= newsrc-to-message-id.pl ==============
if test -f 'newsrc-to-message-id.pl' && test "$first_param" != -c; then
  ${echo} 'x -SKIPPING newsrc-to-message-id.pl (file already exists)'
else
${echo} 'x - extracting newsrc-to-message-id.pl (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'newsrc-to-message-id.pl' &&
#!/usr/bin/perl -w
X
# "newsrc-to-message-id.pl"
# 
# Copyright (c) 1991 by Jonathan Kamens (jik@kamens.brookline.ma.us).
# 
# This file may be freely redistributed as long as this entire
# comment (up to the first blank line below) stays on it, and as long
# as you don't try to make any money distributing it.
# 
# Furthermore, if you make any changes to it and then redistribute
# it, please mark in some ways the changes you have made my version,
# and, if possible, forward the changes back to me.
# 
# $Id: newsrc-to-message-id.pl,v 1.18 2002/04/19 16:22:08 jik Exp $
X
# This script reads a file/files in .newsrc format (or stdin if no
# file is specified).  The output consists of the list of newsgroups
# with ! or : after them to indicate whether they are subscribed or
# not, and then on subsequent lines, the Message-ID's of read messages
# on the specified (either by $NNTPSERVER) or by the command line flag
# '-server') NNTP server.
# 
# This output can then be fed into the 'message-id-to-newsrc.pl'
# script to turn it back into a .newsrc for another NNTP server.
X
# $max_xhdr = 500;
X
push(@INC, "$ENV{'HOME'}/lib/perl");
X
require 'nntp.pl';
X
# Defaults
X
$opt_D = 0;
$ticks = 1;
$unbuffered = 0;
$skip_unsubbed = 0;
$server = $ENV{"NNTPSERVER"};
undef $outfile;
X
$usage = "Usage: $0 [ -server server ] [ -out outputfile ] [ +/-ticks ]
X	[ +/-nntp_debug ] [ +/-buffered ] [ +/-unsubbed ] [ -- ]
X	[ file [ ... ] ]\n";
X
while (@ARGV && ($_ = $ARGV[0]) && /^[-+]/) {
X    shift;
X    if (/^-server$/) {
X	die "Missing argument to \"$_\".\n" if (@ARGV == 0);
X	$server = shift;
X	next;
X    }
X    if (/^-out$/) {
X	die "Missing argument to \"$_\".\n" if (@ARGV == 0);
X	$outfile = shift;
X	next;
X    }
X    elsif (/^(\+|-)ticks$/) {
X	$ticks = ($1 eq "+") ? 1 : 0;
X	next;
X    }
X    elsif (/^(\+|-)nntp_debug$/) {
X	$opt_D = ($1 eq "+") ? 1 : 0;
X	next;
X    }
X    elsif (/^(\+|-)buffered$/) {
X	$unbuffered = ($1 eq "+") ? 0 : 1;
X	next;
X    }
X    elsif (/^(\+|-)unsubbed$/) {
X	$skip_unsubbed = ($1 eq "+") ? 0 : 1;
X	next;
X    }
X    if (/^--$/) {
X	last;
X    }
X    die "Unknown argument \"$_\".\n$usage";
}
X	
die "No NNTP server specified!\n$usage" if (! $server);
X
&news_open($server);
X
if ($outfile) {
X    close(STDOUT);
X    open(STDOUT, ">$outfile") || die "Opening $outfile for write: $!.\n";
X    select(STDOUT);
}
X
if ($unbuffered) {
X    $| = 1;
}
X
while (<>) {
X    if (/^(.*)([:!]) *(.*)$/) {
X	($group, $sub) = ($1, $2);
X	@ranges = split(/,/, $3);
X
X	print "$group$sub\n";
X
X	if ((@ranges > 0) && (($sub eq ":") || (! $skip_unsubbed))) {
X	    @group = &news_select_ng($group);
X
X	    if (@group != 3) {
X		print STDERR "Bogus group \"$group\"?\n";
X	    }
X	    else {
X		my($ng_first, $ng_last, $ng_num) = @group;
X
X		foreach $range (@ranges) {
X		    if ($range =~ /^([0-9]+)-([0-9]+)$/) {
X			$start = $1;
X			$end = $2;
X		    }
X		    else {
X			$start = $end = $range;
X		    }
X		    if ($start < $ng_first) {
X			$start = $ng_first;
X		    }
X		    if ($end > $ng_last) {
X			$end = $ng_last;
X		    }
X		    if ($end && ($start <= $end)) {
X			&print_hdrs($start, $end);
X		    }
X		}
X	    }
X	}
X    }
X    if ($ticks) {
X	if (++$counter % 10 == 0) {
X	    print STDERR $counter;
X	}
X	else {
X	    print STDERR ".";
X	}
X	if ($counter % 50 == 0) {
X	    print STDERR "\n";
X	}
X    }
}
X
print STDERR "\n" if ($ticks);
X
sub print_hdrs {
X    local($first, $last) = @_;
X    local($number, $id);
X    local($span) = $max_xhdr ? $max_xhdr : ($last - $first + 1);
X
X    while ($first <= $last) {
X	$range = sprintf("%d-%d",
X			 $first,
X			 ($first + $span - 1 <= $last) ? 
X			 $first + $span - 1 : $last);
X	last if (! &news_xhdr_init('message-id', $range));
X	$first += $span;
X
X	while ((($number, $id) = &news_xhdr_next()) == 2) {
X	    print "$id\n";
X	}
X    }
}
X
&news_close();
SHAR_EOF
  (set 20 02 04 19 12 22 08 'newsrc-to-message-id.pl'; eval "$shar_touch") &&
  chmod 0555 'newsrc-to-message-id.pl'
if test $? -ne 0
then ${echo} 'restore of newsrc-to-message-id.pl failed'
fi
  if ${md5check}
  then (
       ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'newsrc-to-message-id.pl: MD5 check failed'
       ) << SHAR_EOF
0175bd258852bde9aad83d0b52f4866f  newsrc-to-message-id.pl
SHAR_EOF
  else
test `LC_ALL=C wc -c < 'newsrc-to-message-id.pl'` -ne 3739 && \
  ${echo} 'restoration warning:  size of newsrc-to-message-id.pl is not 3739'
  fi
fi
# ============= nntp.pl ==============
if test -f 'nntp.pl' && test "$first_param" != -c; then
  ${echo} 'x -SKIPPING nntp.pl (file already exists)'
else
${echo} 'x - extracting nntp.pl (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'nntp.pl' &&
#
# nntp.pl
#
# No main program is in this file.
#
# ishii@hexard.co.jp
#
# $Id: nntp.pl,v 1.14 2002/04/19 13:56:44 jik Exp $
#
X
package nntp;
X
# load socket package
use Socket;
X
# PRIVATE: news_command( $command ) -> returned_string
sub news_command {
X    local( $r );
X    print NEWS ($_[0]."\r\n");
X    print STDERR ">".$_[0]."\n" if $main'opt_D;
X    $r = <NEWS>;
X    print STDERR "<".$r if $main'opt_D;
X	if ($r !~ /^[23]/){
X		($retcode, $reason) = split( /[ \t]+/, $r, 2 );
#		print STDERR @_[0].":".$reason."\n";
X	}
X    return $r;
}
X
# PUBLIC: news_open( $server_name )
sub main'news_open {
X    local( $server ) = $_[0];
X    local( $name, $aliases, $proto, $port );
X    local( $type, $len, $thataddr );
X    local( $that );
X    local( $r );
X
#
# create socket sturcture
#
X    ($name, $aliases, $proto) = getprotobyname( "tcp" );
X    ($name, $aliases, $port) = getservbyname( "nntp", "tcp" );
X    ($name, $aliases, $type, $len, $thataddr) = gethostbyname( $server );
X    $that = sockaddr_in($port, $thataddr);
#
# connect with nntp server
#
X    socket( NEWS, PF_INET, SOCK_STREAM, $proto ) ||
X	die "socket: $!\n";
X    connect( NEWS, $that ) || die "connect: $!\n";
X    select( NEWS ); $| = 1; select( STDOUT );
X    $r = <NEWS>;
X    print STDERR "<".$r if $main'opt_D;
X    chop( $r );
X    if ($r !~ /^20[01]/){
X	die "Sorry, your NNTP connection request was rejected.\n";
X    }
X    $r = &news_command("MODE READER"); 
X    if ($r !~ /^(20[01]|500)/){
X        die "Sorry, the mode reader command bombed horribly.\n";
X    }
X    1;
}
X
# PUBLIC: news_select_ng( $newsgroup_name ) -> (first, last, num)
sub main'news_select_ng {
X    local( $ng ) = $_[0];
X    my( $cc, $num, $first, $last );
X    ($cc, $num, $first, $last) = split( /[ \t]+/,
X				       &news_command( "GROUP ".$ng ) );
X    if (($cc !~ /^[23]/)){
X	return undef;
X    }
X    return ( $first, $last, $num );
}
X
# PUBLIC: news_jump( $article_no ) -> article_no
sub main'news_jump {
X    local( $article ) = $_[0];
X    local( $cc );
X    ($cc, $article) = split( /[ \t]+/, &news_command( "STAT ".$article ) );
X    return $article;
}
X
# PUBLIC: news_previous() -> article_no
sub main'news_previous {
X    local( $cc, $article );
X    $cc = &news_command( "LAST" );
X    if ($cc !~ /^[23]/){ return -1; }
X    ($cc, $article) = split( /[ \t]+/, $cc );
X    return $article;
}
X
# PUBLIC: news_next() -> article_no
sub main'news_next {
X    local( $cc, $article );
X    $cc = &news_command( "NEXT" );
X    if ($cc !~ /^[23]/){ return -1; }
X    ($cc, $article) = split( /[ \t]+/, $cc );
X    return $article;
}
X
# PUBLIC: news_header_open()
sub main'news_header_open {
X    local($r) = &news_command( "HEAD" );
X    if ($r !~ /^[23]/){
X	($retcode, $reason) = split( /[ \t]+/, $r, 2 );
#	print STDERR $retcode.":".$reason."\n";
X	return 0;
X    }
X    $news_stat = 1;
X    return 1;
}
X
# PUBLIC: news_header_next()
sub main'news_header_next {
X    local($_);
X    if (! ($_ = <NEWS>)) {
X	$news_stat = 0;
X	return 0;
X    }
X    print STDERR "<".$_ if $main'opt_D;
X    chop; chop;
X    if ($_ eq "."){ $news_stat = 0; return 0; }
X    return 1;
}
X
# PUBLIC: news_header_close()
sub main'news_header_close {
X    if ($news_stat){
X	while (&main'news_header_next){
X	}
X	$news_stat = 0;
X    }
}
X
# PUBLIC: news_get_header()
sub main'news_get_header {
X    local($_);
X    &main'news_header_open;
X    local(%current);
X    while (&main'news_header_next){
X	($key, $value) = split( /:\s*/, $_, 2 );
X	$value =~ s/^[ \t]+//;
X	$current{$key} = $value;
X    }
X    &main'news_header_close;
X    return %current;
}
X
# PUBLIC: news_body_open()
sub main'news_body_open {
X    local($r) = &news_command( "BODY" );
X    if ($r !~ /^[23]/){
X	($retcode, $reason) = split( /[ \t]+/, $r, 2 );
#	print STDERR @_[0].":".$reason."\n";
X	return 0;
X    }
X    $news_stat = 2;
X    return 1;
}
X
# PUBLIC: news_body_next()
sub main'news_body_next {
X    local($_);
X    if (! ($_ = <NEWS>)) {
X	$news_stat = 0;
X	return 0;
X    }
X    print STDERR "<".$_ if $main'opt_D;
X    chop; chop;
X    if ($_ eq "."){ $news_stat = 0; return 0; }
X    return "$_\n";
}
X
# PUBLIC: news_body_close()
sub main'news_body_close {
X    if ($news_stat){
X	while (&main'news_body_next){
X	}
X	$news_stat = 0;
X    }
}
X
X
sub main'news_article_open {
X    if (@_ > 0) {
X	local($r) = &news_command("ARTICLE $_[0]");
X    }
X    else {
X	local($r) = &news_command("BODY");
X    }
X    if ($r !~ /^[23]/){
X	($retcode, $reason) = split( /[ \t]+/, $r, 2 );
#	print STDERR @_[0].":".$reason."\n";
X	return 0;
X    }
X    $news_stat = 2;
X    return 1;
}
X
sub main'news_article_next {
X    &main'news_body_next();
}
X
sub main'news_article_close {
X    &main'news_body_close();
}
X
X
sub main'news_xhdr_init {
X    local($r) = &news_command("XHDR $_[0] $_[1]");
X    if ($r !~ /^[23]/) {
X	($retcode, $reason) = split( /[ \t]+/, $r, 2 );
X	undef;
X    }
X    else {
X	$news_stat = 2;
X	1;
X    }
}
X
sub main'news_xhdr_next {
X    local(@F);
X    local($_);
X    while (1) {
X	if (! ($_ = <NEWS>)) {
X	    $news_stat = 0;
X	    return 0;
X	}
X	print STDERR "<$_" if $main'opt_D;
X	chop; chop;
X	if ($_ eq "."){ $news_stat = 0; return undef; }
X	@F = split(' ', $_, 2);
X	last if ($F[1] ne "(none)");
X    }
X    @F;
}
X
sub main'news_close {
X    &news_command("QUIT");
X    close(NEWS);
}
X
sub main'news_post {
X    local($art) = @_;
X    local($r) = &news_command("POST");
X    if ($r !~ /^[23]/) {
X	($retcode, $reason) = split(' ', $r, 2);
X	return undef;
X    }
X    $art =~ s/(^|[^\r])\n/$1\r\n/g;
X    $art =~ s/(^|\n)\.(\r|$)/$1..$2/g;
X    print NEWS $art;
X
X    $r = &news_command(".");
X    if ($r !~ /^[23]/) {
X	($retcode, $reason) = split(' ', $r, 2);
X	return undef;
X    }
X
X    1;
}
X
1;
SHAR_EOF
  (set 20 02 04 19 09 56 44 'nntp.pl'; eval "$shar_touch") &&
  chmod 0444 'nntp.pl'
if test $? -ne 0
then ${echo} 'restore of nntp.pl failed'
fi
  if ${md5check}
  then (
       ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'nntp.pl: MD5 check failed'
       ) << SHAR_EOF
a03f9c336b83471856e483b594cdf121  nntp.pl
SHAR_EOF
  else
test `LC_ALL=C wc -c < 'nntp.pl'` -ne 5588 && \
  ${echo} 'restoration warning:  size of nntp.pl is not 5588'
  fi
fi
if rm -fr ${lock_dir}
then ${echo} 'x - removed lock directory `'${lock_dir}\''.'
else ${echo} 'x - failed to remove lock directory `'${lock_dir}\''.'
  exit 1
fi
exit 0
