home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3947 < prev    next >
Internet Message Format  |  1991-08-30  |  15KB

  1. Xref: wupost alt.sources:3947 comp.lang.perl:7366 news.software.readers:525
  2. Newsgroups: alt.sources,comp.lang.perl,news.software.readers
  3. Path: wupost!uunet!zaphod.mps.ohio-state.edu!think.com!mintaka!bloom-beacon!bloom-picayune.mit.edu!athena.mit.edu!jik
  4. From: jik@athena.mit.edu (Jonathan I. Kamens)
  5. Subject: preserving .newsrc on new NNTP server
  6. Message-ID: <1991Aug30.210122.9477@athena.mit.edu>
  7. Followup-To: comp.lang.perl
  8. Sender: news@athena.mit.edu (News system)
  9. Nntp-Posting-Host: pit-manager.mit.edu
  10. Organization: Massachusetts Institute of Technology
  11. Date: Fri, 30 Aug 1991 21:01:22 GMT
  12. Lines: 504
  13.  
  14.   I spent the summer working across the country in California, and it was
  15. faster to read news locally than to get it over the network from MIT, so I
  16. shifted to the NNTP server at UCSC.  I did so by creating a new .newsrc with
  17. the same subscribed and unsubscribed groups as my original, and then catching
  18. up in all the subscribed groups.  That is a suboptimal method.
  19.  
  20.   When I came back here this week, I decided to come up with a better one.  So
  21. I wrote the scripts in the shar appended to the end of this message.  There
  22. are four files, in the shar, nntp.pl, newsrc-to-message-id.pl,
  23. message-id-to-newsrc.pl, and merge-newsrcs.pl.
  24.  
  25.   Nntp.pl is a bare-bones of the NNTP commands I needed to do what I wanted to
  26. do.  It isn't complete by any stretch of the imagination, nor is it
  27. particularly robust, but it does the job.  It depends on Randal Schwartz's
  28. "chat2.pl," which has been posted again recently in this newsgroup and is also
  29. available from perl archive sites.  Please don't ask me to mail it to you --
  30. find it in comp.lang.perl or write to Randal :-).
  31.  
  32.   Newsrc-to-message-id.pl reads a .newsrc file and converts it into a file
  33. that lists Message-ID's instead of article numbers, by talking to the NNTP
  34. server to figure out the Message-ID's.  See the script itself for more
  35. information.
  36.  
  37.   Message-id-to-newsrc.pl does the reverse transformation, presumably on a
  38. different NNTP server.
  39.  
  40.   Merge-newsrcs.pl isn't directly related to this conversion process, but I
  41. found it useful anyway.  It reads multiple .newsrc files and merges the lists
  42. of read articles for the various newsgroups in the various files.  I used it
  43. to merge my converted UCSC .newsrc back into my MIT .newsrc from before the
  44. summer.
  45.  
  46.   These scripts are a one-day hack, and I didn't spent gobs of time designing
  47. before I coded, so there may be faster ways to do some of the things I've
  48. done, and there may be some bugs I didn't notice.  If you find either of these
  49. things, or if you have other suggestions or improvements, please let me know.
  50.  
  51. -- 
  52. Jonathan Kamens                          USnail:
  53. MIT Project Athena                11 Ashford Terrace
  54. jik@Athena.MIT.EDU                Allston, MA  02134
  55. Office: 617-253-8085                  Home: 617-782-0710
  56. -- 
  57. #! /bin/sh
  58. # This is a shell archive.  Remove anything before this line, then unpack
  59. # it by saving it into a file and typing "sh file".  To overwrite existing
  60. # files, type "sh file -c".  You can also feed this as standard input via
  61. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  62. # will see the following message at the end:
  63. #        "End of shell archive."
  64. # Contents:  nntp.pl merge-newsrcs.pl message-id-to-newsrc.pl
  65. #   newsrc-to-message-id.pl
  66. # Wrapped by jik@pit-manager on Fri Aug 30 16:46:20 1991
  67. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  68. if test -f 'nntp.pl' -a "${1}" != "-c" ; then 
  69.   echo shar: Will not clobber existing file \"'nntp.pl'\"
  70. else
  71. echo shar: Extracting \"'nntp.pl'\" \(2724 characters\)
  72. sed "s/^X//" >'nntp.pl' <<'END_OF_FILE'
  73. X# "nntp.pl"
  74. X# 
  75. X# Copyright (c) 1991 by Jonathan Kamens (jik@athena.mit.edu).
  76. X# 
  77. X# This file may be freely redistributed as long as this entire
  78. X# comment (up to the first blank line below) stays on it, and as long
  79. X# as you don't try to make any money distributing it.
  80. X# 
  81. X# Furthermore, if you make any changes to it and then redistribute
  82. X# it, please mark in some ways the changes you have made my version,
  83. X# and, if possible, forward the changes back to me.
  84. X# 
  85. X# $Version$
  86. X
  87. X# This file needs Randal Schwartz's "chat2.pl".  It is by no means a
  88. X# complete implementation of NNTP, nor is it even a reasonable
  89. X# implementation :-).  I just implemented what I needed to make it
  90. X# possible for me to do the actual task I was working on.
  91. X# 
  92. X# If you make improvements or additions to this file, I would
  93. X# appreciate it if you would forward them back to me.
  94. X
  95. Xpackage nntp;
  96. X
  97. Xrequire 'chat2.pl';
  98. X
  99. X
  100. X## $connection = &nntp'open('ucbvax.berkeley.edu')
  101. X
  102. Xsub open {
  103. X    local($server) = $_[0];
  104. X    return undef if (! (local($name, $aliases, $port) = 
  105. X            getservbyname("nntp", "tcp")));
  106. X    local($connection) = &chat'open_port($server, $port);
  107. X    &chat'expect($connection, 60, '^2.*\r\n', '$connection', 
  108. X         '^[45].. (.*)\r\n', 
  109. X         "print STDERR \"Connecting to $server: \$1\n\"; undef", 
  110. X         'TIMEOUT', 'undef',
  111. X         'EOF', 'undef');
  112. X}
  113. X
  114. X
  115. X## ($count, $first, $last) = &nntp'group($connection, 'comp.lang.perl')
  116. X
  117. Xsub group {
  118. X    return () if (! &chat'print($_[0], "GROUP $_[1]\r\n"));
  119. X    &chat'expect($_[0], 60, "^2[^ ]* ([^ ]+) ([^ ]+) ([^ ]+) (.*)\r\n",
  120. X         '($1, $2, $3)', '^[45].. (.*)\r\n', 
  121. X         "print STDERR \"$_[1]: \$1\n\"; ()",
  122. X         'TIMEOUT', '()',
  123. X         'EOF', '()');
  124. X}
  125. X
  126. X
  127. X## %headers = &nntp'xhdr($connection, 'message-id', $valid_xhdr_list)
  128. X## 
  129. X## The $valid_xhdr_list can be a message ID in angle braces, or a
  130. X## single article, or a range of articles separated by a dash.
  131. X## 
  132. X## The keys in the returned array are either the Message ID's or
  133. X## article numbers that were requested, and the values are the header 
  134. X## values.
  135. X
  136. Xsub xhdr {
  137. X    local($connection, $field, $list) = @_;
  138. X    local($line, %headers);
  139. X
  140. X    return () if (! &chat'print($connection, "XHDR $field $list\r\n"));
  141. X
  142. X    if (&chat'expect($connection, 60,
  143. X            '^2.. .*\r\n', '1',
  144. X            '^[45].. .*\r\n', '0',
  145. X            'TIMEOUT', '0',
  146. X            'EOF', '0') == 0) {
  147. X    return ();
  148. X    }
  149. X
  150. X    %headers = ();
  151. X
  152. X    while ($line = &chat'expect($connection, 60,
  153. X                '^(..+)\r\n', '$1',
  154. X                '^([^\\.].*)\r\n', '$1',
  155. X                '^\\.\r\n', 'undef',
  156. X                'TIMEOUT', 'undef',
  157. X                'EOF', 'undef')) {
  158. X    local($key, $value) = split(/ /, $line, 2);
  159. X    $headers{$key} = $value;
  160. X    }
  161. X
  162. X    %headers;
  163. X}
  164. X
  165. X## &nntp'close($connection)
  166. X
  167. Xsub close {
  168. X    &chat'print($_[0], "QUIT\r\n");
  169. X    &chat'close($_[0]);
  170. X}
  171. END_OF_FILE
  172. if test 2724 -ne `wc -c <'nntp.pl'`; then
  173.     echo shar: \"'nntp.pl'\" unpacked with wrong size!
  174. fi
  175. # end of 'nntp.pl'
  176. fi
  177. if test -f 'merge-newsrcs.pl' -a "${1}" != "-c" ; then 
  178.   echo shar: Will not clobber existing file \"'merge-newsrcs.pl'\"
  179. else
  180. echo shar: Extracting \"'merge-newsrcs.pl'\" \(2214 characters\)
  181. sed "s/^X//" >'merge-newsrcs.pl' <<'END_OF_FILE'
  182. X#!/usr/local/bin/perl
  183. X
  184. X# "merge-newsrcs.pl"
  185. X# 
  186. X# Copyright (c) 1991 by Jonathan Kamens (jik@athena.mit.edu).
  187. X# 
  188. X# This file may be freely redistributed as long as this entire
  189. X# comment (up to the first blank line below) stays on it, and as long
  190. X# as you don't try to make any money distributing it.
  191. X# 
  192. X# Furthermore, if you make any changes to it and then redistribute
  193. X# it, please mark in some ways the changes you have made my version,
  194. X# and, if possible, forward the changes back to me.
  195. X# 
  196. X# $Version$
  197. X
  198. X# This program reads .newsrc files and merges the lists of read
  199. X# articles in each newsgroup in each file.
  200. X# 
  201. X# If a newsgroup is subscribed in one file and unsubscribed in
  202. X# another, the subscription wins out.
  203. X
  204. X%assoc = ();
  205. X%assocsub = ();
  206. X@ordered = ();
  207. X$hash = 0;
  208. X
  209. Xwhile ($_ = $ARGV[0], /^-/) {
  210. X    shift;
  211. X    if (/^-hash$/) {
  212. X    $hash++;
  213. X    next;
  214. X    }
  215. X    die "Unknown argument \"$_\".\n";
  216. X}
  217. X
  218. Xwhile (<>) {
  219. X    if ($hash && (($hash++ % 10) == 0)) {
  220. X    local($|) = 1;
  221. X    print STDERR "#";
  222. X    }
  223. X    next if (! /^(.*)([:!]) *(.*)$/);
  224. X    chop;
  225. X    if (! $assoc{$1}) {
  226. X    $assoc{$1} = $3;
  227. X    $assocsub{$1} = $2;
  228. X    push(@ordered, $1);
  229. X    next;
  230. X    }
  231. X    elsif ($3 ne "") {
  232. X    $assocsub{$1} = $2 if ($2 eq ":"); # subscribed wins over unsubscribed
  233. X    $assoc{$1} = &merge($assoc{$1}, $3);
  234. X    }
  235. X}
  236. X
  237. Xwhile ($group = shift @ordered) {
  238. X    if ($assoc{$group} ne "") {
  239. X    printf "$group$assocsub{$group} $assoc{$group}\n";
  240. X    }
  241. X    else {
  242. X    printf "$group$assocsub{$group}\n";
  243. X    }
  244. X}
  245. X
  246. Xsub merge {
  247. X    local(@ranges, $range, $merged, $last, $new, $newer);
  248. X    
  249. X    @ranges = split(/,/, @_[0]);
  250. X    push(@ranges, split(/,/, @_[1]));
  251. X
  252. X    foreach $range (@ranges) {
  253. X    if ($range =~ /-/) {
  254. X        $range = sprintf("%6d-%6d", $`, $');
  255. X    }
  256. X    else {
  257. X        $range = sprintf("%6d-%6d", $range, $range);
  258. X    }
  259. X    }
  260. X
  261. X    $merged = shift @ranges;
  262. X
  263. X    while ($range = shift @ranges) {
  264. X    ($merged =~ /......$/) && ($last = $&);
  265. X    ($range =~ /-/) && (($new, $newer) = ($`, $'));
  266. X    if ($new <= $last + 1) {
  267. X        if ($newer > $last) {
  268. X        $merged =~ s/......$//;
  269. X        $range =~ s/^.......//;
  270. X        $merged = $merged . $range;
  271. X        }
  272. X    }
  273. X    else {
  274. X        $merged = $merged . "," . $range;
  275. X    }
  276. X    }
  277. X
  278. X    $merged =~ s/(......)-\1/$1/g;
  279. X    $merged =~ s/ //g;
  280. X    
  281. X    $merged;
  282. X}
  283. END_OF_FILE
  284. if test 2214 -ne `wc -c <'merge-newsrcs.pl'`; then
  285.     echo shar: \"'merge-newsrcs.pl'\" unpacked with wrong size!
  286. fi
  287. chmod +x 'merge-newsrcs.pl'
  288. # end of 'merge-newsrcs.pl'
  289. fi
  290. if test -f 'message-id-to-newsrc.pl' -a "${1}" != "-c" ; then 
  291.   echo shar: Will not clobber existing file \"'message-id-to-newsrc.pl'\"
  292. else
  293. echo shar: Extracting \"'message-id-to-newsrc.pl'\" \(2961 characters\)
  294. sed "s/^X//" >'message-id-to-newsrc.pl' <<'END_OF_FILE'
  295. X#!/usr/local/bin/perl
  296. X
  297. X# "message-id-to-newsrc.pl"
  298. X# 
  299. X# Copyright (c) 1991 by Jonathan Kamens (jik@athena.mit.edu).
  300. X# 
  301. X# This file may be freely redistributed as long as this entire
  302. X# comment (up to the first blank line below) stays on it, and as long
  303. X# as you don't try to make any money distributing it.
  304. X# 
  305. X# Furthermore, if you make any changes to it and then redistribute
  306. X# it, please mark in some ways the changes you have made my version,
  307. X# and, if possible, forward the changes back to me.
  308. X# 
  309. X# $Version$
  310. X
  311. X# This script reads the output of the 'newsrc-to-message-id.pl'
  312. X# script and turns it back into a .newsrc file.
  313. X# 
  314. X# The server to use to convert Message-ID's back into article numbers
  315. X# can be specified using $NNTPSERVER or the '-server' command line
  316. X# flag.
  317. X
  318. Xrequire 'nntp.pl';
  319. X
  320. Xwhile ($_ = $ARGV[0], /^-/) {
  321. X    shift;
  322. X    if (/^-server$/) {
  323. X    die "Missing argument to \"$_\".\n" if (@ARGV == 0);
  324. X    $ENV{'NNTPSERVER'} = shift(@ARGV);
  325. X    next;
  326. X    }
  327. X    if (/^-flush$/) {
  328. X    $| = 1;
  329. X    next;
  330. X    }
  331. X    die "Unknown argument \"$_\".\n";
  332. X}
  333. X    
  334. Xdie "No NNTP server specified!\n" if (! $ENV{'NNTPSERVER'});
  335. X
  336. X$connection = &nntp'open($ENV{'NNTPSERVER'});
  337. Xdie "Could not connect to news server: $!\n" if (! defined($connection));
  338. X
  339. X%byid = ();
  340. X$newsgroup = undef;
  341. X$subbed = undef;
  342. X@articles = ();
  343. X@stats = ();
  344. X%xref = ();
  345. X
  346. Xwhile (<>) {
  347. X    if (/^(.*)([:!])$/) {
  348. X
  349. X    # This is a new group.
  350. X    # If there's an old current group, deal with it.
  351. X
  352. X    &output() if $newsgroup;
  353. X    $newsgroup = $1;
  354. X    $subbed = $2;
  355. X    @articles = ();
  356. X    %byid = ();
  357. X
  358. X    # Make sure the group is valid
  359. X
  360. X    @stats = &nntp'group($connection, $newsgroup);
  361. X    if (@stats == ()) {
  362. X        # It isn't, at this site, so we undef it.
  363. X        $newsgroup = $subbed = undef;
  364. X    }
  365. X    next;
  366. X    }
  367. X
  368. X    # At this point, what we've got must be a message ID.
  369. X
  370. X    next if (! defined($newsgroup));
  371. X
  372. X    chop;
  373. X
  374. X    if (%byid != ()) {
  375. X    push(@articles, $byid{$_}) if (defined($byid{$_}));
  376. X    next;
  377. X    }
  378. X    elsif (((%xref = &nntp'xhdr($connection, 'xref', $_)) != ()) &&
  379. X       ($xref{$_} =~ / $newsgroup:([^ ]+)/)) {
  380. X    push(@articles, $1);
  381. X    next;
  382. X    }
  383. X    else {
  384. X    local(%bynumber, $number);
  385. X    %bynumber = &nntp'xhdr($connection, 'message-id',
  386. X                   "$stats[1]-$stats[2]");
  387. X    if (%bynumber != ()) {
  388. X        foreach $number (keys(%bynumber)) {
  389. X        $byid{$bynumber{$number}} = $number;
  390. X        }
  391. X    }
  392. X    push(@articles, $byid{$_}) if (defined($byid{$_}));
  393. X    }
  394. X}
  395. X
  396. X&output() if $newsgroup;
  397. X
  398. Xsub output {
  399. X    print "$newsgroup$subbed ";
  400. X    if (@articles) {
  401. X    local($first, $last, $new);
  402. X    @articles = sort byval @articles;
  403. X    $first = $last = shift @articles;
  404. X    while ($new = shift @articles) {
  405. X        if ($new > $last + 1) {
  406. X        if ($last > $first) {
  407. X            print "$first-$last,";
  408. X        }
  409. X        else {
  410. X            print "$first,";
  411. X        }
  412. X        $first = $last = $new;
  413. X        next;
  414. X        }
  415. X        else {
  416. X        $last = $new;
  417. X        next;
  418. X        }
  419. X    }
  420. X    if ($last > $first) {
  421. X        print "$first-$last\n";
  422. X    }
  423. X    else {
  424. X        print "$first\n";
  425. X    }
  426. X    }
  427. X    else {
  428. X    print "\n";
  429. X    }
  430. X}
  431. X    
  432. Xsub byval { $a <=> $b; }
  433. END_OF_FILE
  434. if test 2961 -ne `wc -c <'message-id-to-newsrc.pl'`; then
  435.     echo shar: \"'message-id-to-newsrc.pl'\" unpacked with wrong size!
  436. fi
  437. chmod +x 'message-id-to-newsrc.pl'
  438. # end of 'message-id-to-newsrc.pl'
  439. fi
  440. if test -f 'newsrc-to-message-id.pl' -a "${1}" != "-c" ; then 
  441.   echo shar: Will not clobber existing file \"'newsrc-to-message-id.pl'\"
  442. else
  443. echo shar: Extracting \"'newsrc-to-message-id.pl'\" \(1798 characters\)
  444. sed "s/^X//" >'newsrc-to-message-id.pl' <<'END_OF_FILE'
  445. X#!/usr/local/bin/perl
  446. X
  447. X# "newsrc-to-message-id.pl"
  448. X# 
  449. X# Copyright (c) 1991 by Jonathan Kamens (jik@athena.mit.edu).
  450. X# 
  451. X# This file may be freely redistributed as long as this entire
  452. X# comment (up to the first blank line below) stays on it, and as long
  453. X# as you don't try to make any money distributing it.
  454. X# 
  455. X# Furthermore, if you make any changes to it and then redistribute
  456. X# it, please mark in some ways the changes you have made my version,
  457. X# and, if possible, forward the changes back to me.
  458. X# 
  459. X# $Version$
  460. X
  461. X# This script reads a .newsrc file.  The output consists of the list
  462. X# of newsgroups with ! or : after them to indicate whether they are
  463. X# subscribed or not, and then on subsequent lines, the Message-ID's
  464. X# of read messages on the specified (either by $NNTPSERVER) or by the
  465. X# command line flag '-server') NNTP server.
  466. X# 
  467. X# This output can then be fed into the 'message-id-to-newsrc.pl'
  468. X# script to turn it back into a .newsrc for another NNTP server.
  469. X
  470. Xrequire 'nntp.pl';
  471. X
  472. Xwhile ($_ = $ARGV[0], /^-/) {
  473. X    shift;
  474. X    if (/^-server$/) {
  475. X    die "Missing argument to \"$_\".\n" if (@ARGV == 0);
  476. X    $ENV{'NNTPSERVER'} = shift(@ARGV);
  477. X    next;
  478. X    }
  479. X    die "Unknown argument \"$_\".\n";
  480. X}
  481. X    
  482. Xdie "No NNTP server specified!\n" if (! $ENV{'NNTPSERVER'});
  483. X
  484. X$connection = &nntp'open($ENV{'NNTPSERVER'});
  485. X
  486. Xwhile (<>) {
  487. X    if (/^(.*)([:!]) (.*)$/) {
  488. X    local($group, $sub) = ($1, $2);
  489. X    local(@ranges) = split(/,/, $3);
  490. X    local(@group) = &nntp'group($connection, $group);
  491. X    if (! @group) {
  492. X        print STDERR "Bogus group \"$group\"?\n";
  493. X        next;
  494. X    }
  495. X    print "$group$sub\n";
  496. X    local($range, @ids);
  497. X    foreach $range (@ranges) {
  498. X        if (%ids = &nntp'xhdr($connection, 'message-id', $range)) {
  499. X        local($id);
  500. X        foreach $id (values(%ids)) {
  501. X            print "$id\n";
  502. X        }
  503. X        }
  504. X    }
  505. X    }
  506. X}
  507. X    
  508. X&nntp'close($connection);
  509. END_OF_FILE
  510. if test 1798 -ne `wc -c <'newsrc-to-message-id.pl'`; then
  511.     echo shar: \"'newsrc-to-message-id.pl'\" unpacked with wrong size!
  512. fi
  513. chmod +x 'newsrc-to-message-id.pl'
  514. # end of 'newsrc-to-message-id.pl'
  515. fi
  516. echo shar: End of shell archive.
  517. exit 0
  518.