예제 #1
0
class SourceFactory(client.DeferredClientFactory,
                    protocol.ReconnectingClientFactory,
                    IbidSourceFactory):
    auth = ('implicit',)
    supports = ('multiline',)

    jid_str = Option('jid', 'Jabber ID')
    server = Option('server', 'Server hostname (defaults to SRV lookup, '
                              'falling back to JID domain)')
    port = IntOption('port', 'Server port number (defaults to SRV lookup, '
                             'falling back to 5222/5223')
    ssl = BoolOption('ssl', 'Use SSL instead of automatic TLS')
    password = Option('password', 'Jabber password')
    nick = Option('nick', 'Nick for chatrooms', ibid.config['botname'])
    rooms = ListOption('rooms', 'Chatrooms to autojoin', [])
    accept_domains = ListOption('accept_domains',
            'Only accept messages from these domains', [])
    max_public_message_length = IntOption('max_public_message_length',
            'Maximum length of public messages', 512)

    def __init__(self, name):
        IbidSourceFactory.__init__(self, name)
        self.log = logging.getLogger('source.%s' % name)
        client.DeferredClientFactory.__init__(self, JID(self.jid_str),
                                              self.password)
        bot = JabberBot()
        self.addHandler(bot)
        bot.setHandlerParent(self)

    def setServiceParent(self, service):
        c = IbidXMPPClientConnector(reactor, self.authenticator.jid.host, self,
                                    self.server, self.port, self.ssl)
        c.connect()

    def connect(self):
        return self.setServiceParent(None)

    def disconnect(self):
        self.stopTrying()
        self.stopFactory()
        self.proto.xmlstream.transport.loseConnection()
        return True

    def join(self, room):
        return self.proto.join(room)

    def leave(self, room):
        return self.proto.leave(room)

    def url(self):
        return u'xmpp://%s' % (self.jid_str,)

    def logging_name(self, identity):
        return identity.split('/')[0]

    def truncation_point(self, response, event=None):
        if response.get('target', None) in self.proto.rooms:
            return self.max_public_message_length
        return None
예제 #2
0
파일: silc.py 프로젝트: shoosen/ibid
class SourceFactory(IbidSourceFactory):

    auth = ('implicit', )
    supports = ('action', 'topic')

    server = Option('server', 'Server hostname')
    port = IntOption('port', 'Server port number', 706)
    nick = Option('nick', 'Nick', ibid.config['botname'])
    channels = ListOption('channels', 'Channels to autojoin', [])
    realname = Option('realname', 'Real Name', ibid.config['botname'])
    public_key = Option('public_key', 'Filename of public key', 'silc.pub')
    private_key = Option('private_key', 'Filename of private key', 'silc.prv')
    max_public_message_length = IntOption('max_public_message_length',
                                          'Maximum length of public messages',
                                          512)

    def __init__(self, name):
        IbidSourceFactory.__init__(self, name)
        self.log = logging.getLogger('source.%s' % self.name)
        pub = join(ibid.options['base'], self.public_key)
        prv = join(ibid.options['base'], self.private_key)
        if not exists(pub) and not exists(prv):
            keys = create_key_pair(pub, prv, passphrase='')
        else:
            keys = load_key_pair(pub, prv, passphrase='')
        self.client = SilcBot(keys, self.nick, self.nick, self.realname, self)

    def run_one(self):
        self.client.run_one()

    def setServiceParent(self, service):
        self.s = internet.TimerService(0.2, self.run_one)
        if service is None:
            self.s.startService()
        else:
            self.s.setServiceParent(service)

    def disconnect(self):
        self.client.disconnect()
        return True

    def url(self):
        return u'silc://%s@%s:%s' % (self.nick, self.server, self.port)

    def logging_name(self, identity):
        return self.client.logging_name(identity)

    def truncation_point(self, response, event=None):
        if response.get('target', None) in self.client.channels:
            return self.max_public_message_length
        return None
예제 #3
0
class Ping(Processor):
    usage = u'ping <host>'
    features = ('ping',)

    ping = Option('ping', 'Path to ping executable', 'ping')

    def setup(self):
        if not file_in_path(self.ping):
            raise Exception("Cannot locate ping executable")

    @match(r'^ping\s+(\S+)$')
    def handle_ping(self, event, host):
        if host.strip().startswith("-"):
            event.addresponse(False)
            return

        ping = Popen([self.ping, '-q', '-c5', host], stdout=PIPE, stderr=PIPE)
        output, error = ping.communicate()
        ping.wait()

        if not error:
            output = unicode_output(output)
            output = u' '.join(output.splitlines()[-2:])
            event.addresponse(output)
        else:
            error = unicode_output(error).replace(u'\n', u' ') \
                                         .replace(u'ping:', u'', 1).strip()
            event.addresponse(u'Error: %s', error)
예제 #4
0
class Fortune(Processor, RPC):
    usage = u'fortune'
    features = ('fortune', )

    fortune = Option('fortune', 'Path of the fortune executable', 'fortune')

    def __init__(self, name):
        super(Fortune, self).__init__(name)
        RPC.__init__(self)

    def setup(self):
        if not file_in_path(self.fortune):
            raise Exception("Cannot locate fortune executable")

    @match(r'^fortune$')
    def handler(self, event):
        fortune = self.remote_fortune()
        if fortune:
            event.addresponse(fortune)
        else:
            event.addresponse(u"Couldn't execute fortune")

    def remote_fortune(self):
        fortune = Popen(self.fortune, stdout=PIPE, stderr=PIPE)
        output, error = fortune.communicate()
        code = fortune.wait()

        output = unicode_output(output.strip(), 'replace')

        if code == 0:
            return output
        else:
            return None
예제 #5
0
파일: google.py 프로젝트: vhata/ibid
class GoogleScrapeSearch(Processor):
    usage = u"""gcalc <expression>
    gdefine <term>"""

    features = ('google', )

    user_agent = Option(
        'user_agent',
        'HTTP user agent to present to Google (for non-API searches)',
        default_user_agent)

    def _google_scrape_search(self, query, country=None):
        params = {'q': query.encode('utf-8')}
        if country:
            params['cr'] = u'country' + country.upper()

        return get_html_parse_tree('http://www.google.com/search?' +
                                   urlencode(params),
                                   headers={'user-agent': self.user_agent},
                                   treetype='etree')

    @match(r'^gcalc\s+(.+)$')
    def calc(self, event, expression):
        tree = self._google_scrape_search(expression)

        nodes = [
            node for node in tree.findall('.//h2') if node.get('class') == 'r'
        ]
        if len(nodes) == 1:
            # ElementTree doesn't support inline tags:
            # May return ASCII unless an encoding is specified.
            # "utf8" will result in an xml header
            node = ElementTree.tostring(nodes[0], encoding='utf-8')
            node = node.decode('utf-8')
            node = re.sub(r'<sup>(.*?)</sup>', lambda x: u'^' + x.group(1),
                          node)
            node = re.sub(r'<.*?>', '', node)
            node = re.sub(r'(\d)\s+(\d)', lambda x: x.group(1) + x.group(2),
                          node)
            node = decode_htmlentities(node)
            node = re.sub(r'\s+', ' ', node)
            event.addresponse(node)
        else:
            event.addresponse(
                u"%s, Google wasn't interested in calculating that",
                choice(('Sorry', 'Whoops')))

    @match(r'^gdefine\s+(.+)$')
    def define(self, event, term):
        tree = self._google_scrape_search("define:%s" % term)

        definitions = []
        for li in tree.findall('.//li'):
            if li.text:
                definitions.append(li.text)

        if definitions:
            event.addresponse(u' :: '.join(definitions))
        else:
            event.addresponse(u'Are you making up words again?')
