diff --git a/plugins/FunCommands.py b/plugins/FunCommands.py index d078cd0c6..68c0fe10a 100644 --- a/plugins/FunCommands.py +++ b/plugins/FunCommands.py @@ -54,12 +54,6 @@ import telnetlib import threading import mimetypes -# Stupid printing on import... -from cStringIO import StringIO -sys.stdout = StringIO() -import this -sys.stdout = sys.__stdout__ - #import conf import debug import utils @@ -466,54 +460,6 @@ class FunCommands(callbacks.Privmsg): length = 4 irc.reply(msg, utils.soundex(s, length)) - modulechars = '%s%s%s' % (string.ascii_letters, string.digits, '_.') - def pydoc(self, irc, msg, args): - """ - - Returns the __doc__ string for a given Python function. - """ - funcname = privmsgs.getArgs(args) - if funcname.translate(string.ascii, self.modulechars) != '': - irc.error('That\'s not a valid module or function name.') - return - if '.' in funcname: - parts = funcname.split('.') - functionName = parts.pop() - path = os.path.dirname(os.__file__) - for name in parts: - try: - info = imp.find_module(name, [path]) - newmodule = imp.load_module(name, *info) - path = os.path.dirname(newmodule.__file__) - info[0].close() - except ImportError: - irc.error(msg, 'No such module %s exists.' % module) - return - if hasattr(newmodule, functionName): - f = getattr(newmodule, functionName) - if hasattr(f, '__doc__'): - s = f.__doc__.replace('\n\n', '. ') - s = utils.normalizeWhitespace(s) - irc.reply(msg, s) - else: - irc.error(msg, 'That function has no documentation.') - else: - irc.error(msg, 'That function doesn\'t exist.') - else: - try: - f = __builtins__[funcname] - if hasattr(f, '__doc__'): - s = f.__doc__.replace('\n\n', '. ') - s = utils.normalizeWhitespace(s) - irc.reply(msg, s) - else: - irc.error(msg, 'That function has no documentation.') - except SyntaxError: - irc.error(msg, 'That\'s not a function!') - except KeyError: - irc.error(msg, 'That function doesn\'t exist.') - - _eightballs = ( 'outlook not so good.', 'my reply is no.', @@ -543,79 +489,6 @@ class FunCommands(callbacks.Privmsg): irc.reply(msg, random.choice(self._eightballs)) - _these = [str(s) for s in this.s.decode('rot13').splitlines() if s] - _these.pop(0) - def zen(self, irc, msg, args): - """takes no arguments - - Returns one of the zen of Python statements. - """ - irc.reply(msg, random.choice(self._these)) - - def dns(self, irc, msg, args): - """ - - Returns the ip of or the reverse DNS hostname of . - """ - host = privmsgs.getArgs(args) - if ircutils.isIP(host): - hostname = socket.getfqdn(host) - if hostname == host: - irc.error(msg, 'Host not found.') - else: - irc.reply(msg, hostname) - else: - try: - ip = socket.gethostbyname(host) - if ip == '64.94.110.11': - irc.reply(msg, 'Host not found.') - else: - irc.reply(msg, ip) - except socket.error: - irc.error(msg, 'Host not found.') - dns = privmsgs.thread(dns) - - _domains = sets.Set(['com', 'net', 'edu']) - def whois(self, irc, msg, args): - """ - - Returns WHOIS information on the registration of . - must be in tlds .com, .net, or .edu. - """ - domain = privmsgs.getArgs(args) - if '.' not in domain or domain.split('.')[-1] not in self._domains: - irc.error(msg, ' must be in .com, .net, or .edu.') - return - t = telnetlib.Telnet('rs.internic.net', 43) - t.write(domain) - t.write('\n') - s = t.read_all() - for line in s.splitlines(): - line = line.strip() - if not line: - continue - if line.startswith('Registrar'): - registrar = line.split()[-1].capitalize() - elif line.startswith('Referral'): - url = line.split()[-1] - elif line.startswith('Updated'): - updated = line.split()[-1] - elif line.startswith('Creation'): - created = line.split()[-1] - elif line.startswith('Expiration'): - expires = line.split()[-1] - elif line.startswith('Status'): - status = line.split()[-1].lower() - try: - s = '%s <%s> is %s; registered %s, updated %s, expires %s.' % \ - (domain, url, status, created, updated, expires) - irc.reply(msg, s) - except NameError, e: - debug.printf(e) - irc.error(msg, 'I couldn\'t find such a domain.') - whois = privmsgs.thread(whois) - - Class = FunCommands diff --git a/plugins/Network.py b/plugins/Network.py new file mode 100644 index 000000000..4a8d94555 --- /dev/null +++ b/plugins/Network.py @@ -0,0 +1,130 @@ +#!/usr/bin/python + +### +# Copyright (c) 2002, Jeremiah Fincher +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +### + +""" +Various network-related commands. +""" + +from baseplugin import * + +import sets +import socket +import telnetlib + +import debug +import utils +import ircutils +import privmsgs +import callbacks + + +def configure(onStart, afterConnect, advanced): + # This will be called by setup.py to configure this module. onStart and + # afterConnect are both lists. Append to onStart the commands you would + # like to be run when the bot is started; append to afterConnect the + # commands you would like to be run when the bot has finished connecting. + from questions import expect, anything, something, yn + onStart.append('load Network') + +example = utils.wrapLines(""" +Add an example IRC session using this module here. +""") + +class Network(callbacks.Privmsg): + threaded = True + def dns(self, irc, msg, args): + """ + + Returns the ip of or the reverse DNS hostname of . + """ + host = privmsgs.getArgs(args) + if ircutils.isIP(host): + hostname = socket.getfqdn(host) + if hostname == host: + irc.error(msg, 'Host not found.') + else: + irc.reply(msg, hostname) + else: + try: + ip = socket.gethostbyname(host) + if ip == '64.94.110.11': # Verisign sucks! + irc.reply(msg, 'Host not found.') + else: + irc.reply(msg, ip) + except socket.error: + irc.error(msg, 'Host not found.') + + _tlds = sets.Set(['com', 'net', 'edu']) + def whois(self, irc, msg, args): + """ + + Returns WHOIS information on the registration of . + must be in tlds .com, .net, or .edu. + """ + domain = privmsgs.getArgs(args) + if '.' not in domain or domain.split('.')[-1] not in self._tlds: + irc.error(msg, ' must be in .com, .net, or .edu.') + return + elif len(domain.split('.')) != 2: + irc.error(msg, ' must be a domain, not a hostname.') + return + t = telnetlib.Telnet('rs.internic.net', 43) + t.write(domain) + t.write('\n') + s = t.read_all() + for line in s.splitlines(): + line = line.strip() + if not line: + continue + if line.startswith('Registrar'): + registrar = line.split()[-1].capitalize() + elif line.startswith('Referral'): + url = line.split()[-1] + elif line.startswith('Updated'): + updated = line.split()[-1] + elif line.startswith('Creation'): + created = line.split()[-1] + elif line.startswith('Expiration'): + expires = line.split()[-1] + elif line.startswith('Status'): + status = line.split()[-1].lower() + try: + s = '%s <%s> is %s; registered %s, updated %s, expires %s.' % \ + (domain, url, status, created, updated, expires) + irc.reply(msg, s) + except NameError, e: + #debug.printf(e) + irc.error(msg, 'I couldn\'t find such a domain.') + + +Class = Network + +# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: diff --git a/plugins/Python.py b/plugins/Python.py new file mode 100644 index 000000000..fed68a9e9 --- /dev/null +++ b/plugins/Python.py @@ -0,0 +1,126 @@ +#!/usr/bin/python + +### +# Copyright (c) 2002, Jeremiah Fincher +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +### + +""" +Various commands relating to Python (the programming language supybot is +written in) somehow. +""" + +from baseplugin import * + +import os +import imp +import random + +# Stupid printing on import... +from cStringIO import StringIO +sys.stdout = StringIO() +import this +sys.stdout = sys.__stdout__ + +import utils +import privmsgs +import callbacks + + +def configure(onStart, afterConnect, advanced): + # This will be called by setup.py to configure this module. onStart and + # afterConnect are both lists. Append to onStart the commands you would + # like to be run when the bot is started; append to afterConnect the + # commands you would like to be run when the bot has finished connecting. + from questions import expect, anything, something, yn + onStart.append('load Python') + +example = utils.wrapLines(""" +Add an example IRC session using this module here. +""") + +class Python(callbacks.Privmsg): + modulechars = '%s%s%s' % (string.ascii_letters, string.digits, '_.') + def pydoc(self, irc, msg, args): + """ + + Returns the __doc__ string for a given Python function. + """ + funcname = privmsgs.getArgs(args) + if funcname.translate(string.ascii, self.modulechars) != '': + irc.error('That\'s not a valid module or function name.') + return + if '.' in funcname: + parts = funcname.split('.') + functionName = parts.pop() + path = os.path.dirname(os.__file__) + for name in parts: + try: + info = imp.find_module(name, [path]) + newmodule = imp.load_module(name, *info) + path = os.path.dirname(newmodule.__file__) + info[0].close() + except ImportError: + irc.error(msg, 'No such module %s exists.' % module) + return + if hasattr(newmodule, functionName): + f = getattr(newmodule, functionName) + if hasattr(f, '__doc__'): + s = f.__doc__.replace('\n\n', '. ') + s = utils.normalizeWhitespace(s) + irc.reply(msg, s) + else: + irc.error(msg, 'That function has no documentation.') + else: + irc.error(msg, 'That function doesn\'t exist.') + else: + try: + f = __builtins__[funcname] + if hasattr(f, '__doc__'): + s = f.__doc__.replace('\n\n', '. ') + s = utils.normalizeWhitespace(s) + irc.reply(msg, s) + else: + irc.error(msg, 'That function has no documentation.') + except SyntaxError: + irc.error(msg, 'That\'s not a function!') + except KeyError: + irc.error(msg, 'That function doesn\'t exist.') + + _these = [str(s) for s in this.s.decode('rot13').splitlines() if s] + _these.pop(0) # Initial line (The Zen of Python...) + def zen(self, irc, msg, args): + """takes no arguments + + Returns one of the zen of Python statements. + """ + irc.reply(msg, random.choice(self._these)) + + +Class = Python + +# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: diff --git a/test/test_FunCommands.py b/test/test_FunCommands.py index 86d9c933e..c46df7db4 100644 --- a/test/test_FunCommands.py +++ b/test/test_FunCommands.py @@ -51,11 +51,11 @@ class FunCommandsTest(PluginTestCase, PluginDocumentation): for s in nicks[:10]: # 10 is probably enough. self.assertResponse('rot13 [rot13 %s]' % s, s) -## def testChr(self): -## for i in range(256): -## c = chr(i) -## regexp = r'%s|%s' % (re.escape(c), re.escape(repr(c))) -## self.assertRegexp('chr %s' % i, regexp) + def testChr(self): + for i in range(256): + c = chr(i) + regexp = r'%s|%s' % (re.escape(c), re.escape(repr(c))) + self.assertRegexp('chr %s' % i, regexp) def testHexlifyUnhexlify(self): for s in nicks[:10]: # 10, again, is probably enough. @@ -72,28 +72,10 @@ class FunCommandsTest(PluginTestCase, PluginDocumentation): def testUrlquoteUrlunquote(self): self.assertResponse('urlunquote [urlquote ~jfincher]', '~jfincher') - def testPydoc(self): - self.assertNotError('pydoc str') - self.assertError('pydoc foobar') - self.assertError('pydoc assert') - self.assertNotError('pydoc string.translate') - self.assertNotError('pydoc fnmatch.fnmatch') - -## def testOrd(self): -## for c in map(chr, range(256)): -## i = ord(c) -## self.assertResponse('ord %s' % utils.dqrepr(c), str(i)) - - def testZen(self): - self.assertNotError('zen') - - def testDns(self): - self.assertNotError('dns slashdot.org') - self.assertResponse('dns alsdkjfaslkdfjaslkdfj.com', 'Host not found.') - - def testWhois(self): - self.assertNotError('whois ohio-state.edu') - self.assertError('whois slashdot.org') + def testOrd(self): + for c in map(chr, range(256)): + i = ord(c) + self.assertResponse('ord %s' % utils.dqrepr(c), str(i)) # vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: diff --git a/test/test_Network.py b/test/test_Network.py new file mode 100644 index 000000000..9188dd7e9 --- /dev/null +++ b/test/test_Network.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python + +### +# Copyright (c) 2002, Jeremiah Fincher +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +### + +from test import * + +class NetworkTestCase(PluginTestCase, PluginDocumentation): + plugins = ['Network'] + def testDns(self): + self.assertNotError('dns slashdot.org') + self.assertResponse('dns alsdkjfaslkdfjaslkdfj.com', 'Host not found.') + + def testWhois(self): + self.assertNotError('whois ohio-state.edu') + self.assertError('whois www.ohio-state.edu') + self.assertError('whois slashdot.org') + + +# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: + diff --git a/test/test_Python.py b/test/test_Python.py new file mode 100644 index 000000000..a3dd2b6c7 --- /dev/null +++ b/test/test_Python.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +### +# Copyright (c) 2002, Jeremiah Fincher +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +### + +from test import * + +class PythonTestCase(PluginTestCase, PluginDocumentation): + plugins = ('Python',) + def testPydoc(self): + self.assertError('pydoc foobar') + self.assertError('pydoc assert') + self.assertNotError('pydoc str') + self.assertNotError('pydoc string.translate') + self.assertNotError('pydoc fnmatch.fnmatch') + self.assertNotError('pydoc socket.socket') + + def testZen(self): + self.assertNotError('zen') + + +# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: +