~ubuntu-branches/ubuntu/precise/gozerbot/precise

« back to all changes in this revision

Viewing changes to build/lib/gozerplugs/plugs/log.py

  • Committer: Bazaar Package Importer
  • Author(s): Jeremy Malcolm
  • Date: 2008-06-02 19:26:39 UTC
  • mfrom: (1.1.3 upstream) (3.1.1 lenny)
  • Revision ID: james.westby@ubuntu.com-20080602192639-3rn65nx4q1sgd6sy
Tags: 0.8.1-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# plugs/log.py
2
 
#
3
 
#
4
 
 
5
 
""" logging """
6
 
 
7
 
__copyright__ = 'this file is in the public domain'
8
 
 
9
 
from gozerbot.generic import rlog, handle_exception, elapsedstring, dmy, \
10
 
hourmin, lockdec, strtotime
11
 
from gozerbot.commands import cmnds
12
 
from gozerbot.examples import examples
13
 
from gozerbot.callbacks import callbacks, jcallbacks
14
 
from gozerbot.plughelp import plughelp
15
 
from gozerbot.monitor import saymonitor, jabbermonitor
16
 
from gozerbot.aliases import aliases, aliasdel
17
 
from gozerbot.users import users
18
 
import glob, re, thread, pickle, os, mmap, time
19
 
 
20
 
plughelp.add('log', 'logs related commands')
21
 
 
22
 
# check if logs dir exists if not create it
23
 
if not os.path.isdir('logs'):
24
 
    os.mkdir('logs')
25
 
 
26
 
loglock = thread.allocate_lock()
27
 
locked = lockdec(loglock)
28
 
 
29
 
class Logs(object):
30
 
 
31
 
    """ hold handles to log files (per channel) """
32
 
 
33
 
    def __init__(self, logdir):
34
 
        self.logdir = logdir
35
 
        self.maps = {}
36
 
        self.files = {}
37
 
        self.filenames = {}
38
 
        self.lock = thread.allocate_lock()
39
 
        self.loglist = []
40
 
        try:
41
 
            loglistfile = open(self.logdir + os.sep + 'loglist', 'r')
42
 
            self.loglist = pickle.load(loglistfile)
43
 
        except:
44
 
            self.loglist = []
45
 
        rlog(0, 'logs', 'loglist is %s' % str(self.loglist))
46
 
        # open log files in append mode
47
 
        for i in glob.glob(self.logdir + os.sep + '*.log'):
48
 
            reresult = re.search('logs%s(.+)\.' % os.sep, i)
49
 
            filename = reresult.group(1)
50
 
            if not filename:
51
 
                rlog(10, 'logs', "can't determine channel name")
52
 
                continue
53
 
            logfile = open(i, 'a')
54
 
            if logfile:
55
 
                self.files[filename] = logfile
56
 
                self.filenames[filename.lower()] = i
57
 
                rlog(1, 'logs', 'adding file %s' % i)
58
 
            else:
59
 
                rlog(10, 'logs', 'failed to open %s' % i)
60
 
 
61
 
    def save(self):
62
 
        """ save loglist """
63
 
        try:
64
 
            self.lock.acquire()
65
 
            picklefile = open(self.logdir + os.sep + 'loglist', 'w')
66
 
            pickle.dump(self.loglist, picklefile)
67
 
            rlog(0, 'logs', 'loglist saved')
68
 
        finally:
69
 
            self.lock.release()
70
 
 
71
 
    def close(self):
72
 
        """ close log files """
73
 
        try:
74
 
            self.lock.acquire()
75
 
            for i in self.files.keys():
76
 
                rlog(10, 'logs', 'closing ' + str(i))
77
 
                self.files[i].close()
78
 
        finally:
79
 
            self.lock.release()
80
 
        self.save()
81
 
 
82
 
    def size(self, channel):
83
 
        """ get size of log file """
84
 
        if channel[0] in ['#', '!', '&', '+']:
85
 
            chan = channel[1:].lower()
86
 
        else:
87
 
            chan = channel.lower()
88
 
        try:
89
 
            size = os.stat(self.filenames[chan])[6]
90
 
            return size
91
 
        except IOError:
92
 
            return
93
 
 
94
 
    def add(self, channel):
95
 
        """ add logfile for channel """
96
 
        if channel[0] in ['#', '!', '&', '+']:
97
 
            chan = channel[1:].lower()
98
 
        else:
99
 
            chan = channel.lower()
100
 
        filename = self.logdir + os.sep + chan + '.log'
101
 
        rlog(10, 'logs', 'adding logfile %s' % chan)
102
 
        if self.files.has_key(chan):
103
 
            rlog(10, 'logs', 'already opened file %s' % chan)
