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

Annotation of botnow/BNC.pm, Revision 1.1.1.1

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.");
                    214:                        }
                    215:                }
                    216:                #my $captcha = join'', map +(0..9,'a'..'z','A'..'Z')[rand(10+26*2)], 1..4;
                    217:                my $captcha = int(rand(999));
                    218:                my $ircid = int(rand(9223372036854775807));
                    219:                my $hashid = sha256_hex("$ircid");
                    220:                SQLite::set("irc", "id", $ircid, "localtime", time());
                    221:                SQLite::set("irc", "id", $ircid, "hashid", sha256_hex($ircid));
                    222:                SQLite::set("irc", "id", $ircid, "date", main::date());
                    223:                SQLite::set("irc", "id", $ircid, "hostmask", $hostmask);
                    224:                SQLite::set("irc", "id", $ircid, "nick", $nick);
                    225:                SQLite::set("bnc", "ircid", $ircid, "username", $username);
                    226:                SQLite::set("bnc", "ircid", $ircid, "email", $email);
                    227:                SQLite::set("bnc", "ircid", $ircid, "captcha", $captcha);
                    228:                SQLite::set("bnc", "ircid", $ircid, "hashid", $hashid);
                    229:                main::whois($bot->{sock}, $nick);
                    230:                main::ctcp($bot->{sock}, $nick);
                    231:                main::putserv($bot, "PRIVMSG $nick :".`figlet $captcha`);
                    232:                main::putserv($bot, "PRIVMSG $nick :https://$hostname/$hashid/captcha.png");
                    233:                main::putserv($bot, "PRIVMSG $nick :https://$hostname/register.php?hashirc=$hashid");
                    234:                main::putserv($bot, "PRIVMSG $nick :Type !bnc captcha <text>");
                    235:                foreach my $chan (@teamchans) {
                    236:                        main::putservlocalnet($bot, "PRIVMSG $chan :$nick\'s captcha is $captcha");
                    237:                }
                    238:        } else {
                    239:                main::putserv($bot, "PRIVMSG $nick :Invalid username or email. Type !bnc <username> <email> to try again.");
                    240:                foreach my $chan (@teamchans) {
                    241:                        main::putservlocalnet($bot, "PRIVMSG $chan :Help *$nick* on ".$bot->{name});
                    242:                }
                    243:        }
                    244: }
                    245:
                    246: sub mregex {
                    247:        my ($bot, $nick, $host, $hand, $text) = @_;
                    248:        if (!main::isstaff($bot, $nick)) { return; }
                    249:        if ($text =~ /^ips?\s+([-_()|0-9A-Za-z:\.?*\s]{3,})$/) {
                    250:                my $ips = $1; # space-separated list of IPs
                    251:                main::putserv($bot, "PRIVMSG $nick :".regexlist($ips));
                    252:        } elsif ($text =~ /^users?\s+([-_()|0-9A-Za-z:\.?*\s]{3,})$/) {
                    253:                my $users = $1; # space-separated list of usernames
                    254:                main::putserv($bot, "PRIVMSG $nick :".regexlist($users));
                    255:        } elsif ($text =~ /^[-_()|0-9A-Za-z:,\.?*\s]{3,}$/) {
                    256:                my @lines = regex($text);
                    257:                foreach my $l (@lines) { print "$l\n"; }
                    258:        }
                    259: }
                    260: sub mforeach {
                    261:        my ($bot, $nick, $host, $hand, $text) = @_;
                    262:        if ($staff !~ /$nick/) { return; }
                    263:        if ($text =~ /^network\s+del\s+([[:graph:]]+)\s+(#[[:graph:]]+)$/) {
                    264:                my ($user, $chan) = ($1, $2);
                    265:                foreach my $n (@main::networks) {
                    266:                        main::putserv($bot, "PRIVMSG *controlpanel :delchan $user $n->{name} $chan");
                    267:                }
                    268:        }
                    269: }
                    270:
                    271: sub mcontrolpanel {
                    272:        my ($bot, $nick, $host, $hand, @args) = @_;
                    273:        my ($chan, $text);
                    274:        if (@args == 2) {
                    275:                ($chan, $text) = ($args[0], $args[1]);
                    276:        } else { $text = $args[0]; }
                    277:        my $hostmask = "$nick!$host";
                    278:        if($hostmask eq '*controlpanel!znc@znc.in') {
                    279:                if ($text =~ /^Error: User \[cloneuser\] does not exist/) {
                    280:                        createclone($bot);
                    281:                        foreach my $chan (@teamchans) {
                    282:                                main::putserv($bot, "PRIVMSG $chan :Cloneuser created");
                    283:                        }
                    284:                } elsif ($text =~ /^User (.*) added!$/) {
                    285:                        main::debug(ALL, "User $1 created");
                    286:                } elsif ($text =~ /^Password has been changed!$/) {
                    287:                        main::debug(ALL, "Password changed");
                    288:                } elsif ($text =~ /^Queued network (.*) of user (.*) for a reconnect.$/) {
                    289:                        main::debug(ALL, "$2 now connecting to $1...");
                    290:                } elsif ($text =~ /^Admin = false/) {
                    291:                        foreach my $chan (@teamchans) {
                    292:                                main::putserv($bot, "PRIVMSG $chan :ERROR: $nick is not admin");
                    293:                        }
                    294:                        die "ERROR: $nick is not admin";
                    295:                } elsif ($text =~ /^Admin = true/) {
                    296:                        main::debug(ALL, "$nick is ZNC admin");
                    297:                } elsif ($text =~ /(.*) = (.*)/) {
                    298:                        my ($key, $val) = ($1, $2);
                    299:                        main::debug(ALL, "ZNC: $key => $val");
                    300:                } else {
                    301:                        main::debug(ERRORS, "Unexpected 290 BNC.pm: $hostmask $text");
                    302:                }
                    303:        }
                    304: }
                    305: sub loadlog {
                    306:        open(my $fh, '<', "$znclog") or die "Could not read file 'znc.log' $!";
                    307:        chomp(@logs = <$fh>);
                    308:        close $fh;
                    309: }
                    310:
                    311: # return all lines matching a pattern
                    312: sub regex {
                    313:        my ($pattern) = @_;
                    314:        if (!@logs) { loadlog(); }
                    315:        return grep(/$pattern/, @logs);
                    316: }
                    317:
                    318: # given a list of IPs, return matching users
                    319: # or given a list of users, return matching IPs
                    320: sub regexlist {
                    321:        my ($items) = @_;
                    322:        my @items = split /[,\s]+/m, $items;
                    323:        my $pattern = "(".join('|', @items).")";
                    324:        if (!@logs) { loadlog(); }
                    325:        my @matches = grep(/$pattern/, @logs);
                    326:        my @results;
                    327:        foreach my $match (@matches) {
                    328:                if ($match =~ /^\[\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\] \[([^]\/]+)(\/[^]]+)?\] connected to ZNC from (.*)/) {
                    329:                        my ($user, $ip) = ($1, $3);
                    330:                        if ($items =~ /[.:]/) { # items are IP addresses
                    331:                                push(@results, $user);
                    332:                        } else { # items are users
                    333:                                push(@results, $ip);
                    334:                        }
                    335:                }
                    336:        }
                    337:        my @sorted = sort @results;
                    338:        @results = do { my %seen; grep { !$seen{$_}++ } @sorted }; # uniq
                    339:        return join(' ', @results);
                    340: }
                    341:
                    342: sub createclone {
                    343:        my ($bot) = @_;
                    344:        my $socket = $bot->{sock};
                    345:        my $password = Hash::newpass();
                    346:        my $msg = <<"EOF";
                    347: adduser cloneuser $password
                    348: set Nick cloneuser cloneuser
                    349: set Altnick cloneuser cloneuser_
                    350: set Ident cloneuser cloneuser
                    351: set RealName cloneuser cloneuser
                    352: set MaxNetworks cloneuser 1000
                    353: set ChanBufferSize cloneuser 1000
                    354: set MaxQueryBuffers cloneuser 1000
                    355: set QueryBufferSize cloneuser 1000
                    356: set NoTrafficTimeout cloneuser 600
                    357: set QuitMsg cloneuser IRCNow and Forever!
                    358: set RealName cloneuser cloneuser
                    359: set DenySetBindHost cloneuser true
                    360: set Timezone cloneuser US/Pacific
                    361: LoadModule cloneuser controlpanel
                    362: LoadModule cloneuser chansaver
                    363: EOF
                    364: #LoadModule cloneuser buffextras
                    365:        main::putserv($bot, "PRIVMSG *controlpanel :$msg");
                    366:        foreach my $n (@main::networks) {
                    367:                my $net = $n->{name};
                    368:                my $server = $n->{server};
                    369:                my $port = $n->{port};
                    370:                my $trustcerts = $n->{trustcerts};
                    371:                $msg = <<"EOF";
                    372: addnetwork cloneuser $net
                    373: addserver cloneuser $net $server $port
                    374: disconnect cloneuser $net
                    375: EOF
                    376:                if ($trustcerts) {
                    377:                        $msg .= "SetNetwork TrustAllCerts cloneuser $net True\r\n";
                    378:                }
                    379:                my @chans = split /[,\s]+/m, $chans;
                    380:                foreach my $chan (@chans) {
                    381:                        $msg .= "addchan cloneuser $net $chan\r\n";
                    382:                }
                    383:                main::putserv($bot, "PRIVMSG *controlpanel :$msg");
                    384:        }
                    385: }
                    386:
                    387: sub createbnc {
                    388:        my ($bot, $username, $password, $bindhost) = @_;
                    389:        my $netname = $bot->{name};
                    390:        my $msg = <<"EOF";
                    391: cloneuser cloneuser $username
                    392: set Nick $username $username
                    393: set Altnick $username ${username}_
                    394: set Ident $username $username
                    395: set RealName $username $username
                    396: set Password $username $password
                    397: set MaxNetworks $username 1000
                    398: set ChanBufferSize $username 1000
                    399: set MaxQueryBuffers $username 1000
                    400: set QueryBufferSize $username 1000
                    401: set NoTrafficTimeout $username 600
                    402: set QuitMsg $username IRCNow and Forever!
                    403: set BindHost $username $bindhost
                    404: set DCCBindHost $username $bindhost
                    405: set DenySetBindHost $username true
                    406: reconnect $username $netname
                    407: EOF
                    408: #set Language $username en-US
                    409:        main::putserv($bot, "PRIVMSG *controlpanel :$msg");
                    410:        return 1;
                    411: }
                    412: sub mailbnc {
                    413:        my( $username, $email, $password, $service, $hashirc )=@_;
                    414:        my $passhash = sha256_hex("$username");
                    415:
                    416: my $body = <<"EOF";
                    417: You created a bouncer!
                    418:
                    419: Username: $username
                    420: Password: $password
                    421: Server: $hostname
                    422: Port: $sslport for SSL (secure connection)
                    423: Port: $plainport for plaintext
                    424:
                    425: *IMPORTANT*: Verify your email address:
                    426:
                    427: https://$hostname/register.php?hashirc=$hashirc
                    428:
                    429: You *MUST* click on the link or your account will be deleted.
                    430:
                    431: IRCNow
                    432: EOF
                    433:        Mail::mail($mailfrom, $email, $mailname, "Verify IRCNow Account", $body);
                    434: }
                    435:
                    436: sub mtaillog {
                    437:        my ($bot, $nick, $host, $hand, @args) = @_;
                    438:        my ($chan, $text);
                    439:        if (@args == 2) {
                    440:                ($chan, $text) = ($args[0], $args[1]);
                    441:        } else { $text = $args[0]; }
                    442:        my $hostmask = "$nick!$host";
                    443:        open(my $fh, "-|", "/usr/bin/tail", "-f", $znclog) or die "could not start tail: $!";
                    444:        while (my $line = <$fh>) {
                    445:                foreach my $chan (@teamchans) {
                    446:                        main::putserv($bot, "PRIVMSG $chan :$line");
                    447:                }
                    448:        }
                    449: }
                    450:
                    451: sub mlastseen {
                    452:        my ($bot, $nick, $host, $hand, @args) = @_;
                    453:        my ($chan, $text);
                    454:        if (@args == 2) {
                    455:                ($chan, $text) = ($args[0], $args[1]);
                    456:        } else { $text = $args[0]; }
                    457:        my $hostmask = "$nick!$host";
                    458:        if (!@logs) { loadlog(); }
                    459:        my @users = treeget($znctree, "User", "Node");
                    460:        foreach my $user (@users) {
                    461:                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);
                    462:                if (scalar(@lines) == 0) {
                    463:                        foreach my $chan (@teamchans) {
                    464:                                main::putserv($bot, "PRIVMSG $chan :$user never logged in");
                    465:                        }
                    466:                        next;
                    467:                }
                    468:                my $recent = pop(@lines);
                    469:                if ($recent =~ /^\[(\d{4}-\d\d-\d\d) \d\d:\d\d:\d\d\] \[$user\] connected to ZNC from [.0-9a-fA-F:]+/) {
                    470:                        my $date = $1;
                    471:                        foreach my $chan (@teamchans) {
                    472:                                main::putserv($bot, "PRIVMSG $chan :$user $date");
                    473:                        }
                    474:                }
                    475:        }
                    476: }
                    477: #sub resend {
                    478: #      my ($bot, $newnick, $email) = @_;
                    479: #      my $password = newpass();
                    480: #      sendmsg($bot, "*controlpanel", "set Password $newnick $password");
                    481: #      mailverify($newnick, $email, $password, "bouncer");
                    482: #      sendmsg($bot, "$newnick", "Email sent");
                    483: #}
                    484:
                    485: #      if ($reply =~ /^!resend ([-_0-9a-zA-Z]+) ([-_0-9a-zA-Z]+@[-_0-9a-zA-Z]+\.[-_0-9a-zA-Z]+)$/i) {
                    486: #              my ($newnick, $email) = ($1, $2);
                    487: #              my $password = newpass();
                    488: #              resend($bot, $newnick, $email);
                    489: #      }
                    490:
                    491: #sub resetznc {
                    492: #
                    493: #AnonIPLimit 10000
                    494: #AuthOnlyViaModule false
                    495: #ConnectDelay 0
                    496: #HideVersion true
                    497: #LoadModule
                    498: #ServerThrottle
                    499: #1337  209.141.38.137
                    500: #31337  209.141.38.137
                    501: #1337  2605:6400:20:5cc::
                    502: #31337  2605:6400:20:5cc::
                    503: #1337  127.0.0.1
                    504: #1338  127.0.0.1
                    505: #}
                    506: #
                    507: #alias   Provides bouncer-side command alias support.
                    508: #autoreply   Reply to queries when you are away
                    509: #block_motd   Block the MOTD from IRC so it's not sent to your client(s).
                    510: #bouncedcc   Bounces DCC transfers through ZNC instead of sending them directly to the user.
                    511: #clientnotify   Notifies you when another IRC client logs into or out of your account. Configurable.
                    512: #ctcpflood   Don't forward CTCP floods to clients
                    513: #dcc   This module allows you to transfer files to and from ZNC
                    514: #perform   Keeps a list of commands to be executed when ZNC connects to IRC.
                    515: #webadmin   Web based administration module.
                    516:
                    517:
                    518: 1; # MUST BE LAST STATEMENT IN FILE

CVSweb