[BACK]Return to BNC.pm CVS log [TXT][DIR] Up to [local] / botnow

Annotation of botnow/BNC.pm, Revision 1.3

1.1       bountyht    1: #!/usr/bin/perl
                      2:
                      3: package BNC;
                      4:
                      5: use strict;
                      6: use warnings;
                      7: use OpenBSD::Pledge;
                      8: use OpenBSD::Unveil;
                      9: use MIME::Base64;
                     10: use Digest::SHA qw(sha256_hex);
                     11: use lib './';
                     12: require "SQLite.pm";
                     13: require "Hash.pm";
                     14: require "DNS.pm";
                     15: require "Mail.pm";
                     16:
                     17: my %conf = %main::conf;
                     18: my $chans = $conf{chans};
                     19: my $teamchans = $conf{teamchans};
                     20: my @teamchans = split /[,\s]+/m, $teamchans;
                     21: my $staff = $conf{staff};
                     22: my $zncdir = $conf{zncdir};
                     23: my $znclog = $conf{znclog} || "$zncdir/.znc/moddata/adminlog/znc.log";
                     24: my $hostname = $conf{hostname};
                     25: my $terms = $conf{terms};
                     26: my @logs;
                     27: my $expires = $conf{expires};
                     28: my $sslport = $conf{sslport};
                     29: my $plainport = $conf{plainport};
                     30: my $mailfrom = $conf{mailfrom};
                     31: my $mailname = $conf{mailname};
                     32: my $zncconfpath = $conf{zncconfpath} || "$zncdir/.znc/configs/znc.conf";
                     33: my $znctree = { Node => "root" };
                     34:
                     35: use constant {
                     36:        NONE => 0,
                     37:        ERRORS => 1,
                     38:        WARNINGS => 2,
                     39:        ALL => 3,
                     40: };
                     41:
                     42: `doas chown znc:daemon /home/znc/home/znc/.znc/configs/znc.conf`;
                     43: `doas chmod g+r /home/znc/home/znc/.znc/`;
                     44: my @zncconf = main::readarray($zncconfpath);
                     45: $znctree;
                     46: my @users;
                     47: foreach my $line (@zncconf) {
                     48:        if ($line =~ /<User (.*)>/) {
                     49:                push(@users, $1);
                     50:        }
                     51: }
                     52: #$znctree = parseml($znctree, @zncconf);
                     53: main::cbind("pub", "-", "bnc", \&mbnc);
                     54: main::cbind("msg", "-", "bnc", \&mbnc);
                     55: main::cbind("msg", "-", "regex", \&mregex);
                     56: main::cbind("msg", "-", "foreach", \&mforeach);
                     57: main::cbind("msgm", "-", "*", \&mcontrolpanel);
                     58: main::cbind("msg", "-", "taillog", \&mtaillog);
                     59: main::cbind("msg", "-", "lastseen", \&mlastseen);
                     60:
                     61: sub init {
                     62:        #znc.conf file
                     63:        unveil("$zncconfpath", "r") or die "Unable to unveil $!";
                     64:        #dependencies for figlet
                     65:        unveil("/usr/local/bin/figlet", "rx") or die "Unable to unveil $!";
                     66:        unveil("/usr/lib/libc.so.95.1", "r") or die "Unable to unveil $!";
                     67:        unveil("/usr/libexec/ld.so", "r") or die "Unable to unveil $!";
                     68:        unveil("/usr/bin/tail", "rx") or die "Unable to unveil $!";
                     69:        #znc.log file
                     70:        unveil("$znclog", "r") or die "Unable to unveil $!";
                     71:        #print treeget($znctree, "AnonIPLimit")."\n";
                     72:        #print treeget($znctree, "ServerThrottle")."\n";
                     73:        #print treeget($znctree, "ConnectDelay")."\n";
                     74:        #print "treeget\n";
                     75:        #print Dumper \treeget($znctree, "User", "Node");
                     76:        #print Dumper \treeget($znctree, "User", "Network", "Node");
                     77: }
                     78:
                     79: # parseml($tree, @lines)
                     80: # tree is a reference to a hash
                     81: # returns hash ref of tree
                     82: sub parseml {
                     83:        my ($tree, @lines) = @_;
                     84:        #if (scalar(@lines) == 0) { return $tree; }
                     85:        while (scalar(@lines) > 0) {
                     86:                my $line = shift(@lines);
                     87:                if ($line =~ /^\s*([^=<>\s]+)\s*=\s*([^=<>]+)\s*$/) {
                     88:                        my ($tag, $val) = ($1, $2);
                     89:                        $tree->{$tag} = $val;
                     90:                } elsif ($line =~ /^\/\//) { # skip comments
                     91:                } elsif ($line =~ /^\s*$/) { # skip blank lines
                     92:                } elsif ($line =~ /^\s*<([^>\s\/]+)\s*([^>\/]*)>\s*$/) {
                     93:                        my ($tag, $val) = ($1, $2);
                     94:                        if (!defined($tree->{$tag})) { $tree->{$tag} = []; }
                     95:                        my @newlines;
                     96:                        while (scalar(@lines) > 0) {
                     97:                                my $line = shift(@lines);
                     98:                                if ($line =~ /^\s*<\/$tag>\s*$/) {
                     99:                                        my $subtree = parseml({ Node => $val }, @newlines);
                    100:                                        push(@{$tree->{$tag}}, $subtree);
                    101:                                        return parseml($tree, @lines);
                    102:                                }
                    103:                                push(@newlines, $line);
                    104:                        }
                    105:                } else { print "ERROR: $line\n"; }
                    106:                #TODO ERRORS not defined??
                    107: #              } else { main::debug(ERRORS, "ERROR: $line"); }
                    108:        }
                    109:        return $tree;
                    110: }
                    111:
                    112: #Returns array of all values
                    113: #treeget($tree, "User");
                    114: #treeget($tree, "MaFFia Network");
                    115: sub treeget {
                    116:        my ($tree, @keys) = @_;
                    117:        my $subtree;
                    118:        my @rest = @keys;
                    119:        my $key = shift(@rest);
                    120:        $subtree = $tree->{$key};
                    121:        if (!defined($subtree)) {
                    122:                return ("Undefined");
                    123:        } elsif (ref($subtree) eq 'HASH') {
                    124:                return treeget($subtree, @rest);
                    125:        } elsif (ref($subtree) eq 'ARRAY') {
                    126:                my @array = @{$subtree};
                    127:                my @ret;
                    128:                foreach my $hashref (@array) {
                    129:                        push(@ret, treeget($hashref, @rest));
                    130:                }
                    131:                return @ret;
                    132:                #my @array = @{$subtree};
                    133:                #print Dumper treeget($hashref, @rest);
                    134:                #print Dumper treeget({$key => $subtree}, @rest);
                    135:                #return (treeget($hashref, @rest), treeget({$key => $subtree}, @rest));
                    136:        } else {
                    137:                return ($subtree);
                    138:        }
                    139: }
                    140:
                    141: sub mbnc {
                    142:        my ($bot, $nick, $host, $hand, @args) = @_;
                    143:        my ($chan, $text);
                    144:        if (@args == 2) {
                    145:                ($chan, $text) = ($args[0], $args[1]);
                    146:        } else { $text = $args[0]; }
                    147:        my $hostmask = "$nick!$host";
                    148:        if (defined($chan) && $chans =~ /$chan/) {
                    149:                main::putserv($bot, "PRIVMSG $chan :$nick: Please check private message");
                    150:        }
                    151:        if ($text =~ /^$/) {
                    152:                main::putserv($bot, "PRIVMSG $nick :Type !help for new instructions");
                    153:                foreach my $chan (@teamchans) {
                    154:                        main::putservlocalnet($bot, "PRIVMSG $chan :Help *$nick* on ".$bot->{name});
                    155:                }
                    156:                return;
                    157:        } elsif (main::isstaff($bot, $nick) && $text =~ /^delete\s+([[:ascii:]]+)/) {
                    158:                my $username = $1;
                    159:                if (SQLite::deleterows("bnc", "username", $username)) {
                    160:                        main::putserv($bot, "PRIVMSG *controlpanel :deluser $username");
                    161:                        foreach my $chan (@teamchans) {
                    162:                                main::putserv($bot, "PRIVMSG $chan :$username deleted");
                    163:                        }
                    164:                }
                    165:                return;
                    166:        } elsif ($staff =~ /$nick/ && $text =~ /^cloneuser$/i) {
                    167:                main::putserv($bot, "PRIVMSG *controlpanel :deluser cloneuser");
                    168:                sleep 3;
                    169:                main::putserv($bot, "PRIVMSG *controlpanel :get Nick cloneuser");
                    170:        }
                    171:        ### TODO: Check duplicate emails ###
                    172:        my @rows = SQLite::selectrows("irc", "hostmask", $hostmask);
                    173:        foreach my $row (@rows) {
                    174:                my $password = SQLite::get("bnc", "ircid", $row->{id}, "password");
                    175:                if (defined($password)) {
                    176:                        main::putserv($bot, "PRIVMSG $nick :Sorry, only one account per person. Please contact staff if you need help.");
                    177:                        return;
                    178:                }
                    179:        }
                    180:        if ($text =~ /^captcha\s+([[:alnum:]]+)/) {
                    181:                my $text = $1;
                    182:                # TODO avoid using host mask because cloaking can cause problems
                    183:                my $ircid = SQLite::id("irc", "nick", $nick, $expires);
                    184:                my $captcha = SQLite::get("bnc", "ircid", $ircid, "captcha");
                    185:                if ($text ne $captcha) {
                    186:                        main::putserv($bot, "PRIVMSG $nick :Wrong captcha. To get a new captcha, type !bnc <username> <email>");
                    187:                        return;
                    188:                }
                    189:                my $pass = Hash::newpass();
                    190:                chomp(my $encrypted = `encrypt $pass`);
                    191:                my $username = SQLite::get("bnc", "ircid", $ircid, "username");
                    192:                my $email = SQLite::get("bnc", "ircid", $ircid, "email");
                    193:                my $hashirc = SQLite::get("irc", "id", $ircid, "hashid");
                    194:                my $bindhost = "$username.$hostname";
                    195:                SQLite::set("bnc", "ircid", $ircid, "password", $encrypted);
                    196:                if (DNS::nextdns($username)) {
                    197:                        sleep(2);
                    198:                        createbnc($bot, $username, $pass, $bindhost);
                    199:                        main::putserv($bot, "PRIVMSG $nick :Check your email!");
                    200:                        mailbnc($username, $email, $pass, "bouncer", $hashirc);
                    201:                        #www($newnick, $reply, $password, "bouncer");
                    202:                } else {
                    203:                        foreach my $chan (@teamchans) {
                    204:                                main::putserv($bot, "PRIVMSG $chan :Assigning bindhost $bindhost failed");
                    205:                        }
                    206:                }
                    207:                return;
                    208:        } elsif ($text =~ /^([[:alnum:]]+)\s+([[:ascii:]]+)/) {
                    209:                my ($username, $email) = ($1, $2);
                    210: #              my @users = treeget($znctree, "User", "Node");
                    211:                foreach my $user (@users) {
                    212:                        if ($user eq $username) {
                    213:                                main::putserv($bot, "PRIVMSG $nick :Sorry, username taken. Please contact staff if you need help.");
1.3     ! bountyht  214:                                return;
1.1       bountyht  215:                        }
                    216:                }
                    217:                #my $captcha = join'', map +(0..9,'a'..'z','A'..'Z')[rand(10+26*2)], 1..4;
                    218:                my $captcha = int(rand(999));
                    219:                my $ircid = int(rand(9223372036854775807));
                    220:                my $hashid = sha256_hex("$ircid");
                    221:                SQLite::set("irc", "id", $ircid, "localtime", time());
                    222:                SQLite::set("irc", "id", $ircid, "hashid", sha256_hex($ircid));
                    223:                SQLite::set("irc", "id", $ircid, "date", main::date());
                    224:                SQLite::set("irc", "id", $ircid, "hostmask", $hostmask);
                    225:                SQLite::set("irc", "id", $ircid, "nick", $nick);
                    226:                SQLite::set("bnc", "ircid", $ircid, "username", $username);
                    227:                SQLite::set("bnc", "ircid", $ircid, "email", $email);
                    228:                SQLite::set("bnc", "ircid", $ircid, "captcha", $captcha);
                    229:                SQLite::set("bnc", "ircid", $ircid, "hashid", $hashid);
                    230:                main::whois($bot->{sock}, $nick);
                    231:                main::ctcp($bot->{sock}, $nick);
                    232:                main::putserv($bot, "PRIVMSG $nick :".`figlet $captcha`);
                    233:                main::putserv($bot, "PRIVMSG $nick :https://$hostname/$hashid/captcha.png");
                    234:                main::putserv($bot, "PRIVMSG $nick :https://$hostname/register.php?hashirc=$hashid");
                    235:                main::putserv($bot, "PRIVMSG $nick :Type !bnc captcha <text>");
                    236:                foreach my $chan (@teamchans) {
1.2       bountyht  237:                        main::putservlocalnet($bot, "PRIVMSG $chan :$nick\'s on $bot->{name} bnc captcha is $captcha");
1.1       bountyht  238:                }
                    239:        } else {
                    240:                main::putserv($bot, "PRIVMSG $nick :Invalid username or email. Type !bnc <username> <email> to try again.");
                    241:                foreach my $chan (@teamchans) {
                    242:                        main::putservlocalnet($bot, "PRIVMSG $chan :Help *$nick* on ".$bot->{name});
                    243:                }
                    244:        }
                    245: }
                    246:
                    247: sub mregex {
                    248:        my ($bot, $nick, $host, $hand, $text) = @_;
                    249:        if (!main::isstaff($bot, $nick)) { return; }
                    250:        if ($text =~ /^ips?\s+([-_()|0-9A-Za-z:\.?*\s]{3,})$/) {
                    251:                my $ips = $1; # space-separated list of IPs
                    252:                main::putserv($bot, "PRIVMSG $nick :".regexlist($ips));
                    253:        } elsif ($text =~ /^users?\s+([-_()|0-9A-Za-z:\.?*\s]{3,})$/) {
                    254:                my $users = $1; # space-separated list of usernames
                    255:                main::putserv($bot, "PRIVMSG $nick :".regexlist($users));
                    256:        } elsif ($text =~ /^[-_()|0-9A-Za-z:,\.?*\s]{3,}$/) {
                    257:                my @lines = regex($text);
                    258:                foreach my $l (@lines) { print "$l\n"; }
                    259:        }
                    260: }
                    261: sub mforeach {
                    262:        my ($bot, $nick, $host, $hand, $text) = @_;
                    263:        if ($staff !~ /$nick/) { return; }
                    264:        if ($text =~ /^network\s+del\s+([[:graph:]]+)\s+(#[[:graph:]]+)$/) {
                    265:                my ($user, $chan) = ($1, $2);
                    266:                foreach my $n (@main::networks) {
                    267:                        main::putserv($bot, "PRIVMSG *controlpanel :delchan $user $n->{name} $chan");
                    268:                }
                    269:        }
                    270: }
                    271:
                    272: sub mcontrolpanel {
                    273:        my ($bot, $nick, $host, $hand, @args) = @_;
                    274:        my ($chan, $text);
                    275:        if (@args == 2) {
                    276:                ($chan, $text) = ($args[0], $args[1]);
                    277:        } else { $text = $args[0]; }
                    278:        my $hostmask = "$nick!$host";
                    279:        if($hostmask eq '*controlpanel!znc@znc.in') {
                    280:                if ($text =~ /^Error: User \[cloneuser\] does not exist/) {
                    281:                        createclone($bot);
                    282:                        foreach my $chan (@teamchans) {
                    283:                                main::putserv($bot, "PRIVMSG $chan :Cloneuser created");
                    284:                        }
                    285:                } elsif ($text =~ /^User (.*) added!$/) {
                    286:                        main::debug(ALL, "User $1 created");
                    287:                } elsif ($text =~ /^Password has been changed!$/) {
                    288:                        main::debug(ALL, "Password changed");
                    289:                } elsif ($text =~ /^Queued network (.*) of user (.*) for a reconnect.$/) {
                    290:                        main::debug(ALL, "$2 now connecting to $1...");
                    291:                } elsif ($text =~ /^Admin = false/) {
                    292:                        foreach my $chan (@teamchans) {
                    293:                                main::putserv($bot, "PRIVMSG $chan :ERROR: $nick is not admin");
                    294:                        }
                    295:                        die "ERROR: $nick is not admin";
                    296:                } elsif ($text =~ /^Admin = true/) {
                    297:                        main::debug(ALL, "$nick is ZNC admin");
                    298:                } elsif ($text =~ /(.*) = (.*)/) {
                    299:                        my ($key, $val) = ($1, $2);
                    300:                        main::debug(ALL, "ZNC: $key => $val");
                    301:                } else {
                    302:                        main::debug(ERRORS, "Unexpected 290 BNC.pm: $hostmask $text");
                    303:                }
                    304:        }
                    305: }
                    306: sub loadlog {
                    307:        open(my $fh, '<', "$znclog") or die "Could not read file 'znc.log' $!";
                    308:        chomp(@logs = <$fh>);
                    309:        close $fh;
                    310: }
                    311:
                    312: # return all lines matching a pattern
                    313: sub regex {
                    314:        my ($pattern) = @_;
                    315:        if (!@logs) { loadlog(); }
                    316:        return grep(/$pattern/, @logs);
                    317: }
                    318:
                    319: # given a list of IPs, return matching users
                    320: # or given a list of users, return matching IPs
                    321: sub regexlist {
                    322:        my ($items) = @_;
                    323:        my @items = split /[,\s]+/m, $items;
                    324:        my $pattern = "(".join('|', @items).")";
                    325:        if (!@logs) { loadlog(); }
                    326:        my @matches = grep(/$pattern/, @logs);
                    327:        my @results;
                    328:        foreach my $match (@matches) {
                    329:                if ($match =~ /^\[\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\] \[([^]\/]+)(\/[^]]+)?\] connected to ZNC from (.*)/) {
                    330:                        my ($user, $ip) = ($1, $3);
                    331:                        if ($items =~ /[.:]/) { # items are IP addresses
                    332:                                push(@results, $user);
                    333:                        } else { # items are users
                    334:                                push(@results, $ip);
                    335:                        }
                    336:                }
                    337:        }
                    338:        my @sorted = sort @results;
                    339:        @results = do { my %seen; grep { !$seen{$_}++ } @sorted }; # uniq
                    340:        return join(' ', @results);
                    341: }
                    342:
                    343: sub createclone {
                    344:        my ($bot) = @_;
                    345:        my $socket = $bot->{sock};
                    346:        my $password = Hash::newpass();
                    347:        my $msg = <<"EOF";
                    348: adduser cloneuser $password
                    349: set Nick cloneuser cloneuser
                    350: set Altnick cloneuser cloneuser_
                    351: set Ident cloneuser cloneuser
                    352: set RealName cloneuser cloneuser
                    353: set MaxNetworks cloneuser 1000
                    354: set ChanBufferSize cloneuser 1000
                    355: set MaxQueryBuffers cloneuser 1000
                    356: set QueryBufferSize cloneuser 1000
                    357: set NoTrafficTimeout cloneuser 600
                    358: set QuitMsg cloneuser IRCNow and Forever!
                    359: set RealName cloneuser cloneuser
                    360: set DenySetBindHost cloneuser true
                    361: set Timezone cloneuser US/Pacific
                    362: LoadModule cloneuser controlpanel
                    363: LoadModule cloneuser chansaver
                    364: EOF
                    365: #LoadModule cloneuser buffextras
                    366:        main::putserv($bot, "PRIVMSG *controlpanel :$msg");
                    367:        foreach my $n (@main::networks) {
                    368:                my $net = $n->{name};
                    369:                my $server = $n->{server};
                    370:                my $port = $n->{port};
                    371:                my $trustcerts = $n->{trustcerts};
                    372:                $msg = <<"EOF";
                    373: addnetwork cloneuser $net
                    374: addserver cloneuser $net $server $port
                    375: disconnect cloneuser $net
                    376: EOF
                    377:                if ($trustcerts) {
                    378:                        $msg .= "SetNetwork TrustAllCerts cloneuser $net True\r\n";
                    379:                }
                    380:                my @chans = split /[,\s]+/m, $chans;
                    381:                foreach my $chan (@chans) {
                    382:                        $msg .= "addchan cloneuser $net $chan\r\n";
                    383:                }
                    384:                main::putserv($bot, "PRIVMSG *controlpanel :$msg");
                    385:        }
                    386: }
                    387:
                    388: sub createbnc {
                    389:        my ($bot, $username, $password, $bindhost) = @_;
                    390:        my $netname = $bot->{name};
                    391:        my $msg = <<"EOF";
                    392: cloneuser cloneuser $username
                    393: set Nick $username $username
                    394: set Altnick $username ${username}_
                    395: set Ident $username $username
                    396: set RealName $username $username
                    397: set Password $username $password
                    398: set MaxNetworks $username 1000
                    399: set ChanBufferSize $username 1000
                    400: set MaxQueryBuffers $username 1000
                    401: set QueryBufferSize $username 1000
                    402: set NoTrafficTimeout $username 600
                    403: set QuitMsg $username IRCNow and Forever!
                    404: set BindHost $username $bindhost
                    405: set DCCBindHost $username $bindhost
                    406: set DenySetBindHost $username true
                    407: reconnect $username $netname
                    408: EOF
                    409: #set Language $username en-US
                    410:        main::putserv($bot, "PRIVMSG *controlpanel :$msg");
                    411:        return 1;
                    412: }
                    413: sub mailbnc {
                    414:        my( $username, $email, $password, $service, $hashirc )=@_;
                    415:        my $passhash = sha256_hex("$username");
                    416:
                    417: my $body = <<"EOF";
                    418: You created a bouncer!
                    419:
                    420: Username: $username
                    421: Password: $password
                    422: Server: $hostname
                    423: Port: $sslport for SSL (secure connection)
                    424: Port: $plainport for plaintext
                    425:
                    426: *IMPORTANT*: Verify your email address:
                    427:
                    428: https://$hostname/register.php?hashirc=$hashirc
                    429:
                    430: You *MUST* click on the link or your account will be deleted.
                    431:
                    432: IRCNow
                    433: EOF
                    434:        Mail::mail($mailfrom, $email, $mailname, "Verify IRCNow Account", $body);
                    435: }
                    436:
                    437: sub mtaillog {
                    438:        my ($bot, $nick, $host, $hand, @args) = @_;
                    439:        my ($chan, $text);
                    440:        if (@args == 2) {
                    441:                ($chan, $text) = ($args[0], $args[1]);
                    442:        } else { $text = $args[0]; }
                    443:        my $hostmask = "$nick!$host";
                    444:        open(my $fh, "-|", "/usr/bin/tail", "-f", $znclog) or die "could not start tail: $!";
                    445:        while (my $line = <$fh>) {
                    446:                foreach my $chan (@teamchans) {
                    447:                        main::putserv($bot, "PRIVMSG $chan :$line");
                    448:                }
                    449:        }
                    450: }
                    451:
                    452: sub mlastseen {
                    453:        my ($bot, $nick, $host, $hand, @args) = @_;
                    454:        my ($chan, $text);
                    455:        if (@args == 2) {
                    456:                ($chan, $text) = ($args[0], $args[1]);
                    457:        } else { $text = $args[0]; }
                    458:        my $hostmask = "$nick!$host";
                    459:        if (!@logs) { loadlog(); }
                    460:        my @users = treeget($znctree, "User", "Node");
                    461:        foreach my $user (@users) {
                    462:                my @lines = grep(/^\[\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\] \[$user\] connected to ZNC from [.0-9a-fA-F:]+/, @logs);
                    463:                if (scalar(@lines) == 0) {
                    464:                        foreach my $chan (@teamchans) {
                    465:                                main::putserv($bot, "PRIVMSG $chan :$user never logged in");
                    466:                        }
                    467:                        next;
                    468:                }
                    469:                my $recent = pop(@lines);
                    470:                if ($recent =~ /^\[(\d{4}-\d\d-\d\d) \d\d:\d\d:\d\d\] \[$user\] connected to ZNC from [.0-9a-fA-F:]+/) {
                    471:                        my $date = $1;
                    472:                        foreach my $chan (@teamchans) {
                    473:                                main::putserv($bot, "PRIVMSG $chan :$user $date");
                    474:                        }
                    475:                }
                    476:        }
                    477: }
                    478: #sub resend {
                    479: #      my ($bot, $newnick, $email) = @_;
                    480: #      my $password = newpass();
                    481: #      sendmsg($bot, "*controlpanel", "set Password $newnick $password");
                    482: #      mailverify($newnick, $email, $password, "bouncer");
                    483: #      sendmsg($bot, "$newnick", "Email sent");
                    484: #}
                    485:
                    486: #      if ($reply =~ /^!resend ([-_0-9a-zA-Z]+) ([-_0-9a-zA-Z]+@[-_0-9a-zA-Z]+\.[-_0-9a-zA-Z]+)$/i) {
                    487: #              my ($newnick, $email) = ($1, $2);
                    488: #              my $password = newpass();
                    489: #              resend($bot, $newnick, $email);
                    490: #      }
                    491:
                    492: #sub resetznc {
                    493: #
                    494: #AnonIPLimit 10000
                    495: #AuthOnlyViaModule false
                    496: #ConnectDelay 0
                    497: #HideVersion true
                    498: #LoadModule
                    499: #ServerThrottle
                    500: #1337  209.141.38.137
                    501: #31337  209.141.38.137
                    502: #1337  2605:6400:20:5cc::
                    503: #31337  2605:6400:20:5cc::
                    504: #1337  127.0.0.1
                    505: #1338  127.0.0.1
                    506: #}
                    507: #
                    508: #alias   Provides bouncer-side command alias support.
                    509: #autoreply   Reply to queries when you are away
                    510: #block_motd   Block the MOTD from IRC so it's not sent to your client(s).
                    511: #bouncedcc   Bounces DCC transfers through ZNC instead of sending them directly to the user.
                    512: #clientnotify   Notifies you when another IRC client logs into or out of your account. Configurable.
                    513: #ctcpflood   Don't forward CTCP floods to clients
                    514: #dcc   This module allows you to transfer files to and from ZNC
                    515: #perform   Keeps a list of commands to be executed when ZNC connects to IRC.
                    516: #webadmin   Web based administration module.
                    517:
                    518:
                    519: 1; # MUST BE LAST STATEMENT IN FILE

CVSweb