html/news.pl


   1 #
   2 # This script requires external perl module News::NNTPClient. You can download
   3 # sources of this module from:
   4 #		http://www.cpan.org/authors/id/RVA/NNTPClient-0.37.tar.gz
   5 #		http://derwan.irssi.pl/perl-modules/NNTPClient-0.37.tar.gz
   6 # Usage:
   7 #	/ARTICLE [-s <server>] [-p <port>] [-P <password> -U <login>] [-l <group> <count>] [-a] [-L <index>] <Message-ID>
   8 # Settings:
   9 #	/SET news_nntp_server [server] (default environment variable 'NNTPSERVER' is used (or news.tpi.pl if variable not set))
  10 #	/SET news_nntp_port [port] (default is 119)
  11 #	/SET news_show_headers [headers] (default: from newsgroups subject message-id date lines)
  12 #	/SET news_use_news_window [On/Off] (default is On)
  13 #	/SET news_show_signature [On/Off] (default is On)
  14 #	/SET news_use_body_colors [On/Off] (default is On)
  15 #	/SET news_check_count [count] (default is 5)
  16 #	/SET news_use_auth [On/Off] (default is Off)
  17 #	/SET news_auth_user [login]
  18 #	/SET news_auth_password [password]
  19 
  20 use strict;
  21 use Irssi;
  22 use 5.6.0;
  23 use POSIX;
  24 
  25 use vars qw($VERSION %IRSSI);
  26 $VERSION = "0.5.9";
  27 %IRSSI = (
  28 	'authors'	=> 'Marcin Rozycki, Mathieu Doidy',
  29 	'contact'	=> 'derwan@irssi.pl',
  30 	'name'		=> 'news',
  31 	'description'	=> 'News reader, usage:  /article [-s <server>] [-p <port>] [-P <password> -U <login>] [-l <group> <count>] [-a] [-L <index>] <message-id>',
  32 	'url'		=> 'http://derwan.irssi.pl',
  33 	'license'	=> 'GNU GPL v2',
  34 	'changed'	=> 'Fri Feb  6 21:26:57 CET 2004',
  35 );
  36 
  37 use News::NNTPClient;
  38 
  39 my $debug_level = 0;
  40 my $nntp_server = $ENV{'NNTPSERVER'}; $nntp_server = 'news.tpi.pl' unless $nntp_server;
  41 my $nntp_port = '119';
  42 my $default_headers = 'from newsgroups';
  43 my $check_count = 5;
  44 my %pipe_tag = ();
  45 my $news_window_name = 'news';
  46 my @colors = (15, 12, 03, 06, 05, 07, 14);
  47 my @articles = ();
  48 
  49 $| = 1;
  50 
  51 Irssi::command_bind article => sub {
  52 	my $usage = '/article [-s <server>] [-p <port>] [-P <password> -U <login>] [-l <group> <count>] [-a] [-L <index>] <Message-ID>';
  53 
  54 	my $window;
  55 	if (Irssi::settings_get_bool('news_use_news_window')) {
  56 		$window = Irssi::window_find_name($news_window_name);
  57 		if (!$window) {
  58 			Irssi::command('^window new hide');
  59 			Irssi::command('^window name '.$news_window_name);
  60 			$window = Irssi::window_find_name($news_window_name);
  61 		}
  62 	} else {
  63 		$window = Irssi::active_win();
  64 	}
  65 
  66 	my $server = Irssi::settings_get_str('news_nntp_server');
  67 	$server = $nntp_server unless $server;
  68 	my $port = Irssi::settings_get_int('news_nntp_port');
  69 	$port = $nntp_port unless ($port > 0);
  70 	my $count = Irssi::settings_get_int('news_check_count');
  71 	$count = $check_count unless ($count > 0);
  72 
  73 	my ($connection, $artid, $group, $strip, $showall, @article);
  74 	my ($auth, $user, $password);
  75 	my $yes = 0;
  76 
  77 	@_ = split(/ +/, $_[0]);
  78 	while ($_ = shift(@_))
  79 	{
  80 		/^-a$/ and $showall = 1, next;
  81 		/^-s$/ and $server = shift(@_), next;
  82 		/^-p$/ and $port = shift(@_), next;
  83 		/^-P$/ and $password = shift(@_), next;
  84 		/^-U$/ and $user = shift(@_), next;
  85 		/^-l$/ and do {
  86 			$group = shift(@_);
  87 			$window->printformat(MSGLEVEL_CLIENTCRAP, 'news_group_missing', $usage), return unless ($group);
  88 			$_ = shift(@_);
  89 			$count = $_, next if ($_ =~ /^\d+$/ and $_ > 0);
  90 		};
  91 		/^-yes$/i and ++$yes, next;
  92 		/^-L$/ and do {
  93 			$window->printformat(MSGLEVEL_CLIENTCRAP, 'news_no_artids'), return if ($#articles < 0);
  94 			if ($artid = shift(@_)) {
  95 				$window->printformat(MSGLEVEL_CLIENTCRAP, 'news_unknown_argument', $artid, $usage), return if ($artid !~ /^\d+/ or $artid < 0 or $artid > 10);
  96 				$window->printformat(MSGLEVEL_CLIENTCRAP, 'news_unknown_artid', ++$artid), return unless ($articles[--$artid]);
  97 			    $_ = $articles[$artid]->[0];
  98             } else {
  99 				for (my $idx = 0; $idx <= $#articles; $idx++) {
 100 					$window->printformat(MSGLEVEL_CLIENTCRAP, 'news_artid_show',
 101 						($idx + 1), $articles[$idx]->[0], $articles[$idx]->[1], $articles[$idx]->[2]);
 102 				}
 103 			    return;
 104             }
 105 		};
 106 		/^-/ and $window->printformat(MSGLEVEL_CLIENTCRAP, 'news_unknown_argument', $_, $usage), return;
 107 		$artid = ($_ =~ /^<.*>$/) ? $_ : '<'.$_.'>';
 108 		last;
 109 	}
 110 
 111 	$window->printformat(MSGLEVEL_CLIENTCRAP, 'news_server_unknown', $server), return if (!$server or $server !~ /^..*\...*/);
 112 	$window->printformat(MSGLEVEL_CLIENTCRAP, 'news_port_unknown', $port), return if (!$port or $port !~ /^\d+$/ or $port == 0 or $port > 65535);
 113 	$window->printformat(MSGLEVEL_CLIENTCRAP, 'news_missing_argument', $usage), return if (!$group and !$artid);
 114 	$window->printformat(MSGLEVEL_CLIENTCRAP, 'news_article_unknown', $artid), return if (!$group and $artid !~ /^<..*\@..*>$/);
 115 
 116 	my ($rh, $wh);
 117 	pipe($rh, $wh);
 118 
 119 	my $pid = fork();
 120 	unless (defined $pid) {
 121 		close($rh); close($wh);
 122 		$window->printformat(MSGLEVEL_CLIENTCRAP, 'news_cannot_fork');
 123 		return;
 124 
 125 	} elsif ($pid) {
 126 		close ($wh);
 127 		$window->printformat(MSGLEVEL_CLIENTCRAP, 'news_server_connecting', $server, $port, $artid);
 128 		Irssi::pidwait_add($pid);
 129 		$pipe_tag{$rh} = Irssi::input_add(fileno($rh), INPUT_READ, \&news_fork, $rh);
 130 		return;
 131 	}
 132 
 133 	close($rh);
 134 
 135 	$connection = new News::NNTPClient($server, $port, $debug_level);
 136 	print($wh "not_connected $server $port\n"), goto END unless ($connection->{CODE} =~ /^(200|201)$/);
 137 	print($wh "connected ".$connection->{MESG}."\n");
 138 
 139         if ($user && $password or Irssi::settings_get_bool('news_use_auth')) {
 140 		$user = Irssi::settings_get_str('news_auth_user') unless defined $user;
 141 		$password = Irssi::settings_get_str('news_auth_password') unless defined $password;
 142 		$connection->authinfo($user,$password);
 143 	}
 144 	
 145 	
 146 	if ($group) {
 147 		print($wh "listgroup_yes $count\n"), goto END if ($count > 10 and !$yes);
 148 		print($wh "listgroup_request $server $group\n");
 149 		my @list = $connection->listgroup($group);
 150 		print($wh "listgroup_error $server ".$connection->{MESG}."\n"), goto END if ($#list < 0);
 151 
 152 		my $num = $#list;
 153 		print($wh "listgroup_num $group $num $count\n");
 154 		@list = @list[($num - $count) .. $num] if ($num > --$count);
 155 
 156 		N: while ($_ = shift(@list))
 157 		{
 158 			chomp;
 159 			print($wh "space\n");
 160 			foreach my $xhdr ("From", "Subject", "Message-ID")
 161 			{
 162 				my @reply = $connection->xhdr($xhdr, $_);
 163 				chomp $reply[0]; $reply[0] =~ s/^\d+ //;
 164 				goto N unless ($reply[0]);
 165 				if ($xhdr eq "Message-ID") {
 166 					print($wh "memo $reply[0]\,news.pl: listgroup,$group\n");
 167 				} elsif ($xhdr eq "From") {
 168 					$reply[0] = "\002" . $reply[0] . "\002";
 169 				}
 170 				print($wh "listgroup_header $xhdr $reply[0]\n");
 171 			}
 172 		}
 173 		print($wh "space\n");
 174 
 175 	} else {
 176 		my $show_headers = $default_headers .' '. Irssi::settings_get_str('news_show_headers');
 177 		my ($head, $idx, $usecolors, $bodycolor) = (1, 0, Irssi::settings_get_bool('news_use_body_colors'), $colors[0]);
 178 
 179 		print($wh "article_request $server $artid\n");
 180 		foreach ($connection->article($artid))
 181 		{
 182 			unless ($idx++) {
 183 				print($wh "space\n");
 184 				print($wh "memo $artid\,news.pl: read,$server\n");
 185 			}
 186 			chomp; s/\t/        /g;
 187 			/^-- / and do {
 188 				last if (!$showall and !Irssi::settings_get_bool('news_show_signature'));
 189 				$bodycolor = $colors[6], $usecolors = 0 if $usecolors;
 190 			};
 191 			unless ($head) {
 192 				/^$/ and next if (!$showall and $strip++);
 193 				/^..*$/ and $strip = 0;
 194 				if ($usecolors) {
 195 					$_ =~ /^[>| ]+/;
 196 					my $prefix = $&; $prefix =~ s/ //g;
 197 					$bodycolor = ($_ =~ /^[>]+/) ? $colors[(((length($prefix)-1) %5)+1)] : $colors[0];
 198 				}
 199 				print($wh "article_body \003$bodycolor$_\n");
 200 				next;
 201 			}
 202 			/^$/ and print($wh "space\n"), $head = 0, next;
 203 			my ($header, $text) = split(/: /, $_, 2);
 204 			print($wh "article_header $header $text\n") if ($showall or $show_headers =~ /\b$header\b/i);
 205 		}
 206 		print($wh "article_notexist $server $artid\n") unless ($idx);
 207 		print($wh "space\n") unless ($strip);
 208 	}
 209 
 210 	END: print($wh "close\n");
 211 	close($wh);
 212 	POSIX::_exit(1);
 213 };
 214 
 215 sub memo {
 216 	my ($text, $who, $where) = @_;
 217 	G: while ($text =~ /<[A-Za-z0-9\S]+\@[A-Za-z0-9\S]+>/g)
 218 	{
 219 		my $artid = $&;
 220 		foreach my $array (@articles) { goto G if ($artid eq $array->[0]); }
 221 		unshift @articles, [$artid, $who, $where];
 222 	}
 223 	$#articles = 9 if ($#articles > 9);
 224 }
 225 
 226 sub news_fork {
 227 	my $rh = shift;
 228 	while (<$rh>)
 229 	{
 230 		chomp;
 231 		/^close/ and last;
 232 		/^memo / and memo(split(",", $', 3)), next;
 233 		my ($theme, @args) = split / +/, $_, 5;
 234 		my $window = Irssi::window_find_name($news_window_name);
 235 		$window = Irssi::active_win() unless $window;
 236 		$window->printformat(MSGLEVEL_CLIENTCRAP, 'news_' . $theme, @args);
 237 	}
 238 
 239 	Irssi::input_remove($pipe_tag{$rh});
 240 	close($rh);
 241 }
 242 
 243 Irssi::signal_add_last 'message private' => sub { memo($_[1], $_[2], $_[3]); };
 244 Irssi::signal_add_last 'message public' => sub { memo($_[1], $_[2], $_[4]); };
 245 Irssi::signal_add_last 'dcc chat message' => sub { memo($_[1], $_[0]->{nick}, "chat"); };
 246 
 247 Irssi::theme_register([
 248 	'news_server_unknown',		'NNTP %_server unknown%_ or not defined, use: /set news_nntp_server [server], to set it',
 249 	'news_server_bad',		'%_Bad%_ NNTP server {hilight $0} (bad hostname or addres)',
 250 	'news_port_unknown',		'%_NNTP port%_ unknown or not defined, use: /set news_nntp_port [port], to set it',
 251 	'news_missing_argument',	'Missing argument, usage: $0-',
 252 	'news_unknown_argument',	'Unknown argument \'$0\', usage: $1-',
 253 	'news_server_connecting',	'Connecting to {hilight $0} on port {hilight $1}, wait...',
 254 	'news_not_connected',		'%_Cannot connect%_ to NNTP server $0 on port $1',
 255 	'news_connected',		'%_Connected%_; $0-',
 256 	'news_article_unknown',		'Unknown message-id {hilight $0}',
 257 	'news_article_notexist',	'No article {hilight $1} on $0',
 258 	'news_article_request',		'Sending query about article {hilight $1} to $0, wait...',
 259 	'news_article_body',		'$0-',
 260 	'news_article_header',		'%c$0:%n %_$1-%_',
 261 	'news_group_missing',		'Missing argument: newsgroup, usage: $0-',
 262 	'news_listgroup_request',	'Looking for %_new articles%_ in {hilight $1}, wait...',
 263 	'news_listgroup_error',		'Listgroup result: $1-',
 264 	'news_listgroup_num',		'$1 articles in group $0; fetching headers (max in $2 articles), wait...',
 265 	'news_listgroup_header',	'%c$0:%n $1-',
 266 	'news_listgroup_yes',		'Count > 10 ($0). Doing this is not a good idea. Add -YES option to command if you really mean it',
 267 	'news_no_artids',		'Sorry, list of logged message-id\'s is empty :/',
 268 	'news_cannot_fork',		'Cannot fork process',
 269 	'news_artid_show',		'[%_$[!-2]0%_] article %c$1%n [by {hilight $2} ($3-)]',
 270 	'news_unknown_artid',		'Article {hilight $0} not found, type /article -L, to displays list of logged message-id\'s',
 271 	'news_space',				' '
 272 ]);
 273 
 274 # registering settings
 275 Irssi::settings_add_bool('misc', 'news_use_news_window', 1);
 276 Irssi::settings_add_str('misc', 'news_nntp_server', $nntp_server);
 277 Irssi::settings_add_int('misc', 'news_nntp_port', $nntp_port);
 278 Irssi::settings_add_str('misc', 'news_show_headers', $default_headers.' subject message-id date lines content-transfer-encoding');
 279 Irssi::settings_add_bool('misc', 'news_show_signature', 1);
 280 Irssi::settings_add_bool('misc', 'news_use_body_colors', 1);
 281 Irssi::settings_add_bool('misc', 'news_use_auth', 0);
 282 Irssi::settings_add_str('misc', 'news_auth_user', '');
 283 Irssi::settings_add_str('misc', 'news_auth_password', '');
 284 Irssi::settings_add_int('misc', 'news_check_count', $check_count);