#
# This file is part of Zaplet
# Copyright 1999 - 2001 Adam Feuer <adamf@pobox.com>
#
# Zaplet 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, or GNU General Public License as published
# by the Free Software Foundation (either version 2 of the License, or
# (at your option) any later version).
#
# Zaplet 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
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Zaplet; see the file COPYING-Zaplet. If not, write to the
# Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
#
# You should have received a copy of the Python License along
# with Zaplet; see the file COPYING.
#

# zaplet classes
# for use with adzapper filtering proxy

RCS_ID =  '$Id: zaplet_object.py,v 1.9 2001/09/02 04:47:17 adamf Exp $'

# standard modules
import os
import re
import string
import sys
import urlparse

# XML modules
from xml.sax import saxexts, saxlib, saxutils

# adzapper modules
from debug import debug
import zaplet
import zaplet_sax_handler

import xml.sax.drivers.drv_xmlproc
XML_PARSER=xml.sax.drivers.drv_xmlproc.create_parser()  # for use with Builder.py


##################################################################
#
# zaplet object
#
class zaplet_obj:

    """data structure object to hold zaplet"""

    def __init__(self, zapletstring = None):
        """make a new zaplet object. if zapletstring is given, parse the string,
        fill out the object data fields, then compile it."""

        # zaplet version defaults to 0.1
        self.majorversion = 0
        self.minorversion = 1
        self.version = '0.1'
        self.host = ''
        self.comments = []

        self.allow_literal = []
        self.allow_regex = []
        self.allow_re_str = ''
        self.allow_re = None
        self.allow_everything = 0
        self.num_allows = 0

        self.block_literal = []
        self.block_regex = []
        self.block_re_str = ''
        self.block_re = None
        self.block_everything = 0
        self.num_blocks = 0

        self.block_popups_everything = 0
        self.block_popups_literal = []
        self.block_popups_regex = []
        self.block_popups_re_str = ''
        self.block_popups_re = None
        self.num_block_popups = 0
        
        self.filters = []

        self.dir = None
        self.filename = None

        self.valid = 1

        if zapletstring == None:
            return
        
        dh = zaplet_sax_handler.ZapletDocHandler(self)
        self.parser = XML_PARSER
        self.parser.setDocumentHandler(dh)
        self.parser.reset()
        self.parser.feed(zapletstring)
        self.parser.close()

        self.valid = self.compile()
        return 


    def compile(self):
        """call this to compile the changes and make them active"""
        
        # for debugging
        self.printself()

        block_re_str = '' # the block regex that will be built for this zaplet
        allow_re_str = '' # the allow regex that will be built for this zaplet

        block_popups_re_str = '' # the block popups regex that will be built for this zaplet

        if self.version != None and self.version != '':
            vlist = string.split(self.version,'.')
            self.majorversion = string.atoi(vlist[0])
            self.minorversion = string.atoi(vlist[1])



        # build allow regex string
        for regex in self.allow_regex:
            allow_re_str =  allow_re_str + '|' + regex
        for literal in self.allow_literal:
            re_add = re.escape(literal)
            allow_re_str = allow_re_str + '|' + re_add
        # chop off initial |
        allow_re_str = allow_re_str[1:]

        # set number of allow statements
        self.num_allows = len(self.allow_regex) + len (self.allow_literal)



        # build block regex string
        for regex in self.block_regex:
            block_re_str =  block_re_str + '|' + regex
        for literal in self.block_literal:
            re_add = re.escape(literal)
            block_re_str = block_re_str + '|' + re_add
        # chop off initial |
        block_re_str = block_re_str[1:]

        # set number of blocks
        self.num_blocks = len(self.block_regex) + len(self.block_literal)



        # build block popups regex string
        for regex in self.block_popups_regex:
            block_popups_re_str =  block_popups_re_str + '|' + regex
        for literal in self.block_popups_literal:
            re_add = re.escape(literal)
            block_popups_re_str = block_popups_re_str + '|' + re_add
        # chop off initial |
        block_popups_re_str = block_popups_re_str[1:]

        # set number of block_popups
        self.num_block_popups = len(self.block_popups_regex) + len(self.block_popups_literal)



        # if there is no version statement, don't use the zaplet--
        #   version statements are now required!
        if self.majorversion != None and self.minorversion != None:
            debug.debug(7,"self.version: %d.%d " % (self.majorversion,self.minorversion))
        else:
            debug.debug(7,"zaplet not used; no version statement!")
            return None

        # if there is no host statement, don't use the zaplet--
        #   host statements are now required
        if self.host != None:
            debug.debug(7,"self.host: %s " % self.host)
        else:
            debug.debug(7,"zaplet not used; no host statement!")
            return None

        debug.debug(7,"allow_re_str: %s    host: %s" % (allow_re_str,self.host))
        debug.debug(7,"block_re_str: %s    host: %s" % (block_re_str,self.host))

        debug.debug(7,"num_allows: %s    host: %s" % (self.num_allows,self.host))
        debug.debug(7,"num_blocks: %s    host: %s" % (self.num_blocks,self.host))

        debug.debug(7,"block_popups_re_str: %s" % block_popups_re_str)

        # compile regexes
        if allow_re_str == "":
            allow_re_str = "^$"  # empty URL - will never happen
        self.allow_re_str = allow_re_str
        self.allow_re = re.compile(self.allow_re_str)

        self.block_re_str = block_re_str
        self.block_re = re.compile(self.block_re_str)

        self.block_popups_re_str = block_popups_re_str
        self.block_popups_re = re.compile(self.block_popups_re_str)

        for filter in self.filters:
            filter.compile()

        return 0



    def xml_repr(self,fragment=None,indent=None):
        """return a string with an xml representation of ourself

        if fragment is 1, don't start with <?xml version='1.0'>
        if indent is set, use that as the indent
        """

        s1 = ''
        if not fragment:
            s1 = s1 + zaplet.XMLDOC
        if indent != None:
            zindent = indent
        else:
            zindent = ''
        zpindent = '    ' + zindent

        s1 = s1 + zindent + "<zaplet>\n"
        s1 = s1 + zpindent + "<version>" + self.version + "</version>\n"
        s1 = s1 + zpindent + "<host>" + self.host + "</host>\n"

        # zaplet comments
        for comment in self.comments:
            s1 = s1 + zpindent + '<comment>' + comment + '</comment>\n'

        for key0 in ("allow", "block"):
            for key1 in ("literal", "regex"):
                list = "self.%s_%s" % (key0, key1)
                otag = "<%s><%s>" % (key0, key1)
                ctag = "</%s></%s>" % (key1, key0) # need to reverse for closing
                obj = eval(list)
                if obj != None and type(obj) == type([]) and len(obj) > 0: 
                    for item in obj:
                        if item != '':
                            s1 = s1 + zpindent + otag + item + ctag + "\n"

        for filter in self.filters:
            if filter != None:
                s1 = s1 + filter.xml_repr(zpindent)

        s1 = s1 + zindent + "</zaplet>\n"
        return s1

    def xml_repr_web(self,fragment=None,indent=None):
        """fix the xml repr to display to web"""
        zaplet_xml_str = self.xml_repr(fragment,indent)
        s = '<pre>\n'
        s3 = string.replace(zaplet_xml_str,'<','&lt;')
        s3 = string.replace(s3,'>','&gt;')
        s = s + s3
        s = s + '</pre>\n'
        return s



    # using the new XML dtd
    def xml_repr1(self,fragment=None,indent=None):
        """return a string with an xml representation of ourself

        if fragment is 1, don't start with <?xml version='1.0'>
        if indent is set, use that as the indent
        """

        s1 = ''
        if not fragment:
            s1 = s1 + zaplet.XMLDOC
        if indent != None:
            zindent = indent
        else:
            zindent = ''
        zpindent = '    ' + zindent

        s1 = s1 + zindent + "<zaplet>\n"
        s1 = s1 + zpindent + "<version>" + self.version + "</version>\n"
        s1 = s1 + zpindent + "<host>" + self.host + "</host>\n"

        # zaplet comments
        for comment in self.comments:
            s1 = s1 + zpindent + '<comment>' + comment + '</comment>\n'

        actions = 0


        if self.allow_everything == 1:
            s1 = s1 + zpindent + '<allow_url type="everything"/>\n'

        obj = self.allow_literal
        if obj != None and type(obj) == type([]) and len(obj) > 0: 
            for item in obj:
                if item != '':
                    s1 = s1 + zpindent + '<allow_url type="literal">' + item + '</allow_url>\n'
        
        obj = self.allow_regex
        if obj != None and type(obj) == type([]) and len(obj) > 0: 
            for item in obj:
                if item != '':
                    s1 = s1 + zpindent + '<allow_url type="regex">' + item + '</allow_url>\n'

        if self.block_everything == 1:
            s1 = s1 + zpindent + '<block_url type="everything"/>\n'

        obj = self.block_literal
        if obj != None and type(obj) == type([]) and len(obj) > 0: 
            for item in obj:
                if item != '':
                    s1 = s1 + zpindent + '<block_url type="literal">' + item + '</block_url>\n'
                    actions = actions + 1

        
        obj = self.block_regex
        if obj != None and type(obj) == type([]) and len(obj) > 0: 
            for item in obj:
                if item != '':
                    s1 = s1 + zpindent + '<block_url type="regex">' + item + '</block_url>\n'
                    actions = actions + 1

        if self.block_popups_everything == 1:
            s1 = s1 + zpindent + '<block_popups type="everything"/>\n'
            actions = actions + 1

        obj = self.block_popups_literal
        if obj != None and type(obj) == type([]) and len(obj) > 0:
            for item in obj:
                if item != '':
                    s1 = s1 + zpindent + '<block_popups type="literal">' + item + '</block_popups>\n'
                    actions = actions + 1

        obj = self.block_popups_regex
        if obj != None and type(obj) == type([]) and len(obj) > 0:
            for item in obj:
                if item != '':
                    s1 = s1 + zpindent + '<block_popups type="regex">' + item + '</block_popups>\n'
                    actions = actions + 1

        
        for filter in self.filters:
            if filter != None:
                s1 = s1 + filter.xml_repr(zpindent)
                actions = actions + 1

#        if actions == 0 and self.block_everything == 0:
#            # this is because the old default action was to block everything
#            s1 = s1 + zpindent + '<block_url type="everything"/>\n'
            

        s1 = s1 + zindent + "</zaplet>\n"
        return s1



    def xml_repr1_web(self,fragment=None,indent=None):
        """fix the xml repr to display to web"""
        zaplet_xml_str = self.xml_repr1(fragment,indent)
        s = '<pre>\n'
        s3 = string.replace(zaplet_xml_str,'<','&lt;')
        s3 = string.replace(s3,'>','&gt;')
        s = s + s3
        s = s + '</pre>\n'
        return s




    def printself(self):
        debug.debug(7,"version: %s" % self.version)
        debug.debug(7,"host:    %s" % self.host)
        debug.debug(7,"comments:")
        debug.debug(7,self.comments)
        debug.debug(7,"allow_literal:")
        debug.debug(7,self.allow_literal)
        debug.debug(7,"allow_regex:")
        debug.debug(7,self.allow_regex)
        debug.debug(7,"block_literal:")
        debug.debug(7,self.block_literal)
        debug.debug(7,"block_regex:")
        debug.debug(7,self.block_regex)

        for filter in self.filters:
            filter.printself()

