Wrote this basic example (read it again, spell it and use it as it is, an example) which includes a very dirty and primitive authentication method that can allow *unlimited* users and a few commands triggered in private messages ONCE authenticated. This could have been done a way out better, however this is a simple demo, using perl's power it could have taken less than 60 lines... now talking serious, Goki is a great project, I've tried a lot of perl scripts and nothing but *****, merlin should keep this work as simple as it is now ;)  No more talking... and action! (posting it later on my blog with full credits)

## file plugin/chanop.pm ##

package chanop;
#use warnings; # we don't need warnings, we know it's dirty code ;)

# Module wide variables

# add as many nicks as you want, and remember, in order to authenticate
# you need to have the same nick name (not case sensitive)
my %chanops = (
  'xUx' => '12345',
  'demonick' => 'demopass',
  'nick2' => 'somethinghere'
);

# careful, moving things here could make the bot crash :)
my %chdata = (); # hash that will hold all data

foreach $key (sort keys %chanops) {
  %{$chdata{lc($key)}} = ('nick' => lc($key), 'pass' => $chanops{$key});
}

# Module load functions. Set default values here.
BEGIN {
  our $VERSION = 0.4;
  $irc = main::IRC;
  # private events
  $irc->add_handler('privcmd auth','do_auth');
  $irc->add_handler('privcmd who','do_who');
  $irc->add_handler('privcmd join','do_join');
  $irc->add_handler('privcmd part','do_part');
  $irc->add_handler('privcmd kick','do_kick');
  $irc->add_handler('privcmd ban','do_ban');
  $irc->add_handler('privcmd voice','do_voice');
  $irc->add_handler('privcmd devoice','do_devoice');
  $irc->add_handler('privcmd op','do_op');
  $irc->add_handler('privcmd deop','do_deop');
  $irc->add_handler('privcmd sh','do_sh');
  $irc->add_handler('privcmd say','do_say');
}

sub do_say {
  my ( $nick, $hostmask, $text ) = @_;
  if (!&do_auth_check($nick,$hostmask)) { return; }
  my @args = split(" ",$text);
  my $msg = join(" ",@args[1 .. scalar(@args)-1]);
  main::plog "Message sent from $nick to $args[0]\n";
  $irc->say($args[0],$msg);
}

sub do_sh {
  my ( $nick, $hostmask, $text ) = @_;
  if (!&do_auth_check($nick,$hostmask)) { return; }
  main::plog "Exec attempt by $nick\n";
  my @output = `$text`;
  my $line;
  foreach $line (@output) {
    $irc->say($nick, $line);
  }
}

