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

« back to all changes in this revision

Viewing changes to build/lib/gozerbot/irc/ircevent.py

  • Committer: Package Import Robot
  • Author(s): Jeremy Malcolm
  • Date: 2012-04-03 21:58:28 UTC
  • mfrom: (3.1.11 sid)
  • Revision ID: package-import@ubuntu.com-20120403215828-6mik0tzug5na93la
Tags: 0.99.1-2
* Removes logfiles on purge (Closes: #668767)
* Reverted location of installed files back to /usr/lib/gozerbot.

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