2014-09-28 18:03:08 +02:00
#!/usr/bin/python3
2014-09-27 03:40:27 +02:00
# -*- coding: utf-8 -*-
if ' __main__ ' == __name__ :
2014-09-28 18:03:08 +02:00
print ( ''' this is a plugin file, which is not meant to be executed ''' )
2014-09-27 03:40:27 +02:00
exit ( - 1 )
2015-02-05 00:48:02 +01:00
import time , random , unicodedata , re , sys , urllib . request , json
2015-02-05 19:00:38 +01:00
import types
2015-02-05 19:23:05 +01:00
import traceback
2015-02-06 13:19:14 +01:00
import urllib . parse
2014-12-14 03:41:57 +01:00
from local_config import conf , set_conf
2014-09-27 09:19:46 +02:00
from common import *
2014-11-09 16:52:22 +01:00
from urlbot import extract_title
2015-02-06 01:21:53 +01:00
from functools import wraps
2015-02-05 23:13:45 +01:00
2015-02-08 22:18:07 +01:00
ptypes_PARSE = 0
ptypes_COMMAND = 1
ptypes = [ ptypes_PARSE , ptypes_COMMAND ]
2014-09-27 03:40:27 +02:00
2014-09-29 19:15:00 +02:00
joblist = [ ]
2015-02-05 23:34:44 +01:00
plugins = { p : [ ] for p in ptypes }
2014-09-27 05:32:35 +02:00
2015-02-05 23:13:45 +01:00
def pluginfunction ( name , desc , plugin_type , ratelimit_class = RATE_GLOBAL , enabled = True ) :
2015-02-05 23:47:07 +01:00
""" A decorator to make a plugin out of a function """
2015-02-05 23:13:45 +01:00
if plugin_type not in ptypes :
raise TypeError ( " Illegal plugin_type: %s " % plugin_type )
def decorate ( f ) :
f . is_plugin = True
2015-02-06 12:47:27 +01:00
f . is_enabled = enabled
2015-02-05 23:13:45 +01:00
f . plugin_name = name
f . plugin_desc = desc
f . plugin_type = plugin_type
f . ratelimit_class = ratelimit_class
return f
return decorate
2014-09-29 19:15:00 +02:00
def register_event ( t , callback , args ) :
joblist . append ( ( t , callback , args ) )
2015-02-08 22:18:07 +01:00
@pluginfunction ( " mental_ill " , " parse mental illness " , ptypes_PARSE , ratelimit_class = RATE_NO_SILENCE | RATE_GLOBAL )
2015-02-05 23:47:07 +01:00
def parse_mental_ill ( * * args ) :
2014-09-27 03:40:27 +02:00
min_ill = 3
c = 0
flag = False
# return True for min_ill '!' in a row
for d in args [ ' data ' ] :
if ' ! ' == d or ' ? ' == d :
c + = 1
else :
c = 0
if ( min_ill < = c ) :
flag = True
break
if True == flag :
2014-09-28 22:44:42 +02:00
logger ( ' plugin ' , ' sent mental illness reply ' )
2014-09-27 03:40:27 +02:00
return {
2014-09-27 05:32:35 +02:00
' msg ' : ''' Multiple exclamation/question marks are a sure sign of mental disease, with %s as a living example. ''' % args [ ' reply_user ' ]
2014-09-27 03:40:27 +02:00
}
2015-02-08 22:18:07 +01:00
@pluginfunction ( " debbug " , " parse Debian bug numbers " , ptypes_PARSE , ratelimit_class = RATE_NO_SILENCE | RATE_GLOBAL )
2015-02-05 23:47:07 +01:00
def parse_debbug ( * * args ) :
2014-11-09 16:52:22 +01:00
bugs = re . findall ( r ' #( \ d { 4,}) ' , args [ ' data ' ] )
if not bugs :
return None
url = ' https://bugs.debian.org/cgi-bin/bugreport.cgi?bug= %s ' % bugs [ 0 ]
status , title = extract_title ( url )
if 0 == status :
2014-12-06 10:19:30 +01:00
title = ' Debian Bug: %s : %s ' % ( title , url )
2014-11-09 16:52:22 +01:00
elif 3 == status :
pass
else :
return None
logger ( ' plugin ' , ' detected Debian bug ' )
return {
' msg ' : title
}
2015-02-08 22:18:07 +01:00
@pluginfunction ( " cve " , " parse a CVE handle " , ptypes_PARSE , ratelimit_class = RATE_NO_SILENCE | RATE_GLOBAL )
2015-02-05 23:47:07 +01:00
def parse_cve ( * * args ) :
2014-12-01 17:50:24 +01:00
cves = re . findall ( r ' (CVE- \ d \ d \ d \ d- \ d+) ' , args [ ' data ' ] . upper ( ) )
if not cves :
return None
logger ( ' plugin ' , ' detected CVE handle ' )
return {
' msg ' : ' https://security-tracker.debian.org/tracker/ %s ' % cves [ 0 ]
}
2015-02-08 22:18:07 +01:00
@pluginfunction ( " skynet " , " parse skynet " , ptypes_PARSE )
2015-02-05 23:47:07 +01:00
def parse_skynet ( * * args ) :
2014-09-27 05:32:35 +02:00
if ' skynet ' in args [ ' data ' ] . lower ( ) :
2014-09-28 22:44:42 +02:00
logger ( ' plugin ' , ' sent skynet reply ' )
2014-09-27 05:32:35 +02:00
return {
' msg ' : ''' I ' m an independent bot and have nothing to do with other artificial intelligence systems! '''
}
2014-09-27 03:40:27 +02:00
2015-02-08 22:59:34 +01:00
@pluginfunction ( ' latex ' , r ' reacts on \ LaTeX ' , ptypes_PARSE )
def parse_skynet ( * * args ) :
if r ' \ LaTeX ' in args [ ' data ' ] :
return {
' msg ' : ''' LaTeX is way too complex for me, I ' m happy with fmt(1) '''
}
#@pluginfunction('dummy_parser', 'dummy_parser desc', ptypes_PARSE)
#def parse_skynet(**args):
# if 'dummy_parser' in args['data'].lower():
# logger('plugin', 'dummy_parser triggered')
# return {
# 'msg': 'dummy_parser triggered'
# }
2014-12-13 22:46:23 +01:00
def data_parse_other ( msg_obj ) :
data = msg_obj [ ' body ' ]
reply_user = msg_obj [ ' mucnick ' ]
2014-09-27 03:40:27 +02:00
2015-02-08 22:18:07 +01:00
for p in plugins [ ptypes_PARSE ] :
2015-02-05 23:47:07 +01:00
if ratelimit_exceeded ( p . ratelimit_class ) :
2014-09-27 05:32:35 +02:00
continue
2014-09-27 03:40:27 +02:00
2015-02-05 23:47:07 +01:00
ret = p ( reply_user = reply_user , data = data )
2014-09-27 05:32:35 +02:00
if None != ret :
2014-09-28 18:03:08 +02:00
if ' msg ' in list ( ret . keys ( ) ) :
2014-09-27 05:51:18 +02:00
ratelimit_touch ( RATE_CHAT )
2014-12-13 22:46:23 +01:00
send_reply ( ret [ ' msg ' ] , msg_obj )
2014-09-27 03:40:27 +02:00
2015-02-08 22:18:07 +01:00
@pluginfunction ( " help " , " print help for a command or all known commands " , ptypes_COMMAND )
2015-02-06 01:21:53 +01:00
def command_help ( argv , * * args ) :
command = argv [ 0 ]
what = argv [ 1 ] if len ( argv ) > 1 else None
2015-01-03 19:04:01 +01:00
if ' help ' != command :
2014-12-16 08:48:03 +01:00
return
2014-09-27 16:15:01 +02:00
2015-01-03 19:04:01 +01:00
if None == what :
2014-12-02 17:31:06 +01:00
logger ( ' plugin ' , ' empty help request, sent all commands ' )
2015-02-08 22:37:27 +01:00
commands = args [ ' cmd_list ' ]
commands . sort ( )
2015-01-03 19:04:01 +01:00
return {
' msg ' : args [ ' reply_user ' ] + ' : known commands: ' +
2015-02-08 22:37:27 +01:00
str ( commands ) . strip ( ' [] ' )
2015-01-03 19:04:01 +01:00
}
2014-09-27 16:06:26 +02:00
2015-02-08 22:18:07 +01:00
if not what in [ p . plugin_name for p in plugins [ ptypes_COMMAND ] ] :
2015-01-03 19:04:01 +01:00
logger ( ' plugin ' , ' no help found for %s ' % what )
2014-09-27 16:06:26 +02:00
return {
2015-01-03 19:04:01 +01:00
' msg ' : args [ ' reply_user ' ] + ' : no such command: %s ' % what
2014-09-27 05:32:35 +02:00
}
2015-02-08 22:18:07 +01:00
for p in plugins [ ptypes_COMMAND ] :
2015-02-06 01:21:53 +01:00
if what == p . plugin_name :
2015-01-03 19:04:01 +01:00
logger ( ' plugin ' , ' sent help for %s ' % what )
2014-09-27 16:06:26 +02:00
return {
2015-01-03 19:04:01 +01:00
' msg ' : args [ ' reply_user ' ] + ' : help for %s : %s ' % (
2015-02-06 01:21:53 +01:00
what , p . plugin_desc
2015-01-03 19:04:01 +01:00
)
2014-09-27 16:06:26 +02:00
}
2015-02-08 22:18:07 +01:00
@pluginfunction ( " version " , " prints version " , ptypes_COMMAND )
2015-02-06 01:21:53 +01:00
def command_version ( argv , * * args ) :
if ' version ' != argv [ 0 ] :
2014-12-16 08:48:03 +01:00
return
logger ( ' plugin ' , ' sent version string ' )
return {
' msg ' : args [ ' reply_user ' ] + ( ''' : I ' m running ''' + VERSION )
}
2014-09-27 05:32:35 +02:00
2015-02-08 22:18:07 +01:00
@pluginfunction ( " klammer " , " prints an anoying paper clip aka. Karl Klammer " , ptypes_COMMAND )
2015-02-06 01:21:53 +01:00
def command_klammer ( argv , * * args ) :
if ' klammer ' != argv [ 0 ] :
2014-12-16 08:48:03 +01:00
return
logger ( ' plugin ' , ' sent karl klammer ' )
return {
' msg ' : (
args [ ' reply_user ' ] + ' , ' ,
r ''' _, Was moechten ''' ,
r ''' ( _ \ _ Sie tun? ''' ,
r ''' \ 0 O \ ''' ,
r ''' \ \ \ \ [ ] ja ''' ,
r ''' \ ` ' ) [ ] noe ''' ,
r ''' ` ' ' '''
)
}
2014-11-17 19:49:02 +01:00
2015-02-08 22:18:07 +01:00
@pluginfunction ( " unikot " , " prints an unicode string " , ptypes_COMMAND )
2015-02-06 01:21:53 +01:00
def command_unicode ( argv , * * args ) :
if ' unikot ' != argv [ 0 ] :
2014-12-16 08:48:03 +01:00
return
logger ( ' plugin ' , ' sent some unicode ' )
return {
' msg ' : (
args [ ' reply_user ' ] + ''' , here ' s some ''' ,
''' ┌────────┐ ''' ,
''' │Unicode!│ ''' ,
''' └────────┘ '''
)
}
2014-09-27 03:40:27 +02:00
2015-02-08 22:18:07 +01:00
@pluginfunction ( " source " , " prints git URL " , ptypes_COMMAND )
2015-02-06 01:21:53 +01:00
def command_source ( argv , * * args ) :
if not argv [ 0 ] in ( ' source ' , ' src ' ) :
2014-12-16 08:48:03 +01:00
return
logger ( ' plugin ' , ' sent source URL ' )
return {
' msg ' : ' My source code can be found at %s ' % conf ( ' src-url ' )
}
2014-09-27 05:32:35 +02:00
2015-02-08 22:18:07 +01:00
@pluginfunction ( " dice " , " rolls a dice, optional N times " , ptypes_COMMAND , ratelimit_class = RATE_INTERACTIVE )
2015-02-06 01:21:53 +01:00
def command_dice ( argv , * * args ) :
if ' dice ' != argv [ 0 ] :
2014-12-16 08:48:03 +01:00
return
2014-09-27 03:40:27 +02:00
2014-12-20 17:02:26 +01:00
count = 0
try :
2015-02-06 01:21:53 +01:00
count = 1 if len ( argv ) < 2 else int ( argv [ 1 ] )
2014-12-20 17:02:26 +01:00
except ValueError as e :
return {
' msg ' : ' %s : dice: error when parsing int( %s ): %s ' % (
2015-02-06 01:21:53 +01:00
args [ ' reply_user ' ] , argv [ 1 ] , str ( e )
2014-12-20 17:02:26 +01:00
)
}
if 0 > = count or 5 < = count :
return {
' msg ' : ' %s : dice: invalid arguments (0 < N < 5) ' % args [ ' reply_user ' ]
}
2014-12-20 17:10:26 +01:00
dice_char = [ ' ◇ ' , ' ⚀ ' , ' ⚁ ' , ' ⚂ ' , ' ⚃ ' , ' ⚄ ' , ' ⚅ ' ]
msg = ' rolling %s for %s : ' % (
' a dice ' if 1 == count else ' %d dices ' % count , args [ ' reply_user ' ]
)
for i in range ( count ) :
rnd = 0
if args [ ' reply_user ' ] in conf ( ' enhanced-random-user ' ) :
rnd = 0 # this might confuse users. good.
logger ( ' plugin ' , ' sent random (enhanced) ' )
else :
rnd = random . randint ( 1 , 6 )
logger ( ' plugin ' , ' sent random ' )
msg + = ' %s ( %d ) ' % ( dice_char [ rnd ] , rnd )
2014-12-20 17:02:26 +01:00
2014-12-16 08:48:03 +01:00
return {
2014-12-20 17:10:26 +01:00
' msg ' : msg
2014-12-16 08:48:03 +01:00
}
2014-09-27 03:40:27 +02:00
2015-02-08 22:18:07 +01:00
@pluginfunction ( " uptime " , " prints uptime " , ptypes_COMMAND )
2015-02-06 01:21:53 +01:00
def command_uptime ( argv , * * args ) :
if ' uptime ' != argv [ 0 ] :
2014-12-16 08:48:03 +01:00
return
2014-09-27 03:40:27 +02:00
2014-12-16 08:48:03 +01:00
u = int ( conf ( ' uptime ' ) + time . time ( ) )
plural_uptime = ' s '
plural_request = ' s '
2014-09-27 03:40:27 +02:00
2014-12-16 08:48:03 +01:00
if 1 == u :
plural_uptime = ' '
if 1 == conf ( ' request_counter ' ) :
plural_request = ' '
logger ( ' plugin ' , ' sent statistics ' )
return {
' msg ' : args [ ' reply_user ' ] + ( ''' : happily serving for %d second %s , %d request %s so far. ''' % ( u , plural_uptime , conf ( ' request_counter ' ) , plural_request ) )
}
2014-09-27 03:40:27 +02:00
2015-02-08 22:18:07 +01:00
@pluginfunction ( " ping " , " sends pong " , ptypes_COMMAND , ratelimit_class = RATE_INTERACTIVE )
2015-02-06 01:21:53 +01:00
def command_ping ( argv , * * args ) :
if ' ping ' != argv [ 0 ] :
2014-12-16 08:48:03 +01:00
return
2014-09-27 03:40:27 +02:00
2014-12-16 08:48:03 +01:00
rnd = random . randint ( 0 , 3 ) # 1:4
if 0 == rnd :
msg = args [ ' reply_user ' ] + ''' : peng (You ' re dead now.) '''
logger ( ' plugin ' , ' sent pong (variant) ' )
elif 1 == rnd :
msg = args [ ' reply_user ' ] + ''' : I don ' t like you, leave me alone. '''
logger ( ' plugin ' , ' sent pong (dontlike) ' )
else :
msg = args [ ' reply_user ' ] + ''' : pong '''
logger ( ' plugin ' , ' sent pong ' )
return {
' msg ' : msg
}
2014-09-27 03:40:27 +02:00
2015-02-08 22:18:07 +01:00
@pluginfunction ( " info " , " prints info message " , ptypes_COMMAND )
2015-02-06 01:21:53 +01:00
def command_info ( argv , * * args ) :
if ' info ' != argv [ 0 ] :
2014-12-16 08:48:03 +01:00
return
logger ( ' plugin ' , ' sent long info ' )
return {
2015-02-05 01:16:52 +01:00
' msg ' : args [ ' reply_user ' ] + ( ''' : I ' m a bot, my job is to extract <title> tags from posted URLs. In case I ' m annoying or for further questions, please talk to my master %s . I ' m rate limited and shouldn ' t post more than %d messages per %d seconds. To make me exit immediately, highlight me with ' hangup ' in the message (emergency only, please). For other commands, highlight me with ' help ' . ''' % ( conf ( ' bot_owner ' ) , conf ( ' hist_max_count ' ) , conf ( ' hist_max_time ' ) ) )
2014-12-16 08:48:03 +01:00
}
2014-09-27 03:40:27 +02:00
2015-02-08 22:18:07 +01:00
@pluginfunction ( " teatimer " , ' sets a tea timer to $1 or currently %d seconds ' % conf ( ' tea_steep_time ' ) , ptypes_COMMAND )
2015-02-06 01:21:53 +01:00
def command_teatimer ( argv , * * args ) :
if ' teatimer ' != argv [ 0 ] :
2014-12-16 08:48:03 +01:00
return
2014-10-29 13:01:32 +01:00
2014-12-16 08:48:03 +01:00
steep = conf ( ' tea_steep_time ' )
2014-09-29 19:15:00 +02:00
2015-02-06 01:21:53 +01:00
if len ( argv ) > 1 :
2014-10-29 13:12:41 +01:00
try :
2015-02-06 01:21:53 +01:00
steep = int ( argv [ 1 ] )
2014-12-16 08:48:03 +01:00
except Exception as e :
2014-10-29 13:12:41 +01:00
return {
2014-12-16 08:48:03 +01:00
' msg ' : args [ ' reply_user ' ] + ' : error when parsing int( %s ): %s ' % (
2015-02-06 01:21:53 +01:00
argv [ 1 ] , str ( e )
2014-12-16 08:48:03 +01:00
)
2014-10-29 13:12:41 +01:00
}
2014-12-16 08:48:03 +01:00
ready = time . time ( ) + steep
2014-12-02 17:01:40 +01:00
2014-12-16 08:48:03 +01:00
try :
logger ( ' plugin ' , ' tea timer set to %s ' % time . strftime ( ' %F . % T ' , time . localtime ( ready ) ) )
except ValueError as e :
2014-09-29 19:15:00 +02:00
return {
2014-12-16 08:48:03 +01:00
' msg ' : args [ ' reply_user ' ] + ' : time format error: ' + str ( e )
2014-09-29 19:15:00 +02:00
}
2014-12-16 08:48:03 +01:00
# FIXME: this is currently broken because the msg_obj gets modified by the very
# first reply and can't be reused to .reply() with another message
register_event ( ready , send_reply , ( args [ ' reply_user ' ] + ' : Your tea is ready! ' , args [ ' msg_obj ' ] ) )
return {
' msg ' : args [ ' reply_user ' ] + ' : Tea timer set to %s ' % time . strftime (
' %F . % T ' , time . localtime ( ready )
)
}
2015-02-08 22:18:07 +01:00
@pluginfunction ( " decode " , " prints the long description of an unicode character " , ptypes_COMMAND )
2015-02-06 01:21:53 +01:00
def command_decode ( argv , * * args ) :
if ' decode ' != argv [ 0 ] :
2014-10-13 18:23:51 +02:00
return
2015-02-06 01:21:53 +01:00
if len ( argv ) < 1 :
2014-10-13 18:23:51 +02:00
return {
2014-12-16 08:48:03 +01:00
' msg ' : args [ ' reply_user ' ] + ' : usage: decode { single character} '
2014-10-13 18:23:51 +02:00
}
2014-12-16 08:48:03 +01:00
2015-02-06 01:21:53 +01:00
char = argv [ 1 ]
2014-12-16 08:48:03 +01:00
char_esc = str ( char . encode ( ' unicode_escape ' ) ) [ 3 : - 1 ]
logger ( ' plugin ' , ' decode called for %s ' % char )
try :
uni_name = unicodedata . name ( char )
except Exception as e :
logger ( ' plugin ' , ' decode( %s ) failed: %s ' % ( char , str ( e ) ) )
2014-10-13 18:23:51 +02:00
return {
2014-12-16 08:48:03 +01:00
' msg ' : args [ ' reply_user ' ] + " : can ' t decode %s ( %s ): %s " % ( char , char_esc , str ( e ) )
2014-10-13 18:23:51 +02:00
}
2014-12-16 08:48:03 +01:00
return {
' msg ' : args [ ' reply_user ' ] + ' : %s ( %s ) is called " %s " ' % ( char , char_esc , uni_name )
}
2015-02-08 22:18:07 +01:00
@pluginfunction ( " show-blacklist " , " show the current URL blacklist, optionally filtered " , ptypes_COMMAND )
2015-02-06 01:21:53 +01:00
def command_show_blacklist ( argv , * * args ) :
if ' show-blacklist ' != argv [ 0 ] :
2014-12-16 08:48:03 +01:00
return
2014-12-02 17:01:40 +01:00
2014-12-16 08:48:03 +01:00
logger ( ' plugin ' , ' sent URL blacklist ' )
2015-02-06 01:21:53 +01:00
argv1 = None if len ( argv ) < 2 else argv [ 1 ]
2014-12-16 08:48:03 +01:00
return {
2014-12-22 21:06:02 +01:00
' msg ' : [
args [ ' reply_user ' ] + ' : URL blacklist %s : ' % (
2015-02-06 01:21:53 +01:00
' ' if not argv1 else ' (limited to %s ) ' % argv1
2014-12-22 21:06:02 +01:00
)
] + [
2014-12-16 08:48:03 +01:00
b for b in conf ( ' url_blacklist ' )
2015-02-06 01:21:53 +01:00
if not argv1 or argv1 in b
2014-12-16 08:48:03 +01:00
]
}
2014-11-28 19:13:45 +01:00
2015-02-06 01:21:53 +01:00
def usersetting_get ( argv , args ) :
2014-12-14 03:41:57 +01:00
blob = conf_load ( )
arg_user = args [ ' reply_user ' ]
2015-02-06 01:21:53 +01:00
arg_key = argv [ 1 ]
2014-12-14 03:41:57 +01:00
if not arg_user in blob [ ' user_pref ' ] :
return {
' msg ' : args [ ' reply_user ' ] + ' : user key not found '
}
return {
' msg ' : args [ ' reply_user ' ] + ' : %s == %s ' % (
arg_key ,
' on ' if blob [ ' user_pref ' ] [ arg_user ] [ arg_key ] else ' off '
)
}
2015-02-08 22:18:07 +01:00
@pluginfunction ( " set " , " modify a user setting " , ptypes_COMMAND )
2015-02-06 01:21:53 +01:00
def command_usersetting ( argv , * * args ) :
if ' set ' != argv [ 0 ] :
2014-12-14 01:27:13 +01:00
return
2014-12-14 03:41:57 +01:00
settings = [ ' spoiler ' ]
arg_user = args [ ' reply_user ' ]
2015-02-06 01:21:53 +01:00
arg_key = argv [ 1 ] if len ( argv ) > 1 else None
arg_val = argv [ 2 ] if len ( argv ) > 2 else None
2014-12-14 03:41:57 +01:00
if not arg_key in settings :
2014-12-14 01:27:13 +01:00
return {
2014-12-14 03:41:57 +01:00
' msg ' : args [ ' reply_user ' ] + ' : known settings: ' + ( ' , ' . join ( settings ) )
2014-12-14 01:27:13 +01:00
}
2014-12-14 03:41:57 +01:00
if not arg_val in [ ' on ' , ' off ' , None ] :
2014-12-14 01:27:13 +01:00
return {
2014-12-14 03:41:57 +01:00
' msg ' : args [ ' reply_user ' ] + ' : possible values for %s : on, off ' % arg_key
2014-12-14 01:27:13 +01:00
}
2014-12-14 03:41:57 +01:00
if None == arg_val :
# display current value
2015-02-06 01:21:53 +01:00
return usersetting_get ( argv , args )
2014-12-14 01:27:13 +01:00
2014-12-14 03:41:57 +01:00
if conf ( ' persistent_locked ' ) :
return {
' msg ' : args [ ' reply_user ' ] + ''' : couldn ' t get exclusive lock '''
}
set_conf ( ' persistent_locked ' , True )
blob = conf_load ( )
if not arg_user in blob [ ' user_pref ' ] :
blob [ ' user_pref ' ] [ arg_user ] = { }
blob [ ' user_pref ' ] [ arg_user ] [ arg_key ] = (
True if ' on ' == arg_val else False
)
conf_save ( blob )
set_conf ( ' persistent_locked ' , False )
# display value written to db
2015-02-06 01:21:53 +01:00
return usersetting_get ( argv , args )
2014-12-14 01:27:13 +01:00
2015-02-08 22:18:07 +01:00
@pluginfunction ( " cake " , " displays a cake ASCII art " , ptypes_COMMAND )
2015-02-06 01:21:53 +01:00
def command_cake ( argv , * * args ) :
if ' cake ' != argv [ 0 ] :
2014-12-16 07:58:35 +01:00
return
2015-02-08 22:04:26 +01:00
cakes = [ " No cake for you! " ,
2015-02-06 15:13:03 +01:00
( " The Enrichment Center is required to remind you "
" that you will be baked, and then there will be cake. " ) ,
" The cake is a lie! " ,
( " This is your fault. I ' m going to kill you. "
2015-02-08 22:04:26 +01:00
" And all the cake is gone. You don ' t even care, do you? " ) ,
2015-02-06 15:13:03 +01:00
" Quit now and cake will be served immediately. " ,
( " Enrichment Center regulations require both hands to be "
" empty before any cake... " ) ,
( " Uh oh. Somebody cut the cake. I told them to wait for "
" you, but they did it anyway. There is still some left, "
" though, if you hurry back. " ) ,
" I ' m going to kill you, and all the cake is gone. " ,
" Who ' s gonna make the cake when I ' m gone? You? " ]
2014-12-16 07:58:35 +01:00
return {
2015-02-06 15:13:03 +01:00
' msg ' : args [ ' reply_user ' ] + ' : %s ' % ( random . sample ( cakes , 1 ) [ 0 ] )
2014-12-16 07:58:35 +01:00
}
2015-02-08 22:18:07 +01:00
@pluginfunction ( " remember " , " remembers something " , ptypes_COMMAND )
2015-02-06 01:21:53 +01:00
def command_remember ( argv , * * args ) :
if ' remember ' != argv [ 0 ] :
2014-12-23 19:54:05 +01:00
return
logger ( ' plugin ' , ' remember plugin called ' )
2015-02-06 01:21:53 +01:00
if not len ( argv ) > 1 :
2014-12-23 19:54:05 +01:00
return {
' msg ' : args [ ' reply_user ' ] + ' : invalid message '
}
print ( args [ ' data ' ] )
2014-12-27 14:55:24 +01:00
to_remember = ' ' . join ( args [ ' data ' ] . split ( ) [ 2 : ] ) # this is a little dirty. A little lot
set_conf ( ' data_remember ' , to_remember )
2014-12-23 19:54:05 +01:00
return {
2014-12-27 14:55:24 +01:00
' msg ' : args [ ' reply_user ' ] + ' : remembering ' + to_remember
2014-12-23 19:54:05 +01:00
}
2015-02-08 22:18:07 +01:00
@pluginfunction ( " recall " , " recalls something previously ' remember ' ed " , ptypes_COMMAND )
2015-02-06 01:21:53 +01:00
def command_recall ( argv , * * args ) :
if ' recall ' != argv [ 0 ] :
2014-12-23 19:54:05 +01:00
return
logger ( ' plugin ' , ' recall plugin called ' )
return {
' msg ' : args [ ' reply_user ' ] + ' : recalling %s ' % conf ( ' data_remember ' )
}
2015-02-06 01:21:53 +01:00
#TODO: send a hint if someone types plugin as command
2015-02-08 22:18:07 +01:00
@pluginfunction ( " plugin " , " disable ' or ' enable ' plugins " , ptypes_COMMAND )
2015-02-06 01:21:53 +01:00
def command_plugin_activation ( argv , * * args ) :
command = argv [ 0 ]
plugin = argv [ 1 ] if len ( argv ) > 1 else None
2015-01-03 18:00:28 +01:00
2015-01-03 18:59:44 +01:00
if not command in ( ' enable ' , ' disable ' ) :
return
2015-01-03 18:00:28 +01:00
logger ( ' plugin ' , ' plugin activation plugin called ' )
if None == plugin :
return {
' msg ' : args [ ' reply_user ' ] + ' : no plugin given '
}
2015-02-06 01:21:53 +01:00
elif command_plugin_activation . plugin_name == plugin :
2015-01-03 18:42:12 +01:00
return {
' msg ' : args [ ' reply_user ' ] + ' : not allowed '
}
2015-01-03 18:00:28 +01:00
2015-02-08 22:18:07 +01:00
for c in plugins [ ptypes_COMMAND ] :
2015-02-06 01:21:53 +01:00
if c . plugin_name == plugin :
2015-02-08 22:04:26 +01:00
c . is_enabled = ' enable ' == command
2015-01-03 18:00:28 +01:00
2015-01-03 18:59:44 +01:00
return {
' msg ' : args [ ' reply_user ' ] + ' : %s d %s ' % (
command , plugin
)
}
2015-01-03 18:00:28 +01:00
return {
2015-01-03 18:59:44 +01:00
' msg ' : args [ ' reply_user ' ] + ' : unknown plugin %s ' % plugin
2015-01-03 18:00:28 +01:00
}
2015-02-08 22:18:07 +01:00
@pluginfunction ( " wp-en " , " crawl the english Wikipedia " , ptypes_COMMAND )
2015-02-06 01:21:53 +01:00
def command_wp_en ( argv , * * args ) :
if ' wp-en ' != argv [ 0 ] :
2015-02-05 01:16:17 +01:00
return
2015-02-06 01:21:53 +01:00
if argv [ 0 ] :
argv [ 0 ] = ' wp '
2015-02-05 01:16:17 +01:00
2015-02-06 01:21:53 +01:00
return command_wp ( argv , lang = " en " , * * args )
2015-02-05 01:16:17 +01:00
2015-02-08 22:18:07 +01:00
@pluginfunction ( " wp " , " crawl the german Wikipedia " , ptypes_COMMAND )
2015-02-06 01:21:53 +01:00
def command_wp ( argv , lang = " de " , * * args ) :
if ' wp ' != argv [ 0 ] :
2015-02-05 00:48:02 +01:00
return
logger ( ' plugin ' , ' wp plugin called ' )
2015-02-06 14:07:58 +01:00
query = " " . join ( argv [ 1 : ] )
2015-02-06 01:21:53 +01:00
if query == " " :
return {
2015-02-08 22:04:26 +01:00
' msg ' : args [ ' reply_user ' ] + " : You must enter a query "
2015-02-06 01:21:53 +01:00
}
2015-02-06 14:27:35 +01:00
api = { " action " : " query " , " prop " : " extracts " , " explaintext " : " " , " redirects " : " " ,
" exsentences " : 2 , " continue " : " " , " format " : " json " , " titles " : query }
2015-02-08 22:04:26 +01:00
apiurl = " https:// %s .wikipedia.org/w/api.php? %s " % ( lang , urllib . parse . urlencode ( api ) )
2015-02-05 00:48:02 +01:00
try :
2015-02-06 13:19:14 +01:00
response = urllib . request . urlopen ( apiurl )
2015-02-05 00:48:02 +01:00
buf = response . read ( BUFSIZ )
2015-02-06 13:19:14 +01:00
j = json . loads ( buf . decode ( " unicode_escape " ) )
2015-02-06 15:27:11 +01:00
2015-02-06 14:07:58 +01:00
page = next ( iter ( j [ ' query ' ] [ ' pages ' ] . values ( ) ) )
short = page . get ( " extract " , None )
linktitle = page . get ( " title " , query ) . replace ( " " , " _ " )
link = ' https:// %s .wikipedia.org/wiki/ %s ' % ( lang , linktitle )
2015-02-05 00:48:02 +01:00
except Exception as e :
2015-02-06 13:19:14 +01:00
logger ( ' plugin ' , ' wp( %s ) failed: %s , %s ' % ( query , e , traceback . format_exc ( ) ) )
2015-02-05 00:48:02 +01:00
return {
2015-02-06 13:19:14 +01:00
' msg ' : args [ ' reply_user ' ] + " : something failed: %s " % e
2015-02-05 00:48:02 +01:00
}
2015-02-06 14:07:58 +01:00
if short is not None :
2015-02-07 02:12:41 +01:00
return {
2015-02-08 22:04:26 +01:00
' msg ' : args [ ' reply_user ' ] + ' : %s (< %s >) ' % (
short if short . strip ( ) else " (nix) " , link
)
2015-02-05 00:48:02 +01:00
}
2015-02-06 15:27:11 +01:00
elif " missing " in page :
return { ' msg ' : ' Article " %s " not found ' % page . get ( " title " , query ) }
2015-02-08 22:04:26 +01:00
else :
2015-02-06 14:07:58 +01:00
return { ' msg ' : " Something seems wrong with the json " }
2015-02-05 00:48:02 +01:00
2014-10-13 18:23:51 +02:00
#def command_dummy(args):
# if 'register' == args:
# return {
# 'name': 'dummy',
# 'desc': 'dummy description',
2014-12-16 08:48:03 +01:00
# 'args': ('argv0', 'reply_user'),
2015-01-03 18:17:54 +01:00
# 'is_enabled': True,
2014-10-13 18:23:51 +02:00
# 'ratelimit_class': RATE_GLOBAL
# }
#
2015-02-06 01:21:53 +01:00
# if 'dummy' != argv[0]:
2014-12-16 08:48:03 +01:00
# return
2014-12-02 17:01:40 +01:00
#
2014-12-16 08:48:03 +01:00
# logger('plugin', 'dummy plugin called')
#
# return {
# 'msg': args['reply_user'] + ': dummy plugin called'
# }
2014-10-13 18:23:51 +02:00
2015-02-05 19:23:05 +01:00
def else_command ( args ) :
2014-09-28 22:44:42 +02:00
logger ( ' plugin ' , ' sent short info ' )
2014-09-27 03:40:27 +02:00
return {
2014-09-27 05:32:35 +02:00
' msg ' : args [ ' reply_user ' ] + ''' : I ' m a bot (highlight me with ' info ' for more information). '''
2014-09-27 03:40:27 +02:00
}
2014-12-13 22:46:23 +01:00
def data_parse_commands ( msg_obj ) :
data = msg_obj [ ' body ' ]
2015-02-06 01:21:53 +01:00
words = data . split ( )
2014-09-27 03:40:27 +02:00
2014-12-02 17:01:40 +01:00
if 2 > len ( words ) : # need at least two words
2014-09-27 03:40:27 +02:00
return None
2014-12-02 16:37:35 +01:00
# don't reply if beginning of the text matches bot_user
if not data . startswith ( conf ( ' bot_user ' ) ) :
return None
2014-09-27 03:40:27 +02:00
if ' hangup ' in data :
logger ( ' warn ' , ' received hangup: ' + data )
2014-12-02 15:22:02 +01:00
sys . exit ( 1 )
2014-09-27 03:40:27 +02:00
return None
2014-12-13 22:46:23 +01:00
reply_user = msg_obj [ ' mucnick ' ]
2015-02-06 01:21:53 +01:00
2015-02-08 22:18:07 +01:00
for p in plugins [ ptypes_COMMAND ] :
2015-02-06 01:21:53 +01:00
if ratelimit_exceeded ( p . ratelimit_class ) :
2014-09-27 05:32:35 +02:00
continue
2015-02-06 01:21:53 +01:00
if not p . is_enabled :
2015-01-03 18:17:54 +01:00
continue
2015-02-08 22:04:26 +01:00
ret = p (
data = data ,
2015-02-08 22:18:07 +01:00
cmd_list = [ pl . plugin_name for pl in plugins [ ptypes_COMMAND ] ] ,
2015-02-08 22:04:26 +01:00
reply_user = reply_user ,
msg_obj = msg_obj ,
argv = words [ 1 : ]
)
2015-02-06 01:21:53 +01:00
2014-09-27 05:32:35 +02:00
if None != ret :
2014-09-28 18:03:08 +02:00
if ' msg ' in list ( ret . keys ( ) ) :
2014-12-14 15:54:57 +01:00
ratelimit_touch ( RATE_CHAT )
if ratelimit_exceeded ( RATE_CHAT ) :
return False
2014-09-28 18:03:08 +02:00
2014-12-14 15:54:57 +01:00
send_reply ( ret [ ' msg ' ] , msg_obj )
2014-09-27 16:20:34 +02:00
2014-09-27 16:06:26 +02:00
return None
2014-09-27 03:40:27 +02:00
2015-02-05 19:23:05 +01:00
ret = else_command ( { ' reply_user ' : reply_user } )
2014-09-27 03:40:27 +02:00
if None != ret :
if ratelimit_exceeded ( RATE_GLOBAL ) :
return False
2014-09-28 18:03:08 +02:00
if ' msg ' in list ( ret . keys ( ) ) :
2014-12-14 15:54:57 +01:00
send_reply ( ret [ ' msg ' ] , msg_obj )
2014-09-27 05:32:35 +02:00
2014-09-27 09:19:46 +02:00
if debug_enabled ( ) :
2014-12-13 22:46:23 +01:00
def _send_reply ( a , msg_obj ) :
logger ( ' send_reply[ %s ] ' % msg_obj , a )
2014-12-02 17:01:40 +01:00
2014-12-14 16:26:48 +01:00
def _conf ( ignored ) :
2014-12-02 17:01:40 +01:00
return ' bot '
def _ratelimit_exceeded ( ignored = None ) :
return False
def _ratelimit_touch ( ignored = None ) :
return True
try :
2014-12-13 22:46:23 +01:00
send_reply
2014-12-02 17:01:40 +01:00
except NameError :
2014-12-13 22:46:23 +01:00
send_reply = _send_reply
2014-12-02 17:01:40 +01:00
try :
conf
except NameError :
conf = _conf
try :
ratelimit_exceeded
except NameError :
ratelimit_exceeded = _ratelimit_exceeded
try :
ratelimit_touch
except NameError :
ratelimit_touch = _ratelimit_touch
2014-09-27 05:32:35 +02:00
2014-09-27 16:06:26 +02:00
logger ( ' info ' , ' debugging enabled ' )
2015-02-05 19:00:38 +01:00
def register ( func_type ) :
"""
Register plugins .
2015-02-08 22:04:26 +01:00
2015-02-05 19:00:38 +01:00
Arguments :
2015-02-05 23:34:44 +01:00
func_type - - plugin functions with this type ( ptypes ) will be loaded
2015-02-05 19:00:38 +01:00
"""
2015-02-08 22:04:26 +01:00
functions = [ f for n , f in globals ( ) . items ( ) if type ( f ) == types . FunctionType
and f . __dict__ . get ( ' is_plugin ' , False )
2015-02-05 23:34:44 +01:00
and f . plugin_type == func_type ]
2015-02-08 22:04:26 +01:00
2015-02-05 23:34:44 +01:00
logger ( ' info ' , ' auto registering plugins: %s ' % ( " , " . join ( f . plugin_name for f in functions ) ) )
2014-09-27 05:32:35 +02:00
2015-02-05 19:00:38 +01:00
for f in functions :
register_plugin ( f , func_type )
def register_plugin ( function , func_type ) :
try :
2015-02-05 23:34:44 +01:00
plugins [ func_type ] . append ( function )
2015-02-05 19:00:38 +01:00
except Exception as e :
2015-02-08 22:04:26 +01:00
logger ( ' warn ' , ' registering %s failed: %s , %s ' %
2015-02-05 19:23:05 +01:00
( function , e , traceback . format_exc ( ) ) )
2014-09-27 05:32:35 +02:00
def register_all ( ) :
2015-02-08 22:18:07 +01:00
register ( ptypes_PARSE )
register ( ptypes_COMMAND )
2014-09-29 19:15:00 +02:00
def event_trigger ( ) :
if 0 == len ( joblist ) :
return
now = time . time ( )
2014-12-13 23:29:51 +01:00
for ( i , ( t , callback , args ) ) in enumerate ( joblist ) :
2014-09-29 19:15:00 +02:00
if t < now :
2014-12-13 22:57:15 +01:00
callback ( * args )
2014-09-29 19:15:00 +02:00
del ( joblist [ i ] )