104
 
            return 1
105
 
        try:
106
 
            logfile = open(filename,'a')
107
 
            self.files[chan] = logfile
108
 
            self.filenames[chan] = filename
109
 
            if channel not in self.loglist:
110
 
                self.loglist.append(channel)
111
 
            return 1
112
 
        except Exception, ex:
113
 
            handle_exception()
114
 
            return 0
115
 
 
116
 
    def logbot(self, name, ttime, channel, txt):
117
 
        """ log stuff spoken by the bot """
118
 
        if channel not in self.loglist:
119
 
            rlog(1, 'logs', "%s not in loglist" % channel)
120
 
            return
121
 
        if channel[0] in ['#', '!', '&', '+']:
122
 
            chan = channel[1:].lower()
123
 
        else:
124
 
            chan = channel.lower()
125
 
        filename = self.logdir + os.sep + chan + '.log'
126
 
        if not self.files.has_key(chan):
127
 
            if not self.add(channel):
128
 
                rlog(1, 'logs', "can't create logfile %s" % filename)
129
 
                return
130
 
        logfile = self.files[chan]
131
 
        logitem = (name, ttime, 'bot', 'bot@bot', txt)
132
 
        rlog(-1, 'logs', 'logging [%s] <%s> %s ==> %s' % (name, 'bot', txt, \
133
 
filename))
134
 
        # write the data to file (comma seperated)
135
 
        try:
136
 
            self.lock.acquire()
137
 
            logfile.write('%s,%s,%s,%s,%s\n' % logitem)
138
 
            logfile.flush()
139
 
        finally:
140
 
            self.lock.release()
141
 
 
142
 
    def log(self, name, ttime, ievent):
143
 
        """ log ircevent """
144
 
        if ievent.nick == ievent.bot.nick:
145
 
            ievent.nick = 'bot'
146
 
            ievent.userhost = 'bot@bot'
147
 
        channel = ievent.channel
148
 
        if channel not in self.loglist:
149
 
            rlog(1, 'logs', "%s not in loglist" % channel)
150
 
            return
151
 
        if channel[0] in ['#', '!', '&', '+']:
152
 
            chan = channel[1:].lower()
153
 
        else:
154
 
            chan = channel.lower()
155
 
        filename = self.logdir + os.sep + chan + '.log'
156
 
        if not self.files.has_key(chan):
157
 
            if not self.add(ievent.channel):
158
 
                rlog(1, 'logs', "can't create logfile %s" % filename)
159
 
                return
160
 
        # put ievent.cmnd as first txt
161
 
        if ievent.cmnd == 'PRIVMSG' or ievent.cmnd == 'Message':
162
 
            if ievent.usercmnd:
163
 
                tmp = "CMND: " + ievent.txt
164
 
            else:
165
 
                if ievent.txt.startswith('\001ACTION'):
166
 
                    txt = ievent.txt[7:-1]
167
 
                    tmp = "PRIVMSG: /me " + txt
168
 
                else:
169
 
                    tmp = "PRIVMSG: " + ievent.txt
170
 
        elif ievent.cmnd == 'MODE':
171
 
            tmp = "MODE: " + ievent.postfix
172
 
        elif ievent.cmnd == 'PART':
173
 
            tmp = "PART: " + ievent.channel
174
 
        elif ievent.cmnd == 'JOIN':
175
 
            tmp = "JOIN: " + ievent.channel
176
 
        else:
177
 
            return
178
 
        logfile = self.files[chan]
179
 
        logitem = (name, ttime, ievent.nick, ievent.userhost, tmp)
180
 
        rlog(-1, 'logs', 'logging [%s] <%s> %s ==> %s' % (name, ievent.nick, \
181
 
ievent.txt, filename))
182
 
        # write the data to file (comma seperated)
183
 
        try:
184
 
            self.lock.acquire()
185
 
            logfile.write('%s,%s,%s,%s,%s\n' % logitem)
186
 
            logfile.flush()
187
 
        finally:
188
 
            self.lock.release()
189
 
 
190
 
    def getmmap(self, channel):
191
 
        """ get an mmap of a channel .. as of 0.8 this just returns the 
192
 
            open logfile
193
 
        """
194
 
        if channel[0] in ['#', '!', '&', '+']:
195
 
            chan = channel[1:].lower()
196
 
        else:
197
 
            chan = channel.lower()
198
 
        try:
199
 
            filename = self.filenames[chan]
200
 
        except KeyError:
201
 
            rlog(10, 'log', 'logging is not enabled in %s' % channel)
202
 
            return
203
 
        logfile = open(filename, 'r')
204
 
        #size = self.size(channel)
205
 
        #if size == 0:  
206
 
        #    return None
207
 
        #logmap = mmap.mmap(logfile.fileno(), size, mmap.MAP_SHARED, \
208
 
#access=mmap.ACCESS_READ)
209
 
        return logfile
210
 
 
211
 
    def loop(self, logmap, nrtimes, func, withbot=False, withcmnd=False):
212
 
        """ loop over the logmap """
213
 
        logmap.seek(0)
214
 
        teller = 0
215
 
        times = 0
216
 
        for line in logmap:
217
 
            teller += 1
218
 
            if teller % 100000 == 0:
219
 
                time.sleep(0.0001)
220
 
            try:
221
 
                (botname, ttime, nick, userhost, txt) = \
222
 
line.strip().split(',', 4)
223
 
            except ValueError:
224
 
                continue
225
 
            if not withbot and userhost == 'bot@bot':
226
 
                continue
227
 
            if not withcmnd and txt.startswith('CMND:'):
228
 
                continue
229
 
            try:
230
 
                res = func(botname, ttime, nick, userhost, txt)
231
 
            except ValueError:
232
 
                continue
233
 
            if res:
234
 
                times += 1
235
 
                if nrtimes and times > nrtimes:
236
 
                    break
237
 
        logmap.close()
238
 
 
239
 
    def search(self, channel, what, nrtimes):
240
 
        """ search through logfile """
241
 
        res = []
242
 
        if not channel:
243
 
            return
244
 
        andre = re.compile(' and ', re.I)
245
 
        ands = re.split(andre, what)
246
 
        nrtimes = int(nrtimes)
247
 
        logmap = self.getmmap(channel)
248
 
        if not logmap:
249
 
            return
250
 
        res = []
251
 
        def dofunc(botname, ttime, nick, userhost, txt):
252
 
            """ search log line for matching txt """
253
 
            for j in ands:
254
 
                if txt.find(j.strip()) == -1:
255
 
                    return
256
 
            res.append((botname, ttime, nick, userhost, txt))
257
 
            return 1
258
 
        self.loop(logmap, nrtimes, dofunc)        
259
 
        if res:
260
 
            return res[:nrtimes]
261
 
 
262
 
    def seen(self, channel, who):
263
 
        """ get last line of who """
264
 
        logmap = self.getmmap(channel)
265
 
        if not logmap:
266
 
            return
267
 
        result = []
268
 
        who = who.lower()
269
 
        if '*' in who:
270
 
            who = who.replace('*', '.*')
271
 
            rewho = re.compile(who)
272
 
            def dofunc(botname, ttime, nick, userhost, txt):
273
 
                """ add line that matches mask """
274
 
                if re.match(rewho, nick.lower()):
275
 
                    result.append((botname, ttime, nick, userhost, txt))
276
 
        else:
277
 
            def dofunc(botname, ttime, nick, userhost, txt):
278
 
                """ add line that matches nick """
279
 
                if nick.lower() == who:
280
 
                    result.append((botname, ttime, nick, userhost, txt))
281
 
        self.loop(logmap, None, dofunc)
282
 
        if result:
283
 
            return result[-1]
284
 
 
285
 
    def back(self, channel, what, nrtimes):
286
 
        """ search through the logs backwards """
287
 
        if not channel:
288
 
            return
289
 
        res = []
290
 
        andre = re.compile(' and ', re.I)
291
 
        ands = re.split(andre, what)
292
 
        nrtimes = int(nrtimes)
293
 
        logmap = self.getmmap(channel)
294
 
        if not logmap:
295
 
            return
296
 
        def dofunc(botname, ttime, nick, userhost, txt):
297
 
            """ add line that matches """
298
 
            for j in ands:
299
 
                if txt.find(j.strip()) == -1:
300
 
                    return
301
 
            res.append((botname, ttime, nick, userhost, txt))
302
 
            return 1
303
 
        self.loop(logmap, None, dofunc)
304
 
        result = []
305
 
        if res:
306
 
            if len(res) > nrtimes:
307
 
                result = res[len(res)-nrtimes:]
308
 
            else:
309
 
                result = res
310
 
        result.reverse()
311
 
        return result
312
 
 
313
 
    def bback(self, channel, what, nrtimes):
314
 
        """ search through the bot logs backwards """
315
 
        if not channel:
316
 
            return
317
 
        res = []
318
 
        andre = re.compile(' and ', re.I)
319
 
        ands = re.split(andre, what)
320
 
        nrtimes = int(nrtimes)
321
 
        logmap = self.getmmap(channel)
322
 
        if not logmap:
323
 
            return
324
 
        def dofunc(botname, ttime, nick, userhost, txt):
325
 
            """ add line that matches """
326
 
            if nick != 'bot':
327
 
                return
328
 
            for j in ands:
