Home arrow Python arrow Basic IRC Tasks

Basic IRC Tasks

Following up on an earlier DevShed article covering the basics of Python and Internet Relay Chat, this article takes some common IRC tasks, such as listing the users in a given channel or manipulating a channel's modes, and shows how to turn them into Pyton code.

TABLE OF CONTENTS:
  1. Basic IRC Tasks
  2. Communication Tasks
  3. Channel Related Tasks
  4. User Related Tasks
  5. Processing Information
By: Peyton McCullough
Rating: starstarstarstarstar / 4
April 18, 2005

print this article
SEARCH DEV SHED

TOOLS YOU CAN USE

advertisement

Introduction

In “Python and IRC,” I explained the basics of connecting to an IRC server and sending a few messages. Obviously, however, you know that there is much more to IRC than I explained. Forgive the cliché, but what the last article covers is truly only the tip of the iceberg that is the Internet Relay Chat Protocol.

This article will cover some more basics. We'll take some common tasks, such as listing the users in a given channel or manipulating a channel's modes, and turn them into Python code. If you haven't read “Python and IRC,” this article won't do you much good. Even if you have, it might be helpful to speed through it and refresh your memory. With that said, let's move on.

Creating an IRC Module

If I loaded each and every example in this article with basic socket garbage, not only would it be incredibly pointless, but it would be annoying and difficult to sort through to actually get the important stuff. The solution is to create a module that will do all the socket work for us. Actually, scratch that, why not turn this article a bit and build a module that will do socket work and basic IRC tasks? That sounds a lot better, and, as a bonus, all the code we produce can be recycled in future applications.

Let's call our module irchat. In ths module, let's create a class, IRC. Our code will be put into IRC's methods. When an instance of IRC is created, Python will automatically connect to the network specified in the arguments, using the data specified in the arguments. To avoid repetition of “\r\n”, we'll create a send method that automatically appends “\r\n” to the given text and then sends it over. To connect to the server, we're going to have to specify a nickname using IRC's “NICK” command. Since you may want your Python client to use the “NICK” command again, we'll make a method for it. A quit method would also be helpful. Enough lecturing, though, let's get to some code:

import socket

class IRC:

   def __init__ ( self, network, port, name, hostName, serverName, realName ):

      self.network =  network

      self.port = port

      self.hostName = hostName

      self.serverName = serverName

      self.realName = realName

      self.socket = socket.socket ( socket.AF_INET, socket.SOCK_STREAM )

      self.socket.connect ( ( self.network, self.port ) )

      self.nick ( name )

      self.send ( 'USER ' + self.name + ' ' + self.serverName + ' ' + self.hostName + ' :' + self.realName )

   def quit ( self ):

      self.send ( 'QUIT' )

      self.socket.close()

   def send ( self, text ):

      self.socket.send ( text + '\r\n' )

   def nick ( self, name ):

      self.name = name

      self.send ( 'NICK ' + self.name )

The above module will handle the very basics. When an instance of IRC is created and the required data is passed to it, a socket is created and connected. The nickname is then set using the nick method, which takes advantage of the send method. The “USER” command is then sent. No suprises there.

To use the module, you would do something like this:

import irchat

conn = irchat.IRC ( 'irc.network.com', 6667, 'PyIRC', 'PyIRC', 'PyIRC', 'John Doe' )

# Insert code here

conn.quit()

From here on, we will be adding methods to the IRC class. Keep that in mind. Don't go off and create lone functions and later wonder why nothing happens.

Let's catch up with “Python and IRC” now. One of the most important things that “Python and IRC” teaches us is how to receive messages from the server and take them apart, making them easier to process. To do this, we must first create a method, recv, which receives data from the network and then splits it up. The data should be split at “\r\n” (which effectively splits it into commands) and added to a variable, queue. Remember that data will get cut off, too, so we have to store partial data in a variable, partial, and let it get picked up by queue on the next call to recv. This may sound complicated, but it's pretty simple:

queue = []

partial = ''

def recv ( self, size = 2048 ):

commands = self.socket.recv ( size ).split ( '\r\n' )

if len ( self.partial ):

   commands [ 0 ] = self.partial + commands [ 0 ]

   self.partial = ''

if len ( commands [ -1 ] ):

   self.partial = commands [ -1 ]

   self.queue.extend ( commands [ :-1 ] )

