#!/usr/bin/env python
#
# adzapper
# Copyright 1999 - 2001 Adam Feuer
# Adam Feuer <adamf@pobox.com>
#
# This file is part of adzapper.
#
# adzapper is free software; you can redistribute it and/or modify
# it under the terms of the Python License, as published by the
# Python Software Foundation.
#
# adzapper is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# Python License for more details.
#
# You should have received a copy of the Python License along
# with adzapper; see the file COPYING.
#
#
# adzapper is an http proxy that filters out ads
#		
#
"""adzapper startup file
Usage: %(program)s [Options] [<port>]
Options:

-h
    Output this text.

-d <debug level>
    Turn debugging on. 0 is off; higher numbers produce greater detail. 

-p
    Turn profiling on

-v
    Display version number

-u
    Start a separate web server for the web UI on <port>+1
    Done automatically now- this is a no-op.

-n <nameserver ip address>
    Use nameserver at this ip address

-z <zaplet directory>
    Path to zaplet directory. Default is %(here)s/zaplets. If the directory
    name does not start with a '/' it is interpreted relative to the current
    working directory.

-f <zaplet config file>
    Name of zaplet configuration file. Default is
    %(here)s/adzapper.conf. If the file name does not start with a '/'
    it is interpreted relative the current working directory.

<port>    
    Port to run on. Default is port 51966.

"""

RCS_ID =  '$Id: adzapper.py,v 1.13 2001/09/02 04:47:16 adamf Exp $'

# global variables
MAJOR_VERSION = 0
MINOR_VERSION = 4
SUB_VERSION   = 0     # ;-)  

# adzapper config file
ADZAPPER_CONFIG_FILE = 'adzapper.conf'

# standard modules
import string
import getopt
import os
import sys

# holder object for adzapper_engine and zaplet_engine
class combined_engine:
    def __init__(self):
        self.adzapper = None
        self.zaplet = None

    def restart(self):
        self.zaplet.__init__(self.adzapper.zaplet_dirs,self.adzapper.site_zaplet_dir)


