mirror of
				https://github.com/Mikaela/Limnoria.git
				synced 2025-11-04 09:37:25 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			324 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			324 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
#!/usr/bin/env python
 | 
						|
 | 
						|
###
 | 
						|
# Copyright (c) 2003, 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.
 | 
						|
###
 | 
						|
 | 
						|
"""
 | 
						|
This is the main program to run Supybot.
 | 
						|
"""
 | 
						|
 | 
						|
__revision__ = "$Id$"
 | 
						|
 | 
						|
import re
 | 
						|
import os
 | 
						|
import sys
 | 
						|
import atexit
 | 
						|
import shutil
 | 
						|
 | 
						|
if sys.version_info < (2, 3, 0):
 | 
						|
    sys.stderr.write('This program requires Python >= 2.3.0\n')
 | 
						|
    sys.exit(-1)
 | 
						|
 | 
						|
if os.name == 'posix':
 | 
						|
    if os.getuid() == 0 or os.geteuid() == 0:
 | 
						|
        sys.stderr.write('Dude, don\'t even try to run this as root.\n')
 | 
						|
        sys.exit(-1)
 | 
						|
 | 
						|
import time
 | 
						|
import optparse
 | 
						|
 | 
						|
started = time.time()
 | 
						|
 | 
						|
import supybot
 | 
						|
import registry
 | 
						|
 | 
						|
def main():
 | 
						|
    import conf
 | 
						|
    import utils
 | 
						|
    import world
 | 
						|
    import drivers
 | 
						|
    import schedule
 | 
						|
    # We schedule this event rather than have it actually run because if there
 | 
						|
    # is a failure between now and the time it takes the Owner plugin to load
 | 
						|
    # all the various plugins, our registry file might be wiped.  That's bad.
 | 
						|
    when = time.time() + conf.supybot.upkeepInterval()
 | 
						|
    schedule.addEvent(world.upkeep, when, name='upkeep')
 | 
						|
    world.startedAt = started
 | 
						|
    while world.ircs:
 | 
						|
        try:
 | 
						|
            drivers.run()
 | 
						|
        except KeyboardInterrupt:
 | 
						|
            log.info('Exiting due to Ctrl-C.')
 | 
						|
            now = time.time()
 | 
						|
            seconds = now - world.startedAt
 | 
						|
            log.info('Total uptime: %s.', utils.timeElapsed(seconds))
 | 
						|
            (user, system, _, _, _) = os.times()
 | 
						|
            log.info('Total CPU time taken: %s seconds.', user+system)
 | 
						|
            raise SystemExit
 | 
						|
        except SystemExit:
 | 
						|
            raise
 | 
						|
        except:
 | 
						|
            try: # Ok, now we're *REALLY* paranoid!
 | 
						|
                log.exception('Exception raised out of drivers.run:')
 | 
						|
            except Exception, e:
 | 
						|
                print 'Exception raised in log.exception.  This is *really*'
 | 
						|
                print 'bad.  Hopefully it won\'t happen again, but tell us'
 | 
						|
                print 'about it anyway, this is a significant problem.'
 | 
						|
                print 'Anyway, here\'s the exception: %s'% utils.exnToString(e)
 | 
						|
            except:
 | 
						|
                print 'Man, this really sucks.  Not only did log.exception'
 | 
						|
                print 'raise an exception, but freaking-a, it was a string'
 | 
						|
                print 'exception.  People who raise string exceptions should'
 | 
						|
                print 'die a slow, painful death.'
 | 
						|
    log.info('No more Irc objects, exiting.')
 | 
						|
 | 
						|
