IRC on a Higher Level Continued

In the last article, you were taught about events in Python-IRCLib. You were taught what some common events are, how to catch them and how to properly respond to them. While a grasp of events is crucial to developing applications that interact through IRC, it’s important to realize that Python-IRCLib doesn’t just deal with responding to events. The library is a few dozen kilobytes, and all of that space obviously does not contain code that deals with events. The library contains many more features, and we’ll take a look at some of them in this article.

Action Methods

Recall the code to private message a channel or user:


server.privmsg ( ‘#channel’, ‘Message to #channel.’ )
server.privmsg ( ‘UserName’, ‘Message to UserName’ )

The library contains more methods similar to the privmsg method, and a simple method is much easier to use than tinkering with the protocol itself. One such method is an extension of the privmsg method – privmsg_many. While privmsg handles a single target, privmsg_many can easily handle multiple targets. Here’s how it works:


targets = [ '#channel1', '#channel2', 'UserA', 'UserB' ]
server.privmsg_many ( targets, ‘This is a test message.’ )

When you connect to a network, Python-IRCLib will automatically provide the server with a nickname. However, you may wish to change the nickname assigned to your application based on events or the status of your application. This is done with the nick method, which takes a single string as an argument:


server.nick ( ‘New_Name’ )

It may be necessary for your application to acquire information about the network it is operating on. Several methods are availible that send out the proper signal. However, keep in mind that you will need to set up the proper handlers to catch the server’s response. If you’ve read the previous article thorougly, then this shouldn’t be too much of a challenge. Let’s catch one event, though, just to refresh your memory. The who method sends out a “WHO” command like this:


def handleWho ( connection, event ):

   print ‘ ‘.join ( event.arguments() )

irc.add_global_handler ( ‘whoreply’, handleWho )
irc.add_global_handler ( ‘endofwho’, handleWho )

server.who ( ‘User_Name’ )

More specific information about a user can be obtained using the whois method. Again, it takes a single argument:


server.whois ( ‘User_Name’ )

Again, the server sends a response that must be caught. In the last article, I presented a list of all supported events. Go ahead and search through the list for the appropriate event codes, and create an application that catches the server’s reply to the “WHOIS” command.

The last of the “who” commands is the “WHOWAS” command. It is accessed like this:


server.whowas ( ‘User_Name’ )

{mospagebreak title=More Action Methods}

In case you need to see what time it is according to the server, you can use the time method. You simply call it, passing no arguments:


server.time()

The server replies with a “391” message. By looking through the list I gave you earlier, you will find that this equates to the “time” code.

If we need to know the administrator of a certain server, we can use the admin method. It simply sends an “ADMIN” command to the server, and the server sends back the appropriate information. The admin method takes no arguments:


server.admin()

We can get more information about the server by using the “INFO” command, which is called by the corresponding method, info. Like the admin method, the info method takes no arguments:


server.info()

The message of the day may be retreived using the motd method:


server.motd()

A list of channels might prove extremely useful to your application. For example, let’s say your application needed to join channels with over 20 users, or let’s say that your application always needed to be in the most popular channel on the network. The list method may be used, which issues the “LIST” command to the server, and the server’s response can be caught by setting handlers for the events “LISTSTART”, “LIST” and “LISTEND”:


server.list()

If you need to examine the topic of a channel, you can send a “TOPIC” command with the topic method:


server.topic ( ‘#channel’ )

If you are a channel operator, you may also use the list method to set the topic of a given channel by passing an additional argument to the method:


server.topic ( ‘#channel’, ‘New Topic’ )

Similarly, the modes of a channel may be examined by using the mode method. The method may also be used to examine user methods:


server.mode ( ‘#channel’ )
server.mode ( ‘User_Name’ )

If you wish to set a mode, the same method is used along with an additional argument:


server.mode ( ‘#channel’, ‘+m’ )

You may want to create an application that is responsible for controlling a channel. For example, let’s say you wanted to kick users who sent too many messages to the channel too quickly. The kick method is used for this:


server.kick ( ‘#channel’, ‘User_Name’ )

It might also be a good idea to leave a reason for kicking the user:


server.kick ( ‘#channel, ‘User_Name’, ‘Kicked for flooding.’ )

If your application needs a lot of power to operate, you can log on as an IRC operator:


server.oper ( ‘User_Name’, ‘password’ )

You can also send a raw string to the server using the send_raw method. It takes one argument, which is the string you want to send:


server.send_raw ( ‘NICK UserName2′ )

{mospagebreak title=Client-To-Client Protocol}

The client-to-client  (CTCP) protocol allows clients to send each other special messages and queries. For example, I’m sure you’ve encountered the command “/me action” (or, alternatively, “/describe #channel action”). This command utilizes the client-to-client protocol.

We can utilize CTCP in our application. For example, one common CTCP query is “VERSION”. This requests specifics about the target user’s IRC client. If someone queries your application, he or she will not get any data unless you work a response into your application. This is very simple to do. All it involves is setting up a function to handle a CTCP message and then checking to see if the “VERSION” command is part of the message. If it is, then we need to send a reply to the source. Let’s put this into Python by building a simple application:

import irclib

# Connection data
network = ‘irc.freenode.net’
port = 6667
channel = ‘#irclib’
nick = ‘PyTest’
name = ‘Python Test’

# Handle a CTCP query
def handleCTCP ( connection, event ):

   # Check to see if it is a “VERSION” query
   if event.arguments() [ 0 ].upper() == ‘VERSION':

      # Reply to the query, giving version information
      connection.ctcp_reply ( event.source().split ( ‘!’ ) [ 0 ], ‘VERSION Python-IRCLib’ )

# Create and IRC object and add the handler
irc = irclib.IRC()
irc.add_global_handler ( ‘ctcp’, handleCTCP )

# Connect
server = irc.server()
server.connect ( network, port, nick, ircname = name )
server.join ( channel )

# Loop
irc.process_forever()

Send your application a “VERSION” request (“/ctcp PyTest VERSION”) and check the response. As you can see, Python-IRCLib uncomplicates the process. We simply set our application up to handle the appropriate event. The function called then checks to see whether the “VERSION” request was sent. If it was, it responds with the ctcp_reply method. The ctcp_reply method takes two arguments, the target and the message.

Another common query is the “TIME” query. When your application receives a “TIME” query, it should return a string with the current local time. A readable string must be sent, not a timestamp. Let’s modify our test application to respond to “TIME” queries:

import irclib
import time

network = ‘irc.freenode.net
port = 6667
channel = ‘#irclib’
nick = ‘PyTest’
name = ‘Python Test’

def handleCTCP ( connection, event ):

   if event.arguments() [ 0 ].upper() == ‘VERSION':
      connection.ctcp_reply ( event.source().split ( ‘!’ ) [ 0 ], ‘VERSION Python-IRCLib’ )

   # Check to see if it is a “TIME” query
   elif event.arguments() [ 0 ].upper() == ‘TIME':

      # Reply to the query, giving the time
      connection.ctcp_reply ( event.source().split ( ‘!’ ) [ 0 ], ‘TIME ‘ + time.ctime() )

irc = irclib.IRC()
irc.add_global_handler ( ‘ctcp’, handleCTCP )

server = irc.server()
server.connect ( network, port, nick, ircname = name )
server.join ( channel )

irc.process_forever()

{mospagebreak title=Sending to Another Client}

Now, what if your application needs to send another client a CTCP query? First, you would call the ctcp method. Then, you would have to catch the client’s reply to your query –- if any. This is easily done. Let’s build a simple application that sends another user a “TIME” query:

import irclib

# Connection information
network = ‘irc.freenode.net’
port = 6667
channel = ‘#irclib’
nick = ‘PyTest’
name = ‘Python Test’

# Handle the reply
def handleReply ( connection, event ):

   print event.source().split ( ‘!’ ) [ 0 ] + ‘-> ‘ + event.arguments() [ 0 ] + ‘: ‘ + event.arguments() [ 1 ]

# Create an IRC object
irc = irclib.IRC()
irc.add_global_handler ( ‘ctcpreply’, handleReply )

# Create a server object and connect
server = irc.server()
server.connect ( network, port, nick, ircname = name )
server.join ( channel )

# Send the query
# Note that the username comes last
server.ctcp ( ‘TIME’, ‘User_Name’ )

# Loop
irc.process_forever()

Since the first argument sent in a reply will be the query type (“TIME”, etc.), the above handler will work on almost everything. You are not limited to the “TIME” command with the above application.

There are a few other specified commands that you might be interested in using and responding to, so I’ll describe them here. The first such command is the “ACTION” command, and I briefly mentioned it earlier. To send an “ACTION” command, you may use the action method. It is simply a shortcut method, and it is used like this:


server.action ( ‘#channel’, ‘does something interesting.’ )

The “FINGER” command is sent to users to see how long they have been idle. The user’s full name and idle time are supposed to be sent in the reply:


server.ctcp ( ‘FINGER’, ‘User_Name’ )

The “SOURCE” command is sent to users when you want to figure out where to obtain their client:


server.ctcp ( ‘SOURCE’, ‘User_Name’ )

The “PING” command is used to figure out how long it takes for a message to reach a given user. It takes a timestamp as an argument. The target client sends back the message in a reply, and the source client compares the received timestamp with the current time. The difference is the time in seconds that the message took to travel:


import time

def handleReply ( connection, event ):

   if event.arguments() [ 0 ].upper() == ‘PING':
      print event.source().split ( ‘!’ ) [ 0 ] + ‘-> ‘ + str ( time.time() – float ( event.arguments() [ 1 ] ) )
   else:
      print event.source().split ( ‘!’ ) [ 0 ] + ‘-> ‘ + event.arguments() [ 0 ] + ‘: ‘ + event.arguments() [ 1 ]

irc.add_global_handler ( ‘ctcpreply’, handleReply )

server.ctcp ( ‘PING’, ‘User_Name’, str ( time.time() ) )

The “ERRMSG” comand is used as a reply. If your application receives a CTCP query that it is not familiar with, you might want to consider sending an “ERRMSG” command, along with a message explaining that the query type is not recognized:


server.ctcp_reply ( ‘ERRMSG’, ‘User_Name’, ‘Query uknown.’ )

If the command is received as a query, then you should reply saying that no error has ocurred.

The “USERINFO” command asks for information about the user of the target client:


server.ctcp ( ‘USERINFO’, ‘User_Name’ )

When your application is given the command, you should return information about the user of your application, according to the IRC protocol documentation. However, instead of returning information about you for an automated bot, I don’t see why you couldn’t return information about your application:


server.ctcp_reply ( ‘USERINFO’, ‘User_Name’, ‘I am just a bot.’ )

Finally, the “CLIENTINFO” command is used to query a client for information about what commands it accepts:


server.ctcp ( ‘CLIENTINFO’, ‘User_Name’ )

You are, of course, not limited to the above commands in your application. You can create new commands that your applications can share with each other –- a medium for communication.

Conclusion

In the first article, you learned how to connect to an IRC network and stay connected. You also learned about events and how to catch and respond to them. In this article, you learned about methods that act as shortcuts around the IRC protocol, simplifying it so that a full understanding of the protocol is not necessary to develop an application that communicates through IRC. You also learned about the client-to-client protocol, which your application can use to query other users or other applications. Users and other applications can also query and communicate with your application.

These skills allow for the construction of a variety of IRC applications, from simple and primitive to complex and complete. The library we are using eliminates much of the tricky work, allowing us to concentrate on the logic of the applications rather than the medium through which they are communicating.

[gp-comments width="770" linklove="off" ]

antalya escort bayan antalya escort bayan Antalya escort diyarbakir escort