(large commit, see bazaar log)

[Bantracker]
 * Less spaces in README.txt
 * Remove mention of table 'users' in README.txt
 * Add more detail on how to create the bans database in README.txt
 * Add note about supybot-wizard creating the initial database in README.txt
 * Don't hard-code default values in config.py:configure()
 * Tweak config.py
 * Clean up bans.cgi a bit

[Bugtracker]
 * Comment-out obsolete "bug reporting" variables in config.py
 * Update README.txt and remove "bug reporting" stuff, also remove extraneous license info
 * Comment-out obsolete "bug reporting" code
 * Don't import imaplib

[Encyclopedia]
 * Don't hard-code default values in config.py:configure()
 * Check for 'owner' capability before checking if the hostmask is ignored in plugin.py:checkIgnored()
 * Clean up README.txt

[PackageInfo]
 * Don't hard-code default values in config.py:configure()
 * Update default distributions in config.py:configure()
 * Update defaultRelease in config.py 
 * Update README.txt

* Add a few docstrings to commoncgi.py
* Update COPYING
* Update README.txt
This commit is contained in:
Terence Simpson 2011-05-28 07:33:21 +01:00
parent 6fe55f7eb1
commit fd36bffcc0
16 changed files with 269 additions and 294 deletions

View File

@ -9,7 +9,7 @@ kick/ban someone.
It also uses commoncgi.py which should be on your sys.path (or as you can see in
the script, sys.path is modified to include the dir of commoncgi.py)
The schema of the sqlite database:
The schema of the SQLite2 database:
CREATE TABLE bans (
id INTEGER PRIMARY KEY,
@ -32,12 +32,12 @@ CREATE TABLE sessions (
user MEDIUMTEXT NOT NULL,
time INT NOT NULL
);
CREATE TABLE users (
username VARCHAR(50) PRIMARY KEY,
salt VARCHAR(8),
password VARCHAR(50)
);
To configure the plugin, create the sqlite database with above structure and set
supybot.plugins.bantracker.database to its filename. Then enable it per channel
by setting the channel variable supybot.plugins.bantracker.enabled
To configure the plugin, create the SQLite2 database with above structure and
set supybot.plugins.bantracker.database to its filename. Then enable it, either
per-channel or globally, by setting the channel variable:
supybot.plugins.bantracker.enabled
You can create the database by using the "sqlite" command-line tool by passing
the file name and then copy/paste the above table schema.
If you choose to enable this plugin during the initial setup (with the command
supybot-wizard), then the database will be created automatically for you.

View File

@ -31,7 +31,8 @@ user = None
# Delete old sessions
try:
cur.execute("""DELETE FROM sessions WHERE time < %d""", int(time.time()) - 2592000 * 3)
session_timeout = int(time.time()) - (2592000 * 3)
cur.execute('DELETE FROM sessions WHERE time < %d', (session_timeout,))
except:
pass
@ -41,7 +42,7 @@ if form.has_key('sess'):
if cookie.has_key('sess'):
try:
sess = cookie['sess'].value
cur.execute("""SELECT user FROM sessions WHERE session_id=%s""",sess)
cur.execute('SELECT user FROM sessions WHERE session_id=%s',(sess,))
user = cur.fetchall()[0][0]
except:
con.commit()
@ -54,7 +55,7 @@ if not user:
# Log
if form.has_key('log'):
cur.execute("""SELECT log FROM bans WHERE id=%s""", form['log'].value)
cur.execute('SELECT log FROM bans WHERE id=%s', (form['log'].value,))
log = cur.fetchall()
con.commit()
if form.has_key('mark'):
@ -72,10 +73,10 @@ if form.has_key('log'):
# Main page
# Process comments
if form.has_key('comment') and form.has_key('comment_id') and user:
cur.execute("""SELECT ban_id FROM comments WHERE ban_id=%s and comment=%s""", (form['comment_id'].value, form['comment'].value))
cur.execute('SELECT ban_id FROM comments WHERE ban_id=%s and comment=%s', (form['comment_id'].value, form['comment'].value))
comm = cur.fetchall()
if not len(comm):
cur.execute("""INSERT INTO comments (ban_id, who, comment, time) VALUES (%s, %s, %s, %s)""",
cur.execute('INSERT INTO comments (ban_id, who, comment, time) VALUES (%s, %s, %s, %s)',
(form['comment_id'].value,user,form['comment'].value,pickle.dumps(datetime.datetime.now(pytz.UTC))))
con.commit()
@ -178,10 +179,10 @@ print '<th>Log</th></tr>'
# Select and filter bans
def getBans(id=None):
if id == None:
cur.execute("SELECT channel,mask,operator,time,removal,removal_op,id FROM bans ORDER BY id DESC")
if id is None:
cur.execute('SELECT channel,mask,operator,time,removal,removal_op,id FROM bans ORDER BY id DESC')
else:
cur.execute("SELECT channel,mask,operator,time,removal,removal_op,id FROM bans ORDER BY id DESC WHERE id = %d", id)
cur.execute('SELECT channel,mask,operator,time,removal,removal_op,id FROM bans ORDER BY id DESC WHERE id = %d', (id,))
return cur.fetchall()
def myfilter(item, regex, kick, ban, oldban, mute, oldmute, floods, operator, channel):
@ -302,7 +303,7 @@ for b in bans[start:end]:
print ' class="bg2"'
print '>'
print '<td colspan="5" class="comment">'
cur.execute("""SELECT who, comment, time FROM comments WHERE ban_id = %s""" % b[6])
cur.execute('SELECT who, comment, time FROM comments WHERE ban_id = %d', (b[6],))
comments = cur.fetchall()
if len(comments) == 0:
print '<span class="removal">(No comments) </span>'

View File

@ -1,7 +1,7 @@
# -*- Encoding: utf-8 -*-
###
# Copyright (c) 2005-2007 Dennis Kaarsemaker
# Copyright (c) 2008-2010 Terence Simpson
# Copyright (c) 2008-2011 Terence Simpson
# Copyright (c) 2010 Elián Hanisch
#
# This program is free software; you can redistribute it and/or modify
@ -55,9 +55,10 @@ def configure(advanced):
else:
return review
output("If you choose not to enabled Bantracker for all channels, it can be enabled per-channel with the '@Config channel' command")
enabled = yn("Enable Bantracker for all channels?")
database = something("Location of the Bantracker database", default=conf.supybot.directories.data.dirize('bans.db'))
bansite = anything("URL of the Bantracker web interface, without the 'bans.cgi'. (leave this blank if you don't want to run a web server)")
database = something("Location of the Bantracker database", default=Bantracker.database._default)
bansite = anything("URL of the Bantracker web interface, without the 'bans.cgi'. (leave this blank if you aren't running a web server)")
request = yn("Enable review and comment requests from bot?", default=False)
if request and advanced:
@ -67,29 +68,31 @@ def configure(advanced):
type = set([])
for name in re.split(r',?\s+', types):
name = name.lower()
if name in ('removal', 'ban', 'quiet'):
if name in ValidTypes.validStrings:
type.add(name)
output("Which nicks should be bot not requets comments from?")
output("Is case insensitive and wildcards '*' and '?' are accepted.")
ignores = anything("Separate types by spaces or commas:", default=', '.join(Bantracker.request.ignore._default))
output("This is useful if you have automated channel bots that should not be directly asked for reviews")
output("Is case-insensitive and the wildcards '*' and '?' are accepted.")
ignores = anything("Separate nicks by spaces or commas:", default=', '.join(Bantracker.request.ignore._default))
ignore = set([])
for name in re.split(r',?\s+', ignores):
name = name.lower()
ignore.add(name)
output("You can set the comment and review requests for some nicks to be forwarded to specific nicks/channels")
output("This is useful if you have automated channel bots that should not be directly asked for reviews")
output("Which nicks should these requests be forwarded for?")
output("Is case insensitive and wildcards '*' and '?' are accepted.")
forwards = anything("Separate types by spaces or commas:", default=', '.join(Bantracker.request.forward._default))
output("Is case-insensitive and the wildcards '*' and '?' are accepted.")
forwards = anything("Separate nicks by spaces or commas:", default=', '.join(Bantracker.request.forward._default))
forward = set([])
for name in re.split(r',?\s+', forwards):
name = name.lower()
forward.add(name)
output("Which nicks/channels should the requests be forwarded to?")
output("Is case insensitive and wildcards '*' and '?' are accepted.")
channels_i = anything("Separate types by spaces or commas:", default=', '.join(Bantracker.request.forward._default))
output("Which nicks/channels should those requests be forwarded to?")
output("Is case-insensitive and wildcards '*' and '?' are accepted.")
channels_i = anything("Separate nicks/channels by spaces or commas:", default=', '.join(Bantracker.request.forward._default))
channels = set([])
for name in re.split(r',?\s+', channels_i):
name = name.lower()
@ -122,6 +125,7 @@ def configure(advanced):
Bantracker.database.setValue(db_file)
if os.path.exists(db_file):
output("%r already exists" % db_file)
return
output("Creating an initial database in %r" % db_file)
@ -154,13 +158,6 @@ def configure(advanced):
user MEDIUMTEXT NOT NULL,
time INT NOT NULL
)""")
#"""
cur.execute("""CREATE TABLE users (
username VARCHAR(50) PRIMARY KEY,
salt VARCHAR(8),
password VARCHAR(50)
)""")
#"""
except:
@ -176,7 +173,7 @@ Bantracker = conf.registerPlugin('Bantracker')
conf.registerChannelValue(Bantracker, 'enabled',
registry.Boolean(False, """Enable the bantracker"""))
conf.registerGlobalValue(Bantracker, 'database',
registry.String('', "Filename of the bans database", private=True))
registry.String(conf.supybot.directories.data.dirize('bans.db'), "Filename of the bans database", private=True))
conf.registerGlobalValue(Bantracker, 'bansite',
registry.String('', "Web site for the bantracker, without the 'bans.cgi' appended", private=True))

