Chris Williams


POE::Component::IRC::Service::Hybrid - a fully event-driven IRC services module for Hybrid networks.


  use POE::Component::IRC::Service::Hybrid;

  # Do this when you create your sessions. 'IRC-Service' is just a
  # kernel alias to christen the new IRC connection with. (Returns
  # only a true or false success flag, not an object.)

  POE::Component::IRC::Service::Hybrid->new('IRC-Service') or die "Oh noooo! $!";

  # Do stuff like this from within your sessions. This line tells the
  # connection named "IRC-Service" to send your session the following
  # events when they happen.

  $kernel->post('IRC-Service', 'register', qw(connected msg public nick server));

  # You can guess what this line does.

  $kernel->post('IRC-Service', 'connect',
                { ServerName        => '',
                  ServerDesc        => 'Services for LameNET',
                  RemoteServer      => '',
                  ServerPort        => 7666,
                  Password          => 'password', } );

  # Add a services identity to the network

  $kernel->post('IRC-Service' => 'addnick',
                { NickName    => 'Lame',
                  Umode       => '+o',
                  Description => 'Lame Services Bot', } );


POE::Component::IRC::Service::Hybrid is a POE component which acts as an easily controllable IRC Services client for your other POE components and sessions. You create an IRC Services component and tell it what events your session cares about and where to connect to, and it sends back interesting IRC events when they happen. You make the client do things by sending it events.

