Added Euler module
[scrappy.git] / scrappy.py
blob1c60d8e56bac7994fe649fe2ddb196557f1bbc78
1 #!/usr/bin/env python
2 #Let's keep this file in particular as clean and neatly organized as possible.
3 #If this is nice and organized, then writing new modules will be a snap and this
4 #file should rarely have to be edited.
6 import irclib_scrappy
7 import sys, os
8 import traceback
9 import thread
11 ################################################################################
12 #set to False to turn off debugging to stdout
13 DEBUG = True
15 def debug(msg):
16 if DEBUG:
17 print msg
19 ################################################################################
22 #this is our main bot class. Once scrappy.py is called, an instance of this
23 #class (our bot) gets created and some initialization is done. The real work is
24 #done via modules that get loaded here.
25 class scrappy:
26 def __init__(self):
27 debug("Scrappy bot started.")
28 #hard-code these for now
29 #then write a config loading module
30 self.cmdchar = '!'
31 self.nickname = 'scrappy'
32 self.username = 'scrappy'
33 self.realname = 'Scrappy Bot'
34 self.server = ''
35 self.port = 6667
36 self.chanlist = []
37 self.ircsock = '' #this will be the socket
38 self.connection = '' #Thomas, explain this to me later
41 #our event lists.
42 #each module adds functions to be called to these events.
43 #each event handler calls all of the functions within its list.
44 self.events = ["connect", "disconnect", "error", "invite",
45 "join", "kick", "load", "mode", "msg", "part", "ping", "pong",
46 "privmsg", "privnotice", "pubmsg", "pubnotice", "quit"]
47 self.modulelist = []
48 self.connect_events = []
49 self.disconnect_events = []
50 self.error_events = []
51 self.invite_events = []
52 self.join_events = []
53 self.kick_events = []
54 self.load_events = []
55 self.mode_events = []
56 self.msg_events = []
57 self.part_events = []
58 self.ping_events = []
59 self.pong_events = []
60 self.privmsg_events = []
61 self.privnotice_events = []
62 self.pubmsg_events = []
63 self.pubnotice_events = []
64 self.quit_events = [] #for other users quitting, not the bot
65 #self.what_other_events? = []
67 sys.path.append(os.path.join(os.getcwd(), "modules"))
68 #need to load a few modules here - the rest are done elsewhere
69 self.load_module("modmanage")
70 self.load_module("core")
71 self.load_module("config")
73 #self.register_onload_event(loadme)
75 #on_load event
76 #self.on_load()
78 #start the bot
79 self.__main()
80 ########################################################################
81 def parse_argv(self):
82 """Parse the commandline args and print a usage message if incorrect."""
83 if len(sys.argv) < 3: #Need at least server
84 self.print_usage()
85 sys.exit(1)
87 #split out the port if specified
88 s = sys.argv[1].split(":", 1)
89 self.server = s[0]
91 #a port is given
92 if len(s) == 2:
93 try:
94 self.port = int(s[1])
95 except ValueError:
96 print "Error: Erroneous port."
97 sys.exit(1)
99 self.nickname = sys.argv[2]
100 #add channels to chanlist
101 for ch in sys.argv[3:]:
102 self.chanlist.append('#%s' % ch)
104 def print_usage(self):
105 print 'Usage: %s <server[:port]> <nickname> [channel 1 channel 2 ... channelN]' % sys.argv[0]
107 ########################################################################
108 def __main(self):
109 """The real work. Initialize our connection and register events."""
110 #parse comamnd line and create a new socket
111 self.parse_argv()
112 self.ircsock = irclib_scrappy.IRC()
114 #attempt to create a socket and connect to the server
115 try:
116 self.connection = self.ircsock.server().connect(self.server,
117 self.port, self.nickname,
118 username=self.username,ircname=self.realname)
119 #connection failed, print error and exit
120 except irclib_scrappy.ServerConnectionError, x:
121 print x
122 sys.exit(1)
124 #if all goes well, register handlers
125 self.connection.add_global_handler("welcome", self.on_connect)
126 self.connection.add_global_handler("disconnect", self.on_disconnect)
127 self.connection.add_global_handler("error", self.on_error)
128 self.connection.add_global_handler("invite", self.on_invite)
129 self.connection.add_global_handler("join", self.on_join)
130 self.connection.add_global_handler("kick", self.on_kick)
131 self.connection.add_global_handler("mode", self.on_mode)
132 self.connection.add_global_handler("part", self.on_part)
133 self.connection.add_global_handler("ping", self.on_ping)
134 self.connection.add_global_handler("pong", self.on_pong)
135 self.connection.add_global_handler("privmsg", self.on_privmsg)
136 self.connection.add_global_handler("privnotice", self.on_privnotice)
137 self.connection.add_global_handler("pubmsg", self.on_privmsg)
138 self.connection.add_global_handler("quit", self.on_quit)
141 #self.list_modules()
143 #enter main event loop after this
144 #no code after here
145 try:
146 self.ircsock.process_forever()
147 except KeyboardInterrupt:
148 self.connection.quit("Keyboard interrupt!")
151 ########################################################################
152 ###################
153 #Event Registering#
154 ###################
156 def register_event(self, event_type, func):
157 """Call this with an event_type and a function to call when that event_type happens."""
158 #list of legal event types
159 #keep in ABC order
161 if not event_type in self.events:
162 debug("I don't know what an %s event is." % event_type)
163 return
165 #event type is good. Add it to appropriate event list
168 #BUGGY NONWORKING STUFF
170 listname = "self."+event_type+"_events"
171 #debug(func.__name__)
172 if func.__name__ in eval(listname):
173 debug("%s already exists in %s! Removing old copy and inserting this..." % (func, listname))
174 eval(listname).remove(func.__name__)
176 eval(listname).append(func)
178 if event_type == "msg":
179 self.privmsg_events.append(func)
180 self.pubmsg_events.append(func)
183 def unregister_event(self, event_type, func):
184 pass
189 ########################################################################
190 ##################
191 #Event Handlers #
192 ##################
194 def on_connect(self, conn, eventlist):
195 """Called when bot makes a connection to the server."""
196 #do all of our events
197 for func in self.connect_events:
198 thread.start_new_thread(func)
200 if self.identify == True:
201 conn.privmsg("nickserv", "identify %s"
202 % self.nickservpass)
204 #join channels
205 for chan in self.chanlist:
206 if irclib_scrappy.is_channel(chan):
207 conn.join(chan)
209 ########################################################################
210 def on_disconnect(self, conn, eventlist):
211 """Called when the connection to the server is closed."""
212 for func in self.disconnect_events:
213 thread.start_new_thread(func)
214 conn.quit("Scrappy bot signing off.")
215 #do we need to clean stuff up?
216 sys.exit(0)
218 ########################################################################
219 def on_error(self, conn, eventlist):
220 debug("Error received: %s" % eventlist.arguments())
221 for func in self.error_events:
222 thread.start_new_thread(func)
225 ########################################################################
226 def on_invite(self, conn, eventlist):
227 debug("Received an invite: %s" % eventlist.arguments())
228 for func in self.invite_events:
229 thread.start_new_thread(func)
231 ########################################################################
232 def on_join(self, conn, eventlist):
233 debug("User joined: %s" % eventlist.arguments())
234 for func in self.join_events:
235 thread.start_new_thread(func)
237 ########################################################################
238 def on_kick(self, conn, eventlist):
239 debug("Someone was kicked: %s" % eventlist.arguments())
240 for func in self.kick_events:
241 thread.start_new_thread(func)
243 ########################################################################
244 def on_mode(self, conn, eventlist):
245 debug("Mode change: %s" % eventlist.arguments())
246 for func in self.mode_events:
247 thread.start_new_thread(func)
249 ########################################################################
250 def on_part(self, conn, eventlist):
251 debug("Part: %s" % eventlist.arguments())
252 for func in self.part_events:
253 thread.start_new_thread(func)
255 ########################################################################
256 def on_ping(self, conn, eventlist):
257 debug("Ping: %s" % eventlist.arguments())
258 for func in self.ping_events:
259 thread.start_new_thread(func)
261 ########################################################################
262 def on_pong(self, conn, eventlist):
263 debug("Pong: %s" % eventlist.arguments())
264 for func in self.pong_events:
265 thread.start_new_thread(func)
267 ########################################################################
268 def on_privmsg(self, conn, eventlist):
269 """Called when bot receives a private or channel (public) message."""
270 #eventlist.arguments() = the message body
271 arg = eventlist.arguments()[0]
273 iscmd = False #?
275 nick = irclib_scrappy.nm_to_n(eventlist.source())
276 user = irclib_scrappy.nm_to_u(eventlist.source())
277 host = irclib_scrappy.nm_to_h(eventlist.source())
279 if arg[0] == self.cmdchar:
280 cmd = arg[1:]
281 iscmd = True
282 else:
283 cmd = arg
285 #how can we make the list that's passed to functions more friendly?
286 #we end up parsing the list again in the called function...
287 for func in self.privmsg_events:
288 thread.start_new_thread(func, (conn, [nick, user, host, iscmd, cmd, eventlist.target()], self))
292 ########################################################################
293 def on_privnotice(self, conn, eventlist):
294 debug("Privnotice: %s" % eventlist.arguments())
295 for func in self.privnotice_events:
296 thread.start_new_thread(func)
300 ########################################################################
301 #right now this isn't used because it's assumed that privmsg == pubmsg
302 #this should probably be changed...
303 def on_pubmsg(self, conn, eventlist):
304 debug("Pubmsg: % " % eventlist.arguments())
305 for func in self.pubmsg_events:
306 func()
308 ########################################################################
309 def on_quit(self, conn, eventlist):
310 debug("Quit: %s" % eventlist.arguments())
311 for func in self.quit_events:
312 thread.start_new_thread(func)
315 ################
316 #Module Loading#
317 ################
318 def load_module(self,name):
320 #for whatever reason, OS X needs your modules folder to be in PYTHONPATH to load
321 try:
322 #sys.path.append(os.path.join(os.getcwd(), "modules"))
323 exec("from %s import %s" % (name, name))
324 #module = __import__(name)
325 except ImportError:
326 #should be error output
327 print "No such module\n"
328 print traceback.print_exc()
329 return "Sorry, there was an error loading %s." % name
331 debug(eval(name).init(self))
332 self.register_module(name,'foo','foo')
333 return "Loaded %s." % name
335 def unload_module(self, name):
336 try:
337 self.modulelist.index(name)
338 except:
339 print "No such module!"
340 return "Sorry, no module named %s is loaded." % name
341 self.unregister_module(name)
343 return "%s unloaded using a really bad kludge." % name
345 def register_module(self, name, eventlist, function):
346 self.modulelist.append(name)
348 def unregister_module(self, name):
349 self.modulelist.remove(name)
353 def list_modules(self):
354 """List currently loaded modules."""
355 print "Currently loaded modules:"
356 for mod in self.modulelist:
357 print mod
360 if(__name__ == "__main__"):
361 bot = scrappy()