예제 #6
0
class AptFile(Processor):
    usage = u'apt-file [search] <term>'
    feature = ('apt-file',)

    aptfile = Option('apt-file', 'Path to apt-file executable', 'apt-file')

    def setup(self):
        if not file_in_path(self.aptfile):
            raise Exception("Cannot locate apt-file executable")

    @match(r'^apt-?file\s+(?:search\s+)?(.+)$')
    def search(self, event, term):
        apt = Popen([self.aptfile, 'search', term], stdout=PIPE, stderr=PIPE)
        output, error = apt.communicate()
        code = apt.wait()

        if code == 0:
            if output:
                output = unicode_output(output.strip())
                output = [line.split(u':')[0] for line in output.splitlines()]
                packages = sorted(set(output))
                event.addresponse(u'Found %(num)i packages: %(names)s', {
                    'num': len(packages),
                    'names': human_join(packages),
                })
            else:
                event.addresponse(u'No packages found')
        else:
            error = unicode_output(error.strip())
            if u"The cache directory is empty." in error:
                event.addresponse(u'Search error: apt-file cache empty')
            else:
                event.addresponse(u'Search error')
            raise Exception("apt-file: %s" % error)
예제 #7
0
class DrawImage(Processor):
    usage = u'draw <url> [in colour] [width <width>] [height <height>]'
    feature = ('draw-aa',)

    max_filesize = IntOption('max_filesize', 'Only request this many KiB', 200)
    def_height = IntOption('def_height', 'Default height for libaa output', 10)
    max_width = IntOption('max_width', 'Maximum width for ascii output', 60)
    max_height = IntOption('max_height', 'Maximum height for ascii output', 15)
    font_width = IntOption('font_width', 'Font width assumed for output', 6)
    font_height = IntOption('font_height', 'Font height assumed for output', 10)
    img2txt_bin = Option('img2txt_bin', 'libcaca img2txt binary to use', 'img2txt')

    def setup(self):
        if not file_in_path(self.img2txt_bin):
            raise Exception('Cannot locate img2txt executable')

    @match(r'^draw\s+(\S+\.\S+)(\s+in\s+colou?r)?(?:\s+w(?:idth)?\s+(\d+))?(?:\s+h(?:eight)\s+(\d+))?$')
    def draw(self, event, url, colour, width, height):
        if not urlparse(url).netloc:
            url = 'http://' + url
        if urlparse(url).scheme == 'file':
            event.addresponse(u'Are you trying to haxor me?')
            return
        if not urlparse(url).path:
            url += '/'

        try:
            f = urlopen(url_to_bytestring(url))
        except HTTPError, e:
            event.addresponse(u'Sorry, error fetching URL: %s', BaseHTTPRequestHandler.responses[e.code][0])
            return
        except URLError:
            event.addresponse(u'Sorry, error fetching URL')
            return
예제 #8
0
class CounterStrike(Processor):
    usage = u'cs players | who is playing cs'
    feature = ('gameservers', )
    autoload = False

    cs_host = Option('cs_host', 'CS server hostname / IP', '127.0.0.1')
    cs_port = IntOption('cs_port', 'CS server port', 27015)

    @match(
        r'^(?:(?:cs|counter[\s-]*strike)\s+players|who(?:\'s|\s+is)\s+(?:playing|on)\s+(?:cs|counter[\s-]*strike))$'
    )
    def cs_players(self, event):
        server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

        server.sendto('\xFF\xFF\xFF\xFFdetails', (self.cs_host, self.cs_port))
        server.settimeout(5)
        data = server.recv(16384)

        assert data.startswith('\xFF\xFF\xFF\xFFm')
        data = data[5:]

        address, hostname, map, mod, modname, details = data.split('\x00', 5)

        details = details[:5]  # We don't care about the rest
        clientcount, clientmax, protocol, type, os = struct.unpack(
            '<3Bcc', details)

        if clientcount == 0:
            event.addresponse(u'Nobody. Everyone must have lives...')
            return

        server.sendto('\xFF\xFF\xFF\xFFplayers', (self.cs_host, self.cs_port))
        data = server.recv(16384)

        assert data.startswith('\xFF\xFF\xFF\xFF')
        data = data[6:]

        players = []
        while data:
            player = {}
            data = data[1:]
            player['nickname'], data = data.split('\x00', 1)
            player['fragtotal'] = struct.unpack('<i', data[:4])[0]
            data = data[8:]
            players.append(player)

        players.sort(key=lambda x: x['fragtotal'], reverse=True)
        event.addresponse(
            u'There are %(clients)i/%(clientmax)s players playing %(map)s: %(players)s',
            {
                'clients':
                clientcount,
                'clientmax':
                clientmax,
                'map':
                map,
                'players':
                human_join(u'%s (%i)' % (p['nickname'], p['fragtotal'])
                           for p in players),
            })
예제 #9
0
class Bnet(Processor):
    usage = u'dota players | who is playing dota'
    feature = ('gameservers', )
    autoload = False

    bnet_host = Option('bnet_host', 'Bnet server hostname / IP', '127.0.0.1')
    bnet_port = IntOption('bnet_port', 'Bnet server port', 6112)
    bnet_user = Option('bnet_user', 'Bnet username', 'guest')
    bnet_pass = Option('bnet_pass', 'Bnet password', 'guest')

    def bnet_players(self, gametype):
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((self.bnet_host, self.bnet_port))
        s.settimeout(5)
        s.send('\03%s\n%s\n/con\n/quit\n' % (self.bnet_user, self.bnet_pass))

        out = ""
        while (True):
            line = s.recv(1024)
            if line == "":
                break
            out += line

        s.close()

        player_re = re.compile(
            r'^1018 INFO "\s+bnet\s+%s\s+"(\S+?)"?\s+\d+\s+' % gametype)
        users = [
            player_re.match(line).group(1) for line in out.splitlines()
            if player_re.match(line)
        ]
        users.sort()
        return users

    @match(
        r'^(?:dota\s+players|who(?:\'s|\s+is)\s+(?:playing\s+dota|on\s+bnet))$'
    )
    def dota_players(self, event):
        users = self.bnet_players('W3XP')
        if users:
            event.addresponse(u'The battlefield contains %s',
                              human_join(users))
        else:
            event.addresponse(u'Nobody. Everyone must have a lives...')
예제 #10
0
class IMDB(Processor):
    usage = u'imdb [search] [character|company|episode|movie|person] <terms> [#<index>]'
    features = ('imdb', )

    access_system = Option("accesssystem", "Method of querying IMDB", "http")
    adult_search = BoolOption("adultsearch",
                              "Include adult films in search results", True)

    name_keys = {
        "character": "long imdb name",
        "company": "long imdb name",
        "episode": "long imdb title",
        "movie": "long imdb title",
        "person": "name",
    }

    def setup(self):
        if IMDb is None:
            raise Exception("IMDbPY not installed")
        self.imdb = IMDb(accessSystem=self.access_system,
                         adultSearch=int(self.adult_search))

    @match(
        r'^imdb(?:\s+search)?(?:\s+(character|company|episode|movie|person))?\s+(.+?)(?:\s+#(\d+))?$'
    )
    def search(self, event, search_type, terms, index):
        if search_type is None:
            search_type = "movie"
        if index is not None:
            index = int(index) - 1

        result = None
        try:
            if terms.isdigit():
                result = getattr(self.imdb, "get_" + search_type)(terms)
            else:
                results = getattr(self.imdb, "search_" + search_type)(terms)

                if len(results) == 1:
                    index = 0

                if index is not None:
                    result = results[index]
                    self.imdb.update(result)

        except IMDbDataAccessError, e:
            event.addresponse(u"IMDb doesn't like me today. It said '%s'",
                              e[0]["errmsg"])
            raise

        except IMDbError, e:
            event.addresponse(
                u'IMDb must be having a bad day (or you are asking it silly things)'
            )
            raise
