mirror of
				https://github.com/Mikaela/Limnoria.git
				synced 2025-11-04 01:27:21 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			342 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			342 lines
		
	
	
		
			14 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.')
 | 
						|
            break
 | 
						|
        except SystemExit:
 | 
						|
            break
 | 
						|
        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.'
 | 
						|
    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)
 | 
						|
    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.')
 | 
						|
    parser.add_option('', '--strict-rfc', action='store_true',
 | 
						|
                      dest='strictRfc',
 | 
						|
                      help='Determines whether the bot will strictly follow '
 | 
						|
                           'RFC guidelines defining nicks and channels.')
 | 
						|
 | 
						|
    (options, args) = parser.parse_args()
 | 
						|
 | 
						|
    if len(args) > 1:
 | 
						|
        parser.error()
 | 
						|
    elif not args:
 | 
						|
        try:
 | 
						|
            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)
 | 
						|
        except KeyboardInterrupt:
 | 
						|
            print
 | 
						|
            print
 | 
						|
            questions.output("""Well, it looks like you cancelled out of the
 | 
						|
            bot before it was done. Unfortunately, I didn't get to write
 | 
						|
            anything to file.  Please run the bot/wizard again to
 | 
						|
            completion.""")
 | 
						|
            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
 | 
						|
    world.starting = True
 | 
						|
    
 | 
						|
    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.')
 | 
						|
 | 
						|
    conf.allowEval = options.allowEval
 | 
						|
 | 
						|
    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
 | 
						|
 | 
						|
    conf.strictRfc = options.strictRfc
 | 
						|
 | 
						|
    irc = irclib.Irc(nick, user, ident, password)
 | 
						|
    callback = Owner.Class()
 | 
						|
    irc.addCallback(callback)
 | 
						|
    driver = drivers.newDriver(server, irc)
 | 
						|
    
 | 
						|
    if options.profile:
 | 
						|
        import hotshot
 | 
						|
        profiler = hotshot.Profile('%s-%i.prof' % (nick, time.time()))
 | 
						|
        profiler.run('main()')
 | 
						|
    else:
 | 
						|
        main()
 | 
						|
 | 
						|
 | 
						|
    
 | 
						|
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
 |