f975942f07f52012d5b60f7591b36bf5265fdaea
[gpxe.git] / contrib / errcode / gpxebot.py
1 #!/usr/bin/env python
2 # Copyright (C) 2008 Stefan Hajnoczi <stefanha@gmail.com>.
3 #
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License as
6 # published by the Free Software Foundation; either version 2 of the
7 # License, or any later version.
8 #
9 # This program is distributed in the hope that it will be useful, but
10 # WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 # General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 import re
18 import socket
19 import errcode
20
21 HOST = 'irc.freenode.net'
22 PORT = 6667
23 NICK = 'gpxebot'
24 CHAN = '#etherboot'
25 NICKSERV_PASSWORD = None
26 IDENT = 'gpxebot'
27 REALNAME = 'gPXE bot'
28
29 ERRCODE_RE = re.compile(r'(errcode|Error)\s+((0x)?[0-9a-fA-F]{8})')
30
31 NO_ARGS = -1
32
33 handlers = {}
34
35 def nick_from_mask(mask):
36     return (mask.find('!') > -1 and mask.split('!', 1)[0]) or mask
37
38 def autojoin():
39     del handlers['376']
40     if NICKSERV_PASSWORD:
41         pmsg('nickserv', 'identify %s' % NICKSERV_PASSWORD)
42     if CHAN:
43         cmd('JOIN %s' % CHAN)
44
45 def ping(_, arg):
46     cmd('PONG %s' % arg)
47
48 def privmsg(_, target, msg):
49     if target == CHAN:
50         replyto = target
51         if msg.find(NICK) == -1:
52             return
53     elif target == NICK:
54         replyto = nick_from_mask(who)
55     m = ERRCODE_RE.search(msg)
56     if m:
57         try:
58             pmsg(replyto, str(errcode.Errcode(int(m.groups()[1], 16))))
59         except ValueError:
60             pass
61     if msg.find('help') > -1:
62         pmsg(replyto, 'I look up gPXE error codes.  Message me like this:')
63         pmsg(replyto, 'errcode 0x12345678  OR  Error 0x12345678')
64
65 def add_handler(command, handler, nargs):
66     handlers[command] = (handler, nargs)
67
68 def cmd(msg):
69     sock.sendall('%s\r\n' % msg)
70
71 def pmsg(target, msg):
72     cmd('PRIVMSG %s :%s' % (target, msg))
73
74 def dispatch(args):
75     command = args[0]
76     if command in handlers:
77         h = handlers[command]
78         if h[1] == NO_ARGS:
79             h[0]()
80         elif len(args) == h[1]:
81             h[0](*args)
82
83 def parse(line):
84     if line[0] == ':':
85         who, line = line.split(None, 1)
86         who = who[1:]
87     else:
88         who = None
89     args = []
90     while line and line[0] != ':' and line.find(' ') != -1:
91         fields = line.split(None, 1)
92         if len(fields) == 1:
93             fields.append(None)
94         arg, line = fields
95         args.append(arg)
96     if line:
97         if line[0] == ':':
98             args.append(line[1:])
99         else:
100             args.append(line)
101     return who, args
102
103 add_handler('376', autojoin, NO_ARGS)
104 add_handler('PING', ping, 2)
105 add_handler('PRIVMSG', privmsg, 3)
106
107 sock = socket.socket()
108 sock.connect((HOST, PORT))
109 cmd('NICK %s' % NICK)
110 cmd('USER %s none none :%s' % (IDENT, REALNAME))
111
112 rbuf = ''
113 while True:
114     r = sock.recv(4096)
115     if not r:
116         break
117     rbuf += r
118
119     while rbuf.find('\r\n') != -1:
120         line, rbuf = rbuf.split('\r\n', 1)
121         if not line:
122             continue
123         who, args = parse(line)
124         dispatch(args)