329
 
                if txt.find(j.strip()) == -1:
330
 
                    return
331
 
            res.append((botname, ttime, nick, userhost, txt))
332
 
            return 1
333
 
        self.loop(logmap, None, dofunc, withbot=True)
334
 
        result = []
335
 
        if res:
336
 
            if len(res) > nrtimes:
337
 
                result = res[len(res)-nrtimes:]
338
 
            else:
339
 
                result = res
340
 
        result.reverse()
341
 
        return result
342
 
 
343
 
    def fromtime(self, channel, ftime):
344
 
        """ returns log items from a certain time """
345
 
        if not channel:
346
 
            return
347
 
        res = []
348
 
        logmap = self.getmmap(channel)
349
 
        if not logmap:
350
 
            return
351
 
        def dofunc(botname, ttime, nick, userhost, txt):
352
 
            """ add line that is older then given time """
353
 
            logtime = float(ttime)
354
 
            if logtime > ftime:
355
 
                res.append((botname, ttime, nick, userhost, txt))
356
 
        self.loop(logmap, None, dofunc)
357
 
        return res
358
 
 
359
 
    def fromtimewithbot(self, channel, ftime):
360
 
        """ returns log items from a certain time """
361
 
        if not channel:
362
 
            return
363
 
        res = []
364
 
        logmap = self.getmmap(channel)
365
 
        if not logmap:
366
 
            return
367
 
        def dofunc(botname, ttime, nick, userhost, txt):
368
 
            """ add line that is older then given time including bot outout """
369
 
            logtime = float(ttime)
370
 
            if logtime > ftime:
371
 
                res.append((botname, ttime, nick, userhost, txt))
372
 
        self.loop(logmap, None, dofunc, withbot=True)
373
 
        return res
374
 
 
375
 
    def linesback(self, channel, nrtimes):
376
 
        """ return nr log lines back """
377
 
        if not channel:
378
 
            return
379
 
        result = []
380
 
        nrtimes = int(nrtimes)
381
 
        logmap = self.getmmap(channel)
382
 
        if not logmap:
383
 
            return
384
 
        def dofunc(botname, ttime, nick, userhost, txt):
385
 
            """ add line """
386
 
            result.append((botname, ttime, nick, userhost, txt))
387
 
            return 1
388
 
        self.loop(logmap, None, dofunc)
389
 
        if len(result) > nrtimes:
390
 
            return result[len(result)-nrtimes:]
391
 
        else:
392
 
            return result
393
 
 
394
 
    def linesbacknick(self, channel, who, nrtimes):
395
 
        """ return log lines for nick """
396
 
        if not channel:
397
 
            return
398
 
        result = []
399
 
        nrtimes = int(nrtimes)
400
 
        logmap = self.getmmap(channel)
401
 
        if not logmap:
402
 
            return
403
 
        def dofunc(botname, ttime, nick, userhost, txt):
404
 
            """ add line said by nick """
405
 
            if nick.lower() == who.lower():
406
 
                result.insert(0, (botname, ttime, nick, userhost, txt))
407
 
                return 1
408
 
        self.loop(logmap, None, dofunc)
409
 
        return result[:nrtimes]
410
 
 
411
 
    def linesbacknicksearch(self, channel, who, searchitem, nrtimes):
412
 
        """ search logs for lines said by who """
413
 
        if not channel:
414
 
            return
415
 
        who = who.lower()
416
 
        result = []
417
 
        andre = re.compile(' and ', re.I)
418
 
        ands = re.split(andre, searchitem)
419
 
        nrtimes = int(nrtimes)
420
 
        logmap = self.getmmap(channel)
421
 
        if not logmap:
422
 
            return
423
 
        def dofunc(botname, ttime, nick, userhost, txt):
424
 
            """ add line that is said by nick containing txt """
425
 
            if nick.lower() == who.lower():
426
 
                got = 0
427
 
                for j in ands:
428
 
                    if txt.find(j.strip()) == -1:
429
 
                        got = 0
430
 
                        break
431
 
                    got = 1
432
 
                if got:
433
 
                    result.append((botname, ttime, nick, userhost, txt))
434
 
                    return 1
435
 
        self.loop(logmap, None, dofunc)
436
 
        if len(result) > nrtimes:
437
 
            return result[len(result)-nrtimes:]
438
 
        else:
439
 
            return result
440
 
 
441
 
    def lastspoke(self, channel, userhost):
442
 
        """ return time of last line spoken by user with userhost """
443
 
        if not channel:
444
 
            return
445
 
        result = []
446
 
        logmap = self.getmmap(channel)
447
 
        if not logmap:
448
 
            return
449
 
        def dofunc(botname, ttime, nick, uh, txt):
450
 
            """ add line that matches userhost """
451
 
            if userhost == uh:
452
 
                result.append(int(float(ttime)))
453
 
        self.loop(logmap, None, dofunc)
454
 
        if result:
455
 
            return result[-1]
456
 
 
457
 
    def lastspokelist(self, channel, userhost, nrtimes):
458
 
        """ return time of last line spoken by user with userhost """
459
 
        if not channel:
460
 
            return
461
 
        result = []
462
 
        logmap = self.getmmap(channel)
463
 
        if not logmap:
464
 
            return
465
 
        def dofunc(botname, ttime, nick, uh, txt):
466
 
            """ add line that matches userhost """
467
 
            if userhost == uh:
468
 
                result.append(int(float(ttime)))
469
 
        self.loop(logmap, None, dofunc)
470
 
        if result:
471
 
            return result[len(result)-nrtimes:]
472
 
 
473
 
    def lastnicks(self, channel, nrtimes):
474
 
        """ return the nicks of last said lines """
475
 
        if not channel:
476
 
            return
477
 
        logmap = self.getmmap(channel)
478
 
        if not logmap:
479
 
            return
480
 
        result = []
481
 
        def dofunc(botname, ttime, nick, userhost, txt):
482
 
            """ add nicks  """
483
 
            result.append(nick)
484
 
        self.loop(logmap, None, dofunc)
485
 
        if len(result) > nrtimes:
486
 
            result = result[len(result)-nrtimes:]
487
 
        result.reverse()
488
 
        return result
489
 
 
490
 
 
491
 
savelist = []
492
 
 
493
 
logs = Logs('logs')
494
 
savelist.append(logs)
495
 
 
496
 
def prelogsay(botname, printto, txt, who, how, fromm):
497
 
    """ determine if logsay callback needs to be called """
498
 
    if printto in logs.loglist:
499
 
        return 1
500
 
 
501
 
def cblogsay(botname, printto, txt, who, how, fromm):
502
 
    """ log the bots output """
503
 
    logs.logbot(botname, time.time(), printto, txt)
504
 
 
505
 
saymonitor.add('log', cblogsay, prelogsay)
506
 
 
507
 
def jprelogsay(botname, msg):
508
 
    """ jabber log precondition """
509
 
    try:
510
 
        to = str(msg.getTo())
511
 
    except:
512
 
        return
513
 
    if to in logs.loglist:
514
 
        return 1
515
 
 
516
 
def jcblogsay(botname, msg):
517
 
    """ log the jabber message """
518
 
    try:
519
 
        to = str(msg.getTo())
520
 
        txt = msg.getBody()
521
 
    except:
522
 
        return
523
 
    logs.logbot(botname, time.time(), to, txt)
524
 
 
525
 
jabbermonitor.add('log', jcblogsay, jprelogsay)
526
 
 
527
 
def prelog(bot, ievent):
528
 
    """ log pre condition """
529
 
    if ievent.channel and ievent.channel in logs.loglist:
530
 
        return 1
531
 
 
532
 
def logcb(bot, ievent):
533
 
    """ callback that logs ievent """
534
 
    logs.log(bot.name, time.time(), ievent)
535
 
 
536
 
callbacks.add('ALL', logcb, prelog)
537
 
jcallbacks.add('Message', logcb, prelog)
538
 
 
539
 
def handle_logon(bot, ievent):
540
 
    """ log-on .. enable logging in channel the command was given in """
541
 
    if not ievent.channel in logs.loglist:
542
 
        logs.loglist.append(ievent.channel)
543
 
        ievent.reply('logging enabled in %s' % ievent.channel)
544
 
    else:
545
 
        ievent.reply('%s already in loglist' % ievent.channel)
546
 
 
547
 
cmnds.add('log-on', handle_logon, 'OPER')
548
 