else:

   self.queue.extend ( commands )

We must now create a method, retrieve, that pops the first command off of queue and returns it. If the queue is empty, the method should return False:

def retrieve ( self ):

   if len ( self.queue ):

      command = self.queue [ 0 ]

      self.queue.pop ( 0 )

      return command

   else:

      return False

Finally, we have to create a method that dismantles individual commands into something more workable. Recall what a message from the server looks like:

:source some parameters

:source some parameters :another parameter

Pulling that apart isn't too complicated, although it may seem like it. If we split the string in the correct places, we can manage:

def dismantle ( self, command ):

   if command:

      source = command.split ( ':' ) [ 1 ].split ( ' ' ) [ 0 ]

      parameters = command.split ( ':' ) [ 1 ].split ( ' ' ) [ 1: ]

      if not len ( parameters [ -1 ] ):

         parameters.pop()

      if command.count ( ':' ) > 1:

         parameters.append ( ''.join ( command.split ( ':' ) [ 2: ] ) )

      return source, parameters

To clarify, the irchat module should now look something like this:

import socket

class IRC:

   queue = []

   partial = ''

   def __init__ ( self, network, port, name, hostName, serverName, realName ):

      self.network =  network

      self.port = port

      self.hostName = hostName

      self.serverName = serverName

      self.realName = realName

      self.socket = socket.socket ( socket.AF_INET, socket.SOCK_STREAM )

      self.socket.connect ( ( self.network, self.port ) )

      self.nick ( name )

      self.send ( 'USER ' + self.name + ' ' + self.serverName + ' ' + self.hostName + ' :' + self.realName )

   def quit ( self ):

      self.send ( 'QUIT' )

      self.socket.close()

   def send ( self, text ):

      self.socket.send ( text + '\r\n' )

   def nick ( self, name ):

      self.name = name

      self.send ( 'NICK ' + self.name )

   def recv ( self, size = 2048 ):

      commands = self.socket.recv ( size ).split ( '\r\n' )

      if len ( self.partial ):

         commands [ 0 ] = self.partial + commands [ 0 ]

         self.partial = ''

      if len ( commands [ -1 ] ):

         self.partial = commands [ -1 ]

         self.queue.extend ( commands [ :-1 ] )

      else:

         self.queue.extend ( commands )

   def retrieve ( self ):

      if len ( self.queue ):

         command = self.queue [ 0 ]

         self.queue.pop ( 0 )

         return command

      else:

         return False

   def dismantle ( self, command ):

      if command:

         source = command.split ( ':' ) [ 1 ].split ( ' ' ) [ 0 ]

         parameters = command.split ( ':' ) [ 1 ].split ( ' ' ) [ 1: ]

         if not len ( parameters [ -1 ] ):

            parameters.pop()

         if command.count ( ':' ) > 1:

            parameters.append ( ''.join ( command.split ( ':' ) [ 2: ] ) )

         return source, parameters

Here's one way to use our new module. The following script connects to an IRC network and spawns a thread to constantly call the recv module, which, as you know, puts commands into the queue list. It then dismantles the data and prints it out in a neater form:

import irchat

import thread

def autoRecv():

   while True:

      conn.recv()

conn = irchat.IRC ( 'irc.network.com, 6667, 'PyBot', 'PyBot', 'PyBot', 'John Doe' )

thread.start_new_thread ( autoRecv, () )

while True:

   x = conn.dismantle ( conn.retrieve() )

   if x:

      print x [ 0 ] + ':', x [ 1 ]

      print

Let's move on. 



 
 
>>> More Python Articles          >>> More By Peyton McCullough
 

blog comments powered by Disqus
escort Bursa Bursa escort Antalya eskort
   

PYTHON ARTICLES

- Python Big Data Company Gets DARPA Funding
- Python 32 Now Available
- Final Alpha for Python 3.2 is Released
- Python 3.1: String Formatting
- Python 3.1: Strings and Quotes
- Python 3.1: Programming Basics and Strings
- Tuples and Other Python Object Types
- The Dictionary Python Object Type
- String and List Python Object Types
- Introducing Python Object Types
- Mobile Programming using PyS60: Advanced UI ...
- Nested Functions in Python
- Python Parameters, Functions and Arguments
- Python Statements and Functions
- Statements and Iterators in Python

Developer Shed Affiliates

 


Dev Shed Tutorial Topics: