From 90e84e1c774a5e36aaafa7da655c8193218f1f37 Mon Sep 17 00:00:00 2001
From: David Phillips <david@sighup.nz>
Date: Wed, 11 Apr 2018 00:00:06 +1200
Subject: Implement in-chan admin commands with Admin module

Starts to address GitHub issue #11
---
 Plugin/Admin.pm | 163 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 idalius.pl      |   2 +-
 2 files changed, 164 insertions(+), 1 deletion(-)
 create mode 100644 Plugin/Admin.pm

diff --git a/Plugin/Admin.pm b/Plugin/Admin.pm
new file mode 100644
index 0000000..1151fc4
--- /dev/null
+++ b/Plugin/Admin.pm
@@ -0,0 +1,163 @@
+#!/usr/bin/env perl
+
+package Plugin::Admin;
+
+use strict;
+use warnings;
+
+my %config;
+
+sub configure {
+	my $self = $_[0];
+	my $cmdref = $_[1];
+	my $cref = $_[2];
+	%config = %$cref;
+
+	$cmdref->("say", sub { $self->say(@_); } );
+	$cmdref->("action", sub { $self->action(@_); } );
+
+	$cmdref->("nick", sub { $self->nick(@_); } );
+	$cmdref->("join", sub { $self->join(@_); } );
+	$cmdref->("part", sub { $self->part(@_); } );
+	$cmdref->("mode", sub { $self->mode(@_); } );
+	$cmdref->("kick", sub { $self->kick(@_); } );
+	$cmdref->("topic", sub { $self->topic(@_); } );
+	$cmdref->("reconnect", sub { $self->reconnect(@_); } );
+
+	$cmdref->("ignore", sub { $self->ignore(@_); } );
+	$cmdref->("don't ignore", sub { $self->do_not_ignore(@_); } );
+
+	return $self;
+}
+
+sub is_admin {
+	my $who = shift;
+	my $is_admin = grep {$_ eq $who} @{$config{admins}};
+	if (!$is_admin) {
+		# Uhh log this rather than print
+		print "$who isn't an admin, but tried to use a command";
+	}
+	return $is_admin;
+}
+
+sub nick {
+	my ($self, $irc, $logger, $who, $where, $rest, @arguments) = @_;
+
+	return unless is_admin($who);
+	return "Syntax: nick <new nick>" unless @arguments == 1;
+
+	$irc->yield(nick => $arguments[0]);
+}
+
+sub say {
+	my ($self, $irc, $logger, $who, $where, $rest, @arguments) = @_;
+
+	return unless is_admin($who);
+	return "Syntax: say <channel> <msg>" unless @arguments >= 2;
+
+	# Strip nick/channel from message
+	$rest =~ s/^(.*?\s)//;
+
+	$irc->yield(privmsg => $arguments[0] => $rest);
+}
+
+sub action {
+	my ($self, $irc, $logger, $who, $where, $rest, @arguments) = @_;
+
+	return unless is_admin($who);
+	return "Syntax: action <channel> <action text>" unless @arguments >= 2;
+
+	# Strip nick/channel from message
+	$rest =~ s/^(.*?\s)//;
+
+	$irc->yield(ctcp => $arguments[0] => "ACTION $rest");
+}
+
+sub join {
+	my ($self, $irc, $logger, $who, $where, $rest, @arguments) = @_;
+
+	return unless is_admin($who);
+	return "Syntax: join <channel1> [channel2 ...]" unless @arguments >= 1;
+
+	$irc->yield(join => $_) for @arguments;
+}
+
+sub part {
+	my ($self, $irc, $logger, $who, $where, $rest, @arguments) = @_;
+
+	return unless is_admin($who);
+	return "Syntax: part <channel1> [channel2 ...] [partmsg]" unless @arguments >= 1;
+
+	my $nick = (split /!/, $who)[0];
+	my ($chan_str, $reason) = split /\s+(?!#)/, $rest, 2;
+	my @channels = split /\s+/, $chan_str;
+	$reason = "Commanded by $nick" unless $reason;
+	$irc->yield(part => @channels => $reason);
+}
+
+sub mode {
+	my ($self, $irc, $logger, $who, $where, $rest, @arguments) = @_;
+
+	return unless is_admin($who);
+	return "Syntax: mode <everything>" unless @arguments > 0;
+
+	# FIXME should use $where if it's a channel (?)
+	$irc->yield(mode => $rest);
+}
+
+sub kick {
+	my ($self, $irc, $logger, $who, $where, $rest, @arguments) = @_;
+
+	return unless is_admin($who);
+	return "Syntax: kick <channel> <nick> [reason]" unless @arguments >= 2;
+
+	my ($channel, $kickee, undef, $reason) = $rest =~ /^(\S+)\s(\S+)((?:\s)(.*))?$/;
+	if ($channel and $kickee) {
+		my $nick = (split /!/, $who)[0];
+		$reason = "Requested by $nick" unless $reason;
+		$irc->yield(kick => $channel => $kickee => $reason);
+	}
+}
+
+sub topic {
+	my ($self, $irc, $logger, $who, $where, $rest, @arguments) = @_;
+
+	return unless is_admin($who);
+	return "Syntax: topic <new topic>" unless @arguments >= 2;
+
+	# Strip nick/channel from message
+	$rest =~ s/^(.*?\s)//;
+
+	# FIXME use $where if it's a channel
+	$irc->yield(topic => $arguments[0] => $rest);
+}
+
+sub reconnect {
+	my ($self, $irc, $logger, $who, $where, $rest, @arguments) = @_;
+
+	return unless is_admin($who);
+
+	my $reason = $rest;
+	$irc->yield(quit => $reason);
+}
+
+sub ignore {
+	my ($self, $irc, $logger, $who, $where, $rest, @arguments) = @_;
+
+	return unless is_admin($who);
+	return "Syntax: ignore <nick>" unless @arguments == 1;
+
+	$logger->("ERROR: UNIMPLEMENTED FEATURE");
+}
+
+sub do_not_ignore {
+	my ($self, $irc, $logger, $who, $where, $rest, @arguments) = @_;
+
+	return unless is_admin($who);
+	return "Syntax: don't ignore <nick>" unless @arguments == 1;
+
+	$logger->("ERROR: UNIMPLEMENTED FEATURE");
+}
+
+
+1;
diff --git a/idalius.pl b/idalius.pl
index c88ed8e..8f82535 100755
--- a/idalius.pl
+++ b/idalius.pl
@@ -88,7 +88,7 @@ sub run_command {
 	my ($command, $rest) = split /\s+/, $command_string, 2;
 	@arguments = split /\s+/, $rest if $rest;
 	if ($commands{$command}) {
-		return ($commands{$command})->(\&log_info, $who, $where, $rest, @arguments);
+		return ($commands{$command})->($irc, \&log_info, $who, $where, $rest, @arguments);
 	} else {
 		return "No such command \"$command\"";
 	}
-- 
cgit v1.1


From bf8314a0283f7565854fe773c5d1edf8e26c9660 Mon Sep 17 00:00:00 2001
From: David Phillips <david@sighup.nz>
Date: Sun, 29 Jul 2018 22:34:00 +1200
Subject: Implement ignore et al in Admin.pm

---
 Plugin/Admin.pm |  24 +++++++++-
 idalius.pl      | 142 ++++++++------------------------------------------------
 2 files changed, 42 insertions(+), 124 deletions(-)

diff --git a/Plugin/Admin.pm b/Plugin/Admin.pm
index 1151fc4..ad07da2 100644
--- a/Plugin/Admin.pm
+++ b/Plugin/Admin.pm
@@ -26,6 +26,7 @@ sub configure {
 
 	$cmdref->("ignore", sub { $self->ignore(@_); } );
 	$cmdref->("don't ignore", sub { $self->do_not_ignore(@_); } );
+	$cmdref->("who are you ignoring?", sub { $self->dump_ignore(@_); } );
 
 	return $self;
 }
@@ -111,6 +112,7 @@ sub kick {
 	return unless is_admin($who);
 	return "Syntax: kick <channel> <nick> [reason]" unless @arguments >= 2;
 
+	# FIXME should use $where if it's a channel (?)
 	my ($channel, $kickee, undef, $reason) = $rest =~ /^(\S+)\s(\S+)((?:\s)(.*))?$/;
 	if ($channel and $kickee) {
 		my $nick = (split /!/, $who)[0];
@@ -147,7 +149,9 @@ sub ignore {
 	return unless is_admin($who);
 	return "Syntax: ignore <nick>" unless @arguments == 1;
 
-	$logger->("ERROR: UNIMPLEMENTED FEATURE");
+	push @{$config{ignore}}, $arguments[0];
+
+	return "Ignoring $arguments[0]";
 }
 
 sub do_not_ignore {
@@ -156,7 +160,23 @@ sub do_not_ignore {
 	return unless is_admin($who);
 	return "Syntax: don't ignore <nick>" unless @arguments == 1;
 
-	$logger->("ERROR: UNIMPLEMENTED FEATURE");
+	my $target = $arguments[0];
+
+	if (grep { $_ eq $target} @{$config{ignore}}) {
+		@{$config{ignore}} = grep { $_ ne $target } @{$config{ignore}};
+		return "No longer ignoring $target.";
+	} else {
+		return "I wasn't ignoring $target anyway.";
+	}
+}
+
+sub dump_ignore {
+	my ($self, $irc, $logger, $who, $where, $rest, @arguments) = @_;
+
+	return "Syntax: who are you ignoring?" unless @arguments == 0;
+
+	# FIXME special case for empty ignore
+	return "I am ignoring: " . join ", ", @{$config{ignore}};
 }
 
 
diff --git a/idalius.pl b/idalius.pl
index b8fb78a..2dc3ee2 100755
--- a/idalius.pl
+++ b/idalius.pl
@@ -85,13 +85,22 @@ sub register_command {
 sub run_command {
 	my ($command_string, $who, $where) = @_;
 	my @arguments;
-	my ($command, $rest) = split /\s+/, $command_string, 2;
-	@arguments = split /\s+/, $rest if $rest;
-	if ($commands{$command}) {
-		return ($commands{$command})->($irc, \&log_info, $who, $where, $rest, @arguments);
-	} else {
-		return "No such command \"$command\"";
+	my $command_verbatim;
+	my $command;
+
+	for my $c (keys %commands) {
+		if (($command_verbatim) = $command_string =~ m/^(\Q$c\E( |$))/) {
+			$command = $c;
+			last;
+		}
 	}
+
+	return "No such command" unless $command;
+
+	my $rest = (split "\Q$command_verbatim", $command_string, 2)[1];
+	@arguments = split /\s+/, $rest if $rest;
+
+	return ($commands{$command})->($irc, \&log_info, $who, $where, $rest, @arguments);
 }
 
 sub custom_ping {
@@ -210,122 +219,11 @@ sub irc_msg {
 		return;
 	}
 	return unless $is_admin;
-	# FIXME this needs tidying. Some of this can be factored out, surely.
-	if ($what =~ /^nick\s/) {
-		my ($newnick) = $what =~ /^nick\s+(\S+)$/;
-		if ($newnick) {
-			$irc->yield(nick => $newnick);
-			$irc->yield(privmsg => $nick => "Requested.");
-		} else {
-			$irc->yield(privmsg => $nick => "Syntax: nick <nick>");
-		}
-	}
-	if ($what =~ /^ignore\s/) {
-		my ($target) = $what =~ /^ignore\s+(\S+)$/;
-		if ($target) {
-			push @{$config{ignore}}, $target;
-			$irc->yield(privmsg => $nick => "Ignoring $target.");
-		} else {
-			$irc->yield(privmsg => $nick => "Syntax: ignore <nick>");
-		}
-	}
-	if ($what =~ /^don't ignore\s/) {
-		my ($target) = $what =~ /^don't ignore\s+(\S+)$/;
-		if ($target) {
-			if (grep { $_ eq $target} @{$config{ignore}}) {
-				@{$config{ignore}} = grep { $_ ne $target } @{$config{ignore}};
-				$irc->yield(privmsg => $nick => "No longer ignoring $target.");
-			} else {
-				$irc->yield(privmsg => $nick => "I wasn't ignoring $target anyway.");
-			}
-		} else {
-			$irc->yield(privmsg => $nick => "Syntax: don't ignore <nick>");
-		}
-	}
-	if ($what =~ /^part\s/) {
-		my $message;
-		if ($what =~ /^part(\s+(\S+))+$/m) {
-			$what =~ s/^part\s+//;
-			my ($chan_str, $reason) = split /\s+(?!#)/, $what, 2;
-			my @channels = split /\s+/, $chan_str;
-			$reason = "Commanded by $nick" unless $reason;
-			$irc->yield(part => @channels => $reason);
-			$irc->yield(privmsg => $nick => "Requested.");
-		} else {
-			$irc->yield(privmsg => $nick =>
-			            "Syntax: part <channel1> [channel2 ...] [partmsg]");
-		}
-	}
-	if ($what =~ /^join\s/) {
-		if ($what =~ /^join(\s+(\S+))+$/) {
-			$what =~ s/^join\s+//;
-			my @channels = split /\s+/, $what;
-			$irc->yield(join => $_) for @channels;
-			$irc->yield(privmsg => $nick => "Requested.");
-		} else {
-			$irc->yield(privmsg => $nick =>
-			            "Syntax: join <channel1> [channel2 ...]");
-		}
-	}
-	if ($what =~ /^say\s/) {
-		my ($channel, $message) = $what =~ /^say\s+(\S+)\s(.*)$/;
-		if ($channel and $message) {
-			$irc->yield(privmsg => $channel => $message);
-			$irc->yield(privmsg => $nick => "Requested.");
-		} else {
-			$irc->yield(privmsg => $nick => "Syntax: say <channel> <msg>");
-		}
-	}
-	if ($what =~ /^action\s/) {
-		my ($channel, $action) = $what =~ /^action\s+(\S+)\s(.*)$/;
-		if ($channel and $action) {
-			$irc->yield(ctcp => $channel => "ACTION $action");
-			$irc->yield(privmsg => $nick => "Requested.");
-		} else {
-			$irc->yield(privmsg => $nick => "Syntax: action <channel> <action text>");
-		}
-	}
-	if ($what =~ /^topic\s/) {
-		my ($channel, $topic) = $what =~ /^topic\s+(\S+)\s(.*)?$/;
-		if ($channel) {
-			$topic = "" unless $topic;
-			$irc->yield(topic => $channel => $topic);
-			$irc->yield(privmsg => $nick => "Requested.");
-		} else {
-			$irc->yield(privmsg => $nick => "Syntax: topic <channel> <topic>");
-		}
-	}
-	if ($what =~ /^who are you ignoring/) {
-		my $ignores = join ", ", @{$config{ignore}};
-		$irc->yield(privmsg => $nick => "I am ignoring: $ignores");
-	}
-	if ($what =~ /^mode\s/) {
-		my ($rest) = $what =~ /^mode\s+(.*)?$/;
-		if ($rest) {
-			$irc->yield(mode => $rest);
-			$irc->yield(privmsg => $nick => "Requested.");
-		} else {
-			$irc->yield(privmsg => $nick => "Syntax: mode [everything]");
-		}
-	}
-	if ($what =~ /^kick\s/) {
-		my ($channel, $kickee, undef, $reason) = $what =~ /^kick\s+(\S+)\s(\S+)((?:\s)(.*))?$/;
-		if ($channel and $kickee) {
-			$reason = "Requested by $nick" unless $reason;
-			$irc->yield(kick => $channel => $kickee => $reason);
-			$irc->yield(privmsg => $nick => "Requested.");
-		} else {
-			$irc->yield(privmsg => $nick => "Syntax: kick <channel> <nick> [reason]");
-		}
-	}
-	if ($what =~ /^reconnect/) {
-		my ($reason) = $what =~ /^reconnect\s+(.+)$/;
-		$irc->yield(privmsg => $nick => "Doing that now");
-		if (!$reason) {
-			$reason = $config{quit_msg};
-		}
-		$irc->yield(quit => $reason);
-	}
+
+	my $stripped_what = strip_color(strip_formatting($what));
+	my $output = run_command($stripped_what, $who, $nick);
+	$irc->yield(privmsg => $nick => $output) if $output;
+
 	return;
 }
 
-- 
cgit v1.1


From c0ff50bd5082bb6c7093d907864dd799d52c5a98 Mon Sep 17 00:00:00 2001
From: David Phillips <david@sighup.nz>
Date: Sun, 29 Jul 2018 22:36:15 +1200
Subject: Admin: rename join routine to avoid collision with CORE::join

---
 Plugin/Admin.pm | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Plugin/Admin.pm b/Plugin/Admin.pm
index ad07da2..2a2a691 100644
--- a/Plugin/Admin.pm
+++ b/Plugin/Admin.pm
@@ -17,7 +17,7 @@ sub configure {
 	$cmdref->("action", sub { $self->action(@_); } );
 
 	$cmdref->("nick", sub { $self->nick(@_); } );
-	$cmdref->("join", sub { $self->join(@_); } );
+	$cmdref->("join", sub { $self->join_channel(@_); } );
 	$cmdref->("part", sub { $self->part(@_); } );
 	$cmdref->("mode", sub { $self->mode(@_); } );
 	$cmdref->("kick", sub { $self->kick(@_); } );
@@ -74,7 +74,7 @@ sub action {
 	$irc->yield(ctcp => $arguments[0] => "ACTION $rest");
 }
 
-sub join {
+sub join_channel {
 	my ($self, $irc, $logger, $who, $where, $rest, @arguments) = @_;
 
 	return unless is_admin($who);
-- 
cgit v1.1


From c864470d4cf49249c6b4c0e412d9a060024d656e Mon Sep 17 00:00:00 2001
From: David Phillips <david@sighup.nz>
Date: Sun, 29 Jul 2018 22:38:55 +1200
Subject: Add missing arguments to modules

---
 Plugin/Echo.pm     | 2 +-
 Plugin/Map.pm      | 2 +-
 Plugin/Ping.pm     | 2 +-
 Plugin/Timezone.pm | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/Plugin/Echo.pm b/Plugin/Echo.pm
index 9b23af8..5f2c53a 100644
--- a/Plugin/Echo.pm
+++ b/Plugin/Echo.pm
@@ -19,7 +19,7 @@ sub configure {
 }
 
 sub echo {
-	my ($self, $logger, $who, $where, $rest, @arguments) = @_;
+	my ($self, $irc, $logger, $who, $where, $rest, @arguments) = @_;
 
 	return $rest;
 }
diff --git a/Plugin/Map.pm b/Plugin/Map.pm
index 9ca8cef..4bd65a6 100644
--- a/Plugin/Map.pm
+++ b/Plugin/Map.pm
@@ -22,7 +22,7 @@ sub configure {
 }
 
 sub map {
-	my ($self, $logger, $who, $where, $rest, @arguments) = @_;
+	my ($self, $irc, $logger, $who, $where, $rest, @arguments) = @_;
 	my ($command, $subjects) = ($rest =~ /^(.+?)\s+(.*)$/);
 
 	return "[]" unless $subjects;
diff --git a/Plugin/Ping.pm b/Plugin/Ping.pm
index d935512..de6fd8e 100644
--- a/Plugin/Ping.pm
+++ b/Plugin/Ping.pm
@@ -17,7 +17,7 @@ sub configure {
 }
 
 sub ping {
-	my ($self, $logger, $who, $where, $rest, @arguments) = @_;
+	my ($self, $irc, $logger, $who, $where, $rest, @arguments) = @_;
 	my $nick = (split /!/, $who)[0];
 	return "$nick: pong";
 }
diff --git a/Plugin/Timezone.pm b/Plugin/Timezone.pm
index 60a0f34..594c5d7 100644
--- a/Plugin/Timezone.pm
+++ b/Plugin/Timezone.pm
@@ -21,7 +21,7 @@ sub configure {
 }
 
 sub time {
-	my ($self, $logger, $who, $where, $rest, @arguments) = @_;
+	my ($self, $irc, $logger, $who, $where, $rest, @arguments) = @_;
 
 	my $requester = ( split /!/, $who)[0];
 	my @known_zones = (keys %{$config{timezone}});
-- 
cgit v1.1


From 9e0523bba756dc47c3ba690768c93e5dbb514e35 Mon Sep 17 00:00:00 2001
From: David Phillips <david@sighup.nz>
Date: Sun, 29 Jul 2018 23:52:42 +1200
Subject: Add new temporary hack for SASL EXTERNAL

---
 bot.conf.example | 2 ++
 config_file.pm   | 2 ++
 idalius.pl       | 2 ++
 3 files changed, 6 insertions(+)

diff --git a/bot.conf.example b/bot.conf.example
index d874777..29b619d 100644
--- a/bot.conf.example
+++ b/bot.conf.example
@@ -4,6 +4,8 @@ ircname  = a bot
 server   = irc.example.net
 port     = 6667
 usessl   = 1
+sslcert  = foo.crt
+sslkey   = foo.key
 channels = #saxtalk,#bot
 ignore   = trumpetbot,abusiveuser
 password = pleffquiffle
diff --git a/config_file.pm b/config_file.pm
index 304338f..bc30cea 100644
--- a/config_file.pm
+++ b/config_file.pm
@@ -15,6 +15,8 @@ sub parse_config
 		'server',
 		'port',
 		'usessl',
+		'sslcert',
+		'sslkey',
 		'password',
 		'must_id',
 		'quit_msg',
diff --git a/idalius.pl b/idalius.pl
index 2dc3ee2..a451309 100755
--- a/idalius.pl
+++ b/idalius.pl
@@ -31,6 +31,8 @@ my @plugin_list = plugins("dummy", \&register_command, \%config, \&run_command);
 # New PoCo-IRC object
 my $irc = POE::Component::IRC->spawn(
 	UseSSL => $config{usessl},
+	SSLCert => $config{sslcert},
+	SSLKey => $config{sslkey},
 	nick => $config{nick},
 	ircname => $config{ircname},
 	port    => $config{port},
-- 
cgit v1.1