예제 #11
0
class SourceFactory(IbidSourceFactory):

    auth = ('implicit', )
    supports = ('action', 'multiline', 'topic')

    subdomain = Option('subdomain', 'Campfire subdomain')
    secure = BoolOption('secure', 'Use https (paid accounts only)', False)
    token = Option('token', 'Campfire token')
    rooms = ListOption('rooms', 'Rooms to join', [])
    keepalive_timeout = IntOption(
        'keepalive_timeout', 'Stream keepalive timeout. '
        'Campfire sends a keepalive every <5 seconds', 30)

    def __init__(self, name):
        super(SourceFactory, self).__init__(name)
        self.log = logging.getLogger('source.%s' % self.name)
        self.client = CampfireBot(self)

    def setServiceParent(self, service):
        self.client.connect()

    def disconnect(self):
        self.client.disconnect()
        return True

    def url(self):
        protocol = self.secure and 'https' or 'http'
        return '%s://%s.campfirenow.com/' % (protocol, self.subdomain)

    def send(self, response):
        return self.client.send(response)

    def join(self, room_name):
        return self.client.join(room_name)

    def leave(self, room_name):
        return self.client.leave(room_name)

    def truncation_point(self, response, event=None):
        return None
예제 #12
0
class AptFile(Processor):
    usage = u'apt-file [search] <term> [on <distribution>[/<architecture>]]'
    features = ('apt-file',)

    distro = Option('distro', 'Default distribution to search', 'sid')
    arch = Option('arch', 'Default distribution to search', 'i386')

    @match(r'^apt-?file\s+(?:search\s+)?(\S+)'
           r'(?:\s+[oi]n\s+([a-z]+?)(?:[/-]([a-z0-9]+))?)?$')
    def search(self, event, term, distro, arch):
        distro = distro and distro.lower() or self.distro
        arch = arch and arch.lower() or self.arch
        distro = distro + u'-' + arch
        if distro == u'all-all':
            distro = u'all'

        result = json_webservice(
            u'http://dde.debian.net/dde/q/aptfile/byfile/%s/%s' %
            (distro, quote(term)), {'t': 'json'})
        result = result['r']
        if result:
            if isinstance(result[0], list):
                bypkg = map(lambda x: (x[-1], u'/'.join(x[:-1])), result)
                numpackages = len(bypkg)
                packages = defaultdict(list)
                for p, arch in bypkg:
                    packages[p].append(arch)
                packages = map(lambda i: u'%s [%s]' % (i[0], u', '.join(i[1])),
                               packages.iteritems())
            else:
                numpackages = len(result)
                packages = result
            event.addresponse(u'Found %(num)i packages: %(names)s', {
                'num': numpackages,
                'names': human_join(packages),
            })
        else:
            event.addresponse(u'No packages found')
예제 #13
0
파일: manhole.py 프로젝트: vhata/ibid
class SourceFactory(ShellFactory, IbidSourceFactory):

    port = IntOption('port', 'Port number to listen on', 9898)
    username = Option('username', 'Login Username', 'admin')
    password = Option('password', 'Login Password', 'admin')

    def __init__(self, name):
        ShellFactory.__init__(self)
        IbidSourceFactory.__init__(self, name)
        self.name = name

    def setServiceParent(self, service=None):
        if service:
            self.listener = internet.TCPServer(self.port, self).setServiceParent(service)
            return self.listener
        else:
            self.listener = reactor.listenTCP(self.port, self)

    def connect(self):
        return self.setServiceParent(None)

    def disconnect(self):
        self.listener.stopListening()
        return True
예제 #14
0
class BC(Processor):
    usage = u'bc <expression>'

    features = ('bc', )

    bc = Option('bc', 'Path to bc executable', 'bc')
    bc_timeout = FloatOption('bc_timeout', 'Maximum BC execution time (sec)',
                             2.0)

    def setup(self):
        if not file_in_path(self.bc):
            raise Exception("Cannot locate bc executable")

    @match(r'^bc\s+(.+)$')
    def calculate(self, event, expression):
        bc = Popen([self.bc, '-l'], stdin=PIPE, stdout=PIPE, stderr=PIPE)
        start_time = time()
        bc.stdin.write(expression.encode('utf-8') + '\n')
        bc.stdin.close()

        while bc.poll() is None and time() - start_time < self.bc_timeout:
            sleep(0.1)

        if bc.poll() is None:
            kill(bc.pid, SIGTERM)
            event.addresponse(u'Sorry, that took too long. I stopped waiting')
            return

        output = bc.stdout.read()
        error = bc.stderr.read()

        code = bc.wait()

        if code == 0:
            if output:
                output = unicode_output(output.strip())
                output = output.replace('\\\n', '')
                event.addresponse(output)
            else:
                error = unicode_output(error.strip())
                error = error.split(":", 1)[1].strip()
                error = error[0].lower() + error[1:].split('\n')[0]
                event.addresponse(u"I'm sorry, I couldn't deal with the %s",
                                  error)
        else:
            event.addresponse(u"Error running bc")
            error = unicode_output(error.strip())
            raise Exception("BC Error: %s" % error)
예제 #15
0
파일: factoid.py 프로젝트: shoosen/ibid
class StaticFactoid(Processor):
    priority = 900

    extras = Option('static', 'List of static factoids using regexes', {})

    def setup(self):
        self.factoids = static_default.copy()
        self.factoids.update(self.extras)

    @handler
    def static(self, event):
        for factoid in self.factoids.values():
            for match in factoid['matches']:
                if re.search(match, event.message['stripped'], re.I|re.DOTALL):
                    event.addresponse(_interpolate(choice(factoid['responses']), event),
                            address=False)
                    return
예제 #16
0
class Man(Processor):
    usage = u'man [<section>] <page>'
    features = ('man',)

    man = Option('man', 'Path of the man executable', 'man')

    def setup(self):
        if not file_in_path(self.man):
            raise Exception("Cannot locate man executable")

    @match(r'^man\s+(?:(\d)\s+)?(\S+)$')
    def handle_man(self, event, section, page):
        command = [self.man, page]
        if section:
            command.insert(1, section)

        if page.strip().startswith("-"):
            event.addresponse(False)
            return

        env = os.environ.copy()
        env["COLUMNS"] = "500"

        man = Popen(command, stdout=PIPE, stderr=PIPE, env=env)
        output, error = man.communicate()
        code = man.wait()

        if code != 0:
            event.addresponse(u'Manpage not found')
        else:
            output = unicode_output(output.strip(), errors="replace")
            output = output.splitlines()
            index = output.index('NAME')
            if index:
                event.addresponse(output[index+1].strip())
            index = output.index('SYNOPSIS')
            if index:
                event.addresponse(output[index+1].strip())
예제 #17
0
파일: http.py 프로젝트: shoosen/ibid
class SourceFactory(IbidSourceFactory):

    port = IntOption('port', 'Port number to listen on', 8080)
    myurl = Option('url', 'URL to advertise')

    def __init__(self, name):
        IbidSourceFactory.__init__(self, name)
        root = Plugin(name)
        root.putChild('', Index(name))
        root.putChild('message', Message(name))
        root.putChild('static', static.File(locate_resource('ibid', 'static')))
        root.putChild('RPC2', XMLRPC())
        root.putChild('SOAP', SOAP())
        self.site = server.Site(root)

    def setServiceParent(self, service):
        if service:
            return internet.TCPServer(self.port, self.site).setServiceParent(service)
        else:
            reactor.listenTCP(self.port, self.site)

    def url(self):
        return self.myurl