[Note that this module requires a lot of familiarity with the details of the IRC protocol. I'd advise you to read up on the gory details of RFC 1459 <> before starting. Some knowledge of the Hybrid's IRC Server-to-Server protocol would also be advisable, most importantly with TSora. Check out the documents that come with the Hybrid IRCd package.

So you want to write a POE program with POE::Component::IRC::Service::Hybrid? Listen up. The short version is as follows: Create your session(s) and an alias for a new POE::Component::IRC::Service::Hybrid client. (Conceptually, it helps if you think of them as little IRC servers.) In your session's _start handler, send the IRC service a 'register' event to tell it which IRC events you want to receive from it. Send it a 'connect' event at some point to tell it to join the IRC network, and it should start sending you interesting events every once in a while. Use the 'addnick' event to add an IRC client to your "server". The IRC Service accepts two different sets of events, server and client. Server events are commands that are issued by (heh) the server and client events are commands issued by clients.

  # Example of a client command:

  $kernel->post( 'IRC-Service', 'join', 'Lame' , '#LameNET' );

  # Example of a server command:

  $kernel->post( 'IRC-Service', 'sl_server', "MODE #LameNET +o Lame" );

Basically, client commands require a source nickname for the command, eg. it doesn't make sense for a server to "join" a channel.

The long version is the rest of this document.


Well, OK, there's only actually one, so it's more like "METHOD".


Takes two arguments: a name (kernel alias) which this new connection will be known by, the second argument is a hashref of options see connect for more details. WARNING: This method, for all that it's named "new" and called in an OO fashion, doesn't actually return an object. It returns a true or false value which indicates if the new session was created or not. If it returns false, check $! for the POE::Session error code.


How to talk to your new IRC Services component... here's the events we'll accept.

Important Commands


Takes one argument: a hash reference of attributes for the new connection (see the SYNOPSIS section of this doc for an example). This event tells the IRC Services client to connect to a new/different hub and join an IRC network. If it has a connection already open, it'll close it gracefully before reconnecting. Possible attributes for the new connection are "ServerName", the name your IRC Service will be called; "ServerDesc", a brief description of your IRC Service; "RemoteServer", the DNS or IP address of your uplink/hub server; "ServerPort", the port to connect to on your uplink/hub server; "Password", the password required to link to uplink/hub server; "LocalAddr", which local IP address on a multihomed box to connect as; "EOB", set to '0' to disable automatic generation of an End of Burst.


Takes one argument: a hash reference of attributes for the new service client (see the SYNOPSIS section of this doc for an example). This event adds a new client to the IRC Service server. Multiple clients are allowed. Expect to receive an appropriate irc_hyb_nick event for the new client, from which you can derive the clients numeric token. Possible attributes for the new client are "NickName", (duh) the nickname this client will appear as on the IRC network (only required attribute); "UserName", the user part of ident@host (default is nick); "HostName", the host part of ident@host (default is the name of the server); "Umode", the user modes this client will have (defaults to +odk); "Description", equivalent to the IRCName (default server description);


Takes N arguments: a list of event names that your session wants to listen for, minus the "irc_hyb_" prefix. So, for instance, if you just want a bot that keeps track of which people are on a channel, you'll need to listen for CREATEs, JOINs, PARTs, QUITs, and KICKs to people on the channel you're in. You'd tell POE::Component::IRC::Service::Hybrid that you want those events by saying this:

  $kernel->post( 'IRC-Service', 'register', qw(join part quit kick) );

Then, whenever people enter or leave a channel (forcibly or not), your session will receive events with names like "irc_hyb_join", "irc_hyb__kick", etc., which you can use to update a list of people on the channel.

Registering for 'all' will cause it to send all IRC-related events to you; this is the easiest way to handle it.


Takes N arguments: a list of event names which you don't want to receive. If you've previously done a 'register' for a particular event which you no longer care about, this event will tell the IRC connection to stop sending them to you. (If you haven't, it just ignores you. No big deal.)

Server initiated commands

These are commands that come from the IRC Service itself and not from clients.


Sets or removes a GLINE to the IRC network. A GLINE prevents matching users from connecting to the network. Implemented as if the IRC Service is a U: lined server, so ircd must be configured accordingly. Takes four arguments, the target for the gline which can be * (for all servers) or a server numeric; the mask to gline [!][-|+]<mask> the presence of the ! prefix means "force", + means add/activate, - means remove/deactivate; the duration of the gline, ie. the time to expire the gline in seconds since epoch ( ie. output from time() ); the reason for the gline. Mask may be a user@host mask, or a channel name. In the later case (mask starts with a # or &) it is a "BADCHAN". A BADCHAN prevents users from joining a channel with the same name.


A jupe prevents servers from joining the network. Takes five arguments, the target for the jupe, either * for all servers or a server numeric; what to jupe [!][-|+]<server>, ! is force, + activate jupe, - deactivate jupe; the duration of the jupe, ie. the time to expire the jupe in seconds since epoch; the last modification timestamp, ie. the output of time(); the reason for the jupe.


Server kill :) Takes two arguments, the client numeric of the victim; the reason for the kill. If the numeric specified matches one of the IRC Service's internal clients, that client will be automatically removed.


This will disconnect the IRC Service from its uplink/hub server. Expect to receive an "irc_hyb_disconnected" event. Takes no arguments.


Send a raw server command. Exercise extreme caution. Takes one argument, a string representing the raw command that the server will send. The module prepends the appropriate server numeric for you, so don't worry about that. Note, IRC commands must be specified as tokenised equivalents as per P10 specification.

$kernel->post( 'IRC-Service' => sl_server => "MODE #LameNET +o Lame" );

Client initiated commands

These are commands that come from clients on the IRC Service.

ctcp and ctcpreply

Sends a CTCP query or response to the nick(s) or channel(s) which you specify. Takes 3 arguments: the numeric of the client who is sending the command; the nickname or channel to send a message to (use an array reference here to specify multiple recipients), and the plain text of the message to send (the CTCP quoting will be handled for you).


Invites another user onto an invite-only channel. Takes 3 arguments: the numeric of the inviting client, the nick of the user you wish to admit, and the name of the channel to invite them to.


Tells a specified client to join a single channel of your choice. Takes at least two args: the numeric of the client that you want to join, the channel name (required) and the channel key (optional, for password-protected channels).


Request a mode change on a particular channel or user. Takes at least two arguments: the mode changing client's nickname, the mode changes to effect, as a single string (e.g., "+sm-p+o"), and any number of optional operands to the mode changes (nicknames, hostmasks, channel keys, whatever.) Or just pass them all as one big string and it'll still work, whatever.


Allows you to change a client's nickname. Takes two arguments: the nickname of the client who wishes to change nickname and the new username that you'd like to be known as.


Sends a NOTICE message to the nick(s) or channel(s) which you specify. Takes 3 arguments: the nickname of the issuing client, the nick or channel to send a notice to (use an array reference here to specify multiple recipients), and the text of the notice to send.


Tell a client to leave the channels which you pass to it. Takes any number of arguments: the nickname of the client followed by the channel names to depart from.


Sends a public or private message to the nick(s) or channel(s) which you specify. Takes 3 arguments: the nickname of the issuing client, the numeric or channel to send a message to (use an array reference here to specify multiple recipients), and the text of the message to send.


Tells the IRC service to remove a client. Takes one argument: the nickname of the client to disconnect; and one optional argument: some clever, witty string that other users in your channels will see as you leave. The IRC Service will automatically remove the client from its internal list of clients.


Send a raw client command. Exercise extreme caution. Takes one argument, a string representing the raw command that the server will send. Unlike "sl_server" you must specify the full raw command prefixed with the appropriate client nickname.

$kernel->post( 'IRC-Service' => sl_client => ":Lame MODE #LameNET +o Lame2" );


Returns some information about a server. Kinda complicated and not terribly commonly used, so look it up in the RFC if you're curious. Takes as many arguments as you please, but the first argument must be the nickname of a client.


The events you will receive (or can ask to receive) from your running IRC component. Note that all incoming event names your session will receive are prefixed by "irc_hyb_", to inhibit event namespace pollution ( and Dennis had already taken irc_ :p ).

If you wish, you can ask the client to send you every event it generates. Simply register for the event name "all". This is a lot easier than writing a huge list of things you specifically want to listen for.

The IRC Service deals with some events on your behalf, they will be duly noted below.

Important Events


The IRC component will send an "irc_hyb_connected" event as soon as it establishes a connection to an IRC server, before attempting to log in. ARG0 is whatever you passed to "connect" as RemoteServer.

NOTE: When you get an "irc_hyb_connected" event, this doesn't mean you can start sending commands to the server yet. The uplink/hub server and the IRC Service will be in the process of synchronising by way of a net burst. Wait for an "irc_hyb_eob" from your uplink/hub server before sending any events.


This event is generated during a net burst when the IRC Service first joins an IRC network. It is basically a description of a channel and its state, ie. nicks, modes, bans, etc. See TSora specification for the gory details. This is also what servers use to propogate channel JOINS, don't expect to see irc_hyb_join events :(

This is the response from the uplink/hub server we connected to. You can use this event to discern the server numeric of the server we are connected to. ARG0 is server's name, ARG1 is the hop count, ARG2 is the server description.


This follows an irc_hyb_server_link and tells you what version of TSora the uplink can do and its timestamp. ARG0 is highest version of TSora the uplink will do and ARG1 is the lowest version. ARG2 is the timestamp from the uplink. =item irc_hyb_server

Seen during a net burst and when a new server joins the network. ARG0 is the server name. ARG1 is a single string made up of the data for the server, which has the following format <name> <hop> <boot-ts> <link-ts> <protocol> <max-clients> :<description>. See Hint above in irc_hyb_server-link.


Sent by a server when it finishes a net burst. The module will automatically respond to an end of burst by its uplink/hub with an end_of_burst_ack. The module will also automatically send its own end_of_burst message to the uplink/hub unless you set the appropriate option during CONNECT ( See above ).


Received when a server disconnects. ARG0 is the server numeric of the sender. ARG1 is a string with the data of the event, with the following format: <servername> <timestamp> :<description>


The module takes care of "u" requests automagically.


The module takes care of ponging to these automagically.

Miscellaneous events

Events such as join, part, etc. should be same as POE::Component::IRC. See that documentation for details.

All numeric events (see RFC 1459)

Most messages from IRC servers are identified only by three-digit numeric codes with undescriptive constant names like RPL_UMODEIS and ERR_NOTOPLEVEL. (Actually, the list of codes in the RFC is kind of out-of-date... the list in the back of is more complete, and different IRC networks have different and incompatible lists. Ack!) As an example, say you wanted to handle event 376 (RPL_ENDOFMOTD, which signals the end of the MOTD message). You'd register for '376', and listen for 'irc_hyb_376' events. Simple, no? ARG0 is the numeric of the server which sent the message. ARG1 is the text of the message.


Chris Williams, <<gt>

Based on a hell of lot of POE::Component::IRC written by Dennis Taylor, <>


Copyright (c) Dennis Taylor and Chris Williams.

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.


Greatest of debts to Dennis Taylor, <> for letting me "salvage" POE::Component::IRC to write this module.

And to ^kosh and FozzySon and others from #jeditips for allowing me to inflict my coding on them :)


RFC 1459,,,