pybot-commits Mailing List for pybot (Page 2)
Brought to you by:
niemeyer
You can subscribe to this list here.
2001 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
(6) |
Dec
(7) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2002 |
Jan
|
Feb
|
Mar
(1) |
Apr
(7) |
May
(1) |
Jun
(14) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2003 |
Jan
|
Feb
|
Mar
|
Apr
|
May
(56) |
Jun
(4) |
Jul
|
Aug
(85) |
Sep
(2) |
Oct
|
Nov
|
Dec
|
From: Gustavo N. <nie...@us...> - 2003-08-27 17:52:40
|
Update of /cvsroot/pybot/pybot/pybot/modules In directory sc8-pr-cvs1:/tmp/cvs-serv30148/pybot/modules Modified Files: remoteinfo.py Log Message: Removed remaining code handling old "allow" system in remoteinfo. Index: remoteinfo.py =================================================================== RCS file: /cvsroot/pybot/pybot/pybot/modules/remoteinfo.py,v retrieving revision 1.8 retrieving revision 1.9 diff -C2 -d -r1.8 -r1.9 *** remoteinfo.py 27 Aug 2003 17:08:14 -0000 1.8 --- remoteinfo.py 27 Aug 2003 17:52:30 -0000 1.9 *************** *** 85,90 **** class RemoteInfo: def __init__(self): ! db.table("remoteinfo", "id integer primary key, url, regex, interval", ! constraints="unique (url)") self.info = options.get("RemoteInfo.info", {}) self.info_lock = options.get("RemoteInfo.info_lock", {}) --- 85,89 ---- class RemoteInfo: def __init__(self): ! db.table("remoteinfo", "url unique, regex, interval") self.info = options.get("RemoteInfo.info", {}) self.info_lock = options.get("RemoteInfo.info_lock", {}) *************** *** 202,226 **** self.unlock_url(url) - def get_allowed_urls(self, servername, target): - cursor = db.cursor() - cursor.execute("select remoteinfo.url,remoteinfoallow.* " - "from remoteinfoallow left join remoteinfo " - "on remoteinfo.id=remoteinfoallow.infoid") - # [0] url, [1] infoid, [2] servername, [3] target - allowed = {} - for row in cursor.fetchall(): - if (not row[2] or row[2] == servername) and \ - (not row[3] or row[3] == target): - allowed[row[0]] = 1 - return allowed.keys() - def message_remoteinfo(self, msg): ret = None - #allowed = self.get_allowed_urls(msg.server.servername, - # msg.answertarget) allowed = mm.permparams(msg, "remoteinfo") for url, info in self.info.items(): - #if not mm.hasperm(msg, "remoteinfo", url): - # continue if url not in allowed: continue --- 201,208 ---- *************** *** 366,371 **** m = self.re3.match(msg.line) if m: ! if mm.hasperm(msg, "remoteinfo") or \ ! mm.hasperm(msg, "reloadremoteinfo"): cursor = db.cursor() cursor.execute("select * from remoteinfo") --- 348,352 ---- m = self.re3.match(msg.line) if m: ! if mm.hasperm(msg, "remoteinfoadmin"): cursor = db.cursor() cursor.execute("select * from remoteinfo") *************** *** 385,416 **** if interval > 1: unit += "s" - cursor.execute("select * from remoteinfoallow where " - "infoid=%s", (row.id,)) - if cursor.rowcount: - allowed = "(for " - first = 1 - for _row in cursor.fetchall(): - if not first: - allowed += ", " - if _row.servername and _row.target: - allowed += "%s at %s" % (_row.target, - _row.servername) - elif _row.servername: - allowed += "server %s" % _row.servername - elif _row.target: - allowed += _row.target - else: - allowed = "(for everybody)" - break - first = 0 - else: - allowed += ")" - else: - allowed = "(for nobody)" regex = row.regex if regex and regex[0] == "\\": regex = "\\"+regex msg.answer("-", row.url, "each", str(interval), unit, ! "with regex", regex, allowed) else: msg.answer("%:", "No remote info urls are currently " --- 366,374 ---- if interval > 1: unit += "s" regex = row.regex if regex and regex[0] == "\\": regex = "\\"+regex msg.answer("-", row.url, "each", str(interval), unit, ! "with regex", regex) else: msg.answer("%:", "No remote info urls are currently " |
From: Gustavo N. <nie...@us...> - 2003-08-27 17:24:03
|
Update of /cvsroot/pybot/pybot/pybot/modules In directory sc8-pr-cvs1:/tmp/cvs-serv26166/pybot/modules Modified Files: infopack.py Log Message: Protected infopack search with permissions as well. Index: infopack.py =================================================================== RCS file: /cvsroot/pybot/pybot/pybot/modules/infopack.py,v retrieving revision 1.10 retrieving revision 1.11 diff -C2 -d -r1.10 -r1.11 *** infopack.py 27 Aug 2003 17:08:14 -0000 1.10 --- infopack.py 27 Aug 2003 17:23:56 -0000 1.11 *************** *** 420,451 **** [".", "!"]) return 0 ! try: ! pattern = re.compile(regexp, re.I) ! except re.error: ! msg.answer("%:", "Invalid pattern", [".", "!"]) ! return 0 ! results = pack.search(pattern) ! reslen = len(results) ! if not results: ! msg.answer("%:", ["Pattern not found", ! "Couldn't find anything with that pattern", ! "Nothing found"], [".", "!"]) ! elif reslen > MAXSEARCHRESULTS: ! msg.answer("%:", ["Found too many entries", ! "There are many entries like this", ! "There are many matches"], ! ", here are the first %d:"%MAXSEARCHRESULTS) ! elif reslen > 1: ! msg.answer("%:", ["Found %d entries:" % reslen, ! "Found %d matches:" % reslen]) else: ! msg.answer("%:", ["Found one entry:", ! "Found one match:"]) ! n = 0 ! for result in results: ! msg.answer("-", result) ! n += 1 ! if n == MAXSEARCHRESULTS: ! break return 0 --- 420,457 ---- [".", "!"]) return 0 ! if mm.hasperm(msg, "infopack", name): ! try: ! pattern = re.compile(regexp, re.I) ! except re.error: ! msg.answer("%:", "Invalid pattern", [".", "!"]) ! return 0 ! results = pack.search(pattern) ! reslen = len(results) ! if not results: ! msg.answer("%:", ["Pattern not found", ! "Couldn't find anything with that pattern", ! "Nothing found"], [".", "!"]) ! elif reslen > MAXSEARCHRESULTS: ! msg.answer("%:", ["Found too many entries", ! "There are many entries like this", ! "There are many matches"], ! ", here are the first %d:"%MAXSEARCHRESULTS) ! elif reslen > 1: ! msg.answer("%:", ["Found %d entries:" % reslen, ! "Found %d matches:" % reslen]) ! else: ! msg.answer("%:", ["Found one entry:", ! "Found one match:"]) ! n = 0 ! for result in results: ! msg.answer("-", result) ! n += 1 ! if n == MAXSEARCHRESULTS: ! break else: ! msg.answer("%:", ["You're not allowed to search on " ! "this infopack", ! "You can't search on this infopack"], ! [".", "!"]) return 0 |
From: Gustavo N. <nie...@us...> - 2003-08-27 17:08:36
|
Update of /cvsroot/pybot/pybot In directory sc8-pr-cvs1:/tmp/cvs-serv23476 Modified Files: ChangeLog Log Message: * modules/permissions.py: Implemented permission parameters. * modules/{remoteinfo.py,infopack.py}: Adapted to work with premission parameters. * modules/infopack.py: Implemented infopack searching. Index: ChangeLog =================================================================== RCS file: /cvsroot/pybot/pybot/ChangeLog,v retrieving revision 1.32 retrieving revision 1.33 diff -C2 -d -r1.32 -r1.33 *** ChangeLog 26 Aug 2003 19:56:22 -0000 1.32 --- ChangeLog 27 Aug 2003 17:08:13 -0000 1.33 *************** *** 1,2 **** --- 1,9 ---- + 2003-08-27 Gustavo Niemeyer <nie...@co...> + * modules/permissions.py: Implemented permission + parameters. + * modules/{remoteinfo.py,infopack.py}: Adapted to + work with premission parameters. + * modules/infopack.py: Implemented infopack searching. + 2003-08-26 Gustavo Niemeyer <nie...@co...> * pybot/misc.py: Introduced striphtml(). |
From: Gustavo N. <nie...@us...> - 2003-08-27 17:08:35
|
Update of /cvsroot/pybot/pybot/pybot/modules In directory sc8-pr-cvs1:/tmp/cvs-serv23476/pybot/modules Modified Files: infopack.py permission.py remoteinfo.py Log Message: * modules/permissions.py: Implemented permission parameters. * modules/{remoteinfo.py,infopack.py}: Adapted to work with premission parameters. * modules/infopack.py: Implemented infopack searching. Index: infopack.py =================================================================== RCS file: /cvsroot/pybot/pybot/pybot/modules/infopack.py,v retrieving revision 1.9 retrieving revision 1.10 diff -C2 -d -r1.9 -r1.10 *** infopack.py 25 Aug 2003 20:44:24 -0000 1.9 --- infopack.py 27 Aug 2003 17:08:14 -0000 1.10 *************** *** 29,35 **** [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>". """ --- 29,38 ---- [in memory]" (the "infopackadmin" permission is needed). """,""" ! After you load some infopack, you must say explicitly which ! users/channels and servers will be able to obtain information from ! it. To do that give the permission "infopack(<name>)" for these you ! want to allow. To show which infopacks are loaded, send me ! "show infopacks". You can also ask for help about some specific ! infopack with "help infopack <name>". """ *************** *** 39,42 **** --- 42,53 ---- """ + PERM_INFOPACK = """ + Users will be able to access information in some infopack if + they have the "infopack(<name>)" permission. Check "help infopack" + for more information. + """ + + MAXSEARCHRESULTS = 3 + class Info: def __init__(self, phrase="", action=0, notice=0, tonick=0): *************** *** 79,85 **** if line and line[0] != "#": if line[0] == "K": ! if values != []: ! values = [] ! self._info[line[2:].rstrip()] = values elif line[0] == "V": value = line[2:].split(":", 1) --- 90,96 ---- if line and line[0] != "#": if line[0] == "K": ! values = [] ! self._info[line[2:].rstrip().lower()] = \ ! (line[2:].rstrip(), values) elif line[0] == "V": value = line[2:].split(":", 1) *************** *** 147,156 **** found = 0 file = open(self._filename) ! for line in file.xreadlines(): if line and line[0] != "#": if not found: if line[0] == "K": key = line[2:].rstrip() ! if key == findkey: found = 1 foundvalue = 0 --- 158,167 ---- found = 0 file = open(self._filename) ! for line in file.readlines(): if line and line[0] != "#": if not found: if line[0] == "K": key = line[2:].rstrip() ! if key.lower() == findkey: found = 1 foundvalue = 0 *************** *** 164,169 **** break file.close() ! return values ! def get(self, line): --- 175,179 ---- break file.close() ! return key, values def get(self, line): *************** *** 173,179 **** key = m.group(1).lower() if self._info: ! values = self._info.get(key) else: ! values = self.getinfo(key) if values: value = random.choice(values) --- 183,192 ---- key = m.group(1).lower() if self._info: ! try: ! key, values = self._info[key] ! except KeyError: ! values = None else: ! key, values = self.getinfo(key) if values: value = random.choice(values) *************** *** 189,197 **** if "m" in flags: mask = random.choice(self._masks) ! info.phrase = mask%value[1] else: info.phrase = value[1] return info class InfopackModule: def __init__(self): --- 202,251 ---- if "m" in flags: mask = random.choice(self._masks) ! info.phrase = mask % {"key": key, "value": value[1]} else: info.phrase = value[1] return info + def _search(self, pattern, key, values, results): + found = 0 + if pattern.match(key): + found = 1 + value = random.choice(values) + else: + if len(values) > 1: + random.shuffle(values) + for value in values: + if pattern.match(value[1]): + found = 1 + break + if found: + mask = random.choice(self._masks) + phrase = mask % {"key": key, "value": random.choice(values)[1]} + results.append(phrase) + + def search(self, pattern): + results = [] + if self._info: + for key, values in self._info.values(): + self._search(pattern, key, values, results) + else: + file = open(self._filename) + values = [] + for line in file.readlines(): + if line and line[0] != "#": + if line[0] == "K": + if values: + self._search(pattern, key, values, results) + key = line[2:].rstrip() + values = [] + elif line[0] == "V": + value = line[2:].split(":", 1) + value[1] = value[1].rstrip() + values.append(value) + if values: + self._search(pattern, key, values, results) + file.close() + return results + class InfopackModule: def __init__(self): *************** *** 214,218 **** pack.loadcore() ! # [load|reload|unload] infopack <name> [in memory] [.|!] self.re1 = regexp(r"(?P<action>re|un)?load infopack (?P<name>\w+)(?P<inmemory> in memory)?") --- 268,272 ---- pack.loadcore() ! # [load|reload|unload] infopack <name> [in memory] self.re1 = regexp(r"(?P<action>re|un)?load infopack (?P<name>\w+)(?P<inmemory> in memory)?") *************** *** 220,223 **** --- 274,280 ---- self.re2 = regexp(r"show infopacks") + # search infopack <name> for /<regexp>/ + self.re3 = regexp(r"search infopack (?P<name>\S+) for /(?P<regexp>.*)/") + # infopack[s] mm.register_help("infopacks?", HELP, "infopack") *************** *** 322,325 **** --- 379,383 ---- else: # Unload infopack + cursor = db.cursor() if not self.packs.has_key(name): msg.answer("%:", ["Oops!", "Sorry!"], *************** *** 328,331 **** --- 386,391 ---- else: del self.packs[name] + cursor.execute("delete from infopack where name=%s", + name) msg.answer("%:", ["Unloaded", "Done", "Ok"], [".", "!"]) *************** *** 349,354 **** return 0 found = 0 ! for pack in self.packs.values(): info = pack.get(msg.line) if info: --- 409,459 ---- return 0 + m = self.re3.match(msg.line) + if m: + name = m.group("name") + regexp = m.group("regexp") + try: + pack = self.packs[name] + except KeyError: + msg.answer("%:", ["Oops!", "Sorry!"], + "This infopack is not loaded", + [".", "!"]) + return 0 + try: + pattern = re.compile(regexp, re.I) + except re.error: + msg.answer("%:", "Invalid pattern", [".", "!"]) + return 0 + results = pack.search(pattern) + reslen = len(results) + if not results: + msg.answer("%:", ["Pattern not found", + "Couldn't find anything with that pattern", + "Nothing found"], [".", "!"]) + elif reslen > MAXSEARCHRESULTS: + msg.answer("%:", ["Found too many entries", + "There are many entries like this", + "There are many matches"], + ", here are the first %d:"%MAXSEARCHRESULTS) + elif reslen > 1: + msg.answer("%:", ["Found %d entries:" % reslen, + "Found %d matches:" % reslen]) + else: + msg.answer("%:", ["Found one entry:", + "Found one match:"]) + n = 0 + for result in results: + msg.answer("-", result) + n += 1 + if n == MAXSEARCHRESULTS: + break + return 0 + + allowed = mm.permparams(msg, "infopack") + found = 0 ! for name, pack in self.packs.items(): ! if name not in allowed: ! continue info = pack.get(msg.line) if info: Index: permission.py =================================================================== RCS file: /cvsroot/pybot/pybot/pybot/modules/permission.py,v retrieving revision 1.11 retrieving revision 1.12 diff -C2 -d -r1.11 -r1.12 *** permission.py 24 Aug 2003 19:30:53 -0000 1.11 --- permission.py 27 Aug 2003 17:08:14 -0000 1.12 *************** *** 43,51 **** """ ! VALIDUSER = re.compile(".+!.+@.+") class Permission: def __init__(self): ! db.table("permission", "permission,servername,target,userstr,nick") self.help = options.get("Help.perm", {}) mm.register("hasperm", self.mm_hasperm) --- 43,54 ---- """ ! VALIDUSER = re.compile(r".+!.+@.+") ! ! PARAM = re.compile(r"(?P<perm>\S+)\((?P<param>.*)\)$") class Permission: def __init__(self): ! db.table("permission", "permission, param default '', " ! "servername, target, userstr, nick") self.help = options.get("Help.perm", {}) mm.register("hasperm", self.mm_hasperm) *************** *** 53,56 **** --- 56,61 ---- mm.register("setperm", self.mm_setperm) mm.register("unsetperm", self.mm_unsetperm) + mm.register("permparams", self.mm_permparams) + mm.register("permparams_raw", self.mm_permparams_raw) hooks.register("Message", self.message) *************** *** 64,68 **** # (give|remove|del|delete|take) perm[ission] <perm> [to|from] [everyone | [user <user>] [[and] nick <nick>] [on|at] [this channel|channel <channel>] [on|at|to] [this server|server <server>]] ! self.re1 = regexp("(?P<cmd>give|remove|del|delete|take) (?:perm(?:ission)? (?P<perm1>\S+)|(?P<perm2>\S+) perm(?:ission)?)(?: to| from)?(?:(?P<everyone> everyone)|(?: user (?P<user>\S+))?(?:(?: and)? nick (?P<nick>\S+))?(?: on| at)?(?: (?P<thischannel>this channel)| channel (?P<channel>\S+))?(?: on| at| to)?(?: (?P<thisserver>this server)| server (?P<server>\S+))?)?") # (show|list) perm[ission][s] [<perm>] --- 69,73 ---- # (give|remove|del|delete|take) perm[ission] <perm> [to|from] [everyone | [user <user>] [[and] nick <nick>] [on|at] [this channel|channel <channel>] [on|at|to] [this server|server <server>]] ! self.re1 = regexp("(?P<cmd>give|remove|del|delete|take) (?:perm(?:ission)? (?P<perm1>\S+)|(?P<perm2>\S+) perm(?:ission)?)(?: to| from| for)?(?:(?P<everyone> everyone)|(?: user (?P<user>\S+))?(?:(?: and)? nick (?P<nick>\S+))?(?: on| at| to| in| for)?(?: (?P<thischannel>this channel)| channel (?P<channel>\S+))?(?: on| at| to| in| for)?(?: (?P<thisserver>this server)| server (?P<server>\S+))?)?") # (show|list) perm[ission][s] [<perm>] *************** *** 124,131 **** nick = m.group("nick") perm = m.group("perm1") or m.group("perm2") # Everyone is handled transparently, since all # items will be None if m.group("cmd").lower() == "give": ! if not mm.setperm(servername, target, userstr, nick, perm): msg.answer("%:", ["I already have this permission", "This permission was given before", --- 129,142 ---- nick = m.group("nick") perm = m.group("perm1") or m.group("perm2") + _m = PARAM.match(perm) + if _m: + perm, param = _m.group("perm", "param") + else: + param = "" # Everyone is handled transparently, since all # items will be None if m.group("cmd").lower() == "give": ! if not mm.setperm(servername, target, ! userstr, nick, perm, param): msg.answer("%:", ["I already have this permission", "This permission was given before", *************** *** 134,138 **** return 0 else: ! if not mm.unsetperm(servername, target, userstr, nick, perm): msg.answer("%:", "No entries like this were found", [".", "!"]) --- 145,150 ---- return 0 else: ! if not mm.unsetperm(servername, target, ! userstr, nick, perm, param): msg.answer("%:", "No entries like this were found", [".", "!"]) *************** *** 191,194 **** --- 203,208 ---- if first: s += "everyone" + if row.param: + s += " (%s)" % row.param if i == numrows-1: s += "." *************** *** 227,231 **** return 0 ! def mm_hasperm_raw(self, servername, target, user, perm): if servername == "console": return 1 --- 241,245 ---- return 0 ! def mm_hasperm_raw(self, servername, target, user, perm, param=""): if servername == "console": return 1 *************** *** 235,239 **** cursor = db.cursor() cursor.execute("select * from permission where " ! "permission='admin' or permission=%s", perm) for row in cursor.fetchall(): if (not row.servername or row.servername == servername) and \ --- 249,254 ---- cursor = db.cursor() cursor.execute("select * from permission where " ! "permission='admin' or " ! "(permission=%s and param=%s)", (perm, param)) for row in cursor.fetchall(): if (not row.servername or row.servername == servername) and \ *************** *** 244,263 **** return 0 ! def mm_hasperm(self, msg, perm): return self.mm_hasperm_raw(msg.server.servername, ! msg.target, msg.user, perm) ! def mm_setperm(self, servername, target, userstr, nick, perm): if self.mm_unsetperm(servername, target, userstr, nick, ! perm, check=1): return 0 cursor = db.cursor() ! cursor.execute("insert into permission values (%s,%s,%s,%s,%s)", ! perm, servername, target, userstr, nick) return bool(cursor.rowcount) ! def mm_unsetperm(self, servername, target, userstr, nick, perm, check=0): ! where = ["permission=%s"] ! wargs = [perm] if servername: where.append("servername=%s") --- 259,279 ---- return 0 ! def mm_hasperm(self, msg, perm, param=""): return self.mm_hasperm_raw(msg.server.servername, ! msg.target, msg.user, perm, param) ! def mm_setperm(self, servername, target, userstr, nick, perm, param=""): if self.mm_unsetperm(servername, target, userstr, nick, ! perm, param, check=1): return 0 cursor = db.cursor() ! cursor.execute("insert into permission values (%s,%s,%s,%s,%s,%s)", ! (perm, param, servername, target, userstr, nick)) return bool(cursor.rowcount) ! def mm_unsetperm(self, servername, target, userstr, nick, ! perm, param="", check=0): ! where = ["permission=%s", "param=%s"] ! wargs = [perm, param] if servername: where.append("servername=%s") *************** *** 287,290 **** --- 303,324 ---- cursor.execute("select * from permission where "+wstr, *wargs) return bool(cursor.rowcount) + + def mm_permparams_raw(self, servername, target, user, perm): + loggednick = mm.loggednick(servername, user) + cursor = db.cursor() + cursor.execute("select * from permission where " + "permission=%s", (perm,)) + params = {} + 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)) and \ + (not row.nick or row.nick == loggednick): + params[row.param] = 1 + return params.keys() + + def mm_permparams(self, msg, perm): + return self.mm_permparams_raw(msg.server.servername, + msg.target, msg.user, perm) def __loadmodule__(): Index: remoteinfo.py =================================================================== RCS file: /cvsroot/pybot/pybot/pybot/modules/remoteinfo.py,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -d -r1.7 -r1.8 *** remoteinfo.py 25 Aug 2003 21:49:05 -0000 1.7 --- remoteinfo.py 27 Aug 2003 17:08:14 -0000 1.8 *************** *** 28,43 **** and to unload or reload using "(re|un)load remote info [from] <url>". To check what is being remotely loaded, use "show remote[ ]info[s]". To ! load and unload remote infos you'll need the "remoteinfo" permission, ! and to show and reload you need either the "remoteinfo" or the ! "remoteinforeload" permission. """,""" After you setup some URL for remote loading, you must say explicitly which users/channels and servers will be able to obtain information from ! it. To do that use the command "[don't] allow remote info [from] <url> ! [(for|on|at) (user|channel) <target>] [(for|on|at) server <server>]". ! Notice that you may omit user/channel and/or server to give wider ! permissions. ! """,""" ! The default reload interval is 10 minutes. To understand how to build the regex for the remote info command or how to build the remote information check "help remote info syntax". --- 28,38 ---- and to unload or reload using "(re|un)load remote info [from] <url>". To check what is being remotely loaded, use "show remote[ ]info[s]". To ! load and unload remote infos you must be an admin, and to show and reload ! you need the "remoteinfoadmin" permission. """,""" After you setup some URL for remote loading, you must say explicitly which users/channels and servers will be able to obtain information from ! it. To do that give the permission "remoteinfo(<url>)" for these you ! want to allow. The default reload interval is 10 minutes. To understand how to build the regex for the remote info command or how to build the remote information check "help remote info syntax". *************** *** 67,78 **** PERM_REMOTEINFO = """ ! Users with the "remoteinfo" permission can work with remote ! information settings. Check "help remoteinfo" for more information. """ ! PERM_RELOADREMOTEINFO = """ ! Users with the "reloadremoteinfo" permission can ask me to reload ! information from remote URLs. Notice that the "remoteinfo" permission ! allows that as well. Check "help remoteinfo" for more information. """ --- 62,73 ---- PERM_REMOTEINFO = """ ! Users with the "remoteinfo(<url>)" permission will be able to use ! knowledge acquired from the given url. Check "help remoteinfo" for ! more information. """ ! PERM_REMOTEINFOADMIN = """ ! Users with the "remoteinfoadmin" permission can ask me to reload ! information from remote URLs, and to show which URLs are being loaded. """ *************** *** 91,103 **** def __init__(self): db.table("remoteinfo", "id integer primary key, url, regex, interval", ! constraints="unique (url)", ! triggers=[ ! "create trigger remoteinfo1 after delete on remoteinfo " ! "begin" ! " delete from remoteinfoallow where infoid=old.id;" ! "end" ! ]) ! db.table("remoteinfoallow", "infoid, servername, target", ! constraints="unique (infoid, servername, target)") self.info = options.get("RemoteInfo.info", {}) self.info_lock = options.get("RemoteInfo.info_lock", {}) --- 86,90 ---- def __init__(self): db.table("remoteinfo", "id integer primary key, url, regex, interval", ! constraints="unique (url)") self.info = options.get("RemoteInfo.info", {}) self.info_lock = options.get("RemoteInfo.info_lock", {}) *************** *** 113,121 **** self.re2 = regexp(r"(?P<cmd>un|re)load remote *info (?:from )?(?P<url>\S+)") - # [(don[']t|do not)] allow remote[ ]info [from] <url> [(to|for|on|at|in) (user|channel) <target>] [(to|for|on|at|in) server <server>] - self.re3 = regexp(r"(?P<dont>don'?t |do not )?allow remote *info (?:from )?(?P<url>\S+)(?: (?:to|for|on|at|in) (?:user|channel) (?P<target>\S+))?(?: (?:to|for|on|at|in) server (?P<server>\S+))?") - # show remote[ ]info[s] ! self.re4 = regexp(r"show remote *infos?") # remote[ ]info --- 100,105 ---- self.re2 = regexp(r"(?P<cmd>un|re)load remote *info (?:from )?(?P<url>\S+)") # show remote[ ]info[s] ! self.re3 = regexp(r"show remote *infos?") # remote[ ]info *************** *** 125,129 **** mm.register_perm("remoteinfo", PERM_REMOTEINFO) ! mm.register_perm("reloadremoteinfo", PERM_RELOADREMOTEINFO) mm.hooktimer(30, self.reload_all, ()) --- 109,113 ---- mm.register_perm("remoteinfo", PERM_REMOTEINFO) ! mm.register_perm("remoteinfoadmin", PERM_REMOTEINFOADMIN) mm.hooktimer(30, self.reload_all, ()) *************** *** 140,144 **** mm.unregister_help(HELP_SYNTAX) mm.unregister_perm("remoteinfo") ! mm.unregister_perm("reloadremoteinfo") def lock_url(self, url): --- 124,128 ---- mm.unregister_help(HELP_SYNTAX) mm.unregister_perm("remoteinfo") ! mm.unregister_perm("remoteinfoadmin") def lock_url(self, url): *************** *** 233,239 **** def message_remoteinfo(self, msg): ret = None ! allowed = self.get_allowed_urls(msg.server.servername, ! msg.answertarget) for url, info in self.info.items(): if url not in allowed: continue --- 217,226 ---- def message_remoteinfo(self, msg): ret = None ! #allowed = self.get_allowed_urls(msg.server.servername, ! # msg.answertarget) ! allowed = mm.permparams(msg, "remoteinfo") for url, info in self.info.items(): + #if not mm.hasperm(msg, "remoteinfo", url): + # continue if url not in allowed: continue *************** *** 274,278 **** m = self.re1.match(msg.line) if m: ! if mm.hasperm(msg, "remoteinfo"): url = m.group("url") regex = (m.group("regex") or DEFAULTREGEX).strip() --- 261,265 ---- m = self.re1.match(msg.line) if m: ! if mm.hasperm(msg, "admin"): url = m.group("url") regex = (m.group("regex") or DEFAULTREGEX).strip() *************** *** 334,395 **** m = self.re2.match(msg.line) if m: ! cmd = m.group("cmd") ! url = m.group("url") ! cursor = db.cursor() ! cursor.execute("select * from remoteinfo where url=%s", ! (url,)) ! if not cursor.rowcount: ! msg.answer("%:", ["I can't do that.", "Nope.", None], ! ["I'm not loading that url", ! "This url is not in my database"], ! [".", "!"]) ! elif cmd == "un": ! if mm.hasperm(msg, "remoteinfo"): ! if not self.lock_url(url): ! msg.answer("%:", "Can't do that now. URL is " ! "being loaded in this exact " ! "moment. Try again in a few " ! "seconds.") ! else: ! if url in self.info: ! del self.info[url] ! if url in self.info_lock: ! del self.info_lock[url] ! # Unlocking is not really necessary, but ! # politically right. ;-) ! self.unlock_url(url) ! cursor.execute("delete from remoteinfo where url=%s", ! (url,)) ! msg.answer("%:", ["Done", "Of course", "Ready"], ! [".", "!"]) ! else: ! msg.answer("%:", [("You're not", ! ["allowed to change " ! "remote info options", ! "that good", ! "allowed to do this"]), ! "Nope"], [".", "!"]) ! else: ! if mm.hasperm(msg, "remoteinfo") or \ ! mm.hasperm(msg, "reloadremoteinfo"): ! msg.answer("%:", ["Will do that", ! "In a moment", ! "Will be ready in a moment", ! "Starting right now"], [".", "!"]) ! self.reload(url) ! else: ! msg.answer("%:", [("You're not", ! ["allowed to reload remote infos", ! "that good", ! "allowed to do this"]), ! "Nope"], [".", "!"]) ! return 0 ! ! m = self.re3.match(msg.line) ! if m: ! if mm.hasperm(msg, "remoteinfo"): url = m.group("url") - target = m.group("target") or "" - server = m.group("server") or "" cursor = db.cursor() cursor.execute("select * from remoteinfo where url=%s", --- 321,327 ---- m = self.re2.match(msg.line) if m: ! if mm.hasperm(msg, "remoteinfoadmin"): ! cmd = m.group("cmd") url = m.group("url") cursor = db.cursor() cursor.execute("select * from remoteinfo where url=%s", *************** *** 400,441 **** "This url is not in my database"], [".", "!"]) ! return 0 ! if m.group("dont"): ! cursor.execute("delete from remoteinfoallow where " ! "infoid=(select id from remoteinfo where url=%s) " ! "and servername=%s and target=%s", ! (url, server, target)) ! if cursor.rowcount: ! msg.answer("%:", ["Sure", "Done", "Removed", "Ok"], ! [".", "!"]) ! else: ! msg.answer("%:", ["I can't do that.", "Nope.", None], ! ["This target doesn't exist", ! "I'm not allowing this target", ! "This target is not in my database"], ! [".", "!"]) else: ! try: ! cursor.execute("insert into remoteinfoallow values " ! "((select id from remoteinfo where url=%s)," ! " %s,%s)", (url, server, target)) ! except db.error: ! msg.answer("%:", ["I can't do that.", "Nope.", None], ! ["This target is already allowed", ! "I'm already allowing this target", ! "This target is already in my database"], ! [".", "!"]) ! else: ! msg.answer("%:", ["Sure", "Done", "Added", "Ok"], ! [".", "!"]) else: msg.answer("%:", [("You're not", ! ["allowed to change remote info options", "that good", "allowed to do this"]), "Nope"], [".", "!"]) return 0 ! ! m = self.re4.match(msg.line) if m: if mm.hasperm(msg, "remoteinfo") or \ --- 332,368 ---- "This url is not in my database"], [".", "!"]) ! elif cmd == "un": ! if not self.lock_url(url): ! msg.answer("%:", "Can't do that now. URL is " ! "being loaded in this exact " ! "moment. Try again in a few " ! "seconds.") ! else: ! if url in self.info: ! del self.info[url] ! if url in self.info_lock: ! del self.info_lock[url] ! # Unlocking is not really necessary, but ! # politically right. ;-) ! self.unlock_url(url) ! cursor.execute("delete from remoteinfo where url=%s", ! (url,)) ! msg.answer("%:", ["Done", "Of course", "Ready"], ! [".", "!"]) else: ! msg.answer("%:", ["Will do that", ! "In a moment", ! "Will be ready in a moment", ! "Starting right now"], [".", "!"]) ! self.reload(url) else: msg.answer("%:", [("You're not", ! ["allowed to touch remote infos", "that good", "allowed to do this"]), "Nope"], [".", "!"]) return 0 ! ! m = self.re3.match(msg.line) if m: if mm.hasperm(msg, "remoteinfo") or \ |
From: Gustavo N. <nie...@us...> - 2003-08-27 17:08:32
|
Update of /cvsroot/pybot/pybot/data/infopacks In directory sc8-pr-cvs1:/tmp/cvs-serv23476/data/infopacks Modified Files: airport.info ports.info vera.info versions.info Log Message: * modules/permissions.py: Implemented permission parameters. * modules/{remoteinfo.py,infopack.py}: Adapted to work with premission parameters. * modules/infopack.py: Implemented infopack searching. Index: airport.info =================================================================== RCS file: /cvsroot/pybot/pybot/data/infopacks/airport.info,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** airport.info 25 Aug 2003 20:44:23 -0000 1.3 --- airport.info 27 Aug 2003 17:08:13 -0000 1.4 *************** *** 8,3616 **** T:(?:what|where)(?:'s|\s+is)\s+(?:the\s+)?airport\s+(?:code\s+)?([a-z]{3})\s*(?:!*\?[!?]*)?$ T:airport\s+([a-zA-Z]{3})\s*(?:!*\?[!?]*)?$ ! M:That's the airport code for %s. ! M:That's the code for the airport in %s. D:t:I don't know any airport with this code. D:t:I'm not sure this is the code of an airport. D:t:Sorry, I don't know anything about this code. ! K:aae V:tm:Annaba, Algeria ! K:aal [...7189 lines suppressed...] ! K:ZKE V:tm:Kaschechawan, PQ, Canada ! K:ZLO V:tm:Manzanillo, Mexico ! K:ZND V:tm:Zinder, Niger ! K:ZNE V:tm:Newman, Australia ! K:ZQN V:tm:Queenstown, New Zealand ! K:ZRH V:tm:Zuerich (Zurich), Switzerland ! K:ZSS V:tm:Sassandra, Ivory Coast ! K:ZTH V:tm:Zakynthos, Greece ! K:ZTM V:tm:Shamattawa, MB, Canada ! K:ZYL V:tm:Sylhet, Bangla Desh Index: ports.info =================================================================== RCS file: /cvsroot/pybot/pybot/data/infopacks/ports.info,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** ports.info 25 Aug 2003 20:44:23 -0000 1.3 --- ports.info 27 Aug 2003 17:08:13 -0000 1.4 *************** *** 8,16 **** T:what(?:'s|\s+is)\s+(?:the\s+)?port\s+(?:number\s+)?([0-9]+)(?:\s+for)\s*(?:!*\?[!?]*)?$ T:port\s+(\d+)[!?.]*$ ! M:This port is for %s. D:t:I haven't found anything about this port. D:t:I don't know what this port is for. K:0 ! V:t:This is a reserved port. K:1 V:tm:tcpmux - TCP Port Service Multiplexer --- 8,16 ---- T:what(?:'s|\s+is)\s+(?:the\s+)?port\s+(?:number\s+)?([0-9]+)(?:\s+for)\s*(?:!*\?[!?]*)?$ T:port\s+(\d+)[!?.]*$ ! M:Port %(key) is for %(value)s. D:t:I haven't found anything about this port. D:t:I don't know what this port is for. K:0 ! V:t:Port 0 is reserved. K:1 V:tm:tcpmux - TCP Port Service Multiplexer Index: vera.info =================================================================== RCS file: /cvsroot/pybot/pybot/data/infopacks/vera.info,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** vera.info 25 Aug 2003 20:44:23 -0000 1.5 --- vera.info 27 Aug 2003 17:08:13 -0000 1.6 *************** *** 13,14244 **** D:t:I don't know this acronym. D:t:Sorry, I haven't found this acronym. ! M:That's the acronym for %s. ! M:This acronym is for %s. ! K:100vg V:tm:100 Voice Grade [technology] ! K:2s2d V:tm:Double Sided - Double Density (FDD) ! K:3dddi V:tm:3D Device Dependent Interface (MS), "3D DDI" [...28435 lines suppressed...] ! K:ZPL V:tm:Zope Puplic License ! K:ZPR V:tm:Zentrum fuer Paralleles Rechnen (org., Uni Koeln, Germany), Zero Power Resistance ! K:ZRE V:tm:Zero Rate Error ! K:ZRZ V:tm:Zentrales RechenZentrum (org., TUB) ! K:ZSI V:tm:Zentralstelle fuer Sicherheit in der Informationstechnik (org., BSI, predecessor) ! K:ZSL V:tm:Zero Slot LAN (LAN) ! K:ZV V:tm:Zoomed Video (video) ! K:ZVM V:tm:Z/Virtual Machine (IBM, VM), "z/VM" ! K:ZWEI V:tm:ZWEI Was EINE Initially (EINE, LISP) ! K:ZZF V:tm:Zentralamt zur Zulassung von Fernmeldeeinrichtungen (org., Telekom, predecessor, BZT) Index: versions.info =================================================================== RCS file: /cvsroot/pybot/pybot/data/infopacks/versions.info,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** versions.info 25 Aug 2003 20:44:23 -0000 1.2 --- versions.info 27 Aug 2003 17:08:13 -0000 1.3 *************** *** 8,15 **** D:t:I have never seen that package. D:t:Sorry, I don't know anything about that package. ! M:This package has been released in the following distributions: %s ! M:The following distributions contain that package: %s ! M:You'll find that package in the following distributions: %s ! M:It was included in the following distributions: %s K:0verkill V:tm:CL6-CD2: 0.13-1cl; CL9-CD3: 0.16-23753cl --- 8,15 ---- D:t:I have never seen that package. D:t:Sorry, I don't know anything about that package. ! M:Package %(key)s has been released in the following distributions: %(value)s ! M:The following distributions contain package %(key)s: %(value)s ! M:You'll find package %(key)s in the following distributions: %(value)s ! M:%(key)s was included in the following distributions: %(value)s K:0verkill V:tm:CL6-CD2: 0.13-1cl; CL9-CD3: 0.16-23753cl |
From: Gustavo N. <nie...@us...> - 2003-08-27 17:08:31
|
Update of /cvsroot/pybot/pybot/contrib In directory sc8-pr-cvs1:/tmp/cvs-serv23476/contrib Modified Files: vera2info.py Log Message: * modules/permissions.py: Implemented permission parameters. * modules/{remoteinfo.py,infopack.py}: Adapted to work with premission parameters. * modules/infopack.py: Implemented infopack searching. Index: vera2info.py =================================================================== RCS file: /cvsroot/pybot/pybot/contrib/vera2info.py,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** vera2info.py 16 May 2003 17:28:03 -0000 1.2 --- vera2info.py 27 Aug 2003 17:08:13 -0000 1.3 *************** *** 11,15 **** for line in file.xreadlines(): if line[:6] == "@item ": ! key = line[6:].rstrip().lower() if key != lastkey: if lastkey and not nextisvalue: --- 11,15 ---- for line in file.xreadlines(): if line[:6] == "@item ": ! key = line[6:].rstrip() if key != lastkey: if lastkey and not nextisvalue: *************** *** 25,30 **** if not append: sys.stdout.write("V:tm:%s" % value) ! else: sys.stdout.write(", %s" % value) nextisvalue = 0 file.close() --- 25,32 ---- if not append: sys.stdout.write("V:tm:%s" % value) ! elif lastkey != "VERA": sys.stdout.write(", %s" % value) + else: + sys.stdout.write("Virtual Entity of Relevant Acronyms") nextisvalue = 0 file.close() |
From: Gustavo N. <nie...@us...> - 2003-08-26 21:37:39
|
Update of /cvsroot/pybot/pybot/pybot/modules In directory sc8-pr-cvs1:/tmp/cvs-serv6039/pybot/modules Modified Files: rss.py Log Message: Changed chars enclosing the link. Index: rss.py =================================================================== RCS file: /cvsroot/pybot/pybot/pybot/modules/rss.py,v retrieving revision 1.8 retrieving revision 1.9 diff -C2 -d -r1.8 -r1.9 *** rss.py 26 Aug 2003 21:02:44 -0000 1.8 --- rss.py 26 Aug 2003 21:27:41 -0000 1.9 *************** *** 151,155 **** text = item.title if "l" in target.flags and item.link: ! text += " [%s]" % item.link if "d" in target.flags and item["description"]: # item.description() is a method --- 151,155 ---- text = item.title if "l" in target.flags and item.link: ! text += " <%s>" % item.link if "d" in target.flags and item["description"]: # item.description() is a method |
From: Gustavo N. <nie...@us...> - 2003-08-26 21:03:04
|
Update of /cvsroot/pybot/pybot/pybot/modules In directory sc8-pr-cvs1:/tmp/cvs-serv1163/pybot/modules Modified Files: rss.py Log Message: Reordered data when showing rss information to better match the command used to active feeds. Index: rss.py =================================================================== RCS file: /cvsroot/pybot/pybot/pybot/modules/rss.py,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -d -r1.7 -r1.8 *** rss.py 26 Aug 2003 20:46:09 -0000 1.7 --- rss.py 26 Aug 2003 21:02:44 -0000 1.8 *************** *** 302,307 **** interval = "%d seconds" % target.interval msg.answer(" for", target.target, "on", ! target.servername, "each", interval, ! oneline, links, descs, prefix) else: msg.answer("%:", ["You can't", "You're not allowed to", --- 302,307 ---- interval = "%d seconds" % target.interval msg.answer(" for", target.target, "on", ! target.servername, "each", ! oneline, links, descs, prefix, interval) else: msg.answer("%:", ["You can't", "You're not allowed to", |
From: Gustavo N. <nie...@us...> - 2003-08-26 20:46:15
|
Update of /cvsroot/pybot/pybot/pybot/modules In directory sc8-pr-cvs1:/tmp/cvs-serv30763/pybot/modules Modified Files: rss.py Log Message: Allow target updating when a given feed is already active for the given target. Index: rss.py =================================================================== RCS file: /cvsroot/pybot/pybot/pybot/modules/rss.py,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -d -r1.6 -r1.7 *** rss.py 26 Aug 2003 20:25:44 -0000 1.6 --- rss.py 26 Aug 2003 20:46:09 -0000 1.7 *************** *** 247,256 **** prefix, interval, feedid)) except db.error: ! msg.answer("%:", ["Not needed", "It's not needed", ! "Oops"], [".", "!"], ! ["I'm already showing that feed", ! "This feed is already being shown", ! "I'm already showing news from that" ! " feed"], [".", "!"]) else: msg.answer("%:", ["Done", "Ok", "Sure"], [".", "!"]) --- 247,260 ---- prefix, interval, feedid)) except db.error: ! cursor.execute("update rsstarget set " ! "flags=%s, prefix=%s, interval=%s " ! "where feedid=%s and servername=%s " ! "and target=%s", ! (flags, prefix, interval, ! feedid, servername, target)) ! msg.answer("%:", ["Feed updated", ! "Information updated", ! "Feed information updated"], ! [".", "!"]) else: msg.answer("%:", ["Done", "Ok", "Sure"], [".", "!"]) |
From: Gustavo N. <nie...@us...> - 2003-08-26 20:25:51
|
Update of /cvsroot/pybot/pybot/pybot/modules In directory sc8-pr-cvs1:/tmp/cvs-serv27030/pybot/modules Modified Files: rss.py Log Message: Try not to fetch more than one rss news at the same time. Index: rss.py =================================================================== RCS file: /cvsroot/pybot/pybot/pybot/modules/rss.py,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** rss.py 26 Aug 2003 19:56:23 -0000 1.5 --- rss.py 26 Aug 2003 20:25:44 -0000 1.6 *************** *** 131,134 **** --- 131,136 ---- "where id=%s", (now, feed.id)) thread.start_new_thread(self.fetch_news, (feed, now)) + # Try not to fetch more than one at the same time + break # Now check if we must show something |
From: Gustavo N. <nie...@us...> - 2003-08-26 19:56:33
|
Update of /cvsroot/pybot/pybot/pybot/modules In directory sc8-pr-cvs1:/tmp/cvs-serv20387/pybot/modules Modified Files: rss.py Log Message: * pybot/misc.py: Introduced striphtml(). * pybot/rss.py: Allow all news to be colapsed in one line. Strip html from fields. Other minor changes and fixes. Index: rss.py =================================================================== RCS file: /cvsroot/pybot/pybot/pybot/modules/rss.py,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** rss.py 26 Aug 2003 16:21:34 -0000 1.4 --- rss.py 26 Aug 2003 19:56:23 -0000 1.5 *************** *** 19,22 **** --- 19,23 ---- from pybot.locals import * from pybot.util import feedparser + from pybot.misc import striphtml import thread import time *************** *** 24,33 **** HELP = """ You can ask me to show RSS news from any site and for any user/channel ! and server with "[dont] show (rss|news) [from] <url> [with link[s]] ! [with desc[ription][s]] [with prefix "<prefix>"] [each <n>(m|h)] ! [(on|for) (user|channel) <target>] [(on|at) server <server>]". Notice ! that the given interval is the maximum interval. To check what is being ! shown and for which targets, you can send me "show rss". You need the ! "rss" permission to use these commands. """ --- 25,35 ---- HELP = """ You can ask me to show RSS news from any site and for any user/channel ! and server with "[dont] show (rss|news) [from] <url> [[in] one line] ! [with link[s]] [with desc[ription][s]] [with prefix "<prefix>"] ! [each <n>(m|h)] [(on|for) (user|channel) <target>] [(on|at) server ! <server>]". Notice that the given interval is the maximum interval. ! """,""" ! To check what is being shown and for which targets, you can send me ! "show rss". You need the "rss" permission to use these commands. """ *************** *** 47,51 **** # Maxium news to send from a single feed per minute ! ONETIMELIMIT = 1 class RSS: --- 49,53 ---- # Maxium news to send from a single feed per minute ! ONETIMELIMIT = 5 class RSS: *************** *** 86,92 **** mm.hooktimer(60, self.update, ()) ! # [dont] show (rss|news|rss news) [from] <url> [with link[s]] [with desc[ription][s]] [with prefix "<prefix>"] [each <n>(m|h)] [[on|at|in|for] (user|channel) <target>] [[on|at|in|for] server <server>] self.re1 = regexp(refrag.dont(optional=1), r"show (?:rss |news |rss news )(?:from )?(?P<url>(?:https?|ftp)\S+)" r"(?P<links> with links?)?" r"(?P<descs> with desc(?:ription)?s?)?" --- 88,95 ---- mm.hooktimer(60, self.update, ()) ! # [dont] show (rss|news|rss news) [from] <url> [[in] one line] [with link[s]] [with desc[ription][s]] [with prefix "<prefix>"] [each <n>(m|h)] [[on|at|in|for] (user|channel) <target>] [[on|at|in|for] server <server>] self.re1 = regexp(refrag.dont(optional=1), r"show (?:rss |news |rss news )(?:from )?(?P<url>(?:https?|ftp)\S+)" + r"(?P<oneline> (?:in )?one line)?" r"(?P<links> with links?)?" r"(?P<descs> with desc(?:ription)?s?)?" *************** *** 138,146 **** server = servers.get(target.servername) lastid = None for item in cursor.fetchall(): ! if target.prefix: ! text = "%s %s" % (target.prefix, item.title) ! else: ! text = item.title if "l" in target.flags and item.link: text += " [%s]" % item.link --- 141,151 ---- server = servers.get(target.servername) lastid = None + if "1" in target.flags: + oneline = 1 + fulltext = "" + else: + oneline = 0 for item in cursor.fetchall(): ! text = item.title if "l" in target.flags and item.link: text += " [%s]" % item.link *************** *** 148,153 **** # item.description() is a method text += " - "+item["description"] ! server.sendmsg(target.target, None, text, notice=1) lastid = item.id if lastid: # Should always be true cursor.execute("update rsstarget set lastitemid=%s " --- 153,168 ---- # item.description() is a method text += " - "+item["description"] ! if oneline: ! if fulltext: ! fulltext = "%s; %s" % (fulltext, text) ! else: ! fulltext = text ! else: ! server.sendmsg(target.target, None, ! target.prefix, text, notice=1) lastid = item.id + if oneline: + server.sendmsg(target.target, None, + target.prefix, fulltext, notice=1) if lastid: # Should always be true cursor.execute("update rsstarget set lastitemid=%s " *************** *** 164,170 **** for item in items: if "title" in item: ! title = item["title"].strip() ! link = item.get("link", "").strip() ! desc = item.get("description", "").strip() cursor.execute("insert into rssitem values " "(NULL, %s, %s, %s, %s, %s)", --- 179,185 ---- for item in items: if "title" in item: ! title = striphtml(item["title"].strip()) ! link = striphtml(item.get("link", "").strip()) ! desc = striphtml(item.get("description", "").strip()) cursor.execute("insert into rssitem values " "(NULL, %s, %s, %s, %s, %s)", *************** *** 193,196 **** --- 208,213 ---- if m.group("descs"): flags += "d" + if m.group("oneline"): + flags += "1" cursor = db.cursor() if dont: *************** *** 260,264 **** (feed.id,)) for target in cursor.fetchall(): ! links, descs, prefix = "", "", "" if "l" in target.flags: links = "with links" --- 277,283 ---- (feed.id,)) for target in cursor.fetchall(): ! oneline, links, descs, prefix = ("",)*4 ! if "1" in target.flags: ! oneline = "in one line" if "l" in target.flags: links = "with links" *************** *** 278,282 **** msg.answer(" for", target.target, "on", target.servername, "each", interval, ! links, descs, prefix) else: msg.answer("%:", ["You can't", "You're not allowed to", --- 297,301 ---- msg.answer(" for", target.target, "on", target.servername, "each", interval, ! oneline, links, descs, prefix) else: msg.answer("%:", ["You can't", "You're not allowed to", |
From: Gustavo N. <nie...@us...> - 2003-08-26 19:56:32
|
Update of /cvsroot/pybot/pybot/pybot In directory sc8-pr-cvs1:/tmp/cvs-serv20387/pybot Modified Files: misc.py refrag.py Log Message: * pybot/misc.py: Introduced striphtml(). * pybot/rss.py: Allow all news to be colapsed in one line. Strip html from fields. Other minor changes and fixes. Index: misc.py =================================================================== RCS file: /cvsroot/pybot/pybot/pybot/misc.py,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** misc.py 24 Aug 2003 19:30:53 -0000 1.5 --- misc.py 26 Aug 2003 19:56:22 -0000 1.6 *************** *** 22,26 **** import re ! __all__ = ["buildanswer", "breakline"] MAXLINESIZE = 400 --- 22,26 ---- import re ! __all__ = ["buildanswer", "breakline", "regexp", "striphtml"] MAXLINESIZE = 400 *************** *** 109,112 **** --- 109,124 ---- expr += "\s*$" return re.compile(expr, re.I) + + STRIPHTML = re.compile("<.*?>") + def striphtml(s): + s = STRIPHTML.sub("", s) + if '&' not in s: + return s + s = s.replace("<", "<") + s = s.replace(">", ">") + s = s.replace("'", "'") + s = s.replace(""", '"') + s = s.replace("&", "&") # Must be last + return s # vim:ts=4:sw=4:et Index: refrag.py =================================================================== RCS file: /cvsroot/pybot/pybot/pybot/refrag.py,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** refrag.py 25 Aug 2003 18:54:54 -0000 1.1 --- refrag.py 26 Aug 2003 19:56:23 -0000 1.2 *************** *** 76,81 **** def __init__(self): Fragment.__init__(self) ! self._expr = r"(?:\s+(?:to|for|on|at|in)\s+(?:(?P<_thischannel>this\s+channel)|(?P<_me>me)|(?:user|channel)\s+(?P<_target>\S+))(?:\s+(?:for|on|at|in)\s+(?:(?P<_thisserver>this\s+server)|server\s+(?P<_server>\S+)))?)" ! self._expr_onlyserverallowed = r"((?:\s+(?:to|for|on|at|in)\s+(?:(?P<_thischannel>this\s+channel)|(?P<_me>me)|(?:user|channel)\s+(?P<_target>\S+)))?(?:\s+(?:for|on|at|in)\s+(?:(?P<_thisserver>this\s+server)|server\s+(?P<_server>\S+)))?)" def expr(self, optional=0, onlyserverallowed=0): --- 76,81 ---- def __init__(self): Fragment.__init__(self) ! self._expr = r"(?:\s+(?:to|for|on|at|in)?\s+(?:(?P<_thischannel>this\s+channel)|(?P<_me>me)|(?:user|channel)\s+(?P<_target>\S+))(?:\s+(?:for|on|at|in|of)?\s+(?:(?P<_thisserver>this\s+server)|server\s+(?P<_server>\S+)))?)" ! self._expr_onlyserverallowed = r"((?:\s+(?:to|for|on|at|in)?\s+(?:(?P<_thischannel>this\s+channel)|(?P<_me>me)|(?:user|channel)\s+(?P<_target>\S+)))?(?:\s+(?:for|on|at|in|of)?\s+(?:(?P<_thisserver>this\s+server)|server\s+(?P<_server>\S+)))?)" def expr(self, optional=0, onlyserverallowed=0): |
From: Gustavo N. <nie...@us...> - 2003-08-26 19:56:32
|
Update of /cvsroot/pybot/pybot In directory sc8-pr-cvs1:/tmp/cvs-serv20387 Modified Files: ChangeLog Log Message: * pybot/misc.py: Introduced striphtml(). * pybot/rss.py: Allow all news to be colapsed in one line. Strip html from fields. Other minor changes and fixes. Index: ChangeLog =================================================================== RCS file: /cvsroot/pybot/pybot/ChangeLog,v retrieving revision 1.31 retrieving revision 1.32 diff -C2 -d -r1.31 -r1.32 *** ChangeLog 25 Aug 2003 20:44:23 -0000 1.31 --- ChangeLog 26 Aug 2003 19:56:22 -0000 1.32 *************** *** 1,2 **** --- 1,7 ---- + 2003-08-26 Gustavo Niemeyer <nie...@co...> + * pybot/misc.py: Introduced striphtml(). + * pybot/rss.py: Allow all news to be colapsed in one line. + Strip html from fields. Other minor changes and fixes. + 2003-08-25 Gustavo Niemeyer <nie...@co...> * pybot/refrag.py: Introduced the refrag module. It contains |
From: Gustavo N. <nie...@us...> - 2003-08-26 16:22:32
|
Update of /cvsroot/pybot/pybot/pybot/modules In directory sc8-pr-cvs1:/tmp/cvs-serv15443/pybot/modules Modified Files: rss.py Log Message: - Now insert -1 in rsstarget.lastitemid when the list is empty. - Do not allow order-free parameters, since SRE of python < 2.3 is broken in this sense. - Other minor tweaks. Index: rss.py =================================================================== RCS file: /cvsroot/pybot/pybot/pybot/modules/rss.py,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** rss.py 25 Aug 2003 20:46:52 -0000 1.3 --- rss.py 26 Aug 2003 16:21:34 -0000 1.4 *************** *** 27,35 **** [with desc[ription][s]] [with prefix "<prefix>"] [each <n>(m|h)] [(on|for) (user|channel) <target>] [(on|at) server <server>]". Notice ! that after <url> you can use any order, and also that the given interval ! is the maximum interval. ! """,""" ! To check what is being shown and for which targets, you can send me ! "show rss". You need the "rss" permission to use these commands. """ --- 27,33 ---- [with desc[ription][s]] [with prefix "<prefix>"] [each <n>(m|h)] [(on|for) (user|channel) <target>] [(on|at) server <server>]". Notice ! that the given interval is the maximum interval. To check what is being ! shown and for which targets, you can send me "show rss". You need the ! "rss" permission to use these commands. """ *************** *** 43,46 **** --- 41,45 ---- # make pybot flood the channel with more than 10 minutes. MININTERVAL = 10*60 + DEFINTERVAL = 30*60 # Maximum number of stored news from each feed *************** *** 48,52 **** # Maxium news to send from a single feed per minute ! ONETIMELIMIT = 5 class RSS: --- 47,51 ---- # Maxium news to send from a single feed per minute ! ONETIMELIMIT = 1 class RSS: *************** *** 90,100 **** self.re1 = regexp(refrag.dont(optional=1), r"show (?:rss |news |rss news )(?:from )?(?P<url>(?:https?|ftp)\S+)" ! r"(?:" ! r" with prefix \"(?P<prefix>.*?)\"|" ! r"(?P<links> with links?)|" ! r"(?P<descs> with desc(?:ription)?s?)|", ! refrag.interval(), r"|", ! refrag.target(), ! r")*") # show rss [settings] --- 89,97 ---- self.re1 = regexp(refrag.dont(optional=1), r"show (?:rss |news |rss news )(?:from )?(?P<url>(?:https?|ftp)\S+)" ! r"(?P<links> with links?)?" ! r"(?P<descs> with desc(?:ription)?s?)?" ! r"(?: with prefix \"(?P<prefix>.*?)\")?", ! refrag.interval(optional=1), ! refrag.target(optional=1)) # show rss [settings] *************** *** 146,152 **** else: text = item.title ! if "l" in target.flags: text += " [%s]" % item.link ! if "d" in target.flags: # item.description() is a method text += " - "+item["description"] --- 143,149 ---- else: text = item.title ! if "l" in target.flags and item.link: text += " [%s]" % item.link ! if "d" in target.flags and item["description"]: # item.description() is a method text += " - "+item["description"] *************** *** 184,194 **** target, servername = refrag.target.get(msg, m) interval = refrag.interval.get(msg, m, ! default="%ds" % MININTERVAL) if interval < MININTERVAL: msg.answer("%:", "That's below the minimum interval", [".", "!"]) return 0 - interval = refrag.interval.get(msg, m, - default="%ds" % MININTERVAL) url = m.group("url") prefix = m.group("prefix") or "" --- 181,189 ---- target, servername = refrag.target.get(msg, m) interval = refrag.interval.get(msg, m, ! default="%ds" % DEFINTERVAL) if interval < MININTERVAL: msg.answer("%:", "That's below the minimum interval", [".", "!"]) return 0 url = m.group("url") prefix = m.group("prefix") or "" *************** *** 226,231 **** cursor.execute("insert into rsstarget values " "(NULL, %s, %s, %s, %s, %s, %s, " ! " (select max(id) from rssitem where " ! " feedid=%s)" ")", (feedid, servername, target, flags, --- 221,227 ---- cursor.execute("insert into rsstarget values " "(NULL, %s, %s, %s, %s, %s, %s, " ! " ifnull(" ! " (select max(id) from rssitem where " ! " feedid=%s), -1)" ")", (feedid, servername, target, flags, |
From: Gustavo N. <nie...@us...> - 2003-08-26 04:02:29
|
Update of /cvsroot/pybot/pybot/pybot/modules In directory sc8-pr-cvs1:/tmp/cvs-serv16201/pybot/modules Modified Files: rss.py Log Message: Minor tweaks. Index: rss.py =================================================================== RCS file: /cvsroot/pybot/pybot/pybot/modules/rss.py,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** rss.py 25 Aug 2003 18:54:54 -0000 1.1 --- rss.py 25 Aug 2003 19:27:39 -0000 1.2 *************** *** 24,28 **** HELP = """ You can ask me to show RSS news from any site and for any user/channel ! and server with "[dont] show (news|rss news) [from] <url> [with link[s]] [with desc[ription][s]] [with prefix "<prefix>"] [each <n>(m|h)] [(on|for) (user|channel) <target>] [(on|at) server <server>]". Notice --- 24,28 ---- HELP = """ You can ask me to show RSS news from any site and for any user/channel ! and server with "[dont] show (rss|news) [from] <url> [with link[s]] [with desc[ription][s]] [with prefix "<prefix>"] [each <n>(m|h)] [(on|for) (user|channel) <target>] [(on|at) server <server>]". Notice *************** *** 86,92 **** mm.hooktimer(60, self.update, ()) ! # [dont] show (news|rss news) [from] <url> [with link[s]] [with desc[ription][s]] [with prefix "<prefix>"] [each <n>(m|h)] [[on|at|in|for] (user|channel) <target>] [[on|at|in|for] server <server>] self.re1 = regexp(refrag.dont(optional=1), ! r"show (?:rss news |news )(?:from )?(?P<url>(?:https?|ftp)\S+)" r"(?:" r" with prefix \"(?P<prefix>.*?)\"|" --- 86,92 ---- mm.hooktimer(60, self.update, ()) ! # [dont] show (rss|news|rss news) [from] <url> [with link[s]] [with desc[ription][s]] [with prefix "<prefix>"] [each <n>(m|h)] [[on|at|in|for] (user|channel) <target>] [[on|at|in|for] server <server>] self.re1 = regexp(refrag.dont(optional=1), ! r"show (?:rss |news |rss news )(?:from )?(?P<url>(?:https?|ftp)\S+)" r"(?:" r" with prefix \"(?P<prefix>.*?)\"|" *************** *** 219,229 **** cursor.execute("insert into rssfeed values (NULL, %s, 0)", (url,)) try: cursor.execute("insert into rsstarget values " ! "(NULL," ! " (select id from rssfeed where url=%s)," ! " %s, %s, %s, %s, %s, -1)", ! (url, servername, target, flags, ! prefix, interval)) except db.error: msg.answer("%:", ["Not needed", "It's not needed", --- 219,233 ---- cursor.execute("insert into rssfeed values (NULL, %s, 0)", (url,)) + cursor.execute("select id from rssfeed where url=%s", + (url,)) + feedid = cursor.fetchone().id try: cursor.execute("insert into rsstarget values " ! "(NULL, %s, %s, %s, %s, %s, %s, " ! " (select max(id) from rssitem where " ! " feedid=%s)" ! ")", ! (feedid, servername, target, flags, ! prefix, interval, feedid)) except db.error: msg.answer("%:", ["Not needed", "It's not needed", |
From: Gustavo N. <nie...@us...> - 2003-08-25 21:50:02
|
Update of /cvsroot/pybot/pybot/pybot/modules In directory sc8-pr-cvs1:/tmp/cvs-serv12941/pybot/modules Modified Files: remoteinfo.py Log Message: * Reestructured some parts of remoteinfo module, fixing consistency. * Show first char of regex, even if it is a '\' Index: remoteinfo.py =================================================================== RCS file: /cvsroot/pybot/pybot/pybot/modules/remoteinfo.py,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -d -r1.6 -r1.7 *** remoteinfo.py 25 Aug 2003 14:19:17 -0000 1.6 --- remoteinfo.py 25 Aug 2003 21:49:05 -0000 1.7 *************** *** 90,95 **** class RemoteInfo: def __init__(self): ! db.table("remoteinfo", "url,regex,interval") ! db.table("remoteinfoallow", "url,servername,target") self.info = options.get("RemoteInfo.info", {}) self.info_lock = options.get("RemoteInfo.info_lock", {}) --- 90,103 ---- class RemoteInfo: def __init__(self): ! db.table("remoteinfo", "id integer primary key, url, regex, interval", ! constraints="unique (url)", ! triggers=[ ! "create trigger remoteinfo1 after delete on remoteinfo " ! "begin" ! " delete from remoteinfoallow where infoid=old.id;" ! "end" ! ]) ! db.table("remoteinfoallow", "infoid, servername, target", ! constraints="unique (infoid, servername, target)") self.info = options.get("RemoteInfo.info", {}) self.info_lock = options.get("RemoteInfo.info_lock", {}) *************** *** 212,221 **** def get_allowed_urls(self, servername, target): cursor = db.cursor() ! cursor.execute("select * from remoteinfoallow") allowed = {} for row in cursor.fetchall(): ! if (not row.servername or row.servername == servername) and \ ! (not row.target or row.target == target): ! allowed[row.url] = 1 return allowed.keys() --- 220,232 ---- def get_allowed_urls(self, servername, target): cursor = db.cursor() ! cursor.execute("select remoteinfo.url,remoteinfoallow.* " ! "from remoteinfoallow left join remoteinfo " ! "on remoteinfo.id=remoteinfoallow.infoid") ! # [0] url, [1] infoid, [2] servername, [3] target allowed = {} for row in cursor.fetchall(): ! if (not row[2] or row[2] == servername) and \ ! (not row[3] or row[3] == target): ! allowed[row[0]] = 1 return allowed.keys() *************** *** 296,302 **** cursor = db.cursor() ! cursor.execute("select * from remoteinfo where url=%s", ! (url,)) ! if cursor.rowcount: msg.answer("%:", ["I can't do that.", "Nope.", None], ["I'm already loading that url", --- 307,315 ---- cursor = db.cursor() ! try: ! cursor.execute("insert into remoteinfo values " ! "(NULL,%s,%s,%s)", ! (url, regex, interval)) ! except db.error: msg.answer("%:", ["I can't do that.", "Nope.", None], ["I'm already loading that url", *************** *** 305,311 **** [".", "!"]) else: - cursor.execute("insert into remoteinfo values " - "(%s,%s,%s)", - (url, regex, interval)) msg.answer("%:", ["Loading", "No problems", --- 318,321 ---- *************** *** 351,356 **** cursor.execute("delete from remoteinfo where url=%s", (url,)) - cursor.execute("delete from remoteinfoallow where " - "url=%s", (url,)) msg.answer("%:", ["Done", "Of course", "Ready"], [".", "!"]) --- 361,364 ---- *************** *** 393,423 **** [".", "!"]) return 0 ! cursor.execute("select * from remoteinfoallow where url=%s " ! "and servername=%s and target=%s", ! (url, server, target)) ! if cursor.rowcount: ! if m.group("dont"): ! cursor.execute("delete from remoteinfoallow where " ! "url=%s and servername=%s and target=%s", ! (url, server, target)) msg.answer("%:", ["Sure", "Done", "Removed", "Ok"], [".", "!"]) else: msg.answer("%:", ["I can't do that.", "Nope.", None], - ["This target is already allowed", - "I'm already allowing this target", - "This target is already in my database"], - [".", "!"]) - else: - if m.group("dont"): - msg.answer("%:", ["I can't do that.", "Nope.", None], ["This target doesn't exist", "I'm not allowing this target", "This target is not in my database"], [".", "!"]) ! else: cursor.execute("insert into remoteinfoallow values " ! "(%s,%s,%s)", ! (url, server, target)) msg.answer("%:", ["Sure", "Done", "Added", "Ok"], [".", "!"]) --- 401,430 ---- [".", "!"]) return 0 ! if m.group("dont"): ! cursor.execute("delete from remoteinfoallow where " ! "infoid=(select id from remoteinfo where url=%s) " ! "and servername=%s and target=%s", ! (url, server, target)) ! if cursor.rowcount: msg.answer("%:", ["Sure", "Done", "Removed", "Ok"], [".", "!"]) else: msg.answer("%:", ["I can't do that.", "Nope.", None], ["This target doesn't exist", "I'm not allowing this target", "This target is not in my database"], [".", "!"]) ! else: ! try: cursor.execute("insert into remoteinfoallow values " ! "((select id from remoteinfo where url=%s)," ! " %s,%s)", (url, server, target)) ! except db.error: ! msg.answer("%:", ["I can't do that.", "Nope.", None], ! ["This target is already allowed", ! "I'm already allowing this target", ! "This target is already in my database"], ! [".", "!"]) ! else: msg.answer("%:", ["Sure", "Done", "Added", "Ok"], [".", "!"]) *************** *** 452,456 **** unit += "s" cursor.execute("select * from remoteinfoallow where " ! "url=%s", (row.url,)) if cursor.rowcount: allowed = "(for " --- 459,463 ---- unit += "s" cursor.execute("select * from remoteinfoallow where " ! "infoid=%s", (row.id,)) if cursor.rowcount: allowed = "(for " *************** *** 474,479 **** else: allowed = "(for nobody)" msg.answer("-", row.url, "each", str(interval), unit, ! "with regex", row.regex, allowed) else: msg.answer("%:", "No remote info urls are currently " --- 481,489 ---- else: allowed = "(for nobody)" + regex = row.regex + if regex and regex[0] == "\\": + regex = "\\"+regex msg.answer("-", row.url, "each", str(interval), unit, ! "with regex", regex, allowed) else: msg.answer("%:", "No remote info urls are currently " |
From: Gustavo N. <nie...@us...> - 2003-08-25 20:47:05
|
Update of /cvsroot/pybot/pybot/pybot/modules In directory sc8-pr-cvs1:/tmp/cvs-serv31762/pybot/modules Modified Files: rss.py Log Message: Reduced minimum interval to 10 minutes in rss module. Index: rss.py =================================================================== RCS file: /cvsroot/pybot/pybot/pybot/modules/rss.py,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** rss.py 25 Aug 2003 19:27:39 -0000 1.2 --- rss.py 25 Aug 2003 20:46:52 -0000 1.3 *************** *** 40,45 **** """ ! # Fetching below 30 minutes is evil ! MININTERVAL = 30*60 # Maximum number of stored news from each feed --- 40,46 ---- """ ! # Fetching below 30 minutes is evil, but some active services will ! # make pybot flood the channel with more than 10 minutes. ! MININTERVAL = 10*60 # Maximum number of stored news from each feed |
From: Gustavo N. <nie...@us...> - 2003-08-25 20:44:42
|
Update of /cvsroot/pybot/pybot/data/infopacks In directory sc8-pr-cvs1:/tmp/cvs-serv30662/data/infopacks Modified Files: airport.info ports.info vera.info versions.info Log Message: Integrated infopack help into main help. Index: airport.info =================================================================== RCS file: /cvsroot/pybot/pybot/data/infopacks/airport.info,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** airport.info 12 May 2003 20:42:19 -0000 1.2 --- airport.info 25 Aug 2003 20:44:23 -0000 1.3 *************** *** 4,8 **** # information about infobot at http://www.infobot.org. # ! H:This infopack provides a database of airport locations around the world. You can ask for an airport location using "airport <code>". T:(?:what|where)(?:'s|\s+is)\s+(?:the\s+)?airport\s+(?:code\s+)?([a-z]{3})\s*(?:!*\?[!?]*)?$ T:airport\s+([a-zA-Z]{3})\s*(?:!*\?[!?]*)?$ --- 4,9 ---- # information about infobot at http://www.infobot.org. # ! h:airports:airports? ! H:The airport infopack provides a database of airport locations around the world. You can ask for an airport location using "airport <code>". T:(?:what|where)(?:'s|\s+is)\s+(?:the\s+)?airport\s+(?:code\s+)?([a-z]{3})\s*(?:!*\?[!?]*)?$ T:airport\s+([a-zA-Z]{3})\s*(?:!*\?[!?]*)?$ Index: ports.info =================================================================== RCS file: /cvsroot/pybot/pybot/data/infopacks/ports.info,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** ports.info 12 May 2003 20:42:19 -0000 1.2 --- ports.info 25 Aug 2003 20:44:23 -0000 1.3 *************** *** 4,8 **** # information about infobot at http://www.infobot.org. # ! H:This infopack provides a database of port numbers. You can check what service is usually provided in a port number using "port <num>". T:what(?:'s|\s+is)\s+(?:the\s+)?port\s+(?:number\s+)?([0-9]+)(?:\s+for)\s*(?:!*\?[!?]*)?$ T:port\s+(\d+)[!?.]*$ --- 4,9 ---- # information about infobot at http://www.infobot.org. # ! h:port numbers:ports?\s+numbers? ! H:The ports infopack provides a database of port numbers. You can check what service is usually provided in a port number using "port <num>". T:what(?:'s|\s+is)\s+(?:the\s+)?port\s+(?:number\s+)?([0-9]+)(?:\s+for)\s*(?:!*\?[!?]*)?$ T:port\s+(\d+)[!?.]*$ Index: vera.info =================================================================== RCS file: /cvsroot/pybot/pybot/data/infopacks/vera.info,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** vera.info 16 May 2003 17:34:42 -0000 1.4 --- vera.info 25 Aug 2003 20:44:23 -0000 1.5 *************** *** 7,11 **** # ftp://ftp.gnu.org/gnu/vera # ! H:This infopack provides the VERA database of acronyms. You can check for a given a acronym using "acronym <acronym>". T:acronym\s+(\w+)\s*\?*$ D:t:No acronym for that. --- 7,12 ---- # ftp://ftp.gnu.org/gnu/vera # ! h:acronyms:acronyms?|vera ! H:The vera infopack provides the VERA database of acronyms. You can check for a given a acronym using "acronym <acronym>". T:acronym\s+(\w+)\s*\?*$ D:t:No acronym for that. Index: versions.info =================================================================== RCS file: /cvsroot/pybot/pybot/data/infopacks/versions.info,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** versions.info 23 May 2003 21:29:29 -0000 1.1 --- versions.info 25 Aug 2003 20:44:23 -0000 1.2 *************** *** 2,6 **** # released in Conectiva Linux. # ! H:This infopack provides information about which package versions were released in past versions of Conectiva Linux. You can check a given package with "[show] versions [of] <packagename>". T:(?:show\s+)?versions\s+(?:of\s+)?(\S+) D:t:No information about that package. --- 2,7 ---- # released in Conectiva Linux. # ! h:versions:(?:package\s+)?versions? ! H:The versions infopack provides information about which package versions were released in past versions of Conectiva Linux. You can check a given package with "[show] versions [of] <packagename>". T:(?:show\s+)?versions\s+(?:of\s+)?(\S+) D:t:No information about that package. |
From: Gustavo N. <nie...@us...> - 2003-08-25 20:44:42
|
Update of /cvsroot/pybot/pybot In directory sc8-pr-cvs1:/tmp/cvs-serv30662 Modified Files: ChangeLog Log Message: Integrated infopack help into main help. Index: ChangeLog =================================================================== RCS file: /cvsroot/pybot/pybot/ChangeLog,v retrieving revision 1.30 retrieving revision 1.31 diff -C2 -d -r1.30 -r1.31 *** ChangeLog 25 Aug 2003 18:58:50 -0000 1.30 --- ChangeLog 25 Aug 2003 20:44:23 -0000 1.31 *************** *** 8,11 **** --- 8,13 ---- to send news from any RSS feed to any user/channel/server. * QUICK_START: Added small startup tutorial. + * modules/{help.py,infopack.py}: Integrated infopack help + into main help. 2003-08-24 Gustavo Niemeyer <nie...@co...> |
From: Gustavo N. <nie...@us...> - 2003-08-25 20:44:42
|
Update of /cvsroot/pybot/pybot/pybot/modules In directory sc8-pr-cvs1:/tmp/cvs-serv30662/pybot/modules Modified Files: help.py infopack.py Log Message: Integrated infopack help into main help. Index: help.py =================================================================== RCS file: /cvsroot/pybot/pybot/pybot/modules/help.py,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -d -r1.6 -r1.7 *** help.py 24 Aug 2003 19:30:53 -0000 1.6 --- help.py 25 Aug 2003 20:44:23 -0000 1.7 *************** *** 65,76 **** 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) --- 65,77 ---- match = pattern.match(something) if match: if callable(text): ! found |= text(msg, match) elif type(text) in (ListType, TupleType): + found = 1 for line in text: line = line.replace("\n", " ").strip() msg.answer("%:", line) else: + found = 1 text = text.replace("\n", " ").strip() msg.answer("%:", text) *************** *** 80,84 **** alltriggers = [] for pattern, text, triggers in self.data: ! alltriggers.extend(triggers) if alltriggers: alltriggers.sort() --- 81,88 ---- alltriggers = [] for pattern, text, triggers in self.data: ! if len(triggers) == 1 and callable(triggers[0]): ! alltriggers.extend(triggers[0]()) ! else: ! alltriggers.extend(triggers) if alltriggers: alltriggers.sort() *************** *** 104,107 **** --- 108,112 ---- pattern = pattern.replace(" ?", r"\s*") pattern = pattern.replace(" ", r"\s+") + pattern = pattern+"\s*$" self.data.append((re.compile(pattern, re.I), text, triggers)) Index: infopack.py =================================================================== RCS file: /cvsroot/pybot/pybot/pybot/modules/infopack.py,v retrieving revision 1.8 retrieving revision 1.9 diff -C2 -d -r1.8 -r1.9 *** infopack.py 24 Aug 2003 19:30:53 -0000 1.8 --- infopack.py 25 Aug 2003 20:44:24 -0000 1.9 *************** *** 49,65 **** 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) --- 49,77 ---- def __init__(self, filename): self._filename = filename + self.reset() + + def reset(self): self._info = {} self._triggers = [] self._masks = [] self._defaults = [] ! self._help_patterns = [] ! self._help_triggers = [] ! self._help_text = [] ! ! def help_match(self, line): ! for pattern in self._help_patterns: ! if pattern.match(line): ! return 1 ! return 0 ! ! def help_triggers(self): ! return self._help_triggers ! ! def help_text(self): ! return self._help_text def load(self): ! self.reset() values = [] file = open(self._filename) *************** *** 80,84 **** self._masks.append(line[2:].rstrip()) elif line[0] == "H": ! self._help.append(line[2:].rstrip()) elif line[0] == "D": value = line[2:].split(":", 1) --- 92,102 ---- self._masks.append(line[2:].rstrip()) elif line[0] == "H": ! self._help_text.append(line[2:].rstrip()) ! elif line[0] == "h": ! tokens = line[2:].rstrip().split(":", 1) ! if tokens[0]: ! self._help_triggers.append(tokens[1]) ! if tokens[1]: ! self._help_patterns.append(re.compile(tokens[0])) elif line[0] == "D": value = line[2:].split(":", 1) *************** *** 88,94 **** def loadcore(self): ! self._info = {} ! self._triggers = [] ! self._masks = [] values = [] file = open(self._filename) --- 106,110 ---- def loadcore(self): ! self.reset() values = [] file = open(self._filename) *************** *** 101,105 **** self._masks.append(line[2:].rstrip()) elif line[0] == "H": ! self._help.append(line[2:].rstrip()) elif line[0] == "D": value = line[2:].split(":", 1) --- 117,127 ---- self._masks.append(line[2:].rstrip()) elif line[0] == "H": ! self._help_text.append(line[2:].rstrip()) ! elif line[0] == "h": ! tokens = line[2:].rstrip().split(":", 1) ! if tokens[0]: ! self._help_triggers.append(tokens[0]) ! if tokens[1]: ! self._help_patterns.append(re.compile(tokens[1])) elif line[0] == "D": value = line[2:].split(":", 1) *************** *** 111,117 **** def unload(self): ! self._info = {} ! self._triggers = [] ! self._phrases = [] def reload(self): --- 133,137 ---- def unload(self): ! self.reset() def reload(self): *************** *** 204,208 **** # infopack <name> ! mm.register_help("infopack (?P<name>\S+)", self.help) mm.register_perm("infopackadmin", PERM_INFOPACKADMIN) --- 224,232 ---- # infopack <name> ! mm.register_help("infopack (?P<name>\S+)", self.help_infopack) ! ! # .+ ! mm.register_help("(?P<something>.+)", self.help_match, ! self.help_triggers) mm.register_perm("infopackadmin", PERM_INFOPACKADMIN) *************** *** 214,221 **** mm.unregister_perm("infopackadmin") ! def help(self, msg, match): name = match.group("name") try: ! help = self.packs[name].help() except KeyError: msg.answer("%:", "There's no infopack with that name.") --- 238,245 ---- mm.unregister_perm("infopackadmin") ! def help_infopack(self, msg, match): name = match.group("name") try: ! help = self.packs[name].help_text() except KeyError: msg.answer("%:", "There's no infopack with that name.") *************** *** 223,226 **** --- 247,267 ---- for line in help: msg.answer("%:", line) + return 1 + + def help_match(self, msg, match): + something = match.group("something") + found = 0 + for pack in self.packs.values(): + if pack.help_match(something): + found = 1 + for line in pack.help_text(): + msg.answer("%:", line) + return found + + def help_triggers(self): + alltriggers = [] + for pack in self.packs.values(): + alltriggers.extend(pack.help_triggers()) + return alltriggers def message(self, msg): |
From: Gustavo N. <nie...@us...> - 2003-08-25 18:59:12
|
Update of /cvsroot/pybot/pybot In directory sc8-pr-cvs1:/tmp/cvs-serv11464 Modified Files: ChangeLog TODO Added Files: QUICK_START Log Message: Added small startup tutorial. --- NEW FILE: QUICK_START --- Here is a quick startup tutorial: ---------- % cvs -z3 -d:pserver:ano...@cv...:/cvsroot/pybot co pybot cvs server: Updating pybot U pybot/ChangeLog U pybot/LICENSE U pybot/README U pybot/TODO U pybot/pybot.conf U pybot/pybot.py (...) % cd pybot % vi pybot.conf (... defaults are usually ok ...) % ./pybot.py -c pybot> pybot> help (...) pybot> pybot> connect to irc.freenode.net with servername freenode and with nick MyBot [MSG] I'm going there! pybot> pybot> pybot> join #conectiva on freenode pybot> [MSG] No problems. pybot> quit (... bot disconnects ...) % ./pybot.py -c (... bot automatically reconnects to freenode ...) pybot> pybot> show channels [MSG] In server freenode, I'm in the following channels: #conectiva pybot> help modules (... check the help and load additional modules ...) pybot> help permissions (... check the help and give some permissions ...) pybot> quit % ./pybot.py & [1] 8528 Index: ChangeLog =================================================================== RCS file: /cvsroot/pybot/pybot/ChangeLog,v retrieving revision 1.29 retrieving revision 1.30 diff -C2 -d -r1.29 -r1.30 *** ChangeLog 25 Aug 2003 18:54:54 -0000 1.29 --- ChangeLog 25 Aug 2003 18:58:50 -0000 1.30 *************** *** 7,10 **** --- 7,11 ---- Mark Pilgrim's "ultra liberal" parser, and allows one to send news from any RSS feed to any user/channel/server. + * QUICK_START: Added small startup tutorial. 2003-08-24 Gustavo Niemeyer <nie...@co...> Index: TODO =================================================================== RCS file: /cvsroot/pybot/pybot/TODO,v retrieving revision 1.13 retrieving revision 1.14 diff -C2 -d -r1.13 -r1.14 *** TODO 22 Aug 2003 13:22:11 -0000 1.13 --- TODO 25 Aug 2003 18:58:50 -0000 1.14 *************** *** 5,10 **** directories. - - Develop a README explaining how to do the basic setup of pybot. - - Cross identification between servers (is this useful?). --- 5,8 ---- |
From: Gustavo N. <nie...@us...> - 2003-08-25 18:55:28
|
Update of /cvsroot/pybot/pybot/pybot/util In directory sc8-pr-cvs1:/tmp/cvs-serv10959/pybot/util Added Files: feedparser.py Log Message: * pybot/rss.py: Introduced generic RSS module! It's based on Mark Pilgrim's "ultra liberal" parser, and allows one to send news from any RSS feed to any user/channel/server. * pybot/refrag.py: Introduced the refrag module. It contains reusable "fragments" of regular expression patterns. It's meant to reduce the number of times one has to code similar patterns. --- NEW FILE: feedparser.py --- #!/usr/bin/python """Ultra-liberal feed parser Visit http://diveintomark.org/projects/feed_parser/ for the latest version Handles RSS 0.9x, RSS 1.0, RSS 2.0, Pie/Atom/Echo feeds RSS 0.9x/common elements: - title, link, guid, description, webMaster, managingEditor, language copyright, lastBuildDate, pubDate Additional RSS 1.0/2.0 elements: - dc:rights, dc:language, dc:creator, dc:date, dc:subject, content:encoded, admin:generatorAgent, admin:errorReportsTo, Addition Pie/Atom/Echo elements: - subtitle, created, issued, modified, summary, id, content Things it handles that choke other parsers: - bastard combinations of RSS 0.9x and RSS 1.0 - illegal XML characters - naked and/or invalid HTML in description - content:encoded in item element - guid in item element - fullitem in item element - non-standard namespaces - inline XML in content (Pie/Atom/Echo) - multiple content items per entry (Pie/Atom/Echo) Requires Python 2.2 or later """ __version__ = "2.5.3" __author__ = "Mark Pilgrim <http://diveintomark.org/>" __copyright__ = "Copyright 2002-3, Mark Pilgrim" __contributors__ = ["Jason Diamond <http://injektilo.org/>", "John Beimler <http://john.beimler.org/>"] __license__ = "Python" __history__ = """ 1.0 - 9/27/2002 - MAP - fixed namespace processing on prefixed RSS 2.0 elements, added Simon Fell's test suite 1.1 - 9/29/2002 - MAP - fixed infinite loop on incomplete CDATA sections 2.0 - 10/19/2002 JD - use inchannel to watch out for image and textinput elements which can also contain title, link, and description elements JD - check for isPermaLink="false" attribute on guid elements JD - replaced openAnything with open_resource supporting ETag and If-Modified-Since request headers JD - parse now accepts etag, modified, agent, and referrer optional arguments JD - modified parse to return a dictionary instead of a tuple so that any etag or modified information can be returned and cached by the caller 2.0.1 - 10/21/2002 - MAP - changed parse() so that if we don't get anything because of etag/modified, return the old etag/modified to the caller to indicate why nothing is being returned 2.0.2 - 10/21/2002 - JB - added the inchannel to the if statement, otherwise its useless. Fixes the problem JD was addressing by adding it. 2.1 - 11/14/2002 - MAP - added gzip support 2.2 - 1/27/2003 - MAP - added attribute support, admin:generatorAgent. start_admingeneratoragent is an example of how to handle elements with only attributes, no content. 2.3 - 6/11/2003 - MAP - added USER_AGENT for default (if caller doesn't specify); also, make sure we send the User-Agent even if urllib2 isn't available. Match any variation of backend.userland.com/rss namespace. 2.3.1 - 6/12/2003 - MAP - if item has both link and guid, return both as-is. 2.4 - 7/9/2003 - MAP - added preliminary Pie/Atom/Echo support based on Sam Ruby's snapshot of July 1 <http://www.intertwingly.net/blog/1506.html>; changed project name 2.5 - 7/25/2003 - MAP - changed to Python license (all contributors agree); removed unnecessary urllib code -- urllib2 should always be available anyway; return actual url, status, and full HTTP headers (as result['url'], result['status'], and result['headers']) if parsing a remote feed over HTTP -- this should pass all the HTTP tests at <http://diveintomark.org/tests/client/http/>; added the latest namespace-of-the-week for RSS 2.0 2.5.1 - 7/26/2003 - RMK - clear opener.addheaders so we only send our custom User-Agent (otherwise urllib2 sends two, which confuses some servers) 2.5.2 - 7/28/2003 - MAP - entity-decode inline xml properly; added support for inline <xhtml:body> and <xhtml:div> as used in some RSS 2.0 feeds 2.5.3 - 8/6/2003 - TvdV - patch to track whether we're inside an image or textInput, and also to return the character encoding (if specified) """ try: import timeoutsocket # http://www.timo-tasi.org/python/timeoutsocket.py timeoutsocket.setDefaultSocketTimeout(10) except ImportError: pass import cgi, re, sgmllib, string, StringIO, gzip, urllib2 sgmllib.tagfind = re.compile('[a-zA-Z][-_.:a-zA-Z0-9]*') USER_AGENT = "UltraLiberalFeedParser/%s +http://diveintomark.org/projects/feed_parser/" % __version__ def decodeEntities(data): data = data or '' data = data.replace('<', '<') data = data.replace('>', '>') data = data.replace('"', '"') data = data.replace(''', "'") data = data.replace('&', '&') return data class FeedParser(sgmllib.SGMLParser): namespaces = {"http://backend.userland.com/rss": "", "http://blogs.law.harvard.edu/tech/rss": "", "http://purl.org/rss/1.0/": "", "http://example.com/newformat#": "", "http://example.com/necho": "", "http://purl.org/echo/": "", "uri/of/echo/namespace#": "", "http://purl.org/pie/": "", "http://purl.org/rss/1.0/modules/textinput/": "ti", "http://purl.org/rss/1.0/modules/company/": "co", "http://purl.org/rss/1.0/modules/syndication/": "sy", "http://purl.org/dc/elements/1.1/": "dc", "http://webns.net/mvcb/": "admin", "http://www.w3.org/1999/xhtml": "xhtml"} def reset(self): self.channel = {} self.items = [] self.elementstack = [] self.inchannel = 0 self.initem = 0 self.incontent = 0 self.intextinput = 0 self.inimage = 0 self.contentmode = None self.contenttype = None self.contentlang = None self.namespacemap = {} sgmllib.SGMLParser.reset(self) def push(self, element, expectingText): self.elementstack.append([element, expectingText, []]) def pop(self, element): if not self.elementstack: return if self.elementstack[-1][0] != element: return element, expectingText, pieces = self.elementstack.pop() if not expectingText: return output = "".join(pieces) output = decodeEntities(output) if self.incontent and self.initem: if not self.items[-1].has_key(element): self.items[-1][element] = [] self.items[-1][element].append({"language":self.contentlang, "type":self.contenttype, "value":output}) elif self.initem: self.items[-1][element] = output elif self.inchannel and (not self.intextinput) and (not self.inimage): self.channel[element] = output def _addNamespaces(self, attrs): for prefix, value in attrs: if not prefix.startswith("xmlns:"): continue prefix = prefix[6:] if prefix.find('backend.userland.com/rss') <> -1: # match any backend.userland.com namespace prefix = 'http://backend.userland.com/rss' if self.namespaces.has_key(value): self.namespacemap[prefix] = self.namespaces[value] def _mapToStandardPrefix(self, name): colonpos = name.find(':') if colonpos <> -1: prefix = name[:colonpos] suffix = name[colonpos+1:] prefix = self.namespacemap.get(prefix, prefix) name = prefix + ':' + suffix return name def _getAttribute(self, attrs, name): value = [v for k, v in attrs if self._mapToStandardPrefix(k) == name] if value: value = value[0] else: value = None return value def start_channel(self, attrs): self.push('channel', 0) self.inchannel = 1 def end_channel(self): self.pop('channel') self.inchannel = 0 def start_image(self, attrs): self.inimage = 1 def end_image(self): self.inimage = 0 def start_textinput(self, attrs): self.intextinput = 1 def end_textinput(self): self.intextinput = 0 def start_item(self, attrs): self.items.append({}) self.push('item', 0) self.initem = 1 def end_item(self): self.pop('item') self.initem = 0 def start_dc_language(self, attrs): self.push('language', 1) start_language = start_dc_language def end_dc_language(self): self.pop('language') end_language = end_dc_language def start_dc_creator(self, attrs): self.push('creator', 1) start_managingeditor = start_dc_creator start_webmaster = start_dc_creator def end_dc_creator(self): self.pop('creator') end_managingeditor = end_dc_creator end_webmaster = end_dc_creator def start_dc_rights(self, attrs): self.push('rights', 1) start_copyright = start_dc_rights def end_dc_rights(self): self.pop('rights') end_copyright = end_dc_rights def start_dc_date(self, attrs): self.push('date', 1) start_lastbuilddate = start_dc_date start_pubdate = start_dc_date def end_dc_date(self): self.pop('date') end_lastbuilddate = end_dc_date end_pubdate = end_dc_date def start_dc_subject(self, attrs): self.push('category', 1) def end_dc_subject(self): self.pop('category') def start_link(self, attrs): self.push('link', self.inchannel or self.initem) def end_link(self): self.pop('link') def start_guid(self, attrs): self.guidislink = ('ispermalink', 'false') not in attrs self.push('guid', 1) def end_guid(self): self.pop('guid') if self.guidislink: if not self.items[-1].has_key('link'): # guid acts as link, but only if "ispermalink" is not present or is "true", # and only if the item doesn't already have a link element self.items[-1]['link'] = self.items[-1]['guid'] def start_title(self, attrs): self.push('title', self.inchannel or self.initem) def start_description(self, attrs): self.push('description', self.inchannel or self.initem) def start_content_encoded(self, attrs): self.push('content_encoded', 1) start_fullitem = start_content_encoded def end_content_encoded(self): self.pop('content_encoded') end_fullitem = end_content_encoded def start_admin_generatoragent(self, attrs): self.push('generator', 1) value = self._getAttribute(attrs, 'rdf:resource') if value: self.elementstack[-1][2].append(value) self.pop('generator') def start_feed(self, attrs): self.inchannel = 1 def end_feed(self): self.inchannel = 0 def start_entry(self, attrs): self.items.append({}) self.push('item', 0) self.initem = 1 def end_entry(self): self.pop('item') self.initem = 0 def start_subtitle(self, attrs): self.push('subtitle', 1) def end_subtitle(self): self.pop('subtitle') def start_summary(self, attrs): self.push('summary', 1) def end_summary(self): self.pop('summary') def start_modified(self, attrs): self.push('modified', 1) def end_modified(self): self.pop('modified') def start_created(self, attrs): self.push('created', 1) def end_created(self): self.pop('created') def start_issued(self, attrs): self.push('issued', 1) def end_issued(self): self.pop('issued') def start_id(self, attrs): self.push('id', 1) def end_id(self): self.pop('id') def start_content(self, attrs): self.incontent = 1 if ('mode', 'escaped') in attrs: self.contentmode = 'escaped' elif ('mode', 'base64') in attrs: self.contentmode = 'base64' else: self.contentmode = 'xml' mimetype = [v for k, v in attrs if k=='type'] if mimetype: self.contenttype = mimetype[0] xmllang = [v for k, v in attrs if k=='xml:lang'] if xmllang: self.contentlang = xmllang[0] self.push('content', 1) def end_content(self): self.pop('content') self.incontent = 0 self.contentmode = None self.contenttype = None self.contentlang = None def start_body(self, attrs): self.incontent = 1 self.contentmode = 'xml' self.contenttype = 'application/xhtml+xml' xmllang = [v for k, v in attrs if k=='xml:lang'] if xmllang: self.contentlang = xmllang[0] self.push('content', 1) start_div = start_body start_xhtml_body = start_body start_xhtml_div = start_body end_body = end_content end_div = end_content end_xhtml_body = end_content end_xhtml_div = end_content def unknown_starttag(self, tag, attrs): if self.incontent and self.contentmode == 'xml': self.handle_data("<%s%s>" % (tag, "".join([' %s="%s"' % t for t in attrs]))) return self._addNamespaces(attrs) colonpos = tag.find(':') if colonpos <> -1: prefix = tag[:colonpos] suffix = tag[colonpos+1:] prefix = self.namespacemap.get(prefix, prefix) if prefix: prefix = prefix + '_' methodname = 'start_' + prefix + suffix try: method = getattr(self, methodname) return method(attrs) except AttributeError: return self.push(prefix + suffix, 0) return self.push(tag, 0) def unknown_endtag(self, tag): if self.incontent and self.contentmode == 'xml': self.handle_data("</%s>" % tag) return colonpos = tag.find(':') if colonpos <> -1: prefix = tag[:colonpos] suffix = tag[colonpos+1:] prefix = self.namespacemap.get(prefix, prefix) if prefix: prefix = prefix + '_' methodname = 'end_' + prefix + suffix try: method = getattr(self, methodname) return method() except AttributeError: return self.pop(prefix + suffix) return self.pop(tag) def handle_charref(self, ref): # called for each character reference, e.g. for " ", ref will be "160" # Reconstruct the original character reference. if not self.elementstack: return text = "&#%s;" % ref if self.incontent and self.contentmode == 'xml': text = cgi.escape(text) self.elementstack[-1][2].append(text) def handle_entityref(self, ref): # called for each entity reference, e.g. for "©", ref will be "copy" # Reconstruct the original entity reference. if not self.elementstack: return text = "&%s;" % ref if self.incontent and self.contentmode == 'xml': text = cgi.escape(text) self.elementstack[-1][2].append(text) def handle_data(self, text): # called for each block of plain text, i.e. outside of any tag and # not containing any character or entity references if not self.elementstack: return if self.incontent and self.contentmode == 'xml': text = cgi.escape(text) self.elementstack[-1][2].append(text) def handle_comment(self, text): # called for each comment, e.g. <!-- insert message here --> pass def handle_pi(self, text): # called for each processing instruction, e.g. <?instruction> pass def handle_decl(self, text): # called for the DOCTYPE, if present, e.g. # <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" # "http://www.w3.org/TR/html4/loose.dtd"> pass _new_declname_match = re.compile(r'[a-zA-Z][-_.a-zA-Z0-9:]*\s*').match def _scan_name(self, i, declstartpos): rawdata = self.rawdata n = len(rawdata) if i == n: return None, -1 m = self._new_declname_match(rawdata, i) if m: s = m.group() name = s.strip() if (i + len(s)) == n: return None, -1 # end of buffer return string.lower(name), m.end() else: self.updatepos(declstartpos, i) self.error("expected name token") def parse_declaration(self, i): # override internal declaration handler to handle CDATA blocks if self.rawdata[i:i+9] == '<![CDATA[': k = self.rawdata.find(']]>', i) if k == -1: k = len(self.rawdata) self.handle_data(cgi.escape(self.rawdata[i+9:k])) return k+3 return sgmllib.SGMLParser.parse_declaration(self, i) class FeedURLHandler(urllib2.HTTPRedirectHandler, urllib2.HTTPDefaultErrorHandler): def http_error_default(self, req, fp, code, msg, headers): if ((code / 100) == 3) and (code != 304): return self.http_error_302(req, fp, code, msg, headers) from urllib import addinfourl infourl = addinfourl(fp, headers, req.get_full_url()) infourl.status = code return infourl # raise urllib2.HTTPError(req.get_full_url(), code, msg, headers, fp) def http_error_302(self, req, fp, code, msg, headers): infourl = urllib2.HTTPRedirectHandler.http_error_302(self, req, fp, code, msg, headers) infourl.status = code return infourl def http_error_301(self, req, fp, code, msg, headers): infourl = urllib2.HTTPRedirectHandler.http_error_301(self, req, fp, code, msg, headers) infourl.status = code return infourl http_error_300 = http_error_302 http_error_307 = http_error_302 def open_resource(source, etag=None, modified=None, agent=None, referrer=None): """ URI, filename, or string --> stream This function lets you define parsers that take any input source (URL, pathname to local or network file, or actual data as a string) and deal with it in a uniform manner. Returned object is guaranteed to have all the basic stdio read methods (read, readline, readlines). Just .close() the object when you're done with it. If the etag argument is supplied, it will be used as the value of an If-None-Match request header. If the modified argument is supplied, it must be a tuple of 9 integers as returned by gmtime() in the standard Python time module. This MUST be in GMT (Greenwich Mean Time). The formatted date/time will be used as the value of an If-Modified-Since request header. If the agent argument is supplied, it will be used as the value of a User-Agent request header. If the referrer argument is supplied, it will be used as the value of a Referer[sic] request header. """ if hasattr(source, "read"): return source if source == "-": return sys.stdin if not agent: agent = USER_AGENT # try to open with urllib2 (to use optional headers) request = urllib2.Request(source) if etag: request.add_header("If-None-Match", etag) if modified: request.add_header("If-Modified-Since", format_http_date(modified)) request.add_header("User-Agent", agent) if referrer: request.add_header("Referer", referrer) request.add_header("Accept-encoding", "gzip") opener = urllib2.build_opener(FeedURLHandler()) opener.addheaders = [] # RMK - must clear so we only send our custom User-Agent try: return opener.open(request) except: # source is not a valid URL, but it might be a valid filename pass # try to open with native open function (if source is a filename) try: return open(source) except: pass # treat source as string return StringIO.StringIO(str(source)) def get_etag(resource): """ Get the ETag associated with a response returned from a call to open_resource(). If the resource was not returned from an HTTP server or the server did not specify an ETag for the resource, this will return None. """ if hasattr(resource, "info"): return resource.info().getheader("ETag") return None def get_modified(resource): """ Get the Last-Modified timestamp for a response returned from a call to open_resource(). If the resource was not returned from an HTTP server or the server did not specify a Last-Modified timestamp, this function will return None. Otherwise, it returns a tuple of 9 integers as returned by gmtime() in the standard Python time module(). """ if hasattr(resource, "info"): last_modified = resource.info().getheader("Last-Modified") if last_modified: return parse_http_date(last_modified) return None short_weekdays = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] long_weekdays = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"] months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] def format_http_date(date): """ Formats a tuple of 9 integers into an RFC 1123-compliant timestamp as required in RFC 2616. We don't use time.strftime() since the %a and %b directives can be affected by the current locale (HTTP dates have to be in English). The date MUST be in GMT (Greenwich Mean Time). """ return "%s, %02d %s %04d %02d:%02d:%02d GMT" % (short_weekdays[date[6]], date[2], months[date[1] - 1], date[0], date[3], date[4], date[5]) rfc1123_match = re.compile(r"(?P<weekday>[A-Z][a-z]{2}), (?P<day>\d{2}) (?P<month>[A-Z][a-z]{2}) (?P<year>\d{4}) (?P<hour>\d{2}):(?P<minute>\d{2}):(?P<second>\d{2}) GMT").match rfc850_match = re.compile(r"(?P<weekday>[A-Z][a-z]+), (?P<day>\d{2})-(?P<month>[A-Z][a-z]{2})-(?P<year>\d{2}) (?P<hour>\d{2}):(?P<minute>\d{2}):(?P<second>\d{2}) GMT").match asctime_match = re.compile(r"(?P<weekday>[A-Z][a-z]{2}) (?P<month>[A-Z][a-z]{2}) ?(?P<day>\d\d?) (?P<hour>\d{2}):(?P<minute>\d{2}):(?P<second>\d{2}) (?P<year>\d{4})").match def parse_http_date(date): """ Parses any of the three HTTP date formats into a tuple of 9 integers as returned by time.gmtime(). This should not use time.strptime() since that function is not available on all platforms and could also be affected by the current locale. """ date = str(date) year = 0 weekdays = short_weekdays m = rfc1123_match(date) if not m: m = rfc850_match(date) if m: year = 1900 weekdays = long_weekdays else: m = asctime_match(date) if not m: return None try: year = year + int(m.group("year")) month = months.index(m.group("month")) + 1 day = int(m.group("day")) hour = int(m.group("hour")) minute = int(m.group("minute")) second = int(m.group("second")) weekday = weekdays.index(m.group("weekday")) a = int((14 - month) / 12) julian_day = (day - 32045 + int(((153 * (month + (12 * a) - 3)) + 2) / 5) + int((146097 * (year + 4800 - a)) / 400)) - (int((146097 * (year + 4799)) / 400) - 31738) + 1 daylight_savings_flag = 0 return (year, month, day, hour, minute, second, weekday, julian_day, daylight_savings_flag) except: # the month or weekday lookup probably failed indicating an invalid timestamp return None def parse(uri, etag=None, modified=None, agent=None, referrer=None): r = FeedParser() f = open_resource(uri, etag=etag, modified=modified, agent=agent, referrer=referrer) data = f.read() if hasattr(f, "headers"): if f.headers.get('content-encoding', '') == 'gzip': try: data = gzip.GzipFile(fileobj=StringIO.StringIO(data)).read() except: # some feeds claim to be gzipped but they're not, so we get garbage data = '' r.feed(data) result = {"channel": r.channel, "items": r.items} newEtag = get_etag(f) if newEtag: result["etag"] = newEtag elif etag: result["etag"] = etag newModified = get_modified(f) if newModified: result["modified"] = newModified elif modified: result["modified"] = modified if hasattr(f, "url"): result["url"] = f.url if hasattr(f, "headers"): result["headers"] = f.headers.dict if hasattr(f, "status"): result["status"] = f.status elif hasattr(f, "url"): result["status"] = 200 # get the xml encoding if result.get('encoding', '') == '': xmlheaderRe = re.compile('<\?.*encoding="(.*)".*\?>') match = xmlheaderRe.match(data) if match: result['encoding'] = match.groups()[0].lower() f.close() return result TEST_SUITE = ('http://www.pocketsoap.com/rssTests/rss1.0withModules.xml', 'http://www.pocketsoap.com/rssTests/rss1.0withModulesNoDefNS.xml', 'http://www.pocketsoap.com/rssTests/rss1.0withModulesNoDefNSLocalNameClash.xml', 'http://www.pocketsoap.com/rssTests/rss2.0noNSwithModules.xml', 'http://www.pocketsoap.com/rssTests/rss2.0noNSwithModulesLocalNameClash.xml', 'http://www.pocketsoap.com/rssTests/rss2.0NSwithModules.xml', 'http://www.pocketsoap.com/rssTests/rss2.0NSwithModulesNoDefNS.xml', 'http://www.pocketsoap.com/rssTests/rss2.0NSwithModulesNoDefNSLocalNameClash.xml') if __name__ == '__main__': import sys if sys.argv[1:]: urls = sys.argv[1:] else: urls = TEST_SUITE from pprint import pprint for url in urls: print url print result = parse(url) pprint(result) print """ TODO - textinput/textInput - image - author - contributor - comments """ |
From: Gustavo N. <nie...@us...> - 2003-08-25 18:55:19
|
Update of /cvsroot/pybot/pybot In directory sc8-pr-cvs1:/tmp/cvs-serv10959 Modified Files: ChangeLog README Log Message: * pybot/rss.py: Introduced generic RSS module! It's based on Mark Pilgrim's "ultra liberal" parser, and allows one to send news from any RSS feed to any user/channel/server. * pybot/refrag.py: Introduced the refrag module. It contains reusable "fragments" of regular expression patterns. It's meant to reduce the number of times one has to code similar patterns. Index: ChangeLog =================================================================== RCS file: /cvsroot/pybot/pybot/ChangeLog,v retrieving revision 1.28 retrieving revision 1.29 diff -C2 -d -r1.28 -r1.29 *** ChangeLog 25 Aug 2003 14:10:33 -0000 1.28 --- ChangeLog 25 Aug 2003 18:54:54 -0000 1.29 *************** *** 1,2 **** --- 1,11 ---- + 2003-08-25 Gustavo Niemeyer <nie...@co...> + * pybot/refrag.py: Introduced the refrag module. It contains + reusable "fragments" of regular expression patterns. It's + meant to reduce the number of times one has to code similar + patterns. + * pybot/rss.py: Introduced generic RSS module! It's based on + Mark Pilgrim's "ultra liberal" parser, and allows one + to send news from any RSS feed to any user/channel/server. + 2003-08-24 Gustavo Niemeyer <nie...@co...> * pybot/misc.py,modules/help.py,modules/*: Now regular Index: README =================================================================== RCS file: /cvsroot/pybot/pybot/README,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** README 21 Aug 2003 18:46:27 -0000 1.4 --- README 25 Aug 2003 18:54:54 -0000 1.5 *************** *** 7,24 **** and has since then evolved into a full featured bot. - Requirements - ------------ - - Pybot requires the sqlite (http://sqlite.org) SQL database library, - and its python module (http://pysqlite.sf.net). - - Download - -------- - - Current access to its source is available trough CVS only, in the - sourceforge pybot project: - - http://sourceforge.net/projects/pybot - End user features ----------------- --- 7,10 ---- *************** *** 27,43 **** - may join multiple servers and multiple channels at once (implemented without threads); - full online control (just talk to him); - load, reload and unload modules at runtime; ! - flexible user registry, allowing automatic identification and ! manual identification under different nicks; - very flexible permission system; - full online help; - auto recover from network errors; - - auto timming of messages to avoid being kicked by the server. - lots of additional functionalities through available modules; - even basic functionality is implemented using modules; - random answers, to humanify the bot a little bit; ! - persistence implemented with transparent pickling and sqlite ! database; Developer features --- 13,28 ---- - may join multiple servers and multiple channels at once (implemented without threads); + - remembers last state, even if killed; - full online control (just talk to him); - load, reload and unload modules at runtime; ! - flexible user registry, allowing automatic identification ! and manual identification under different nicks; - very flexible permission system; - full online help; - auto recover from network errors; - lots of additional functionalities through available modules; - even basic functionality is implemented using modules; - random answers, to humanify the bot a little bit; ! - persistence implemented with transparent pickling and sqlite database; Developer features *************** *** 51,54 **** --- 36,53 ---- - user registry allows pluggable meta-data; + Requirements + ------------ + + Pybot requires the sqlite (http://sqlite.org) SQL database library, + and its python module (http://pysqlite.sf.net). + + Download + -------- + + Current access to its source is available trough CVS only, in the + sourceforge pybot project: + + http://sourceforge.net/projects/pybot + Standard modules ---------------- *************** *** 91,94 **** --- 90,98 ---- Allows searching in logs, and checking what was the last time the bot has seen somebody. + + - rss + Generic RSS module. It's based on Mark Pilgrim's "ultra liberal" + parser, and allows one to send news from any RSS feed to any + user/channel/server. - ignore |
From: Gustavo N. <nie...@us...> - 2003-08-25 18:55:17
|
Update of /cvsroot/pybot/pybot/pybot In directory sc8-pr-cvs1:/tmp/cvs-serv10959/pybot Modified Files: locals.py Added Files: refrag.py Log Message: * pybot/rss.py: Introduced generic RSS module! It's based on Mark Pilgrim's "ultra liberal" parser, and allows one to send news from any RSS feed to any user/channel/server. * pybot/refrag.py: Introduced the refrag module. It contains reusable "fragments" of regular expression patterns. It's meant to reduce the number of times one has to code similar patterns. --- NEW FILE: refrag.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 class Fragment: def __init__(self, expr=""): self._expr = expr def expr(self, optional=0): if optional: return self._expr+"?" return self._expr def __str__(self): return self.expr() def __call__(self, *args, **kwargs): return self.expr(*args, **kwargs) def get(self, msg, match): raise TypeError, "this method must be overloaded" class Dont(Fragment): def __init__(self): Fragment.__init__(self, r"(?P<_dont>don'?t\s+|do not\s+)") def get(self, msg, match): return match.group("_dont") dont = Dont() class Interval(Fragment): def __init__(self): Fragment.__init__(self, r"(?:\s+each\s+(?P<_interval>[0-9]+)\s*(?P<_intervalunit>se?c?o?n?d?s?|mi?n?u?t?e?s?|ho?u?r?s?))") def get(self, msg, match, default=None): interval = match.group("_interval") if not interval: if not default: msg.answer("%:", "Internal error: no interval and no default.") return None interval = default[:-1] unit = default[-1] else: unit = match.group("_intervalunit")[0] unitindex = ["s", "m", "h"].index(unit) unitfactor = [1, 60, 3600][unitindex] try: interval = int(interval)*unitfactor if interval == 0: raise ValueError except ValueError: msg.answer("%:", ["Hummm...", "Oops!", "Heh..."], ["This interval is not valid", "There's something wrong with the " "interval you provided"], ["!", "."]) return None return interval interval = Interval() class Target(Fragment): def __init__(self): Fragment.__init__(self) self._expr = r"(?:\s+(?:to|for|on|at|in)\s+(?:(?P<_thischannel>this\s+channel)|(?P<_me>me)|(?:user|channel)\s+(?P<_target>\S+))(?:\s+(?:for|on|at|in)\s+(?:(?P<_thisserver>this\s+server)|server\s+(?P<_server>\S+)))?)" self._expr_onlyserverallowed = r"((?:\s+(?:to|for|on|at|in)\s+(?:(?P<_thischannel>this\s+channel)|(?P<_me>me)|(?:user|channel)\s+(?P<_target>\S+)))?(?:\s+(?:for|on|at|in)\s+(?:(?P<_thisserver>this\s+server)|server\s+(?P<_server>\S+)))?)" def expr(self, optional=0, onlyserverallowed=0): if onlyserverallowed: expr = self._expr_onlyserverallowed else: expr = self._expr if optional: expr += "?" return expr def get(self, msg, match, allowempty=0): target = match.group("_target") or "" if not target and match.group("_thischannel"): target = msg.answertarget server = match.group("_server") or "" if not server and match.group("_thischannel"): target = msg.answertarget if not target and not server and match.group("_me"): target = msg.user.nick server = msg.server.servername elif not allowempty: if not target: target = msg.answertarget if not server: server = msg.server.servername return target, server target = Target() # vim:ts=4:sw=4:et Index: locals.py =================================================================== RCS file: /cvsroot/pybot/pybot/pybot/locals.py,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** locals.py 24 Aug 2003 19:30:53 -0000 1.1 --- locals.py 25 Aug 2003 18:54:54 -0000 1.2 *************** *** 18,21 **** --- 18,22 ---- from pybot import * + from pybot import refrag from pybot.misc import regexp |
From: Gustavo N. <nie...@us...> - 2003-08-25 18:55:12
|
Update of /cvsroot/pybot/pybot/pybot/modules In directory sc8-pr-cvs1:/tmp/cvs-serv10959/pybot/modules Added Files: rss.py Log Message: * pybot/rss.py: Introduced generic RSS module! It's based on Mark Pilgrim's "ultra liberal" parser, and allows one to send news from any RSS feed to any user/channel/server. * pybot/refrag.py: Introduced the refrag module. It contains reusable "fragments" of regular expression patterns. It's meant to reduce the number of times one has to code similar patterns. --- NEW FILE: rss.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.locals import * from pybot.util import feedparser import thread import time HELP = """ You can ask me to show RSS news from any site and for any user/channel and server with "[dont] show (news|rss news) [from] <url> [with link[s]] [with desc[ription][s]] [with prefix "<prefix>"] [each <n>(m|h)] [(on|for) (user|channel) <target>] [(on|at) server <server>]". Notice that after <url> you can use any order, and also that the given interval is the maximum interval. """,""" To check what is being shown and for which targets, you can send me "show rss". You need the "rss" permission to use these commands. """ PERM_RSS = """ The "rss" permission allows you to change what servers and channels will receive RSS news. Check "help rss" for more information. """ # Fetching below 30 minutes is evil MININTERVAL = 30*60 # Maximum number of stored news from each feed CACHELIMIT = 50 # Maxium news to send from a single feed per minute ONETIMELIMIT = 5 class RSS: def __init__(self): db.table("rssfeed", "id integer primary key, " "url unique on conflict ignore, " "lastfetch", triggers=[ "create trigger rssfeed1 after delete on rssfeed" " begin" " delete from rsstarget where feedid=old.id;" " delete from rssitem where feedid=old.id;" " end" ]) db.table("rsstarget", "id integer primary key, " "feedid, servername, target, flags, " "prefix, interval, lastitemid", constraints="unique (feedid, servername, target)", triggers=[ "create trigger rsstarget1 after delete on rsstarget" " begin" " delete from rssfeed where id=old.feedid and" " (select count(feedid) from rsstarget where feedid=old.feedid)==0;" " end" ]) db.table("rssitem", "id integer primary key, feedid, timestamp, " "title, link, description", constraints="unique (feedid, title, link, description)" " on conflict ignore") hooks.register("Message", self.message) # (rss|news|rss news) mm.register_help("news|rss|rss news", HELP, ["rss", "news"]) mm.register_perm("rss", PERM_RSS) mm.hooktimer(60, self.update, ()) # [dont] show (news|rss news) [from] <url> [with link[s]] [with desc[ription][s]] [with prefix "<prefix>"] [each <n>(m|h)] [[on|at|in|for] (user|channel) <target>] [[on|at|in|for] server <server>] self.re1 = regexp(refrag.dont(optional=1), r"show (?:rss news |news )(?:from )?(?P<url>(?:https?|ftp)\S+)" r"(?:" r" with prefix \"(?P<prefix>.*?)\"|" r"(?P<links> with links?)|" r"(?P<descs> with desc(?:ription)?s?)|", refrag.interval(), r"|", refrag.target(), r")*") # show rss [settings] self.re2 = regexp(r"show rss") def unload(self): hooks.unregister("Message", self.message) mm.unhooktimer(60, self.update, ()) mm.unregister_help(HELP) mm.unregister_perm("rss") def update(self): cursor = db.cursor() # Check if we must fetch something cursor.execute("select * from rssfeed") now = int(time.time()) for feed in cursor.fetchall(): lastfetch = int(feed.lastfetch) if now-lastfetch >= MININTERVAL: # Clear old news cursor.execute("delete from rssitem where feedid=%s and " "id not in (select id from rssitem " "where feedid=%s " "order by id desc limit %s)", (feed.id, feed.id, CACHELIMIT)) cursor.execute("select min(interval) from rsstarget where " "feedid=%s", (feed.id,)) row = cursor.fetchone() if row: # Should always be true interval = int(row[0]) if now-lastfetch >= interval: cursor.execute("update rssfeed set lastfetch=%s " "where id=%s", (now, feed.id)) thread.start_new_thread(self.fetch_news, (feed, now)) # Now check if we must show something cursor.execute("select * from rsstarget") for target in cursor.fetchall(): cursor.execute("select * from rssitem where " "id > %s and feedid=%s order by id limit %s", (target.lastitemid, target.feedid, ONETIMELIMIT)) if cursor.rowcount: server = servers.get(target.servername) lastid = None for item in cursor.fetchall(): if target.prefix: text = "%s %s" % (target.prefix, item.title) else: text = item.title if "l" in target.flags: text += " [%s]" % item.link if "d" in target.flags: # item.description() is a method text += " - "+item["description"] server.sendmsg(target.target, None, text, notice=1) lastid = item.id if lastid: # Should always be true cursor.execute("update rsstarget set lastitemid=%s " "where id=%s", (lastid, target.id,)) def fetch_news(self, feed, now): news = feedparser.parse(feed.url) items = news["items"] if items: # Reverse, since top items are usually newer items.reverse() localdb = db.copy() # We're in a thread cursor = localdb.cursor() for item in items: if "title" in item: title = item["title"].strip() link = item.get("link", "").strip() desc = item.get("description", "").strip() cursor.execute("insert into rssitem values " "(NULL, %s, %s, %s, %s, %s)", (feed.id, now, title, link, desc)) def message(self, msg): if not msg.forme: return None m = self.re1.match(msg.line) if m: if mm.hasperm(msg, "rss"): dont = refrag.dont.get(msg, m) target, servername = refrag.target.get(msg, m) interval = refrag.interval.get(msg, m, default="%ds" % MININTERVAL) if interval < MININTERVAL: msg.answer("%:", "That's below the minimum interval", [".", "!"]) return 0 interval = refrag.interval.get(msg, m, default="%ds" % MININTERVAL) url = m.group("url") prefix = m.group("prefix") or "" flags = "" if m.group("links"): flags += "l" if m.group("descs"): flags += "d" cursor = db.cursor() if dont: cursor.execute("delete from rsstarget where " "feedid=(select id from rssfeed where url=%s) " "and servername=%s and target=%s", (url, servername, target)) if not cursor.rowcount: msg.answer("%:", ["Not needed", "It's not needed", "Oops"], [".", "!"], ["I don't know anything about this" " news feed", "This feed is not being shown" " anywhere", "I'm not showing news from that" " feed"], [".", "!"]) else: msg.answer("%:", ["Done", "Ok", "Sure"], [".", "!"]) else: cursor.execute("insert into rssfeed values (NULL, %s, 0)", (url,)) try: cursor.execute("insert into rsstarget values " "(NULL," " (select id from rssfeed where url=%s)," " %s, %s, %s, %s, %s, -1)", (url, servername, target, flags, prefix, interval)) except db.error: msg.answer("%:", ["Not needed", "It's not needed", "Oops"], [".", "!"], ["I'm already showing that feed", "This feed is already being shown", "I'm already showing news from that" " feed"], [".", "!"]) else: msg.answer("%:", ["Done", "Ok", "Sure"], [".", "!"]) else: msg.answer("%:", ["You can't", "You're not allowed to", "You're not good enough to"], ["do this", "change rss settings"], [".", "!"]) return 0 m = self.re2.match(msg.line) if m: if mm.hasperm(msg, "rss"): cursor = db.cursor() cursor.execute("select * from rssfeed") if not cursor.rowcount: msg.answer("%:", ["No rss feeds are being shown", "There are no rss feeds being shown", "No feeds registered"], [".", "!"]) return 0 msg.answer("%:", "The following feeds are being shown:") for feed in cursor.fetchall(): msg.answer("-", feed.url) cursor.execute("select * from rsstarget where feedid=%s", (feed.id,)) for target in cursor.fetchall(): links, descs, prefix = "", "", "" if "l" in target.flags: links = "with links" if "d" in target.flags: descs = "with descriptions" if target.prefix: prefix = "with prefix \"%s\"" % target.prefix target.interval = int(target.interval) if target.interval % (60*60) == 0: i = target.interval/(60*60) s = (i > 0) and "s" or "" interval = "%d hour%s" % (i, s) elif target.interval % 60 == 0: interval = "%d minutes" % (target.interval/60) else: interval = "%d seconds" % target.interval msg.answer(" for", target.target, "on", target.servername, "each", interval, links, descs, prefix) else: msg.answer("%:", ["You can't", "You're not allowed to", "You're not good enough to"], ["do this", "change rss settings"], ["!", "."]) return 0 def __loadmodule__(): global mod mod = RSS() def __unloadmodule__(): global mod mod.unload() del mod # vim:ts=4:sw=4:et |