rendler has asked for the wisdom of the Perl Monks concerning the following question:

My head is kinda swimming at the moment trying to figure out how to capture a whois query sent to the server. Here's the gist of my problem, I have an IRC bot that needs to check if a user who has issued it a command is a channel operator. So my idea was to do a $kernel->post('irc', 'whois', $nick); and then parse the output of that to see if they are. The problem is that POE sends events to pre defined subs such as irc_319() for the whois information I need. So how in the world would I capture the whois information called from my other sub which in itself is called from irc_public().

Replies are listed 'Best First'.
Re: Capturing queries in POE::Component::IRC
by Matts (Deacon) on Mar 01, 2002 at 07:45 UTC
    What you want to do for this is create a whole new session, giving that session all the required state information. From that session's _start state, call $kernel->post('irc', 'whois', $nick), and then capture the output in irc_319() and process it accordingly.

    This is (I think) the only safe way to do it because another command could come in while you're waiting for the whois command to come back, and so you'd get concurrency bugs.

    Let me know if you want to see some code, because this is a great example for my POE tutorial that I'm going to give at The Perl Conf this year.

      Some code would be greatly appreicated, thanks :)
      Okay a little about my bot, first off my irc_public() from the main script looks a little something like this.
      sub irc_public { my ($kernel, $who, $where, $msg) = @_[KERNEL, ARG0 .. ARG2]; run_script($kernel, $bot_version, $bot_nick, $irc_admins, $qstat_m +aster, $who, $where, $msg, $qstat_addr, $User_Info, @randquote); }
      run_script() is contained in QStatBot::Scripts.pm, Scripts.pm itself contains 3 subs, the first one checks for all the scripts within the scripts/ directory and requires the file then
      my @alias = eval "${script}_load()";
      which will return 2 values from the script, the bot command seen from a public channel and the alias that it is used with it. And the information about those scripts are stored in a global hash inside the module. The sub itself:
      our %script_aliases = load_scripts(); sub load_scripts { my (%script_aliases, $script_aliases); if (-d "scripts") { while(<scripts/*.script>) { my $script_name = $_; my $script = $1 if $script_name =~ /\/(.*)\.script/; print "Loading script: $script_name\n"; require "$script_name"; my @alias = eval "${script}_load()"; $script_aliases{$alias[0]} = $alias[1]; } return %script_aliases; } else { die "Scripts directory does not exist.\n"; } }
      And then the next sub QStatBot::Script::run_script() which recives all those variables from irc_public() when ever something happens in the channel , the bot looks at the messages and determines if any of them are commands my checking the global hash to see if the key exists and then calling up the sub for which that command is tied to.
      sub run_script { our ($kernel, $bot_version, $bot_nick, $irc_admins, $qstat_master, + $irc_host, $irc_chan, $irc_msg, $qstat_addr, $User_Info, @randquote) + = @_; our ($irc_nick, $irc_hostmask) = split(/!/, $irc_host); if ($irc_msg =~ /^$bot_nick.* commands$/i) { my @commands; for (keys %script_aliases) { push @commands, $_; } @commands = sort @commands; my $commands = join ', ', @commands; send_chan_message($irc_chan, "commands: $commands", $kernel); } elsif ($irc_msg =~ /^$bot_nick.* /i) { for (keys %script_aliases) { if ($irc_msg =~ /^$bot_nick.* $_/) { eval "$script_aliases{$_}()"; last; } } } }
      Those variables also seem to have to be made global as well since they do not get imported into the scripts otherwise. Before I had declared all the variables I needed inside all the scripts beforehand such as:
      sub mem_usage_load { my $alias = 'mem usage'; my $sub = 'display_mem_usage'; my $variables = '$kernel, $irc_chan'; return ($alias, $sub, $variables); }
      And passed the variables through such as eval "$script_aliases{$_}{'sub'}($script_aliases{$_}{'variables'})"; but that was kinda awkward having to do it like that so I dropped the idea and just made the variables global to save on the hassles caused. Anways, it's these scripts that are the problem I need to call another sub QStatBot::Scripts::check_permission() (maybe from run_script() just before eval "$script_aliases{$_}()";) which I will later create to look for another predefined value returned from ${script}_load() and stored in the global hash, that of course will be returned from scriptname_load() from the various scripts. The value will be either 'v' or 'o' to define what the user who has issued the command has to currently be inside the channel (voice or operator). It's this sub I would have to issue the whois command to the server and collect the information returned and then process it and return a 0 or 1 to if the user is a allowed to use such a command. Thanks.
      My suggestion is to base if off their hostmask rather then getting their nick and whois-ing it every time. The hostmask is sent along with every thing a user says to a channel (PRIVMSG in the irc protocol), so I'm sure there's some what POE::Component::IRC returns that. I know Net::IRC does.
        Yes gathering the hostmask is easy enough, but I do not want to go down the route of basing it off hostmask, things like keeping hostmasks up to date and adding and removing new ones become too mundane after awhile.