ActiveState Code

Recipe 299411: Connect to an IRC server and store messages into a file


You want to connect to an IRC server, join a channel and store private message into a file on your hard disk for future reading. I haven't tried but I think you can execute this code from an hosting always connected to the internet and read the message through a web browser.

Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import socket, string

#some user data, change as per your taste
SERVER = '2night.azzurra.org'
PORT = 6667
NICKNAME = 'test_py'
CHANNEL = '#test_py'

#open a socket to handle the connection
IRC = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

#open a connection with the server
def irc_conn():
    IRC.connect((SERVER, PORT))

#simple function to send data through the socket
def send_data(command):
    IRC.send(command + '\n')

#join the channel
def join(channel):
    send_data("JOIN %s" % channel)

#send login data (customizable)
def login(nickname, username='user', password = None, realname='Pythonist', hostname='Helena', servername='Server'):
    send_data("USER %s %s %s %s" % (username, hostname, servername, realname))
    send_data("NICK " + nickname)

irc_conn()
login(NICKNAME)
join(CHANNEL)

while (1):
    buffer = IRC.recv(1024)
    msg = string.split(buffer)
    if msg[0] == "PING": #check if server have sent ping command
        send_data("PONG %s" % msg[1]) #answer with pong as per RFC 1459
    if msg [1] == 'PRIVMSG' and msg[2] == NICKNAME:
        filetxt = open('/tmp/msg.txt', 'a+') #open an arbitrary file to store the messages
        nick_name = msg[0][:string.find(msg[0],"!")] #if a private message is sent to you catch it
        message = ' '.join(msg[3:])
        filetxt.write(string.lstrip(nick_name, ':') + ' -> ' + string.lstrip(message, ':') + '\n') #write to the file
        filetxt.flush() #don't wait for next message, write it now!

Discussion

This recipe show how simple is the use of sockets to handle connection with every Internet protocol, just know the RFC for that protocol. A lot of improvements can be done, for example you can send a confirmation to who wrote you every time you store their message.

The tricky part is this one:

if msg[0] == "PING": send_data("PONG %s" % msg[1])

As per RFC, the server will check if you connection is alive sending you a PING command, if you don't answer with a PONG your connection will die with a timeout error, you have to send back the data contained in msg[1]. If you are curious to see which kind of information the server has sent you can add a simple print statement:

if msg[0] == "PING": sys.stdout.write(msg) send_data("PONG %s" % msg[1])

Comments

  1. 1. At 12:57 a.m. on 17 aug 2004, Anonymous said:

    Shorter, more featureful example.

    from twisted.internet import reactor, protocol
    from twisted.protocols import irc
    
    class LoggingIRCClient(irc.IRCClient):
        logfile = file('/tmp/msg.txt', 'a+')
    
        nickname = 'logging_bot'
    
        def signedOn(self):
            self.join('#test_py')
    
        def privmsg(self, user, channel, message):
            self.logfile.write(user.split('!')[0] + ' -> ' + message + '\n')
            self.logfile.flush()
    
    def main():
        f = protocol.ReconnectingClientFactory()
        f.protocol = LoggingIRCClient
        reactor.connectTCP('irc.freenode.net', 6667, f)
        reactor.run()
    
    if __name__ == '__main__':
        main()
    
  2. 2. At 4:03 a.m. on 17 aug 2004, Gian Mario Tagliaretti (the author) said:

    twisted is not part of std python. Thank's for you comment but the great twisted package is not part of the standard distribution, the meaning of this recipe is how to use sockets to connect an IRC server using only std python code.

Sign in to comment