From b27ec46df2d0c6769ac043732faf05f752dd270b Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Sun, 26 Aug 2018 04:43:25 -0400 Subject: slacktopic.pl: refactor a bit, comment a lot --- slacktopic.pl | 137 ++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 89 insertions(+), 48 deletions(-) diff --git a/slacktopic.pl b/slacktopic.pl index ea450f1..e45d094 100644 --- a/slacktopic.pl +++ b/slacktopic.pl @@ -1,16 +1,20 @@ #!/usr/bin/perl -# irssi script. updates the ##slackware topic any time there's a security -# update in the Slackware ChangeLog. +# slacktopic.pl, by B. Watson . +# Licensed under the WTFPL. See http://www.wtfpl.net/txt/copying/ for details. + +# This is an irssi script that updates the ##slackware topic any time +# there's a new update in the Slackware ChangeLog. Place the script in +# your ~/.irssi/scripts/autorun/ dir. # At script startup, and again every $update_frequency seconds, we # check for updates like so: # - Exec a curl process to get the first part of the ChangeLog -# and extract the date from it. -# - Extract the date from the current /topic. -# - If the /topic has a date, and if it's different, update the -# /topic. Only the date (inside []) is changed, all the other -# stuff is left as-is. +# and extract the new date from it. +# - Extract the old date from the current /topic. +# - If the /topic has an old date, and if it's different from the new +# date, update the /topic (really, get ChanServ to do it). Only the date +# (inside []) is changed, all the other stuff is left as-is. # Assumptions made: # - Every new ChangeLog entry is a security fix. This is almost @@ -26,10 +30,16 @@ # ChanServ's topic command (flag +t in access list). Again, no # harm done, but no topic updates either. -# TODO: send debug/error/status messages to window #1, including -# successful topic updates. Otherwise, I'll never know when this script -# is working (the topic gets changed by ChanServ, I can't tell if that -# was my script doing it or another op doing it manually...) +# Notes: +# - This script would possibly work for other FreeNode channels that track +# a ChangeLog and update the /topic when there's a change. You'd want +# to at least change $update_channel and $update_cmd. If you're not on +# FreeNode, more surgery will be required (if there's a way to change +# the /topic by talking to a 'services' bot, it should be possible). +# - Please don't try to talk me into using LWP and one of the Date:: +# modules in place of executing curl and date. Slackware doesn't ship +# them, plus they're huge and I don't want to keep them loaded in +# irssi all the time. # References: # https://raw.githubusercontent.com/irssi/irssi/master/docs/perl.txt @@ -38,34 +48,33 @@ use warnings; use strict; +# I really wish I could just say 'use Irssi ":all"' here. use Irssi qw/ + channel_find command + command_bind + signal_add_last timeout_add timeout_add_once timeout_remove window_find_name - window_find_item - windows - window_find_refnum - channel_find - command_bind - pidwait_add - signal_add_last /; our $VERSION = "0.1"; our %IRSSI = ( - authors => 'Urchlay', - contact => 'Urchlay on FreeNode ##slackware', + authors => 'B. Watson', + contact => 'yalhcru@gmail.com or Urchlay on FreeNode ##slackware', name => 'slacktopic', description => 'Updates ##slackware /topic whenever there\'s a ' . 'security update in the Slackware ChangeLog.', license => 'WTFPL', - url => 'none', + url => 'http://urchlay.naptime.net/repos/misc-scripts/', ); +### Configurables. + # TODO: make some or all of these config variables into irssi -# settings. Probably overkill, this script is niche-market (probably +# settings? Probably overkill, this script is niche-market (probably # nobody but the author will ever run it...) # Print verbose debugging messages in local irssi window? @@ -76,7 +85,10 @@ our $DEBUG = 1; #our $FAKE = '9999-99-99'; our $FAKE = 0; -# Slackware ChangeLog URL. Version number is hardcoded here. +# Slackware ChangeLog URL. Version number is hardcoded here. Notice it's +# the plain http URL, not https (which doesn't even exist). Actually, +# ftp would also work, but then you got the whole passive vs. active +# firewall mess. our $changelog_url = "http://ftp.slackware.com/pub/slackware/slackware64-14.2/ChangeLog.txt"; @@ -85,12 +97,17 @@ our $changelog_url = our $cmd_timeout = 60; # $update_cmd will write its output here. It'll be in YYYY-MM-DD form, -# which is just what's needed for the /topic. +# which is just what's needed for the /topic. I prefer to keep this +# in ~/.irssi, but it might be better in /tmp (especially if /tmp is +# a tmpfs). our $cmd_outfile = "$ENV{HOME}/.irssi/slack_update.txt"; # We /exec this to get the first line of the ChangeLog. So long as Pat # follows his standard conventions, bytes 0-28 are the first line of -# the ChangeLog. +# the ChangeLog. If you *really* wanted to, you could use wget instead +# of curl, but it doesn't have the --range option... All the business +# with rm and mv is to (try to) avoid ever reading the file when it's +# only partially written. our $curl_args = "--silent --range 0-28 --max-time $cmd_timeout"; our $update_cmd = "rm -f $cmd_outfile ; " . "curl $curl_args $changelog_url |" . @@ -112,11 +129,14 @@ our $server_regex = qr/\.freenode\.(org|net)$/; # talks to ftp.slackware.com, so be polite here. our $update_frequency = 600; -# Bookkeeping stuffs. +### End of configurables. + +### Bookkeeping stuffs. our $timeout_tag; our $child_proc; our $log_window; +### Functions. # Print a message to the status window, if there is one. Otherwise print # it to whatever the active window happens to be. Use this or one of # (err|debug|log)msg for all output, don't use regular print or warn. @@ -134,9 +154,7 @@ sub errmsg { } sub debugmsg { - return unless $DEBUG; - my (undef, $file, $line) = caller; - echo("$file:$line: $_") for @_; + goto &errmsg if $DEBUG; } sub logmsg { @@ -161,17 +179,22 @@ sub init { command_bind("slacktopic", "start_update"); # Check once at script load. - start_update(); + initial_update(); - # Also, automatically run it on a timer. 3rd argument unused here. - timeout_add($update_frequency * 1000, "start_update", 0); + if($update_frequency < 60) { + # Typo protection. Ugh. + errmsg("You didn't really mean to set \$update_frequency to " . + "$update_frequency seconds, did you? Not starting timer. " . + "Fix the script and reload it."); + } else { + # Also, automatically run it on a timer. 3rd argument unused here. + timeout_add($update_frequency * 1000, "start_update", 0); + } } -# Start the update process. -sub start_update { - debugmsg("start_update() called"); - - # Don't do anything if we're not joined to the channel already. +# Return a Channel (always true) if we're joined to the correct channel, +# otherwise return undef (false). +sub get_channel { my $chan = channel_find($update_channel); if(!$chan) { errmsg("not joined to $update_channel"); @@ -185,7 +208,28 @@ sub start_update { return; } - exec_update(); + return $chan; +} + +# First update might need to be delayed. Usually we're being autoloaded at +# irssi startup, and we might get called before autojoining the channel, +# and/or before being logged in to services. Hard-coded 10 sec here. If +# FreeNode or your ISP is being slow, the first update still might +# fail. Oh well. +sub initial_update { + if(get_channel()) { + start_update(); + } else { + timeout_add_once(10 * 1000, "start_update", 0); + } +} + +# Start the update process. +sub start_update { + debugmsg("start_update() called"); + + # Don't do anything if we're not joined to the channel already. + exec_update() if get_channel(); } # Called when an /exec finishes. @@ -205,11 +249,12 @@ sub finish_update { undef $child_proc; } - my $chan = channel_find($update_channel); - if(!$chan) { - debugmsg("not joined to $update_channel"); - return; - } + # ChanServ would let us change the topic even if we weren't in + # the channel, but let's not do that. For one thing, it's a PITA + # to retrieve the old topic, if we're not in the channel. + # No debugmsg here, get_channel() already did it. + my $chan = get_channel(); + return unless $chan; # Get the date of the last update. my $new_date; @@ -217,7 +262,6 @@ sub finish_update { errmsg("$cmd_outfile not found, update command failed"); return; }; - chomp($new_date = <$fh>); close $fh; $new_date ||= ""; @@ -273,10 +317,7 @@ sub exec_update { 1000 * ($cmd_timeout + 2), 'update_timed_out', 0); # last arg is unused - - # is this really necessary? seems it isn't. - #pidwait_add($child_proc->{pid}); } -# main() +### main() init(); -- cgit v1.2.3