~ubuntu-branches/ubuntu/utopic/gozerbot/utopic

« back to all changes in this revision

Viewing changes to gozerbot/ircevent.py

  • Committer: Bazaar Package Importer
  • Author(s): Jeremy Malcolm
  • Date: 2009-09-14 09:00:29 UTC
  • mfrom: (1.1.4 upstream) (3.1.5 sid)
  • Revision ID: james.westby@ubuntu.com-20090914090029-uval0ekt72kmklxw
Tags: 0.9.1.3-3
Changed dependency on python-setuptools to python-pkg-resources
(Closes: #546435) 

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# gozerbot/ircevent.py
2
 
#
3
 
#
4
 
# http://www.irchelp.org/irchelp/rfc/rfc2812.txt
5
 
 
6
 
""" an ircevent is extracted from the IRC string received from the server """
7
 
 
8
 
__copyright__ = 'this file is in the public domain'
9
 
 
10
 
from gozerbot.generic import rlog, stripident, fix_format, fromenc
11
 
import time, re, types, copy
12
 
 
13
 
cpy = copy.deepcopy
14
 
 
15
 
def makeargrest(ievent):
16
 
    """ create ievent.args and ievent.rest .. this is needed because \
17
 
         ircevents might be created outside the parse() function """ 
18
 
    try:
19
 
        ievent.args = ievent.txt.split()[1:]
20
 
    except ValueError:
21
 
        ievent.args = []
22
 
    try:
23
 
        cmnd, ievent.rest = ievent.txt.split(' ', 1)
24
 
    except ValueError:
25
 
        ievent.rest = ""   
26
 
    ievent.command = ievent.txt.split(' ')[0]
27
 
 
28
 
class Ircevent(object):
29
 
 
30
 
    """ represents an IRC event """
31
 
    
32
 
    def __init__(self, ievent=None):
33
 
        self.jabber = False
34
 
        self.groupchat = False
35
 
        self.cmnd = None
36
 
        self.prefix = u""
37
 
        self.postfix = u""
38
 
        self.target = u""
39
 
        self.arguments = []
40
 
        self.nick = u""
41
 
        self.user = u""
42
 
        self.ruserhost = u""
43
 
        self.userhost = u""
44
 
        self.stripped = u""
45
 
        self.resource = u""
46
 
        self.channel = u""
47
 
        self.origtxt = u""
48
 
        self.txt = u""
49
 
        self.command = u""
50
 
        self.alias = u""
51
 
        self.aliased = u""
52
 
        self.time = time.time()
53
 
        self.msg = False
54
 
        self.args = []
55
 
        self.rest = u""
56
 
        self.usercmnd = 0
57
 
        self.bot = None
58
 
        self.sock = None
59
 
        self.inqueue = None
60
 
        self.queues = []
61
 
        self.printto = None
62
 
        self.speed = 5
63
 
        self.groups = None
64
 
        self.cc = u""
65
 
        self.jid = None
66
 
        self.jidchange = None
67
 
        self.conn = None
68
 
        self.to = None
69
 
        self.denied = False
70
 
        self.options = {}
71
 
        if ievent:
72
 
            self.copyin(ievent)
73
 
 
74
 
    def copyin(self, ievent):
75
 
        """ copy ievent """
76
 
        self.cmnd = cpy(ievent.cmnd)
77
 
        self.prefix = cpy(ievent.prefix)
78
 
        self.postfix = cpy(ievent.postfix)
79
 
        self.target = cpy(ievent.target)
80
 
        self.arguments = list(ievent.arguments)
81
 
        self.nick = cpy(ievent.nick)
82
 
        self.user = cpy(ievent.user)
83
 
        self.ruserhost = cpy(ievent.ruserhost)
84
 
        self.userhost = cpy(ievent.userhost)
85
 
        self.stripped = cpy(ievent.stripped)
86
 
        self.resource = cpy(ievent.resource)
87
 
        self.channel = cpy(ievent.channel)
88
 
        self.origtxt = cpy(ievent.origtxt)
89
 
        self.txt = cpy(ievent.txt)
90
 
        self.command = cpy(ievent.command)
91
 
        self.alias = cpy(ievent.alias)
92
 
        self.aliased = cpy(ievent.aliased)
93
 
        self.time = ievent.time
94
 
        self.msg = cpy(ievent.msg)
95
 
        self.args = list(ievent.args)
96
 
        self.rest = cpy(ievent.rest)
97
 
        self.usercmnd = cpy(ievent.usercmnd)
98
 
        self.bot = ievent.bot
99
 
        self.sock = ievent.sock
100
 
        self.printto = ievent.printto
101
 
        self.speed = int(ievent.speed)
102
 
        self.inqueue = ievent.inqueue
103
 
        self.queues = list(ievent.queues)
104
 
        self.cc = cpy(ievent.cc)
105
 
        self.jid = ievent.jid
106
 
        self.jidchange = ievent.jidchange
107
 
        self.conn = ievent.conn
108
 
        self.to = ievent.to
109
 
        self.denied = ievent.denied
110
 
        self.options = dict(ievent.options)
111
 
        
112
 
    def __str__(self):
113
 
        return "cmnd=%s prefix=%s postfix=%s arguments=%s nick=%s user=%s \
114
 
userhost=%s channel=%s txt='%s' command=%s args=%s rest=%s speed=%s options=%s" % \
115
 
(self.cmnd, self.prefix, self.postfix, self.arguments, self.nick, self.user, \
116
 
self.userhost, self.channel, self.txt, self.command, self.args, self.rest, \
117
 
self.speed, self.options)
118
 
 
119
 
    def __del__(self):
120
 
        if self.bot:
121
 
            self.bot.gcevents += 1
122
 
 
123
 
    def parse(self, bot, rawstr):
124
 
        """ parse raw string into ircevent """
125
 
        bot.nrevents += 1 
126
 
        rawstr = rawstr.rstrip()
127
 
        splitted = re.split('\s+', rawstr)
128
 
        # check if there is a prefix (: in front)
129
 
        if not rawstr[0] == ':':
130
 
            # no prefix .. 1st word is command
131
 
            splitted.insert(0, ":none!none@none")
132
 
            rawstr = ":none!none@none " + rawstr
133
 
        self.prefix = splitted[0][1:]
134
 
        # get nick/userhost
135
 
        nickuser = self.prefix.split('!')
136
 
        if len(nickuser) == 2:
137
 
            self.nick = nickuser[0]
138
 
            self.userhost = nickuser[1]
139
 
        self.cmnd = splitted[1]
140
 
        if pfc.has_key(self.cmnd):
141
 
            self.arguments = splitted[2:pfc[self.cmnd]+2]
142
 
            txtsplit = re.split('\s+', rawstr, pfc[self.cmnd]+2)
143
 
            self.txt = txtsplit[-1]
144
 
        else:
145
 
            self.arguments = splitted[2:]
146
 
        # 1st argument is target
147
 
        if self.arguments:
148
 
            self.target = self.arguments[0]
149
 
        self.postfix = ' '.join(self.arguments)
150
 
        # check if target is text
151
 
        if self.target and self.target.startswith(':'):
152
 
            self.txt = ' '.join(self.arguments)
153
 
        # strip strarting ':' from txt
154
 
        if self.txt:
155
 
            if self.txt[0] == ":":
156
 
                self.txt = self.txt[1:]
157
 
        rlog(0, 'ircevent',"%s %s %s" % (self.cmnd, self.arguments, self.txt))
158
 
        # determine channel
159
 
        if self.cmnd == 'PRIVMSG':
160
 
            self.channel = self.arguments[0]
161
 
        elif self.cmnd == 'JOIN' or self.cmnd == 'PART':
162
 
            if self.arguments:
163
 
                self.channel = self.arguments[0]
164
 
            else:
165
 
                self.channel = self.txt
166
 
        elif self.cmnd == 'MODE':
167
 
            self.channel = self.arguments[0]
168
 
        elif self.cmnd == 'TOPIC':
169
 
            self.channel = self.arguments[0]
170
 
        elif self.cmnd == 'KICK':
171
 
            self.channel = self.arguments[0]
172
 
        elif self.cmnd == '353':
173
 
            self.channel = self.arguments[2]
174
 
        elif self.cmnd == '324':
175
 
            self.channel = self.arguments[1]
176
 
        self.channel = self.channel.lower()
177
 
        if self.userhost:
178
 
            # userhost before possible stripident
179
 
            self.ruserhost = self.userhost
180
 
            self.userhost = stripident(self.userhost)
181
 
            # jabber compat .. this is userhost on irc
182
 
            self.stripped = self.userhost
183
 
            # determine user
184
 
            self.user = self.userhost.split('@')[0]
185
 
        self.origtxt = self.txt
186
 
        self.channel = self.channel.strip()
187
 
        rlog(-1, 'ircevent', self)
188
 
        try:
189
 
            nr = int(self.cmnd)
190
 
            if nr > 399:
191
 
                rlog(10, bot.name + '.error', '%s: %s' % (self.cmnd, self.txt))
192
 
        except ValueError:
193
 
            pass
194
 
        return self
195
 
 
196
 
    def reply(self, txt, result=None, nick=None, dot=False, nritems=False, \
197
 
nr=False):
198
 
        """ reply txt .. first check if queue then if DCC then /msg 
199
 
            otherwise assume channel
200
 
        """
201
 
        if result == []:
202
 
            return
203
 
        restxt = ""
204
 
        if type(result) == types.DictType:
205
 
            for i, j in result.iteritems():
206
 
                if type(j) == types.ListType:
207
 
                    z = ' .. '.join(j)
208
 
                else:
209
 
                    z = j                 
210
 
                restxt += "[%s] %s %s " % (i, z, dot)
211
 
            if restxt:
212
 
                restxt = restxt[:-6]
213
 
        lt = False
214
 
        if type(txt) == types.ListType and not result:
215
 
            result = txt
216
 
            origtxt = u""
217
 
            lt = True
218
 
        else:
219
 
            origtxt = txt
220
 
        if result:
221
 
            lt = True
222
 
        if self.queues:
223
 
            for i in self.queues:
224
 
                if restxt:
225
 
                    i.put_nowait(restxt)
226
 
                elif lt:
227
 
                    for j in result:
228
 
                        i.put_nowait(j)
229
 
                else:
230
 
                    i.put_nowait(txt)
231
 
            return
232
 
        if not self.bot:
233
 
            rlog(10, 'irc', 'no bot defined in ircevent')
234
 
            return
235
 
        pretxt = origtxt
236
 
        if lt and not restxt:
237
 
            res = []
238
 
            for i in result:
239
 
                if type(i) == types.ListType or type(i) == types.TupleType:
240
 
                    res.extend(i)
241
 
                else:
242
 
                    res.append(i)
243
 
            result = res
244
 
            if nritems:
245
 
                if len(result) > 1:
246
 
                    pretxt += "(%s items) .. " % len(result)
247
 
            txtlist = result
248
 
            if not nr is False:
249
 
                try:
250
 
                    start = int(nr)
251
 
                except ValueError:
252
 
                    start = 0
253
 
                txtlist2 = []
254
 
                teller = start
255
 
                for i in txtlist:
256
 
                    txtlist2.append(u"%s) %s" % (teller, i))
257
 
                    teller += 1
258
 
                txtlist = txtlist2
259
 
            if dot == True:
260
 
                restxt = ' .. '.join(txtlist)
261
 
            elif dot:
262
 
                restxt = dot.join(txtlist)
263
 
            else:
264
 
                restxt = ' '.join(txtlist)
265
 
        if pretxt:
266
 
            restxt = pretxt + restxt
267
 
        if self.cmnd == 'DCC' and self.sock:
268
 
            self.bot.say(self.sock, restxt, speed=self.speed)
269
 
            return
270
 
        if nick:
271
 
            self.bot.say(nick, restxt, fromm=nick, speed=self.speed)
272
 
            return
273
 
        if self.msg:
274
 
            self.bot.say(self.nick, restxt, fromm=self.nick, speed=self.speed)
275
 
            return
276
 
        # check if bot is in silent mode .. if so use /msg 
277
 
        silent = False
278
 
        channel = self.printto or self.channel
279
 
        try:
280
 
            silent = self.bot.channels[channel]['silent']
281
 
        except (KeyError, TypeError):
282
 
            pass
283
 
        if silent:
284
 
                self.bot.say(self.nick, restxt, fromm=self.nick, \
285
 
speed=self.speed)
286
 
                return
287
 
        if self.printto:
288
 
            self.bot.say(self.printto, restxt, fromm=self.nick, \
289
 
speed=self.speed)
290
 
            return
291
 
        else:
292
 
            self.bot.say(self.channel, restxt, fromm=self.nick, \
293
 
speed=self.speed)
294
 
 
295
 
    def missing(self, txt):
296
 
        """ show what arguments are missing """
297
 
        if self.origtxt:
298
 
            splitted = self.origtxt.split()
299
 
            if self.bot.nick in splitted[0]:
300
 
                try:
301
 
                    cmnd = splitted[1]
302
 
                except IndexError:
303
 
                    cmnd = splitted[0]
304
 
            elif 'cmnd' in splitted[0]:
305
 
                try:
306
 
                    cmnd = splitted[2]
307
 
                except IndexError:
308
 
                    cmnd = splitted[0]
309
 
            else:
310
 
                if self.msg:
311
 
                    cmnd = splitted[0]
312
 
                else:
313
 
                    if self.aliased:
314
 
                        cmnd = self.aliased
315
 
                    else:
316
 
                        cmnd = splitted[0][1:]
317
 
            self.reply(cmnd + ' ' + txt)
318
 
        else:
319
 
            self.reply('missing origtxt: %s' % txt)
320
 
 
321
 
# postfix count aka how many arguments
322
 
 
323
 
pfc = {}
324
 
pfc['NICK'] = 0
325
 
pfc['QUIT'] = 0
326
 
pfc['SQUIT'] = 1
327
 
pfc['JOIN'] = 0
328
 
pfc['PART'] = 1
329
 
pfc['TOPIC'] = 1
330
 
pfc['KICK'] = 2
331
 
pfc['PRIVMSG'] = 1
332
 
pfc['NOTICE'] = 1
333
 
pfc['SQUERY'] = 1
334
 
pfc['PING'] = 0
335
 
pfc['ERROR'] = 0
336
 
pfc['AWAY'] = 0
337
 
pfc['WALLOPS'] = 0
338
 
pfc['INVITE'] = 1
339
 
pfc['001'] = 1
340
 
pfc['002'] = 1
341
 
pfc['003'] = 1
342
 
pfc['004'] = 4
343
 
pfc['005'] = 15
344
 
pfc['302'] = 1
345
 
pfc['303'] = 1
346
 
pfc['301'] = 2
347
 
pfc['305'] = 1
348
 
pfc['306'] = 1
349
 
pfc['311'] = 5
350
 
pfc['312'] = 3
351
 
pfc['313'] = 2
352
 
pfc['317'] = 3
353
 
pfc['318'] = 2
354
 
pfc['319'] = 2
355
 
pfc['314'] = 5
356
 
pfc['369'] = 2
357
 
pfc['322'] = 3
358
 
pfc['323'] = 1
359
 
pfc['325'] = 3
360
 
pfc['324'] = 4
361
 
pfc['331'] = 2
362
 
pfc['332'] = 2
363
 
pfc['341'] = 3
364
 
pfc['342'] = 2
365
 
pfc['346'] = 3
366
 
pfc['347'] = 2
367
 
pfc['348'] = 3
368
 
pfc['349'] = 2
369
 
pfc['351'] = 3
370
 
pfc['352'] = 7
371
 
pfc['315'] = 2
372
 
pfc['353'] = 3
373
 
pfc['366'] = 2
374
 
pfc['364'] = 3
375
 
pfc['365'] = 2
376
 
pfc['367'] = 2
377
 
pfc['368'] = 2
378
 
pfc['371'] = 1
379
 
pfc['374'] = 1
380
 
pfc['375'] = 1
381
 
pfc['372'] = 1
382
 
pfc['376'] = 1
383
 
pfc['381'] = 1
384
 
pfc['382'] = 2
385
 
pfc['383'] = 5
386
 
pfc['391'] = 2
387
 
pfc['392'] = 1
388
 
pfc['393'] = 1
389
 
pfc['394'] = 1
390
 
pfc['395'] = 1
391
 
pfc['262'] = 3
392
 
pfc['242'] = 1
393
 
pfc['235'] = 3
394
 
pfc['250'] = 1
395
 
pfc['251'] = 1
396
 
pfc['252'] = 2
397
 
pfc['253'] = 2
398
 
pfc['254'] = 2
399
 
pfc['255'] = 1
400
 
pfc['256'] = 2
401
 
pfc['257'] = 1
402
 
pfc['258'] = 1
403
 
pfc['259'] = 1
404
 
pfc['263'] = 2
405
 
pfc['265'] = 1
406
 
pfc['266'] = 1
407
 
pfc['401'] = 2
408
 
pfc['402'] = 2
409
 
pfc['403'] = 2
410
 
pfc['404'] = 2
411
 
pfc['405'] = 2
412
 
pfc['406'] = 2
413
 
pfc['407'] = 2
414
 
pfc['408'] = 2
415
 
pfc['409'] = 1
416
 
pfc['411'] = 1
417
 
pfc['412'] = 1
418
 
pfc['413'] = 2
419
 
pfc['414'] = 2
420
 
pfc['415'] = 2
421
 
pfc['421'] = 2
422
 
pfc['422'] = 1
423
 
pfc['423'] = 2
424
 
pfc['424'] = 1
425
 
pfc['431'] = 1
426
 
pfc['432'] = 2
427
 
pfc['433'] = 2
428
 
pfc['436'] = 2
429
 
pfc['437'] = 2
430
 
pfc['441'] = 3
431
 
pfc['442'] = 2
432
 
pfc['443'] = 3
433
 
pfc['444'] = 2
434
 
pfc['445'] = 1
435
 
pfc['446'] = 1
436
 
pfc['451'] = 1
437
 
pfc['461'] = 2
438
 
pfc['462'] = 1
439
 
pfc['463'] = 1
440
 
pfc['464'] = 1
441
 
pfc['465'] = 1
442
 
pfc['467'] = 2
443
 
pfc['471'] = 2
444
 
pfc['472'] = 2
445
 
pfc['473'] = 2
446
 
pfc['474'] = 2
447
 
pfc['475'] = 2
448
 
pfc['476'] = 2
449
 
pfc['477'] = 2
450
 
pfc['478'] = 3
451
 
pfc['481'] = 1
452
 
pfc['482'] = 2
453
 
pfc['483'] = 1
454
 
pfc['484'] = 1
455
 
pfc['485'] = 1
456
 
pfc['491'] = 1
457
 
pfc['501'] = 1
458
 
pfc['502'] = 1