sub do_deop {
  # deop #channel nick
  my ($nick,$hostmask,$text) = @_;
  if (!&do_auth_check($nick,$hostmask)) { return; }
  my @args = split(" ",$text);
  if ($args[0] !~ /^\#/) { $args[0] = "#" . $args[0]; }
  main::plog "Deop on $args[0] to $args[1] by $nick\n";
  $irc->deop($args[0],$args[1]);
}

sub do_op {
  # op #channel nick
  my ($nick,$hostmask,$text) = @_;
  if (!&do_auth_check($nick,$hostmask)) { return; }
  my @args = split(" ",$text);
  if ($args[0] !~ /^\#/) { $args[0] = "#" . $args[0]; }
  main::plog "Op on $args[0] to $args[1] by $nick\n";
  $irc->op($args[0],$args[1]);
}

sub do_devoice {
  # devoice #channel nick
  my ($nick,$hostmask,$text) = @_;
  if (!&do_auth_check($nick,$hostmask)) { return; }
  my @args = split(" ",$text);
  if ($args[0] !~ /^\#/) { $args[0] = "#" . $args[0]; }
  $irc->devoice($args[0],$args[1]);
}

sub do_voice {
  # voice #channel nick
  my ($nick,$hostmask,$text) = @_;
  if (!&do_auth_check($nick,$hostmask)) { return; }
  my @args = split(" ",$text);
  if ($args[0] !~ /^\#/) { $args[0] = "#" . $args[0]; }
  main::plog "Voice on $args[0] to $args[1] by $nick\n";
  $irc->voice($args[0],$args[1]);
}

sub do_ban {
  # ban #channel nick|hostmask
  my ($nick,$hostmask,$text) = @_;
  if (!&do_auth_check($nick,$hostmask)) { return; }
  my @args = split(" ",$text);
  if ($args[0] !~ /^\#/) { $args[0] = "#" . $args[0]; }
  main::plog "Ban on $args[0] to $args[1] by $nick\n";
  $irc->mode($args[0],"+b",$args[1]);
}

sub do_kick {
  # kick #channel nick reason
  my ($nick,$hostmask,$text) = @_;
  if (!&do_auth_check($nick,$hostmask)) { return; }
  my @args = split(" ",$text);
  if ($args[0] !~ /^\#/) { $args[0] = "#" . $args[0]; }
  my $reason = join(" ",@args[2 .. scalar(@args)-1]) || $args[1];
  main::plog "Kick on $args[0] to $args[1] ($reason) by $nick\n";
  $irc->kick($args[0],$args[1],$reason);
}

sub do_part {
  # part #channel
  my ($nick,$hostmask,$text) = @_;
  if (!&do_auth_check($nick,$hostmask)) { return; }
  my @args = split(" ",$text);
  if ($args[0] !~ /^\#/) { $args[0] = "#" . $args[0]; }
  main::plog "Parting $args[0] by $nick\n";
  $irc->part($args[0]);
}

sub do_join {
  # join #channel
  my ($nick,$hostmask,$text) = @_;
  if (!&do_auth_check($nick,$hostmask)) { return; }
  my @args = split(" ",$text);
  if ($args[0] !~ /^\#/) { $args[0] = "#" . $args[0]; }
  main::plog "Joining $args[0] by $nick\n";
  $irc->join($args[0]);
}

sub do_who {
  my ($nick,$hostmask,$text) = @_;
  if (!&do_auth_check($nick,$hostmask)) { return; }
  foreach my $key (sort keys %chdata) {
    if (exists($chdata{$key}{'hostmask'})) {
      $irc->say($nick, $chdata{$key}{'nick'} . " (". $chdata{$key}{'hostmask'}.")");
    }
  }
  return;
}

sub do_auth_check {
  my ($nick,$hostmask) = @_;
  my $tmphostmask = (split("\!",$hostmask))[1];
  if (!exists($chdata{lc($nick)}{'hostmask'})) {
    main::plog "Unauthorized access from $hostmask\n";
    return 0;
  }
  if ($chdata{lc($nick)}{'hostmask'} eq $tmphostmask) { return 1; }
  return 0;
}

sub do_auth {
  my ($nick,$hostmask,$text) = @_;
  my $tmphostmask = (split("\!",$hostmask))[1];
  if (!exists($chdata{lc($nick)})) {
    main::plog "Invalid user tried to AUTH: $nick ($tmphostmask)\n";
    return;
  }
  my @args = split(" ",$text);
  if ($chdata{lc($nick)}{'pass'} ne $args[0]) {
    main::plog "Invalid Login attemp from $nick ($tmphostmask)\n";
    $irc->notice($nick,"Invalid Password, attemp logged!");
    return;
  }
  if (exists($chdata{lc($nick)}{'hostmask'})) {
    main::plog "RE-AUTH from $nick from ".$chdata{lc($nick)}{'hostmask'}." to $tmphostmask\n";
  }
  else {  main::plog "AUTH from $nick from $tmphostmask\n"; }
  $chdata{lc($nick)}{'hostmask'} = $tmphostmask;
  $irc->notice($nick, "Authentication Succesful!");
}

return 1;

# Module unload functions, free memory and close open filehandles here
END {
  # Does not currently work, but is here for future compatibility
  # $irc->del_handler( '', '' );
}