def main():
    # fix the path
    program=sys.argv[0]
    here=os.path.join(os.path.split(program)[0])
    sys.path=[os.path.join(here,'src'),os.path.join(here,'src','medusa'),here] + filter(None, sys.path)

    # import modules.
    from debug import debug

    # preload this for use with gordon mcmillan's Builder.py
    import xml.sax.drivers.drv_xmlproc


    # fix asyncore signal handling
    import asyncore
    import asyncore_fixes
    asyncore.poll = asyncore_fixes.b_poll

    # fix asyncore logging 
    asyncore.dispatcher.log_info = debug.log_info
    asyncore.dispatcher.log = debug.log

    # fix http_server.http_channel writable predicate
    import http_server
    import http_server_fixes
    http_server.http_channel.writable = http_server_fixes.writable
    if hasattr(http_server.http_channel, 'writable_for_proxy'):
        delattr(http_server.http_channel, 'writable_for_proxy')
    http_server.http_channel.handle_close = http_server_fixes.handle_close
    http_server.http_request.log = http_server_fixes.log  # no logging!


    # adzapper and zaplet modules
    import http_proxy
    from adzapper import platform_dependent, adzapper_engine
    import zaplet
    import ui_handler


    import resolver

    # Problem with medusa's resolver on windows9x
    if sys.platform == "win32":
        Platform, SubPlatform, Type = platform_dependent.getWindowsPlatformName()
        if SubPlatform == "Windows":
            import resolver_fixes 
            resolver.caching_resolver.resolve = resolver_fixes.my_resolve
            resolver.caching_resolver.resolve_ptr = resolver_fixes.my_resolve_ptr

    

    # debugging defaults to off
    debug.debuglevel = 0

    # profiling defaults to off
    profiling_on = 0

    # we don't have the nameserver IP address yet
    nameserver = None

    # set the defaults for the adzapper config file
    program=sys.argv[0]
    here=os.path.join(os.getcwd(),os.path.split(program)[0])
    adzapper_config_file = os.path.join(here,ADZAPPER_CONFIG_FILE)
    
    site_zaplet_dir = None

    program_name = sys.argv[0]
    args = sys.argv[1:]
    debug.debug (1,("args: ",  args))

    try:
        optlist, arglist = getopt.getopt(args, 'hpvud:n:z:f:')
    except getopt.error, error_message:
        print "error message: %s" % error_message
        print
        print __doc__ % vars()
        raise SystemExit

    debug.debug(1,('args: ' , args))
    debug.debug(1,('optlist' , optlist))
    debug.debug(1,('arglist: ' , arglist))

    if arglist == []:
        port = None
    else:
        debug.debug(1, 'port: %s ' % arglist[0])
        port = string.atoi(arglist[0])

    if '-h' in args:
        print __doc__ % vars()
        raise SystemExit

    if '-v' in args:
        VERSION_STRING = '%d.%d.%d' % (MAJOR_VERSION,MINOR_VERSION,SUB_VERSION)
        print '%s version: %s' % (program_name,VERSION_STRING)
        raise SystemExit

    if '-p' in args:
        profiling_on = 1

    if '-d' in args:
        for list_item in optlist:
            if list_item[0] == '-d':
                debug.debuglevel = string.atoi(list_item[1])

    if '-n' in args:
        for list_item in optlist:
            if list_item[0] == '-n':
                nameserver = list_item[1]

    if '-z' in args:
        # site zaplet directory
	# note: if more then one '-z' is specified,
	# the last one on the command line is used.
        for list_item in optlist:
            if list_item[0] == '-z':
                site_zaplet_dir = list_item[1]
                
    if '-f' in args:
        for list_item in optlist:
            if list_item[0] == '-f':
                adzapper_config_file = list_item[1]

    debug.debug(1,'Debugging output is turned on at level %d' % debug.debuglevel)

    # announce that we are starting
    if sys.platform == "win32":
        print "adzapper initializing..."

    # initialize the adzapper and zaplet engines
    # make the holder object for the combined adzapper and zaplet engines
    ce = combined_engine()

    # initialize adzapper engine - for adzapper defaults, ACLs, etc.
    ce.adzapper = adzapper_engine.adzapper_engine(adzapper_config_file)

    # if port was specified on the command line, use it;
    # otherwise, use config file's value
    if port == None:
        port = ce.adzapper.port

    # if there was a site_zaplet_directory set on the commandline,
    # it overrides the one specified in the config file.
    if site_zaplet_dir:
        ce.adzapper.site_zaplet_dir = site_zaplet_dir

    # now set the nameserver
    if (nameserver == None):
        # no commandline parameter-- is it in the config file?
        if ce.adzapper.nameserver != None:
            # yes, this overrides the automatic configuration
            nameserver = ce.adzapper.nameserver
        else:
            # get the nameserver IP address for resolver
            # either out of resolv.conf or the Registry, depending
            # on the platform
            nameserver = platform_dependent.getNameServer()
            if (nameserver == None):
                # nameserver defaults to localhost
                nameserver = '127.0.0.1'
                
    debug.debug(1,"nameserver: %s" % nameserver)

    # initialize zaplet engine - for blocking URLs
    #
    # zaplet_engine needs a list of dirs and the site zaplet dir
    ce.zaplet = zaplet.zaplet_engine.zaplet_engine(ce.adzapper.zaplet_dirs,ce.adzapper.site_zaplet_dir)

    # make sure the popup blocking is set right
    ce.zaplet.set_block_popups_regex(ce.adzapper.block_popups_regex)


    # make the persistent resolver
    debug.debug(2,'Using nameserver %s' % nameserver)            
    resolver = resolver.caching_resolver (nameserver)
    
    # install signal handler to catch the signal SIGHUP 
    # (only do this for Unix platforms)
    platform_dependent.setSighupHandler(ce.restart)

    # make the HTTP server
    hs = http_server.http_server ('', port)

    # make the proxy handler and install it
    #   need to give it the resolver and the combined_engine
    ph = http_proxy.http_proxy_handler(resolver,ce)
    hs.install_handler (ph)

    # make the UI handler and install it
    uih = ui_handler.ui_handler(ce)
    hs.install_handler(uih)

    # make a separate HTTP server for the UI and install it
    uihs = http_server.http_server('',port+1)
    uidh = ui_handler.ui_handler(ce,1) # ui_handler that always matches
    uihs.install_handler(uidh)

    # announce that we are running
    if sys.platform == "win32":
        print "adzapper running."


    if profiling_on:
        def profile_loop ():
            global asyncore
            try:
                asyncore.loop()
            except KeyboardInterrupt:
                pass
            import profile
            profile.run ('profile_loop()', 'profile.out')
    else:
        asyncore.loop()



if __name__ == '__main__':

    main()