if __name__ == '__main__':
 | 
						|
    ###
 | 
						|
    # Options:
 | 
						|
    # -p (profiling)
 | 
						|
    # -O (optimizing)
 | 
						|
    # -n, --nick (nick)
 | 
						|
    # -s, --server (server)
 | 
						|
    # --startup (commands to run onStart)
 | 
						|
    # --connect (commands to run afterConnect)
 | 
						|
    # --config (configuration values)
 | 
						|
    parser = optparse.OptionParser(usage='Usage: %prog [options] configFile',
 | 
						|
                                   version='supybot 0.76.1')
 | 
						|
    parser.add_option('-P', '--profile', action='store_true', dest='profile',
 | 
						|
                      help='enables profiling')
 | 
						|
    parser.add_option('-O', action='count', dest='optimize',
 | 
						|
                      help='-O optimizes asserts out of the code; ' \
 | 
						|
                           '-OO optimizes asserts and uses psyco.')
 | 
						|
    parser.add_option('-n', '--nick', action='store',
 | 
						|
                      dest='nick', default='',
 | 
						|
                      help='nick the bot should use')
 | 
						|
    parser.add_option('-s', '--server', action='store',
 | 
						|
                      dest='server', default='',
 | 
						|
                      help='server to connect to')
 | 
						|
    parser.add_option('-u', '--user', action='store',
 | 
						|
                      dest='user', default='',
 | 
						|
                      help='full username the bot should use')
 | 
						|
    parser.add_option('-i', '--ident', action='store',
 | 
						|
                      dest='ident', default='',
 | 
						|
                      help='ident the bot should use')
 | 
						|
    parser.add_option('-p', '--password', action='store',
 | 
						|
                      dest='password', default='',
 | 
						|
                      help='server password the bot should use')
 | 
						|
    parser.add_option('', '--allow-eval', action='store_true',
 | 
						|
                      dest='allowEval',
 | 
						|
                      help='Determines whether the bot will '
 | 
						|
                           'allow the evaluation of arbitrary Python code.')
 | 
						|
 | 
						|
    (options, args) = parser.parse_args()
 | 
						|
 | 
						|
    if len(args) > 1:
 | 
						|
        parser.error()
 | 
						|
    elif not args:
 | 
						|
        import socket
 | 
						|
        import ircutils
 | 
						|
        import questions
 | 
						|
        questions.output("""It seems like you're running supybot for the first
 | 
						|
        time.  Or, perhaps, you just forgot to give this program an argument
 | 
						|
        for your registry file.  If the latter is the case, simply press Ctrl-C
 | 
						|
        and this script will exit and you can run it again as indicated.  If
 | 
						|
        the former is the case, however, we'll have a few questions for you
 | 
						|
        to write your initial registry file.""")
 | 
						|
        ###
 | 
						|
        # Nick.
 | 
						|
        ###
 | 
						|
        nick = questions.something("""What nick would you like your bot to
 | 
						|
        use?""")
 | 
						|
        while not ircutils.isNick(nick):
 | 
						|
            questions.output("""That's not a valid IRC nick.  Please choose a
 | 
						|
            different nick.""")
 | 
						|
            nick = questions.something("""What nick would you like your bot
 | 
						|
            to use?""")
 | 
						|
 | 
						|
        ###
 | 
						|
        # Server.
 | 
						|
        ###
 | 
						|
        def checkServer(server):
 | 
						|
            try:
 | 
						|
                ip = socket.gethostbyname(server)
 | 
						|
                questions.output("""%s resolved to %s.""" % (server, ip))
 | 
						|
                return True
 | 
						|
            except socket.error:
 | 
						|
                questions.output("""That's not a valid hostname.  Please enter
 | 
						|
                a hostname that resolves.""")
 | 
						|
                return False
 | 
						|
        server = questions.something("""What server would you like your bot
 | 
						|
        to connect to?""")
 | 
						|
        while not checkServer(server):
 | 
						|
            server = questions.something("""What server would you like your bot
 | 
						|
            to connect to?""")
 | 
						|
 | 
						|
        ###
 | 
						|
        # Channels.
 | 
						|
        ###
 | 
						|
        def checkChannels(s):
 | 
						|
            for channel in s.split():
 | 
						|
                if ',' in channel:
 | 
						|
                    (channel, _) = channel.split(',', 1)
 | 
						|
                if not ircutils.isChannel(channel):
 | 
						|
                    questions.output("""%s is not a valid IRC channel.  Please
 | 
						|
                    choose a different channel.""" % channel)
 | 
						|
                    return False
 | 
						|
            return True
 | 
						|
        channels = questions.something("""What channels would you like your bot
 | 
						|
        to join when it connects to %s?  Separate your channels by spaces; if
 | 
						|
        any channels require a keyword to join, separate the keyword from the
 | 
						|
        channel by a comma.  For instance, if you want to join #supybot with
 | 
						|
        no keyword and #secret with a keyword of 'foo', you would type
 | 
						|
        '#supybot #secret,foo' without the quotes.""" % server)
 | 
						|
        while not checkChannels(channels):
 | 
						|
            channels = questions.something("""What channels would you like your
 | 
						|
            bot to join when it connects to %s?  Separate your channels by
 | 
						|
            spaces; if any channels require a keyword to join, separate the
 | 
						|
            keyword from the channel by a comma.  For instance, if you want to
 | 
						|
            join #supybot with no keyword and #secret with a keyword of 'foo',
 | 
						|
            you would type '#supybot #secret,foo' without the quotes.
 | 
						|
            """ % server)
 | 
						|
 | 
						|
        ###
 | 
						|
        # Filename.
 | 
						|
        ###
 | 
						|
        def checkFilename(s):
 | 
						|
            if os.path.exists(s):
 | 
						|
                questions.output("""That file already exists.  Please choose a
 | 
						|
                file that doesn't exist yet.  You can always copy it over
 | 
						|
                later, of course, but we'd rather play it safe ourselves and
 | 
						|
                not risk overwriting an important file.""")
 | 
						|
                return False
 | 
						|
            try:
 | 
						|
                fd = file(s, 'w')
 | 
						|
                fd.write('supybot.nick: %s\n' % nick)
 | 
						|
                fd.write('supybot.server: %s\n' % server)
 | 
						|
                fd.write('supybot.channels: %s\n' % channels)
 | 
						|
                fd.close()
 | 
						|
                questions.output("""File %s written.  Now, to run your bot,
 | 
						|
                run this script with just that filename as an option.  Once you
 | 
						|
                do so, your configuration file will become much fuller and more
 | 
						|
                complete, with help descriptions describing all the options and
 | 
						|
                a significant number more options than you see now.  Have fun!
 | 
						|
                """ % s)
 | 
						|
                return True
 | 
						|
            except EnvironmentError, e:
 | 
						|
                questions.output("""Python told me that it couldn't create your
 | 
						|
                file, giving me this specific error: %s.""" % e)
 | 
						|
                return False
 | 
						|
        filename = questions.something("""What filename would you like to write
 | 
						|
        this configuration to?""")
 | 
						|
        while not checkFilename(filename):
 | 
						|
            filename = questions.something("""What filename would you like to
 | 
						|
            write this configuration to?""")
 | 
						|
        questions.output("""Great!  Seeya on the flipside!""")
 | 
						|
        sys.exit(0)
 | 
						|
    else:
 | 
						|
        registryFilename = args.pop()
 | 
						|
        try:
 | 
						|
            # The registry *MUST* be opened before importing log or conf.
 | 
						|
            registry.open(registryFilename)
 | 
						|
            shutil.copy(registryFilename, registryFilename + '.bak')
 | 
						|
        except registry.InvalidRegistryFile, e:
 | 
						|
            sys.stderr.write(str(e))
 | 
						|
            sys.stderr.write(os.linesep)
 | 
						|
            sys.exit(-1)
 | 
						|
        except EnvironmentError, e:
 | 
						|
            sys.stderr.write(str(e))
 | 
						|
            sys.stderr.write(os.linesep)
 | 
						|
            sys.exit(-1)
 | 
						|
 | 
						|
    import log
 | 
						|
    import conf
 | 
						|
    import world
 | 
						|
    
 | 
						|
    def closeRegistry():
 | 
						|
        # We only print if world.dying so we don't see these messages during
 | 
						|
        # upkeep.
 | 
						|
        if world.dying:
 | 
						|
            log.info('Writing registry file to %s', registryFilename)
 | 
						|
        registry.close(conf.supybot, registryFilename, annotated=True)
 | 
						|
        if world.dying:
 | 
						|
            log.info('Finished writing registry file.')
 | 
						|
    world.flushers.append(closeRegistry)
 | 
						|
    world.registryFilename = registryFilename
 | 
						|
 | 
						|
    nick = options.nick or conf.supybot.nick()
 | 
						|
    user = options.user or conf.supybot.user()
 | 
						|
    ident = options.ident or conf.supybot.ident()
 | 
						|
    password = options.password or conf.supybot.password()
 | 
						|
 | 
						|
    server = options.server or conf.supybot.server()
 | 
						|
    if ':' in server:
 | 
						|
        serverAndPort = server.split(':', 1)
 | 
						|
        serverAndPort[1] = int(serverAndPort[1])
 | 
						|
        server = tuple(serverAndPort)
 | 
						|
    else:
 | 
						|
        server = (server, 6667)
 | 
						|
 | 
						|
    if options.optimize:
 | 
						|
        __builtins__.__debug__ = False
 | 
						|
        if options.optimize > 1:
 | 
						|
            try:
 | 
						|
                import psyco
 | 
						|
                psyco.full()
 | 
						|
            except ImportError:
 | 
						|
                log.warning('Psyco isn\'t installed, cannot -OO.')
 | 
						|
 | 
						|
    if options.allowEval:
 | 
						|
        conf.allowEval = True
 | 
						|
 | 
						|
    if not os.path.exists(conf.supybot.directories.log()):
 | 
						|
        os.mkdir(conf.supybot.directories.log())
 | 
						|
    if not os.path.exists(conf.supybot.directories.conf()):
 | 
						|
        os.mkdir(conf.supybot.directories.conf())
 | 
						|
    if not os.path.exists(conf.supybot.directories.data()):
 | 
						|
        os.mkdir(conf.supybot.directories.data())
 | 
						|
 | 
						|
    import irclib
 | 
						|
    import ircmsgs
 | 
						|
    import drivers
 | 
						|
    import callbacks
 | 
						|
    import Owner
 | 
						|
 | 
						|
    irc = irclib.Irc(nick, user, ident, password)
 | 
						|
    callback = Owner.Class()
 | 
						|
    irc.addCallback(callback)
 | 
						|
    driver = drivers.newDriver(server, irc)
 | 
						|
    
 | 
						|
    if options.profile:
 | 
						|
        import profile
 | 
						|
        profile.run('main()', '%s-%i.prof' % (nick, time.time()))
 | 
						|
    else:
 | 
						|
        main()
 | 
						|
 | 
						|
 | 
						|
    
 | 
						|
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
 |