[pybot-commits] CVS: pybot/pybot/modules example.py,NONE,1.1 __init__.py,1.2,1.3 eval.py,1.3,1.4 for
Brought to you by:
niemeyer
Update of /cvsroot/pybot/pybot/pybot/modules In directory sc8-pr-cvs1:/tmp/cvs-serv6970/pybot/modules Modified Files: __init__.py eval.py forward.py freshmeat.py help.py ignore.py infopack.py log.py messages.py modulecontrol.py notes.py options.py permission.py plock.py pong.py randnum.py repeat.py servercontrol.py social.py testadora.py threadedexample.py timer.py uptime.py userdata.py xmlrpc.py Added Files: example.py Removed Files: soap.py Log Message: Major work on pybot!! * modules/*: All modules moved to the new re matching system. * command.py: Removed old matching system. * modules/*: Pickling replaced by sqlite in all places were persistence was needed. * modules/*: All modules have inline help. * modules/*: All modules have permission help. * modules/infopack.py: Infopacks have help now. * *: Many method names changed to a better alternative. * options.py: Removed soft/hard relation. Now there's a single dict that might resist to reboots, if necessary. Notice that no standard module uses it for persistent options, since they use sqlite. * modules/example.py: Introduced basic sample module. * modules/soap.py: Obsoleted. Use xmlrpc instead. * scripts/pybotmsg.py: Added a basic xmlrpc client. * runner.py: Included other modules in the "default load" ones. * *: Other changes I probably forgot. --- NEW FILE: example.py --- # Copyright (c) 2000-2003 Gustavo Niemeyer <nie...@co...> # # This file is part of pybot. # # pybot is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # pybot is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with pybot; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA from pybot import mm, hooks, options, db import time import re HELP = """ This is a module implementation showing a basic but complete module to serve as reference for other modules. It implements the command "hello (world|irc)". You will need the "example" permission to use that. """ PERM_EXAMPLE = """ The "example" permission allows users to access commands in the "example" module. For more information, check "help example". """ class Example: def __init__(self): hooks.register("Message", self.message) # hello (world|irc) self.re1 = re.compile(r"hello\s+(?P<what>world|irc)\s*[.!]*$", re.I) mm.register_help(r"example", HELP, "example") mm.register_perm("example", PERM_EXAMPLE) # This is a volatile variable which will be reset once pybot # reboots, but won't be lost if pybot reloads this module. Use # "show option Test.firstload" to check it. #firstload = options.get("Test.firstload", [int(time.time())]) # This is a persistent variable which will resist even if # pybot dies. Notice that no module in the standard module set # is using this kind of persistence (they use sqlite instead), # and if no module uses it, the "memory" file is transparently # not saved. #loads = options.get("Test.loads", [1], reboot=1) #loads[0] += 1 # This is a simple way of doing the same thing with the sqlite # dict system. It is useful for simple variables like this. #loads = int(db["loads"] or 0) #loads += 1 #db["loads"] = loads # And this is a more complex one, saving the load time as well # ('num' wasn't needed in this case since we could use the number # of entries in the table, but was included to show a table with # more than one field). #db.table("test", "num,timestamp") #cursor = db.cursor() #cursor.execute("select max(num) from test") #row = cursor.fetchone() #if row[0]: # loads = int(row[0])+1 #else: # loads = 1 #cursor.execute("insert into test values (%s,%s)", # loads, int(time.time())) def unload(self): hooks.unregister("Message", self.message) mm.unregister_help(HELP) mm.unregister_perm(PERM_EXAMPLE) def message(self, msg): if not msg.forme: return None m = self.re1.match(msg.line) if m: if mm.hasperm(msg, "example"): what = m.group("what") msg.answer("%:", "The", what, "welcomes you", [(",", "/"), None], [".", "!"]) else: msg.answer("%:", ["You have no permission for that", "You are not allowed to do this"], [".", "!"]) return 0 def __loadmodule__(): global mod mod = Example() def __unloadmodule__(): global mod mod.unload() del mod # vim:ts=4:sw=4:et Index: __init__.py =================================================================== RCS file: /cvsroot/pybot/pybot/pybot/modules/__init__.py,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** __init__.py 4 Dec 2001 00:57:38 -0000 1.2 --- __init__.py 12 May 2003 20:42:20 -0000 1.3 *************** *** 1,3 **** ! # Copyright (c) 2000-2001 Gustavo Niemeyer <nie...@co...> # # This file is part of pybot. --- 1,3 ---- ! # Copyright (c) 2000-2003 Gustavo Niemeyer <nie...@co...> # # This file is part of pybot. Index: eval.py =================================================================== RCS file: /cvsroot/pybot/pybot/pybot/modules/eval.py,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** eval.py 5 May 2003 17:42:10 -0000 1.3 --- eval.py 12 May 2003 20:42:20 -0000 1.4 *************** *** 1,3 **** ! # Copyright (c) 2000-2001 Gustavo Niemeyer <nie...@co...> # # This file is part of pybot. --- 1,3 ---- ! # Copyright (c) 2000-2003 Gustavo Niemeyer <nie...@co...> # # This file is part of pybot. *************** *** 21,26 **** import re class Eval: ! def __init__(self, bot): hooks.register("Message", self.message) self.dict = {} --- 21,44 ---- import re + HELP = """ + The "eval <expr>" command allows you to evaluate expressions + using the python evaluation mechanism. The following functions are + currently available: map, zip, len, min, max, chr, ord, abs, hex, int, + oct, list, long, float, round, tuple, reduce, filter, coerce, plus all + methods in the 'math' method. For more information on these functions, + consult the Python manual. + """,""" + This command depends on the "eval" permission. Notice that a malicious + user is able to hang me using this command, so no untrusted users should + have this permission. + """ + + PERM_EVAL = """ + This permission allows users to use the "eval" command. For more + information send me "help eval". + """ + class Eval: ! def __init__(self): hooks.register("Message", self.message) self.dict = {} *************** *** 52,86 **** # Match 'eval <expr>[!|.]' self.re1 = re.compile(r"eval\s+(?P<expr>.*?)[!.]*$") def unload(self): hooks.unregister("Message", self.message) def message(self, msg): ! var = [] ! if msg.forme: ! m = self.re1.match(msg.line) ! if m: ! if mm.hasperm(0, msg.server.servername, msg.target, msg.user, "eval"): ! try: ! answer = str(eval(m.group("expr"), self.dict)) ! except: ! msg.answer("%:", ["Can't evaluate this", "There's something wrong with this expression"], [".", "!"]) ! else: ! if len(answer) > 255: ! msg.answer("%:", "Sorry, your answer is too long...") ! else: ! msg.answer("%:", str(answer)) else: ! msg.answer("%:", ["Sorry...", "Oops!", "Heh!"], "You don't have this power", [".", "!"]) ! return 0 ! def __loadmodule__(bot): ! global _eval ! _eval = Eval(bot) ! def __unloadmodule__(bot): ! global _eval ! _eval.unload() ! del _eval # vim:ts=4:sw=4:et --- 70,115 ---- # Match 'eval <expr>[!|.]' self.re1 = re.compile(r"eval\s+(?P<expr>.*?)[!.]*$") + + # eval[uate|uation] + mm.register_help("eval(?:uate|uation)?", HELP, "eval") + + mm.register_perm("eval", PERM_EVAL) def unload(self): hooks.unregister("Message", self.message) + mm.unregister_help(HELP) + mm.unregister_perm("eval") def message(self, msg): ! if not msg.forme: ! return None ! ! m = self.re1.match(msg.line) ! if m: ! if mm.hasperm(msg, "eval"): ! try: ! answer = str(eval(m.group("expr"), self.dict)) ! except: ! msg.answer("%:", ["Can't evaluate this", ! "There's something wrong with this " ! "expression"], [".", "!"]) else: ! if len(answer) > 255: ! msg.answer("%:", "Sorry, your answer is too long...") ! else: ! msg.answer("%:", str(answer)) ! else: ! msg.answer("%:", ["Sorry...", "Oops!"], ! "You don't have this power", [".", "!"]) ! return 0 ! def __loadmodule__(): ! global mod ! mod = Eval() ! def __unloadmodule__(): ! global mod ! mod.unload() ! del mod # vim:ts=4:sw=4:et Index: forward.py =================================================================== RCS file: /cvsroot/pybot/pybot/pybot/modules/forward.py,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** forward.py 20 Jun 2002 17:37:15 -0000 1.3 --- forward.py 12 May 2003 20:42:21 -0000 1.4 *************** *** 1,3 **** ! # Copyright (c) 2000-2001 Gustavo Niemeyer <nie...@co...> # # This file is part of pybot. --- 1,3 ---- ! # Copyright (c) 2000-2003 Gustavo Niemeyer <nie...@co...> # # This file is part of pybot. *************** *** 17,27 **** # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ! from pybot import mm, hooks, options, servers from string import join import re class Forward: ! def __init__(self, bot): ! self.data = options.gethard("Forward.data", []) hooks.register("Message", self.message_forward, 100) hooks.register("OutMessage", self.message_forward, 100) --- 17,46 ---- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ! from pybot import mm, hooks, servers, db from string import join import re + HELP = """ + You can make me forward messages between servers and/or channels using + "forward messages [for you] [from|on|at] (user|channel) <target>] + [(from|on) server <server>] to (user|channel) <target> [on server + <server>]". You may include a string to identify the origin of the + forwarded message appending "with (server|channel [and server]|<string>)" + to the message above. + """,""" + You can check what is being forwarded with "show forwards". The "forward" + permission is necessary to change or list forwards. + """ + + PERM_FORWARD = """ + The "forward" permission allows users to make me forward messages + between servers and/or channels, and to list what is being forwarded. + Check "help forward" for more information. + """ + class Forward: ! def __init__(self): ! db.table("forward", "fromserver,fromtarget,toserver,totarget," ! "flags,with") hooks.register("Message", self.message_forward, 100) hooks.register("OutMessage", self.message_forward, 100) *************** *** 34,42 **** hooks.register("Message", self.message) ! # Match 'forward messages [[(from|on|at) server <fromserver1>] | for you | [(from|on|at) [user|channel] <fromtarget>] [(from|on|at) server <fromserver2>]] to [user|channel] <totarget> [(on|at) server <toserver>] [with (server|channel [and server]|<withstring>)] [!|.]' ! self.re1 = re.compile(r"(?P<dont>do\s+not\s+|don't\s+)?forward\s+messages\s+(?:(?:(?:from\s+|on\s+|at\s+)server\s+(?P<fromserver1>\S+)\s+)|(?:(?P<foryou>for\s+you\s+)?(?:(?:from\s+|on\s+|at\s+)(?:channel\s+|user\s+)?(?P<fromtarget>\S+)\s+)?(?:(?:from\s+|on\s+|at\s+)(?:server\s+)?(?P<fromserver2>\S+)\s+)?))?to\s+(?:user\s+|channel\s+)?(?P<totarget>\S+)(?:\s+(?:on\s+|at\s+)server\s+(?P<toserver>\S+))?(?:\s+with(?:(?P<withserver1>\s+server)|(?P<withchannel>\s+channel)(?:\s+and\s+(?P<withserver2>server))?|(?P<withstring>\S+)))?\s*[!.]*$", re.I) ! # Match 'what['re| are] you forwarding [?]' ! self.re2 = re.compile(r"what(?:'re|\s+are)\s+you\s+forwarding\s*\?*$", re.I) def unload(self): --- 53,66 ---- hooks.register("Message", self.message) ! # forward messages [for you] [(from|on|at) [user|channel] <fromtarget>] [(from|on|at) server <fromserver>]] to [user|channel] <totarget> [(on|at) server <toserver>] [with (server|channel [and server]|<withstring>)] [!|.] ! self.re1 = re.compile(r"(?P<dont>do\s+not\s+|don't\s+)?forward\s+messages\s+(?P<foryou>for\s+you\s+)?(?:(?:from\s+|on\s+|at\s+)(?:channel\s+|user\s+)?(?P<fromtarget>\S+)\s+)?(?:(?:from\s+|on\s+|at\s+)(?:server\s+)?(?P<fromserver>\S+)\s+)?to\s+(?:user\s+|channel\s+)?(?P<totarget>\S+)(?:\s+(?:on\s+|at\s+)server\s+(?P<toserver>\S+))?(?:\s+with\s+(?P<withchannel>channel)?(?:\s+and\s+)?(?P<withserver>server)?(?P<withstring>\S+)?)?\s*$", re.I) ! # show forwards ! self.re2 = re.compile(r"show\s+forwards\s*$", re.I) ! ! # [message] forward[ing] ! mm.register_help("(?:message\s+)?forward(?:ing)?", HELP, "forward") ! ! mm.register_perm("forward", PERM_FORWARD) def unload(self): *************** *** 50,159 **** hooks.unregister("UserParted", self.parted_forward, 100) hooks.unregister("Message", self.message) def do_forward(self, server, target, nick, forme, before, after): ! for tuple in self.data: ! if (tuple[0]==None or tuple[0]==server.servername) and \ ! (tuple[1]==None or tuple[1]==target) and \ ! (not tuple[2] or forme): ! fwdserver = servers.get(tuple[3]) if fwdserver: s = nick ! if tuple[6]: ! s = s+"@"+tuple[6] else: ! with = tuple[5] ! if with&1: s = s+"@"+target ! if with&2: s = s+","+server.servername ! elif with&2: s = s+"@"+server.servername ! fwdserver.sendmsg(tuple[4], None, before+s+after, outhooks=0) ! def message_forward(self, msg): ! self.do_forward(msg.server, msg.target, msg.user.nick, msg.forme, "<", "> "+msg.rawline) def notice_forward(self, msg): ! self.do_forward(msg.server, msg.target, msg.user.nick, msg.forme, "-", "- "+msg.rawline) def ctcp_forward(self, msg): if msg.ctcp == "ACTION": ! self.do_forward(msg.server, msg.target, msg.user.nick, msg.forme, "* ", " "+msg.rawline) def joined_forward(self, server, target, user): ! self.do_forward(server, target, user.nick, 0, "--> ", " has joined") def parted_forward(self, server, target, user, reason): if reason: ! self.do_forward(server, target, user.nick, 0, "--> ", " has leaved: "+reason) else: ! self.do_forward(server, target, user.nick, 0, "--> ", " has leaved") def message(self, msg): ! var = [] ! if msg.forme: ! m = self.re1.match(msg.line) ! if m: ! if mm.hasperm(0, msg.server.servername, msg.target, msg.user, "forward"): ! foryou = m.group("foryou") != None ! fromtarget = m.group("fromtarget") ! fromserver = m.group("fromserver1") or m.group("fromserver2") ! totarget = m.group("totarget") ! toserver = m.group("toserver") or msg.server.servername ! with = 0 if m.group("withchannel"): ! with = with|1 ! if m.group("withserver1") or m.group("withserver2"): ! with = with|2 ! withstring = m.group("withstring") ! if m.group("dont"): ! try: ! self.data.remove((fromserver, fromtarget, foryou, toserver, totarget, with, withstring)) ! msg.answer("%:", ["Sure", "I'll not forward", "Of course", "No problems"], ["!", "."]) ! except ValueError: ! msg.answer("%:", ["Sorry, but", "Oops! I think", None], "I'm not forwarding any messages like this", [".", "!"]) else: ! self.data.append((fromserver, fromtarget, foryou, toserver, totarget, with, withstring)) ! msg.answer("%:", ["Sure", "I'll forward", "Right now", "Of course"], ["!", "."]) ! return 0 ! ! m = self.re2.match(msg.line) ! if m: ! if mm.hasperm(0, msg.server.servername, msg.target, msg.user, "listforward"): ! if self.data: ! for tuple in self.data: ! str = "I'm forwarding messages" ! if tuple[2]: ! str = str+" for me" ! if tuple[0] and tuple[1] and tuple[1] != msg.server.servername: ! str = str+" from "+tuple[1]+" at "+tuple[0] ! elif tuple[1]: ! str = str+" from "+tuple[1] ! elif tuple[0]: ! str = str+" from server "+tuple[0] ! str = str+" to "+tuple[4] ! if tuple[3] and tuple[3] != msg.server.servername: ! str = str+" at "+tuple[3] ! if tuple[5]==3: ! str = str+" with channel and server" ! elif tuple[5]&1: ! str = str+" with channel" ! elif tuple[5]&2: ! str = str+" with server" ! elif tuple[6]: ! str = str+" with "+tuple[6] ! msg.answer("%:", str, [".", "!"]) else: ! msg.answer("%:", ["Sir,", None], "I'm not forwarding anything", ["!", "."]) ! return 0 ! def __loadmodule__(bot): ! global forward ! forward = Forward(bot) ! def __unloadmodule__(bot): ! global forward ! forward.unload() ! del forward # vim:ts=4:sw=4:et --- 74,245 ---- hooks.unregister("UserParted", self.parted_forward, 100) hooks.unregister("Message", self.message) + mm.unregister_help(HELP) + mm.unregister_perm("forward") def do_forward(self, server, target, nick, forme, before, after): ! cursor = db.cursor() ! cursor.execute("select * from forward") ! for row in cursor.fetchall(): ! if (row.fromserver is None or ! row.fromserver == server.servername) and \ ! (row.fromtarget is None or row.fromtarget == target) and \ ! (forme or "f" in row.flags): ! fwdserver = servers.get(row.toserver) if fwdserver: s = nick ! if row.with.startswith(":"): ! s = s+"@"+row.with[1:] else: ! if "c" in row.with: s = s+"@"+target ! if "s" in row.with: s = s+","+server.servername ! elif "s" in row.with: s = s+"@"+server.servername ! fwdserver.sendmsg(row.totarget, None, before+s+after, ! outhooks=0) ! def message_forward(self, msg): ! self.do_forward(msg.server, msg.target, msg.user.nick, msg.forme, ! "<", "> "+msg.rawline) def notice_forward(self, msg): ! self.do_forward(msg.server, msg.target, msg.user.nick, msg.forme, ! "-", "- "+msg.rawline) def ctcp_forward(self, msg): if msg.ctcp == "ACTION": ! self.do_forward(msg.server, msg.target, msg.user.nick, msg.forme, ! "* ", " "+msg.rawline) def joined_forward(self, server, target, user): ! self.do_forward(server, target, user.nick, 0, ! "--> ", " has joined") def parted_forward(self, server, target, user, reason): if reason: ! self.do_forward(server, target, user.nick, 0, ! "--> ", " has leaved: "+reason) else: ! self.do_forward(server, target, user.nick, 0, ! "--> ", " has leaved") def message(self, msg): ! if not msg.forme: ! return None ! ! m = self.re1.match(msg.line) ! if m: ! if mm.hasperm(msg, "forward"): ! foryou = m.group("foryou") != None ! fromtarget = m.group("fromtarget") ! fromserver = m.group("fromserver") ! totarget = m.group("totarget") ! toserver = m.group("toserver") or msg.server.servername ! withstring = m.group("withstring") ! if withstring: ! with = ":"+withstring ! else: ! with = "" if m.group("withchannel"): ! with += "c" ! if m.group("withserver"): ! with += "s" ! flags = "" ! if foryou: ! flags += "f" ! cursor = db.cursor() ! where = [] ! wargs = [] ! if fromserver: ! where.append("fromserver=%s") ! wargs.append(fromserver) ! else: ! where.append("fromserver isnull") ! if fromtarget: ! where.append("fromtarget=%s") ! wargs.append(fromtarget) ! else: ! where.append("fromtarget isnull") ! where.extend(["toserver=%s", "totarget=%s", ! "flags=%s", "with=%s"]) ! wstr = " and ".join(where) ! wargs.extend([toserver, totarget, flags, with]) ! if m.group("dont"): ! cursor.execute("delete from forward where "+wstr, *wargs) ! if not cursor.rowcount: ! msg.answer("%:", ["Sorry, but", ! "Oops! I think", None], ! "I'm not forwarding any messages " ! "like this", [".", "!"]) else: ! msg.answer("%:", ["Sure", "I won't forward", ! "Of course", "No problems"], ! ["!", "."]) ! else: ! cursor.execute("select * from forward where "+wstr, ! *wargs) ! if cursor.rowcount: ! msg.answer("%:", "I'm already forwarding this.") else: ! cursor.execute("insert into forward values " ! "(%s,%s,%s,%s,%s,%s)", ! fromserver, fromtarget, ! toserver, totarget, flags, with) ! msg.answer("%:", ["Sure", "I'll forward", ! "Right now", "Of course"], ! ["!", "."]) ! return 0 ! ! m = self.re2.match(msg.line) ! if m: ! if mm.hasperm(msg, "forward"): ! cursor = db.cursor() ! cursor.execute("select * from forward") ! rows = cursor.fetchall() ! if not rows: ! msg.answer("%:", "I'm not forwarding anything", ["!", "."]) ! return 0 ! ! for row in rows: ! str = "I'm forwarding messages" ! if "f" in row.flags: ! str += " for me" ! if row.fromserver and row.fromtarget: ! str += " from " ! str += row.fromtarget ! str += " on server " ! str += msg.fromserver ! elif row.fromtarget: ! str += " from " ! str += row.fromtarget ! elif row.fromserver: ! str += " from server " ! str += row.fromserver ! str += " to " ! str += row.totarget ! if row.toserver and row.toserver != msg.server.servername: ! str += " on server " ! str += row.toserver ! if row.with.startswith(":"): ! str += " with " ! str += row.with[1:] ! elif "c" in row.with and "s" in row.with: ! str = str+" with channel and server" ! elif "c" in row.with: ! str = str+" with channel" ! elif "s" in row.with: ! str = str+" with server" ! msg.answer("%:", str, ".") ! return 0 ! def __loadmodule__(): ! global mod ! mod = Forward() ! def __unloadmodule__(): ! global mod ! mod.unload() ! del mod # vim:ts=4:sw=4:et Index: freshmeat.py =================================================================== RCS file: /cvsroot/pybot/pybot/pybot/modules/freshmeat.py,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -d -r1.7 -r1.8 *** freshmeat.py 9 May 2003 21:32:06 -0000 1.7 --- freshmeat.py 12 May 2003 20:42:21 -0000 1.8 *************** *** 1,3 **** ! # Copyright (c) 2000-2001 Gustavo Niemeyer <nie...@co...> # # This file is part of pybot. --- 1,3 ---- ! # Copyright (c) 2000-2003 Gustavo Niemeyer <nie...@co...> # # This file is part of pybot. *************** *** 17,21 **** # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ! from pybot import mm, hooks, options, servers, config import urllib import thread --- 17,21 ---- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ! from pybot import mm, hooks, servers, config, db import urllib import thread *************** *** 23,35 **** import re ! HELP = [ ! ("""\ ! You may tell me which channels/users I have to notify of freshmeat news \ ! with "[don't] show freshmeat news [(on|to) [channel|user] <target> [on \ ! server <server>]]".\ ! """,)] class Freshmeat: ! def __init__(self, bot): self.url = config.get("freshmeat", "url") if config.has_option("freshmeat", "proxy"): --- 23,41 ---- import re ! HELP = """ ! You may tell me which channels/users I have to notify of freshmeat news ! with "[don't] show freshmeat news [(on|to) [channel|user] <target> [on ! server <server>]]". The "freshmeat" permission is necessary to change ! these settings. ! """ ! ! PERM_FRESHMEAT = """ ! The "freshmeat" permission allows you to change what servers and ! channels will receive freshmeat news. Check "help freshmeat" for ! more information. ! """ class Freshmeat: ! def __init__(self): self.url = config.get("freshmeat", "url") if config.has_option("freshmeat", "proxy"): *************** *** 38,59 **** self.proxy = None self.interval = config.getint("freshmeat", "interval") ! self.newslast = options.gethard("Freshmeat.newslast", [None]) ! self.newstargets = options.gethard("Freshmeat.newstargets", []) ! self.newstargets_lock = thread.allocate_lock() self.fetch_lock = thread.allocate_lock() hooks.register("Message", self.message) ! mm.hooktimer(0, self.interval*60, self.checknews, ()) ! # Match '[don[']t|do not] show freshmeat news [(to|on|at|for) [channel|user] <target> [[on|at] server <server>]] [!|.]' self.re1 = re.compile(r"(?P<dont>don'?t\s+|do\s+not\s+)?show\s+freshmeat\s+news(?:\s+(?:to|on|at|for)(?:\s+channel|\s+user)?\s+(?P<target>\S+)(?:(?:\s+on|\s+at)?\s+server\s+(?P<server>\S+?))?)?\s*[!.]*$", re.I) # freshmeat [news] ! mm.register_help(0, "freshmeat(?:\s+news)?", HELP, "freshmeat") def unload(self): hooks.unregister("Message", self.message) ! mm.unhooktimer(0, self.interval*60, self.checknews, ()) ! ! mm.unregister_help(0, HELP) def shownews(self, newslist): --- 44,69 ---- self.proxy = None self.interval = config.getint("freshmeat", "interval") ! ! db.table("freshmeat", "servername,target") ! self.fetch_lock = thread.allocate_lock() + hooks.register("Message", self.message) ! ! mm.hooktimer(self.interval*60, self.checknews, ()) ! # [don[']t|do not] show freshmeat news [(to|on|at|for) [channel|user] <target> [[on|at] server <server>]] self.re1 = re.compile(r"(?P<dont>don'?t\s+|do\s+not\s+)?show\s+freshmeat\s+news(?:\s+(?:to|on|at|for)(?:\s+channel|\s+user)?\s+(?P<target>\S+)(?:(?:\s+on|\s+at)?\s+server\s+(?P<server>\S+?))?)?\s*[!.]*$", re.I) # freshmeat [news] ! mm.register_help("freshmeat(?:\s+news)?", HELP, "freshmeat") ! ! mm.register_perm("freshmeat", PERM_FRESHMEAT) def unload(self): hooks.unregister("Message", self.message) ! mm.unhooktimer(self.interval*60, self.checknews, ()) ! mm.unregister_help(HELP) ! mm.unregister_perm("freshmeat") def shownews(self, newslist): *************** *** 66,75 **** first = 0 newsmsg = newsmsg+news[0] ! self.newstargets_lock.acquire() ! for target in self.newstargets: ! server = servers.get(target[0]) if server: ! server.sendmsg(target[1], None, "Freshmeat news:", newsmsg, notice=1) ! self.newstargets_lock.release() def fetchnews(self): --- 76,86 ---- first = 0 newsmsg = newsmsg+news[0] ! cursor = db.cursor() ! cursor.execute("select * from freshmeat") ! for row in cursor.fetchall(): ! server = servers.get(row.servername) if server: ! server.sendmsg(row.target, None, "Freshmeat news:", ! newsmsg, notice=1) def fetchnews(self): *************** *** 84,87 **** --- 95,101 ---- else: newslist = [] + # We're in a thread. Get our own database object. + localdb = db.copy() + last = localdb["freshmeat.last"] while 1: news_name = string.rstrip(url.readline()) *************** *** 93,102 **** news_name = news_name[:-defstrlen] news_tuple = (news_name, news_time, news_url) ! if not (news_name and news_time and news_url) or news_tuple == self.newslast[0]: break newslist.append(news_tuple) url.close() if newslist: ! self.newslast[0] = newslist[0] newslist.reverse() self.shownews(newslist) --- 107,116 ---- news_name = news_name[:-defstrlen] news_tuple = (news_name, news_time, news_url) ! if not (news_name and news_time and news_url) or str(news_tuple) == last: break newslist.append(news_tuple) url.close() if newslist: ! localdb["freshmeat.last"] = str(newslist[0]) newslist.reverse() self.shownews(newslist) *************** *** 104,147 **** def checknews(self): ! if self.newstargets and self.fetch_lock.acquire(0): thread.start_new_thread(self.fetchnews, ()) def message(self, msg): ! if msg.forme: ! m = self.re1.match(msg.line) ! if m: ! if mm.hasperm(0, msg.server.servername, msg.target, msg.user, "freshmeatnews"): ! target = m.group("target") or msg.target ! servername = m.group("server") or msg.server.servername ! tuple = (servername, target) ! if not m.group("dont"): ! try: ! self.newstargets.index(tuple) ! except ValueError: ! self.newstargets.append(tuple) ! msg.answer("%:", ["Sure", "I'll show", "Of course"], ["!", ", sir!"]) ! else: ! msg.answer("%:", ["Oops!", "Sorry!", "Nope."], "I'm already showing news for this target", ["!", "."]) else: ! self.newstargets_lock.acquire() ! try: ! self.newstargets.remove(tuple) ! except ValueError: ! msg.answer("%:", ["Oops!", "Sorry!", "Nope."], "I'm not showing news for this target", ["!", "."]) ! else: ! msg.answer("%:", ["Sure", "I won't show", "Of course"], ["!", "."]) ! self.newstargets_lock.release() else: ! msg.answer("%:", ["You can't", "You're not allowed to", "You're not good enough to"], ["do this", "You can't change freshmeat news settings"], ["!", "."]) ! return 0 ! def __loadmodule__(bot): ! global freshmeat ! freshmeat = Freshmeat(bot) ! def __unloadmodule__(bot): ! global freshmeat ! freshmeat.unload() ! del freshmeat # vim:ts=4:sw=4:et --- 118,175 ---- def checknews(self): ! cursor = db.cursor() ! cursor.execute("select * from freshmeat") ! if cursor.rowcount and self.fetch_lock.acquire(0): thread.start_new_thread(self.fetchnews, ()) def message(self, msg): ! if not msg.forme: ! return None ! ! m = self.re1.match(msg.line) ! if m: ! if mm.hasperm(msg, "freshmeat"): ! target = m.group("target") or msg.target ! servername = m.group("server") or msg.server.servername ! cursor = db.cursor() ! if not m.group("dont"): ! cursor.execute("select * from freshmeat where " ! "servername=%s and target=%s", ! servername, target) ! if cursor.rowcount: ! msg.answer("%:", ["Oops!", "Sorry!", "Nope."], ! "I'm already showing news for " ! "this target", ["!", "."]) else: ! cursor.execute("insert into freshmeat values (%s,%s)", ! servername, target) ! msg.answer("%:", ["Sure", "I'll show", ! "Of course"], ["!", "."]) else: ! cursor.execute("delete from freshmeat where " ! "servername=%s and target=%s", ! servername, target) ! if not cursor.rowcount: ! msg.answer("%:", ["Oops!", "Sorry!", "Nope."], ! "I'm not showing news for " ! "this target", ["!", "."]) ! else: ! msg.answer("%:", ["Sure", "I won't show", ! "Of course"], ["!", "."]) ! else: ! msg.answer("%:", ["You can't", "You're not allowed to", ! "You're not good enough to"], ! ["do this", ! "change freshmeat settings"], ["!", "."]) ! return 0 ! def __loadmodule__(): ! global mod ! mod = Freshmeat() ! def __unloadmodule__(): ! global mod ! mod.unload() ! del mod # vim:ts=4:sw=4:et Index: help.py =================================================================== RCS file: /cvsroot/pybot/pybot/pybot/modules/help.py,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** help.py 9 May 2003 21:32:06 -0000 1.4 --- help.py 12 May 2003 20:42:21 -0000 1.5 *************** *** 1,3 **** ! # Copyright (c) 2000-2001 Gustavo Niemeyer <nie...@co...> # # This file is part of pybot. --- 1,3 ---- ! # Copyright (c) 2000-2003 Gustavo Niemeyer <nie...@co...> # # This file is part of pybot. *************** *** 18,40 **** from pybot import hooks, mm, options ! from types import ListType import re ! HELP = [ ! ("""\ ! You may ask for help using "[show] help [about] <something>".\ ! """,) ! ] class Help: ! def __init__(self, bot): ! self.data = options.getsoft("Help.data", []) ! self.triggers = options.getsoft("Help.triggers", {}) mm.register("register_help", self.mm_register_help) mm.register("unregister_help", self.mm_unregister_help) hooks.register("Message", self.message) # [show] help [about] <keyword> self.re1 = re.compile(r"(?:show\s+)?help(?:\s+about)?(?:\s+(?P<something>.+?))?\s*[.!]*$", re.I) def unload(self): --- 18,46 ---- from pybot import hooks, mm, options ! from types import ListType, TupleType import re ! HELP = """ ! You may ask for help using "[show] help [about] <something>". ! """ ! ! PERM_HELP = """ ! I'll only allow users with the "help" permission to ask for help. ! """ class Help: ! def __init__(self): ! self.data = options.get("Help.data", []) ! self.perm = options.get("Help.perm", {}) mm.register("register_help", self.mm_register_help) mm.register("unregister_help", self.mm_unregister_help) + mm.register("register_perm", self.mm_register_perm) + mm.register("unregister_perm", self.mm_unregister_perm) hooks.register("Message", self.message) # [show] help [about] <keyword> self.re1 = re.compile(r"(?:show\s+)?help(?:\s+about)?(?:\s+(?P<something>.+?))?\s*[.!]*$", re.I) + + self.mm_register_perm("help", PERM_HELP) def unload(self): *************** *** 42,78 **** mm.unregister("register_help") mm.unregister("unregister_help") def message(self, msg): ! if msg.forme: ! m = self.re1.match(msg.line) ! if m: ! if mm.hasperm(0, msg.server.servername, msg.target, msg.user, "help"): ! something = m.group("something") ! if something: ! found = 0 ! for pattern, text, triggers in self.data: ! if pattern.match(something): ! found = 1 for line in text: ! msg.answer("%:", *line) ! else: ! found = 1 ! for line in HELP: ! msg.answer("%:", *line) ! alltriggers = [] ! for pattern, text, triggers in self.data: ! alltriggers.extend(triggers) ! if alltriggers: ! alltriggers.sort() ! s = "At least the following help items are known: " ! s += ", ".join(alltriggers) ! msg.answer("%:", s) ! if not found: ! msg.answer("%:", ["No", "Sorry, no", "Sorry, but there's no"], "help about that", [".", "!"]) else: ! msg.answer("%:", ["Sorry, you", "You"], ["can't", "are not allowed to"], "ask for help", [".", "!"]) ! return 0 ! def mm_register_help(self, defret, pattern, text, triggers=None): if not triggers: triggers = [] --- 48,100 ---- mm.unregister("register_help") mm.unregister("unregister_help") + mm.unregister("register_perm") + mm.unregister("unregister_perm") + self.mm_unregister_perm("help") def message(self, msg): ! if not msg.forme: ! return None ! ! m = self.re1.match(msg.line) ! if m: ! if mm.hasperm(msg, "help"): ! something = m.group("something") ! if something: ! found = 0 ! for pattern, text, triggers in self.data: ! match = pattern.match(something) ! if match: ! found = 1 ! if callable(text): ! text(msg, match) ! elif type(text) in (ListType, TupleType): for line in text: ! line = line.replace("\n", " ").strip() ! msg.answer("%:", line) ! else: ! text = text.replace("\n", " ").strip() ! msg.answer("%:", text) else: ! found = 1 ! msg.answer("%:", HELP.replace("\n", " ").strip()) ! alltriggers = [] ! for pattern, text, triggers in self.data: ! alltriggers.extend(triggers) ! if alltriggers: ! alltriggers.sort() ! s = "At least the following help topics are known: " ! s += ", ".join(alltriggers) ! msg.answer("%:", s) ! if not found: ! msg.answer("%:", ["No", "Sorry, no", ! "Sorry, but there's no"], ! "help about that", [".", "!"]) ! else: ! msg.answer("%:", ["Sorry, you", "You"], ! ["can't", "are not allowed to"], ! "ask for help", [".", "!"]) ! return 0 ! def mm_register_help(self, pattern, text, triggers=None): if not triggers: triggers = [] *************** *** 81,99 **** self.data.append((re.compile(pattern, re.I), text, triggers)) ! def mm_unregister_help(self, defret, text): for i in range(len(self.data)-1,-1,-1): if self.data[i][1] == text: del self.data[i] # Make sure it is loaded first to let mm.register_help() # available to everyone. __loadlevel__ = 90 ! ! def __loadmodule__(bot): global help ! help = Help(bot) ! def __unloadmodule__(bot): global help help.unload() --- 103,129 ---- self.data.append((re.compile(pattern, re.I), text, triggers)) ! def mm_unregister_help(self, text): for i in range(len(self.data)-1,-1,-1): if self.data[i][1] == text: del self.data[i] + def mm_register_perm(self, perm, text): + self.perm[perm] = text + + def mm_unregister_perm(self, perm): + try: + del self.perm[perm] + except KeyError: + pass + # Make sure it is loaded first to let mm.register_help() # available to everyone. __loadlevel__ = 90 ! def __loadmodule__(): global help ! help = Help() ! def __unloadmodule__(): global help help.unload() Index: ignore.py =================================================================== RCS file: /cvsroot/pybot/pybot/pybot/modules/ignore.py,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** ignore.py 20 Jun 2002 17:37:16 -0000 1.3 --- ignore.py 12 May 2003 20:42:21 -0000 1.4 *************** *** 1,3 **** ! # Copyright (c) 2000-2001 Gustavo Niemeyer <nie...@co...> # # This file is part of pybot. --- 1,3 ---- ! # Copyright (c) 2000-2003 Gustavo Niemeyer <nie...@co...> # # This file is part of pybot. *************** *** 17,111 **** # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ! from pybot import mm, hooks, options ! from pybot.user import User class Ignore: ! def __init__(self, bot): ! self.ignoredata = options.gethard("Ignore.ignore", []) hooks.register("Message", self.message_ignore, 200) hooks.register("Message", self.message) def unload(self): hooks.unregister("Message", self.message_ignore, 200) hooks.unregister("Message", self.message) def message_ignore(self, msg): if self.isignored(msg.server.servername, msg.target, msg.user) and \ ! not mm.hasperm(0, msg.server.servername, msg.target, msg.user, None): return -1 def message(self, msg): ! var = [] ! if msg.match(var, 5, "%", "ignore", [("user", 0, "~"), None], [(["on", "at", None], [(1, "~this", "channel"), ("channel", 2, "^[#&+!][^,^G]+$")]), None], [(["on", "at", None], [(3, "~this", "server"), ("server", 4, "~")]), None], ["!", ".", None]): ! if mm.hasperm(0, msg.server.servername, msg.target, msg.user, "ignore"): ! if var[0] or var[1] or var[2] or var[3] or var[4]: ! if var[1]: ! channel = msg.target ! server = msg.server.servername ! else: ! channel = var[2] ! if var[3]: ! server = msg.server.servername ! else: ! server = var[4] ! if var[0]: ! user = User() ! user.setstring(var[0]) else: ! user = None ! self.ignore(server,channel,user) ! msg.answer("%:", ["Done!", "Ignored!", "No problems, sir!", "Ok, sir!"]) ! else: ! msg.answer("%:", ["Sorry, you", "Sir, you", "You"], ["can't ignore.", "don't have this power."]) ! return 0 ! if msg.match(var, 5, "%", "don't", "ignore", [("user", 0, "~"), None], [(["on", "at", None], [(1, "~this", "channel"), ("channel", 2, "^[#&+!][^,^G]+$")]), None], [(["on", "at", None], [(3, "~this", "server"), ("server", 4, "~")]), None], ["!", ".", None]): ! if mm.hasperm(0, msg.server.servername, msg.target, msg.user, "ignore"): ! if var[0] or var[1] or var[2] or var[3] or var[4]: ! if var[1]: ! channel = msg.target ! server = msg.server.servername else: ! channel = var[2] ! if var[3]: ! server = msg.server.servername ! else: ! server = var[4] ! if var[0]: ! user = User() ! user.setstring(var[0]) else: ! user = None ! self.dontignore(server,channel,user) ! msg.answer("%:", ["Done, sir!", "No problems!", "Ok!", "Right now!", "Right now, sir!"]) else: ! msg.answer("%:", ["Sorry, you", "Sir, you", "You"], "don't have this power.") return 0 ! def ignore(self, server, channel, user): ! self.ignoredata.append((server,channel,user)) ! def dontignore(self, server, channel, user): ! for tup in self.ignoredata: ! if (tup[0] == None or tup[0] == server) and \ ! (tup[1] == None or tup[1] == channel) and \ ! (tup[2] == None or user.match(tup[2].nick, tup[2].username, tup[2].host)): ! self.ignoredata.remove(tup) ! return 1 ! def isignored(self, server, channel, user): ! for tup in self.ignoredata: ! if (tup[0] == None or tup[0] == server) and \ ! (tup[1] == None or tup[1] == channel) and \ ! (tup[2] == None or user.match(tup[2].nick, tup[2].username, tup[2].host)): return 1 ! def __loadmodule__(bot): ! global ignore ! ignore = Ignore(bot) ! def __unloadmodule__(bot): ! global ignore ! ignore.unload() ! del ignore # vim:ts=4:sw=4:et --- 17,160 ---- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ! from pybot import mm, hooks, db ! import re ! ! HELP = """ ! You can make me ignore and unignore people sending me the message ! "[don't] ignore [user <user>] [on|at] [this channel|channel <channel>] ! [on|at] [this server|server <server>]. To do that, you must have the ! "ignore" permission. You may also give the "neverignore" permission ! to the people that should never be ignored, even if matching some ! ignore pattern. ! """ ! ! PERM_IGNORE = """ ! This permission allow users to change the ignore settings. For more ! information use "help ignore". ! """ ! ! PERM_NEVERIGNORE = """ ! People with the "neverignore" permission will never be ignored by ! me, even when they match some active ignore pattern. ! """ class Ignore: ! def __init__(self): ! db.table("ignore", "servername,target,userstr") ! hooks.register("Message", self.message_ignore, 200) hooks.register("Message", self.message) + + # [do not|don't] ignore [user <user>] [on|at] [this channel|channel <channel>] [on|at] [this server|server <server>] + self.re1 = re.compile(r"(?P<dont>do\s+not\s+|don't\s+)?ignore\s+(?:user\s+(?P<user>\S+?))?(?:(?:on\s+|at\s+)?(?:(?P<thischannel>this\s+channel)|channel\s+(?P<channel>\S+)))?(?:(?:on\s+|at\s+)?(?:(?P<thisserver>this\s+server)|server\s+(?P<server>\S+?)))?\s*$", re.I) + + # [un]ignore + mm.register_help(r"(?:un)?ignore", HELP, "ignore") + + mm.register_perm("ignore", PERM_IGNORE) + mm.register_perm("neverignore", PERM_NEVERIGNORE) def unload(self): hooks.unregister("Message", self.message_ignore, 200) hooks.unregister("Message", self.message) + mm.unregister_help(HELP) + mm.unregister_perm("ignore") + mm.unregister_perm("neverignore") def message_ignore(self, msg): if self.isignored(msg.server.servername, msg.target, msg.user) and \ ! not mm.hasperm(msg, "neverignore"): return -1 def message(self, msg): ! if not msg.forme: ! return None ! ! m = self.re1.match(msg.line) ! if m: ! if mm.hasperm(msg, "ignore"): ! userstr = m.group("user") ! if not filter(bool, m.groups()): ! return ! if m.group("thischannel"): ! target = msg.target ! servername = msg.server.servername ! else: ! target = m.group("channel") ! if m.group("thisserver"): ! servername = msg.server.servername else: ! servername = m.group("server") ! if not m.group("dont"): ! if self.ignore(servername, target, userstr): ! msg.answer("%:", ["Done", "Ignored", ! "No problems", "Ok"], [".", "!"]) else: ! msg.answer("%:", "I was already ignoring it", ! [".", "!"]) ! else: ! if self.dontignore(servername, target, userstr): ! msg.answer("%:", ["Done", "No problems", ! "Ok", "Right now"], [".", "!"]) else: ! msg.answer("%:", "I'm not ignoring it", [".", "!"]) else: ! msg.answer("%:", ["Sorry, you", "Oops, you", "You"], ! ["can't do this", "don't have this power"], ! [".", "!"]) return 0 ! def ignore(self, servername, target, userstr): ! cursor = db.cursor() ! existed = self.dontignore(servername, target, userstr, check=1) ! if existed: ! return 0 ! cursor.execute("insert into ignore values (%s,%s,%s)", ! servername, target, userstr) ! return 1 ! def dontignore(self, servername, target, userstr, check=0): ! where = [] ! wargs = [] ! if servername: ! where.append("servername=%s") ! wargs.append(servername) ! else: ! where.append("servername isnull") ! if target: ! where.append("target=%s") ! wargs.append(target) ! else: ! where.append("target isnull") ! if userstr: ! where.append("userstr=%s") ! wargs.append(userstr) ! else: ! where.append("userstr isnull") ! wstr = " and ".join(where) ! cursor = db.cursor() ! if not check: ! cursor.execute("delete from ignore where "+wstr, *wargs) ! else: ! cursor.execute("select * from ignore where "+wstr, *wargs) ! return bool(cursor.rowcount) ! def isignored(self, servername, target, user): ! cursor = db.cursor() ! cursor.execute("select * from ignore") ! for row in cursor.fetchall(): ! if (not row.servername or row.servername == servername) and \ ! (not row.target or row.target == target) and \ ! (not row.userstr or user.matchstr(row.userstr)): return 1 ! def __loadmodule__(): ! global mod ! mod = Ignore() ! def __unloadmodule__(): ! global mod ! mod.unload() ! del mod # vim:ts=4:sw=4:et Index: infopack.py =================================================================== RCS file: /cvsroot/pybot/pybot/pybot/modules/infopack.py,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** infopack.py 9 May 2003 21:32:06 -0000 1.4 --- infopack.py 12 May 2003 20:42:21 -0000 1.5 *************** *** 17,25 **** # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ! from pybot import config, options, hooks, mm from random import randrange import re import os class Info: def __init__(self, phrase="", action=0, notice=0, tonick=0): --- 17,42 ---- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ! from pybot import config, hooks, mm, db from random import randrange import re import os + HELP = """ + Infopacks are knowledge packages that you can plug to make me + provide some specific information to all users. To load some + infopack, put it in the infopack directory (check the configuration + file), and use the command "[load|reload|unload] infopack <name> + [in memory]" (the "infopackadmin" permission is needed). + """,""" + To show which infopacks are loaded, send me "show infopacks". You + can also ask for help about some specific infopack with "help infopack + <name>". + """ + + PERM_INFOPACKADMIN = """ + Users with the "infopackadmin" permission can change infopack + settings. Check "help infopack" for more informatino. + """ + class Info: def __init__(self, phrase="", action=0, notice=0, tonick=0): *************** *** 31,46 **** class Infopack: def __init__(self, filename): ! self.__filename = filename ! self.__info = {} ! self.__triggers = [] ! self.__masks = [] ! self.__defaults = [] ! def load(self): ! self.__info = {} ! self.__triggers = [] ! self.__masks = [] values = [] ! file = open(self.__filename) for line in file.xreadlines(): if line and line[0] != "#": --- 48,67 ---- class Infopack: def __init__(self, filename): ! self._filename = filename ! self._info = {} ! self._triggers = [] ! self._masks = [] ! self._defaults = [] ! self._help = [] ! ! def help(self): ! return self._help ! def load(self): ! self._info = {} ! self._triggers = [] ! self._masks = [] values = [] ! file = open(self._filename) for line in file.xreadlines(): if line and line[0] != "#": *************** *** 48,52 **** if values != []: values = [] ! self.__info[line[2:].rstrip()] = values elif line[0] == "V": value = line[2:].split(":", 1) --- 69,73 ---- if values != []: values = [] ! self._info[line[2:].rstrip()] = values elif line[0] == "V": value = line[2:].split(":", 1) *************** *** 55,84 **** elif line[0] == "T": pattern = re.compile(line[2:].rstrip(), re.I) ! self.__triggers.append(pattern) elif line[0] == "M": ! self.__masks.append(line[2:].rstrip()) elif line[0] == "D": value = line[2:].split(":", 1) value[1] = value[1].rstrip() ! self.__defaults.append(value) ... [truncated message content] |