2003-03-12 07:26:59 +01:00
#!/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.
###
2003-03-25 07:53:51 +01:00
"""
Provides a multitude of fun , useless commands .
"""
2003-03-12 07:26:59 +01:00
from baseplugin import *
2003-08-07 08:25:33 +02:00
from itertools import imap , ifilter
2003-03-12 07:26:59 +01:00
import os
import gc
import re
2003-04-02 09:27:00 +02:00
import imp
import sys
2003-03-12 07:26:59 +01:00
import new
import md5
import sha
import time
import math
import cmath
2003-09-03 19:18:38 +02:00
import getopt
2003-08-25 21:34:25 +02:00
import socket
2003-03-12 07:26:59 +01:00
import string
import random
import urllib
import inspect
2003-09-06 23:51:21 +02:00
import textwrap
2003-08-25 21:34:25 +02:00
import telnetlib
2003-03-12 07:26:59 +01:00
import threading
import mimetypes
2003-09-01 10:05:14 +02:00
# Stupid printing on import...
from cStringIO import StringIO
sys . stdout = StringIO ( )
import this
sys . stdout = sys . __stdout__
2003-03-12 07:26:59 +01:00
#import conf
import debug
2003-04-03 11:11:57 +02:00
import utils
2003-03-12 07:26:59 +01:00
import ircmsgs
import privmsgs
import callbacks
2003-08-27 18:25:43 +02:00
example = utils . wrapLines ( """
2003-08-25 22:12:21 +02:00
< jemfinch > @list FunCommands
< supybot > base , binary , calc , chr , coin , cpustats , decode , dice , dns , encode , hexlify , kernel , last , lastfrom , leet , levenshtein , lithp , md5 , mimetype , netstats , objects , ord , pydoc , rot13 , rpn , sha , soundex , unhexlify , uptime , urlquote , urlunquote , xor
< jemfinch > @netstats
< supybot > I have received 211 messages for a total of 19535 bytes . I have sent 109 messages for a total of 8672 bytes .
< jemfinch > @ord A
< supybot > 65
< jemfinch > @chr 65
< supybot > A
< jemfinch > @base 2 10101010101001010101010101
< supybot > 44733781
< jemfinch > @binary jemfinch
< supybot > 0110101001100101011011010110011001101001011011100110001101101000
< jemfinch > ( that ' s what the bits in a string look like for ' jemfinch ' )
< jemfinch > @encode string - escape " \x00 \x01 "
< supybot > \x00 \x01
< jemfinch > @decode string - escape " \\ x01 \\ x02 "
< supybot > ' \x01 \x02 '
< jemfinch > @hexlify jemfinch
< supybot > 6 a656d66696e6368
< jemfinch > @unhexlify 6 a656d66696e6368
< supybot > jemfinch
< jemfinch > @xor password The quick brown fox jumps over the lazy dog .
< supybot > ' $ \t \x16 S \x06 \x1a \x1b \x07 \x1b A \x11 \x01 \x18 \x18 \x1c D \x16 \x0e \x0b S \x1d \x1a \x1f \x14 \x03 A \x1c \x05 \x12 \x1d R \x10 \x18 \x04 S \x1f \x16 \x15 \x0b D \x14 \x0e \x14 ] '
< jemfinch > ( now watch this - - a nested command : ) )
< jemfinch > @xor password [ xor password The quick brown fox jumps over the lazy dog . ]
< supybot > The quick brown fox jumps over the lazy dog .
< jemfinch > ( xor is a reversible encryption method . It ' s easy to crack, so don ' t use it for real things : ) )
< jemfinch > @rot13 jemfinch
< supybot > wrzsvapu
< jemfinch > @rot13 [ rot13 jemfinch ]
< supybot > jemfinch
< jemfinch > @mimetype someSong . mp3
< supybot > audio / mpeg
< jemfinch > @md5 jemfinch
< supybot > cb2faabafafa9037493cf33779a2dc2e
< jemfinch > @unhexlify [ md5 jemfinch ]
< supybot > / 7 I < 7 y .
< jemfinch > @sha jemfinch
< supybot > b06a020b92ff41317f152139a4dda98f6c638812
< jemfinch > @coin
< supybot > heads
< jemfinch > @coin
< supybot > heads
< jemfinch > @coin
< supybot > tails
< jemfinch > @dice 2 d20
< supybot > 3 and 10
< jemfinch > @lithp Sally sells seashells by the seashore .
< supybot > THally thellth theathellth by the theathore .
< jemfinch > @dice 4 d100
< supybot > 25 , 97 , 85 , and 93
< jemfinch > @leet All your base are belong to us ! !
< supybot > 411 y0ur b453 4 r3 b310ng + 0 uz ! !
< jemfinch > @cpustats
< supybot > I have taken 5.4 seconds of user time and 0.29 seconds of system time , for a total of 5.69 seconds of CPU time . My children have taken 0.0 seconds of user time and 0.0 seconds of system time for a total of 0.0 seconds of CPU time . I ' ve taken a total of 0.00329929635973 % o f this computer ' s time . Out of 2 spawned threads , I have 1 active .
< jemfinch > @uptime
< supybot > I have been running for 28 minutes and 47 seconds .
< jemfinch > @calc e * * ( i * pi ) + 1
< supybot > 0
< jemfinch > @calc 1 + 2 + 3
< supybot > 6
< jemfinch > @rpn 1 2 3 + +
< supybot > 6
< jemfinch > @objects
< supybot > I have 24941 objects : 234 modules , 716 classes , 5489 functions , 1656 dictionaries , 827 lists , and 14874 tuples ( and a few other different types ) . I have a total of 119242 references .
< jemfinch > @levenshtein supybot supbot
< supybot > 1
< jemfinch > ( taht ' s the edit distance between " supybot " and " supbot " )
< jemfinch > @soundex jemfinch
< supybot > J515
< jemfinch > @soundex supercallifragilisticexpealadocious
< supybot > S162
< jemfinch > @soundex supercallifragilisticexpealadocious 20
< supybot > S1624162423221432200
< jemfinch > @pydoc str
< supybot > str ( object ) - > string . Return a nice string representation of the object . If the argument is a string , the return value is the same object .
< jemfinch > @dns kernel . org
< supybot > 204.152 .189 .116
2003-08-30 21:30:28 +02:00
< jemfinch > @zen
< supybot > jemfinch : Beautiful is better than ugly .
2003-09-05 12:56:30 +02:00
< jemfinch > @whois ohio - state . edu
< supybot > jemfinch : ohio - state . edu < http : / / www . educause . edu / edudomain > is active ; registered 18 - aug - 1987 , updated 19 - aug - 2003 , expires 18 - aug - 2004.
2003-08-27 18:25:43 +02:00
""" )
2003-08-25 22:12:21 +02:00
2003-03-12 07:26:59 +01:00
class FunCommands ( callbacks . Privmsg ) :
2003-09-05 21:28:04 +02:00
priority = 98 # Really just to test.
2003-03-12 07:26:59 +01:00
def __init__ ( self ) :
callbacks . Privmsg . __init__ ( self )
self . sentMsgs = 0
self . recvdMsgs = 0
self . sentBytes = 0
self . recvdBytes = 0
def inFilter ( self , irc , msg ) :
self . recvdMsgs + = 1
self . recvdBytes + = len ( str ( msg ) )
return msg
def outFilter ( self , irc , msg ) :
self . sentMsgs + = 1
self . sentBytes + = len ( str ( msg ) )
return msg
def netstats ( self , irc , msg , args ) :
2003-04-16 10:26:58 +02:00
""" takes no arguments
Returns some interesting network - related statistics .
"""
2003-03-12 07:26:59 +01:00
irc . reply ( msg ,
' I have received %s messages for a total of %s bytes. ' \
' I have sent %s messages for a total of %s bytes. ' % \
( self . recvdMsgs , self . recvdBytes ,
self . sentMsgs , self . sentBytes ) )
2003-08-28 00:43:29 +02:00
def hexip ( self , irc , msg , args ) :
""" <ip>
Returns the hexadecimal IP for that IP .
"""
ip = privmsgs . getArgs ( args )
if not ircutils . isIP ( ip ) :
irc . error ( msg , ' %r is not a valid IP. ' % ip )
return
quads = ip . split ( ' . ' )
ret = " "
for quad in quads :
i = int ( quad )
ret + = ' %02x ' % i
irc . reply ( msg , ret . upper ( ) )
2003-03-15 12:18:28 +01:00
def ord ( self , irc , msg , args ) :
""" <letter>
2003-03-15 11:00:49 +01:00
2003-03-15 12:18:28 +01:00
Returns the 8 - bit value of < letter > .
"""
letter = privmsgs . getArgs ( args )
if len ( letter ) != 1 :
irc . error ( msg , ' Letter must be of length 1 (for obvious reasons) ' )
else :
2003-06-13 18:53:33 +02:00
irc . reply ( msg , str ( ord ( letter ) ) )
2003-03-15 11:00:49 +01:00
2003-03-15 12:18:28 +01:00
def chr ( self , irc , msg , args ) :
""" <number>
2003-03-15 11:00:49 +01:00
2003-03-15 12:18:28 +01:00
Returns the character associated with the 8 - bit value < number >
"""
try :
2003-03-15 13:00:31 +01:00
i = privmsgs . getArgs ( args )
if i . startswith ( ' 0x ' ) :
base = 16
elif i . startswith ( ' 0b ' ) :
base = 2
i = i [ 2 : ]
elif i . startswith ( ' 0 ' ) :
base = 8
else :
base = 10
i = int ( i , base )
2003-03-15 12:18:28 +01:00
irc . reply ( msg , chr ( i ) )
except ValueError :
irc . error ( msg , ' That number doesn \' t map to an 8-bit character. ' )
2003-08-20 18:26:23 +02:00
2003-03-15 13:00:31 +01:00
def base ( self , irc , msg , args ) :
""" <base> <number>
2003-03-31 12:08:22 +02:00
Converts from base < base > the number < number >
2003-03-15 13:00:31 +01:00
"""
( base , number ) = privmsgs . getArgs ( args , needed = 2 )
irc . reply ( msg , str ( long ( number , int ( base ) ) ) )
2003-03-31 12:08:22 +02:00
def binary ( self , irc , msg , args ) :
""" <text>
Returns the binary representation of < text > .
"""
L = [ ]
for c in privmsgs . getArgs ( args ) :
2003-06-12 18:05:27 +02:00
LL = [ ]
2003-03-31 12:08:22 +02:00
i = ord ( c )
2003-06-12 18:05:27 +02:00
counter = 8
2003-03-31 12:08:22 +02:00
while i :
2003-06-12 18:05:27 +02:00
counter - = 1
2003-03-31 12:08:22 +02:00
if i & 1 :
2003-06-12 18:05:27 +02:00
LL . append ( ' 1 ' )
2003-03-31 12:08:22 +02:00
else :
2003-06-12 18:05:27 +02:00
LL . append ( ' 0 ' )
2003-03-31 12:08:22 +02:00
i >> = 1
2003-06-12 18:05:27 +02:00
while counter :
LL . append ( ' 0 ' )
counter - = 1
LL . reverse ( )
L . extend ( LL )
2003-03-31 12:08:22 +02:00
irc . reply ( msg , ' ' . join ( L ) )
2003-08-20 18:26:23 +02:00
2003-07-31 08:43:19 +02:00
def encode ( self , irc , msg , args ) :
""" <encoding> <text>
Returns an encoded form of the given text ; the valid encodings are
2003-09-06 10:39:50 +02:00
available in the documentation of the Python codecs module :
< http : / / www . python . org / doc / lib / node126 . html > .
2003-07-31 08:43:19 +02:00
"""
encoding , text = privmsgs . getArgs ( args , needed = 2 )
irc . reply ( msg , text . encode ( encoding ) )
def decode ( self , irc , msg , args ) :
""" <encoding> <text>
Returns an un - encoded form of the given text ; the valid encodings are
2003-09-06 10:39:50 +02:00
available in the documentation of the Python codecs module :
< http : / / www . python . org / doc / lib / node126 . html > .
2003-07-31 08:43:19 +02:00
"""
encoding , text = privmsgs . getArgs ( args , needed = 2 )
irc . reply ( msg , text . decode ( encoding ) . encode ( ' utf-8 ' ) )
2003-08-20 18:26:23 +02:00
2003-03-12 07:26:59 +01:00
def hexlify ( self , irc , msg , args ) :
2003-04-16 10:26:58 +02:00
""" <text>
Returns a hexstring from the given string ; a hexstring is a string
composed of the hexadecimal value of each character in the string
"""
2003-03-12 07:26:59 +01:00
text = privmsgs . getArgs ( args )
2003-08-28 19:56:27 +02:00
irc . reply ( msg , text . encode ( ' hex_codec ' ) )
2003-03-12 07:26:59 +01:00
def unhexlify ( self , irc , msg , args ) :
2003-04-16 10:26:58 +02:00
""" <hexstring>
Returns the string corresponding to < hexstring > . Obviously ,
< hexstring > must be a string of hexadecimal digits .
"""
2003-03-12 07:26:59 +01:00
text = privmsgs . getArgs ( args )
try :
2003-08-28 19:56:27 +02:00
irc . reply ( msg , text . decode ( ' hex_codec ' ) )
2003-03-12 07:26:59 +01:00
except TypeError :
irc . error ( msg , ' Invalid input. ' )
def xor ( self , irc , msg , args ) :
2003-04-16 10:26:58 +02:00
""" <password> <text>
Returns < text > XOR - encrypted with < password > . See
http : / / www . yoe . org / developer / xor . html for information about XOR
encryption .
"""
2003-03-12 07:26:59 +01:00
( password , text ) = privmsgs . getArgs ( args , 2 )
passwordlen = len ( password )
i = 0
ret = [ ]
for c in text :
ret . append ( chr ( ord ( c ) ^ ord ( password [ i ] ) ) )
i = ( i + 1 ) % passwordlen
2003-04-11 23:49:47 +02:00
irc . reply ( msg , ' ' . join ( ret ) )
2003-03-12 07:26:59 +01:00
def mimetype ( self , irc , msg , args ) :
2003-04-16 10:26:58 +02:00
""" <filename>
Returns the mime type associated with < filename >
"""
2003-03-12 07:26:59 +01:00
filename = privmsgs . getArgs ( args )
( type , encoding ) = mimetypes . guess_type ( filename )
if type is not None :
irc . reply ( msg , type )
else :
s = ' I couldn \' t figure out that filename. '
irc . reply ( msg , s )
def md5 ( self , irc , msg , args ) :
2003-04-16 10:26:58 +02:00
""" <text>
Returns the md5 hash of a given string . Read
http : / / www . rsasecurity . com / rsalabs / faq / 3 - 6 - 6. html for more information
about md5 .
"""
2003-03-12 07:26:59 +01:00
text = privmsgs . getArgs ( args )
irc . reply ( msg , md5 . md5 ( text ) . hexdigest ( ) )
def sha ( self , irc , msg , args ) :
2003-04-16 10:26:58 +02:00
""" <text>
Returns the SHA hash of a given string . Read
http : / / www . secure - hash - algorithm - md5 - sha - 1. co . uk / for more information
about SHA .
"""
2003-03-12 07:26:59 +01:00
text = privmsgs . getArgs ( args )
irc . reply ( msg , sha . sha ( text ) . hexdigest ( ) )
def urlquote ( self , irc , msg , args ) :
2003-04-16 10:26:58 +02:00
""" <text>
Returns the URL quoted form of the text .
"""
2003-03-12 07:26:59 +01:00
text = privmsgs . getArgs ( args )
irc . reply ( msg , urllib . quote ( text ) )
def urlunquote ( self , irc , msg , args ) :
2003-04-16 10:26:58 +02:00
""" <text>
Returns the text un - URL quoted .
"""
2003-03-12 07:26:59 +01:00
text = privmsgs . getArgs ( args )
s = urllib . unquote ( text )
irc . reply ( msg , s )
def rot13 ( self , irc , msg , args ) :
2003-04-16 10:26:58 +02:00
""" <text>
Rotates < text > 13 characters to the right in the alphabet . Rot13 is
commonly used for text that simply needs to be hidden from inadvertent
reading by roaming eyes , since it ' s easily reversible.
"""
2003-03-12 07:26:59 +01:00
text = privmsgs . getArgs ( args )
irc . reply ( msg , text . encode ( ' rot13 ' ) )
def coin ( self , irc , msg , args ) :
2003-04-16 10:26:58 +02:00
""" takes no arguments
Flips a coin and returns the result .
"""
2003-03-12 07:26:59 +01:00
if random . randrange ( 0 , 2 ) :
2003-04-16 10:26:58 +02:00
irc . reply ( msg , ' heads ' )
2003-03-12 07:26:59 +01:00
else :
2003-04-16 10:26:58 +02:00
irc . reply ( msg , ' tails ' )
2003-03-12 07:26:59 +01:00
_dicere = re . compile ( r ' ( \ d+)d( \ d+) ' )
def dice ( self , irc , msg , args ) :
2003-04-16 10:26:58 +02:00
""" <dice>d<sides>
Rolls a die with < sides > number of sides < dice > times .
For example , 2 d6 will roll 2 six - sided dice ; 10 d10 will roll 10
ten - sided dice .
"""
2003-03-12 07:26:59 +01:00
arg = privmsgs . getArgs ( args )
m = re . match ( self . _dicere , arg )
if m :
2003-03-31 12:45:41 +02:00
( dice , sides ) = map ( int , m . groups ( ) )
2003-03-12 07:26:59 +01:00
if dice > 6 :
irc . error ( msg , ' You can \' t roll more than 6 dice. ' )
elif sides > 100 :
irc . error ( msg , ' Dice can \' t have more than 100 sides. ' )
else :
L = [ 0 ] * dice
for i in xrange ( dice ) :
L [ i ] = random . randrange ( 1 , sides + 1 )
2003-08-25 22:12:21 +02:00
irc . reply ( msg , utils . commaAndify ( [ str ( x ) for x in L ] ) )
2003-03-12 07:26:59 +01:00
else :
irc . error ( msg , ' Dice must be of the form <dice>d<sides> ' )
2003-03-28 07:52:08 +01:00
def lithp ( self , irc , msg , args ) :
2003-04-16 10:26:58 +02:00
""" <text>
Returns the lisping version of < text >
"""
2003-03-28 07:52:08 +01:00
text = privmsgs . getArgs ( args )
2003-03-31 07:56:22 +02:00
text = text . replace ( ' sh ' , ' th ' )
text = text . replace ( ' SH ' , ' TH ' )
2003-03-28 08:00:15 +01:00
text = text . replace ( ' ss ' , ' th ' )
text = text . replace ( ' SS ' , ' th ' )
2003-03-28 07:57:48 +01:00
text = text . replace ( ' s ' , ' th ' )
2003-03-31 12:45:41 +02:00
text = text . replace ( ' z ' , ' th ' )
2003-03-28 07:57:48 +01:00
text = text . replace ( ' S ' , ' TH ' )
2003-03-31 12:45:41 +02:00
text = text . replace ( ' Z ' , ' TH ' )
2003-03-28 07:57:48 +01:00
text = text . replace ( ' x ' , ' kth ' )
text = text . replace ( ' X ' , ' KTH ' )
irc . reply ( msg , text )
2003-08-20 18:26:23 +02:00
2003-03-12 07:26:59 +01:00
_leettrans = string . maketrans ( ' oOaAeElBTiIts ' , ' 004433187!1+5 ' )
_leetres = ( ( re . compile ( r ' \ b(?:(?:[yY][o0O][oO0uU])|u) \ b ' ) , ' j00 ' ) ,
( re . compile ( r ' fear ' ) , ' ph33r ' ) ,
( re . compile ( r ' [aA][tT][eE] ' ) , ' 8 ' ) ,
( re . compile ( r ' [aA][tT] ' ) , ' @ ' ) ,
( re . compile ( r ' [sS] \ b ' ) , ' z ' ) ,
( re . compile ( r ' x ' ) , ' >< ' ) , )
def leet ( self , irc , msg , args ) :
2003-04-16 10:26:58 +02:00
""" <text>
Returns the l33tspeak version of < text >
"""
2003-03-12 07:26:59 +01:00
s = privmsgs . getArgs ( args )
for ( r , sub ) in self . _leetres :
s = re . sub ( r , sub , s )
s = s . translate ( self . _leettrans )
irc . reply ( msg , s )
def cpustats ( self , irc , msg , args ) :
2003-04-16 10:26:58 +02:00
""" takes no arguments
Returns some interesting CPU - related statistics on the bot .
"""
2003-03-12 07:26:59 +01:00
( user , system , childUser , childSystem , elapsed ) = os . times ( )
2003-04-02 11:31:50 +02:00
timeRunning = time . time ( ) - world . startedAt
2003-08-30 04:33:28 +02:00
activeThreads = threading . activeCount ( )
2003-03-12 07:26:59 +01:00
response = ' I have taken %s seconds of user time and %s seconds of ' \
' system time, for a total of %s seconds of CPU time. My ' \
' children have taken %s seconds of user time and %s seconds ' \
' of system time for a total of %s seconds of CPU time. ' \
' I \' ve taken a total of %s %% of this computer \' s time. ' \
2003-09-03 11:38:17 +02:00
' Out of %s I have %s active. ' \
' I have processed %s . ' % \
2003-03-12 07:26:59 +01:00
( user , system , user + system ,
childUser , childSystem , childUser + childSystem ,
( user + system + childUser + childSystem ) / timeRunning ,
2003-09-03 11:38:17 +02:00
utils . nItems ( world . threadsSpawned , ' thread ' , ' spawned ' ) ,
2003-09-01 07:42:35 +02:00
activeThreads ,
2003-09-03 11:38:17 +02:00
utils . nItems ( world . commandsProcessed , ' command ' ) )
2003-03-12 07:26:59 +01:00
irc . reply ( msg , response )
def uptime ( self , irc , msg , args ) :
2003-09-01 07:42:35 +02:00
""" takes no arguments.
Returns the amount of time the bot has been running .
"""
2003-04-03 11:11:57 +02:00
response = ' I have been running for %s . ' % \
2003-05-20 17:37:25 +02:00
utils . timeElapsed ( time . time ( ) - world . startedAt )
2003-03-12 07:26:59 +01:00
irc . reply ( msg , response )
###
# So this is how the 'calc' command works:
# First, we make a nice little safe environment for evaluation; basically,
# the names in the 'math' and 'cmath' modules. Then, we remove the ability
# of a random user to get ints evaluated: this means we have to turn all
# int literals (even octal numbers and hexadecimal numbers) into floats.
# Then we delete all square brackets, underscores, and whitespace, so no
# one can do list comprehensions or call __...__ functions.
###
2003-04-11 22:04:43 +02:00
_mathEnv = { ' __builtins__ ' : new . module ( ' __builtins__ ' ) , ' i ' : 1 j }
2003-03-12 07:26:59 +01:00
_mathEnv . update ( math . __dict__ )
_mathEnv . update ( cmath . __dict__ )
_mathInt = re . compile ( r ' (?<! \ d| \ .)( \ d+)(?! \ d+| \ .| \ . \ d+) ' )
_mathHex = re . compile ( r ' (0x[A-Fa-f \ d]+) ' )
2003-08-15 02:42:35 +02:00
_mathOctal = re . compile ( r ' (^|[^ \ dA-Fa-f.])(0[0-7]+) ' )
2003-04-20 10:52:59 +02:00
def _complexToString ( self , x ) :
real = x . real
imag = x . imag
2003-09-06 07:25:05 +02:00
if - 1e-12 < real < 1e-12 and - 1e-12 < imag < 1e-12 :
2003-04-20 10:52:59 +02:00
return ' 0 '
if int ( real ) == real :
real = int ( real )
if int ( imag ) == imag :
imag = int ( imag )
2003-09-06 07:25:05 +02:00
if - 1e-12 < real < 1e-12 :
2003-04-20 10:52:59 +02:00
real = 0
2003-09-06 07:25:05 +02:00
if - 1e-12 < imag < 1e-12 :
2003-04-20 10:52:59 +02:00
imag = 0
if imag == 0 :
return str ( real )
elif real == 0 :
return ' %s *i ' % imag
else :
return ' %s + %s i ' % ( real , imag )
2003-08-20 18:26:23 +02:00
2003-03-12 07:26:59 +01:00
def calc ( self , irc , msg , args ) :
2003-04-16 10:26:58 +02:00
""" <math expression>
Returns the value of the evaluted < math expression > . The syntax is
Python syntax ; the type of arithmetic is floating point .
"""
2003-03-12 07:26:59 +01:00
text = privmsgs . getArgs ( args )
text = text . translate ( string . ascii , ' _[] \t ' )
text = text . replace ( ' lambda ' , ' ' )
def hex2float ( m ) :
literal = m . group ( 1 )
i = long ( literal , 16 )
return ' %s .0 ' % i
def oct2float ( m ) :
( previous , literal ) = m . groups ( )
i = long ( literal , 8 )
return ' %s %s .0 ' % ( previous , i )
text = self . _mathHex . sub ( hex2float , text )
2003-08-17 04:02:53 +02:00
#debug.printf('After unhexing: %r' % text)
2003-03-12 07:26:59 +01:00
text = self . _mathOctal . sub ( oct2float , text )
2003-08-17 04:02:53 +02:00
#debug.printf('After unocting: %r' % text)
2003-03-12 07:26:59 +01:00
text = self . _mathInt . sub ( r ' \ 1.0 ' , text )
2003-08-17 04:02:53 +02:00
#debug.printf('After uninting: %r' % text)
2003-03-12 07:26:59 +01:00
try :
x = complex ( eval ( text , self . _mathEnv , self . _mathEnv ) )
2003-04-20 10:52:59 +02:00
irc . reply ( msg , self . _complexToString ( x ) )
2003-03-31 12:18:40 +02:00
except OverflowError :
2003-03-31 12:34:22 +02:00
irc . reply ( msg , ' Go get scanez, this is a *real* math problem! ' )
2003-03-12 07:26:59 +01:00
except Exception , e :
irc . reply ( msg , debug . exnToString ( e ) )
2003-09-06 07:25:05 +02:00
_rpnEnv = {
' dup ' : lambda s : s . extend ( [ s . pop ( ) ] * 2 ) ,
}
2003-04-20 10:52:59 +02:00
def rpn ( self , irc , msg , args ) :
""" <rpn math expression>
Returns the value of an RPN expression .
"""
stack = [ ]
for arg in args :
try :
stack . append ( float ( arg ) )
except ValueError : # Not a float.
if arg in self . _mathEnv :
f = self . _mathEnv [ arg ]
if callable ( f ) :
called = False
arguments = [ ]
while not called and stack :
arguments . append ( stack . pop ( ) )
try :
stack . append ( f ( * arguments ) )
called = True
except TypeError :
pass
if not called :
irc . error ( msg , ' Not enough arguments for %s ' % arg )
return
else :
stack . append ( f )
2003-09-06 07:25:05 +02:00
elif arg in self . _rpnEnv :
self . _rpnEnv [ arg ] ( stack )
2003-04-20 10:52:59 +02:00
else :
arg2 = stack . pop ( )
arg1 = stack . pop ( )
2003-09-06 07:25:05 +02:00
s = ' %s %s %s ' % ( arg1 , arg , arg2 )
stack . append ( eval ( s , self . _mathEnv , self . _mathEnv ) )
2003-04-20 10:52:59 +02:00
if len ( stack ) == 1 :
irc . reply ( msg , str ( self . _complexToString ( complex ( stack [ 0 ] ) ) ) )
else :
2003-08-07 08:25:33 +02:00
s = ' , ' . join ( imap ( self . _complexToString , imap ( complex , stack ) ) )
2003-04-20 11:04:27 +02:00
irc . reply ( msg , ' Stack: [ %s ] ' % s )
2003-04-20 10:52:59 +02:00
2003-03-12 07:26:59 +01:00
def objects ( self , irc , msg , args ) :
2003-04-16 10:26:58 +02:00
""" takes no arguments.
Returns the number and types of Python objects in memory . """
2003-08-07 11:19:40 +02:00
classes = 0
functions = 0
modules = 0
dicts = 0
lists = 0
tuples = 0
2003-08-11 07:06:41 +02:00
refcounts = 0
2003-03-12 07:26:59 +01:00
objs = gc . get_objects ( )
2003-08-07 11:19:40 +02:00
for obj in objs :
if isinstance ( obj , tuple ) :
tuples + = 1
elif inspect . isroutine ( obj ) :
functions + = 1
elif isinstance ( obj , dict ) :
dicts + = 1
elif isinstance ( obj , list ) :
lists + = 1
elif inspect . isclass ( obj ) :
classes + = 1
elif inspect . ismodule ( obj ) :
modules + = 1
2003-08-11 07:06:41 +02:00
refcounts + = sys . getrefcount ( obj )
2003-03-12 07:26:59 +01:00
response = ' I have %s objects: %s modules, %s classes, %s functions, ' \
' %s dictionaries, %s lists, and %s tuples (and a few other ' \
2003-08-11 07:06:41 +02:00
' different types). I have a total of %s references. ' % \
2003-03-12 07:26:59 +01:00
( len ( objs ) , modules , classes , functions ,
2003-08-11 07:06:41 +02:00
dicts , lists , tuples , refcounts )
2003-03-12 07:26:59 +01:00
irc . reply ( msg , response )
2003-04-04 17:49:24 +02:00
def levenshtein ( self , irc , msg , args ) :
""" <string1> <string2>
Returns the levenshtein distance ( also known as the " edit distance "
between < string1 > and < string2 >
"""
( s1 , s2 ) = privmsgs . getArgs ( args , needed = 2 )
irc . reply ( msg , str ( utils . distance ( s1 , s2 ) ) )
2003-04-05 13:23:28 +02:00
def soundex ( self , irc , msg , args ) :
""" <string> [<length>]
Returns the Soundex hash to a given length . The length defaults to
4 , since that ' s the standard length for a soundex hash. For unlimited
length , use 0.
"""
( s , length ) = privmsgs . getArgs ( args , optional = 1 )
if length :
length = int ( length )
else :
length = 4
irc . reply ( msg , utils . soundex ( s , length ) )
2003-04-02 09:27:00 +02:00
modulechars = ' %s %s %s ' % ( string . ascii_letters , string . digits , ' _. ' )
def pydoc ( self , irc , msg , args ) :
""" <python function>
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 ( ' . ' )
module = ' . ' . join ( parts [ : - 1 ] )
2003-04-02 10:13:10 +02:00
if module not in __builtins__ and module not in sys . modules :
2003-04-02 09:27:00 +02:00
path = os . path . dirname ( os . __file__ )
for name in parts [ : - 1 ] :
try :
info = imp . find_module ( name , path )
newmodule = imp . load_module ( name , * info )
path = newmodule . __path__
info [ 1 ] . close ( )
except ImportError :
irc . error ( msg , ' No such module %s exists. ' % module )
return
try :
s = eval ( funcname + ' .__doc__ ' )
2003-04-03 09:38:46 +02:00
s = s . replace ( ' \n \n ' , ' . ' )
s = ' ' . join ( s . split ( ) )
2003-09-03 20:16:06 +02:00
except ( SyntaxError , NameError ) :
2003-08-17 04:02:53 +02:00
irc . error ( msg , ' No such function exists. ' )
return
2003-04-02 09:27:00 +02:00
except AttributeError :
2003-08-17 04:02:53 +02:00
irc . error ( msg , ' That function has no documentation. ' )
return
2003-04-02 09:27:00 +02:00
irc . reply ( msg , s )
2003-08-20 18:26:23 +02:00
2003-09-07 07:26:18 +02:00
_eightballs = (
2003-08-29 09:49:11 +02:00
' outlook not so good. ' ,
' my reply is no. ' ,
' don \' t count on it. ' ,
' you may rely on it. ' ,
' ask again later. ' ,
' most likely. ' ,
' cannot predict now. ' ,
' yes. ' ,
' yes, most definitely. ' ,
' better not tell you now. ' ,
' it is certain. ' ,
' very doubtful. ' ,
' it is decidedly so. ' ,
' concentrate and ask again. ' ,
' signs point to yes. ' ,
' my sources say no. ' ,
' without a doubt. ' ,
' reply hazy, try again. ' ,
' as I see it, yes. ' ,
2003-09-07 07:26:18 +02:00
)
2003-08-29 09:49:11 +02:00
def eightball ( self , irc , msg , args ) :
""" [<question>]
Asks the magic eightball a question .
"""
irc . reply ( msg , random . sample ( self . _eightballs , 1 ) [ 0 ] )
2003-08-30 21:23:34 +02:00
_these = [ str ( s ) for s in this . s . decode ( ' rot13 ' ) . splitlines ( ) if s ]
2003-08-30 21:25:14 +02:00
_these . pop ( 0 )
2003-08-30 21:23:34 +02:00
def zen ( self , irc , msg , args ) :
""" takes no arguments.
Returns one of the zen of Python statements .
"""
irc . reply ( msg , random . sample ( self . _these , 1 ) [ 0 ] )
2003-09-06 23:51:21 +02:00
_lesses = { }
def less ( self , irc , msg , args ) :
""" <text>
Deals out < text > in small , IrcMsg - sized pieces . Mostly useful for
piecing - out nested commands .
"""
text = privmsgs . getArgs ( args , needed = 0 , optional = 1 )
userHostmask = msg . prefix . split ( ' ! ' , 1 ) [ 1 ]
if text :
lines = textwrap . wrap ( text , 400 )
lines . reverse ( )
s = lines . pop ( )
self . _lesses [ userHostmask ] = lines
irc . reply ( msg , s )
else :
try :
s = self . _lesses [ userHostmask ] . pop ( )
irc . reply ( msg , s )
except ( KeyError , IndexError ) : # Nothing in the list or dict.
irc . error ( msg , ' I have no less history for you. ' )
2003-08-25 21:34:25 +02:00
def dns ( self , irc , msg , args ) :
2003-09-03 11:38:17 +02:00
""" <host|ip>
Returns the ip of < host > or the reverse DNS hostname of < ip > .
"""
2003-08-25 21:34:25 +02:00
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 )
irc . reply ( msg , ip )
except socket . error :
irc . error ( msg , ' Host not found. ' )
dns = privmsgs . thread ( dns )
2003-09-05 11:59:59 +02:00
_domains = sets . Set ( [ ' com ' , ' net ' , ' edu ' ] )
def whois ( self , irc , msg , args ) :
""" <domain>
Returns WHOIS information on the registration of < domain > . < domain >
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 , ' <domain> 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 )
2003-09-03 11:38:17 +02:00
2003-03-12 07:26:59 +01:00
Class = FunCommands
2003-04-03 10:24:52 +02:00
2003-03-24 09:41:19 +01:00
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: