Created
July 4, 2014 19:15
-
-
Save mniip/6d64525e1ae9a26ee39b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use strict; | |
use Coro; | |
use Xchat; | |
Xchat::register("op helper", "0.0"); | |
{ | |
package Promise; | |
sub new($) | |
{ | |
my $class = shift; | |
my $self = {}; | |
$self->{coro} = $Coro::current; | |
bless $self, $class; | |
return $self; | |
} | |
sub wait($) | |
{ | |
my $self = shift; | |
while(!exists $self->{value}) | |
{ | |
Coro::cede; | |
} | |
return $self->{value}; | |
} | |
sub fulfill($;$) | |
{ | |
my $self = shift; | |
$self->{value} = shift; | |
$self->{coro}->cede_to; | |
} | |
} | |
{ | |
package WhoisPromise; | |
our @ISA = qw(Promise); | |
my @promises; | |
my %lastwhois; | |
sub new($;$) | |
{ | |
my $class = shift; | |
my $self = {}; | |
$self->{coro} = $Coro::current; | |
$self->{nick} = shift; | |
bless $self, $class; | |
push \@promises, $self; | |
Xchat::command("quote WHOIS :$self->{nick}"); | |
return $self; | |
} | |
sub provide($;$) | |
{ | |
my $whois = shift; | |
for my $i (0 .. $#promises) | |
{ | |
if(!Xchat::nickcmp($promises[$i]->{nick}, $whois->{nick})) | |
{ | |
$promises[$i]->fulfill($whois); | |
undef $promises[$i]; | |
} | |
} | |
@promises = grep { defined } @promises; | |
} | |
Xchat::hook_server("311", sub { | |
my $w = shift; | |
$lastwhois{nick} = $w->[3]; | |
$lastwhois{ident} = $w->[4]; | |
$lastwhois{host} = $w->[5]; | |
return Xchat::EAT_NONE; | |
}); | |
Xchat::hook_server("330", sub { | |
my $w = shift; | |
$lastwhois{account} = $w->[4]; | |
return Xchat::EAT_NONE; | |
}); | |
Xchat::hook_server("318", sub { | |
WhoisPromise::provide(\%lastwhois); | |
%lastwhois = (); | |
return Xchat::EAT_NONE; | |
}); | |
} | |
{ | |
package ChanservPromise; | |
our @ISA = qw(Promise); | |
my @promises; | |
sub new($;$;$) | |
{ | |
my $class = shift; | |
my $self = {}; | |
$self->{coro} = $Coro::current; | |
$self->{channel} = shift; | |
$self->{nick} = shift; | |
bless $self, $class; | |
push \@promises, $self; | |
Xchat::command("quote CS OP $self->{channel} $self->{nick}"); | |
return $self; | |
} | |
Xchat::hook_server("MODE", sub { | |
my $w = shift; | |
if($w->[0] =~ /^:ChanServ!/ && $w->[3] eq "+o") | |
{ | |
my $channel = $w->[2]; | |
my $nickname = $w->[4]; | |
for my $i (0 .. $#promises) | |
{ | |
if(!Xchat::nickcmp($promises[$i]->{nick}, $nickname) && !Xchat::nickcmp($promises[$i]->{channel}, $channel)) | |
{ | |
$promises[$i]->fulfill(1); | |
undef $promises[$i]; | |
} | |
} | |
@promises = grep { defined } @promises; | |
} | |
return Xchat::EAT_NONE; | |
}); | |
Xchat::hook_server("NOTICE", sub { | |
my $w = shift; | |
my $we = shift; | |
if($w->[0] =~ /^:ChanServ!/ && $we->[3] eq ":You are not authorized to perform this operation.") | |
{ | |
my $p = pop @promises; | |
if(defined $p) | |
{ | |
$p->fulfill(0); | |
} | |
} | |
}); | |
} | |
Xchat::hook_command("czap", sub { | |
Coro::killall; | |
@WhoisPromise::promises = (); | |
@ChanservPromise::promises = (); | |
return Xchat::EAT_ALL; | |
}); | |
{ | |
package Action; | |
sub new($) | |
{ | |
my $class = shift; | |
my $self = {}; | |
bless $self, $class; | |
return $self; | |
} | |
sub execute($) | |
{ | |
} | |
} | |
{ | |
package CommandAction; | |
sub new($;$) | |
{ | |
my $class = shift; | |
my $self = {}; | |
$self->{command} = shift; | |
bless $self, $class; | |
return $self; | |
} | |
sub execute($) | |
{ | |
my $self = shift; | |
Xchat::print($self->{command}); | |
Xchat::command($self->{command}); | |
} | |
} | |
{ | |
package ModeAction; | |
sub new($;$) | |
{ | |
my $class = shift; | |
my $self = {}; | |
$self->{channel} = shift; | |
$self->{letters} = []; | |
$self->{arguments} = []; | |
$self->{num} = 0; | |
my @l = Xchat::get_list("channels"); | |
$self->{max} = $l[0]->{maxmodes}; | |
bless $self, $class; | |
return $self; | |
} | |
sub execute($) | |
{ | |
my $self = shift; | |
my $letters = ""; | |
my $arguments = ""; | |
for my $i (0 .. $#{$self->{arguments}}) | |
{ | |
if(ref $self->{arguments}->[$i] eq "CODE") | |
{ | |
my $arg = &{$self->{arguments}->[$i]}(); | |
if(defined $arg) | |
{ | |
$arguments .= " " . $arg; | |
$letters .= $self->{letters}->[$i]; | |
} | |
} | |
else | |
{ | |
$arguments .= " " . $self->{arguments}->[$i]; | |
$letters .= $self->{letters}->[$i]; | |
} | |
} | |
Xchat::print("quote MODE $self->{channel} $letters $arguments"); | |
Xchat::command("quote MODE $self->{channel} $letters $arguments"); | |
} | |
sub can_add($) | |
{ | |
my $self = shift; | |
return $self->{num} < $self->{max}; | |
} | |
sub add($;$;$) | |
{ | |
my $self = shift; | |
push $self->{letters}, shift; | |
push $self->{arguments}, shift; | |
$self->{num}++; | |
} | |
} | |
sub execute_actions | |
{ | |
for my $action (@_) | |
{ | |
$action->execute; | |
} | |
} | |
sub add_mode | |
{ | |
my ($actions, $channel, $letter, $arguments) = @_; | |
my $last = $actions->[-1]; | |
unless(defined $last && $last->isa("ModeAction") && $last->can_add) | |
{ | |
$last = ModeAction->new($channel); | |
push $actions, $last; | |
} | |
$last->add($letter, $arguments); | |
} | |
sub parse_actions | |
{ | |
my $channel = shift; | |
my $string = shift; | |
my @actions = (); | |
for my $oaction (split /,/, $string) | |
{ | |
my $action = $oaction; | |
$action =~ s/^\s*//; | |
$action =~ s/\s*$//; | |
if(length($action)) | |
{ | |
my $c = substr $action, 0, 1; | |
$action = substr $action, 1; | |
if($c eq '+' || $c eq '-' || $c eq '=') | |
{ | |
$action =~ s/^\s*//; | |
if(length($action)) | |
{ | |
my $mode = substr $action, 0, 1; | |
$action = substr $action, 1; | |
if(length($action)) | |
{ | |
$action =~ /^(\s*:|(?:\s*[=!@])+)?\s*(.*)$/; | |
my $whoiser = $1; | |
$action = $2; | |
$whoiser =~ s/\s//g; | |
if($action =~ /^[^:=!@]/) | |
{ | |
if(length($whoiser)) | |
{ | |
$action =~ /^([^\s\$]+)(.*)$/; | |
my $nick = $1; | |
my $forward = $2; | |
$forward =~ s/\s//g; | |
if(defined $nick) | |
{ | |
my $p = WhoisPromise->new($nick); | |
add_mode(\@actions, $channel, "$c$mode", sub { | |
my %whois = %{$p->wait}; | |
if($whoiser eq ':') | |
{ | |
if(defined $whois{account}) | |
{ | |
return "\$a:$whois{account}"; | |
} | |
Xchat::print("Warning: whois for $p->{nick} contains no account name"); | |
} | |
elsif(defined $whois{nick}) | |
{ | |
my $nickmask = ($whoiser =~ /=/) ? $whois{nick} : "*"; | |
my $identmask = ($whoiser =~ /\!/) ? $whois{ident} : "*"; | |
my $hostmask = ($whoiser =~ /@/) ? $whois{host} : "*"; | |
return "$nickmask!$identmask\@$hostmask$forward"; | |
} | |
Xchat::print("Warning: whois for $p->{nick} failed"); | |
}); | |
next; | |
} | |
} | |
else | |
{ | |
$action =~ s/\s//g; | |
add_mode(\@actions, $channel, "$c$mode", $action); | |
next; | |
} | |
} | |
} | |
else | |
{ | |
add_mode(\@actions, $channel, "$c$mode", ""); | |
next; | |
} | |
} | |
} | |
elsif($c eq 'r' || $c eq 'k') | |
{ | |
$action =~ /^\s*(\S+)\s*(?:\s+(.*\S)\s*)?$/; | |
my $nick = $1; | |
if(defined $nick) | |
{ | |
my $reason = $2; | |
my $cmd = $c eq 'r' ? "REMOVE" : "KICK"; | |
if(defined $reason) | |
{ | |
push @actions, CommandAction->new("quote $cmd $channel $nick :$reason"); | |
next; | |
} | |
else | |
{ | |
push @actions, CommandAction->new("quote $cmd $channel $nick"); | |
next; | |
} | |
} | |
} | |
} | |
Xchat::print("Warning: Ignoring unknown action '$oaction'"); | |
} | |
return @actions; | |
} | |
sub command | |
{ | |
my $w = shift; | |
my $cmd = $w->[0]; | |
my $channel = Xchat::get_info("channel"); | |
my $me = Xchat::get_info("nick"); | |
my $we = shift; | |
async | |
{ | |
if($cmd eq "cd" || $cmd eq "co") | |
{ | |
my $c = ChanservPromise->new($channel, $me); | |
unless($c->wait()) | |
{ | |
Xchat::print("Warning: Could not perform CS OP, actions aborted"); | |
return; | |
} | |
} | |
my @actions = parse_actions($channel, $we->[1]); | |
if($cmd eq "d" || $cmd eq "cd") | |
{ | |
add_mode(\@actions, $channel, "-o", $me); | |
} | |
execute_actions(@actions); | |
}; | |
Coro::cede; | |
return Xchat::EAT_ALL; | |
} | |
Xchat::hook_command("d", \&command); | |
Xchat::hook_command("o", \&command); | |
Xchat::hook_command("cd", \&command); | |
Xchat::hook_command("co", \&command); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment