package IRC::Tools::Server; use IRC::Parser::Mapped qw(:all); use Carp qw(croak); use Exporter qw(import); our @EXPORT_OK = qw($Server $Support); our %EXPORT_TAGS = ( casemap => [ qw(rfc_lc rfc_uc rfc_casemap) ], prefix => [ qw(mode2prefix prefix2mode) ], ); my %EXISTS; push @EXPORT_OK, grep {!$EXISTS{$_}++} @{ $EXPORT_TAGS{$_} } foreach(keys %EXPORT_TAGS); $EXPORT_TAGS{all} = \@EXPORT_OK; undef(%EXISTS); our $Server = {}; our $Support = {}; handler Server => { '004' => sub { @{ $Server }{qw(name version usermodes chanmodes listmodes)} = split ' ', $_[PM_ARGS]; PM_OK }, '005' => sub { PIECE: foreach(split ' ', $_[PM_ARGS]) { $Support->{uc($_)} = 1, next PIECE unless /=/; my($key, $val) = split '=', $_, 2; $key =~ y/a-z/A-Z/; if($key eq 'CHANMODES') { $Support->{$key} = [ split ',', $val ]; } elsif($key eq 'PREFIX') { my($modes, $prefix) = $val =~ /^\((.+)\)(.+)$/; @{ $Support->{$key} }{ split('', $modes) } = split '', $prefix; } elsif($key eq 'CASEMAPPING') { rfc_casemap($val); } elsif(grep {$_ eq $key} qw(MAXLIST TARGMAX IDCHAN)) { # CHANLIMIT foreach(split ',', $val) { my($k, $v) = split ':'; $Support->{$key}->{$k} = $v; } } else { $Support->{$key} = $val; } } PM_OK }, ERROR => sub { $Server = {}, $Support = {}; } }, PRI_CRITICAL + 10; # Very *critical*? sub mode2prefix { foreach(keys %{ $Support->{PREFIX} }) { return $Support->{PREFIX}->{$_} if $_ eq $_[0]; } } sub prefix2mode { foreach(keys %{ $Support->{PREFIX} }) { return $_ if $Support->{PREFIX}->{$_} eq $_[0]; } } my $CASEMAP; # as tr/// is handled at compile time, a var won't suffice unless I eval() this whole thing # which I can only do at a considerable cost to performance, so I won't my $CMAPS = { 'ascii' => { 'LC' => sub { local $_ = shift; y/A-Z/a-z/; $_; }, 'UC' => sub { local $_ = shift; y/a-z/A-Z/; $_; } }, 'rfc1459' => { 'LC' => sub { local $_ = shift; y/A-Z[]\\^/a-z{}|~/; $_; }, 'UC' => sub { local $_ = shift; y/a-z{}|~/A-Z[]\\^/; $_; } }, 'strict-rfc1459' => { 'LC' => sub { local $_ = shift; y/A-Z[]\\/a-z{}|/; $_; }, 'UC' => sub { local $_ = shift; y/a-z{}|/A-Z[]\\/; $_; } } }; sub rfc_casemap { return $CASEMAP unless @_; if(exists $CMAPS->{$_[0]}) { $CASEMAP = $_[0]; # do { no warnings; *rfc_lc = $CMAPS->{$CASEMAP}->{LC}; *rfc_uc = $CMAPS->{$CASEMAP}->{UC}; }; - apparently, when exported to a namespace.. its a reference to as it is at the time.. which would only make sense, it happens at ompile time.. oops } else { $CASEMAP = 'ascii'; warn "casemap(): unknown casemap $_[0], assuming 'ascii'."; } } rfc_casemap('ascii'); # lexical returns first element, scalar a list sub rfc_lc { scalar @_ or croak "usage: rfc_uc(LIST)"; my @lc = (); push @lc, $CMAPS->{$CASEMAP}->{LC}->($_) while(local $_ = shift); wantarray() ? @lc : $lc[0]; } # scalar returns array reference, otherwise a list sub rfc_uc { scalar @_ or croak "usage: rfc_uc(LIST)"; my @uc = (); push @uc, $CMAPS->{$CASEMAP}->{UC}->($_) while(local $_ = shift); wantarray() ? @uc : $uc[0]; } 1;