예제 #18
0
class Tracepath(Processor):
    usage = u'tracepath <host>'
    features = ('tracepath',)

    tracepath = Option('tracepath', 'Path to tracepath executable', 'tracepath')

    def setup(self):
        if not file_in_path(self.tracepath):
            raise Exception("Cannot locate tracepath executable")

    @match(r'^tracepath\s+(\S+)$')
    def handle_tracepath(self, event, host):

        tracepath = Popen([self.tracepath, host], stdout=PIPE, stderr=PIPE)
        output, error = tracepath.communicate()
        code = tracepath.wait()

        if code == 0:
            output = unicode_output(output)
            event.addresponse(output, conflate=False)
        else:
            error = unicode_output(error.strip())
            event.addresponse(u'Error: %s', error.replace(u'\n', u' '))
예제 #19
0
class Units(Processor):
    usage = u'convert [<value>] <unit> to <unit>'
    features = ('units', )
    priority = 10

    units = Option('units', 'Path to units executable', 'units')

    temp_scale_names = {
        'fahrenheit': 'tempF',
        'f': 'tempF',
        'celsius': 'tempC',
        'celcius': 'tempC',
        'c': 'tempC',
        'kelvin': 'tempK',
        'k': 'tempK',
        'rankine': 'tempR',
        'r': 'tempR',
    }

    temp_function_names = set(temp_scale_names.values())

    def setup(self):
        if not file_in_path(self.units):
            raise Exception("Cannot locate units executable")

    def format_temperature(self, unit):
        "Return the unit, and convert to 'tempX' format if a known temperature scale"

        lunit = unit.lower()
        if lunit in self.temp_scale_names:
            unit = self.temp_scale_names[lunit]
        elif lunit.startswith("deg") and " " in lunit and lunit.split(
                None, 1)[1] in self.temp_scale_names:
            unit = self.temp_scale_names[lunit.split(None, 1)[1]]
        return unit

    @match(r'^convert\s+(-?[0-9.]+)?\s*(.+)\s+(?:in)?to\s+(.+)$')
    def convert(self, event, value, frm, to):

        # We have to special-case temperatures because GNU units uses function notation
        # for direct temperature conversions
        if self.format_temperature(frm) in self.temp_function_names \
                and self.format_temperature(to) in self.temp_function_names:
            frm = self.format_temperature(frm)
            to = self.format_temperature(to)

        if value is not None:
            if frm in self.temp_function_names:
                frm = "%s(%s)" % (frm, value)
            else:
                frm = '%s %s' % (value, frm)

        units = Popen([self.units, '--verbose', '--', frm, to],
                      stdout=PIPE,
                      stderr=PIPE)
        output, error = units.communicate()
        code = units.wait()

        output = unicode_output(output)
        result = output.splitlines()[0].strip()

        if code == 0:
            event.addresponse(result)
        elif code == 1:
            if result == "conformability error":
                event.addresponse(
                    u"I don't think %(from)s can be converted to %(to)s", {
                        'from': frm,
                        'to': to,
                    })
            elif result.startswith("conformability error"):
                event.addresponse(
                    u"I don't think %(from)s can be converted to %(to)s: %(error)s",
                    {
                        'from': frm,
                        'to': to,
                        'error': result.split(":", 1)[1],
                    })
            else:
                event.addresponse(u"I can't do that: %s", result)
예제 #20
0
파일: buildbot.py 프로젝트: shoosen/ibid
class BuildBot(Processor, RPC):
    usage = u'rebuild <branch> [ (revision|r) <number> ]'
    feature = ('buildbot', )
    autoload = False

    server = Option('server', 'Buildbot server hostname', 'localhost')
    status_port = IntOption('status_port', 'Buildbot server port number', 9988)
    change_port = IntOption('change_port', 'Buildbot server port number', 9989)
    source = Option('source', 'Source to send commit notifications to')
    channel = Option('channel', 'Channel to send commit notifications to')

    def __init__(self, name):
        Processor.__init__(self, name)
        RPC.__init__(self)

    def setup(self):
        self.status = pb.PBClientFactory()
        reactor.connectTCP(self.server, self.status_port, self.status)
        d = self.status.login(
            credentials.UsernamePassword('statusClient', 'clientpw'))
        d.addCallback(self.store_root, 'status')
        d.addCallback(
            lambda root: root.callRemote('subscribe', 'builds', 0, self))
        d.addErrback(self.exception)

        self.change = pb.PBClientFactory()
        reactor.connectTCP(self.server, self.change_port, self.change)
        d = self.change.login(
            credentials.UsernamePassword('change', 'changepw'))
        d.addCallback(self.store_root, 'change')
        d.addErrback(self.exception)

    def remote_built(self, branch, revision, person, result):
        reply = u"Build %s of %s triggered by %s: %s" % (revision, branch,
                                                         person, result)
        ibid.dispatcher.send({
            'reply': reply,
            'source': self.source,
            'target': self.channel
        })
        return True

    @match(r'^(?:re)?build\s+(.+?)(?:\s+(?:revision|r)?\s*(\d+))?$')
    def build(self, event, branch, revision):
        change = {
            'who': str(event.sender['nick']),
            'branch': str(branch),
            'files': [None],
            'revision': revision and str(revision) or '-1',
            'comments': 'Rebuild',
        }

        d = self.change_root.callRemote('addChange', change)
        d.addCallback(self.respond, event, True)
        d.addErrback(self.respond, event, False)
        event.processed = True

    def respond(self, rpc_response, event, result):
        ibid.dispatcher.send({
            'reply': result and 'Okay'
            or u"buildbot doesn't want to build :-(",
            'source': event.source,
            'target': event.channel
        })

    def store_root(self, root, type):
        setattr(self, '%s_root' % type, root)
        return root

    def exception(self, exception):
        print exception
        raise exception

    def remote_buildsetSubmitted(self, buildset):
        pass

    def remote_builderAdded(self, builderName, builder):
        pass

    def remote_builderChangedState(self, builderName, state, foo):
        pass

    def remote_buildStarted(self, builderName, build):
        print "Build %s started on %s" % (builderName, build)

    def remote_buildETAUpdate(self, build, ETA):
        pass

    def remote_stepStarted(self, build, step):
        pass

    def remote_stepTextChanged(self, build, step, text):
        pass

    def remote_stepText2Changed(self, build, step, text2):
        pass

    def remote_stepETAUpdate(self, build, step, ETA, expectations):
        pass

    def remote_logStarted(self, build, step, log):
        pass

    def remote_logChunk(self, build, step, log, channel, text):
        pass

    def remote_logFinished(self, build, step, log):
        pass

    def remote_stepFinished(self, build, step, results):
        pass

    def remote_buildFinished(self, builderName, build, results):
        print "Build %s finished on %s" % (builderName, build)

    def remote_builderRemoved(self, builderName):
        pass
예제 #21
0
파일: dc.py 프로젝트: vhata/ibid
class SourceFactory(protocol.ReconnectingClientFactory, IbidSourceFactory):
    protocol = DCBot

    supports = ['multiline', 'topic']
    auth = ('op', )

    port = IntOption('port', 'Server port number', 411)
    server = Option('server', 'Server hostname')
    nick = Option('nick', 'DC nick', ibid.config['botname'])
    password = Option('password', 'Password', None)
    interest = Option('interest', 'User Description', '')
    speed = Option('speed', 'Bandwidth', '1kbps')
    email = Option('email', 'eMail Address', 'http://ibid.omnia.za.net/')
    sharesize = IntOption('sharesize', 'DC Share Size (bytes)', 0)
    slots = IntOption('slots', 'DC Open Slots', 0)
    action_prefix = Option('action_prefix', 'Command for actions (i.e. +me)',
                           None)
    banned_prefixes = Option('banned_prefixes',
                             'Prefixes not allowed in bot responses, i.e. !',
                             '')
    max_message_length = IntOption('max_message_length',
                                   'Maximum length of messages', 490)
    ping_interval = FloatOption('ping_interval',
                                'Seconds idle before sending a PING', 60)
    pong_timeout = FloatOption('pong_timeout', 'Seconds to wait for PONG', 300)
    # ReconnectingClient uses this:
    maxDelay = IntOption('max_delay',
                         'Max seconds to wait inbetween reconnects', 900)
    factor = FloatOption('delay_factor',
                         'Factor to multiply delay inbetween reconnects by', 2)

    def __init__(self, name):
        IbidSourceFactory.__init__(self, name)
        self.log = logging.getLogger('source.%s' % self.name)
        self._auth = {}

    def setup(self):
        if self.action_prefix is None and 'action' in self.supports:
            self.supports.remove('action')
        if self.action_prefix is not None and 'action' not in self.supports:
            self.supports.append('action')

    def setServiceParent(self, service):
        if service:
            internet.TCPClient(self.server, self.port,
                               self).setServiceParent(service)
        else:
            reactor.connectTCP(self.server, self.port, self)

    def connect(self):
        return self.setServiceParent(None)

    def disconnect(self):
        self.stopTrying()
        self.stopFactory()
        if hasattr(self, 'proto'):
            self.proto.transport.loseConnection()
        return True

    def truncation_point(self, response, event=None):
        return self.max_message_length

    def _dc_auth_callback(self, nick, result):
        self._auth[nick] = result

    def auth_op(self, event, credential):
        nick = event.sender['nick']
        if nick in self.proto.hub_users and self.proto.hub_users[nick].op in (
                True, False):
            return self.proto.hub_users[nick].op

        reactor.callFromThread(self.proto.authenticate, nick,
                               self._dc_auth_callback)
        for i in xrange(150):
            if nick in self._auth:
                break
            sleep(0.1)

        if nick in self._auth:
            result = self._auth[nick]
            del self._auth[nick]
            return result

    def url(self):
        return u'dc://%s@%s:%s' % (self.nick, self.server, self.port)
예제 #22
0
파일: smtp.py 프로젝트: shoosen/ibid
class SourceFactory(IbidSourceFactory, smtp.SMTPFactory):

    supports = ('multiline',)

    port = IntOption('port', 'Port number to listen on', 10025)
    address = Option('address', 'Email address to accept messages for and send from', 'ibid@localhost')
    accept = ListOption('accept', 'Email addresses to accept messages for', [])
    relayhost = Option('relayhost', 'SMTP server to relay outgoing messages to')

    def __init__(self, name):
        IbidSourceFactory.__init__(self, name)
        self.log = logging.getLogger('source.%s' % name)
        self.delivery = IbidDelivery(self)

    def buildProtocol(self, addr):
        p = smtp.SMTPFactory.buildProtocol(self, addr)
        p.delivery = self.delivery
        return p

    def setServiceParent(self, service):
        self.service = service
        if service:
            internet.TCPServer(self.port, self).setServiceParent(service)
        else:
            reactor.listenTCP(self.port, self)

    def url(self):
        return u'mailto:%s' % (self.address,)

    def respond(self, event):
        messages = {}
        for response in event.responses:
            if response['target'] not in messages:
                messages[response['target']] = response
            else:
                messages[response['target']]['reply'] += '\n' + response['reply']

        for message in messages.values():
            if 'subject' not in message:
                message['Subject'] = 'Re: ' + event['subject']
            if 'message-id' in event.headers:
                response['In-Reply-To'] = event.headers['message-id']
                if 'references' in event.headers:
                    response['References'] = '%(references)s %(message-id)s' % event.headers
                elif 'in-reply-to' in event.headers:
                    response['References'] = '%(in-reply-to)s %(message-id)s' % event.headers
                else:
                    response['References'] = '%(message-id)s' % event.headers

            self.send(message)

    def send(self, response):
        message = response['reply']
        response['To'] = response['target']
        response['Date'] = smtp.rfc822date()
        if 'Subject' not in response:
            response['Subject'] = 'Message from %s' % ibid.config['botname']
        response['Content-Type'] = 'text/plain; charset=utf-8'

        del response['target']
        del response['source']
        del response['reply']

        body = ''
        for header, value in response.items():
            body += '%s: %s\n' % (header, value)
        body += '\n'
        body += message

        port = ':' in self.relayhost and int(self.relayhost.split(':')[1]) or 25
        smtp.sendmail(self.relayhost.split(':')[0], self.address, response['To'], body.encode('utf-8'), port=port)
        self.log.debug(u"Sent email to %s: %s", response['To'], response['Subject'])
예제 #23
0
파일: irc.py 프로젝트: rsnyman/ibid
class SourceFactory(protocol.ReconnectingClientFactory, IbidSourceFactory):
    protocol = Ircbot

    auth = ('hostmask', 'nickserv')
    supports = ('action', 'notice', 'topic', 'channel key')

    port = IntOption('port', 'Server port number', 6667)
    ssl = BoolOption('ssl', 'Use SSL', False)
    server = Option('server', 'Server hostname')
    nick = Option('nick', 'IRC nick', ibid.config['botname'])
    realname = Option('realname', 'Full Name', ibid.config['botname'])
    password = Option('password', 'Connection password', None)
    username = Option('username', 'Local username', None)
    modes = Option('modes', 'User modes to set')
    channels = ListOption('channels', 'Channels to autojoin', [])
    ping_interval = FloatOption('ping_interval',
                                'Seconds idle before sending a PING', 60)
    pong_timeout = FloatOption('pong_timeout', 'Seconds to wait for PONG', 300)
    # ReconnectingClient uses this:
    maxDelay = IntOption('max_delay',
                         'Max seconds to wait inbetween reconnects', 900)
    factor = FloatOption('delay_factor',
                         'Factor to multiply delay inbetween reconnects by', 2)

    def __init__(self, name):
        IbidSourceFactory.__init__(self, name)
        self._auth = {}
        self._auth_ticket = 0
        self._auth_ticket_lock = Lock()
        self.log = logging.getLogger('source.%s' % self.name)

    def setServiceParent(self, service):
        if self.ssl:
            sslctx = ssl.ClientContextFactory()
            if service:
                internet.SSLClient(self.server, self.port, self,
                                   sslctx).setServiceParent(service)
            else:
                reactor.connectSSL(self.server, self.port, self, sslctx)
        else:
            if service:
                internet.TCPClient(self.server, self.port,
                                   self).setServiceParent(service)
            else:
                reactor.connectTCP(self.server, self.port, self)

    def connect(self):
        return self.setServiceParent(None)

    def disconnect(self):
        self.stopTrying()
        self.stopFactory()
        if hasattr(self, 'proto'):
            self.proto.transport.loseConnection()
        return True

    def join(self, channel, key=None):
        return self.proto.join(channel, key)

    def leave(self, channel):
        return self.proto.leave(channel)

    def change_nick(self, nick):
        return self.proto.setNick(nick.encode('utf-8'))

    def send(self, response):
        return self.proto.send(response)

    def logging_name(self, identity):
        if identity is None:
            return u''
        return identity.split(u'!')[0]

    def truncation_point(self, response, event=None):
        target = response['target'].split('!')[0]
        raw_target = target.encode('utf-8')
        if hasattr(self.proto, 'hostmask'):
            hostmask_len = len(self.proto.hostmask)
        else:
            hostmask_len = 50

        # max = 512 - len(':' + hostmask + ' ' + command + ' ' + target + ' :\r\n')

        cmds = {
            'notice': len('NOTICE'),
            'topic': len('TOPIC'),
            'action': len('PRIVMSG\001ACTION \001')
        }
        for cmd, command_len in cmds.items():
            if response.get(cmd, False):
                break
        else:
            command_len = len('PRIVMSG')

        return 505 - command_len - len(raw_target) - hostmask_len

    def url(self):
        return u'irc://%s@%s:%s' % (self.nick, self.server, self.port)

    def auth_hostmask(self, event, credential=None):
        for credential in event.session.query(Credential) \
                .filter_by(method=u'hostmask', account_id=event.account) \
                .filter(or_(Credential.source == event.source,
                            Credential.source == None)) \
                .all():
            if fnmatch(event.sender['connection'], credential.credential):
                return True

    def auth_nickserv(self, event, credential):
        self._auth_ticket_lock.acquire()
        self._auth_ticket += 1
        ticket = self._auth_ticket
        self._auth_ticket_lock.release()

        def callback(result):
            self._auth[ticket] = result

        reactor.callFromThread(self.proto.authenticate, event.sender['nick'],
                               callback)
        # We block in the plugin thread for up to this long, waiting for
        # NickServ to reply
        wait = 15
        for i in xrange(wait * 10):
            if ticket in self._auth:
                break
            sleep(0.1)

        if ticket in self._auth:
            result = self._auth[ticket]
            del self._auth[ticket]
            return result
예제 #24
0
파일: languages.py 프로젝트: shoosen/ibid
class Translate(Processor):
    usage = u"""translate (<phrase>|<url>) [from <language>] [to <language>]
    translation chain <phrase> [from <language>] [to <language>]"""

    feature = ('translate',)

    api_key = Option('api_key', 'Your Google API Key (optional)', None)
    referer = Option('referer', 'The referer string to use (API searches)', default_referer)
    dest_lang = Option('dest_lang', 'Destination language when none is specified', 'english')

    chain_length = IntOption('chain_length', 'Maximum length of translation chains', 10)

    lang_names = {'afrikaans':'af', 'albanian':'sq', 'arabic':'ar',
                  'belarusian':'be', 'bulgarian':'bg', 'catalan':'ca',
                  'chinese':'zh', 'chinese simplified':'zh-cn',
                  'chinese traditional':'zh-tw', 'croatian':'hr', 'czech':'cs',
                  'danish':'da', 'dutch':'nl', 'english':'en', 'estonian':'et',
                  'filipino':'tl', 'finnish':'fi', 'french':'fr',
                  'galacian':'gl', 'german':'de', 'greek':'el', 'hebrew':'iw',
                  'hindi':'hi', 'hungarian':'hu', 'icelandic':'is',
                  'indonesian':'id', 'irish':'ga', 'italian':'it',
                  'japanese':'ja', 'korean': 'ko', 'latvian':'lv',
                  'lithuanian':'lt', 'macedonian':'mk', 'malay':'ms',
                  'maltese':'mt', 'norwegian':'no', 'persian':'fa',
                  'polish':'pl', 'portuguese':'pt', 'romanian':'ro',
                  'russian': 'ru', 'serbian':'sr', 'slovak':'sk',
                  'slovenian':'sl', 'spanish':'es', 'swahili':'sw',
                  'swedish':'sv', 'thai':'th', 'turkish':'tr', 'ukrainian':'uk',
                  'uzbek': 'uz', 'vietnamese':'vi', 'welsh':'cy',
                  'yiddish': 'yi', 'haitian creole': 'ht'}

    alt_lang_names = {'simplified':'zh-CN', 'simplified chinese':'zh-CN',
                   'traditional':'zh-TW', 'traditional chinese':'zh-TW',
                   'bokmal':'no', 'norwegian bokmal':'no',
                   u'bokm\N{LATIN SMALL LETTER A WITH RING ABOVE}l':'no',
                   u'norwegian bokm\N{LATIN SMALL LETTER A WITH RING ABOVE}l':
                        'no',
                   'farsi': 'fa',
                   'haitian': 'ht', 'kreyol': 'ht'}

    LANG_REGEX = '|'.join(lang_names.keys() + lang_names.values() +
                            alt_lang_names.keys())

    @match(r'^(?:translation\s*)?languages$')
    def languages (self, event):
        event.addresponse(human_join(sorted(self.lang_names.keys())))

    @match(r'^translate\s+(.*?)(?:\s+from\s+(' + LANG_REGEX + r'))?'
            r'(?:\s+(?:in)?to\s+(' + LANG_REGEX + r'))?$')
    def translate (self, event, text, src_lang, dest_lang):
        dest_lang = self.language_code(dest_lang or self.dest_lang)
        src_lang = self.language_code(src_lang or '')

        if is_url(text):
            if urlparse(text).scheme in ('', 'http'):
                url = url_to_bytestring(text)
                query = {'sl': src_lang, 'tl': dest_lang, 'u': url}
                event.addresponse(u'http://translate.google.com/translate?' +
                                    urlencode(query))
            else:
                event.addresponse(u'I can only translate HTTP pages')
            return

        try:
            translated = self._translate(event, text, src_lang, dest_lang)[0]
            event.addresponse(translated)
        except TranslationException, e:
            event.addresponse(u"I couldn't translate that: %s.", unicode(e))
예제 #25
0
class Summon(Processor):
    usage = u'summon <person> [via <source>]'
    features = ('summon', )
    permission = u'summon'

    default_source = Option('default_source',
                            u'Default source to summon people via', u'jabber')

    @authorise(fallthrough=False)
    @match(r'^summon\s+(\S+)(?:\s+(?:via|on|using)\s+(\S+))?$')
    def summon(self, event, who, source):
        if not source:
            source = self.default_source

        if source.lower() not in ibid.sources:
            event.addresponse(u"I'm afraid that I'm not connected to %s",
                              source)
            return

        account = event.session.query(Account) \
            .options(eagerload('identities')) \
            .join('identities') \
            .filter(
                or_(
                    and_(
                        Identity.identity == who,
                        Identity.source == event.source,
                    ),
                    Account.username == who,
                )) \
            .first()

        if account:
            for other_identity in [
                    id for id in account.identities
                    if id.source.lower() == source.lower()
            ]:
                if any(True for channel in ibid.channels[
                        other_identity.source].itervalues()
                       if other_identity.id in channel):
                    event.addresponse(
                        u'Your presence has been requested by '
                        u'%(who)s in %(channel)s on %(source)s.', {
                            'who': event.sender['nick'],
                            'channel':
                            (not event.public) and u'private' or event.channel,
                            'source': event.source,
                        },
                        target=other_identity.identity,
                        source=other_identity.source,
                        address=False)
                    event.addresponse(True)
                else:
                    event.addresponse(
                        u"Sorry %s doesn't appear to be available right now.",
                        who)
                return

        event.addresponse(
            u"Sorry, I don't know how to find %(who)s on %(source)s. "
            u'%(who)s must first link an identity on %(source)s.', {
                'who': who,
                'source': source,
            })
        return
예제 #26
0
class Ports(Processor):
    usage = u"""port for <protocol>
    (tcp|udp) port <number>"""
    features = ('ports',)
    priority = 10

    services = Option('services', 'Path to services file', '/etc/services')
    nmapservices = Option('nmap-services', "Path to Nmap's services file", '/usr/share/nmap/nmap-services')
    protocols = {}
    ports = {}

    def setup(self):
        self.filename = None
        if exists(self.nmapservices):
            self.filename = self.nmapservices
            self.nmap = True
        elif exists(self.services):
            self.filename = self.services
            self.nmap = False

        if not self.filename:
            raise Exception(u"Services file doesn't exist")

    def _load_services(self):
        if self.protocols:
            return

        self.protocols = defaultdict(list)
        self.ports = defaultdict(list)
        f = open(self.filename)
        for line in f.readlines():
            parts = line.split()
            if parts and not parts[0].startswith('#') and parts[0] != 'unknown':
                number, transport = parts[1].split('/')
                port = '%s (%s)' % (number, transport.upper())
                self.protocols[parts[0].lower()].append(port)
                self.ports[parts[1]].append(parts[0])
                if not self.nmap:
                    for proto in parts[2:]:
                        if proto.startswith('#'):
                            break
                        self.protocols[proto.lower()].append(port)

    @match(r'(?:{proto:any} )?ports?(?: numbers?)?(?(1)| for {proto:any})')
    def portfor(self, event, proto):
        self._load_services()
        protocol = proto.lower()
        if protocol in self.protocols:
            event.addresponse(human_join(self.protocols[protocol]))
        else:
            event.addresponse(u"I don't know about that protocol")

    @match(r'^(?:(udp|tcp|sctp)\s+)?port\s+(\d+)$')
    def port(self, event, transport, number):
        self._load_services()
        results = []
        if transport:
            results.extend(self.ports.get('%s/%s' % (number, transport.lower()), []))
        else:
            for transport in ('tcp', 'udp', 'sctp'):
                results.extend('%s (%s)' % (protocol, transport.upper()) for protocol in self.ports.get('%s/%s' % (number, transport.lower()), []))

        if results:
            event.addresponse(human_join(results))
        else:
            event.addresponse(u"I don't know about any protocols using that port")
예제 #27
0
class IPCalc(Processor):
    usage = u"""ipcalc <network>/<subnet>
    ipcalc <address> - <address>"""
    features = ('ipcalc',)

    ipcalc = Option('ipcalc', 'Path to ipcalc executable', 'ipcalc')

    def setup(self):
        if not file_in_path(self.ipcalc):
            raise Exception("Cannot locate ipcalc executable")

    def call_ipcalc(self, parameters):
        ipcalc = Popen([self.ipcalc, '-n', '-b'] + parameters,
                       stdout=PIPE, stderr=PIPE)
        output, error = ipcalc.communicate()
        code = ipcalc.wait()
        output = unicode_output(output)

        return (code, output, error)

    @match(r'^ipcalc\s+((?:\d{1,3}\.){3}\d{1,3}|(?:0x)?[0-9A-F]{8})'
           r'(?:(?:/|\s+)((?:\d{1,3}\.){3}\d{1,3}|\d{1,2}))?$')
    def ipcalc_netmask(self, event, address, netmask):
        address = address
        if netmask:
            address += u'/' + netmask
        code, output, error = self.call_ipcalc([address])

        if code == 0:
            if output.startswith(u'INVALID ADDRESS'):
                event.addresponse(u"That's an invalid address. "
                                  u"Try something like 192.168.1.0/24")
            else:
                response = {}
                for line in output.splitlines():
                    if ":" in line:
                        name, value = [x.strip() for x in line.split(u':', 1)]
                        name = name.lower()
                        if name == "netmask":
                            value, response['cidr'] = value.split(' = ')
                        elif name == "hosts/net":
                            value, response['class'] = value.split(None, 1)
                        response[name] = value

                event.addresponse(u'Host: %(address)s/%(netmask)s (/%(cidr)s) '
                    u'Wildcard: %(wildcard)s | '
                    u'Network: %(network)s (%(hostmin)s - %(hostmax)s) '
                    u'Broadcast: %(broadcast)s Hosts: %(hosts/net)s %(class)s',
                    response)
        else:
            error = unicode_output(error.strip())
            event.addresponse(error.replace(u'\n', u' '))

    @match(r'^ipcalc\s+((?:\d{1,3}\.){3}\d{1,3}|(?:0x)?[0-9A-F]{8})\s*-\s*'
           r'((?:\d{1,3}\.){3}\d{1,3}|(?:0x)?[0-9A-F]{8})$')
    def ipcalc_deggregate(self, event, frm, to):
        code, output, error = self.call_ipcalc([frm, '-', to])

        if code == 0:
            if output.startswith(u'INVALID ADDRESS'):
                event.addresponse(u"That's an invalid address. "
                                  u"Try something like 192.168.1.0")
            else:
                event.addresponse(u'Deaggregates to: %s',
                                  human_join(output.splitlines()[1:]))
        else:
            error = unicode_output(error.strip())
            event.addresponse(error.replace(u'\n', u' '))
예제 #28
0
파일: memory.py 프로젝트: shoosen/ibid
class MemoryLog(Processor):

    feature = ('memory', )
    autoload = False

    mem_filename = Option('mem_filename', 'Memory log filename',
                          'logs/memory.log')
    mem_interval = IntOption('mem_interval',
                             'Interval between memory stat logging', 0)
    obj_filename = Option('obj_filename', 'Object Statistics log filename',
                          'logs/objstats.log')
    obj_interval = IntOption('obj_interval',
                             'Interval between logging object statistics', 0)

    def setup(self):
        fns = []
        if self.mem_interval:
            fns.append(self.mem_filename)
        if self.obj_interval:
            fns.append(self.obj_filename)
        for filename in fns:
            if os.path.isfile(filename + '.10.gz'):
                os.remove(filename + '.10.gz')
            for i in range(9, 0, -1):
                if os.path.isfile('%s.%i.gz' % (filename, i)):
                    os.rename('%s.%i.gz' % (filename, i),
                              '%s.%i.gz' % (filename, i + 1))
            if os.path.isfile(filename):
                o = gzip.open(filename + '.1.gz', 'wb')
                i = open(filename, 'rb')
                o.write(i.read())
                o.close()
                i.close()
                stat = os.stat(filename)
                os.utime(filename + '.1.gz', (stat.st_atime, stat.st_mtime))

        if self.mem_interval:
            self.mem_file = file(self.mem_filename, 'w+')
            self.mem_file.write('Ibid Memory Log v2: %s\n' %
                                ibid.config['botname'])
            self.mem_csv = csv.writer(self.mem_file)
            self.mem_last = datetime.utcnow()

        if self.obj_interval:
            self.obj_file = file(self.obj_filename, 'w+')
            self.obj_file.write('Ibid Object Log v1: %s\n' %
                                ibid.config['botname'])
            self.obj_last = datetime.utcnow()

    def process(self, event):
        if self.mem_interval and event.time - self.mem_last >= \
                timedelta(seconds=self.mem_interval):
            self.mem_log()
            self.mem_last = event.time
        if self.obj_interval and event.time - self.obj_last >= \
                timedelta(seconds=self.obj_interval):
            self.obj_log()
            self.obj_last = event.time

    def mem_log(self):
        status = get_memusage()
        gc.collect()

        self.mem_csv.writerow((
            datetime.utcnow().isoformat(),
            len(gc.get_objects()),
            status['VmSize'],
            status['VmRSS'],
        ))
        self.mem_file.flush()

    def obj_log(self):
        self.obj_file.write(
            '%s %s\n' %
            (datetime.utcnow().isoformat(), json.dumps(objgraph.typestats())))
        self.obj_file.flush()
