POE::C...:State(3pm)
π POE::Component::IRC::State(3pm) π
User Contributed Perl Documentation Β· POE::Component::IRC::State(3pm)
okay bestie, sit down, hydrate, because we're about to talk about the IRC component that actually remembers things. πΈ
β¨ NAME β¨
POE::Component::IRC::State β a fully event-driven IRC client module with nickname and channel tracking
like yes she's an IRC client, but she's the kind that takes notes. she knows who's in the channel. she knows who left. she is that girl. π
π SYNOPSIS π
here's a whole lil Rot13 "encryption" bot (emphasis on the air quotes, it's not encryption bestie, it's a vibe):
# A simple Rot13 'encryption' bot
use strict;
use warnings;
use POE qw(Component::IRC::State);
my $nickname = 'Flibble' . $$;
my $ircname = 'Flibble the Sailor Bot';
my $ircserver = 'irc.blahblahblah.irc';
my $port = 6667;
my @channels = ( '#Blah', '#Foo', '#Bar' );
# We create a new PoCo-IRC object and component.
my $irc = POE::Component::IRC::State->spawn(
nick => $nickname,
server => $ircserver,
port => $port,
ircname => $ircname,
) or die "Oh noooo! $!";
POE::Session->create(
package_states => [
main => [ qw(_default _start irc_001 irc_public) ],
],
heap => { irc => $irc },
);
$poe_kernel->run();
sub _start {
my ($kernel, $heap) = @_[KERNEL, HEAP];
# We get the session ID of the component from the object
# and register and connect to the specified server.
my $irc_session = $heap->{irc}->session_id();
$kernel->post( $irc_session => register => 'all' );
$kernel->post( $irc_session => connect => { } );
return;
}
sub irc_001 {
my ($kernel, $sender) = @_[KERNEL, SENDER];
# Get the component's object at any time by accessing the heap of
# the SENDER
my $poco_object = $sender->get_heap();
print "Connected to ", $poco_object->server_name(), "\n";
# In any irc_* events SENDER will be the PoCo-IRC session
$kernel->post( $sender => join => $_ ) for @channels;
return;
}
sub irc_public {
my ($kernel ,$sender, $who, $where, $what) = @_[KERNEL, SENDER, ARG0 .. ARG2];
my $nick = ( split /!/, $who )[0];
my $channel = $where->[0];
my $poco_object = $sender->get_heap();
if ( my ($rot13) = $what =~ /^rot13 (.+)/ ) {
# Only operators can issue a rot13 command to us.
return if !$poco_object->is_channel_operator( $channel, $nick );
$rot13 =~ tr[a-zA-Z][n-za-mN-ZA-M];
$kernel->post( $sender => privmsg => $channel => "$nick: $rot13" );
}
return;
}
# We registered for all events, this will produce some debug info.
sub _default {
my ($event, $args) = @_[ARG0 .. $#_];
my @output = ( "$event: " );
for my $arg ( @$args ) {
if (ref $arg eq 'ARRAY') {
push( @output, '[' . join(', ', @$arg ) . ']' );
}
else {
push ( @output, "'$arg'" );
}
}
print join ' ', @output, "\n";
return 0;
}
π¦ DESCRIPTION π¦
POE::Component::IRC::State is a sub-class of POE::Component::IRC which tracks IRC state entities such as nicks and channels. π
for general usage, go read the docs for POE::Component::IRC. this document is the extra-glow-up document β it covers the extra methods that POE::Component::IRC::State provides. periodt.
this component tracks channels and nicks, so that it always has a current snapshot of what channels it is on and who else is on those channels. the returned object provides methods to query the collected state. she's keeping receipts, bestie, and the receipts are accurate. π₯
π CONSTRUCTORS π
POE::Component::IRC::State's constructors, and its "connect" event, all take the same arguments as POE::Component::IRC does β as well as two additional ones:
'AwayPoll'β the interval (in seconds) in which to poll (i.e."WHO #channel") the away status of channel members. defaults to0(disabled). if enabled, you will receive"irc_away_sync_*"/"irc_user_away"/"irc_user_back"events, and will be able to use the"is_away"method for users other than yourself. π«Ά this can cause a lot of increase in traffic, especially if you are on big channels, so if you do use this, you probably don't want to set it too low. for reference, X-Chat uses300seconds (5 minutes). β°'WhoJoiners'β a boolean indicating whether the component should send a"WHO nick"for every person which joins a channel. defaults to on (the"WHO"is sent). π if you turn this off,"is_operator"will not work and"nick_info"will only return the keys'Nick','User','Host'and'Userhost'.
ngl, that second one is a real tradeoff. turning off 'WhoJoiners' saves traffic but you lose powers. main character energy costs bandwidth, that's just the law. π
to be continued, bestie β more parts incoming π§π
ban_mask</p>
Hand it a channel and a ban mask β like the kind you'd pass to MODE +b-b β and it'll give you back a list of the nicks on that channel who match that ban mask. π If the channel isn't in the state, or literally nobody matches, you get an empty list. Sorry bestie, no matches means no nicks.
channel_ban_list</p>
Feed it a channel. You get back a hashref holding the banlist, if the channel's in the state β otherwise a false value. The hashref's keys are the entries on the list, and each of those entries has its own keys: 'SetBy' and 'SetAt'. Those two hold, respectively, the nick!hostmask of whoever set that entry (or just the nick if that's all the ircd gives us π₯²) and the time it got set.
channel_creation_time</p>
Takes a channel. Gives you the channel's creation time, or a false value. That's it, that's the whole function. β°
channel_except_list</p>
Takes a channel. You get a hashref with the ban exception list if the channel's in the state, false if it's not. The keys of that hashref are the entries on the list, and each one carries 'SetBy' and 'SetAt' β the nick!hostmask of whoever set the entry (or just the nick if that's all the ircd gives us) and the time it was set. β¨
channel_invex_list</p>
Takes a channel. Returns a hashref with the invite exception list if the channel's in the state, false if not. Again: hashref keys are the list entries, each with 'SetBy' and 'SetAt', holding the nick!hostmask of the setter (or just the nick, if that's the most the ircd is gonna give us π) and the time it was set.
channel_key</p>
Takes a channel. Returns the channel key, or a false value. π
channel_limit</p>
Takes a channel. Returns the channel limit, or a false value.
channel_list</p>
Takes a channel. Returns a list of every nick on that channel. If the component happens to not be on that channel, you get an empty list back. No cap.
channel_modes</p>
Takes a channel. Returns a hash ref keyed on channel mode, with the mode's argument (if it has one) as the value. If the channel isn't in the state though, you get a false value instead.
channels</p>
No parameters, none needed. Returns a hashref keyed on channel name, telling you whether the bot is operator, halfop or has voice on that channel.
for my $channel ( keys %{ $irc->channels() } ) {
$irc->yield( 'privmsg' => $channel => 'm00!' );
}
channel_topic</p>
Takes a channel. Returns a hashref full of topic info if the channel's in the state, false if it's not. That hashref has these keys: 'Value', 'SetBy', 'SetAt'. Respectively they hold the topic itself, the nick!hostmask of whoever set it (or just the nick if that's all the ircd gives us π) and the time it was set.
If the component happens to not be on the channel, nothing comes back at all.
channel_url</p>
Takes a channel. Returns that channel's URL. If the channel has no URL, or the component isn't on the channel, nothing comes back. π¦
has_channel_voice</p>
Takes a channel and a nickname. True if that nick has voice on that channel. False if the nick doesn't have voice there, or if the nick/channel just doesn't exist in the state.
is_away</p>
Takes a nick. True if that nick is away. False if the nick isn't away, or isn't in the state. Heads up: this only works for your own IRC user unless you specified a value for 'AwayPoll' in "spawn". π«Ά
is_channel_admin</p>
Takes a channel and a nickname. True if the nick is an admin on that channel. False if they're not an admin there, or if the nick/channel isn't in the state.
is_channel_halfop</p>
Takes a channel and a nickname. True if the nick is a half-operator on that channel. False if they're not a half-op there, or if the nick/channel isn't in the state.
is_channel_member</p>
Takes a channel and a nickname. True if the nick is on that channel. False if they're not on it, or if the nick/channel isn't in the state.
is_channel_mode_set</p>
Takes a channel and a single mode flag matching [A-Za-z]. True if that mode is set on the channel.
is_channel_operator</p>
Takes a channel and a nickname. True if the nick is an operator on that channel. False if they're not an op there, or if the nick/channel isn't in the state.
is_channel_owner</p>
Takes a channel and a nickname. True if the nick is an owner on that channel. False if they're not an owner there, or if the nick/channel isn't in the state.
is_channel_synced</p>
Takes a channel. True if the channel has been synced. False if it hasn't been synced, or if the channel isn't in the state.
is_operator</p>
Takes a nick. True if that nick is an IRC operator. False if they're not an IRC operator, or aren't in the state.
is_user_mode_set</p>
Takes a single user mode flag matching [A-Za-z]. True if that user mode is set.
nick_channel_modes</p>
Takes a channel and a nickname. Returns the modes of that nick on that channel (ie. qaohv). If the nick isn't on the channel in the state, you get a false value. π
nick_channels</p>
Takes a nickname. Returns a list of the channels that that nickname and the component are both on. Empty list if the nickname doesn't exist in the state.
nick_info</p>
Takes a nickname. Returns a hashref carrying info similar to what WHOIS gives you. False value if the nickname doesn't exist in the state. The hashref has these keys:
'Nick', 'User', 'Host', 'Userhost', 'Hops', 'Real', 'Server' and, if applicable, 'IRCop'.
nick_long_form</p>
Takes a nickname. Returns the long form of that nick, ie. "nick!user@host", or a false value if the nick isn't in the state. π
nicks</p>
No parameters. Returns a list of every nick it knows about, itself included. If the component happens to be on no channels then you get an empty list back.
umode</p>
No parameters. Returns the current user mode set for the bot.
π OUTPUT EVENTS π
Augmented events β¨
New parameters get bolted onto the following POE::Component::IRC events. Like, the events you already know? They got upgraded. π
irc_quit
See also "irc_quit" in POE::Component::IRC.
Extra parameter "ARG2" holds an arrayref of channel names that are common to the quitting client and the component.
irc_nick
See also "irc_nick" in POE::Component::IRC.
Extra parameter "ARG2" holds an arrayref of channel names that are common to the nick changing client and the component.
irc_kick
See also "irc_kick" in POE::Component::IRC.
Extra parameter "ARG4" holds the full nick!user@host of the kicked individual. π
irc_topic
See also "irc_kick" in POE::Component::IRC.
Extra parameter "ARG3" holds the old topic hashref, like the one "channel_topic" gives you.
irc_disconnected
irc_error
irc_socketerr
All three of these get two extra parameters. "ARG1" is a hash of info about your IRC user (peep "nick_info"), while "ARG2" is a hash of the channels you were on (peep "channels").
New events π
On top of all the usual POE::Component::IRC irc_* events, these are the ones you can register for:
irc_away_sync_start
Sent whenever the component starts to synchronise the away statuses of channel members. "ARG0" is the channel name. You'll only get this event if you specified a value for 'AwayPoll' in "spawn".
irc_away_sync_end
Sent whenever the component has finished synchronising the away statuses of channel members. "ARG0" is the channel name. Again, you only get this one if you specified a value for 'AwayPoll' in "spawn".
irc_chan_mode
Basically identical to "irc_mode", except it's sent once for each individual mode with its respective argument if it has one (ie. the banmask if it's +b or -b). But heads up β this event is only sent for channel modes.
irc_chan_sync
Sent whenever the component has finished synchronising a channel it has joined. "ARG0" is the channel name and "ARG1" is the time in seconds that the channel took to synchronise. β±οΈ
irc_chan_sync_invex
Sent whenever the component has finished synchronising a channel's INVEX (invite list). Usually this gets triggered by the component being opped on a channel. "ARG0" is the channel name.
irc_chan_sync_excepts
Sent whenever the component has finished synchronising a channel's EXCEPTS (ban exemption list). Usually triggered by the component being opped on a channel. "ARG0" is the channel.
irc_nick_sync
Sent whenever the component has finished synchronising a user who has joined a channel the component is on. "ARG0" is the user's nickname and "ARG1" the channel they've joined. π¦
irc_user_away
Sent when an IRC user sets his/her status to away. "ARG0" is the nickname, "ARG1" is an arrayref of channel names that are common to the nickname and the component. You'll only get this event if you specified a value for 'AwayPoll' in "spawn".
Note: the above is only for users other than yourself. To know when you change your own away status, register for the"irc_305"and"irc_306"events.
irc_user_back
Sent when an IRC user unsets his/her away status. "ARG0" is the nickname, "ARG1" is an arrayref of channel names that are common to the nickname and the component. Only if you specified a value for 'AwayPoll' in "spawn", bestie.
Note: this above is also only for users other than yourself. To know when you change your own away status, register for the"irc_305"and"irc_306"events.
irc_user_mode
Almost identical to "irc_mode", except it's sent for each individual umode that's being set. π
π CAVEATS (read this bestie, fr fr)
So, plot twist: this component is a bit of a gossip. It gathers alllll its info by registering for irc_quit, irc_nick, irc_join, irc_part, irc_mode, irc_kick and various numeric replies. Like, it is the group chat lurker. π
Here's the thing though β when the component is asked to join a channel, when it joins it will issue WHO #channel, MODE #channel, and MODE #channel b. Those three little requests between them solicit the numerics irc_352, irc_324 and irc_329, respectively. And when someone joins a channel the bot is on, it issues a WHO nick. So likeβ¦ yeah. You may want to ignore these. π« (Those WHO/MODE replies are literally just the component doing its little research, no cap.)
Now the β¨ messy β¨ part, and I need you to sit with me for this one:
Currently, whenever the component sees a topic or channel list change, it will use time for the SetAt value and the full address of the user who set it for the SetBy value. That's our version of events.
But when an ircd gives us its record of such changes, it will use its own time (obviously π) and may only give us the nickname of the user, rather than their full address.
So if our time and the ircd's time do not match, or the ircd uses the nickname only, ugly inconsistencies can develop. π
Which means the SetAt and SetBy values are inaccurate at best, and you should use them with this in mind (for now, at least). Don't be out here trusting them with your whole heart, bestie, they're giving unreliable narrator energy. π
π AUTHOR
Chris Williams <chris@bingosnet.co.uk>
With contributions from Lyndon Miller. π«Ά (ty for your service, king)
π LICENCE
This module may be used, modified, and distributed under the same terms as Perl itself. Please see the license that came with your Perl distribution for details. π
π SEE ALSO
POE::Component::IRCPOE::Component::IRC::Qnet::State
Go read those too, bestie, they're the whole vibe. β¨π¦
And that's the page, babes! π This absolute icon of a doc is perl v5.40.1, dated 2025-08-21, and it lives under User Contributed Perl Documentation for POE::C...:State(3pm) β go off, you beautiful little manpage. Slay, periodt. ππΈ
π¦ where this page comes from
- ubuntu resolute: libpoe-component-irc-perl 6.95+dfsg-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu stonking: libpoe-component-irc-perl 6.95+dfsg-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms