2012-04-09 02:19:39 +00:00
# coding=utf-8
from datetime import datetime
2012-04-30 16:22:10 +00:00
from datetime import timedelta
2012-04-09 02:19:39 +00:00
import re
2012-04-30 16:22:10 +00:00
import sys
2012-04-09 02:19:39 +00:00
import string
import time
2012-04-16 16:28:43 +00:00
import imp
2012-04-30 16:22:10 +00:00
import random
from xml . dom . minidom import parse
from xml . dom . minidom import parseString
from xml . dom . minidom import getDOMImplementation
BANLIST = [ ]
CREDITS = { }
filename = " "
def load_module ( datas_path ) :
global BANLIST , CREDITS , filename
CREDITS = dict ( )
BANLIST = list ( )
filename = datas_path + " /general.xml "
sys . stdout . write ( " Loading banlist ... " )
dom = parse ( filename )
for item in dom . documentElement . getElementsByTagName ( " ban " ) :
BANLIST . append ( item . getAttribute ( " name " ) )
print ( " done ( %d users banned) " % ( len ( BANLIST ) ) )
def save_module ( ) :
global BANLIST , ALIAS , filename
sys . stdout . write ( " Saving banlist ... " )
impl = getDOMImplementation ( )
newdoc = impl . createDocument ( None , ' global ' , None )
top = newdoc . documentElement
for name in BANLIST :
item = parseString ( ' <ban name= " %s " /> ' % ( name ) ) . documentElement
top . appendChild ( item ) ;
with open ( filename , " w " ) as f :
newdoc . writexml ( f )
print ( " done " )
class Credits :
def __init__ ( self , name ) :
self . name = name
self . credits = 5
self . randsec = timedelta ( seconds = random . randint ( 0 , 55 ) )
self . lastmessage = datetime . now ( ) + self . randsec
self . iask = True
def ask ( self ) :
if self . name in BANLIST :
return False
now = datetime . now ( ) + self . randsec
if self . lastmessage . minute == now . minute and ( self . lastmessage . second == now . second or self . lastmessage . second == now . second - 1 ) :
print ( " AUTOBAN %s : too low time between messages " % self . name )
2012-05-03 14:16:38 +00:00
#BANLIST.append(self.name)
self . credits - = self . credits / 2 #Une alternative
2012-04-30 16:22:10 +00:00
return False
self . iask = True
return self . credits > 0 or self . lastmessage . minute != now . minute
def speak ( self ) :
if self . iask :
self . iask = False
now = datetime . now ( ) + self . randsec
if self . lastmessage . minute != now . minute :
self . credits = min ( 15 , self . credits + 5 )
self . lastmessage = now
self . credits - = 1
return self . credits > - 3
def to_string ( self ) :
print ( " %s : %d ; reset: %d " % ( self . name , self . credits , self . randsec . seconds ) )
2012-04-09 02:19:39 +00:00
class Message :
def __init__ ( self , srv , line ) :
self . srv = srv
self . time = datetime . now ( )
2012-04-30 16:22:10 +00:00
self . channel = " "
self . content = " "
2012-04-09 02:19:39 +00:00
line = line . rstrip ( ) #remove trailing 'rn'
if line . find ( ' PRIVMSG ' ) != - 1 : #Call a parsing function
complete = line [ 1 : ] . split ( ' : ' , 1 ) #Parse the message into useful data
info = complete [ 0 ] . split ( ' ' )
self . cmd = " PRIVMSG "
2012-05-14 15:50:11 +00:00
if len ( complete ) < 2 or len ( info ) < 3 :
last = " "
info = list ( )
for lettre in line :
if len ( info ) > 2 :
complete [ 1 ] + = lettre
elif lettre == " : " or lettre == " " :
if last != " " :
info . append ( last )
if len ( info ) > 2 :
complete = list ( )
complete . append ( " " . join ( info ) )
complete . append ( " " )
else :
last + = lettre
2012-04-09 02:19:39 +00:00
self . sender = ( info [ 0 ] . split ( ' ! ' ) ) [ 0 ]
2012-04-30 16:22:10 +00:00
self . realname = ( info [ 0 ] . split ( ' ! ' ) ) [ 1 ]
2012-04-09 02:19:39 +00:00
self . channel = info [ 2 ]
self . content = complete [ 1 ]
2012-04-30 16:22:10 +00:00
elif line . find ( ' ACTION ' ) != - 1 :
complete = line [ 1 : ] . split ( ' : ' , 1 ) #Parse the message into useful data
info = complete [ 0 ] . split ( ' ' )
self . cmd = " ACTION "
self . sender = ( info [ 0 ] . split ( ' ! ' ) ) [ 0 ]
self . realname = ( info [ 0 ] . split ( ' ! ' ) ) [ 1 ]
self . channel = info [ 2 ]
self . content = complete [ 1 ]
2012-04-09 02:19:39 +00:00
elif line . find ( ' NICK ' ) != - 1 :
complete = line [ 1 : ] . split ( ' : ' , 1 ) #Parse the message into useful data
if len ( complete ) > 1 :
info = complete [ 0 ] . split ( ' ' )
self . cmd = " NICK "
self . sender = ( info [ 0 ] . split ( ' ! ' ) ) [ 0 ]
2012-04-30 16:22:10 +00:00
self . realname = ( info [ 0 ] . split ( ' ! ' ) ) [ 1 ]
2012-04-09 02:19:39 +00:00
self . content = complete [ 1 ]
else :
self . cmd = " NONE "
elif line . find ( ' JOIN ' ) != - 1 :
complete = line [ 1 : ] . split ( ' : ' , 1 ) #Parse the message into useful data
if len ( complete ) > 1 :
info = complete [ 0 ] . split ( ' ' )
self . cmd = " JOIN "
self . sender = ( info [ 0 ] . split ( ' ! ' ) ) [ 0 ]
2012-04-30 16:22:10 +00:00
self . realname = ( info [ 0 ] . split ( ' ! ' ) ) [ 1 ]
2012-04-09 02:19:39 +00:00
self . channel = complete [ 1 ]
else :
self . cmd = " NONE "
elif line . find ( ' PART ' ) != - 1 :
complete = line [ 1 : ] . split ( ' : ' , 1 ) #Parse the message into useful data
info = complete [ 0 ] . split ( ' ' )
self . cmd = " PART "
self . sender = ( info [ 0 ] . split ( ' ! ' ) ) [ 0 ]
2012-04-30 16:22:10 +00:00
self . realname = ( info [ 0 ] . split ( ' ! ' ) ) [ 1 ]
2012-04-09 02:19:39 +00:00
self . channel = info [ 2 ]
if len ( complete ) > 1 :
self . content = complete [ 1 ]
else :
self . content = " "
2012-05-14 15:50:11 +00:00
elif line . find ( ' QUIT ' ) != - 1 :
complete = line [ 1 : ] . split ( ' : ' , 1 ) #Parse the message into useful data
info = complete [ 0 ] . split ( ' ' )
self . cmd = " QUIT "
self . sender = ( info [ 0 ] . split ( ' ! ' ) ) [ 0 ]
self . realname = ( info [ 0 ] . split ( ' ! ' ) ) [ 1 ]
self . channel = info [ 2 ]
if len ( complete ) > 1 :
self . content = complete [ 1 ]
else :
self . content = " "
2012-04-30 16:22:10 +00:00
elif line . find ( ' MODE ' ) != - 1 :
complete = line [ 1 : ] . split ( ' ' )
if len ( complete ) > = 5 :
self . cmd = " MODE "
self . channel = complete [ 2 ]
self . mode = complete [ 3 ]
self . sender = complete [ 4 ]
else :
self . cmd = " NONE "
2012-04-09 02:19:39 +00:00
elif line . find ( ' PING ' ) != - 1 : #If server pings then pong
line = line . split ( )
self . cmd = " PING "
self . content = line [ 1 ]
else :
self . cmd = " UNKNOWN "
print ( line )
2012-05-03 14:16:38 +00:00
@property
def is_owner ( self ) :
return self . sender == self . srv . owner
2012-04-09 02:19:39 +00:00
def send_msg ( self , channel , msg , cmd = " PRIVMSG " , endl = " \r \n " ) :
2012-04-30 16:22:10 +00:00
if CREDITS [ self . realname ] . speak ( ) :
self . srv . send_msg ( channel , msg , cmd , endl )
2012-04-09 02:19:39 +00:00
def send_global ( self , msg , cmd = " PRIVMSG " , endl = " \r \n " ) :
2012-04-30 16:22:10 +00:00
if CREDITS [ self . realname ] . speak ( ) :
self . srv . send_global ( msg , cmd , endl )
2012-04-09 02:19:39 +00:00
def send_chn ( self , msg ) :
""" Send msg on the same channel as receive message """
2012-04-30 16:22:10 +00:00
if CREDITS [ self . realname ] . speak ( ) :
if self . channel == self . srv . nick :
self . send_snd ( msg )
else :
self . srv . send_msg ( self . channel , msg )
2012-04-09 02:19:39 +00:00
def send_snd ( self , msg ) :
""" Send msg to the sender who send the original message """
2012-04-30 16:22:10 +00:00
if CREDITS [ self . realname ] . speak ( ) :
self . srv . send_msg_usr ( self . sender , msg )
2012-04-09 02:19:39 +00:00
2012-04-12 01:06:17 +00:00
2012-04-30 16:22:10 +00:00
def authorize ( self ) :
if self . realname not in CREDITS :
CREDITS [ self . realname ] = Credits ( self . realname )
elif self . content [ 0 ] == ' ` ' :
return True
elif not CREDITS [ self . realname ] . ask ( ) :
return False
return self . srv . accepted_channel ( self . channel )
2012-04-09 02:19:39 +00:00
def treat ( self , mods ) :
if self . cmd == " PING " :
self . pong ( )
2012-04-30 16:22:10 +00:00
elif self . cmd == " PRIVMSG " and self . authorize ( ) :
2012-04-09 02:19:39 +00:00
self . parsemsg ( mods )
elif self . cmd == " NICK " :
print ( " %s change de nom pour %s " % ( self . sender , self . content ) )
elif self . cmd == " PART " :
print ( " %s vient de quitter %s " % ( self . sender , self . channel ) )
elif self . cmd == " JOIN " :
print ( " %s arrive sur %s " % ( self . sender , self . channel ) )
def pong ( self ) :
self . srv . s . send ( ( " PONG %s \r \n " % self . content ) . encode ( ) )
2012-04-30 16:22:10 +00:00
def reparsemsg ( self ) :
if self . mods is not None :
self . parsemsg ( self . mods )
else :
print ( " Can ' t reparse message " )
2012-04-09 02:19:39 +00:00
def parsemsg ( self , mods ) :
#Treat all messages starting with 'nemubot:' as distinct commands
2012-04-11 15:33:57 +00:00
if self . content . find ( " %s : " % self . srv . nick ) == 0 :
2012-04-09 02:19:39 +00:00
messagel = self . content . lower ( )
#Is it a simple response?
2012-04-11 15:33:57 +00:00
if re . match ( " .*(m[ ' ]?entends?[ -]+tu|h?ear me|do you copy|ping) " , messagel ) is not None :
2012-04-09 02:19:39 +00:00
self . send_chn ( " %s : pong " % ( self . sender ) )
2012-04-16 16:28:43 +00:00
elif re . match ( " .*(quel(le)? heure est[ -]il|what time is it) " , messagel ) is not None :
now = datetime . now ( )
self . send_chn ( " %s : j ' envoie ce message à %s : %d : %d . " % ( self . sender , now . hour , now . minute , now . second ) )
2012-05-14 15:50:11 +00:00
elif re . match ( " .*qui est ([a-zA-Z0-9_-]+) " , messagel ) is not None :
result = re . match ( " .*qui est ([a-zA-Z0-9_-]+).* " , self . content )
self . send_chn ( " !whois %s " % ( result . group ( 1 ) ) )
2012-04-09 02:19:39 +00:00
elif re . match ( " .*di[st] (a|à) ([a-zA-Z0-9_]+) (.+)$ " , messagel ) is not None :
result = re . match ( " .*di[st] (a|à) ([a-zA-Z0-9_]+) (qu(e | ' ))?(.+)$ " , self . content )
self . send_chn ( " %s : %s " % ( result . group ( 2 ) , result . group ( 5 ) ) )
elif re . match ( " .*di[st] (.+) (a|à) ([a-zA-Z0-9_]+)$ " , messagel ) is not None :
result = re . match ( " .*di[st] (.+) (à|a) ([a-zA-Z0-9_]+)$ " , self . content )
self . send_chn ( " %s : %s " % ( result . group ( 3 ) , result . group ( 1 ) ) )
elif re . match ( " .*di[st] sur (#[a-zA-Z0-9]+) (.+)$ " , self . content ) is not None :
result = re . match ( " .*di[st] sur (#[a-zA-Z0-9]+) (.+)$ " , self . content )
2012-04-30 16:22:10 +00:00
self . send_msg ( result . group ( 1 ) , result . group ( 2 ) )
2012-04-09 02:19:39 +00:00
elif re . match ( " .*di[st] (.+) sur (#[a-zA-Z0-9]+)$ " , self . content ) is not None :
result = re . match ( " .*di[st] (.+) sur (#[a-zA-Z0-9]+)$ " , self . content )
2012-04-30 16:22:10 +00:00
self . send_msg ( result . group ( 2 ) , result . group ( 1 ) )
2012-04-09 02:19:39 +00:00
2012-04-18 21:35:58 +00:00
#Try modules
2012-04-09 02:19:39 +00:00
else :
2012-04-16 16:28:43 +00:00
for im in mods . keys ( ) :
if mods [ im ] . parseask ( self ) :
2012-04-09 02:19:39 +00:00
return
2012-04-18 21:35:58 +00:00
#Owner commands
2012-04-16 16:28:43 +00:00
elif self . content [ 0 ] == ' ` ' and self . sender == self . srv . owner :
self . cmd = self . content [ 1 : ] . split ( ' ' )
2012-05-14 15:50:11 +00:00
if self . cmd [ 0 ] == " reload " or self . cmd [ 0 ] == " reload_nosave " :
2012-04-16 16:28:43 +00:00
if len ( self . cmd ) > 1 :
if self . cmd [ 1 ] in mods :
2012-05-14 15:50:11 +00:00
if self . cmd [ 0 ] == " reload " :
mods [ self . cmd [ 1 ] ] . save_module ( )
2012-04-16 16:28:43 +00:00
imp . reload ( mods [ self . cmd [ 1 ] ] )
mods [ self . cmd [ 1 ] ] . load_module ( self . srv . datas_dir )
self . send_snd ( " Module %s rechargé avec succès. " % self . cmd [ 1 ] )
else :
self . send_snd ( " Module inconnu %s . " % self . cmd [ 1 ] )
else :
self . send_snd ( " Usage: `reload /module/. " )
self . send_snd ( " Loaded modules: " + ' , ' . join ( mods . keys ( ) ) + " . " )
2012-04-30 16:22:10 +00:00
elif self . cmd [ 0 ] == " ban " :
if len ( self . cmd ) > 1 :
BANLIST . append ( self . cmd [ 1 ] )
else :
print ( BANLIST )
elif self . cmd [ 0 ] == " banlist " :
print ( BANLIST )
elif self . cmd [ 0 ] == " unban " :
if len ( self . cmd ) > 1 :
BANLIST . remove ( self . cmd [ 1 ] )
elif self . cmd [ 0 ] == " credits " :
if len ( self . cmd ) > 1 and self . cmd [ 1 ] in CREDITS :
self . send_chn ( " %s a %d crédits. " % ( self . cmd [ 1 ] , CREDITS [ self . cmd [ 1 ] ] ) )
else :
for c in CREDITS . keys ( ) :
print ( CREDITS [ c ] . to_string ( ) )
2012-04-18 21:35:58 +00:00
#Messages stating with !
2012-04-09 02:19:39 +00:00
elif self . content [ 0 ] == ' ! ' :
2012-04-30 16:22:10 +00:00
self . mods = mods
2012-04-09 02:19:39 +00:00
self . cmd = self . content [ 1 : ] . split ( ' ' )
if self . cmd [ 0 ] == " help " :
if len ( self . cmd ) > 1 :
if self . cmd [ 1 ] in mods :
self . send_snd ( mods [ self . cmd [ 1 ] ] . help_full ( ) )
else :
self . send_snd ( " No help for command %s " % self . cmd [ 1 ] )
else :
2012-04-18 21:35:58 +00:00
self . send_snd ( " Pour me demander quelque chose, commencez votre message par mon nom ; je réagis à certain messages commençant par !, consulter l ' aide de chaque module : " )
for im in mods . keys ( ) :
self . send_snd ( " - !help %s : %s " % ( im , mods [ im ] . help_tiny ( ) ) )
2012-04-09 02:19:39 +00:00
2012-05-18 09:38:50 +00:00
else :
for im in mods . keys ( ) :
if im == " alias " :
continue
if mods [ im ] . parseanswer ( self ) :
return
if mods [ " alias " ] . parseanswer ( self ) :
2012-04-09 02:19:39 +00:00
return
else :
2012-04-16 16:28:43 +00:00
for im in mods . keys ( ) :
if mods [ im ] . parselisten ( self ) :
2012-04-09 02:19:39 +00:00
return
2012-04-18 21:35:58 +00:00
##############################
# #
# Extraction/Format text #
# #
##############################
def just_countdown ( self , delta , resolution = 5 ) :
sec = delta . seconds
hours , remainder = divmod ( sec , 3600 )
minutes , seconds = divmod ( remainder , 60 )
an = int ( delta . days / 365.25 )
days = delta . days % 365.25
sentence = " "
force = False
if resolution > 0 and ( force or an > 0 ) :
force = True
sentence + = " %i an " % ( an )
if an > 1 :
sentence + = " s "
if resolution > 2 :
sentence + = " , "
elif resolution > 1 :
sentence + = " et "
if resolution > 1 and ( force or days > 0 ) :
force = True
sentence + = " %i jour " % ( days )
if days > 1 :
sentence + = " s "
if resolution > 3 :
sentence + = " , "
elif resolution > 2 :
sentence + = " et "
if resolution > 2 and ( force or hours > 0 ) :
force = True
sentence + = " %i heure " % ( hours )
if hours > 1 :
sentence + = " s "
if resolution > 4 :
sentence + = " , "
elif resolution > 3 :
sentence + = " et "
if resolution > 3 and ( force or minutes > 0 ) :
force = True
sentence + = " %i minute " % ( minutes )
if minutes > 1 :
sentence + = " s "
if resolution > 4 :
sentence + = " et "
if resolution > 4 and ( force or seconds > 0 ) :
force = True
sentence + = " %i seconde " % ( seconds )
if seconds > 1 :
sentence + = " s "
return sentence [ 1 : ]
def countdown_format ( self , date , msg_before , msg_after , timezone = None ) :
""" Replace in a text %s by a sentence incidated the remaining time before/after an event """
if timezone != None :
os . environ [ ' TZ ' ] = timezone
time . tzset ( )
#Calculate time before the date
if datetime . now ( ) > date :
sentence_c = msg_after
delta = datetime . now ( ) - date
else :
sentence_c = msg_before
delta = date - datetime . now ( )
if timezone != None :
os . environ [ ' TZ ' ] = " Europe/Paris "
return sentence_c % self . just_countdown ( delta )
2012-04-09 02:19:39 +00:00
def extractDate ( self ) :
2012-04-18 21:35:58 +00:00
""" Parse a message to extract a time and date """
2012-04-09 02:19:39 +00:00
msgl = self . content . lower ( )
result = re . match ( " ^[^0-9]+(([0-9] { 1,4})[^0-9]+([0-9] { 1,2}|janvier|january|fevrier|février|february|mars|march|avril|april|mai|maï|may|juin|juni|juillet|july|jully|august|aout|août|septembre|september|october|octobre|oktober|novembre|november|decembre|décembre|december)([^0-9]+([0-9] { 1,4}))?)[^0-9]+(([0-9] { 1,2})[^0-9]*[h ' :]([^0-9]*([0-9] { 1,2})([^0-9]*[m \" :][^0-9]*([0-9] { 1,2}))?)?)?.*$ " , msgl + " TXT " )
if result is not None :
day = result . group ( 2 )
if len ( day ) == 4 :
year = day
day = 0
month = result . group ( 3 )
if month == " janvier " or month == " january " or month == " januar " :
month = 1
elif month == " fevrier " or month == " février " or month == " february " :
month = 2
elif month == " mars " or month == " march " :
month = 3
elif month == " avril " or month == " april " :
month = 4
elif month == " mai " or month == " may " or month == " maï " :
month = 5
elif month == " juin " or month == " juni " or month == " junni " :
month = 6
elif month == " juillet " or month == " jully " or month == " july " :
month = 7
elif month == " aout " or month == " août " or month == " august " :
month = 8
elif month == " september " or month == " septembre " :
month = 9
elif month == " october " or month == " october " or month == " oktober " :
month = 10
elif month == " november " or month == " novembre " :
month = 11
elif month == " december " or month == " decembre " or month == " décembre " :
month = 12
if day == 0 :
day = result . group ( 5 )
else :
year = result . group ( 5 )
hour = result . group ( 7 )
minute = result . group ( 9 )
second = result . group ( 11 )
print ( " Chaîne reconnue : %s / %s / %s %s : %s : %s " % ( day , month , year , hour , minute , second ) )
if year == None :
year = date . today ( ) . year
if hour == None :
hour = 0
if minute == None :
minute = 0
if second == None :
second = 1
else :
second = int ( second ) + 1
if second > 59 :
minute = int ( minute ) + 1
second = 0
return datetime ( int ( year ) , int ( month ) , int ( day ) , int ( hour ) , int ( minute ) , int ( second ) )
else :
return None