예제 #29
0
파일: languages.py 프로젝트: shoosen/ibid
class Dict(Processor):
    usage = u"""spell <word> [using <strategy>]
    define <word> [using <dictionary>]
    (dictionaries|strategies)
    (dictionary|strategy) <name>"""
    feature = ('dict',)

    server = Option('server', 'Dictionary server hostname', 'localhost')
    port = IntOption('port', 'Dictionary server port number', 2628)

    @staticmethod
    def reduce_suggestions(suggestions):
        "Remove duplicate suggestions and suffixes"
        output = []
        for s in suggestions:
            s = s.getword()
            if not s.startswith('-') and s not in output:
                output.append(s)
        return output

    @match(r'^(?:define|dict)\s+(.+?)(?:\s+using\s+(.+))?$')
    def define(self, event, word, dictionary):
        connection = Connection(self.server, self.port)
        dictionary = dictionary is None and '*' or dictionary.lower()
        dictionaries = connection.getdbdescs().keys()

        if dictionary != '*' and dictionary not in dictionaries:
            event.addresponse(
                    u"I'm afraid I don't have a dictionary of that name. I know about: %s",
                    human_join(sorted(dictionaries)))
            return

        definitions = connection.define(dictionary, word.encode('utf-8'))
        if definitions:
            event.addresponse(u', '.join(d.getdefstr() for d in definitions))
        else:
            suggestions = connection.match(dictionary, 'lev', word.encode('utf-8'))
            if suggestions:
                event.addresponse(
                        u"I don't know about %(word)s. Maybe you meant %(suggestions)s?", {
                            'word': word,
                            'suggestions': human_join(
                                self.reduce_suggestions(suggestions),
                                conjunction=u'or'),
                })
            else:
                event.addresponse(u"I don't have a definition for that. Is it even a word?")

    @match(r'^spell\s+(.+?)(?:\s+using\s+(.+))?$')
    def handle_spell(self, event, word, strategy):
        connection = Connection(self.server, self.port)
        word = word.encode('utf-8')
        strategies = connection.getstratdescs().keys()

        if connection.match('*', 'exact', word):
            event.addresponse(choice((
                u'That seems correct. Carry on',
                u'Looks good to me',
                u"Yup, that's a word all right",
                u'Yes, you *can* spell',
            )))
            return

        strategy = strategy is None and 'lev' or strategy.lower()
        if strategy not in strategies:
            event.addresponse(
                    u"I'm afraid I don't know about such a strategy. I know about: %s",
                    human_join(sorted(strategies)))

        suggestions = connection.match('*', strategy, word)
        if suggestions:
            event.addresponse(u'Suggestions: %s', human_join(
                    self.reduce_suggestions(suggestions), conjunction=u'or'))
        else:
            event.addresponse(u"That doesn't seem correct, but I can't find anything to suggest")

    @match(r'^dictionaries$')
    def handle_dictionaries(self, event):
        connection = Connection(self.server, self.port)
        dictionaries = connection.getdbdescs()
        event.addresponse(u'My Dictionaries: %s', human_join(sorted(dictionaries.keys())))

    @match(r'^strater?gies$')
    def handle_strategies(self, event):
        connection = Connection(self.server, self.port)
        strategies = connection.getstratdescs()
        event.addresponse(u'My Strategies: %s', human_join(sorted(strategies.keys())))

    @match(r'^dictionary\s+(.+?)$')
    def handle_dictionary(self, event, dictionary):
        connection = Connection(self.server, self.port)
        dictionaries = connection.getdbdescs()
        dictionary = dictionary.lower()
        if dictionary in dictionaries:
            event.addresponse(unicode(dictionaries[dictionary]))
        else:
            event.addresponse(u"I don't have that dictionary")

    @match(r'^strater?gy\s+(.+?)$')
    def handle_strategy(self, event, strategy):
        connection = Connection(self.server, self.port)
        strategies = connection.getstratdescs()
        strategy = strategy.lower()
        if strategy in strategies:
            event.addresponse(unicode(strategies[strategy]))
        else:
            event.addresponse(u"I don't have that strategy")
예제 #30
0
파일: log.py 프로젝트: shoosen/ibid
class Log(Processor):

    addressed = False
    processed = True
    event_types = (u'message', u'state', u'action', u'notice')
    priority = 1900

    log = Option('log', 'Log file to log messages to. Can contain substitutions: source, channel, year, month, day',
            'logs/%(year)d/%(month)02d/%(source)s/%(channel)s.log')

    timestamp_format = Option('timestamp_format', 'Format to substitute %(timestamp)s with', '%Y-%m-%d %H:%M:%S%z')
    date_utc = BoolOption('date_utc', 'Log with UTC timestamps', False)

    message_format = Option('message_format', 'Format string for messages',
            u'%(timestamp)s <%(sender_nick)s> %(message)s')
    action_format = Option('action_format', 'Format string for actions',
            u'%(timestamp)s * %(sender_nick)s %(message)s')
    notice_format = Option('notice_format', 'Format string for notices',
            u'%(timestamp)s -%(sender_nick)s- %(message)s')
    presence_format = Option('presence_format', 'Format string for presence events',
            u'%(timestamp)s %(sender_nick)s (%(sender_connection)s) is now %(state)s')
    rename_format = Option('rename_format', 'Format string for rename events',
            u'%(timestamp)s %(sender_nick)s (%(sender_connection)s) has renamed to %(new_nick)s')

    public_logs = ListOption('public_logs',
            u'List of source:channel globs for channels which should have public logs',
            [])
    public_mode = Option('public_mode',
            u'File Permissions mode for public channels, in octal', '644')
    private_mode = Option('private_mode',
            u'File Permissions mode for private chats, in octal', '640')
    dir_mode = Option('dir_mode',
            u'Directory Permissions mode, in octal', '755')

    fd_cache = IntOption('fd_cache', 'Number of log files to keep open.', 5)

    lock = Lock()
    logs = WeakValueDictionary()
    # Ensures that recently used FDs are still available in logs:
    recent_logs = []

    def setup(self):
        sources = list(set(ibid.config.sources.keys())
                       | set(ibid.sources.keys()))
        for glob in self.public_logs:
            if u':' not in glob:
                log.warning(u"public_logs configuration values must follow the "
                            u"format source:channel. \"%s\" doesn't contain a "
                            u"colon.", glob)
                continue
            source_glob = glob.split(u':', 1)[0]
            if not fnmatch.filter(sources, source_glob):
                log.warning(u'public_logs includes "%s", but there is no '
                            u'configured source matching "%s"',
                            glob, source_glob)

    def get_logfile(self, event):
        self.lock.acquire()
        try:
            when = event.time
            if not self.date_utc:
                when = when.replace(tzinfo=tzutc()).astimezone(tzlocal())

            if event.channel is not None:
                channel = ibid.sources[event.source].logging_name(event.channel)
            else:
                channel = ibid.sources[event.source].logging_name(event.sender['id'])
            filename = self.log % {
                    'source': event.source.replace('/', '-'),
                    'channel': channel.replace('/', '-'),
                    'year': when.year,
                    'month': when.month,
                    'day': when.day,
                    'hour': when.hour,
                    'minute': when.minute,
                    'second': when.second,
            }
            filename = join(ibid.options['base'], expanduser(filename))
            log = self.logs.get(filename, None)
            if log is None:
                try:
                    makedirs(dirname(filename), int(self.dir_mode, 8))
                except OSError, e:
                    if e.errno != EEXIST:
                        raise e

                log = open(filename, 'a')
                self.logs[filename] = log

                for glob in self.public_logs:
                    if u':' not in glob:
                        continue
                    source_glob, channel_glob = glob.split(u':', 1)
                    if (fnmatch.fnmatch(event.source, source_glob)
                            and fnmatch.fnmatch(channel, channel_glob)):
                        chmod(filename, int(self.public_mode, 8))
                        break
                else:
                    chmod(filename, int(self.private_mode, 8))
            else: