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
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
2014-09-27 03:40:27 +02:00
2014-09-29 19:15:00 +02:00
joblist = [ ]
2014-09-27 05:32:35 +02:00
plugins = { }
plugins [ ' parse ' ] = [ ]
plugins [ ' command ' ] = [ ]
2014-09-29 19:15:00 +02:00
def register_event ( t , callback , args ) :
joblist . append ( ( t , callback , args ) )
2014-09-27 03:40:27 +02:00
def parse_mental_ill ( args ) :
2014-09-27 05:32:35 +02:00
if ' register ' == args :
return {
' name ' : ' parse mental illness ' ,
' args ' : ( ' data ' , ' reply_user ' ) ,
' ratelimit_class ' : RATE_NO_SILENCE | RATE_GLOBAL
}
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
}
2014-11-09 16:52:22 +01:00
def parse_debbug ( args ) :
if ' register ' == args :
return {
' name ' : ' parse Debian bug numbers ' ,
' args ' : ( ' data ' , ) ,
' ratelimit_class ' : RATE_NO_SILENCE | RATE_GLOBAL
}
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
}
2014-12-01 17:50:24 +01:00
def parse_cve ( args ) :
if ' register ' == args :
return {
' name ' : ' parse a CVE handle ' ,
' args ' : ( ' data ' , ) ,
' ratelimit_class ' : RATE_NO_SILENCE | RATE_GLOBAL
}
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 ]
}
2014-09-27 03:40:27 +02:00
def parse_skynet ( args ) :
2014-09-27 05:32:35 +02:00
if ' register ' == args :
2014-09-27 03:40:27 +02:00
return {
2014-09-27 05:32:35 +02:00
' name ' : ' parse skynet ' ,
' args ' : ( ' data ' , ) ,
2014-09-27 03:40:27 +02:00
' ratelimit_class ' : RATE_GLOBAL
}
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
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
2014-09-27 05:32:35 +02:00
for p in plugins [ ' parse ' ] :
if ratelimit_exceeded ( p [ ' ratelimit_class ' ] ) :
continue
2014-09-27 03:40:27 +02:00
2014-09-27 05:32:35 +02:00
args = { }
2014-09-27 03:40:27 +02:00
2014-09-28 18:03:08 +02:00
if ' args ' in list ( p . keys ( ) ) :
2014-09-27 05:32:35 +02:00
for a in p [ ' args ' ] :
2014-12-02 17:01:40 +01:00
if None == a :
continue
2014-09-27 05:32:35 +02:00
if ' data ' == a :
args [ ' data ' ] = data
elif ' reply_user ' == a :
args [ ' reply_user ' ] = reply_user
else :
2014-12-14 16:26:48 +01:00
logger ( ' warn ' , ' unknown required arg for %s : %s ' % ( p [ ' name ' ] , a ) )
2014-09-27 03:40:27 +02:00
2014-09-27 05:32:35 +02:00
ret = p [ ' func ' ] ( args )
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
2014-09-27 16:06:26 +02:00
def command_help ( args ) :
if ' register ' == args :
return {
' name ' : ' help ' ,
2015-01-03 19:04:01 +01:00
' desc ' : ' print help for a command or all known commands ' ,
2014-12-16 08:48:03 +01:00
' args ' : ( ' argv0 ' , ' argv1 ' , ' reply_user ' , ' cmd_list ' ) ,
2015-01-03 18:17:54 +01:00
' is_enabled ' : True ,
2014-09-27 16:06:26 +02:00
' ratelimit_class ' : RATE_GLOBAL
}
2015-01-03 19:04:01 +01:00
command = args [ ' argv0 ' ]
what = args [ ' argv1 ' ]
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-01-03 19:04:01 +01:00
return {
' msg ' : args [ ' reply_user ' ] + ' : known commands: ' +
str ( args [ ' cmd_list ' ] ) . strip ( ' [] ' )
}
2014-09-27 16:06:26 +02:00
2015-01-03 19:04:01 +01:00
if not what in [ p [ ' name ' ] for p in plugins [ ' command ' ] ] :
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
}
2014-09-27 16:06:26 +02:00
for p in plugins [ ' command ' ] :
2015-01-03 19:04:01 +01:00
if what == p [ ' name ' ] :
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 ' % (
what , p [ ' desc ' ]
)
2014-09-27 16:06:26 +02:00
}
2014-09-27 03:40:27 +02:00
def command_version ( args ) :
2014-09-27 05:32:35 +02:00
if ' register ' == args :
2014-09-27 03:40:27 +02:00
return {
2014-09-27 16:06:26 +02:00
' name ' : ' version ' ,
' desc ' : ' prints version ' ,
2014-12-16 08:48:03 +01:00
' args ' : ( ' argv0 ' , ' reply_user ' ) ,
2015-01-03 18:17:54 +01:00
' is_enabled ' : True ,
2014-09-27 03:40:27 +02:00
' ratelimit_class ' : RATE_GLOBAL
}
2014-12-16 08:48:03 +01:00
if ' version ' != args [ ' argv0 ' ] :
return
logger ( ' plugin ' , ' sent version string ' )
return {
' msg ' : args [ ' reply_user ' ] + ( ''' : I ' m running ''' + VERSION )
}
2014-09-27 05:32:35 +02:00
2014-11-17 19:49:02 +01:00
def command_klammer ( args ) :
if ' register ' == args :
return {
2014-11-17 19:55:45 +01:00
' name ' : ' klammer ' ,
' desc ' : ' prints an anoying paper clip aka. Karl Klammer ' ,
2014-12-16 08:48:03 +01:00
' args ' : ( ' argv0 ' , ' reply_user ' ) ,
2015-01-03 18:17:54 +01:00
' is_enabled ' : True ,
2014-11-17 19:49:02 +01:00
' ratelimit_class ' : RATE_GLOBAL
}
2014-12-16 08:48:03 +01:00
if ' klammer ' != args [ ' argv0 ' ] :
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
2014-09-27 03:40:27 +02:00
def command_unicode ( args ) :
2014-09-27 05:32:35 +02:00
if ' register ' == args :
return {
2014-09-27 16:06:26 +02:00
' name ' : ' unikot ' ,
' desc ' : ' prints an unicode string ' ,
2014-12-16 08:48:03 +01:00
' args ' : ( ' argv0 ' , ' reply_user ' ) ,
2015-01-03 18:17:54 +01:00
' is_enabled ' : True ,
2014-09-27 05:32:35 +02:00
' ratelimit_class ' : RATE_GLOBAL
}
2014-12-16 08:48:03 +01:00
if ' unikot ' != args [ ' argv0 ' ] :
return
logger ( ' plugin ' , ' sent some unicode ' )
return {
' msg ' : (
args [ ' reply_user ' ] + ''' , here ' s some ''' ,
''' ┌────────┐ ''' ,
''' │Unicode!│ ''' ,
''' └────────┘ '''
)
}
2014-09-27 03:40:27 +02:00
def command_source ( args ) :
2014-09-27 05:32:35 +02:00
if ' register ' == args :
2014-09-27 03:40:27 +02:00
return {
2014-09-27 16:06:26 +02:00
' name ' : ' source ' ,
' desc ' : ' prints git URL ' ,
2014-12-16 08:48:03 +01:00
' args ' : ( ' argv0 ' , ' reply_user ' ) ,
2015-01-03 18:17:54 +01:00
' is_enabled ' : True ,
2014-09-27 03:40:27 +02:00
' ratelimit_class ' : RATE_GLOBAL
}
2015-01-04 07:39:58 +01:00
if not args [ ' argv0 ' ] 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
2014-09-27 03:40:27 +02:00
def command_dice ( args ) :
2014-09-27 05:32:35 +02:00
if ' register ' == args :
return {
2014-09-27 16:06:26 +02:00
' name ' : ' dice ' ,
2014-12-20 17:02:26 +01:00
' desc ' : ' rolls a dice, optional N times ' ,
' args ' : ( ' argv0 ' , ' argv1 ' , ' reply_user ' ) ,
2015-01-03 18:17:54 +01:00
' is_enabled ' : True ,
2014-09-27 05:32:35 +02:00
' ratelimit_class ' : RATE_INTERACTIVE
}
2014-12-16 08:48:03 +01:00
if ' dice ' != args [ ' argv0 ' ] :
return
2014-09-27 03:40:27 +02:00
2014-12-20 17:02:26 +01:00
count = 0
try :
count = 1 if None is args [ ' argv1 ' ] else int ( args [ ' argv1 ' ] )
except ValueError as e :
return {
' msg ' : ' %s : dice: error when parsing int( %s ): %s ' % (
args [ ' reply_user ' ] , args [ ' argv1 ' ] , str ( e )
)
}
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
def command_uptime ( args ) :
2014-09-27 05:32:35 +02:00
if ' register ' == args :
return {
2014-09-27 16:06:26 +02:00
' name ' : ' uptime ' ,
' desc ' : ' prints uptime ' ,
2014-12-16 08:48:03 +01:00
' args ' : ( ' argv0 ' , ' reply_user ' ) ,
2015-01-03 18:17:54 +01:00
' is_enabled ' : True ,
2014-09-27 05:32:35 +02:00
' ratelimit_class ' : RATE_GLOBAL
}
2014-12-16 08:48:03 +01:00
if ' uptime ' != args [ ' argv0 ' ] :
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
def command_ping ( args ) :
2014-09-27 05:32:35 +02:00
if ' register ' == args :
return {
2014-09-27 16:06:26 +02:00
' name ' : ' ping ' ,
' desc ' : ' sends pong ' ,
2014-12-16 08:48:03 +01:00
' args ' : ( ' argv0 ' , ' reply_user ' ) ,
2015-01-03 18:17:54 +01:00
' is_enabled ' : True ,
2014-09-27 05:32:35 +02:00
' ratelimit_class ' : RATE_INTERACTIVE
}
2014-12-16 08:48:03 +01:00
if ' ping ' != args [ ' argv0 ' ] :
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
def command_info ( args ) :
2014-09-27 05:32:35 +02:00
if ' register ' == args :
return {
2014-09-27 16:06:26 +02:00
' name ' : ' info ' ,
' desc ' : ' prints info message ' ,
2014-12-16 08:48:03 +01:00
' args ' : ( ' argv0 ' , ' reply_user ' ) ,
2015-01-03 18:17:54 +01:00
' is_enabled ' : True ,
2014-09-27 05:32:35 +02:00
' ratelimit_class ' : RATE_GLOBAL
}
2014-12-16 08:48:03 +01:00
if ' info ' != args [ ' argv0 ' ] :
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
2014-09-29 19:15:00 +02:00
def command_teatimer ( args ) :
if ' register ' == args :
return {
' name ' : ' teatimer ' ,
2014-10-29 13:01:32 +01:00
' desc ' : ' sets a tea timer to $1 or currently %d seconds ' % conf ( ' tea_steep_time ' ) ,
2014-12-13 22:46:23 +01:00
' args ' : ( ' reply_user ' , ' msg_obj ' , ' argv0 ' , ' argv1 ' ) ,
2015-01-03 18:17:54 +01:00
' is_enabled ' : True ,
2014-09-29 19:15:00 +02:00
' ratelimit_class ' : RATE_GLOBAL
}
2014-12-16 08:48:03 +01:00
if ' teatimer ' != args [ ' argv0 ' ] :
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
2014-12-16 08:48:03 +01:00
if None != args [ ' argv1 ' ] :
2014-10-29 13:12:41 +01:00
try :
2014-12-16 08:48:03 +01:00
steep = int ( args [ ' argv1 ' ] )
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 ' % (
args [ ' argv1 ' ] , str ( e )
)
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 )
)
}
2014-10-13 18:23:51 +02:00
def command_decode ( args ) :
if ' register ' == args :
return {
' name ' : ' decode ' ,
' desc ' : ' prints the long description of an unicode character ' ,
2014-12-16 08:48:03 +01:00
' args ' : ( ' argv0 ' , ' argv1 ' , ' 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
}
2014-12-16 08:48:03 +01:00
if ' decode ' != args [ ' argv0 ' ] :
2014-10-13 18:23:51 +02:00
return
2014-12-16 08:48:03 +01:00
if None == args [ ' argv1 ' ] :
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
char = args [ ' argv1 ' ]
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 )
}
2014-11-28 19:13:45 +01:00
def command_show_blacklist ( args ) :
if ' register ' == args :
return {
' name ' : ' show-blacklist ' ,
2014-12-05 15:05:37 +01:00
' desc ' : ' show the current URL blacklist, optionally filtered ' ,
2014-12-16 08:48:03 +01:00
' args ' : ( ' argv0 ' , ' reply_user ' , ' argv1 ' ) ,
2015-01-03 18:17:54 +01:00
' is_enabled ' : True ,
2014-11-28 19:13:45 +01:00
' ratelimit_class ' : RATE_GLOBAL
}
2014-12-16 08:48:03 +01:00
if ' show-blacklist ' != args [ ' argv0 ' ] :
return
2014-12-02 17:01:40 +01:00
2014-12-16 08:48:03 +01:00
logger ( ' plugin ' , ' sent URL blacklist ' )
return {
2014-12-22 21:06:02 +01:00
' msg ' : [
args [ ' reply_user ' ] + ' : URL blacklist %s : ' % (
' ' if not args [ ' argv1 ' ] else ' (limited to %s ) ' % args [ ' argv1 ' ]
)
] + [
2014-12-16 08:48:03 +01:00
b for b in conf ( ' url_blacklist ' )
if not args [ ' argv1 ' ] or args [ ' argv1 ' ] in b
]
}
2014-11-28 19:13:45 +01:00
2014-12-14 03:41:57 +01:00
def usersetting_get ( args ) :
blob = conf_load ( )
arg_user = args [ ' reply_user ' ]
arg_key = args [ ' argv1 ' ]
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 '
)
}
2014-12-14 01:27:13 +01:00
def command_usersetting ( args ) :
if ' register ' == args :
return {
' name ' : ' set ' ,
' desc ' : ' modify a user setting ' ,
' args ' : ( ' reply_user ' , ' argv0 ' , ' argv1 ' , ' argv2 ' , ' msg_obj ' ) ,
2015-01-03 18:17:54 +01:00
' is_enabled ' : True ,
2014-12-14 01:27:13 +01:00
' ratelimit_class ' : RATE_GLOBAL
}
if ' set ' != args [ ' argv0 ' ] :
return
2014-12-14 03:41:57 +01:00
settings = [ ' spoiler ' ]
arg_user = args [ ' reply_user ' ]
arg_key = args [ ' argv1 ' ]
arg_val = args [ ' argv2 ' ]
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
return usersetting_get ( 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
return usersetting_get ( args )
2014-12-14 01:27:13 +01:00
2014-12-16 07:58:35 +01:00
def command_cake ( args ) :
if ' register ' == args :
return {
' name ' : ' cake ' ,
' desc ' : ' displays a cake ASCII art ' ,
' args ' : ( ' argv0 ' , ' reply_user ' ) ,
2015-01-03 18:17:54 +01:00
' is_enabled ' : True ,
2014-12-16 07:58:35 +01:00
' ratelimit_class ' : RATE_GLOBAL
}
if ' cake ' != args [ ' argv0 ' ] :
return
return {
' msg ' : args [ ' reply_user ' ] + ' : no cake for you '
}
2014-12-23 19:54:05 +01:00
def command_remember ( args ) :
if ' register ' == args :
return {
' name ' : ' remember ' ,
' desc ' : ' remembers something ' ,
' args ' : ( ' argv0 ' , ' argv1 ' , ' data ' , ' reply_user ' ) ,
2015-01-03 18:17:54 +01:00
' is_enabled ' : True ,
2014-12-23 19:54:05 +01:00
' ratelimit_class ' : RATE_GLOBAL
}
if ' remember ' != args [ ' argv0 ' ] :
return
logger ( ' plugin ' , ' remember plugin called ' )
if not args [ ' argv1 ' ] :
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
}
def command_recall ( args ) :
if ' register ' == args :
return {
' name ' : ' recall ' ,
' desc ' : " recalls something previously ' remember ' ed " ,
' args ' : ( ' argv0 ' , ' reply_user ' ) ,
2015-01-03 18:17:54 +01:00
' is_enabled ' : True ,
2014-12-23 19:54:05 +01:00
' ratelimit_class ' : RATE_GLOBAL
}
if ' recall ' != args [ ' argv0 ' ] :
return
logger ( ' plugin ' , ' recall plugin called ' )
return {
' msg ' : args [ ' reply_user ' ] + ' : recalling %s ' % conf ( ' data_remember ' )
}
2015-01-03 18:00:28 +01:00
def command_plugin_activation ( args ) :
if ' register ' == args :
return {
' name ' : ' plugin ' ,
2015-01-03 18:59:44 +01:00
' desc ' : " ' disable ' or ' enable ' plugins " ,
' args ' : ( ' argv0 ' , ' argv1 ' , ' reply_user ' ) ,
2015-01-03 18:17:54 +01:00
' is_enabled ' : True ,
2015-01-03 18:00:28 +01:00
' ratelimit_class ' : RATE_GLOBAL
}
2015-01-03 18:59:44 +01:00
command = args [ ' argv0 ' ]
plugin = args [ ' argv1 ' ]
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-01-03 18:42:12 +01:00
elif ' plugin ' == plugin :
return {
' msg ' : args [ ' reply_user ' ] + ' : not allowed '
}
2015-01-03 18:00:28 +01:00
2015-01-03 18:59:44 +01:00
for i , c in enumerate ( plugins [ ' command ' ] ) :
if c [ ' name ' ] == plugin :
plugins [ ' command ' ] [ i ] [ ' is_enabled ' ] = \
True if ' enable ' == command else False
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-05 01:16:17 +01:00
def command_wp_en ( args ) :
if ' register ' == args :
return {
' name ' : ' wp-en ' ,
' desc ' : ' crawl the english Wikipedia ' ,
' args ' : ( ' argv0 ' , ' argv1 ' , ' argv2 ' , ' reply_user ' ) ,
' is_enabled ' : True ,
' ratelimit_class ' : RATE_GLOBAL
}
if ' wp-en ' != args [ ' argv0 ' ] :
return
if args [ ' argv0 ' ] :
args [ ' argv0 ' ] = ' wp '
return command_wp ( args , lang = ' en ' )
def command_wp ( args , lang = ' de ' ) :
2015-02-05 00:48:02 +01:00
if ' register ' == args :
return {
' name ' : ' wp ' ,
2015-02-05 01:16:17 +01:00
' desc ' : ' crawl the german Wikipedia ' ,
2015-02-05 01:04:52 +01:00
' args ' : ( ' argv0 ' , ' argv1 ' , ' argv2 ' , ' reply_user ' ) ,
2015-02-05 00:48:02 +01:00
' is_enabled ' : True ,
' ratelimit_class ' : RATE_GLOBAL
}
if ' wp ' != args [ ' argv0 ' ] :
return
logger ( ' plugin ' , ' wp plugin called ' )
query = args [ ' argv1 ' ]
# FIXME: escaping. probably.
2015-02-05 01:04:52 +01:00
api = ( ' https:// %s .wikipedia.org/w/api.php?action=query&prop=extracts& ' + \
' explaintext&exsentences=2&rawcontinue=1&format=json&titles= %s ' ) % (
lang , query
)
link = ' https:// %s .wikipedia.org/wiki/ %s ' % ( lang , query )
2015-02-05 00:48:02 +01:00
( j , short ) = ( None , None )
failed = False
try :
response = urllib . request . urlopen ( api )
buf = response . read ( BUFSIZ )
j = json . loads ( buf . decode ( ' utf-8 ' ) )
except Exception as e :
logger ( ' plugin ' , ' wp( %s ) failed: %s ' % ( query , str ( e ) ) )
return {
' msg ' : args [ ' reply_user ' ] + " : something failed: %s " % str ( e )
}
# FIXME: this looks rather shitty. We're looking for
# >>> j['query']['pages']['88112']['extract'] == str()
if not ' query ' in j :
failed = True
else :
j = j [ ' query ' ]
if not ' pages ' in j :
failed = True
else :
j = j [ ' pages ' ]
flag = True
for stuff in j :
if ' extract ' in j [ stuff ] :
flag = False
j = j [ stuff ] [ ' extract ' ]
break
failed = flag
if failed :
return {
' msg ' : args [ ' reply_user ' ] + ' : the json object looks bad, sorry for that. '
}
else :
short = str ( j )
return {
2015-02-05 00:52:33 +01:00
' msg ' : args [ ' reply_user ' ] + ' : %s (< %s >) ' % (
' (nix) ' if 0 == len ( short . strip ( ) ) else short , link
)
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
# }
#
2014-12-16 08:48:03 +01:00
# if 'dummy' != args['argv0']:
# 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 ' ]
2014-09-27 03:40:27 +02:00
words = data . split ( ' ' )
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 ' ]
2014-12-14 01:27:13 +01:00
( argv0 , argv1 , argv2 ) = ( None , None , None )
2014-12-02 17:09:46 +01:00
if 1 < len ( words ) :
argv0 = words [ 1 ]
if 2 < len ( words ) :
argv1 = words [ 2 ]
2014-12-14 01:27:13 +01:00
if 3 < len ( words ) :
argv2 = words [ 3 ]
2014-09-27 03:40:27 +02:00
2014-09-27 05:32:35 +02:00
for p in plugins [ ' command ' ] :
if ratelimit_exceeded ( p [ ' ratelimit_class ' ] ) :
continue
2015-01-03 18:17:54 +01:00
if not p [ ' is_enabled ' ] :
continue
2014-09-27 05:32:35 +02:00
args = { }
2014-09-28 18:03:08 +02:00
if ' args ' in list ( p . keys ( ) ) :
2014-09-27 05:32:35 +02:00
for a in p [ ' args ' ] :
2014-12-02 17:01:40 +01:00
if None == a :
continue
2014-09-27 03:40:27 +02:00
2014-09-27 05:32:35 +02:00
if ' data ' == a :
args [ ' data ' ] = data
2014-09-27 16:06:26 +02:00
elif ' cmd_list ' == a :
cmds = [ c [ ' name ' ] for c in plugins [ ' command ' ] ]
cmds . sort ( )
args [ ' cmd_list ' ] = cmds
2014-09-27 05:32:35 +02:00
elif ' reply_user ' == a :
args [ ' reply_user ' ] = reply_user
2014-12-13 22:46:23 +01:00
elif ' msg_obj ' == a :
args [ ' msg_obj ' ] = msg_obj
2014-10-29 13:05:23 +01:00
elif ' argv0 ' == a :
args [ ' argv0 ' ] = argv0
2014-10-29 13:01:32 +01:00
elif ' argv1 ' == a :
args [ ' argv1 ' ] = argv1
2014-12-14 01:27:13 +01:00
elif ' argv2 ' == a :
args [ ' argv2 ' ] = argv2
2014-09-27 05:32:35 +02:00
else :
2014-12-14 16:26:48 +01:00
logger ( ' warn ' , ' unknown required arg for %s : %s ' % ( p [ ' name ' ] , a ) )
2014-09-27 03:40:27 +02:00
2014-09-27 05:32:35 +02:00
ret = p [ ' func ' ] ( args )
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 .
Arguments :
func_type - - functions with startswith ( func_type + " _ " ) will be loaded
"""
2014-09-27 05:32:35 +02:00
plugins [ func_type ] = [ ]
2015-02-05 19:00:38 +01:00
functions = [ f for n , f in globals ( ) . items ( ) if n . startswith ( func_type + " _ " )
and type ( f ) == types . FunctionType ]
logger ( ' info ' , ' auto registering plugins: %s ' % ( " , " . join ( f . __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 :
ret = function ( ' register ' )
ret [ ' func ' ] = function
plugins [ func_type ] . append ( ret )
except Exception as e :
2015-02-05 19:23:05 +01:00
logger ( ' warn ' , ' registering %s failed: %s , %s ' %
( function , e , traceback . format_exc ( ) ) )
2014-09-27 05:32:35 +02:00
def register_all ( ) :
register ( ' parse ' )
register ( ' 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 ] )