examples.add('log-on', 'enable logging of the channel in which the command \
549
 
was given', 'log-on')
550
 
 
551
 
def handle_logoff(bot, ievent):
552
 
    """ log-off .. disable logging in channel the command was given in"""
553
 
    try:
554
 
        logs.loglist.remove(ievent.channel)
555
 
        ievent.reply('logging disabled in %s' % ievent.channel)
556
 
    except ValueError:
557
 
        ievent.reply('%s not in loglist' % ievent.channel)
558
 
 
559
 
cmnds.add('log-off', handle_logoff, 'OPER')
560
 
examples.add('log-off', 'disable logging of the channel in which the command \
561
 
was given', 'log-off')
562
 
 
563
 
def handle_loglist(bot, ievent):
564
 
    """ log-list .. show list of channels that are being logged """
565
 
    ievent.reply(str(logs.loglist))
566
 
 
567
 
cmnds.add('log-list', handle_loglist, 'OPER')
568
 
examples.add('log-list', 'show list of current logged channels', 'log-list')
569
 
 
570
 
def handle_loglen(bot, ievent):
571
 
    """ log-len show length of logfile for channel in which command was \
572
 
        given """
573
 
    if ievent.channel not in logs.loglist:
574
 
        ievent.reply('logging not enabled in %s' % ievent.channel)
575
 
        return
576
 
    if ievent.channel[0] in ['#', '!', '&', '+']:
577
 
        chan = ievent.channel[1:].lower()
578
 
    else:
579
 
        chan = ievent.channel.lower()
580
 
    ievent.reply(str(logs.size(chan)))
581
 
 
582
 
cmnds.add('log-len', handle_loglen, 'OPER')
583
 
examples.add('log-len', 'show size of log file of the channel the command \
584
 
was given in', 'log-len')
585
 
aliases.data['log-size'] = 'log-len'
586
 
 
587
 
def sayresult(bot, ievent, result, withbot=False):
588
 
    """ reply with result """
589
 
    got = 0
590
 
    if result:
591
 
        res = []
592
 
        for i in result:
593
 
            try:
594
 
                if not withbot and i[3] == 'bot@bot':
595
 
                    continue
596
 
                if not withbot and ('PRIVMSG' in i[4] or 'CMND' in i[4]):
597
 
                    what = i[4].split(':', 1)[1].strip()
598
 
                else:
599
 
                    what = i[4].strip()
600
 
            except (ValueError, IndexError):
601
 
                what = i[4].strip()
602
 
            res.append("[%s %s] <%s> %s" % (dmy(float(i[1])), \
603
 
hourmin(float(i[1])), i[2], what))
604
 
            got += 1
605
 
        ievent.reply(res, dot=True)
606
 
    if not got:
607
 
        ievent.reply("nothing found")
608
 
 
609
 
def handle_logback(bot, ievent):
610
 
    """ log-back [<nrtimes>] <txt> .. search back through channel log """
611
 
    if not ievent.channel:
612
 
        ievent.reply("use chan <channelname> to set channel to search in")
613
 
        return
614
 
    if ievent.channel not in logs.loglist:
615
 
        ievent.reply('logging not enabled in %s' % ievent.channel)
616
 
        return
617
 
    try:
618
 
        nrtimes = int(ievent.args[0])
619
 
        txt = ' '.join(ievent.args[1:])
620
 
    except ValueError:
621
 
        txt = ievent.rest
622
 
        nrtimes = 100000
623
 
    except IndexError:
624
 
        ievent.missing('<searchitem> or <nrtimes> <searchitem>')
625
 
        return
626
 
    result = logs.back(ievent.channel, txt, nrtimes)
627
 
    sayresult(bot, ievent, result)
628
 
 
629
 
cmnds.add('log-back', handle_logback, ['USER', 'WEB', 'ANON'], speed=3)
630
 
examples.add('log-back', "log-back [<nrlinesback>] <txt> .. search backwards in log \
631
 
file of channel", '1) log-back http 2) log-back 1 http')
632
 
aliases.data['b'] = 'log-back'
633
 
aliases.data['back'] = 'log-back'
634
 
 
635
 
def handle_logbback(bot, ievent):
636
 
    """ log-botback [<nrtimes>] <txt> ['back' <bytesback>] .. search back \
637
 
        through bot output in the channel log """
638
 
    if not ievent.channel:
639
 
        ievent.reply("use chan <channelname> to set channel to search in")
640
 
        return
641
 
    if ievent.channel not in logs.loglist:
642
 
        ievent.reply('logging not enabled in %s' % ievent.channel)
643
 
        return
644
 
    try:
645
 
        nrtimes = int(ievent.args[0])
646
 
        txt = ' '.join(ievent.args[1:])
647
 
    except ValueError:
648
 
        txt = ievent.rest
649
 
        nrtimes = 100000
650
 
    except IndexError:
651
 
        ievent.missing('<searchitem> or <nrtimes> <searchitem>')
652
 
        return
653
 
    result = logs.bback(ievent.channel, txt, nrtimes)
654
 
    sayresult(bot, ievent, result, withbot=True)
655
 
 
656
 
cmnds.add('log-bback', handle_logbback, ['USER', 'WEB', 'ANON'], speed=3)
657
 
examples.add('bback', "log-bback [<nrtimes>] <txt> ['back' <bytesback>] .. \
658
 
search backwards in the bot output of the channel log file", '1) log-back \
659
 
http 2) log-back 1 http')
660
 
aliases.data['bback'] = 'log-bback'
661
 
 
662
 
def handle_logsearch(bot, ievent):
663
 
    """ log-search [<nrtimes>] <txt> ['back' <bytesback>] .. search the log \
664
 
        from the beginning """
665
 
    if not ievent.channel:
666
 
        ievent.reply("use chan <channelname> to set channel to search in")
667
 
        return
668
 
    if ievent.channel not in logs.loglist:
669
 
        ievent.reply('logging not enabled in %s' % ievent.channel)
670
 
        return
671
 
    try:
672
 
        nrtimes = int(ievent.args[0])
673
 
        txt = ' '.join(ievent.args[1:])
674
 
    except ValueError:
675
 
        txt = ievent.rest
676
 
        nrtimes = 100000
677
 
    except IndexError:
678
 
        ievent.missing(' <searchitem> or <nrtimes> <searchitem>')
679
 
        return
680
 
    result = logs.search(ievent.channel, txt, nrtimes)
681
 
    sayresult(bot, ievent, result)
682
 
 
683
 
cmnds.add('log-search', handle_logsearch, ['USER', 'WEB', 'ANON'], speed=3)
684
 
examples.add('log-search', 'log-search [<nrtimes>] <txt> .. search the log \
685
 
from the beginning', '1) log-search http 2) log-search 10 http')
686
 
aliasdel('search')
687
 
 
688
 
def handle_loglast(bot, ievent):
689
 
    """ log-last [<nr>] [<nick>] [<txt>] .. search log for last lines of
690
 
        <nick> containing <txt> """
691
 
    if ievent.channel not in logs.loglist:
692
 
        ievent.reply('logging not enabled in %s' % ievent.channel)
693
 
        return
694
 
    result = []
695
 
    try:
696
 
        nrlines = int(ievent.args[0])
697
 
        del ievent.args[0]
698
 
    except (IndexError, ValueError):
699
 
        nrlines = 100000
700
 
    try:
701
 
        nick, txt = ievent.args
702
 
    except ValueError:
703
 
        txt = None
704
 
        try:
705
 
            nick = ievent.args[0]
706
 
        except IndexError:
707
 
            nick = None
708
 
    if nick and txt:
709
 
        result = logs.linesbacknicksearch(ievent.channel, nick, txt, \
710
 
nrlines)
711
 
    elif nick: 
712
 
        result = logs.linesbacknick(ievent.channel, nick, nrlines)
713
 
    else:
714
 
        result = logs.linesback(ievent.channel, nrlines)
715
 
    if result:
716
 
        sayresult(bot, ievent, result)
717
 
    else:
718
 
        ievent.reply('no result found')
719
 
 
720
 
cmnds.add('log-last', handle_loglast, ['USER', 'WEB', 'ANON'], speed=3)
721
 
examples.add('log-last', 'log-last [<nr>] [<nick>] [<txt>] .. show lastlines \
722
 
of channel or user', '1) log-last dunker 2) log-last 5 dunker 3) log-last \
723
 
dunker http 4) log-last 5 dunker http')
724
 
aliases.data['last'] = 'log-last'
725
 
 
726
 
def handle_logtime(bot, ievent):
727
 
    """ show log from a certain time """
728
 
    if not logs:
729
 
        ievent.reply('log plugin is not enabled')
730
 
        return
731
 
    if ievent.channel not in logs.loglist:
732
 
        ievent.reply('logging is not enabled in %s' % ievent.channel)
733
 
        return
734
 
    fromtime = strtotime(ievent.rest)
735
 
    if not fromtime:
736
 
        ievent.reply("can't detect time")
737
 
        return
738
 
    result = logs.fromtimewithbot(ievent.channel, fromtime)
739
 
    if result:
740
 
        username = users.getname(ievent.userhost)
741
 
        res = []
742
 
        for i in result:
743
 
            if i[2] == 'bot':
744
 
                txt = i[4]
745
 
            else:
746
 
                nr = i[4].find(' ')
747
 
                txt = i[4][nr:].strip()
748
 
            res.append("[%s] <%s> %s" % (hourmin(float(i[1])), i[2], txt))
749
 
        ievent.reply(res)
750
 
        return
751
 
    ievent.reply('no data found')
752
 
    
753
 
cmnds.add('log-time', handle_logtime, ['USER', 'WEB', 'ANON'])
754
 
examples.add('log-time', 'show log since given time', 'log-time 21:00')
755
 
 
756
 
def handle_active(bot, ievent):
757
 
    """ active [<minback>] .. show who has been active, default is the 
758
 
        last 15 min 
759
 
    """
760
 
    if not logs:
761
 
        ievent.reply('log plugin is not enabled')
762
 
        return
763
 
    if ievent.channel not in logs.loglist:
764
 
        ievent.reply('logging is not enabled in %s' % ievent.channel)
765
 
        return
766
 
    try:
767
 
        channel = ievent.args[0].lower()
768
 
    except IndexError:
769
 
        channel = ievent.channel
770
 
    minback = 15
771
 
    result = [] 
772
 
    for i in logs.fromtime(ievent.channel, time.time() - 15*60):
773
 
        if i[2] not in result:
774
 
            result.append(i[2])
775
 
    if len(result) > 1:
776
 
        ievent.reply("active in the last %s minutes: " % minback, result)
777
 
    elif len(result) == 1:
778
 
        ievent.reply("%s is active" % result[0])
779
 
    else:
780
 
        ievent.reply("nobody active")
781
 
 
782
 
cmnds.add('active', handle_active, ['USER', 'WEB', 'ANON'])
783
 
examples.add('active', 'active [<minutesback>] .. show who has been active \
784
 
in the last 15 or <minutesback> minutes', '1) active 2) active 600')
785
 
aliases.data['a'] = 'active'
786
 
 
787
 
def handle_line(bot, ievent):
788
 
    """ line .. show activity of last hour """
789
 
    if not logs:
790
 
        ievent.reply('log plugin is not enabled')
791
 
        return
792
 
    if ievent.channel not in logs.loglist:
793
 
        ievent.reply('logging is not enabled in %s' % ievent.channel)
794
 
        return
795
 
    now = time.time()
796
 
    times = [0]*61
797
 
    for i in logs.fromtime(ievent.channel, time.time() - 60*60):
798
 
        try:
799
 
            diff = float(now - float(i[1]))
800
 
        except ValueError:
801
 
            continue
802
 
        times[int(diff/60)] += 1
803
 
    result = ""
804
 
    for j in range(61):
805
 
        if times[j]:
806
 
            result += "%s " % times[j]
807
 
        else:
808
 
            result += "- "
809
 
    result += '(number of lines per minute for the last hour .. \
810
 
most recent minute first)'
811
 
    ievent.reply(result) 
812
 
 
813
 
cmnds.add('line', handle_line, ['USER', 'WEB', 'ANON'])
814
 
examples.add('line', 'show activity for the last hour', 'line')
815
 
aliases.data['l'] = 'line'
816
 
 
817
 
# thnx to timp for this one
818
 
def handle_dayline(bot, ievent):
819
 
    """ dayline .. show activity for last 24 hours """
820
 
    if not logs:
821
 
        ievent.reply('log plugin is not enabled')
822
 
        return
823
 
    if ievent.channel not in logs.loglist:
824
 
        ievent.reply('logging is not enabled in %s' % ievent.channel)
825
 
        return
826
 
    now = time.time()
827
 
    times = [0]*25   
828
 
    for i in logs.fromtime(ievent.channel, time.time() - 24*60*60):
829
 
        diff = int(now/1440 - float(i[1])/1440)
830
 
        if diff < 25:
831
 
            times[diff] += 1
832
 
    result = ""
833
 
    for j in range(25):
834
 
        if times[j]:   
835
 
            result += "%s " % times[j]
836
 
        else:
837
 
            result += "- "
838
 
    result += ' (nr lines per hour for the last day .. most recent hour first)'
839
 
    ievent.reply(result)
840
 
 
841
 
cmnds.add('dayline', handle_dayline, ['USER', 'WEB', 'ANON'])
842
 
examples.add('dayline', 'show nr of lines spoken in last day', 'dl')
843
 
aliases.data['dl'] = 'dayline'
844
 
 
845
 
def handle_mono(bot, ievent):   
846
 
    """ mono [<nick>] .. show length of monologue """
847
 
    if not logs:
848
 
        ievent.reply('log plugin is not enabled')
849
 
        return
850
 
    if ievent.channel not in logs.loglist:
851
 
        ievent.reply('logging is not enabled in %s' % ievent.channel)
852
 
        return
853
 
    teller = 0
854
 
    skip = 0
855
 
    try:
856
 
        nick = ievent.args[0].lower() 
857
 
    except IndexError:
858
 
        nick = ievent.nick.lower()
859
 
    for i in logs.fromtime(ievent.channel, time.time() - 60*60):
860
 
        if i[4].startswith('CMND:'):
861
 
            continue
862
 
        if i[2].lower() == nick:
863
 
            teller += 1
864
 
        else:
865
 
            teller = 0
866
 
    if teller > 4:
867
 
        ievent.reply('%s lines of monologue' % teller)
868
 
    else:
869
 
        ievent.reply("%s is not making a monologue" % nick)
870
 
 
871
 
cmnds.add('mono', handle_mono, ['USER', 'ANON'])
872
 
examples.add('mono', 'mono [<nick>] .. show nr lines of monologue', \
873
 
'1) mono 2) mono dunker')