]> jfr.im git - irc/evilnet/x3.git/blob - src/modpython.py
mod-python: generalised the setting of the PYTHONPATH environment variable
[irc/evilnet/x3.git] / src / modpython.py
1 #!/usr/bin/python
2
3
4 # TODO notes:
5 #
6 # - impliment handle_* functions for everything x3 has register fetaures for
7 # - impliment script load/unload for user scripts.
8 # - load a script via this script.
9 # - script calls functions from here to set its functions up for calling on various actions
10 # - provide helper functions for subscripts to save settings attached to users/chanels
11 # - provide helper functions for scripts to do common things like msg a person or a channel,
12 # reply, etc.
13
14 import svc
15
16 import math
17
18 import sys
19
20
21 class irc:
22 """Used to interact with the world of IRC from module scripts"""
23
24 # some defaults to make shorthand easy
25 caller = ''
26 target = ''
27 service = ''
28
29 def __init__(self, service = None, caller = None, target = None):
30 """ Constructor """
31 self.caller = caller #the person who sent the command/message
32 self.service = service #the service who saw the message
33 self.target = target #the channel message was in (if public)
34
35 def send_target_privmsg(self, source, target, message):
36 svc.send_target_privmsg(source, target, "%s "%(message))
37
38 def reply(self, message):
39 """ Send a private reply to the user using convenience values"""
40 #print "DEBUG: sending a message from %s to %s: %s"%(self.service, self.caller, message)
41 if(len(self.target)):
42 self.send_target_privmsg(self.service, self.target, "%s: %s"%(self.caller, message))
43 else:
44 self.send_target_privmsg(self.service, self.caller, message)
45
46 class handler:
47 """ Main hub of python system. Handle callbacks from c. """
48
49 def __init__(self):
50 #print "DEBUG: constructor for handler initing"
51 self.plugins = plugins(self)
52 if(not self.plugins):
53 print "DEBUG: unable to make self.plugins!?!"
54
55 def init(self, irc): # not to be confused with __init__!
56 """ This gets called once all the objects are up and running. Otherwise,
57 were not done initing this own instance to be able to start calling it """
58 #print "DEBUG: in handler.init()"
59 self.plugins.init()
60 return 0
61
62 def join(self, irc, channel, nick):
63 #user = svc.get_user(nick)
64 #print "DEBUG: handler.join()"
65 return self.plugins.callhandler("join", irc, [channel, nick], [channel, nick])
66
67 def server_link(self, irc, name, desc):
68 return self.plugins.callhandler("server_link", irc, [name, desc], [name, desc])
69
70 def new_user(self, irc, nick, ident, hostname, info):
71 # we may filter on all the user fields, but we only pass the nick because
72 # the plugin can get the rest itself
73 return self.plugins.callhandler("new_user", irc, [nick, ident, hostname, info], [nick])
74
75 def nick_change(self, irc, nick, old_nick):
76 return self.plugins.callhandler("nick_change", irc, [nick, old_nick], [nick, old_nick])
77
78 def cmd_run(self, irc, cmd):
79 #print "DEBUG: handler.cmd_run: %s"%cmd
80 eval(cmd)
81 return 0
82
83 def addhook(self, event, method, filter=[None], data=None):
84 self.plugins.addhook(event, method, filter, data)
85 return 0
86
87 def addcommand(self, plugin, command, method):
88 self.addhook("command", method, [plugin, command])
89
90 def cmd_command(self, irc, plugin, cmd, args):
91 #print "DEBUG: handel.cmd_command; %s %s; args= %s"%(plugin, cmd, args)
92 return self.plugins.callhandler("command", irc, [plugin, cmd], [args])
93
94 def load(self, irc, plugin):
95 return self.plugins.load(plugin)
96
97 class plugins:
98 """Class to handle loading/unloading of plugins"""
99 loaded_plugins = {}
100 hooks = []
101
102 class hook:
103 """ This is a request from a plugin to be called on an event """
104 event = "" # Event to be called on (eg "join")
105 method = None # Method to call
106 filter = None # Arguments to filter
107 data = "" # plugin-supplied data for plugin use
108
109 def __init__(self, event, method, filter, data):
110 self.event = event
111 self.method = method
112 self.filter = filter
113 self.data = data
114
115 def event_is(self, event, evdata):
116 if(self.event == event):
117 for i in range(len(self.filter)):
118 if( self.filter[i] != None
119 and self.filter[i] != evdata[i]): # should be case insensitive? or how to compare?
120 #print "DEBUG: rejecting event, %s is not %s"%(self.filter[i], evdata[i])
121 return False
122 return True
123 else:
124 return False
125
126 def trigger(self, irc, args):
127 #print "DEBUG: Triggering %s event. with '%s' arguments."%(self.event, args)
128 self.method(irc, *args)
129
130 def __init__(self, handler):
131 """ Constructor """
132 #print "DEBUG: constructor for plugins initing"
133 self.handler = handler
134
135 def init(self):
136 #print "DEBUG: in plugins.init()"
137 self.load("annoy")
138 self.load("hangman")
139
140 def addhook(self, event, method, filter=[None], data=None):
141 #print "DEBUG: Adding hook for %s."%event
142 self.hooks.append(self.hook(event, method, filter, data))
143
144 def findhooksforevent(self, event, data):
145 ret = []
146 #print "DEBUG: findhooksforevent() looking..."
147 for hook in self.hooks:
148 #print "DEBUG: looking at a %s hook..."%hook.event
149 if(hook.event_is(event, data)):
150 ret.append(hook)
151 return ret
152
153 def callhandler(self, event, irc, filter, args):
154 for hook in self.findhooksforevent(event, filter):
155 if(hook.trigger(irc, args)):
156 return 1
157 return 0
158
159 def load(self, name):
160 """ Loads a plugin by name """
161 mod_name = "plugins.%s"%name
162 need_reload = False
163 if(sys.modules.has_key(mod_name)):
164 need_reload = true
165 #TODO: try to catch compile errors etc.
166
167 if(need_reload == False):
168 __import__(mod_name)
169 module = sys.modules[mod_name]
170 if(need_reload == True):
171 reload(module) # to ensure its read fresh
172 Class = module.Class
173 pluginObj = Class(self.handler, irc())
174 self.loaded_plugins[mod_name] = pluginObj
175 return True
176