]>
jfr.im git - erebus.git/blob - erebus.py
3 # Erebus IRC bot - Author: John Runyon
6 import os
, sys
, select
, MySQLdb
, MySQLdb
. cursors
, time
, random
7 import bot
, config
, ctlmod
9 class Erebus ( object ): #singleton to pass around
22 def __init__ ( self
, nick
, auth
= None ):
29 def msg ( self
, * args
, ** kwargs
):
30 main
. randbot (). msg ( self
, * args
, ** kwargs
)
31 def slowmsg ( self
, * args
, ** kwargs
):
32 main
. randbot (). slowmsg ( self
, * args
, ** kwargs
)
33 def fastmsg ( self
, * args
, ** kwargs
):
34 main
. randbot (). fastmsg ( self
, * args
, ** kwargs
)
37 return self
. auth
is not None
39 def authed ( self
, auth
):
40 if auth
== '0' : self
. auth
= None
41 else : self
. auth
= auth
. lower ()
49 if c
. execute ( "SELECT level FROM users WHERE auth = %s " , ( self
. auth
,)):
52 self
. glevel
= row
[ 'level' ]
60 if chan
not in self
. chans
: self
. chans
. append ( chan
)
63 self
. chans
. remove ( chan
)
65 return len ( self
. chans
) == 0
68 def nickchange ( self
, newnick
):
71 def __str__ ( self
): return self
. nick
72 def __repr__ ( self
): return "<User %r ( %d )>" % ( self
. nick
, self
. glevel
)
74 class Channel ( object ):
75 def __init__ ( self
, name
, bot
):
85 if c
. execute ( "SELECT user, level FROM chusers WHERE chan = %s " , ( self
. name
,)):
87 while row
is not None :
88 self
. levels
[ row
[ 'user' ]] = row
[ 'level' ]
92 def msg ( self
, * args
, ** kwargs
):
93 self
. bot
. msg ( self
, * args
, ** kwargs
)
94 def slowmsg ( self
, * args
, ** kwargs
):
95 self
. bot
. slowmsg ( self
, * args
, ** kwargs
)
96 def fastmsg ( self
, * args
, ** kwargs
):
97 self
. bot
. fastmsg ( self
, * args
, ** kwargs
)
99 def levelof ( self
, auth
):
103 if auth
in self
. levels
:
104 return self
. levels
[ auth
]
108 def setlevel ( self
, auth
, level
, savetodb
= True ):
112 if c
. execute ( "REPLACE INTO chusers (chan, user, level) VALUES ( %s , %s , %s )" , ( self
. name
, auth
, level
)):
113 self
. levels
[ auth
] = level
118 def userjoin ( self
, user
, level
= None ):
119 if user
not in self
. users
: self
. users
. append ( user
)
120 if level
== 'op' and user
not in self
. ops
: self
. ops
. append ( user
)
121 if level
== 'voice' and user
not in self
. voices
: self
. voices
. append ( user
)
122 def userpart ( self
, user
):
123 if user
in self
. ops
: self
. ops
. remove ( user
)
124 if user
in self
. voices
: self
. voices
. remove ( user
)
125 if user
in self
. users
: self
. users
. remove ( user
)
127 def userop ( self
, user
):
128 if user
in self
. users
and user
not in self
. ops
: self
. ops
. append ( user
)
129 def uservoice ( self
, user
):
130 if user
in self
. users
and user
not in self
. voices
: self
. voices
. append ( user
)
131 def userdeop ( self
, user
):
132 if user
in self
. ops
: self
. ops
. remove ( user
)
133 def userdevoice ( self
, user
):
134 if user
in self
. voices
: self
. voices
. remove ( user
)
136 def __str__ ( self
): return self
. name
137 def __repr__ ( self
): return "<Channel %r >" % ( self
. name
)
139 def __init__ ( self
, cfg
):
141 self
. trigger
= cfg
. trigger
142 if os
. name
== "posix" :
144 self
. po
= select
. poll ()
145 else : # f.e. os.name == "nt" (Windows)
146 self
. potype
= "select"
149 def newbot ( self
, nick
, user
, bind
, authname
, authpass
, server
, port
, realname
):
150 if bind
is None : bind
= ''
151 obj
= bot
. Bot ( self
, nick
, user
, bind
, authname
, authpass
, server
, port
, realname
)
152 self
. bots
[ nick
. lower ()] = obj
154 def newfd ( self
, obj
, fileno
):
155 self
. fds
[ fileno
] = obj
156 if self
. potype
== "poll" :
157 self
. po
. register ( fileno
, select
. POLLIN
)
158 elif self
. potype
== "select" :
159 self
. fdlist
. append ( fileno
)
161 def bot ( self
, name
): #get Bot() by name (nick)
162 return self
. bots
[ name
. lower ()]
163 def fd ( self
, fileno
): #get Bot() by fd/fileno
164 return self
. fds
[ fileno
]
165 def randbot ( self
): #get Bot() randomly
166 return self
. bots
[ random
. choice ( self
. bots
. keys ())]
168 def user ( self
, _nick
, justjoined
= False , create
= True ):
170 if nick
in self
. users
:
171 return self
. users
[ nick
]
173 user
= self
. User ( _nick
)
174 self
. users
[ nick
] = user
177 self
. randbot (). conn
. send ( "WHO %s n %% ant,1" % ( nick
))
182 def channel ( self
, name
): #get Channel() by name
183 if name
. lower () in self
. chans
:
184 return self
. chans
[ name
. lower ()]
188 def newchannel ( self
, bot
, name
):
189 chan
= self
. Channel ( name
. lower (), bot
)
190 self
. chans
[ name
. lower ()] = chan
194 if self
. potype
== "poll" :
195 return [ fd
for ( fd
, ev
) in self
. po
. poll ()]
196 elif self
. potype
== "select" :
197 return select
. select ( self
. fdlist
, [], [])[ 0 ]
199 def connectall ( self
):
200 for bot
in self
. bots
. itervalues ():
201 if bot
. conn
. state
== 0 :
204 def module ( self
, name
):
205 return ctlmod
. modules
[ name
]
207 def log ( self
, source
, level
, message
):
208 print " %0 9.3f %s [ %s ] %s " % ( time
. time () % 100000 , source
, level
, message
)
210 def getuserbyauth ( self
, auth
):
211 return [ u
for u
in self
. users
. itervalues () if u
. auth
== auth
. lower ()]
214 def hook ( self
, word
, handler
):
216 self
. msghandlers
[ word
]. append ( handler
)
218 self
. msghandlers
[ word
] = [ handler
]
219 def unhook ( self
, word
, handler
):
220 if word
in self
. msghandlers
and handler
in self
. msghandlers
[ word
]:
221 self
. msghandlers
[ word
]. remove ( handler
)
222 def hashook ( self
, word
):
223 return word
in self
. msghandlers
and len ( self
. msghandlers
[ word
]) != 0
224 def gethook ( self
, word
):
225 return self
. msghandlers
[ word
]
227 def hooknum ( self
, word
, handler
):
229 self
. numhandlers
[ word
]. append ( handler
)
231 self
. numhandlers
[ word
] = [ handler
]
232 def unhooknum ( self
, word
, handler
):
233 if word
in self
. numhandlers
and handler
in self
. numhandlers
[ word
]:
234 self
. numhandlers
[ word
]. remove ( handler
)
235 def hasnumhook ( self
, word
):
236 return word
in self
. numhandlers
and len ( self
. numhandlers
[ word
]) != 0
237 def getnumhook ( self
, word
):
238 return self
. numhandlers
[ word
]
240 def hookchan ( self
, chan
, handler
):
242 self
. chanhandlers
[ chan
]. append ( handler
)
244 self
. chanhandlers
[ chan
] = [ handler
]
245 def unhookchan ( self
, chan
, handler
):
246 if chan
in self
. chanhandlers
and handler
in self
. chanhandlers
[ chan
]:
247 self
. chanhandlers
[ chan
]. remove ( handler
)
248 def haschanhook ( self
, chan
):
249 return chan
in self
. chanhandlers
and len ( self
. chanhandlers
[ chan
]) != 0
250 def getchanhook ( self
, chan
):
251 return self
. chanhandlers
[ chan
]
254 class MyCursor ( MySQLdb
. cursors
. DictCursor
):
255 def execute ( self
, * args
, ** kwargs
):
256 if 'norecurse' in kwargs
: norecurse
= kwargs
[ 'norecurse' ]
257 else : norecurse
= False
258 main
. log ( "[SQL]" , "?" , "MyCursor.execute(self, %s , %s )" % ( ', ' . join ([ repr ( i
) for i
in args
]), ', ' . join ([ str ( key
)+ "=" + repr ( kwargs
[ key
]) for key
in kwargs
])))
259 # print "%09.3f [SQL] [#] MyCursor.execute(self, %s, %s)" % (time.time() % 100000, ', '.join([repr(i) for i in args]), ', '.join([str(key)+"="+repr(kwargs[key]) for key in kwargs]))
261 return super ( self
.__ class
__ , self
). execute (* args
, ** kwargs
)
262 except MySQLdb
. MySQLError
as e
:
263 main
. log ( "[SQL]" , "!" , "MySQL error! %r " % ( e
))
264 # print "%09.3f [SQL] [!] MySQL error! %r" % (time.time() % 100000, e)
267 return self
. execute ( norecurse
= True , * args
, ** kwargs
)
274 main
. db
= MySQLdb
. connect ( host
= cfg
. dbhost
, user
= cfg
. dbuser
, passwd
= cfg
. dbpass
, db
= cfg
. dbname
, cursorclass
= MyCursor
)
279 cfg
= config
. Config ( 'bot.config' )
281 pidfile
= open ( cfg
. pidfile
, 'w' )
282 pidfile
. write ( str ( os
. getpid ()))
287 autoloads
= [ mod
for mod
, yes
in cfg
. items ( 'autoloads' ) if int ( yes
) == 1 ]
288 for mod
in autoloads
:
289 ctlmod
. load ( main
, mod
)
293 if c
. execute ( "SELECT nick, user, bind, authname, authpass FROM bots WHERE active = 1" ):
297 main
. newbot ( row
[ 'nick' ], row
[ 'user' ], row
[ 'bind' ], row
[ 'authname' ], row
[ 'authpass' ], cfg
. host
, cfg
. port
, cfg
. realname
)
301 poready
= main
. poll ()
302 for fileno
in poready
:
303 for line
in main
. fd ( fileno
). getdata ():
304 main
. fd ( fileno
). parse ( line
)
306 if __name__
== '__main__' :
307 try : os
. rename ( 'logfile' , 'oldlogs/ %s ' % ( time
. time ()))
309 sys
. stdout
= open ( 'logfile' , 'w' , 1 )
310 sys
. stderr
= sys
. stdout