aboutsummaryrefslogtreecommitdiff
path: root/slacktopic.pl
blob: 12fe27b87c70855a6a7fa0987533e82f56ff372f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#!/usr/bin/perl

# irssi script. updates the ##slackware topic any time there's a security
# update in Pat's ChangeLog. Depends on an external shell script,
# slack_last_update.sh.

# Plan of action:
# - When this script is loaded, it uses an irssi timer to check
#   for updates periodically.
# - When there's an update, it asks for ops in the channel if not already
#   opped, changes the topic (replacing only the [YYYY-MM-DD] part), then
#   if we weren't already opped, it deops. If we *were* already opped,
#   it doesn't deop (that would be *annoying*).

# Assumptions made:
# - By the time the first check happens ($update_frequency sec after
#   script is loaded, or whenever it's run manually), we will be logged
#   into services.
# - We have enough ChanServ access on the channel to set the topic via
#   ChanServ's topic command (flag +t in access list).

# References:
# https://raw.githubusercontent.com/irssi/irssi/master/docs/perl.txt
# http://wiki.foonetic.net/wiki/ChanServ_Commands

use warnings;
use strict;

use Irssi qw/
	command
	timeout_add
	timeout_add_once
	timeout_remove
	window_find_name
	window_find_item
	windows
	channel_find
	command_bind
/;

our $VERSION = "0.1";
our %IRSSI = (
	authors     => 'Urchlay',
	contact     => 'Urchlay on FreeNode ##slackware',
	name        => 'slacktopic',
	description => 'Updates ##slackware /topic whenever there\'s a ' .
	               'security update in the Slackware ChangeLog.',
	license     => 'WTFPL',
	url         => 'none',
);

# External script. Assume it's in $PATH. Could hardcode the full
# path instead.
our $update_script = "slack_last_update.sh";

# Where the script stores the last update date.
our $update_file = "$ENV{HOME}/.slack_last_update";

# What channel's /topic are we updating?
our $update_channel = "##slackware";

# Seconds between update checks. Every check executes $update_script, which
# talks to ftp.slackware.com, so be polite here.
# TODO: make this an irssi setting?
our $update_frequency = 600;

# Print debugging message in local irssi window?
our $DEBUG = 1;

sub echo {
	command("/echo $_") for @_;
}

sub errmsg {
	my (undef, $file, $line) = caller;
	echo("$file:$line: $_") for @_;
}

sub debugmsg {
	return unless $DEBUG;
	my (undef, $file, $line) = caller;
	echo("$file:$line: $_") for @_;
}

sub init {
	debugmsg("init() called");

	# Command for manual updates.
	command_bind("slacktopic", "update_check");

	# Check once at script load.
	update_check();

	# Also, automatically run it on a timer. 3rd argument unused here.
	timeout_add($update_frequency * 1000, "update_check", 0);
}

sub update_check {
	debugmsg("update_check() called");

	# Don't do anything if we're not joined to the channel already.
	my $chan = channel_find($update_channel);
	debugmsg("not joined to $update_channel") unless $chan;;
	return unless $chan;

	# Get the date of the last update.
	my $new_date = exec_update();
	if(not defined $new_date) {
		errmsg("couldn't get new date, not updating topic");
		return;
	}

	# This should never happen, but...
	if($new_date !~ /^\d\d\d\d-\d\d-\d\d/) {
		errmsg("$update_script result isn't a valid date: $new_date");
		return;
	}

	# Get old topic, replace the date with the new one.
	debugmsg("\$new_date is: $new_date");
	my $t = $chan->{topic};
	$t =~ s,\[\d\d\d\d-\d\d-\d\d\],[$new_date],;

	# Don't do anything if the topic's already correct.
	if($t eq $chan->{topic}) {
		debugmsg("topic already correct, not doing anything");
		return;
	}

	# Ask ChanServ to change the topic for us. We don't need +o in
	# the channel, so long as we're logged in to services and have +t.
	debugmsg("asking ChanServ to update the topic");
	$chan->{server}->send_raw("ChanServ topic $update_channel :$t");
}

sub exec_update {
	debugmsg("exec_update() called");
	open my $fh, "$update_script|" or do {
		errmsg("couldn't execute '$update_script': $!");
		return undef;
	};

	chomp(my $result = <$fh>);
	close $fh;
	my $status = $? >> 8;

	debugmsg("$update_script exit status: $status, result '$result'");
	return $result;
}

# main()
init();