Merge lp:~stefanor/ibid/misc into lp:~ibid-core/ibid/old-trunk-pack-0.92
- misc
- Merge into old-trunk-pack-0.92
Proposed by
Stefano Rivera
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Michael Gorven | ||||
Approved revision: | 559 | ||||
Merged at revision: | 556 | ||||
Proposed branch: | lp:~stefanor/ibid/misc | ||||
Merge into: | lp:~ibid-core/ibid/old-trunk-pack-0.92 | ||||
Diff against target: | None lines | ||||
To merge this branch: | bzr merge lp:~stefanor/ibid/misc | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michael Gorven | Approve | ||
Jonathan Hitchcock | Approve | ||
Review via email: mp+4051@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
Stefano Rivera (stefanor) wrote : | # |
Revision history for this message
Jonathan Hitchcock (vhata) : | # |
review:
Approve
Revision history for this message
Michael Gorven (mgorven) wrote : | # |
I have a few minor changes, but looks fine otherwise. Good work.
review approve
status approve
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'INSTALL' | |||
2 | --- INSTALL 2009-02-24 23:55:20 +0000 | |||
3 | +++ INSTALL 2009-02-24 16:03:17 +0000 | |||
4 | @@ -7,7 +7,8 @@ | |||
5 | 7 | # apt-get install python-virtualenv python-soappy python-twisted \ | 7 | # apt-get install python-virtualenv python-soappy python-twisted \ |
6 | 8 | python-configobj python-sqllite2 python-feedparser \ | 8 | python-configobj python-sqllite2 python-feedparser \ |
7 | 9 | python-httplib2 python-beautifulsoup python-dictclient \ | 9 | python-httplib2 python-beautifulsoup python-dictclient \ |
9 | 10 | python-imdbpy python-dns pysilc python-pinder | 10 | python-imdbpy python-dns python-simplejson \ |
10 | 11 | python-jinja pysilc python-pinder | ||
11 | 11 | 12 | ||
12 | 12 | Switch to the user ibid will be running as. | 13 | Switch to the user ibid will be running as. |
13 | 13 | Set up a virtual Python environment | 14 | Set up a virtual Python environment |
14 | 14 | 15 | ||
15 | === modified file 'ibid/config.ini' | |||
16 | --- ibid/config.ini 2009-02-23 09:44:40 +0000 | |||
17 | +++ ibid/config.ini 2009-03-01 15:16:39 +0000 | |||
18 | @@ -32,18 +32,18 @@ | |||
19 | 32 | [[smtp]] | 32 | [[smtp]] |
20 | 33 | relayhost = localhost | 33 | relayhost = localhost |
21 | 34 | address = ibid@localhost | 34 | address = ibid@localhost |
23 | 35 | accept = ibid@foo.com, | 35 | accept = ibid@foo.com, |
24 | 36 | [[pb]] | 36 | [[pb]] |
25 | 37 | [[reaper]] | 37 | [[reaper]] |
26 | 38 | type = silc | 38 | type = silc |
27 | 39 | server = silc.za.net | 39 | server = silc.za.net |
28 | 40 | channels = ibid, | 40 | channels = ibid, |
29 | 41 | name = Ibid Bot | 41 | name = Ibid Bot |
35 | 42 | [[campfire]] | 42 | [[campfire]] |
36 | 43 | subdomain = ibid | 43 | subdomain = ibid |
37 | 44 | rooms = Room 1, | 44 | rooms = Room 1, |
38 | 45 | username = foo@bar.com | 45 | username = foo@bar.com |
39 | 46 | password = baz | 46 | password = baz |
40 | 47 | 47 | ||
41 | 48 | [plugins] | 48 | [plugins] |
42 | 49 | [[ping]] | 49 | [[ping]] |
43 | @@ -71,4 +71,4 @@ | |||
44 | 71 | server = localhost | 71 | server = localhost |
45 | 72 | 72 | ||
46 | 73 | [databases] | 73 | [databases] |
48 | 74 | ibid = sqlite:///ibid.db | 74 | ibid = sqlite:///ibid.db |
49 | 75 | 75 | ||
50 | === modified file 'ibid/plugins/admin.py' | |||
51 | --- ibid/plugins/admin.py 2009-02-13 21:19:45 +0000 | |||
52 | +++ ibid/plugins/admin.py 2009-03-01 23:01:30 +0000 | |||
53 | @@ -5,9 +5,9 @@ | |||
54 | 5 | 5 | ||
55 | 6 | help = {} | 6 | help = {} |
56 | 7 | 7 | ||
58 | 8 | help['plugins'] = 'Lists, loads and unloads plugins.' | 8 | help['plugins'] = u'Lists, loads and unloads plugins.' |
59 | 9 | class ListPLugins(Processor): | 9 | class ListPLugins(Processor): |
61 | 10 | """list plugins""" | 10 | u"""list plugins""" |
62 | 11 | feature = 'plugins' | 11 | feature = 'plugins' |
63 | 12 | 12 | ||
64 | 13 | @match(r'^lsmod|list\s+plugins$') | 13 | @match(r'^lsmod|list\s+plugins$') |
65 | @@ -20,8 +20,9 @@ | |||
66 | 20 | event.addresponse(', '.join(plugins)) | 20 | event.addresponse(', '.join(plugins)) |
67 | 21 | return event | 21 | return event |
68 | 22 | 22 | ||
70 | 23 | help['core'] = 'Reloads core modules.' | 23 | help['core'] = u'Reloads core modules.' |
71 | 24 | class ReloadCoreModules(Processor): | 24 | class ReloadCoreModules(Processor): |
72 | 25 | u"""reload (reloader|dispatcher|databases|auth)""" | ||
73 | 25 | feature = 'core' | 26 | feature = 'core' |
74 | 26 | 27 | ||
75 | 27 | priority = -5 | 28 | priority = -5 |
76 | @@ -39,7 +40,7 @@ | |||
77 | 39 | event.addresponse(result and u'%s reloaded' % module or u"Couldn't reload %s" % module) | 40 | event.addresponse(result and u'%s reloaded' % module or u"Couldn't reload %s" % module) |
78 | 40 | 41 | ||
79 | 41 | class LoadModules(Processor): | 42 | class LoadModules(Processor): |
81 | 42 | """(load|unload|reload) <plugin|processor>""" | 43 | u"""(load|unload|reload) <plugin|processor>""" |
82 | 43 | feature = 'plugins' | 44 | feature = 'plugins' |
83 | 44 | 45 | ||
84 | 45 | permission = u'plugins' | 46 | permission = u'plugins' |
85 | @@ -59,7 +60,7 @@ | |||
86 | 59 | 60 | ||
87 | 60 | help['die'] = u'Terminates the bot' | 61 | help['die'] = u'Terminates the bot' |
88 | 61 | class Die(Processor): | 62 | class Die(Processor): |
90 | 62 | """die""" | 63 | u"""die""" |
91 | 63 | feature = 'die' | 64 | feature = 'die' |
92 | 64 | 65 | ||
93 | 65 | permission = u'admin' | 66 | permission = u'admin' |
94 | 66 | 67 | ||
95 | === modified file 'ibid/plugins/apt.py' | |||
96 | --- ibid/plugins/apt.py 2009-02-16 08:13:23 +0000 | |||
97 | +++ ibid/plugins/apt.py 2009-03-01 19:58:06 +0000 | |||
98 | @@ -2,67 +2,129 @@ | |||
99 | 2 | 2 | ||
100 | 3 | from ibid.plugins import Processor, match | 3 | from ibid.plugins import Processor, match |
101 | 4 | from ibid.config import Option | 4 | from ibid.config import Option |
102 | 5 | from ibid.utils import file_in_path, unicode_output | ||
103 | 5 | 6 | ||
104 | 6 | help = {} | 7 | help = {} |
105 | 7 | 8 | ||
106 | 8 | help['aptitude'] = u'Searches for packages' | 9 | help['aptitude'] = u'Searches for packages' |
107 | 9 | class Aptitude(Processor): | 10 | class Aptitude(Processor): |
109 | 10 | """(apt|aptitude|apt-get) [search] <term>""" | 11 | u"""apt (search|show) <term>""" |
110 | 11 | feature = 'aptitude' | 12 | feature = 'aptitude' |
111 | 12 | 13 | ||
112 | 13 | aptitude = Option('aptitude', 'Path to aptitude executable', 'aptitude') | 14 | aptitude = Option('aptitude', 'Path to aptitude executable', 'aptitude') |
113 | 14 | 15 | ||
115 | 15 | @match(r'^(?:apt|aptitude|apt-get)\s+(?:search\s+)(.+)$') | 16 | bad_search_strings = ( |
116 | 17 | "?action", "~a", "?automatic", "~A", "?broken", "~b", | ||
117 | 18 | "?config-files", "~c", "?garbage", "~g", "?installed", "~i", | ||
118 | 19 | "?new", "~N", "?obsolete", "~o", "?upgradable", "~U", | ||
119 | 20 | "?user-tag", "?version", "~V" | ||
120 | 21 | ) | ||
121 | 22 | |||
122 | 23 | def setup(self): | ||
123 | 24 | if not file_in_path(self.aptitude): | ||
124 | 25 | raise Exception("Cannot locate aptitude executeable") | ||
125 | 26 | |||
126 | 27 | def _check_terms(self, event, term): | ||
127 | 28 | "Check for naughty users" | ||
128 | 29 | |||
129 | 30 | for word in self.bad_search_strings: | ||
130 | 31 | if word in term: | ||
131 | 32 | event.addresponse(u"I can't tell you about my host system. Sorry.") | ||
132 | 33 | return False | ||
133 | 34 | |||
134 | 35 | if term.strip().startswith("-"): | ||
135 | 36 | event.addresponse(False) | ||
136 | 37 | return False | ||
137 | 38 | |||
138 | 39 | return True | ||
139 | 40 | |||
140 | 41 | @match(r'^(?:apt|aptitude|apt-get|apt-cache)\s+search\s+(.+)$') | ||
141 | 16 | def search(self, event, term): | 42 | def search(self, event, term): |
142 | 43 | |||
143 | 44 | if not self._check_terms(event, term): | ||
144 | 45 | return | ||
145 | 46 | |||
146 | 17 | apt = Popen([self.aptitude, 'search', '-F', '%p', term], stdout=PIPE, stderr=PIPE) | 47 | apt = Popen([self.aptitude, 'search', '-F', '%p', term], stdout=PIPE, stderr=PIPE) |
147 | 18 | output, error = apt.communicate() | 48 | output, error = apt.communicate() |
148 | 19 | code = apt.wait() | 49 | code = apt.wait() |
149 | 20 | 50 | ||
151 | 21 | if code == 0 and output: | 51 | if code == 0: |
152 | 22 | if output: | 52 | if output: |
154 | 23 | event.addresponse(u', '.join(line.strip() for line in output.splitlines())) | 53 | output = unicode_output(output.strip()) |
155 | 54 | output = [line.strip() for line in output.splitlines()] | ||
156 | 55 | event.addresponse(u"Found %i packages: %s" % (len(output), u', '.join(output))) | ||
157 | 24 | else: | 56 | else: |
158 | 25 | event.addresponse(u'No packages found') | 57 | event.addresponse(u'No packages found') |
163 | 26 | 58 | else: | |
164 | 27 | @match(r'(?:apt|aptitude|apt-get)\s+(?:show\s+)(.+)$') | 59 | error = unicode_output(error.strip()) |
165 | 28 | def show(self, event, package): | 60 | if error.startswith(u"E: "): |
166 | 29 | apt = Popen([self.aptitude, 'show', package], stdout=PIPE, stderr=PIPE) | 61 | error = error[3:] |
167 | 62 | event.addresponse(u"Couldn't search: %s" % error) | ||
168 | 63 | |||
169 | 64 | @match(r'(?:apt|aptitude|apt-get)\s+show\s+(.+)$') | ||
170 | 65 | def show(self, event, term): | ||
171 | 66 | |||
172 | 67 | if not self._check_terms(event, term): | ||
173 | 68 | return | ||
174 | 69 | |||
175 | 70 | apt = Popen([self.aptitude, 'show', term], stdout=PIPE, stderr=PIPE) | ||
176 | 30 | output, error = apt.communicate() | 71 | output, error = apt.communicate() |
177 | 31 | code = apt.wait() | 72 | code = apt.wait() |
178 | 32 | 73 | ||
181 | 33 | if code == 0 and output: | 74 | if code == 0: |
180 | 34 | print output | ||
182 | 35 | description = None | 75 | description = None |
183 | 76 | output = unicode_output(output) | ||
184 | 36 | for line in output.splitlines(): | 77 | for line in output.splitlines(): |
185 | 37 | if not description: | 78 | if not description: |
190 | 38 | if line.startswith('Description:'): | 79 | if line.startswith(u'Description:'): |
191 | 39 | description = u'%s:' % line.replace('Description:', '', 1).strip() | 80 | description = u'%s:' % line.split(None, 1)[1] |
192 | 40 | elif line.startswith('Provided by:'): | 81 | elif line.startswith(u'Provided by:'): |
193 | 41 | description = u'Virtual package provided by %s' % line.replace('Provided by:', '', 1).strip() | 82 | description = u'Virtual package provided by %s' % line.split(None, 2)[2] |
194 | 83 | elif line != "": | ||
195 | 84 | description += u' ' + line.strip() | ||
196 | 42 | else: | 85 | else: |
198 | 43 | description += ' ' + line.strip() | 86 | # More than one package listed |
199 | 87 | break | ||
200 | 44 | if description: | 88 | if description: |
201 | 45 | event.addresponse(description) | 89 | event.addresponse(description) |
202 | 46 | else: | 90 | else: |
204 | 47 | event.addresponse(u'No such package') | 91 | raise Exception("We couldn't successfully parse aptitude's output") |
205 | 92 | else: | ||
206 | 93 | error = unicode_output(error.strip()) | ||
207 | 94 | if error.startswith(u"E: "): | ||
208 | 95 | error = error[3:] | ||
209 | 96 | event.addresponse(u"Couldn't find package: %s" % error) | ||
210 | 48 | 97 | ||
211 | 49 | help['apt-file'] = u'Searches for packages containing the specified file' | 98 | help['apt-file'] = u'Searches for packages containing the specified file' |
212 | 50 | class AptFile(Processor): | 99 | class AptFile(Processor): |
214 | 51 | """apt-file [search] <term>""" | 100 | u"""apt-file [search] <term>""" |
215 | 52 | feature = 'apt-file' | 101 | feature = 'apt-file' |
216 | 53 | 102 | ||
217 | 54 | aptfile = Option('apt-file', 'Path to apt-file executable', 'apt-file') | 103 | aptfile = Option('apt-file', 'Path to apt-file executable', 'apt-file') |
218 | 55 | 104 | ||
219 | 105 | def setup(self): | ||
220 | 106 | if not file_in_path(self.aptfile): | ||
221 | 107 | raise Exception("Cannot locate apt-file executeable") | ||
222 | 108 | |||
223 | 56 | @match(r'^apt-?file\s+(?:search\s+)?(.+)$') | 109 | @match(r'^apt-?file\s+(?:search\s+)?(.+)$') |
224 | 57 | def search(self, event, term): | 110 | def search(self, event, term): |
225 | 58 | apt = Popen([self.aptfile, 'search', term], stdout=PIPE, stderr=PIPE) | 111 | apt = Popen([self.aptfile, 'search', term], stdout=PIPE, stderr=PIPE) |
226 | 59 | output, error = apt.communicate() | 112 | output, error = apt.communicate() |
227 | 60 | code = apt.wait() | 113 | code = apt.wait() |
228 | 61 | 114 | ||
230 | 62 | if code == 0 and output: | 115 | if code == 0: |
231 | 63 | if output: | 116 | if output: |
235 | 64 | event.addresponse(u', '.join(line.split(':')[0] for line in output.splitlines())) | 117 | output = unicode_output(output.strip()) |
236 | 65 | else: | 118 | output = [line.split(u':')[0] for line in output.splitlines()] |
237 | 66 | event.addresponse(u'No packages found') | 119 | event.addresponse(u"Found %i packages: %s" % (len(output), u', '.join(output))) |
238 | 120 | else: | ||
239 | 121 | event.addresponse(u'No packages found.') | ||
240 | 122 | else: | ||
241 | 123 | error = unicode_output(error.strip()) | ||
242 | 124 | if u"The cache directory is empty." in error: | ||
243 | 125 | event.addresponse(u'Search error: apt-file cache empty.') | ||
244 | 126 | else: | ||
245 | 127 | event.addresponse(u'Search error') | ||
246 | 128 | raise Exception("apt-file: %s" % error) | ||
247 | 67 | 129 | ||
248 | 68 | # vi: set et sta sw=4 ts=4: | 130 | # vi: set et sta sw=4 ts=4: |
249 | 69 | 131 | ||
250 | === modified file 'ibid/plugins/auth.py' | |||
251 | --- ibid/plugins/auth.py 2009-02-22 15:30:46 +0000 | |||
252 | +++ ibid/plugins/auth.py 2009-03-01 23:01:30 +0000 | |||
253 | @@ -13,9 +13,9 @@ | |||
254 | 13 | 13 | ||
255 | 14 | actions = {'revoke': 'Revoked', 'grant': 'Granted', 'remove': 'Removed'} | 14 | actions = {'revoke': 'Revoked', 'grant': 'Granted', 'remove': 'Removed'} |
256 | 15 | 15 | ||
258 | 16 | help['auth'] = 'Adds and removes authentication credentials and permissions' | 16 | help['auth'] = u'Adds and removes authentication credentials and permissions' |
259 | 17 | class AddAuth(Processor): | 17 | class AddAuth(Processor): |
261 | 18 | """authenticate <account> using <method> [<credential>]""" | 18 | u"""authenticate <account> [on source] using <method> [<credential>]""" |
262 | 19 | feature = 'auth' | 19 | feature = 'auth' |
263 | 20 | 20 | ||
264 | 21 | @match(r'^authenticate\s+(.+?)(?:\s+on\s+(.+))?\s+using\s+(\S+)\s+(.+)$') | 21 | @match(r'^authenticate\s+(.+?)(?:\s+on\s+(.+))?\s+using\s+(\S+)\s+(.+)$') |
265 | @@ -59,7 +59,9 @@ | |||
266 | 59 | 59 | ||
267 | 60 | permission_values = {'no': '-', 'yes': '+', 'auth': ''} | 60 | permission_values = {'no': '-', 'yes': '+', 'auth': ''} |
268 | 61 | class Permissions(Processor): | 61 | class Permissions(Processor): |
270 | 62 | """(grant|revoke|remove) <permission> (to|from|on) <username> [when authed] | list permissions""" | 62 | u"""(grant|revoke) <permission> (to|from|on) <username> [when authed] |
271 | 63 | permissions [for <username>] | ||
272 | 64 | list permissions""" | ||
273 | 63 | feature = 'auth' | 65 | feature = 'auth' |
274 | 64 | 66 | ||
275 | 65 | permission = u'admin' | 67 | permission = u'admin' |
276 | @@ -139,7 +141,7 @@ | |||
277 | 139 | event.addresponse(', '.join(permissions)) | 141 | event.addresponse(', '.join(permissions)) |
278 | 140 | 142 | ||
279 | 141 | class Auth(Processor): | 143 | class Auth(Processor): |
281 | 142 | """auth <credential>""" | 144 | u"""auth <credential>""" |
282 | 143 | feature = 'auth' | 145 | feature = 'auth' |
283 | 144 | 146 | ||
284 | 145 | @match(r'^auth(?:\s+(.+))?$') | 147 | @match(r'^auth(?:\s+(.+))?$') |
285 | 146 | 148 | ||
286 | === modified file 'ibid/plugins/basic.py' | |||
287 | --- ibid/plugins/basic.py 2009-02-13 21:19:45 +0000 | |||
288 | +++ ibid/plugins/basic.py 2009-03-01 23:01:30 +0000 | |||
289 | @@ -1,14 +1,13 @@ | |||
290 | 1 | from random import choice | 1 | from random import choice |
291 | 2 | import re | 2 | import re |
292 | 3 | import logging | ||
293 | 4 | 3 | ||
294 | 5 | from ibid.plugins import Processor, match, handler, authorise | 4 | from ibid.plugins import Processor, match, handler, authorise |
295 | 6 | 5 | ||
296 | 7 | help = {} | 6 | help = {} |
297 | 8 | 7 | ||
299 | 9 | help['saydo'] = 'Says or does stuff in a channel.' | 8 | help['saydo'] = u'Says or does stuff in a channel.' |
300 | 10 | class SayDo(Processor): | 9 | class SayDo(Processor): |
302 | 11 | """(say|do) <channel> <text>""" | 10 | u"""(say|do) <channel> <text>""" |
303 | 12 | feature = 'saydo' | 11 | feature = 'saydo' |
304 | 13 | 12 | ||
305 | 14 | permission = u'saydo' | 13 | permission = u'saydo' |
306 | @@ -25,7 +24,7 @@ | |||
307 | 25 | 24 | ||
308 | 26 | help['redirect'] = u'Redirects the response to a command to a different channel.' | 25 | help['redirect'] = u'Redirects the response to a command to a different channel.' |
309 | 27 | class RedirectCommand(Processor): | 26 | class RedirectCommand(Processor): |
311 | 28 | """redirect [to] <channel> [on <source>] <command>""" | 27 | u"""redirect [to] <channel> [on <source>] <command>""" |
312 | 29 | feature = 'redirect' | 28 | feature = 'redirect' |
313 | 30 | 29 | ||
314 | 31 | priority = -1200 | 30 | priority = -1200 |
315 | @@ -57,31 +56,15 @@ | |||
316 | 57 | responses.append(response) | 56 | responses.append(response) |
317 | 58 | event.responses = responses | 57 | event.responses = responses |
318 | 59 | 58 | ||
321 | 60 | choose_re = re.compile(r'(?:\s*,\s*(?:or\s+)?)|(?:\s+or\s+)', re.I) | 59 | help['choose'] = u'Choose one of the given options.' |
320 | 61 | help['choose'] = 'Choose one of the given options.' | ||
322 | 62 | class Choose(Processor): | 60 | class Choose(Processor): |
324 | 63 | """choose <choice> or <choice>...""" | 61 | u"""choose <choice> or <choice>...""" |
325 | 64 | feature = 'choose' | 62 | feature = 'choose' |
326 | 65 | 63 | ||
327 | 64 | choose_re = re.compile(r'(?:\s*,\s*(?:or\s+)?)|(?:\s+or\s+)', re.I) | ||
328 | 65 | |||
329 | 66 | @match(r'^(?:choose|choice|pick)\s+(.+)$') | 66 | @match(r'^(?:choose|choice|pick)\s+(.+)$') |
330 | 67 | def choose(self, event, choices): | 67 | def choose(self, event, choices): |
349 | 68 | event.addresponse(u'I choose %s' % choice(choose_re.split(choices))) | 68 | event.addresponse(u'I choose %s' % choice(self.choose_re.split(choices))) |
332 | 69 | |||
333 | 70 | class UnicodeWarning(Processor): | ||
334 | 71 | |||
335 | 72 | priority = 1950 | ||
336 | 73 | |||
337 | 74 | def setup(self): | ||
338 | 75 | self.log = logging.getLogger('plugins.unicode') | ||
339 | 76 | |||
340 | 77 | def process(self, object): | ||
341 | 78 | if isinstance(object, dict): | ||
342 | 79 | for value in object.values(): | ||
343 | 80 | self.process(value) | ||
344 | 81 | elif isinstance(object, list): | ||
345 | 82 | for value in object: | ||
346 | 83 | self.process(value) | ||
347 | 84 | elif isinstance(object, str): | ||
348 | 85 | self.log.warning(u"Found a non-unicode string: %s" % object) | ||
350 | 86 | 69 | ||
351 | 87 | # vi: set et sta sw=4 ts=4: | 70 | # vi: set et sta sw=4 ts=4: |
352 | 88 | 71 | ||
353 | === modified file 'ibid/plugins/buildbot.py' | |||
354 | --- ibid/plugins/buildbot.py 2009-02-23 20:29:44 +0000 | |||
355 | +++ ibid/plugins/buildbot.py 2009-03-01 23:01:30 +0000 | |||
356 | @@ -9,7 +9,7 @@ | |||
357 | 9 | help = {'buildbot': u'Displays buildbot build results and triggers builds.'} | 9 | help = {'buildbot': u'Displays buildbot build results and triggers builds.'} |
358 | 10 | 10 | ||
359 | 11 | class BuildBot(Processor, RPC): | 11 | class BuildBot(Processor, RPC): |
361 | 12 | """rebuild <branch> [ (revision|r) <number> ]""" | 12 | u"""rebuild <branch> [ (revision|r) <number> ]""" |
362 | 13 | feature = 'buildbot' | 13 | feature = 'buildbot' |
363 | 14 | 14 | ||
364 | 15 | server = Option('server', 'Buildbot server hostname', 'localhost') | 15 | server = Option('server', 'Buildbot server hostname', 'localhost') |
365 | 16 | 16 | ||
366 | === modified file 'ibid/plugins/bzr.py' | |||
367 | --- ibid/plugins/bzr.py 2009-02-18 10:41:14 +0000 | |||
368 | +++ ibid/plugins/bzr.py 2009-03-01 23:01:30 +0000 | |||
369 | @@ -10,7 +10,7 @@ | |||
370 | 10 | from ibid.config import Option | 10 | from ibid.config import Option |
371 | 11 | from ibid.utils import ago | 11 | from ibid.utils import ago |
372 | 12 | 12 | ||
374 | 13 | help = {'bzr': 'Retrieves commit logs from a Bazaar repository.'} | 13 | help = {'bzr': u'Retrieves commit logs from a Bazaar repository.'} |
375 | 14 | 14 | ||
376 | 15 | class LogFormatter(log.LogFormatter): | 15 | class LogFormatter(log.LogFormatter): |
377 | 16 | 16 | ||
378 | @@ -42,7 +42,7 @@ | |||
379 | 42 | self.to_file.write(commit) | 42 | self.to_file.write(commit) |
380 | 43 | 43 | ||
381 | 44 | class Bazaar(Processor, RPC): | 44 | class Bazaar(Processor, RPC): |
383 | 45 | """last commit to <repo> | commit <revno> [full] | 45 | u"""(last commit|commit <revno>) [to <repo>] [full] |
384 | 46 | repositories""" | 46 | repositories""" |
385 | 47 | feature = 'bzr' | 47 | feature = 'bzr' |
386 | 48 | 48 | ||
387 | @@ -83,7 +83,7 @@ | |||
388 | 83 | 83 | ||
389 | 84 | for commit in commits: | 84 | for commit in commits: |
390 | 85 | if commit: | 85 | if commit: |
392 | 86 | event.addresponse(commit.strip()) | 86 | event.addresponse(unicode(commit.strip())) |
393 | 87 | 87 | ||
394 | 88 | def get_commits(self, repository, start, end=None, full=None): | 88 | def get_commits(self, repository, start, end=None, full=None): |
395 | 89 | branch = None | 89 | branch = None |
396 | 90 | 90 | ||
397 | === modified file 'ibid/plugins/config.py' | |||
398 | --- ibid/plugins/config.py 2009-02-13 21:55:56 +0000 | |||
399 | +++ ibid/plugins/config.py 2009-03-01 23:01:30 +0000 | |||
400 | @@ -5,12 +5,14 @@ | |||
401 | 5 | from ibid.config import FileConfig | 5 | from ibid.config import FileConfig |
402 | 6 | from ibid.plugins import Processor, match, authorise | 6 | from ibid.plugins import Processor, match, authorise |
403 | 7 | 7 | ||
405 | 8 | help = {'config': 'Gets and sets configuration settings, and rereads the configuration file.'} | 8 | help = {'config': u'Gets and sets configuration settings, and rereads the configuration file.'} |
406 | 9 | 9 | ||
407 | 10 | log = logging.getLogger('plugins.config') | 10 | log = logging.getLogger('plugins.config') |
408 | 11 | 11 | ||
409 | 12 | class Config(Processor): | 12 | class Config(Processor): |
411 | 13 | """reread config | set config <name> <value> | get config <name>""" | 13 | u"""reread config |
412 | 14 | set config <name> to <value> | ||
413 | 15 | get config <name>""" | ||
414 | 14 | feature = 'config' | 16 | feature = 'config' |
415 | 15 | 17 | ||
416 | 16 | priority = -10 | 18 | priority = -10 |
417 | 17 | 19 | ||
418 | === modified file 'ibid/plugins/core.py' | |||
419 | --- ibid/plugins/core.py 2009-02-23 20:29:44 +0000 | |||
420 | +++ ibid/plugins/core.py 2009-03-01 19:58:06 +0000 | |||
421 | @@ -1,13 +1,12 @@ | |||
422 | 1 | import re | 1 | import re |
423 | 2 | from time import time | 2 | from time import time |
424 | 3 | from random import choice | 3 | from random import choice |
425 | 4 | import logging | ||
426 | 4 | 5 | ||
427 | 5 | import ibid | 6 | import ibid |
428 | 6 | from ibid.plugins import Processor, handler | 7 | from ibid.plugins import Processor, handler |
429 | 7 | from ibid.config import Option, IntOption | 8 | from ibid.config import Option, IntOption |
430 | 8 | 9 | ||
431 | 9 | help = {} | ||
432 | 10 | |||
433 | 11 | class Addressed(Processor): | 10 | class Addressed(Processor): |
434 | 12 | 11 | ||
435 | 13 | priority = -1500 | 12 | priority = -1500 |
436 | @@ -89,14 +88,20 @@ | |||
437 | 89 | class Address(Processor): | 88 | class Address(Processor): |
438 | 90 | 89 | ||
439 | 91 | processed = True | 90 | processed = True |
441 | 92 | acknowledgements = Option('acknowledgements', 'Responses for positive acknowledgements', (u'Okay', u'Sure', u'Done', u'Righto', u'Alrighty', u'Yessir')) | 91 | acknowledgements = Option('acknowledgements', 'Responses for positive acknowledgements', |
442 | 92 | (u'Okay', u'Sure', u'Done', u'Righto', u'Alrighty', u'Yessir')) | ||
443 | 93 | refusals = Option('refusals', 'Responses for negative acknowledgements', | ||
444 | 94 | (u'No', u"I won't", u"Shan't", u"I'm sorry, but I can't do that")) | ||
445 | 93 | 95 | ||
446 | 94 | @handler | 96 | @handler |
447 | 95 | def address(self, event): | 97 | def address(self, event): |
448 | 96 | addressed = [] | 98 | addressed = [] |
449 | 97 | for response in event.responses: | 99 | for response in event.responses: |
450 | 98 | if isinstance(response, bool): | 100 | if isinstance(response, bool): |
452 | 99 | response = choice(self.acknowledgements) | 101 | if response: |
453 | 102 | response = choice(self.acknowledgements) | ||
454 | 103 | else: | ||
455 | 104 | response = choice(self.refusals) | ||
456 | 100 | if isinstance(response, basestring) and event.public: | 105 | if isinstance(response, basestring) and event.public: |
457 | 101 | addressed.append('%s: %s' % (event.sender['nick'], response)) | 106 | addressed.append('%s: %s' % (event.sender['nick'], response)) |
458 | 102 | else: | 107 | else: |
459 | @@ -111,9 +116,7 @@ | |||
460 | 111 | def process(self, event): | 116 | def process(self, event): |
461 | 112 | event.time = time() | 117 | event.time = time() |
462 | 113 | 118 | ||
463 | 114 | help['complain'] = 'Responds with a complaint. Used to handle unprocessed messages.' | ||
464 | 115 | class Complain(Processor): | 119 | class Complain(Processor): |
465 | 116 | feature = 'complain' | ||
466 | 117 | 120 | ||
467 | 118 | priority = 950 | 121 | priority = 950 |
468 | 119 | complaints = Option('complaints', 'Complaint responses', (u'Huh?', u'Sorry...', u'?', u'Excuse me?', u'*blink*', u'What?')) | 122 | complaints = Option('complaints', 'Complaint responses', (u'Huh?', u'Sorry...', u'?', u'Excuse me?', u'*blink*', u'What?')) |
469 | @@ -147,4 +150,20 @@ | |||
470 | 147 | else: | 150 | else: |
471 | 148 | event.processed = True | 151 | event.processed = True |
472 | 149 | 152 | ||
473 | 153 | class UnicodeWarning(Processor): | ||
474 | 154 | priority = 1950 | ||
475 | 155 | |||
476 | 156 | def setup(self): | ||
477 | 157 | self.log = logging.getLogger('plugins.unicode') | ||
478 | 158 | |||
479 | 159 | def process(self, object): | ||
480 | 160 | if isinstance(object, dict): | ||
481 | 161 | for value in object.values(): | ||
482 | 162 | self.process(value) | ||
483 | 163 | elif isinstance(object, list): | ||
484 | 164 | for value in object: | ||
485 | 165 | self.process(value) | ||
486 | 166 | elif isinstance(object, str): | ||
487 | 167 | self.log.warning(u"Found a non-unicode string: %s" % object) | ||
488 | 168 | |||
489 | 150 | # vi: set et sta sw=4 ts=4: | 169 | # vi: set et sta sw=4 ts=4: |
490 | 151 | 170 | ||
491 | === modified file 'ibid/plugins/crypto.py' | |||
492 | --- ibid/plugins/crypto.py 2009-01-24 12:39:04 +0000 | |||
493 | +++ ibid/plugins/crypto.py 2009-03-01 23:01:30 +0000 | |||
494 | @@ -6,35 +6,36 @@ | |||
495 | 6 | 6 | ||
496 | 7 | help = {} | 7 | help = {} |
497 | 8 | 8 | ||
499 | 9 | help['hash'] = 'Calculates numerous cryptographic hash functions.' | 9 | help['hash'] = u'Calculates numerous cryptographic hash functions.' |
500 | 10 | class Hash(Processor): | 10 | class Hash(Processor): |
502 | 11 | """(md5|sha1|sha224|sha256|sha384|sha512|crypt) <string> [<salt>]""" | 11 | u"""(md5|sha1|sha224|sha256|sha384|sha512) <string> |
503 | 12 | crypt <string> <salt>""" | ||
504 | 12 | feature = 'hash' | 13 | feature = 'hash' |
505 | 13 | 14 | ||
506 | 14 | @match(r'^(md5|sha1|sha224|sha256|sha384|sha512)\s+(.+?)$') | 15 | @match(r'^(md5|sha1|sha224|sha256|sha384|sha512)\s+(.+?)$') |
507 | 15 | def hash(self, event, hash, string): | 16 | def hash(self, event, hash, string): |
509 | 16 | event.addresponse(eval('hashlib.%s' % hash.lower())(string).hexdigest()) | 17 | event.addresponse(unicode(eval('hashlib.%s' % hash.lower())(string).hexdigest())) |
510 | 17 | 18 | ||
511 | 18 | @match(r'^crypt\s+(.+)\s+(\S+)$') | 19 | @match(r'^crypt\s+(.+)\s+(\S+)$') |
512 | 19 | def handle_crypt(self, event, string, salt): | 20 | def handle_crypt(self, event, string, salt): |
514 | 20 | event.addresponse(crypt(string, salt)) | 21 | event.addresponse(unicode(crypt(string, salt))) |
515 | 21 | 22 | ||
517 | 22 | help['base64'] = 'Encodes and decodes base 16, 32 and 64.' | 23 | help['base64'] = u'Encodes and decodes base 16, 32 and 64.' |
518 | 23 | class Base64(Processor): | 24 | class Base64(Processor): |
520 | 24 | """b(16|32|64)(encode|decode) <string>""" | 25 | u"""b(16|32|64)(encode|decode) <string>""" |
521 | 25 | feature = 'base64' | 26 | feature = 'base64' |
522 | 26 | 27 | ||
523 | 27 | @match(r'^b(16|32|64)(enc|dec)(?:ode)?\s+(.+?)$') | 28 | @match(r'^b(16|32|64)(enc|dec)(?:ode)?\s+(.+?)$') |
524 | 28 | def base64(self, event, base, operation, string): | 29 | def base64(self, event, base, operation, string): |
526 | 29 | event.addresponse(eval('base64.b%s%sode' % (base, operation.lower()))(string)) | 30 | event.addresponse(unicode(eval('base64.b%s%sode' % (base, operation.lower()))(string))) |
527 | 30 | 31 | ||
529 | 31 | help['rot13'] = 'Transforms a string with ROT13.' | 32 | help['rot13'] = u'Transforms a string with ROT13.' |
530 | 32 | class Rot13(Processor): | 33 | class Rot13(Processor): |
532 | 33 | """rot13 <string>""" | 34 | u"""rot13 <string>""" |
533 | 34 | feature = 'rot13' | 35 | feature = 'rot13' |
534 | 35 | 36 | ||
535 | 36 | @match(r'^rot13\s+(.+)$') | 37 | @match(r'^rot13\s+(.+)$') |
536 | 37 | def rot13(self, event, string): | 38 | def rot13(self, event, string): |
538 | 38 | event.addresponse(string.encode('rot13')) | 39 | event.addresponse(unicode(string.encode('rot13'))) |
539 | 39 | 40 | ||
540 | 40 | # vi: set et sta sw=4 ts=4: | 41 | # vi: set et sta sw=4 ts=4: |
541 | 41 | 42 | ||
542 | === modified file 'ibid/plugins/dict.py' | |||
543 | --- ibid/plugins/dict.py 2009-02-03 18:03:49 +0000 | |||
544 | +++ ibid/plugins/dict.py 2009-03-01 23:01:30 +0000 | |||
545 | @@ -3,11 +3,12 @@ | |||
546 | 3 | from ibid.plugins import Processor, match | 3 | from ibid.plugins import Processor, match |
547 | 4 | from ibid.config import Option, IntOption | 4 | from ibid.config import Option, IntOption |
548 | 5 | 5 | ||
550 | 6 | help = {'dict': 'Defines words and checks spellings.'} | 6 | help = {'dict': u'Defines words and checks spellings.'} |
551 | 7 | 7 | ||
552 | 8 | class Dict(Processor): | 8 | class Dict(Processor): |
555 | 9 | """(spell|define) <word> [using (<dictionary>|<stratergy>)] | 9 | u"""(spell|define) <word> [using (<dictionary>|<strategy>)] |
556 | 10 | (dictionaries|strategies)""" | 10 | (dictionaries|strategies) |
557 | 11 | (dictionary|strategy) <name>""" | ||
558 | 11 | feature = 'dict' | 12 | feature = 'dict' |
559 | 12 | 13 | ||
560 | 13 | server = Option('server', 'Dictionary server hostname', 'localhost') | 14 | server = Option('server', 'Dictionary server hostname', 'localhost') |
561 | @@ -24,15 +25,15 @@ | |||
562 | 24 | event.addresponse(u', '.join([d.getdefstr() for d in definitions])) | 25 | event.addresponse(u', '.join([d.getdefstr() for d in definitions])) |
563 | 25 | 26 | ||
564 | 26 | @match(r'spell\s+(.+?)(?:\s+using\s+(.+))?$') | 27 | @match(r'spell\s+(.+?)(?:\s+using\s+(.+))?$') |
567 | 27 | def handle_spell(self, event, word, stratergy): | 28 | def handle_spell(self, event, word, strategy): |
568 | 28 | suggestions = self.connection.match('*', stratergy or 'soundex', word) | 29 | suggestions = self.connection.match('*', strategy or 'soundex', word) |
569 | 29 | event.addresponse(u', '.join([d.getword() for d in suggestions])) | 30 | event.addresponse(u', '.join([d.getword() for d in suggestions])) |
570 | 30 | 31 | ||
571 | 31 | @match(r'^dictionaries$') | 32 | @match(r'^dictionaries$') |
572 | 32 | def handle_dictionaries(self, event): | 33 | def handle_dictionaries(self, event): |
573 | 33 | event.addresponse(u', '.join(self.dictionaries.keys())) | 34 | event.addresponse(u', '.join(self.dictionaries.keys())) |
574 | 34 | 35 | ||
576 | 35 | @match(r'^strategies$') | 36 | @match(r'^strater?gies$') |
577 | 36 | def handle_strategies(self, event): | 37 | def handle_strategies(self, event): |
578 | 37 | event.addresponse(u', '.join(self.strategies.keys())) | 38 | event.addresponse(u', '.join(self.strategies.keys())) |
579 | 38 | 39 | ||
580 | @@ -43,10 +44,10 @@ | |||
581 | 43 | else: | 44 | else: |
582 | 44 | event.addresponse(u"I don't have that response") | 45 | event.addresponse(u"I don't have that response") |
583 | 45 | 46 | ||
588 | 46 | @match(r'^stratergy\s+(.+?)$') | 47 | @match(r'^strater?gy\s+(.+?)$') |
589 | 47 | def handle_stratergy(self, event, stratergy): | 48 | def handle_strategy(self, event, strategy): |
590 | 48 | if stratergy in self.strategies: | 49 | if strategy in self.strategies: |
591 | 49 | event.addresponse(unicode(self.strategies[stratergy])) | 50 | event.addresponse(unicode(self.strategies[strategy])) |
592 | 50 | else: | 51 | else: |
593 | 51 | event.addresponse(u"I don't have that response") | 52 | event.addresponse(u"I don't have that response") |
594 | 52 | 53 | ||
595 | 53 | 54 | ||
596 | === modified file 'ibid/plugins/eval.py' | |||
597 | --- ibid/plugins/eval.py 2009-02-12 16:49:56 +0000 | |||
598 | +++ ibid/plugins/eval.py 2009-03-01 23:01:30 +0000 | |||
599 | @@ -10,10 +10,10 @@ | |||
600 | 10 | 10 | ||
601 | 11 | from ibid.plugins import Processor, match, authorise | 11 | from ibid.plugins import Processor, match, authorise |
602 | 12 | 12 | ||
604 | 13 | help = {'eval': 'Evaluates Python, Perl and Lua code.'} | 13 | help = {'eval': u'Evaluates Python, Perl and Lua code.'} |
605 | 14 | 14 | ||
606 | 15 | class Python(Processor): | 15 | class Python(Processor): |
608 | 16 | """py <code>""" | 16 | u"""py <code>""" |
609 | 17 | feature = 'eval' | 17 | feature = 'eval' |
610 | 18 | 18 | ||
611 | 19 | permission = u'eval' | 19 | permission = u'eval' |
612 | @@ -27,13 +27,13 @@ | |||
613 | 27 | exec('import sys', globals) | 27 | exec('import sys', globals) |
614 | 28 | exec('import re', globals) | 28 | exec('import re', globals) |
615 | 29 | exec('import time', globals) | 29 | exec('import time', globals) |
617 | 30 | result = str(eval(code, globals, {})) | 30 | result = unicode(eval(code, globals, {})) |
618 | 31 | except Exception, e: | 31 | except Exception, e: |
620 | 32 | result = str(e) | 32 | result = unicode(e) |
621 | 33 | event.addresponse(result) | 33 | event.addresponse(result) |
622 | 34 | 34 | ||
623 | 35 | class Perl(Processor): | 35 | class Perl(Processor): |
625 | 36 | """pl <code>""" | 36 | u"""pl <code>""" |
626 | 37 | feature = 'eval' | 37 | feature = 'eval' |
627 | 38 | 38 | ||
628 | 39 | permission = u'eval' | 39 | permission = u'eval' |
629 | @@ -46,10 +46,10 @@ | |||
630 | 46 | except Exception, e: | 46 | except Exception, e: |
631 | 47 | result = e | 47 | result = e |
632 | 48 | 48 | ||
634 | 49 | event.addresponse(str(result)) | 49 | event.addresponse(unicode(result)) |
635 | 50 | 50 | ||
636 | 51 | class Lua(Processor): | 51 | class Lua(Processor): |
638 | 52 | """lua <code>""" | 52 | u"""lua <code>""" |
639 | 53 | feature = 'eval' | 53 | feature = 'eval' |
640 | 54 | 54 | ||
641 | 55 | permission = u'eval' | 55 | permission = u'eval' |
642 | @@ -62,4 +62,4 @@ | |||
643 | 62 | except Exception, e: | 62 | except Exception, e: |
644 | 63 | result = e | 63 | result = e |
645 | 64 | 64 | ||
647 | 65 | event.addresponse(str(result)) | 65 | event.addresponse(unicode(result)) |
648 | 66 | 66 | ||
649 | === modified file 'ibid/plugins/factoid.py' | |||
650 | --- ibid/plugins/factoid.py 2009-02-23 20:29:44 +0000 | |||
651 | +++ ibid/plugins/factoid.py 2009-03-01 23:01:30 +0000 | |||
652 | @@ -12,7 +12,9 @@ | |||
653 | 12 | from ibid.plugins.identity import get_identities | 12 | from ibid.plugins.identity import get_identities |
654 | 13 | from ibid.models import Base | 13 | from ibid.models import Base |
655 | 14 | 14 | ||
657 | 15 | help = {'factoids': u'Factoids are arbitrary pieces of information stored by a key.'} | 15 | help = {'factoids': u'Factoids are arbitrary pieces of information stored by a key. ' + |
658 | 16 | u'Factoids beginning with a command such as "<action>" or "<reply>" will supress the "name verb value" output. ' + | ||
659 | 17 | u'Search searches the keys. Scan searches the values.'} | ||
660 | 16 | 18 | ||
661 | 17 | log = logging.getLogger('plugins.factoid') | 19 | log = logging.getLogger('plugins.factoid') |
662 | 18 | 20 | ||
663 | @@ -85,7 +87,7 @@ | |||
664 | 85 | return factoid or query.order_by(func.random()).first() | 87 | return factoid or query.order_by(func.random()).first() |
665 | 86 | 88 | ||
666 | 87 | class Utils(Processor): | 89 | class Utils(Processor): |
668 | 88 | """literal <name> [starting at <number>]""" | 90 | u"""literal <name> [starting from <number>]""" |
669 | 89 | feature = 'factoids' | 91 | feature = 'factoids' |
670 | 90 | 92 | ||
671 | 91 | @match(r'^literal\s+(.+?)(?:\s+start(?:ing)?\s+(?:from\s+)?(\d+))?$') | 93 | @match(r'^literal\s+(.+?)(?:\s+start(?:ing)?\s+(?:from\s+)?(\d+))?$') |
672 | @@ -99,7 +101,8 @@ | |||
673 | 99 | session.close() | 101 | session.close() |
674 | 100 | 102 | ||
675 | 101 | class Forget(Processor): | 103 | class Forget(Processor): |
677 | 102 | """forget <name>""" | 104 | u"""forget <name> |
678 | 105 | <name> is the same as <other name>""" | ||
679 | 103 | feature = 'factoids' | 106 | feature = 'factoids' |
680 | 104 | 107 | ||
681 | 105 | permission = u'factoid' | 108 | permission = u'factoid' |
682 | @@ -172,7 +175,7 @@ | |||
683 | 172 | event.addresponse(u"I don't know about %s" % name) | 175 | event.addresponse(u"I don't know about %s" % name) |
684 | 173 | 176 | ||
685 | 174 | class Search(Processor): | 177 | class Search(Processor): |
687 | 175 | """(search|scan) for <pattern>""" | 178 | u"""(search|scan) for <pattern> [from <start>]""" |
688 | 176 | feature = 'factoids' | 179 | feature = 'factoids' |
689 | 177 | 180 | ||
690 | 178 | limit = IntOption('search_limit', u'Maximum number of results to return', 30) | 181 | limit = IntOption('search_limit', u'Maximum number of results to return', 30) |
691 | @@ -198,7 +201,7 @@ | |||
692 | 198 | event.addresponse(u"I couldn't find anything with that name") | 201 | event.addresponse(u"I couldn't find anything with that name") |
693 | 199 | 202 | ||
694 | 200 | class Get(Processor, RPC): | 203 | class Get(Processor, RPC): |
696 | 201 | """<factoid> [( #<number> | /<pattern>/ )]""" | 204 | u"""<factoid> [( #<number> | /<pattern>/ )]""" |
697 | 202 | feature = 'factoids' | 205 | feature = 'factoids' |
698 | 203 | 206 | ||
699 | 204 | verbs = verbs | 207 | verbs = verbs |
700 | @@ -265,8 +268,7 @@ | |||
701 | 265 | return reply | 268 | return reply |
702 | 266 | 269 | ||
703 | 267 | class Set(Processor): | 270 | class Set(Processor): |
706 | 268 | """<name> (<verb>|=<verb>=) <value> | 271 | u"""<name> (<verb>|=<verb>=) [also] <value>""" |
705 | 269 | <name> is the same as <name>""" | ||
707 | 270 | feature = 'factoids' | 272 | feature = 'factoids' |
708 | 271 | 273 | ||
709 | 272 | verbs = verbs | 274 | verbs = verbs |
710 | 273 | 275 | ||
711 | === modified file 'ibid/plugins/feeds.py' | |||
712 | --- ibid/plugins/feeds.py 2009-02-23 20:29:44 +0000 | |||
713 | +++ ibid/plugins/feeds.py 2009-03-01 23:01:30 +0000 | |||
714 | @@ -44,7 +44,7 @@ | |||
715 | 44 | self.entries = self.feed['entries'] | 44 | self.entries = self.feed['entries'] |
716 | 45 | 45 | ||
717 | 46 | class Manage(Processor): | 46 | class Manage(Processor): |
719 | 47 | """add feed <url> as <name> | 47 | u"""add feed <url> as <name> |
720 | 48 | list feeds | 48 | list feeds |
721 | 49 | remove <name> feed""" | 49 | remove <name> feed""" |
722 | 50 | feature = 'feeds' | 50 | feature = 'feeds' |
723 | @@ -72,7 +72,7 @@ | |||
724 | 72 | 72 | ||
725 | 73 | session.close() | 73 | session.close() |
726 | 74 | 74 | ||
728 | 75 | @match(r'^list\s+feeds$') | 75 | @match(r'^(?:list\s+)?feeds$') |
729 | 76 | def list(self, event): | 76 | def list(self, event): |
730 | 77 | session = ibid.databases.ibid() | 77 | session = ibid.databases.ibid() |
731 | 78 | feeds = session.query(Feed).all() | 78 | feeds = session.query(Feed).all() |
732 | @@ -98,7 +98,7 @@ | |||
733 | 98 | session.close() | 98 | session.close() |
734 | 99 | 99 | ||
735 | 100 | class Retrieve(Processor): | 100 | class Retrieve(Processor): |
737 | 101 | """(latest|last) [ <count> ] articles from <name> [ starting [(at|from)] <number> ] | 101 | u"""latest [ <count> ] articles from <name> [ starting at <number> ] |
738 | 102 | article ( <number> | /<pattern>/ ) from <name>""" | 102 | article ( <number> | /<pattern>/ ) from <name>""" |
739 | 103 | feature = 'feeds' | 103 | feature = 'feeds' |
740 | 104 | 104 | ||
741 | 105 | 105 | ||
742 | === modified file 'ibid/plugins/google.py' | |||
743 | --- ibid/plugins/google.py 2009-02-12 20:58:39 +0000 | |||
744 | +++ ibid/plugins/google.py 2009-03-01 23:01:30 +0000 | |||
745 | @@ -5,12 +5,12 @@ | |||
746 | 5 | from ibid.plugins import Processor, match | 5 | from ibid.plugins import Processor, match |
747 | 6 | from ibid.config import Option | 6 | from ibid.config import Option |
748 | 7 | 7 | ||
750 | 8 | help = {'google': 'Retrieves results from Google and Google Calculator.'} | 8 | help = {'google': u'Retrieves results from Google and Google Calculator.'} |
751 | 9 | 9 | ||
752 | 10 | user_agent = 'Mozilla/5.0' | 10 | user_agent = 'Mozilla/5.0' |
753 | 11 | 11 | ||
754 | 12 | class Search(Processor): | 12 | class Search(Processor): |
756 | 13 | """google [for] <term>""" | 13 | u"""google [for] <term>""" |
757 | 14 | feature = 'google' | 14 | feature = 'google' |
758 | 15 | 15 | ||
759 | 16 | user_agent = Option('user_agent', 'HTTP user agent to present to Google', user_agent) | 16 | user_agent = Option('user_agent', 'HTTP user agent to present to Google', user_agent) |
760 | @@ -21,7 +21,6 @@ | |||
761 | 21 | if country: | 21 | if country: |
762 | 22 | url = url + '&meta=cr%%3Dcountry%s' % country.upper() | 22 | url = url + '&meta=cr%%3Dcountry%s' % country.upper() |
763 | 23 | 23 | ||
764 | 24 | print self.user_agent | ||
765 | 25 | f = urlopen(Request(url, headers={'user-agent': self.user_agent})) | 24 | f = urlopen(Request(url, headers={'user-agent': self.user_agent})) |
766 | 26 | soup = BeautifulSoup(f.read()) | 25 | soup = BeautifulSoup(f.read()) |
767 | 27 | f.close() | 26 | f.close() |
768 | @@ -31,15 +30,15 @@ | |||
769 | 31 | for item in items: | 30 | for item in items: |
770 | 32 | try: | 31 | try: |
771 | 33 | url = item.a['href'] | 32 | url = item.a['href'] |
774 | 34 | title = ''.join([e.string for e in item.a.contents]) | 33 | title = u''.join([e.string for e in item.a.contents]) |
775 | 35 | results.append('"%s" %s' % (title, url)) | 34 | results.append(u'"%s" %s' % (title, url)) |
776 | 36 | except Exception: | 35 | except Exception: |
777 | 37 | pass | 36 | pass |
778 | 38 | 37 | ||
780 | 39 | event.addresponse(', '.join(results)) | 38 | event.addresponse(u', '.join(results)) |
781 | 40 | 39 | ||
782 | 41 | class Calc(Processor): | 40 | class Calc(Processor): |
784 | 42 | """gcalc <expression>""" | 41 | u"""gcalc <expression>""" |
785 | 43 | feature = 'google' | 42 | feature = 'google' |
786 | 44 | 43 | ||
787 | 45 | user_agent = Option('user_agent', 'HTTP user agent to present to Google', user_agent) | 44 | user_agent = Option('user_agent', 'HTTP user agent to present to Google', user_agent) |
788 | @@ -57,7 +56,7 @@ | |||
789 | 57 | event.addresponse(font.b.string) | 56 | event.addresponse(font.b.string) |
790 | 58 | 57 | ||
791 | 59 | class Define(Processor): | 58 | class Define(Processor): |
793 | 60 | """gdefine <term>""" | 59 | u"""gdefine <term>""" |
794 | 61 | feature = 'google' | 60 | feature = 'google' |
795 | 62 | 61 | ||
796 | 63 | user_agent = Option('user_agent', 'HTTP user agent to present to Google', user_agent) | 62 | user_agent = Option('user_agent', 'HTTP user agent to present to Google', user_agent) |
797 | @@ -70,7 +69,7 @@ | |||
798 | 70 | 69 | ||
799 | 71 | definitions = [] | 70 | definitions = [] |
800 | 72 | for li in soup.findAll('li'): | 71 | for li in soup.findAll('li'): |
802 | 73 | definitions.append('"%s"' % li.contents[0]) | 72 | definitions.append('"%s"' % li.contents[0].strip()) |
803 | 74 | 73 | ||
804 | 75 | if definitions: | 74 | if definitions: |
805 | 76 | event.addresponse(', '.join(definitions)) | 75 | event.addresponse(', '.join(definitions)) |
806 | @@ -78,7 +77,7 @@ | |||
807 | 78 | event.addresponse(u"Are you making up words again?") | 77 | event.addresponse(u"Are you making up words again?") |
808 | 79 | 78 | ||
809 | 80 | class Compare(Processor): | 79 | class Compare(Processor): |
811 | 81 | """google cmp [for] <term> and <term>""" | 80 | u"""google cmp [for] <term> and <term>""" |
812 | 82 | feature = 'google' | 81 | feature = 'google' |
813 | 83 | 82 | ||
814 | 84 | user_agent = Option('user_agent', 'HTTP user agent to present to Google', user_agent) | 83 | user_agent = Option('user_agent', 'HTTP user agent to present to Google', user_agent) |
815 | 85 | 84 | ||
816 | === modified file 'ibid/plugins/help.py' | |||
817 | --- ibid/plugins/help.py 2009-02-21 12:31:38 +0000 | |||
818 | +++ ibid/plugins/help.py 2009-03-01 23:01:30 +0000 | |||
819 | @@ -3,10 +3,12 @@ | |||
820 | 3 | import ibid | 3 | import ibid |
821 | 4 | from ibid.plugins import Processor, match | 4 | from ibid.plugins import Processor, match |
822 | 5 | 5 | ||
824 | 6 | help = {'help': 'Provides help and usage information about plugins.'} | 6 | help = {'help': u'Provides help and usage information about plugins.'} |
825 | 7 | 7 | ||
826 | 8 | class Help(Processor): | 8 | class Help(Processor): |
828 | 9 | """(help|usage) [<feature>]""" | 9 | u"""features |
829 | 10 | help [<feature>] | ||
830 | 11 | usage <feature>""" | ||
831 | 10 | feature = 'help' | 12 | feature = 'help' |
832 | 11 | 13 | ||
833 | 12 | @match(r'^help$') | 14 | @match(r'^help$') |
834 | 13 | 15 | ||
835 | === modified file 'ibid/plugins/http.py' | |||
836 | --- ibid/plugins/http.py 2009-02-03 18:03:49 +0000 | |||
837 | +++ ibid/plugins/http.py 2009-03-01 23:01:30 +0000 | |||
838 | @@ -8,15 +8,18 @@ | |||
839 | 8 | 8 | ||
840 | 9 | title = re.compile(r'<title>(.*)<\/title>', re.I+re.S) | 9 | title = re.compile(r'<title>(.*)<\/title>', re.I+re.S) |
841 | 10 | 10 | ||
843 | 11 | help['get'] = 'Retrieves a URL and returns the HTTP status and optionally the HTML title.' | 11 | help['get'] = u'Retrieves a URL and returns the HTTP status and optionally the HTML title.' |
844 | 12 | class HTTP(Processor): | 12 | class HTTP(Processor): |
846 | 13 | """(get|head) <url>""" | 13 | u"""(get|head) <url>""" |
847 | 14 | feature = 'get' | 14 | feature = 'get' |
848 | 15 | 15 | ||
849 | 16 | max_size = IntOption('max_size', 'Only request this many bytes', 500) | 16 | max_size = IntOption('max_size', 'Only request this many bytes', 500) |
850 | 17 | 17 | ||
851 | 18 | @match(r'^(get|head)\s+(.+)$') | 18 | @match(r'^(get|head)\s+(.+)$') |
852 | 19 | def handler(self, event, action, url): | 19 | def handler(self, event, action, url): |
853 | 20 | if not url.lower().startswith("http://") and not url.lower().startswith("https://"): | ||
854 | 21 | url = "http://" + url | ||
855 | 22 | |||
856 | 20 | http = Http() | 23 | http = Http() |
857 | 21 | headers={} | 24 | headers={} |
858 | 22 | if action.lower() == 'get': | 25 | if action.lower() == 'get': |
859 | 23 | 26 | ||
860 | === modified file 'ibid/plugins/identity.py' | |||
861 | --- ibid/plugins/identity.py 2009-02-23 20:43:40 +0000 | |||
862 | +++ ibid/plugins/identity.py 2009-03-01 23:01:30 +0000 | |||
863 | @@ -16,7 +16,7 @@ | |||
864 | 16 | 16 | ||
865 | 17 | help['accounts'] = u'An account represents a person. An account has one or more identities, which is a user on a specific source.' | 17 | help['accounts'] = u'An account represents a person. An account has one or more identities, which is a user on a specific source.' |
866 | 18 | class Accounts(Processor): | 18 | class Accounts(Processor): |
868 | 19 | """create account <name>""" | 19 | u"""create account <name>""" |
869 | 20 | feature = 'accounts' | 20 | feature = 'accounts' |
870 | 21 | 21 | ||
871 | 22 | @match(r'^create\s+account\s+(.+)$') | 22 | @match(r'^create\s+account\s+(.+)$') |
872 | @@ -56,7 +56,7 @@ | |||
873 | 56 | chars = string.letters + string.digits | 56 | chars = string.letters + string.digits |
874 | 57 | 57 | ||
875 | 58 | class Identities(Processor): | 58 | class Identities(Processor): |
877 | 59 | """(I|<username>) (am|is) <identity> on <source> | 59 | u"""(I am|<username> is) <identity> on <source> |
878 | 60 | remove identity <identity> on <source> [from <username>]""" | 60 | remove identity <identity> on <source> [from <username>]""" |
879 | 61 | feature = 'accounts' | 61 | feature = 'accounts' |
880 | 62 | priority = -10 | 62 | priority = -10 |
881 | @@ -179,9 +179,8 @@ | |||
882 | 179 | 179 | ||
883 | 180 | session.close() | 180 | session.close() |
884 | 181 | 181 | ||
885 | 182 | help['attributes'] = 'Adds and removes attributes attached to an account' | ||
886 | 183 | class Attributes(Processor): | 182 | class Attributes(Processor): |
888 | 184 | """set (my|<account>) <name> to <value>""" | 183 | u"""set (my|<account>) <name> to <value>""" |
889 | 185 | feature = 'accounts' | 184 | feature = 'accounts' |
890 | 186 | 185 | ||
891 | 187 | @match(r"^set\s+(my|.+?)(?:\'s)?\s+(.+)\s+to\s+(.+)$") | 186 | @match(r"^set\s+(my|.+?)(?:\'s)?\s+(.+)\s+to\s+(.+)$") |
892 | @@ -213,6 +212,8 @@ | |||
893 | 213 | log.info(u"Added attribute '%s' = '%s' to account %s (%s) by %s/%s (%s)", name, value, account.id, account.username, event.account, event.identity, event.sender['connection']) | 212 | log.info(u"Added attribute '%s' = '%s' to account %s (%s) by %s/%s (%s)", name, value, account.id, account.username, event.account, event.identity, event.sender['connection']) |
894 | 214 | 213 | ||
895 | 215 | class Describe(Processor): | 214 | class Describe(Processor): |
896 | 215 | u"""who (am I|is <username>)""" | ||
897 | 216 | feature = "accounts" | ||
898 | 216 | 217 | ||
899 | 217 | @match(r'^who\s+(?:is|am)\s+(I|.+?)$') | 218 | @match(r'^who\s+(?:is|am)\s+(I|.+?)$') |
900 | 218 | def describe(self, event, username): | 219 | def describe(self, event, username): |
901 | 219 | 220 | ||
902 | === modified file 'ibid/plugins/imdb.py' | |||
903 | --- ibid/plugins/imdb.py 2009-02-23 14:59:37 +0000 | |||
904 | +++ ibid/plugins/imdb.py 2009-03-01 23:01:30 +0000 | |||
905 | @@ -6,14 +6,17 @@ | |||
906 | 6 | from .. imdb import IMDb, IMDbDataAccessError, IMDbError | 6 | from .. imdb import IMDb, IMDbDataAccessError, IMDbError |
907 | 7 | 7 | ||
908 | 8 | from ibid.plugins import Processor, match | 8 | from ibid.plugins import Processor, match |
910 | 9 | from ibid.config import Option, IntOption | 9 | from ibid.config import Option, BoolOption |
911 | 10 | 10 | ||
913 | 11 | help = {'imdb': 'Looks up movies on IMDB.com.'} | 11 | help = {'imdb': u'Looks up movies on IMDB.com.'} |
914 | 12 | 12 | ||
915 | 13 | class IMDB(Processor): | 13 | class IMDB(Processor): |
917 | 14 | "imdb [search] [character|company|episode|movie|person] <terms> [result <index>]" | 14 | u"imdb [search] [character|company|episode|movie|person] <terms> [#<index>]" |
918 | 15 | feature = 'imdb' | 15 | feature = 'imdb' |
919 | 16 | 16 | ||
920 | 17 | access_system = Option("accesssystem", "Method of querying IMDB", "http") | ||
921 | 18 | adult_search = BoolOption("adultsearch", "Include adult films in search results", True) | ||
922 | 19 | |||
923 | 17 | name_keys = { | 20 | name_keys = { |
924 | 18 | "character": "long imdb name", | 21 | "character": "long imdb name", |
925 | 19 | "company": "long imdb name", | 22 | "company": "long imdb name", |
926 | @@ -23,10 +26,9 @@ | |||
927 | 23 | } | 26 | } |
928 | 24 | 27 | ||
929 | 25 | def setup(self): | 28 | def setup(self): |
932 | 26 | # adultSearch = 1 is the default, but we expose this parameter for bot-owners to tweak. | 29 | self.imdb = IMDb(accessSystem=self.access_system, adultSearch=int(self.adult_search)) |
931 | 27 | self.imdb = IMDb(accessSystem='http', adultSearch=1) | ||
933 | 28 | 30 | ||
935 | 29 | @match(r'^imdb(?:\s+search)?(?:\s+(character|company|episode|movie|person))?\s+(.+?)(?:\s+result\s+(\d+))?$') | 31 | @match(r'^imdb(?:\s+search)?(?:\s+(character|company|episode|movie|person))?\s+(.+?)(?:\s+#(\d+))?$') |
936 | 30 | def search(self, event, search_type, terms, index): | 32 | def search(self, event, search_type, terms, index): |
937 | 31 | if search_type is None: | 33 | if search_type is None: |
938 | 32 | search_type = "movie" | 34 | search_type = "movie" |
939 | @@ -60,7 +62,7 @@ | |||
940 | 60 | return | 62 | return |
941 | 61 | 63 | ||
942 | 62 | if len(results) == 0: | 64 | if len(results) == 0: |
944 | 63 | event.addresponse(u"Sorry, couldn't find that. You sure you know how to spell?") | 65 | event.addresponse(u"Sorry, couldn't find that.") |
945 | 64 | else: | 66 | else: |
946 | 65 | results = [x[self.name_keys[search_type]] for x in results] | 67 | results = [x[self.name_keys[search_type]] for x in results] |
947 | 66 | results = enumerate(results) | 68 | results = enumerate(results) |
948 | @@ -99,7 +101,7 @@ | |||
949 | 99 | desc += u" Starring: %s." % (u", ".join(x["name"] for x in episode["cast"][:3])) | 101 | desc += u" Starring: %s." % (u", ".join(x["name"] for x in episode["cast"][:3])) |
950 | 100 | if episode.has_key("rating"): | 102 | if episode.has_key("rating"): |
951 | 101 | desc += u" Rated: %.1f " % episode["rating"] | 103 | desc += u" Rated: %.1f " % episode["rating"] |
953 | 102 | desc += u", ".join(movie.get("genres", ())) | 104 | desc += u", ".join(episode.get("genres", ())) |
954 | 103 | desc += u" Plot: %s" % episode.get("plot outline", u"Unknown") | 105 | desc += u" Plot: %s" % episode.get("plot outline", u"Unknown") |
955 | 104 | return desc | 106 | return desc |
956 | 105 | 107 | ||
957 | @@ -116,12 +118,7 @@ | |||
958 | 116 | return desc | 118 | return desc |
959 | 117 | 119 | ||
960 | 118 | def display_person(self, person): | 120 | def display_person(self, person): |
967 | 119 | # Quite a few fields are normally repeated in the bio, so we won't bother including them. | 121 | desc = u"%s: %s. %s." % (person.personID, person["name"], |
962 | 120 | #desc = u"%s: %s, Born " % (person.personID, person["name"]) | ||
963 | 121 | #if person["birth name"] != person["name"]: | ||
964 | 122 | # desc += u"%s " % person["birth name"] | ||
965 | 123 | #desc += u"%s. %s" % (person["birth date"], u" ".join(person["mini biography"])) | ||
966 | 124 | return u"%s: %s. %s. Bio: %s" % (person.personID, person["name"], | ||
968 | 125 | u", ".join(role.title() for role in ( | 122 | u", ".join(role.title() for role in ( |
969 | 126 | u"actor", u"animation department", u"art department", | 123 | u"actor", u"animation department", u"art department", |
970 | 127 | u"art director", u"assistant director", u"camera department", | 124 | u"art director", u"assistant director", u"camera department", |
971 | @@ -132,6 +129,12 @@ | |||
972 | 132 | u"production designer", u"set decorator", u"sound department", | 129 | u"production designer", u"set decorator", u"sound department", |
973 | 133 | u"speccial effects department", u"stunts", u"transport department", | 130 | u"speccial effects department", u"stunts", u"transport department", |
974 | 134 | u"visual effects department", u"writer", u"miscellaneous crew" | 131 | u"visual effects department", u"writer", u"miscellaneous crew" |
976 | 135 | ) if person.has_key(role)), u" ".join(person["mini biography"])) | 132 | ) if person.has_key(role))) |
977 | 133 | if person.has_key("mini biography"): | ||
978 | 134 | desc += u" " + u" ".join(person["mini biography"]) | ||
979 | 135 | else: | ||
980 | 136 | if person.has_key("birth name") or person.has_key("birth date"): | ||
981 | 137 | desc += u" Born %s." % u", ".join(person[attr] for attr in ("birth name", "birth date") if person.has_key(attr)) | ||
982 | 138 | return desc | ||
983 | 136 | 139 | ||
984 | 137 | # vi: set et sta sw=4 ts=4: | 140 | # vi: set et sta sw=4 ts=4: |
985 | 138 | 141 | ||
986 | === modified file 'ibid/plugins/info.py' | |||
987 | --- ibid/plugins/info.py 2009-02-23 20:29:44 +0000 | |||
988 | +++ ibid/plugins/info.py 2009-03-01 19:58:06 +0000 | |||
989 | @@ -1,15 +1,17 @@ | |||
990 | 1 | from subprocess import Popen, PIPE | 1 | from subprocess import Popen, PIPE |
991 | 2 | import os | ||
992 | 2 | 3 | ||
993 | 3 | from nickometer import nickometer | 4 | from nickometer import nickometer |
994 | 4 | 5 | ||
995 | 5 | from ibid.plugins import Processor, match, RPC | 6 | from ibid.plugins import Processor, match, RPC |
996 | 6 | from ibid.config import Option | 7 | from ibid.config import Option |
997 | 8 | from ibid.utils import file_in_path, unicode_output | ||
998 | 7 | 9 | ||
999 | 8 | help = {} | 10 | help = {} |
1000 | 9 | 11 | ||
1001 | 10 | help['fortune'] = u'Returns a random fortune.' | 12 | help['fortune'] = u'Returns a random fortune.' |
1002 | 11 | class Fortune(Processor, RPC): | 13 | class Fortune(Processor, RPC): |
1004 | 12 | """fortune""" | 14 | u"""fortune""" |
1005 | 13 | feature = 'fortune' | 15 | feature = 'fortune' |
1006 | 14 | 16 | ||
1007 | 15 | fortune = Option('fortune', 'Path of the fortune executable', 'fortune') | 17 | fortune = Option('fortune', 'Path of the fortune executable', 'fortune') |
1008 | @@ -18,6 +20,10 @@ | |||
1009 | 18 | super(Fortune, self).__init__(name) | 20 | super(Fortune, self).__init__(name) |
1010 | 19 | RPC.__init__(self) | 21 | RPC.__init__(self) |
1011 | 20 | 22 | ||
1012 | 23 | def setup(self): | ||
1013 | 24 | if not file_in_path(self.fortune): | ||
1014 | 25 | raise Exception("Cannot locate fortune executeable") | ||
1015 | 26 | |||
1016 | 21 | @match(r'^fortune$') | 27 | @match(r'^fortune$') |
1017 | 22 | def handler(self, event): | 28 | def handler(self, event): |
1018 | 23 | event.addresponse(self.remote_fortune() or u"Couldn't execute fortune") | 29 | event.addresponse(self.remote_fortune() or u"Couldn't execute fortune") |
1019 | @@ -27,14 +33,16 @@ | |||
1020 | 27 | output, error = fortune.communicate() | 33 | output, error = fortune.communicate() |
1021 | 28 | code = fortune.wait() | 34 | code = fortune.wait() |
1022 | 29 | 35 | ||
1023 | 36 | output = unicode_output(output.strip()) | ||
1024 | 37 | |||
1025 | 30 | if code == 0: | 38 | if code == 0: |
1027 | 31 | return output.strip() | 39 | return output |
1028 | 32 | else: | 40 | else: |
1029 | 33 | return None | 41 | return None |
1030 | 34 | 42 | ||
1031 | 35 | help['nickometer'] = u'Calculates how lame a nick is.' | 43 | help['nickometer'] = u'Calculates how lame a nick is.' |
1032 | 36 | class Nickometer(Processor): | 44 | class Nickometer(Processor): |
1034 | 37 | """nickometer [<nick>] [with reasons]""" | 45 | u"""nickometer [<nick>] [with reasons]""" |
1035 | 38 | feature = 'nickometer' | 46 | feature = 'nickometer' |
1036 | 39 | 47 | ||
1037 | 40 | @match(r'^(?:nick|lame)-?o-?meter(?:(?:\s+for)?\s+(.+?))?(\s+with\s+reasons)?$') | 48 | @match(r'^(?:nick|lame)-?o-?meter(?:(?:\s+for)?\s+(.+?))?(\s+with\s+reasons)?$') |
1038 | @@ -47,30 +55,42 @@ | |||
1039 | 47 | 55 | ||
1040 | 48 | help['man'] = u'Retrieves information from manpages.' | 56 | help['man'] = u'Retrieves information from manpages.' |
1041 | 49 | class Man(Processor): | 57 | class Man(Processor): |
1043 | 50 | """man [<section>] <page>""" | 58 | u"""man [<section>] <page>""" |
1044 | 51 | feature = 'man' | 59 | feature = 'man' |
1045 | 52 | 60 | ||
1046 | 53 | man = Option('man', 'Path of the man executable', 'man') | 61 | man = Option('man', 'Path of the man executable', 'man') |
1047 | 54 | 62 | ||
1048 | 63 | def setup(self): | ||
1049 | 64 | if not file_in_path(self.man): | ||
1050 | 65 | raise Exception("Cannot locate man executeable") | ||
1051 | 66 | |||
1052 | 55 | @match(r'^man\s+(?:(\d)\s+)?(\S+)$') | 67 | @match(r'^man\s+(?:(\d)\s+)?(\S+)$') |
1053 | 56 | def handle_man(self, event, section, page): | 68 | def handle_man(self, event, section, page): |
1054 | 57 | command = [self.man, page] | 69 | command = [self.man, page] |
1055 | 58 | if section: | 70 | if section: |
1056 | 59 | command.insert(1, section) | 71 | command.insert(1, section) |
1058 | 60 | man = Popen(command, stdout=PIPE, stderr=PIPE) | 72 | |
1059 | 73 | if page.strip().startswith("-"): | ||
1060 | 74 | event.addresponse(False) | ||
1061 | 75 | return | ||
1062 | 76 | |||
1063 | 77 | env = os.environ.copy() | ||
1064 | 78 | env["COLUMNS"] = "500" | ||
1065 | 79 | |||
1066 | 80 | man = Popen(command, stdout=PIPE, stderr=PIPE, env=env) | ||
1067 | 61 | output, error = man.communicate() | 81 | output, error = man.communicate() |
1068 | 62 | code = man.wait() | 82 | code = man.wait() |
1069 | 63 | 83 | ||
1070 | 64 | if code != 0: | 84 | if code != 0: |
1071 | 65 | event.addresponse(u'Manpage not found') | 85 | event.addresponse(u'Manpage not found') |
1072 | 66 | else: | 86 | else: |
1081 | 67 | lines = [unicode(line, 'utf-8', errors='replace') for line in output.splitlines()] | 87 | output = unicode_output(output.strip(), errors="replace") |
1082 | 68 | index = lines.index('NAME') | 88 | output = output.splitlines() |
1083 | 69 | if index: | 89 | index = output.index('NAME') |
1084 | 70 | event.addresponse(lines[index+1].strip()) | 90 | if index: |
1085 | 71 | index = lines.index('SYNOPSIS') | 91 | event.addresponse(output[index+1].strip()) |
1086 | 72 | if index: | 92 | index = output.index('SYNOPSIS') |
1087 | 73 | event.addresponse(lines[index+1].strip()) | 93 | if index: |
1088 | 74 | 94 | event.addresponse(output[index+1].strip()) | |
1089 | 75 | 95 | ||
1090 | 76 | # vi: set et sta sw=4 ts=4: | 96 | # vi: set et sta sw=4 ts=4: |
1091 | 77 | 97 | ||
1092 | === modified file 'ibid/plugins/irc.py' | |||
1093 | --- ibid/plugins/irc.py 2009-02-12 19:59:13 +0000 | |||
1094 | +++ ibid/plugins/irc.py 2009-03-01 23:01:30 +0000 | |||
1095 | @@ -3,10 +3,10 @@ | |||
1096 | 3 | import ibid | 3 | import ibid |
1097 | 4 | from ibid.plugins import Processor, match, authorise | 4 | from ibid.plugins import Processor, match, authorise |
1098 | 5 | 5 | ||
1100 | 6 | help = {"irc": "Provides commands for joining/parting channels on IRC and Jabber, and changing the bot's nick"} | 6 | help = {"irc": u"Provides commands for joining/parting channels on IRC and Jabber, and changing the bot's nick"} |
1101 | 7 | 7 | ||
1102 | 8 | class Actions(Processor): | 8 | class Actions(Processor): |
1104 | 9 | """(join|part|leave) [<channel> [on <source>]] | 9 | u"""(join|part|leave) [<channel> [on <source>]] |
1105 | 10 | change nick to <nick> [on <source>]""" | 10 | change nick to <nick> [on <source>]""" |
1106 | 11 | feature = 'irc' | 11 | feature = 'irc' |
1107 | 12 | 12 | ||
1108 | @@ -24,6 +24,10 @@ | |||
1109 | 24 | return | 24 | return |
1110 | 25 | channel = event.channel | 25 | channel = event.channel |
1111 | 26 | 26 | ||
1112 | 27 | if source.lower() not in ibid.sources: | ||
1113 | 28 | event.addresponse(u"I don't have a source called %s" % source.lower()) | ||
1114 | 29 | return | ||
1115 | 30 | |||
1116 | 27 | source = ibid.sources[source.lower()] | 31 | source = ibid.sources[source.lower()] |
1117 | 28 | 32 | ||
1118 | 29 | if not hasattr(source, 'join'): | 33 | if not hasattr(source, 'join'): |
1119 | @@ -43,6 +47,11 @@ | |||
1120 | 43 | 47 | ||
1121 | 44 | if not source: | 48 | if not source: |
1122 | 45 | source = event.source | 49 | source = event.source |
1123 | 50 | |||
1124 | 51 | if source.lower() not in ibid.sources: | ||
1125 | 52 | event.addresponse(u"I don't have a source called %s" % source.lower()) | ||
1126 | 53 | return | ||
1127 | 54 | |||
1128 | 46 | source = ibid.sources[source.lower()] | 55 | source = ibid.sources[source.lower()] |
1129 | 47 | 56 | ||
1130 | 48 | if not hasattr(source, 'change_nick'): | 57 | if not hasattr(source, 'change_nick'): |
1131 | 49 | 58 | ||
1132 | === modified file 'ibid/plugins/karma.py' | |||
1133 | --- ibid/plugins/karma.py 2009-02-23 20:29:44 +0000 | |||
1134 | +++ ibid/plugins/karma.py 2009-03-01 23:01:30 +0000 | |||
1135 | @@ -28,9 +28,12 @@ | |||
1136 | 28 | self.value = 0 | 28 | self.value = 0 |
1137 | 29 | 29 | ||
1138 | 30 | class Set(Processor): | 30 | class Set(Processor): |
1140 | 31 | """<subject> (++|--|==|ftw|ftl) [[reason]]""" | 31 | u"""<subject> (++|--|==|ftw|ftl) [[reason]]""" |
1141 | 32 | feature = 'karma' | 32 | feature = 'karma' |
1142 | 33 | 33 | ||
1143 | 34 | # Clashes with morse | ||
1144 | 35 | priority = 10 | ||
1145 | 36 | |||
1146 | 34 | permission = u'karma' | 37 | permission = u'karma' |
1147 | 35 | 38 | ||
1148 | 36 | increase = Option('increase', 'Suffixes which indicate increased karma', ('++', 'ftw')) | 39 | increase = Option('increase', 'Suffixes which indicate increased karma', ('++', 'ftw')) |
1149 | @@ -85,7 +88,7 @@ | |||
1150 | 85 | event.processed = True | 88 | event.processed = True |
1151 | 86 | 89 | ||
1152 | 87 | class Get(Processor): | 90 | class Get(Processor): |
1154 | 88 | """karma for <subject> | 91 | u"""karma for <subject> |
1155 | 89 | [reverse] karmaladder""" | 92 | [reverse] karmaladder""" |
1156 | 90 | feature = 'karma' | 93 | feature = 'karma' |
1157 | 91 | 94 | ||
1158 | 92 | 95 | ||
1159 | === modified file 'ibid/plugins/lookup.py' | |||
1160 | --- ibid/plugins/lookup.py 2009-02-22 10:37:32 +0000 | |||
1161 | +++ ibid/plugins/lookup.py 2009-03-01 23:01:30 +0000 | |||
1162 | @@ -14,7 +14,12 @@ | |||
1163 | 14 | 14 | ||
1164 | 15 | help = {} | 15 | help = {} |
1165 | 16 | 16 | ||
1166 | 17 | help["lookup"] = u"Lookup things on popular sites." | ||
1167 | 18 | |||
1168 | 17 | class Bash(Processor): | 19 | class Bash(Processor): |
1169 | 20 | u"bash[.org] (random|<number>)" | ||
1170 | 21 | |||
1171 | 22 | feature = "lookup" | ||
1172 | 18 | 23 | ||
1173 | 19 | @match(r'^bash(?:\.org)?\s+(random|\d+)$') | 24 | @match(r'^bash(?:\.org)?\s+(random|\d+)$') |
1174 | 20 | def bash(self, event, quote): | 25 | def bash(self, event, quote): |
1175 | @@ -22,15 +27,23 @@ | |||
1176 | 22 | soup = BeautifulSoup(f.read(), convertEntities=BeautifulSoup.HTML_ENTITIES) | 27 | soup = BeautifulSoup(f.read(), convertEntities=BeautifulSoup.HTML_ENTITIES) |
1177 | 23 | f.close() | 28 | f.close() |
1178 | 24 | 29 | ||
1179 | 30 | if quote.lower() == "random": | ||
1180 | 31 | number = u"".join(soup.find('p', attrs={'class': 'quote'}).find('b').contents) | ||
1181 | 32 | event.addresponse(u"%s:" % number) | ||
1182 | 33 | |||
1183 | 25 | quote = soup.find('p', attrs={'class': 'qt'}) | 34 | quote = soup.find('p', attrs={'class': 'qt'}) |
1184 | 26 | if not quote: | 35 | if not quote: |
1185 | 27 | event.addresponse(u"There's no such quote, but if you keep talking like that maybe there will be.") | 36 | event.addresponse(u"There's no such quote, but if you keep talking like that maybe there will be.") |
1186 | 28 | else: | 37 | else: |
1187 | 29 | for line in quote.contents: | 38 | for line in quote.contents: |
1188 | 30 | if str(line) != '<br />': | 39 | if str(line) != '<br />': |
1190 | 31 | event.addresponse(str(line).strip()) | 40 | event.addresponse(unicode(line).strip()) |
1191 | 32 | 41 | ||
1192 | 33 | class LastFm(Processor): | 42 | class LastFm(Processor): |
1193 | 43 | u"last.fm for <username>" | ||
1194 | 44 | |||
1195 | 45 | feature = "lookup" | ||
1196 | 46 | |||
1197 | 34 | @match(r'^last\.?fm\s+for\s+(\S+?)\s*$') | 47 | @match(r'^last\.?fm\s+for\s+(\S+?)\s*$') |
1198 | 35 | def listsongs(self, event, username): | 48 | def listsongs(self, event, username): |
1199 | 36 | songs = feedparser.parse("http://ws.audioscrobbler.com/1.0/user/%s/recenttracks.rss?%s" % (username, time())) | 49 | songs = feedparser.parse("http://ws.audioscrobbler.com/1.0/user/%s/recenttracks.rss?%s" % (username, time())) |
1200 | @@ -41,7 +54,8 @@ | |||
1201 | 41 | 54 | ||
1202 | 42 | help['lotto'] = u"Gets the latest lotto results from the South African National Lottery" | 55 | help['lotto'] = u"Gets the latest lotto results from the South African National Lottery" |
1203 | 43 | class Lotto(Processor): | 56 | class Lotto(Processor): |
1205 | 44 | """lotto""" | 57 | u"""lotto""" |
1206 | 58 | |||
1207 | 45 | feature = 'lotto' | 59 | feature = 'lotto' |
1208 | 46 | 60 | ||
1209 | 47 | errors = { | 61 | errors = { |
1210 | @@ -51,7 +65,7 @@ | |||
1211 | 51 | 65 | ||
1212 | 52 | za_url = 'http://www.nationallottery.co.za/' | 66 | za_url = 'http://www.nationallottery.co.za/' |
1213 | 53 | za_re = re.compile(r'images/balls/ball_(\d+).gif') | 67 | za_re = re.compile(r'images/balls/ball_(\d+).gif') |
1215 | 54 | za_text = 'Latest lotto results for South Africa, Lotto: ' | 68 | za_text = u'Latest lotto results for South Africa, Lotto: ' |
1216 | 55 | 69 | ||
1217 | 56 | @match(r'lotto(\s+for\s+south\s+africa)?') | 70 | @match(r'lotto(\s+for\s+south\s+africa)?') |
1218 | 57 | def za(self, event, za): | 71 | def za(self, event, za): |
1219 | @@ -69,15 +83,18 @@ | |||
1220 | 69 | 83 | ||
1221 | 70 | if len(balls) != 14: | 84 | if len(balls) != 14: |
1222 | 71 | return event.addresponse(self.errors['balls'] % \ | 85 | return event.addresponse(self.errors['balls'] % \ |
1224 | 72 | (14, len(balls), ", ".join(balls))) | 86 | (14, len(balls), u", ".join(balls))) |
1225 | 73 | 87 | ||
1230 | 74 | r += " ".join(balls[:6]) | 88 | r += u" ".join(balls[:6]) |
1231 | 75 | r += " (Bonus: %s), Lotto Plus: " % (balls[6], ) | 89 | r += u" (Bonus: %s), Lotto Plus: " % (balls[6], ) |
1232 | 76 | r += " ".join(balls[7:13]) | 90 | r += u" ".join(balls[7:13]) |
1233 | 77 | r += " (Bonus: %s)" % (balls[13], ) | 91 | r += u" (Bonus: %s)" % (balls[13], ) |
1234 | 78 | event.addresponse(r) | 92 | event.addresponse(r) |
1235 | 79 | 93 | ||
1236 | 80 | class FMyLife(Processor): | 94 | class FMyLife(Processor): |
1237 | 95 | u"""fml (<number>|random)""" | ||
1238 | 96 | |||
1239 | 97 | feature = "lookup" | ||
1240 | 81 | 98 | ||
1241 | 82 | def remote_get(self, id): | 99 | def remote_get(self, id): |
1242 | 83 | f = urlopen('http://www.fmylife.com/' + str(id)) | 100 | f = urlopen('http://www.fmylife.com/' + str(id)) |
1243 | @@ -87,11 +104,17 @@ | |||
1244 | 87 | quote = soup.find('div', id='wrapper').div.p | 104 | quote = soup.find('div', id='wrapper').div.p |
1245 | 88 | return quote and u'"%s"' % (quote.contents[0],) or None | 105 | return quote and u'"%s"' % (quote.contents[0],) or None |
1246 | 89 | 106 | ||
1248 | 90 | @match(r'^(?:fml\s+|http://www\.fmylife\.com/\S+/)(\d+)$') | 107 | @match(r'^(?:fml\s+|http://www\.fmylife\.com/\S+/)(\d+|random)$') |
1249 | 91 | def fml(self, event, id): | 108 | def fml(self, event, id): |
1251 | 92 | event.addresponse(self.remote_get(int(id)) or u"No such quote") | 109 | event.addresponse(self.remote_get(id) or u"No such quote") |
1252 | 110 | |||
1253 | 111 | help["microblog"] = u"Looks up messages on microblogging services like twitter and identica." | ||
1254 | 93 | 112 | ||
1255 | 94 | class Twitter(Processor): | 113 | class Twitter(Processor): |
1256 | 114 | u"""latest (tweet|identica) from <name> | ||
1257 | 115 | (tweet|identica) <number>""" | ||
1258 | 116 | |||
1259 | 117 | feature = "microblog" | ||
1260 | 95 | 118 | ||
1261 | 96 | default = { 'twitter': 'http://twitter.com/', | 119 | default = { 'twitter': 'http://twitter.com/', |
1262 | 97 | 'tweet': 'http://twitter.com/', | 120 | 'tweet': 'http://twitter.com/', |
1263 | @@ -135,6 +158,10 @@ | |||
1264 | 135 | event.addresponse(self.remote_update('identi.ca', int(id))) | 158 | event.addresponse(self.remote_update('identi.ca', int(id))) |
1265 | 136 | 159 | ||
1266 | 137 | class Currency(Processor): | 160 | class Currency(Processor): |
1267 | 161 | u"""exchange <amount> <currency> for <currency> | ||
1268 | 162 | currencies for <country>""" | ||
1269 | 163 | |||
1270 | 164 | feature = "lookup" | ||
1271 | 138 | 165 | ||
1272 | 139 | headers = {'User-Agent': 'Mozilla/5.0', 'Referer': 'http://www.xe.com/'} | 166 | headers = {'User-Agent': 'Mozilla/5.0', 'Referer': 'http://www.xe.com/'} |
1273 | 140 | currencies = [] | 167 | currencies = [] |
1274 | @@ -179,6 +206,10 @@ | |||
1275 | 179 | event.addresponse(u'No currencies found') | 206 | event.addresponse(u'No currencies found') |
1276 | 180 | 207 | ||
1277 | 181 | class Weather(Processor): | 208 | class Weather(Processor): |
1278 | 209 | u"""weather in <city> | ||
1279 | 210 | forecast for <city>""" | ||
1280 | 211 | |||
1281 | 212 | feature = "lookup" | ||
1282 | 182 | 213 | ||
1283 | 183 | defaults = { 'ct': 'Cape Town, South Africa', | 214 | defaults = { 'ct': 'Cape Town, South Africa', |
1284 | 184 | 'jhb': 'Johannesburg, South Africa', | 215 | 'jhb': 'Johannesburg, South Africa', |
1285 | 185 | 216 | ||
1286 | === modified file 'ibid/plugins/math.py' | |||
1287 | --- ibid/plugins/math.py 2009-02-26 10:05:53 +0000 | |||
1288 | +++ ibid/plugins/math.py 2009-03-01 19:58:06 +0000 | |||
1289 | @@ -2,17 +2,22 @@ | |||
1290 | 2 | 2 | ||
1291 | 3 | from ibid.plugins import Processor, match | 3 | from ibid.plugins import Processor, match |
1292 | 4 | from ibid.config import Option | 4 | from ibid.config import Option |
1293 | 5 | from ibid.utils import file_in_path, unicode_output | ||
1294 | 5 | 6 | ||
1295 | 6 | help = {} | 7 | help = {} |
1296 | 7 | 8 | ||
1297 | 8 | help['bc'] = u'Calculate mathematical expressions using bc' | 9 | help['bc'] = u'Calculate mathematical expressions using bc' |
1298 | 9 | class BC(Processor): | 10 | class BC(Processor): |
1300 | 10 | """bc <expression>""" | 11 | u"""bc <expression>""" |
1301 | 11 | 12 | ||
1302 | 12 | feature = 'bc' | 13 | feature = 'bc' |
1303 | 13 | 14 | ||
1304 | 14 | bc = Option('bc', 'Path to bc executable', 'bc') | 15 | bc = Option('bc', 'Path to bc executable', 'bc') |
1305 | 15 | 16 | ||
1306 | 17 | def setup(self): | ||
1307 | 18 | if not file_in_path(self.bc): | ||
1308 | 19 | raise Exception("Cannot locate bc executeable") | ||
1309 | 20 | |||
1310 | 16 | @match(r'^bc\s+(.+)$') | 21 | @match(r'^bc\s+(.+)$') |
1311 | 17 | def calculate(self, event, expression): | 22 | def calculate(self, event, expression): |
1312 | 18 | bc = Popen([self.bc, '-l'], stdin=PIPE, stdout=PIPE, stderr=PIPE) | 23 | bc = Popen([self.bc, '-l'], stdin=PIPE, stdout=PIPE, stderr=PIPE) |
1313 | @@ -20,11 +25,23 @@ | |||
1314 | 20 | code = bc.wait() | 25 | code = bc.wait() |
1315 | 21 | 26 | ||
1316 | 22 | if code == 0: | 27 | if code == 0: |
1318 | 23 | event.addresponse(output.strip()) | 28 | if output: |
1319 | 29 | output = unicode_output(output.strip()) | ||
1320 | 30 | output = output.replace('\\\n', '') | ||
1321 | 31 | event.addresponse(output) | ||
1322 | 32 | else: | ||
1323 | 33 | error = unicode_output(error.strip()) | ||
1324 | 34 | error = error.split(":", 1)[1].strip() | ||
1325 | 35 | error = error[0].lower() + error[1:] | ||
1326 | 36 | event.addresponse(u"You can't %s" % error) | ||
1327 | 37 | else: | ||
1328 | 38 | event.addresponse(u"Error running bc") | ||
1329 | 39 | error = unicode_output(error.strip()) | ||
1330 | 40 | raise Exception("BC Error: %s" % error) | ||
1331 | 24 | 41 | ||
1333 | 25 | help['calc'] = 'Returns the anwser to mathematical expressions' | 42 | help['calc'] = u'Returns the anwser to mathematical expressions' |
1334 | 26 | class Calc(Processor): | 43 | class Calc(Processor): |
1336 | 27 | """[calc] <expression>""" | 44 | u"""[calc] <expression>""" |
1337 | 28 | feature = 'calc' | 45 | feature = 'calc' |
1338 | 29 | 46 | ||
1339 | 30 | priority = 500 | 47 | priority = 500 |
1340 | 31 | 48 | ||
1341 | === modified file 'ibid/plugins/memo.py' | |||
1342 | --- ibid/plugins/memo.py 2009-02-23 20:29:44 +0000 | |||
1343 | +++ ibid/plugins/memo.py 2009-03-01 23:01:30 +0000 | |||
1344 | @@ -13,7 +13,7 @@ | |||
1345 | 13 | from ibid.models import Base, Identity, Account | 13 | from ibid.models import Base, Identity, Account |
1346 | 14 | from ibid.utils import ago | 14 | from ibid.utils import ago |
1347 | 15 | 15 | ||
1349 | 16 | help = {'memo': 'Keeps messages for people.'} | 16 | help = {'memo': u'Keeps messages for people.'} |
1350 | 17 | 17 | ||
1351 | 18 | memo_cache = {} | 18 | memo_cache = {} |
1352 | 19 | log = logging.getLogger('plugins.memo') | 19 | log = logging.getLogger('plugins.memo') |
1353 | @@ -40,7 +40,7 @@ | |||
1354 | 40 | Memo.recipient = relation(Identity, primaryjoin=Memo.to_id==Identity.id) | 40 | Memo.recipient = relation(Identity, primaryjoin=Memo.to_id==Identity.id) |
1355 | 41 | 41 | ||
1356 | 42 | class Tell(Processor): | 42 | class Tell(Processor): |
1358 | 43 | """(tell|pm|privmsg|msg) <person> <message>""" | 43 | u"""(tell|pm|privmsg|msg) <person> <message>""" |
1359 | 44 | feature = 'memo' | 44 | feature = 'memo' |
1360 | 45 | 45 | ||
1361 | 46 | permission = u'sendmemo' | 46 | permission = u'sendmemo' |
1362 | @@ -135,7 +135,7 @@ | |||
1363 | 135 | session.close() | 135 | session.close() |
1364 | 136 | 136 | ||
1365 | 137 | class Messages(Processor): | 137 | class Messages(Processor): |
1367 | 138 | """my messages | 138 | u"""my messages |
1368 | 139 | message <number>""" | 139 | message <number>""" |
1369 | 140 | feature = 'memo' | 140 | feature = 'memo' |
1370 | 141 | 141 | ||
1371 | 142 | 142 | ||
1372 | === modified file 'ibid/plugins/misc.py' | |||
1373 | --- ibid/plugins/misc.py 2009-02-23 20:29:44 +0000 | |||
1374 | +++ ibid/plugins/misc.py 2009-03-01 23:01:30 +0000 | |||
1375 | @@ -9,7 +9,7 @@ | |||
1376 | 9 | 9 | ||
1377 | 10 | help['coffee'] = u"Times coffee brewing and reserves cups for people" | 10 | help['coffee'] = u"Times coffee brewing and reserves cups for people" |
1378 | 11 | class Coffee(Processor): | 11 | class Coffee(Processor): |
1380 | 12 | """coffee (on|please)""" | 12 | u"""coffee (on|please)""" |
1381 | 13 | feature = 'coffee' | 13 | feature = 'coffee' |
1382 | 14 | 14 | ||
1383 | 15 | pot = None | 15 | pot = None |
1384 | @@ -48,7 +48,7 @@ | |||
1385 | 48 | 48 | ||
1386 | 49 | help['version'] = u"Show the Ibid version currently running" | 49 | help['version'] = u"Show the Ibid version currently running" |
1387 | 50 | class Version(Processor): | 50 | class Version(Processor): |
1389 | 51 | """version""" | 51 | u"""version""" |
1390 | 52 | feature = 'version' | 52 | feature = 'version' |
1391 | 53 | 53 | ||
1392 | 54 | @match(r'^version$') | 54 | @match(r'^version$') |
1393 | @@ -57,7 +57,7 @@ | |||
1394 | 57 | 57 | ||
1395 | 58 | help['dvorak'] = u"Makes text typed on a QWERTY keyboard as if it was Dvorak work, and vice-versa" | 58 | help['dvorak'] = u"Makes text typed on a QWERTY keyboard as if it was Dvorak work, and vice-versa" |
1396 | 59 | class Dvorak(Processor): | 59 | class Dvorak(Processor): |
1398 | 60 | """(aoeu|asdf) <text>""" | 60 | u"""(aoeu|asdf) <text>""" |
1399 | 61 | feature = 'dvorak' | 61 | feature = 'dvorak' |
1400 | 62 | 62 | ||
1401 | 63 | # List of characters on each keyboard layout | 63 | # List of characters on each keyboard layout |
1402 | @@ -69,11 +69,11 @@ | |||
1403 | 69 | # Typed by a Dvorak typist on a QWERTY-mapped keyboard | 69 | # Typed by a Dvorak typist on a QWERTY-mapped keyboard |
1404 | 70 | typed_on_qwerty = dict(zip(map(ord, qwermap), dvormap)) | 70 | typed_on_qwerty = dict(zip(map(ord, qwermap), dvormap)) |
1405 | 71 | 71 | ||
1407 | 72 | @match(r'asdf\s+(.+)') | 72 | @match(r'(?:asdf|dvorak)\s+(.+)') |
1408 | 73 | def convert_from_qwerty(self, event, text): | 73 | def convert_from_qwerty(self, event, text): |
1409 | 74 | event.addresponse(text.translate(self.typed_on_qwerty)) | 74 | event.addresponse(text.translate(self.typed_on_qwerty)) |
1410 | 75 | 75 | ||
1412 | 76 | @match(r'aoeu\s+(.+)') | 76 | @match(r'(?:aoeu|querty)\s+(.+)') |
1413 | 77 | def convert_from_dvorak(self, event, text): | 77 | def convert_from_dvorak(self, event, text): |
1414 | 78 | event.addresponse(text.translate(self.typed_on_dvorak)) | 78 | event.addresponse(text.translate(self.typed_on_dvorak)) |
1415 | 79 | 79 | ||
1416 | 80 | 80 | ||
1417 | === modified file 'ibid/plugins/morse.py' | |||
1418 | --- ibid/plugins/morse.py 2009-01-24 12:39:04 +0000 | |||
1419 | +++ ibid/plugins/morse.py 2009-03-01 23:01:30 +0000 | |||
1420 | @@ -2,8 +2,10 @@ | |||
1421 | 2 | 2 | ||
1422 | 3 | help = {} | 3 | help = {} |
1423 | 4 | 4 | ||
1424 | 5 | help["morse"] = u"Translates messages into and out of morse code." | ||
1425 | 6 | |||
1426 | 5 | class Morse(Processor): | 7 | class Morse(Processor): |
1428 | 6 | """morse (text|morsecode)""" | 8 | u"""morse (text|morsecode)""" |
1429 | 7 | feature = 'morse' | 9 | feature = 'morse' |
1430 | 8 | 10 | ||
1431 | 9 | @match(r'^morse\s+(.+)$') | 11 | @match(r'^morse\s+(.+)$') |
1432 | @@ -64,12 +66,12 @@ | |||
1433 | 64 | 66 | ||
1434 | 65 | 67 | ||
1435 | 66 | def text2morse(text): | 68 | def text2morse(text): |
1437 | 67 | return " ".join(table.get(c.upper(), c) for c in text) | 69 | return u" ".join(table.get(c.upper(), c) for c in text) |
1438 | 68 | 70 | ||
1439 | 69 | def morse2text(morse): | 71 | def morse2text(morse): |
1440 | 70 | rtable = dict((v, k) for k, v in table.items()) | 72 | rtable = dict((v, k) for k, v in table.items()) |
1441 | 71 | toks = morse.split(' ') | 73 | toks = morse.split(' ') |
1443 | 72 | return " ".join(rtable.get(t, t) for t in toks) | 74 | return u" ".join(rtable.get(t, t) for t in toks) |
1444 | 73 | 75 | ||
1445 | 74 | if message.replace('-', '').replace('.', '').isspace(): | 76 | if message.replace('-', '').replace('.', '').isspace(): |
1446 | 75 | event.addresponse(morse2text(message)) | 77 | event.addresponse(morse2text(message)) |
1447 | 76 | 78 | ||
1448 | === modified file 'ibid/plugins/network.py' | |||
1449 | --- ibid/plugins/network.py 2009-02-03 18:03:49 +0000 | |||
1450 | +++ ibid/plugins/network.py 2009-03-01 19:58:06 +0000 | |||
1451 | @@ -6,17 +6,18 @@ | |||
1452 | 6 | 6 | ||
1453 | 7 | from ibid.plugins import Processor, match | 7 | from ibid.plugins import Processor, match |
1454 | 8 | from ibid.config import Option | 8 | from ibid.config import Option |
1455 | 9 | from ibid.utils import file_in_path, unicode_output | ||
1456 | 9 | 10 | ||
1457 | 10 | help = {} | 11 | help = {} |
1458 | 11 | ipaddr = re.compile('\d+\.\d+\.\d+\.\d+') | 12 | ipaddr = re.compile('\d+\.\d+\.\d+\.\d+') |
1459 | 12 | 13 | ||
1460 | 13 | help['dns'] = u'Performs DNS lookups' | 14 | help['dns'] = u'Performs DNS lookups' |
1461 | 14 | class DNS(Processor): | 15 | class DNS(Processor): |
1463 | 15 | """(dns|nslookup|dig) [<record type>] [for] <host> [(from|@) <nameserver>]""" | 16 | u"""dns [<record type>] [for] <host> [from <nameserver>]""" |
1464 | 16 | 17 | ||
1465 | 17 | feature = 'dns' | 18 | feature = 'dns' |
1466 | 18 | 19 | ||
1468 | 19 | @match(r'^(?:dns|nslookup|dig)(?:\s+(a|aaaa|ptr|ns|soa|cname|mx|txt|spf|srv|sshfp|cert))?\s+(?:for\s+)?(\S+?)(?:\s+(?:from\s+|@)\s*(\S+))?$') | 20 | @match(r'^(?:dns|nslookup|dig|host)(?:\s+(a|aaaa|ptr|ns|soa|cname|mx|txt|spf|srv|sshfp|cert))?\s+(?:for\s+)?(\S+?)(?:\s+(?:from\s+|@)\s*(\S+))?$') |
1469 | 20 | def resolve(self, event, record, host, nameserver): | 21 | def resolve(self, event, record, host, nameserver): |
1470 | 21 | if not record: | 22 | if not record: |
1471 | 22 | if ipaddr.search(host): | 23 | if ipaddr.search(host): |
1472 | @@ -42,36 +43,49 @@ | |||
1473 | 42 | 43 | ||
1474 | 43 | responses = [] | 44 | responses = [] |
1475 | 44 | for rdata in answers: | 45 | for rdata in answers: |
1481 | 45 | responses.append(str(rdata)) | 46 | responses.append(unicode(rdata)) |
1482 | 46 | 47 | ||
1483 | 47 | event.addresponse(', '.join(responses)) | 48 | event.addresponse(u', '.join(responses)) |
1484 | 48 | 49 | ||
1485 | 49 | help['ping'] = 'ICMP pings the specified host.' | 50 | help['ping'] = u'ICMP pings the specified host.' |
1486 | 50 | class Ping(Processor): | 51 | class Ping(Processor): |
1488 | 51 | """ping <host>""" | 52 | u"""ping <host>""" |
1489 | 52 | feature = 'ping' | 53 | feature = 'ping' |
1490 | 53 | 54 | ||
1491 | 54 | ping = Option('ping', 'Path to ping executable', 'ping') | 55 | ping = Option('ping', 'Path to ping executable', 'ping') |
1492 | 55 | 56 | ||
1493 | 57 | def setup(self): | ||
1494 | 58 | if not file_in_path(self.ping): | ||
1495 | 59 | raise Exception("Cannot locate ping executeable") | ||
1496 | 60 | |||
1497 | 56 | @match(r'^ping\s+(\S+)$') | 61 | @match(r'^ping\s+(\S+)$') |
1498 | 57 | def handle_ping(self, event, host): | 62 | def handle_ping(self, event, host): |
1500 | 58 | 63 | if host.strip().startswith("-"): | |
1501 | 64 | event.addresponse(False) | ||
1502 | 65 | return | ||
1503 | 66 | |||
1504 | 59 | ping = Popen([self.ping, '-q', '-c5', host], stdout=PIPE, stderr=PIPE) | 67 | ping = Popen([self.ping, '-q', '-c5', host], stdout=PIPE, stderr=PIPE) |
1505 | 60 | output, error = ping.communicate() | 68 | output, error = ping.communicate() |
1506 | 61 | code = ping.wait() | 69 | code = ping.wait() |
1507 | 62 | 70 | ||
1508 | 63 | if code == 0: | 71 | if code == 0: |
1510 | 64 | event.addresponse(' '.join(output.splitlines()[-2:])) | 72 | output = unicode_output(' '.join(output.splitlines()[-2:])) |
1511 | 73 | event.addresponse(output) | ||
1512 | 65 | else: | 74 | else: |
1514 | 66 | event.addresponse(error.replace('\n', ' ').replace('ping:', '', 1).strip()) | 75 | error = unicode_output(error.replace('\n', ' ').replace('ping:', '', 1).strip()) |
1515 | 76 | event.addresponse(error) | ||
1516 | 67 | 77 | ||
1518 | 68 | help['tracepath'] = 'Traces the path to the given host.' | 78 | help['tracepath'] = u'Traces the path to the given host.' |
1519 | 69 | class Tracepath(Processor): | 79 | class Tracepath(Processor): |
1521 | 70 | """tracepath <host>""" | 80 | u"""tracepath <host>""" |
1522 | 71 | feature = 'tracepath' | 81 | feature = 'tracepath' |
1523 | 72 | 82 | ||
1524 | 73 | tracepath = Option('tracepath', 'Path to tracepath executable', 'tracepath') | 83 | tracepath = Option('tracepath', 'Path to tracepath executable', 'tracepath') |
1525 | 74 | 84 | ||
1526 | 85 | def setup(self): | ||
1527 | 86 | if not file_in_path(self.tracepath): | ||
1528 | 87 | raise Exception("Cannot locate tracepath executeable") | ||
1529 | 88 | |||
1530 | 75 | @match(r'^tracepath\s+(\S+)$') | 89 | @match(r'^tracepath\s+(\S+)$') |
1531 | 76 | def handle_tracepath(self, event, host): | 90 | def handle_tracepath(self, event, host): |
1532 | 77 | 91 | ||
1533 | @@ -80,31 +94,53 @@ | |||
1534 | 80 | code = tracepath.wait() | 94 | code = tracepath.wait() |
1535 | 81 | 95 | ||
1536 | 82 | if code == 0: | 96 | if code == 0: |
1537 | 97 | output = unicode_output(output) | ||
1538 | 83 | for line in output.splitlines(): | 98 | for line in output.splitlines(): |
1539 | 84 | event.addresponse(line) | 99 | event.addresponse(line) |
1540 | 85 | else: | 100 | else: |
1542 | 86 | event.addresponse(error.replace('\n', ' ').strip()) | 101 | error = unicode_output(error.strip()) |
1543 | 102 | event.addresponse(error.replace('\n', ' ')) | ||
1544 | 87 | 103 | ||
1546 | 88 | help['ipcalc'] = 'IP address calculator' | 104 | help['ipcalc'] = u'IP address calculator' |
1547 | 89 | class IPCalc(Processor): | 105 | class IPCalc(Processor): |
1549 | 90 | """ipcalc <network> <subnet> | 106 | u"""ipcalc <network> <subnet> |
1550 | 91 | ipcalc <address> - <address>""" | 107 | ipcalc <address> - <address>""" |
1551 | 92 | feature = 'ipcalc' | 108 | feature = 'ipcalc' |
1552 | 93 | 109 | ||
1553 | 94 | ipcalc = Option('ipcalc', 'Path to ipcalc executable', 'ipcalc') | 110 | ipcalc = Option('ipcalc', 'Path to ipcalc executable', 'ipcalc') |
1554 | 95 | 111 | ||
1555 | 112 | deaggregate_re = re.compile(r'^((?:\d{1,3}\.){3}\d{1,3})\s+-\s+((?:\d{1,3}\.){3}\d{1,3})$') | ||
1556 | 113 | |||
1557 | 114 | def setup(self): | ||
1558 | 115 | if not file_in_path(self.ipcalc): | ||
1559 | 116 | raise Exception("Cannot locate ipcalc executeable") | ||
1560 | 117 | |||
1561 | 96 | @match(r'^ipcalc\s+(.+)$') | 118 | @match(r'^ipcalc\s+(.+)$') |
1562 | 97 | def handle_ipcalc(self, event, parameter): | 119 | def handle_ipcalc(self, event, parameter): |
1565 | 98 | 120 | if parameter.strip().startswith("-"): | |
1566 | 99 | ipcalc = Popen([self.ipcalc, '-n', '-b', parameter], stdout=PIPE, stderr=PIPE) | 121 | event.addresponse(False) |
1567 | 122 | return | ||
1568 | 123 | |||
1569 | 124 | m = self.deaggregate_re.match(parameter) | ||
1570 | 125 | if m: | ||
1571 | 126 | parameter = [m.group(1), '-', m.group(2)] | ||
1572 | 127 | else: | ||
1573 | 128 | parameter = [parameter] | ||
1574 | 129 | |||
1575 | 130 | ipcalc = Popen([self.ipcalc, '-n', '-b'] + parameter, stdout=PIPE, stderr=PIPE) | ||
1576 | 100 | output, error = ipcalc.communicate() | 131 | output, error = ipcalc.communicate() |
1577 | 101 | code = ipcalc.wait() | 132 | code = ipcalc.wait() |
1578 | 102 | 133 | ||
1579 | 103 | if code == 0: | 134 | if code == 0: |
1583 | 104 | for line in output.splitlines(): | 135 | output = unicode_output(output) |
1584 | 105 | if line: | 136 | if output.startswith("INVALID ADDRESS"): |
1585 | 106 | event.addresponse(line) | 137 | event.addresponse(u"That's an invalid address. Try something like 192.168.1.0/24") |
1586 | 138 | else: | ||
1587 | 139 | for line in output.splitlines(): | ||
1588 | 140 | if line.strip(): | ||
1589 | 141 | event.addresponse(line) | ||
1590 | 107 | else: | 142 | else: |
1591 | 143 | error = unicode_output(error.strip()) | ||
1592 | 108 | event.addresponse(error.replace('\n', ' ')) | 144 | event.addresponse(error.replace('\n', ' ')) |
1593 | 109 | 145 | ||
1594 | 110 | # vi: set et sta sw=4 ts=4: | 146 | # vi: set et sta sw=4 ts=4: |
1595 | 111 | 147 | ||
1596 | === modified file 'ibid/plugins/roshambo.py' | |||
1597 | --- ibid/plugins/roshambo.py 2009-01-24 12:39:04 +0000 | |||
1598 | +++ ibid/plugins/roshambo.py 2009-03-01 23:01:30 +0000 | |||
1599 | @@ -6,9 +6,9 @@ | |||
1600 | 6 | 6 | ||
1601 | 7 | choices = ['paper', 'rock', 'scissors'] | 7 | choices = ['paper', 'rock', 'scissors'] |
1602 | 8 | 8 | ||
1604 | 9 | help['roshambo'] = 'Plays rock, paper, scissors.' | 9 | help['roshambo'] = u'Plays rock, paper, scissors.' |
1605 | 10 | class RoShamBo(Processor): | 10 | class RoShamBo(Processor): |
1607 | 11 | """roshambo (rock|paper|scissors)""" | 11 | u"""roshambo (rock|paper|scissors)""" |
1608 | 12 | feature = 'roshambo' | 12 | feature = 'roshambo' |
1609 | 13 | 13 | ||
1610 | 14 | @match(r'^roshambo\s+(rock|paper|scissors)$') | 14 | @match(r'^roshambo\s+(rock|paper|scissors)$') |
1611 | @@ -17,11 +17,11 @@ | |||
1612 | 17 | bchoice = randint(0, 2) | 17 | bchoice = randint(0, 2) |
1613 | 18 | 18 | ||
1614 | 19 | if uchoice == bchoice: | 19 | if uchoice == bchoice: |
1616 | 20 | reply = 'We drew! I also chose %s' % choices[bchoice] | 20 | reply = u'We drew! I also chose %s' % choices[bchoice] |
1617 | 21 | elif (uchoice + 1) % 3 == bchoice: | 21 | elif (uchoice + 1) % 3 == bchoice: |
1619 | 22 | reply = 'You win! I chose %s :-(' % choices[bchoice] | 22 | reply = u'You win! I chose %s :-(' % choices[bchoice] |
1620 | 23 | else: | 23 | else: |
1622 | 24 | reply = 'I win! I chose %s' % choices[bchoice] | 24 | reply = u'I win! I chose %s' % choices[bchoice] |
1623 | 25 | 25 | ||
1624 | 26 | event.addresponse(reply) | 26 | event.addresponse(reply) |
1625 | 27 | return event | 27 | return event |
1626 | 28 | 28 | ||
1627 | === modified file 'ibid/plugins/seen.py' | |||
1628 | --- ibid/plugins/seen.py 2009-02-18 19:05:10 +0000 | |||
1629 | +++ ibid/plugins/seen.py 2009-03-01 23:01:30 +0000 | |||
1630 | @@ -10,7 +10,7 @@ | |||
1631 | 10 | from ibid.models import Base, Identity, Account | 10 | from ibid.models import Base, Identity, Account |
1632 | 11 | from ibid.utils import ago | 11 | from ibid.utils import ago |
1633 | 12 | 12 | ||
1635 | 13 | help = {'seen': 'Records when people were last seen.'} | 13 | help = {'seen': u'Records when people were last seen.'} |
1636 | 14 | 14 | ||
1637 | 15 | class Sighting(Base): | 15 | class Sighting(Base): |
1638 | 16 | __table__ = Table('seen', Base.metadata, | 16 | __table__ = Table('seen', Base.metadata, |
1639 | @@ -64,7 +64,7 @@ | |||
1640 | 64 | session.close() | 64 | session.close() |
1641 | 65 | 65 | ||
1642 | 66 | class Seen(Processor): | 66 | class Seen(Processor): |
1644 | 67 | """seen <who>""" | 67 | u"""seen <who>""" |
1645 | 68 | feature = 'seen' | 68 | feature = 'seen' |
1646 | 69 | 69 | ||
1647 | 70 | datetime_format = Option('datetime_format', 'Format string for timestamps', '%Y/%m/%d %H:%M:%S') | 70 | datetime_format = Option('datetime_format', 'Format string for timestamps', '%Y/%m/%d %H:%M:%S') |
1648 | 71 | 71 | ||
1649 | === modified file 'ibid/plugins/sources.py' | |||
1650 | --- ibid/plugins/sources.py 2009-02-17 21:04:17 +0000 | |||
1651 | +++ ibid/plugins/sources.py 2009-03-01 23:01:30 +0000 | |||
1652 | @@ -1,10 +1,10 @@ | |||
1653 | 1 | import ibid | 1 | import ibid |
1654 | 2 | from ibid.plugins import Processor, match, authorise | 2 | from ibid.plugins import Processor, match, authorise |
1655 | 3 | 3 | ||
1657 | 4 | help = {'sources': 'Controls and lists the configured sources.'} | 4 | help = {'sources': u'Controls and lists the configured sources.'} |
1658 | 5 | 5 | ||
1659 | 6 | class Admin(Processor): | 6 | class Admin(Processor): |
1661 | 7 | """(connect|disconnect) (to|from) <source> | 7 | u"""(connect|disconnect) (to|from) <source> |
1662 | 8 | load <source> source""" | 8 | load <source> source""" |
1663 | 9 | feature = 'sources' | 9 | feature = 'sources' |
1664 | 10 | 10 | ||
1665 | @@ -37,7 +37,7 @@ | |||
1666 | 37 | event.addresponse(u"Couldn't load %s source" % source) | 37 | event.addresponse(u"Couldn't load %s source" % source) |
1667 | 38 | 38 | ||
1668 | 39 | class Info(Processor): | 39 | class Info(Processor): |
1670 | 40 | """(sources|list configured sources)""" | 40 | u"""(sources|list configured sources)""" |
1671 | 41 | feature = 'sources' | 41 | feature = 'sources' |
1672 | 42 | 42 | ||
1673 | 43 | @match(r'^sources$') | 43 | @match(r'^sources$') |
1674 | 44 | 44 | ||
1675 | === modified file 'ibid/plugins/tools.py' | |||
1676 | --- ibid/plugins/tools.py 2009-02-23 13:08:26 +0000 | |||
1677 | +++ ibid/plugins/tools.py 2009-03-01 19:58:06 +0000 | |||
1678 | @@ -4,31 +4,32 @@ | |||
1679 | 4 | 4 | ||
1680 | 5 | from ibid.plugins import Processor, match | 5 | from ibid.plugins import Processor, match |
1681 | 6 | from ibid.config import Option | 6 | from ibid.config import Option |
1682 | 7 | from ibid.utils import file_in_path, unicode_output | ||
1683 | 7 | 8 | ||
1684 | 8 | help = {} | 9 | help = {} |
1685 | 9 | 10 | ||
1687 | 10 | help['retest'] = 'Checks whether a regular expression matches a given string.' | 11 | help['retest'] = u'Checks whether a regular expression matches a given string.' |
1688 | 11 | class ReTest(Processor): | 12 | class ReTest(Processor): |
1690 | 12 | """does <pattern> match <string>""" | 13 | u"""does <pattern> match <string>""" |
1691 | 13 | feature = 'retest' | 14 | feature = 'retest' |
1692 | 14 | 15 | ||
1693 | 15 | @match('^does\s+(.+?)\s+match\s+(.+?)$') | 16 | @match('^does\s+(.+?)\s+match\s+(.+?)$') |
1694 | 16 | def retest(self, event, regex, string): | 17 | def retest(self, event, regex, string): |
1696 | 17 | event.addresponse(re.search(regex, string) and 'Yes' or 'No') | 18 | event.addresponse(re.search(regex, string) and u'Yes' or u'No') |
1697 | 18 | 19 | ||
1699 | 19 | help['random'] = 'Generates random numbers.' | 20 | help['random'] = u'Generates random numbers.' |
1700 | 20 | class Random(Processor): | 21 | class Random(Processor): |
1702 | 21 | """random [ <max> | <min> <max> ]""" | 22 | u"""random [ <max> | <min> <max> ]""" |
1703 | 22 | feature = 'random' | 23 | feature = 'random' |
1704 | 23 | 24 | ||
1705 | 24 | @match('^rand(?:om)?(?:\s+(\d+)(?:\s+(\d+))?)?$') | 25 | @match('^rand(?:om)?(?:\s+(\d+)(?:\s+(\d+))?)?$') |
1706 | 25 | def random(self, event, begin, end): | 26 | def random(self, event, begin, end): |
1707 | 26 | if not begin and not end: | 27 | if not begin and not end: |
1709 | 27 | event.addresponse(str(random())) | 28 | event.addresponse(unicode(random())) |
1710 | 28 | else: | 29 | else: |
1711 | 29 | begin = int(begin) | 30 | begin = int(begin) |
1712 | 30 | end = end and int(end) or 0 | 31 | end = end and int(end) or 0 |
1714 | 31 | event.addresponse(str(randint(min(begin,end), max(begin,end)))) | 32 | event.addresponse(unicode(randint(min(begin,end), max(begin,end)))) |
1715 | 32 | 33 | ||
1716 | 33 | bases = { 'bin': (lambda x: int(x, 2), lambda x: "".join(map(lambda y:str((x>>y)&1), range(8-1, -1, -1)))), | 34 | bases = { 'bin': (lambda x: int(x, 2), lambda x: "".join(map(lambda y:str((x>>y)&1), range(8-1, -1, -1)))), |
1717 | 34 | 'hex': (lambda x: int(x, 6), hex), | 35 | 'hex': (lambda x: int(x, 6), hex), |
1718 | @@ -36,9 +37,9 @@ | |||
1719 | 36 | 'dec': (lambda x: int(x, 10), lambda x: x), | 37 | 'dec': (lambda x: int(x, 10), lambda x: x), |
1720 | 37 | 'ascii': (ord, chr), | 38 | 'ascii': (ord, chr), |
1721 | 38 | } | 39 | } |
1723 | 39 | help['base'] = 'Converts between numeric bases as well as ASCII.' | 40 | help['base'] = u'Converts between numeric bases as well as ASCII.' |
1724 | 40 | class Base(Processor): | 41 | class Base(Processor): |
1726 | 41 | """convert <num> from <base> to <base>""" | 42 | u"""convert <num> from <base> to <base>""" |
1727 | 42 | feature = 'base' | 43 | feature = 'base' |
1728 | 43 | 44 | ||
1729 | 44 | @match(r'^convert\s+(\S+)\s+(?:from\s+)?(%s)\s+(?:to\s+)?(%s)$' % ('|'.join(bases.keys()), '|'.join(bases.keys()))) | 45 | @match(r'^convert\s+(\S+)\s+(?:from\s+)?(%s)\s+(?:to\s+)?(%s)$' % ('|'.join(bases.keys()), '|'.join(bases.keys()))) |
1730 | @@ -48,9 +49,9 @@ | |||
1731 | 48 | event.addresponse(str(number)) | 49 | event.addresponse(str(number)) |
1732 | 49 | 50 | ||
1733 | 50 | 51 | ||
1735 | 51 | help['units'] = 'Converts values between various units.' | 52 | help['units'] = u'Converts values between various units.' |
1736 | 52 | class Units(Processor): | 53 | class Units(Processor): |
1738 | 53 | """convert [<value>] <unit> to <unit>""" | 54 | u"""convert [<value>] <unit> to <unit>""" |
1739 | 54 | feature = 'units' | 55 | feature = 'units' |
1740 | 55 | 56 | ||
1741 | 56 | units = Option('units', 'Path to units executable', 'units') | 57 | units = Option('units', 'Path to units executable', 'units') |
1742 | @@ -69,6 +70,10 @@ | |||
1743 | 69 | 70 | ||
1744 | 70 | temp_function_names = set(temp_scale_names.values()) | 71 | temp_function_names = set(temp_scale_names.values()) |
1745 | 71 | 72 | ||
1746 | 73 | def setup(self): | ||
1747 | 74 | if not file_in_path(self.units): | ||
1748 | 75 | raise Exception("Cannot locate units executeable") | ||
1749 | 76 | |||
1750 | 72 | def format_temperature(self, unit): | 77 | def format_temperature(self, unit): |
1751 | 73 | "Return the unit, and convert to 'tempX' format if a known temperature scale" | 78 | "Return the unit, and convert to 'tempX' format if a known temperature scale" |
1752 | 74 | 79 | ||
1753 | @@ -99,6 +104,7 @@ | |||
1754 | 99 | output, error = units.communicate() | 104 | output, error = units.communicate() |
1755 | 100 | code = units.wait() | 105 | code = units.wait() |
1756 | 101 | 106 | ||
1757 | 107 | output = unicode_output(output) | ||
1758 | 102 | result = output.splitlines()[0].strip() | 108 | result = output.splitlines()[0].strip() |
1759 | 103 | 109 | ||
1760 | 104 | if code == 0: | 110 | if code == 0: |
1761 | 105 | 111 | ||
1762 | === modified file 'ibid/plugins/trac.py' | |||
1763 | --- ibid/plugins/trac.py 2009-02-23 20:29:44 +0000 | |||
1764 | +++ ibid/plugins/trac.py 2009-03-01 23:01:30 +0000 | |||
1765 | @@ -9,7 +9,7 @@ | |||
1766 | 9 | from ibid.config import Option | 9 | from ibid.config import Option |
1767 | 10 | from ibid.utils import ago | 10 | from ibid.utils import ago |
1768 | 11 | 11 | ||
1770 | 12 | help = {'trac': 'Retrieves tickets from a Trac database.'} | 12 | help = {'trac': u'Retrieves tickets from a Trac database.'} |
1771 | 13 | 13 | ||
1772 | 14 | class Ticket(object): | 14 | class Ticket(object): |
1773 | 15 | pass | 15 | pass |
1774 | @@ -20,7 +20,7 @@ | |||
1775 | 20 | mapper(Ticket, ticket_table) | 20 | mapper(Ticket, ticket_table) |
1776 | 21 | 21 | ||
1777 | 22 | class GetTicket(Processor, RPC): | 22 | class GetTicket(Processor, RPC): |
1779 | 23 | """ticket <number> | 23 | u"""ticket <number> |
1780 | 24 | (open|my|<who>'s) tickets""" | 24 | (open|my|<who>'s) tickets""" |
1781 | 25 | feature = 'trac' | 25 | feature = 'trac' |
1782 | 26 | 26 | ||
1783 | 27 | 27 | ||
1784 | === modified file 'ibid/plugins/url.py' | |||
1785 | --- ibid/plugins/url.py 2009-02-18 19:11:41 +0000 | |||
1786 | +++ ibid/plugins/url.py 2009-03-01 23:01:30 +0000 | |||
1787 | @@ -1,4 +1,5 @@ | |||
1788 | 1 | from datetime import datetime | 1 | from datetime import datetime |
1789 | 2 | from urllib import urlencode | ||
1790 | 2 | from urllib2 import urlopen, HTTPRedirectHandler, build_opener, HTTPError | 3 | from urllib2 import urlopen, HTTPRedirectHandler, build_opener, HTTPError |
1791 | 3 | import re | 4 | import re |
1792 | 4 | 5 | ||
1793 | @@ -9,7 +10,7 @@ | |||
1794 | 9 | from ibid.config import Option | 10 | from ibid.config import Option |
1795 | 10 | from ibid.models import Base | 11 | from ibid.models import Base |
1796 | 11 | 12 | ||
1798 | 12 | help = {'url': 'Captures URLs seen in channel, and shortens and lengthens URLs'} | 13 | help = {'url': u'Captures URLs seen in channel, and shortens and lengthens URLs'} |
1799 | 13 | 14 | ||
1800 | 14 | class URL(Base): | 15 | class URL(Base): |
1801 | 15 | __table__ = Table('urls', Base.metadata, | 16 | __table__ = Table('urls', Base.metadata, |
1802 | @@ -46,16 +47,16 @@ | |||
1803 | 46 | session.close() | 47 | session.close() |
1804 | 47 | 48 | ||
1805 | 48 | class Shorten(Processor): | 49 | class Shorten(Processor): |
1807 | 49 | """shorten <url>""" | 50 | u"""shorten <url>""" |
1808 | 50 | feature = 'url' | 51 | feature = 'url' |
1809 | 51 | 52 | ||
1810 | 52 | @match(r'^shorten\s+(\S+\.\S+)$') | 53 | @match(r'^shorten\s+(\S+\.\S+)$') |
1811 | 53 | def shorten(self, event, url): | 54 | def shorten(self, event, url): |
1813 | 54 | f = urlopen('http://is.gd/api.php?longurl=%s' % url) | 55 | f = urlopen('http://is.gd/api.php?%s' % urlencode({'longurl': url})) |
1814 | 55 | shortened = f.read() | 56 | shortened = f.read() |
1815 | 56 | f.close() | 57 | f.close() |
1816 | 57 | 58 | ||
1818 | 58 | event.addresponse(shortened) | 59 | event.addresponse(unicode(shortened)) |
1819 | 59 | 60 | ||
1820 | 60 | class NullRedirect(HTTPRedirectHandler): | 61 | class NullRedirect(HTTPRedirectHandler): |
1821 | 61 | 62 | ||
1822 | @@ -63,10 +64,14 @@ | |||
1823 | 63 | return None | 64 | return None |
1824 | 64 | 65 | ||
1825 | 65 | class Lengthen(Processor): | 66 | class Lengthen(Processor): |
1827 | 66 | """<url>""" | 67 | u"""<url>""" |
1828 | 67 | feature = 'url' | 68 | feature = 'url' |
1829 | 68 | 69 | ||
1831 | 69 | services = Option('services', 'List of URL prefixes of URL shortening services', ('http://is.gd/', 'http://tinyurl.com/', 'http://ff.im/', 'http://shorl.com/', 'http://icanhaz.com/', 'http://url.omnia.za.net/', 'http://snipurl.com/', 'http://tr.im/', 'http://snipr.com/')) | 70 | services = Option('services', 'List of URL prefixes of URL shortening services', ( |
1832 | 71 | 'http://is.gd/', 'http://tinyurl.com/', 'http://ff.im/', | ||
1833 | 72 | 'http://shorl.com/', 'http://icanhaz.com/', 'http://url.omnia.za.net/', | ||
1834 | 73 | 'http://snipurl.com/', 'http://tr.im/', 'http://snipr.com/' | ||
1835 | 74 | )) | ||
1836 | 70 | 75 | ||
1837 | 71 | def setup(self): | 76 | def setup(self): |
1838 | 72 | self.lengthen.im_func.pattern = re.compile(r'^((?:%s)\S+)$' % '|'.join([re.escape(service) for service in self.services]), re.I) | 77 | self.lengthen.im_func.pattern = re.compile(r'^((?:%s)\S+)$' % '|'.join([re.escape(service) for service in self.services]), re.I) |
1839 | @@ -78,7 +83,7 @@ | |||
1840 | 78 | f = opener.open(url) | 83 | f = opener.open(url) |
1841 | 79 | except HTTPError, e: | 84 | except HTTPError, e: |
1842 | 80 | if e.code in (301, 302, 303, 307): | 85 | if e.code in (301, 302, 303, 307): |
1844 | 81 | event.addresponse(e.hdrs['location']) | 86 | event.addresponse(unicode(e.hdrs['location'])) |
1845 | 82 | return | 87 | return |
1846 | 83 | 88 | ||
1847 | 84 | f.close() | 89 | f.close() |
1848 | 85 | 90 | ||
1849 | === modified file 'ibid/source/irc.py' | |||
1850 | --- ibid/source/irc.py 2009-02-23 20:29:44 +0000 | |||
1851 | +++ ibid/source/irc.py 2009-03-01 23:04:43 +0000 | |||
1852 | @@ -100,7 +100,8 @@ | |||
1853 | 100 | def send(self, response): | 100 | def send(self, response): |
1854 | 101 | message = response['reply'].replace('\n', ' ')[:490] | 101 | message = response['reply'].replace('\n', ' ')[:490] |
1855 | 102 | if 'action' in response and response['action']: | 102 | if 'action' in response and response['action']: |
1857 | 103 | self.me(response['target'].encode('utf-8'), message.encode('utf-8')) | 103 | # We can't use self.me() because it prepends a # onto channel names |
1858 | 104 | self.ctcpMakeQuery(response['target'].encode('utf-8'), [('ACTION', message.encode('utf-8'))]) | ||
1859 | 104 | self.factory.log.debug(u"Sent action to %s: %s", response['target'], message) | 105 | self.factory.log.debug(u"Sent action to %s: %s", response['target'], message) |
1860 | 105 | else: | 106 | else: |
1861 | 106 | self.msg(response['target'].encode('utf-8'), message.encode('utf-8')) | 107 | self.msg(response['target'].encode('utf-8'), message.encode('utf-8')) |
1862 | 107 | 108 | ||
1863 | === modified file 'ibid/utils.py' | |||
1864 | --- ibid/utils.py 2009-02-21 20:06:39 +0000 | |||
1865 | +++ ibid/utils.py 2009-03-01 19:58:06 +0000 | |||
1866 | @@ -1,4 +1,6 @@ | |||
1867 | 1 | from htmlentitydefs import name2codepoint | 1 | from htmlentitydefs import name2codepoint |
1868 | 2 | import os | ||
1869 | 3 | import os.path | ||
1870 | 2 | import re | 4 | import re |
1871 | 3 | 5 | ||
1872 | 4 | def ago(delta, units=None): | 6 | def ago(delta, units=None): |
1873 | @@ -28,3 +30,16 @@ | |||
1874 | 28 | def decode_htmlentities(string): | 30 | def decode_htmlentities(string): |
1875 | 29 | entity_re = re.compile("&(#?)(\d{1,5}|\w{1,8});") | 31 | entity_re = re.compile("&(#?)(\d{1,5}|\w{1,8});") |
1876 | 30 | return entity_re.subn(substitute_entity, string)[0] | 32 | return entity_re.subn(substitute_entity, string)[0] |
1877 | 33 | |||
1878 | 34 | def file_in_path(program): | ||
1879 | 35 | path = os.environ.get("PATH", os.defpath).split(os.pathsep) | ||
1880 | 36 | path = [os.path.join(dir, program) for dir in path] | ||
1881 | 37 | path = [True for file in path if os.path.isfile(file)] | ||
1882 | 38 | return bool(path) | ||
1883 | 39 | |||
1884 | 40 | def unicode_output(output, errors="strict"): | ||
1885 | 41 | try: | ||
1886 | 42 | encoding = os.getenv("LANG").split(".")[1] | ||
1887 | 43 | except: | ||
1888 | 44 | encoding = "ascii" | ||
1889 | 45 | return unicode(output, encoding, errors) |
A day's worth of plugin hacking. Unfortunately, rather disparate.