View File

@ -1,17 +1,8 @@
Copyright (c) 2005-2007, Dennis Kaarsemaker
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as
published by the Free Software Foundation.
This program 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.
Bug information reporting plugin, works with many well-known bugtrackers.
The syntax to add a tracker is weird, here are some examples:
@bugtracker add freedesktop bugzilla https://bugs.freedesktop.org Freedesktop
@bugtracker add malone malone https://launchpad.net/malone Malone
@bugtracker add launchpad launchpad https://launchpad.net/malone Launchpad
@bugtracker add debian debbugs http://bugs.debian.org Debian
@bugtracker add openoffice issuezilla http://www.openoffice.org/issues OpenOffice
@bugtracker add django trac http://code.djangoproject.com/ticket Django
@ -21,21 +12,23 @@ In general: @bugtracker add <name> <type> <baseurl> [description]
Bugtracker dialects (types) this plugin understands:
* Bugzilla
* Issuezilla (OpenOffice.org's tjernobyl transformation of bugzilla)
* Malone
* Launchpad (Including Ubuntu)
* Debbugs (debbugs sucks donkeyballs - please fix debbugs)
* Trac (with not-too-buggered-up templates, it needs to do screenscraping)
* Sourceforge (needs atid and group_id in the url!)
* Trac
* WikiForms (see bugs.gnewsense.org for an example)
* str.php from the CUPS project
* Mantis (http://www.mantisbt.org)
A notable exception is Sourceforge. Unfortunatly, it has no API or data export
feature to output bug information in a well-formed way.
To request a bug report, use this syntax:
bug 123
bug #123
supybot bug 123
launchpad bug 123
bug 123, 4, 5
bug 1, 3 and 89
bugs 1, 3 and 89
To rename a bugtracker:
@bugtracker rename old-name new-name
@ -45,47 +38,3 @@ existing tracker.
The bug snarfing (responding to bug numbers/urls) will only work in channels
where supybot.plugins.bugtracker.bugsnarfer is True.
Automatic reporting of new bugs is also possible for Malone (the launchpad
bugtracker). Enabling this is not a trivial process. First step is to set the
supybot.plugins.bugtracker.reportercache variable to a dir for this purpose. You
also need a mail account that supports the + hack (mail for foo+bar@baz.com is
automatically delivered to foo@baz.com while the Delivered-To: header is set to
foo+bar@baz.com) which is accessible via IMAP. I know this is a rather strong
requirement, but that's the way it works now. Patches to make it work in other
situations are appreciated.
Anyway, once that is all set up you're almost there. Let's assume the
mailaddress is bugreporter@yourdomain.com. Now pick a tag for your bugreports,
e.g. ubuntu (you can set a different tag per channel) and create a launchpad
account with address bugreporter+ubuntu@yourdomain.com. Activate that account
and make sure it gets bugmail for the product(s) you want to monitor.
Now set the supybot.plugins.bugtracker.bugreporter in the channels where bugs
are to be reported to the value of the tag for bugs to be reported there and
watch bugs flowing in.
To prevent old bugs from showing up when they change or a comment is being
added, you can manually fill the cache. Just touch files in the reporters cache
with the following name:
tag_here/malone/NN/MMMM where NN is int(bugid/1000) and MMMM is the bugid.
If your products already have many bugreports, consider doing some
screenscraping with the malone searchpages and sed/awk :)
A quick hack I use to get all launchpad bugids preseeded:
cd /home/ubugtu/data/bugmail # This is my cachedir
cd launchpad # This is the tag
mkdir malone
product=launchpad
amount=2000 # 2000 is the amount of bugs, chck this on
# launchpad under all bugs ever reported
# Download a summary of all bugs
for x in `seq 0 75 $amount`; do
wget "https://bugs.launchpad.net/$product/+bugs?search=Search&field.status=Unconfirmed&field.status=Confirmed&field.status=In+Progress&field.status=Needs+Info&field.status=Fix+Committed&field.status=Fix+Released&field.status=Rejected&field.omit_dupes.used=&start=$x" -O $x;
done
grep -h =.amount * | sed -e 's/.*>\(.*\)<.*/\1/' | awk '{print "malone/" int($1/1000)}' | sort -u | xargs mkdir -p
grep -h =.amount * | sed -e 's/.*>\(.*\)<.*/\1/' | awk '{print "malone/" int($1/1000) "/" $1}' | xargs -n100 touch

View File

@ -1,7 +1,7 @@
# -*- Encoding: utf-8 -*-
###
# Copyright (c) 2005-2007 Dennis Kaarsemaker
# Copyright (c) 2008-2010 Terence Simpson
# Copyright (c) 2008-2011 Terence Simpson
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
@ -45,13 +45,14 @@ def configure(advanced):
else:
return repeatdelay
output("Each of the next 3 questions can be set per-channel with the '@Config channel' command")
bugSnarfer = yn("Enable detecting bugs numbers and URL in all channels?", default=Bugtracker.bugSnarfer._default)
cveSnarfer = yn("Enable detecting CVE numbers and URL in all channels?", default=Bugtracker.cveSnarfer._default)
oopsSnarfer = yn("Enable detecting Launchpad OOPS IDs in all channels?", default=Bugtracker.oopsSnarfer._default)
if advanced:
replyNoBugtracker = something("What should the bot reply with when a a user requests information from an unknown bug tracker?", default=Bugtracker.replyNoBugtracker._default)
snarfTarget = something("What should be the default bug tracker used when one isn't specified?", default=Bugtracker.snarfTarget._default)
replyWhenNotFound = yn("Respond when a bug is not found?", default=Bugtracker.replyWhenNotFound._default)
replyWhenNotFound = yn("Should the bot report when a bug is not found?", default=Bugtracker.replyWhenNotFound._default)
repeatdelay = getRepeatdelay()
else:
replyNoBugtracker = Bugtracker.replyNoBugtracker._default
@ -89,8 +90,8 @@ conf.registerChannelValue(Bugtracker, 'oopsSnarfer',
enabled, such that any OOPS ### seen in the channel
will have their information reported into the channel."""))
conf.registerChannelValue(Bugtracker, 'bugReporter',
registry.String('', """Report new bugs (experimental)"""))
#conf.registerChannelValue(Bugtracker, 'bugReporter',
# registry.String('', """Report new bugs (experimental)"""))
conf.registerChannelValue(Bugtracker, 'replyNoBugtracker',
registry.String('I don\'t have a bugtracker %s.', """Determines the phrase
@ -98,7 +99,7 @@ conf.registerChannelValue(Bugtracker, 'replyNoBugtracker',
bugtracker site."""))
conf.registerChannelValue(Bugtracker, 'snarfTarget',
registry.String('lp', """Determines the bugtracker to query when the
registry.String('launchpad', """Determines the bugtracker to query when the
snarf command is triggered"""))
conf.registerGlobalValue(Bugtracker, 'bugtrackers',
@ -117,18 +118,18 @@ conf.registerChannelValue(Bugtracker, 'showassignee',
conf.registerChannelValue(Bugtracker, 'extended',
registry.Boolean(False, "Show optional extneded bug information, specific to trackers"))
conf.registerGlobalValue(Bugtracker, 'reportercache',
registry.String('', """Name of the basedir for the bugreporter cache""", private=True))
#conf.registerGlobalValue(Bugtracker, 'reportercache',
# registry.String('', """Name of the basedir for the bugreporter cache""", private=True))
conf.registerGlobalValue(Bugtracker, 'imap_server',
registry.String('', """IMAP server for bugmail account""",private=True))
#conf.registerGlobalValue(Bugtracker, 'imap_server',
# registry.String('', """IMAP server for bugmail account""",private=True))
conf.registerGlobalValue(Bugtracker, 'imap_user',
registry.String('', """IMAP user for bugmail account""", private=True))
#conf.registerGlobalValue(Bugtracker, 'imap_user',
# registry.String('', """IMAP user for bugmail account""", private=True))
conf.registerGlobalValue(Bugtracker, 'imap_password',
registry.String('', """IMAP password for bugmail account""", private=True))
#conf.registerGlobalValue(Bugtracker, 'imap_password',
# registry.String('', """IMAP password for bugmail account""", private=True))
conf.registerGlobalValue(Bugtracker, 'imap_ssl',
registry.Boolean(False, """Use SSL for imap connections""", private=True))
#conf.registerGlobalValue(Bugtracker, 'imap_ssl',
# registry.Boolean(False, """Use SSL for imap connections""", private=True))

View File

@ -24,13 +24,15 @@ import supybot.registry as registry
import supybot.schedule as schedule
import supybot.log as supylog
import re, os, time, imaplib, commands
#import imaplib
import re, os, time, commands
import xml.dom.minidom as minidom
from htmlentitydefs import entitydefs as entities
import email.FeedParser
import SOAPpy
bad_words = ["fuck","fuk","fucking","fuking","fukin","fuckin","fucked","fuked","fucker","shit","cunt","bastard","nazi","nigger","nigga","cock","bitches","bitch"]
# All the words below will be censored when reporting bug information
bad_words = set(["fuck","fuk","fucking","fuking","fukin","fuckin","fucked","fuked","fucker","shit","cunt","bastard","nazi","nigger","nigga","cock","bitches","bitch"])
def makeClean(s):
words = s.split()
@ -95,7 +97,7 @@ class Bugtracker(callbacks.PluginRegexp):
def __init__(self, irc):
callbacks.PluginRegexp.__init__(self, irc)
self.db = ircutils.IrcDict()
events = []
# self.events = []
for name in self.registryValue('bugtrackers'):
registerBugtracker(name)
group = self.registryValue('bugtrackers.%s' % name.replace('.','\\.'), value=False)
@ -104,27 +106,28 @@ class Bugtracker(callbacks.PluginRegexp):
else:
self.log.warning("Bugtracker: Unknown trackertype: %s (%s)" % (group.trackertype(), name))
self.shorthand = utils.abbrev(self.db.keys())
# Schedule bug reporting
self.shown = {}
#TODO: Remove everything below this line
if self.registryValue('imap_server') and self.registryValue('reportercache'):
try:
schedule.removeEvent(self.name() + '.bugreporter')
except:
pass
schedule.addPeriodicEvent(lambda: self.reportnewbugs(irc), 60, name=self.name() + '.bugreporter')
self.events += [self.name() + '.bugreporter']
self.log.info('Bugtracker: Adding scheduled event "%s.bugreporter"' % self.name())
# # Schedule bug reporting
# #TODO: Remove everything below this line
# if self.registryValue('imap_server') and self.registryValue('reportercache'):
# try:
# schedule.removeEvent(self.name() + '.bugreporter')
# except:
# pass
# schedule.addPeriodicEvent(lambda: self.reportnewbugs(irc), 60, name=self.name() + '.bugreporter')
# self.events += [self.name() + '.bugreporter']
# self.log.info('Bugtracker: Adding scheduled event "%s.bugreporter"' % self.name())
def die(self): #TODO: Remove me
try:
for event in self.events:
self.log.info('Bugtracker: Removing scheduled event "%s"' % event)
schedule.removeEvent(event)
schedule.removeEvent(self.name())
except:
pass
# try:
# for event in self.events:
# self.log.info('Bugtracker: Removing scheduled event "%s"' % event)
# schedule.removeEvent(event)
# schedule.removeEvent(self.name())
# except:
# pass
def is_ok(self, channel, tracker, bug):
'''Flood/repeat protection'''
@ -138,95 +141,97 @@ class Bugtracker(callbacks.PluginRegexp):
return False
def is_new(self, tracker, tag, id): #Depricated
bugreporter_base = self.registryValue('reportercache')
if not os.path.exists(os.path.join(bugreporter_base,tag,tracker.name,str(int(id/1000)),str(id))):
try:
os.makedirs(os.path.join(bugreporter_base,tag,tracker.name,str(int(id/1000))))
except:
pass
fd = open(os.path.join(bugreporter_base,tag,tracker.name,str(int(id/1000)),str(id)),'w')
fd.close()
return True
return False
# bugreporter_base = self.registryValue('reportercache')
# if not os.path.exists(os.path.join(bugreporter_base,tag,tracker.name,str(int(id/1000)),str(id))):
# try:
# os.makedirs(os.path.join(bugreporter_base,tag,tracker.name,str(int(id/1000))))
# except:
# pass
# fd = open(os.path.join(bugreporter_base,tag,tracker.name,str(int(id/1000)),str(id)),'w')
# fd.close()
# return True
# return False
def reportnewbugs(self,irc): #Depricated
# Compile list of bugs
self.log.info("Bugtracker: Checking for new bugs")
bugs = {}
if self.registryValue('imap_ssl'):
sc = imaplib.IMAP4_SSL(self.registryValue('imap_server'))
else:
sc = imaplib.IMAP4(self.registryValue('imap_server'))
sc.login(self.registryValue('imap_user'), self.registryValue('imap_password'))
sc.select('INBOX')
new_mail = sc.search(None, '(UNSEEN)')[1][0].split()[:20]
# Read all new mail
for m in new_mail:
msg = sc.fetch(m, 'RFC822')[1][0][1]
fp = email.FeedParser.FeedParser()
sc.store(m, '+FLAGS', "(\Deleted)") # Mark message deleted so we don't have to process it again
fp.feed(msg)
bug = fp.close()
tag = None
if 'X-Launchpad-Bug' not in bug.keys():
self.log.info('Bugtracker: Ignoring e-mail with no detectable bug (Not from Launchpad)')
continue
else:
tag = bug['X-Launchpad-Bug']
if 'distribution=' not in tag and 'product=' not in tag:
self.log.info('Bugtracker: Ignoring e-mail with no detectable bug (no distro/product)')
continue
else:
tag = tag.split(';')[0].strip().replace("product=",'').replace("distribution=","")
if not tag:
self.log.info('Bugtracker: Ignoring e-mail with no detectible bug (bad tag)')
tag = tag[tag.find('+')+1:tag.find('@')]
if tag not in bugs:
bugs[tag] = {}
# Determine bugtracker type (currently only Launchpad is supported anyway)
if bug['X-Launchpad-Bug']:
tracker = self.db['launchpad']
id = int(bug['Reply-To'].split()[1])
subj = bug['Subject'];
if '[NEW]' not in subj: #Not a new bug
continue
if self.is_new(tracker, tag, id):
component = bug['X-Launchpad-Bug']
if 'component' in component:
component = component[component.find('component=')+10:]
component = component[:component.find(';')].replace('None','')
else:
component = ''
try:
if component:
bugs[tag][id] = self.get_bug('',tracker, id, False)[0].replace('"','(%s) "' % component, 1)
else:
bugs[tag][id] = self.get_bug('',tracker, id, False)[0]
if '[apport]' in bugs[tag][id]:
bugs[tag].pop(id)
except:
self.log.info("Bugtracker: Unable to get new bug %d" % id)
pass
else:
self.log.info('Bugtracker: Ignoring e-mail with no detectable bug')
reported_bugs = 0
for c in irc.state.channels:
tags = self.registryValue('bugReporter', channel=c)
if not tags:
continue
for tag in tags.split(','):
if not tag or tag not in bugs.keys():
continue
for b in sorted(bugs[tag].keys()):
irc.queueMsg(ircmsgs.privmsg(c,'New bug: #%s' % bugs[tag][b][bugs[tag][b].find('bug ')+4:]))
reported_bugs = reported_bugs+1
# # Compile list of bugs
# self.log.info("Bugtracker: Checking for new bugs")
# bugs = {}
# if self.registryValue('imap_ssl'):
# sc = imaplib.IMAP4_SSL(self.registryValue('imap_server'))
# else:
# sc = imaplib.IMAP4(self.registryValue('imap_server'))
# sc.login(self.registryValue('imap_user'), self.registryValue('imap_password'))
# sc.select('INBOX')
# new_mail = sc.search(None, '(UNSEEN)')[1][0].split()[:20]
#
# # Read all new mail
# for m in new_mail:
# msg = sc.fetch(m, 'RFC822')[1][0][1]
# fp = email.FeedParser.FeedParser()
# sc.store(m, '+FLAGS', "(\Deleted)") # Mark message deleted so we don't have to process it again
# fp.feed(msg)
# bug = fp.close()
# tag = None
#
# if 'X-Launchpad-Bug' not in bug.keys():
# self.log.info('Bugtracker: Ignoring e-mail with no detectable bug (Not from Launchpad)')
# continue
# else:
# tag = bug['X-Launchpad-Bug']
# if 'distribution=' not in tag and 'product=' not in tag:
# self.log.info('Bugtracker: Ignoring e-mail with no detectable bug (no distro/product)')
# continue
# else:
# tag = tag.split(';')[0].strip().replace("product=",'').replace("distribution=","")
#
# if not tag:
# self.log.info('Bugtracker: Ignoring e-mail with no detectible bug (bad tag)')
#
# tag = tag[tag.find('+')+1:tag.find('@')]
# if tag not in bugs:
# bugs[tag] = {}
#
# # Determine bugtracker type (currently only Launchpad is supported anyway)
# if bug['X-Launchpad-Bug']:
# tracker = self.db['launchpad']
# id = int(bug['Reply-To'].split()[1])
# subj = bug['Subject'];
# if '[NEW]' not in subj: #Not a new bug
# continue
# if self.is_new(tracker, tag, id):
# component = bug['X-Launchpad-Bug']
# if 'component' in component:
# component = component[component.find('component=')+10:]
# component = component[:component.find(';')].replace('None','')
# else:
# component = ''
# try:
# if component:
# bugs[tag][id] = self.get_bug('',tracker, id, False)[0].replace('"','(%s) "' % component, 1)
# else:
# bugs[tag][id] = self.get_bug('',tracker, id, False)[0]
# if '[apport]' in bugs[tag][id]:
# bugs[tag].pop(id)
# except:
# self.log.info("Bugtracker: Unable to get new bug %d" % id)
# pass
# else:
# self.log.info('Bugtracker: Ignoring e-mail with no detectable bug')
#
# reported_bugs = 0
#
# for c in irc.state.channels:
# tags = self.registryValue('bugReporter', channel=c)
# if not tags:
# continue
# for tag in tags.split(','):
# if not tag or tag not in bugs.keys():
# continue
# for b in sorted(bugs[tag].keys()):
# irc.queueMsg(ircmsgs.privmsg(c,'New bug: #%s' % bugs[tag][b][bugs[tag][b].find('bug ')+4:]))
# reported_bugs = reported_bugs+1
def add(self, irc, msg, args, name, trackertype, url, description):
"""<name> <type> <url> [<description>]
@ -359,18 +364,18 @@ class Bugtracker(callbacks.PluginRegexp):
msg.tag('nbugs', nbugs + len(bugids))
bt = map(lambda x: x.lower(), match.group('bt').split())
# Strip off trailing ':' from the tracker name. Allows for (LP: #nnnnnn)
if len(bt) and bt[0].endswith(':'):
if bt and bt[0].endswith(':'):
bt[0] = bt[:-1]
name = ''
if len(bt) == 1 and not (bt[0] in ['bug','bugs']):
try:
name = bt[0].lower()
name = bt[0]
tracker = self.db[name]
except:
return
elif len(bt) == 2:
try:
name = bt[0].lower()
name = bt[0]
tracker = self.db[name]
except:
name = ''

10
COPYING
View File

@ -1,10 +1,10 @@
Most of the code in this package is licensed under the GNU GPL Version 2,
the exception is the Lart plugin, which has a BSD-style license.
See Lart/__init__.py for the license.
Unless otherwise specified, the code in this package is licensed under the
GNU GPL Version 2 license, Refer to each of the files in plugin directories
for specifics.
NOTE! The GPL below is copyrighted by the Free Software Foundation, but
the instance of code that it refers to (the kde programs) are copyrighted
by the authors who actually wrote it.
the instance of code that it refers to (the plugins) are copyrighted
by the authors who actually wrote them.
---------------------------------------------------------------------------

View File

@ -1,23 +1,16 @@
Copyright (c) 2006-2007, Dennis Kaarsemaker
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as
published by the Free Software Foundation.
This program 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.
This plugin used to have package lookup, this was mooved to the PackageInfo
plugin.
Factoid plugin
Note: This plugin used to have package lookup, this was mooved to the
PackageInfo plugin.
Pick a name for your database. A lowercase-only name without spaces is probably
best, this example wil use myfactoids as name. Then create a directory to store
your databases in (somewere in $botdir/data would be best). In the new directory
create an sqlite database with the following command:
your databases in (somewere in $botdir/data would be best).
If you choose to enable this plugin during supybot-wizard the database will be
created for you. If noy, you can create the database manually.
In the new directory create an SQLite2 database with the following command:
sqlite myfactoids.db
Then copy/paste in the below 2 tables:
CREATE TABLE facts (
id INTEGER PRIMARY KEY,
@ -36,6 +29,7 @@ CREATE TABLE log (
oldvalue VARCHAR(200) NOT NULL
);
If you want to create more databases, repeat these last two steps.
When the databases exist, you need to configure the bots to actually use them.
@ -44,9 +38,10 @@ dirand the channel value supybot.plugins.encyclopedia.database to the name of
the database (without the .db suffix).
Documentation on adding/editing factoids can be found on
https://wiki.ubuntu.com/UbuntuBots To give people edit access, let them register
with your bot and use: %addeditor nickname_here (replace % with your prefix
char). Similarly you can use removeeditor :).
https://ubottu.com/devel/wiki/Plugins#Encyclopedia
To give people edit access, let them register with your bot and use the command:
@addeditor nickname_here
(replace @ with your prefix char). Similarly you can use removeeditor :).
The web interface is a simple cgi script with some templates, css and the
commoncgi.py file from the bzr tree. Make sure you set the variables datadir and

View File

@ -105,12 +105,12 @@ def configure(advanced):
db_file = Encyclopedia.database()
if not db_dir:
db_dir = conf.supybot.directories.data()
db_dir = Encyclopedia.datadir._default
output("supybot.plugins.Encyclopedia.datadir will be set to %r" % db_dir)
Encyclopedia.datadir.setValue(db_dir)
if not db_file:
db_file = 'ubuntu'
db_file = Encyclopedia.database._default
output("supybot.plugins.Encyclopedia.database will be set to %r" % db_file)
Encyclopedia.database.setValue(db_dir)

View File

@ -31,13 +31,14 @@ else:
import sre as re
def checkIgnored(hostmask, recipient='', users=ircdb.users, channels=ircdb.channels):
if ircdb.ignores.checkIgnored(hostmask):
return True
try:
id = ircdb.users.getUserId(hostmask)
user = users.getUser(id)
except KeyError:
# If there's no user...
if ircdb.ignores.checkIgnored(hostmask):
return True
if ircutils.isChannel(recipient):
channel = channels.getChannel(recipient)
if channel.checkIgnored(hostmask):
@ -46,9 +47,13 @@ def checkIgnored(hostmask, recipient='', users=ircdb.users, channels=ircdb.chann
return False
else:
return False
if user._checkCapability('owner'):
# Owners shouldn't ever be ignored.
return False
if ircdb.ignores.checkIgnored(hostmask):
return True
elif user.ignore:
return True
elif recipient:

View File

@ -1,22 +1,26 @@
This plugin allows package lookup via apt-cache/apt-file
If you choose to enable this plugin from the supybot-wizard command, then most
of the setup will be automatically done for you. You may still change the values
of the settings manaually.
--Setup--
supybot.plugins.PackageInfo.aptdir:
Directory to use to store the apt cache (Global)
Default: ''
Default: '$BOTDIR/data/aptdir'
Create a new empty directory that will be used for the apt cache.
In this directory, you create sources.list files for every release you
want to search. The name of the file is important, since the filename (without
the .list suffix) is the name that is used to refer to the release.
The .list file should contain _both_ the deb and deb-src source lines.
Eg:
deb http://archive.ubuntu.com/ubuntu jaunty main restricted universe multiverse
deb-src http://archive.ubuntu.com/ubuntu jaunty main restricted universe multiverse
Eg; in lucid.list:
deb http://archive.ubuntu.com/ubuntu ludid main restricted universe multiverse
deb-src http://archive.ubuntu.com/ubuntu lucid main restricted universe multiverse
supybot.plugins.PackageInfo.defaultRelease:
Set this to the default release to use when none is specified. (Channel)
Default: ''
Default: 'lucid'
Whenever you create a new .list file, it is important to run the update_apt
and update_apt_file scripts that comes with this plugin. Before you run these,

View File

@ -43,17 +43,17 @@ deb-src http://archive.ubuntu.com/ubuntu/ %s main restricted universe multiverse
if enabled and advanced:
prefixchar = something("Which prefix character should be bot respond to?", default=PackageInfo.prefixchar._default)
defaultRelease = something("What should be the default distrobution when not specified?", default=PackageInfo.defaultRelease._default)
aptdir = something("Which directory should be used for the apt cache when looking up packages?", default=conf.supybot.directories.data.dirize('aptdir'))
aptdir = something("Which directory should be used for the apt cache when looking up packages?", default=PackageInfo.aptdir._default)
# People tend to thing this should be /var/cache/apt
while aptdir.startswith('/var'):
while aptdir.startswith('/var'): #NOTE: This is not a good hack. Maybe just blacklist /var/cache/apt (or use apt to report back the cache dir)
output("NO! Do not use your systems apt directory")
aptdir = something("Which directory should be used for the apt cache when looking up packages?", default=conf.supybot.directories.data.dirize('aptdir'))
aptdir = something("Which directory should be used for the apt cache when looking up packages?", default=PackageInfo.aptdir._default)
else:
prefixchar = PackageInfo.prefixchar._default
defaultRelease = PackageInfo.defaultRelease._default
aptdir = conf.supybot.directories.data.dirize('aptdir')
aptdir = PackageInfo.aptdir._default
PackageInfo.enabled.setValue(enabled)
@ -61,7 +61,7 @@ deb-src http://archive.ubuntu.com/ubuntu/ %s main restricted universe multiverse
PackageInfo.prefixchar.setValue(prefixchar)
PackageInfo.defaultRelease.setValue(defaultRelease)
default_dists = set(['hardy', 'jaunty', 'karmic', 'lucid', 'maveric'])
default_dists = set(['dapper', 'hardy', 'lucid', 'maveric', 'natty', 'oneiric'])
pluginDir = os.path.abspath(os.path.dirname(__file__))
update_apt = os.path.join(pluginDir, 'update_apt')
update_apt_file = os.path.join(pluginDir, 'update_apt_file')
@ -115,7 +115,7 @@ conf.registerChannelValue(PackageInfo, 'enabled',
conf.registerChannelValue(PackageInfo, 'prefixchar',
conf.ValidPrefixChars('!', "Character the bot will respond to"))
conf.registerChannelValue(PackageInfo, 'defaultRelease',
registry.String('lucid', "Default release to use when none is specified"))
registry.String('natty', "Default release to use when none is specified"))
conf.registerGlobalValue(PackageInfo, 'aptdir',
conf.Directory(conf.supybot.directories.data.dirize('aptdir'), "Path to the apt directory", private=True))

5
PackageInfo/update_apt Normal file → Executable file
View File

@ -1,11 +1,14 @@
#!/usr/bin/env bash
# Set DIR to the same value as supybot.plugins.PackageInfo.aptdir
if [ -z "$DIR" ]; then
DIR=/home/bot/aptdir
fi
# Be quiet bt default
DEFAULT_OPTS="-qq"
# Check command-line arguments
while [ "x$1" != "x" ]; do
case "$1" in
-v|--verbose)
@ -27,7 +30,7 @@ while [ "x$1" != "x" ]; do
exit 1
;;
*)
echo "This script takes no arguments" >&2
echo "This script takes no non-argument parameters" >&2
exit 1
;;
esac

5
PackageInfo/update_apt_file Normal file → Executable file
View File

@ -5,14 +5,17 @@ if [ ! -x "$(which apt-file)" ]; then
exit 1
fi
# Set DIR to the same value as supybot.plugins.PackageInfo.aptdir
if [ -z "$DIR" ]; then
DIR=/home/bot/aptdir
fi
# Be quiet by default
if [ -z "$VERBOSE" ]; then
VERBOSE="no"
fi
# Check command-line arguments
while [ "x$1" != "x" ]; do
case "$1" in
-v|--verbose)
@ -31,7 +34,7 @@ while [ "x$1" != "x" ]; do
exit 1
;;
*)
echo "This script takes no arguments" >&2
echo "This script takes no non-argument parameterss" >&2
exit 1
;;
esac

View File

@ -6,8 +6,9 @@ setting up an ubottu clone for the first time.
These plugins are designed to work with Python 2.5 and Python 2.6, they are
untested and unsupported on Python 3.0. The recommended way to set-up these
plugins is to first create a directory for the bot, then move this directory to
there and rename it to "plugins". After that you should make sure you have the
following installed on the system:
there and rename it to "plugins". Alternatively you can create an empty plugins
directory and create links to each separate plugin directory inside there.
After that you should make sure you have the following installed on the system:
Name Debian/Ubuntu package Website
Python-apt python-apt N/A Debian (and derivatives) only
@ -19,6 +20,8 @@ SOAPpy python-soappy http://soapy.sourceforge.net/
Launchpadlib python-launchpadlib https://launchpad.net/launchpadlib
apt-file apt-file N/A Debian (and derivatives) only
Launchpadlib will become a required module for Bugtracker (and possibly others)
Once these packages are installed, and in the bot directory containing the
"plugins" sub-directory, run this command: "supybot-wizard".
This wizard will guide you through the process of setting up the bot for an IRC
@ -32,11 +35,11 @@ Bantracker Helps to track bans/kicks/quiets/removes in channels
Bugtracker Show information on bugs for various bug trackers.
Encyclopedia A factoid encyclopaedia.
IRCLogin Allows password-less login from users identified to services.
Lart A database of "larts".
Mess Random mess, pulls random things from the internet.
Lart A database of "larts". (Unmaintained)
Mess Random mess, pulls random things from the internet. (Unmaintained)
PackageInfo Lookup information on Debian packages and file search.
(works on Debian and derivatives only)
Webcal Updates a channel topic based on events in an iCal.
(works on Debian and derivatives only, unless you take special measures)
Webcal Updates a channel topic based on events in an iCal. (Unmaintained)
Note: Mess and Lart are largely unmaintained but are working, Webcal is
unmaintained and mostly broken except for extremely simple iCal feeds.
@ -44,12 +47,16 @@ unmaintained and mostly broken except for extremely simple iCal feeds.
If you chose to enable Bantracker or Encyclopedia, initial databases will be
created in the "data" directory. These are named "bans.db" for the Bantracker
plugin and "ubuntu.db" for the Encyclopedia plugin. You can obtain the same
database that ubottu uses by overwriting the "bans/ubuntu.db" file with the one
database that ubottu uses by overwriting the "ubuntu.db" file with the one
located at http://ubottu.com/ubuntu.db or by running the "@sync" command with
the bot in IRC. If you enabled the PackageInfo plugin several .list files will
be created in "data/aptdir/", these will be used with the "apt-cache" and
"apt-file" commands to retrieve package information and find files within
packages. When asked if you want to run the "update_apt" script you should
the bot in IRC.
The Bantracker database from ubottu is not available to the
public, as it will contain logs of channels which are not publically logged.
If you enabled the PackageInfo plugin several .list files will be created in
"data/aptdir/", these will be used with the "apt-cache" and "apt-file" commands
to retrieve package information and find files within packages.
When asked if you want to run the "update_apt" script you should
answer "y" to download the package information, this will take a while
depending on the speed of your connection and proximity to the default servers.
The same is true for the "update_apt_file" script, which will only be ran if
@ -62,5 +69,7 @@ the user the bot is run as.
Once you have selected the plugins you want to enable, you will be asked "Would
you like to set the prefix char(s) for your bot?", you should answer "y" and
set it to anything other than the prefix character for Encyclopedia and
PacakgeInfo. If you weren't asked, it defaults to '!'. The recommended
character is '@'.
PacakgeInfo. If you weren't asked, it defaults to '!' for those plugins. The
recommended character to use is '@'. Do not set the prefix chacter for commands
and for the plugins to the same value, you will run into trouble.

View File

@ -31,6 +31,7 @@ if cookie.has_key('tz'):
cookie['tz']['version'] = 1
class IOWrapper:
'''Class to wrap default IO, used with templates'''
def __init__(self):
self.buf = []
def write(self, val):
@ -42,6 +43,7 @@ sys.stdout = IOWrapper()
sys.stderr = IOWrapper()
def send_page(template):
'''Sends a template page and exit'''
data = sys.stdout.getvalue()
errdata = sys.stderr.getvalue()
sys.stdout = sys.__stdout__
@ -64,5 +66,6 @@ def send_page(template):
sys.exit(0)
def q(txt):
'''Simple HTML entity quoting'''
return txt.replace('&','&amp;').replace('<','&lt;').replace('>','&gt;').replace('"','&quot;')