home *** CD-ROM | disk | FTP | other *** search
/ PC World 2001 April / PCWorld_2001-04_cd.bin / Software / TemaCD / webclean / webcleanerconf < prev    next >
Text File  |  2001-01-14  |  52KB  |  1,254 lines

  1. #!/usr/bin/env python2
  2. """ webcleanerconf
  3.  
  4.     Copyright (C) 2000,2001  Bastian Kleineidam
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation; either version 2 of the License, or
  9.     (at your option) any later version.
  10.  
  11.     This program is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program; if not, write to the Free Software
  18.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  
  20. This is a nice graphical configuration tool for WebCleaner. Because
  21. it depends on some classes that come only with WebCleaner, I do not
  22. separate this tool from the WebCleaner source.
  23.  
  24. Developer note: you have to create() all windows which are created at
  25. runtime. This is also a FAQ entry in the FOX documentation.
  26. """
  27. import sys
  28. if sys.version[:5] < "2.0":
  29.     raise SystemExit, "This program requires Python 2.0 or later."
  30. from FXPy import *
  31. import WebCleanerConf
  32. import os,string,tempfile,time
  33. from webfilter import _
  34. from webfilter.get_dom import *
  35. from webfilter.Rules import GetRuleFromNode, GetRuleFromName, FilterRules, Netlocparts
  36. from types import IntType
  37.  
  38. # set the directory for new files
  39. tempfile.tempdir = WebCleanerConf.config_dir
  40.  
  41. DEBUG_LEVEL=0
  42. def debug(msg):
  43.     if DEBUG_LEVEL:
  44.        sys.stderr.write("DEBUG: "+msg+"\n")
  45.  
  46. def error(msg):
  47.     sys.stderr.write("error: "+msg+"\n")
  48.  
  49. HelpText = \
  50. _("Most values have a tooltip. Point your mouse over the labels and"
  51.   "you can read them.\n"
  52.   "Unix users can also read the manual page with 'man webcleanerconf'.")
  53.  
  54. TipText = {
  55.  
  56. #Proxy GUI settings (configfile settings):
  57. "Port": _("Set the port adress the WebCleaner proxy is listening on.\n"
  58.           "Default value is 8080."),
  59.  
  60. "Logfile": _("The name for the logfile can be empty (no logging), 'stdout'\n"
  61.              "(standard out) or a filename (relative or absolute)."),
  62.  
  63. "Buffer size": _("The buffer size tells the proxy to read data in chunks with the\n"
  64.                  "given size."),
  65.  
  66. "Timeout":  _("Network timeout after which the connection is disabled. Currently\n"
  67.               "this is used only with HTTPS connections, the other connections\n"
  68.               "have the system defined socket timeout."),
  69.  
  70. "Obfuscate IP": _("When this checkbox is active (configuration file value = 1) the\n"
  71.                   "proxy translates the numerical IP name into an integer number.\n"
  72.                   "For example '5.7.9.11' gets mapped to\n"
  73.                   "5*2^24 + 7*2^16 + 9*2^8 + 11*2^0 = 84347147"),
  74.  
  75. "Debug level":  _("Set the debugging level. Debug output is on stderr.\n"
  76.                   "Debug levels:\n"
  77.                   "0 - disabled (default)\n"
  78.                   "1 - normal debug messages\n"
  79.                   "2 - print requests and filtering\n"
  80.                   "3 - detailed filter messages"),
  81.  
  82. "Parent Proxy": _("The parent proxy WebCleaner should use."),
  83.  
  84. "Rewriter":     _("Rewrite HTML code. This is very powerful and can filter\n"
  85.                   "almost all advertising and other crap."),
  86.  
  87. "Parent Proxy Port": _("The parent proxy port WebCleaner should use."),
  88.  
  89. "BinaryCharFilter":  _("Replace illegal binary characters in HTML code like the quote\n"
  90.                        "chars often found in Microsoft pages."),
  91.  
  92. "Header":   _("Add, modify and delete HTTP headers of request and response."),
  93.  
  94. "Blocker":  _("Block specific sites by URL name."),
  95.  
  96. "GifImage": _("Deanimates GIFs and removes all unwanted GIF image\n"
  97.               "extensions (for example GIF comments)."),
  98.  
  99. "Compress": _("Compression of documents with good compression ratio\n"
  100.               "like HTML, WAV, etc."),
  101.  
  102. #Filter GUI settings (configfile settings):
  103.  
  104. "Title": _("The title of the filter."),
  105.  
  106. "Description": _("Some good description what this filter does."),
  107.  
  108. "Language": _("If you specify incompatible regular expressions\n"
  109.               "choose the appropriate language here."),
  110.  
  111. "Filename": _("The name of the configuration file where these\n"
  112.               "filters are stored."),
  113.  
  114. "disable": _("You can disable a whole folder or single filter rules"),
  115.  
  116. }
  117.  
  118.  
  119. RemoveText = \
  120. _("You cannot remove folders. If you really want to get rid\n"
  121. "of this folder, delete the appropriate configuration file.\n"
  122. "It is always safer to disable a folder or filter instead of\n"
  123. "deleting it!")
  124.  
  125. def lang_num(lang):
  126.     """a little helper function for an FXComboBox"""
  127.     if lang=="Perl": return 1
  128.     if lang=="Python": return 2
  129.     return 0
  130.  
  131. def num_lang(num):
  132.     """another little helper function for an FXComboBox"""
  133.     if num==1: return "Perl"
  134.     if num==2: return "Python"
  135.     return None
  136.  
  137. def get_time(secs):
  138.     """return formatted timestamp"""
  139.     import time
  140.     t = time.localtime(secs)
  141.     return time.strftime("%d.%m.%Y %H:%M:%S", t)
  142.  
  143. # names of the filter types
  144. Filternames = ['block', 'rewrite', 'allow', 'header', 'image', 'nocomments']
  145.  
  146. def loadIcon(app, filename):
  147.     """load icons from the config_dir directory"""
  148.     filename = os.path.join(WebCleanerConf.config_dir, filename)
  149.     ext = string.lower(filename[-3:])
  150.     data = open(filename, 'rb').read()
  151.     if ext=='gif':
  152.         return FXGIFIcon(app, data)
  153.     if ext=='png':
  154.         return FXPNGIcon(app, data)
  155.  
  156.  
  157. class FXRuleFrameFactory:
  158.     """Every Rule (see webfilter/Rules.py) has a "fromFactory" function.
  159.        A factory has a function from***Rule for every different Rule
  160.        class.
  161.        This particular factory generates windows which display all the
  162.        variables found in a rule.
  163.     """
  164.     def __init__(self, rootframe):
  165.         """Because we store frames in a hierarchical tree, we need
  166.        a tree rootframe.
  167.        To distinguish frames we have a unique index for each."""
  168.         self.rootframe = rootframe
  169.         self.index = 0
  170.  
  171.     def inc_index(self):
  172.         self.index += 1
  173.  
  174.     def fromRule(self, rule):
  175.         self.inc_index()
  176.         return FXRuleFrame(self.rootframe, rule, self.index)
  177.  
  178.     def fromRewriteRule(self, rule):
  179.         self.inc_index()
  180.         return FXRewriteRuleFrame(self.rootframe, rule, self.index)
  181.  
  182.     def fromAllowRule(self, rule):
  183.         self.inc_index()
  184.         return FXAllowRuleFrame(self.rootframe, rule, self.index)
  185.  
  186.     def fromBlockRule(self, rule):
  187.         self.inc_index()
  188.         return FXBlockRuleFrame(self.rootframe, rule, self.index)
  189.  
  190.     def fromHeaderRule(self, rule):
  191.         self.inc_index()
  192.         return FXHeaderRuleFrame(self.rootframe, rule, self.index)
  193.  
  194.     def fromImageRule(self, rule):
  195.         self.inc_index()
  196.         return FXImageRuleFrame(self.rootframe, rule, self.index)
  197.  
  198.     def fromNocommentRule(self, rule):
  199.         self.inc_index()
  200.         return FXNocommentRuleFrame(self.rootframe, rule, self.index)
  201.  
  202.     def fromFilterRules(self, rule):
  203.         self.inc_index()
  204.         return FXFilterRulesFrame(self.rootframe, rule, self.index)
  205.  
  206.  
  207. class FXRuleFrame(FXVerticalFrame):
  208.     """display all variables found in a basic Rule.
  209.     This means basically we have a FOX widget for each variable
  210.     found in the rule (e.g. for rule.title we have an FXTextField).
  211.     """
  212.     (ID_TITLE,
  213.      ID_DESC,
  214.      ID_DISABLE_RULE,
  215.      ID_LAST,
  216.     ) = range(FXVerticalFrame.ID_LAST, FXVerticalFrame.ID_LAST+4)
  217.  
  218.     def __init__(self, parent, rule, index):
  219.         FXVerticalFrame.__init__(self, parent, LAYOUT_FILL_X|LAYOUT_FILL_Y)
  220.         # event map
  221.         FXMAPFUNC(self,SEL_COMMAND, FXRuleFrame.ID_TITLE,FXRuleFrame.onCmdTitle)
  222.         FXMAPFUNC(self,SEL_CHANGED, FXRuleFrame.ID_DESC, FXRuleFrame.onCmdDesc)
  223.         FXMAPFUNC(self,SEL_COMMAND, FXRuleFrame.ID_DISABLE_RULE,FXRuleFrame.onCmdDisableRule)
  224.         self.rule = rule
  225.         # augment the rule information with the (unique) index
  226.         self.rule.index = index
  227.         FXLabel(self, self.get_name(), opts=LAYOUT_CENTER_X|LAYOUT_TOP|LAYOUT_FILL_X)
  228.         f = FXHorizontalFrame(self, LAYOUT_FILL_X|LAYOUT_LEFT|LAYOUT_TOP, 0,0,0,0, 0,0,0,0, 0,0)
  229.         FXLabel(f, _("Title")+":\t"+TipText["Title"], opts=LAYOUT_CENTER_Y|LAYOUT_LEFT)
  230.         t = FXTextField(f, 15, self, FXRuleFrame.ID_TITLE)
  231.         t.setText(self.rule.title)
  232.         t = FXCheckButton(f, _("disable")+"\t"+TipText["disable"], self, FXRuleFrame.ID_DISABLE_RULE,ICON_AFTER_TEXT|LAYOUT_RIGHT|LAYOUT_CENTER_Y|LAYOUT_FILL_X)
  233.         t.setCheck(self.rule.disable)
  234.         FXLabel(self, _("Description")+":\t"+TipText["Description"])
  235.         f = FXVerticalFrame(self, FRAME_SUNKEN|FRAME_THICK|LAYOUT_FILL_X|LAYOUT_FILL_Y, 0,0,0,0, 0,0,0,0, 0,0)
  236.         t = FXText(f, self, FXRuleFrame.ID_DESC, opts=LAYOUT_FILL_X|LAYOUT_FILL_Y|TEXT_WORDWRAP)
  237.         t.setText(self.rule.desc)
  238.         t.setEditable()
  239.  
  240.     def get_name(self):
  241.         """display this name at the top of the window"""
  242.         s = string.capitalize(self.rule.get_name())+_(" rule")
  243.         s += " (ID%d"%self.rule.ruleid+") - "+get_time(self.rule.timestamp)
  244.         return s
  245.  
  246.     def onCmdTitle(self, sender, sel, ptr):
  247.         title = string.strip(sender.getText())
  248.         if not title:
  249.             error(_("empty title"))
  250.             sender.setText(self.rule.title)
  251.             return 1
  252.         sender.setText(title)
  253.         self.rule.title = title
  254.         self.getApp().dirty = 1
  255.         debug("Rule title changed")
  256.         # send message to main window for treelist updating
  257.         win = self.getApp().getMainWindow()
  258.         win.handle(sender, MKUINT(ConfWindow.ID_TITLE,SEL_COMMAND), ptr)
  259.         return 1
  260.  
  261.     def onCmdDesc(self, sender, sel, ptr):
  262.         if self.rule.desc != sender.getText():
  263.             self.rule.desc = sender.getText()
  264.             self.getApp().dirty = 1
  265.             debug("Rule description changed")
  266.         return 1
  267.  
  268.     def onCmdDisableRule(self, sender, sel, ptr):
  269.         self.rule.disable = sender.getCheck()
  270.         self.getApp().dirty = 1
  271.         debug("Rule "+(self.rule.disable and "disabled" or "enabled"))
  272.         return 1
  273.  
  274.  
  275.  
  276. class FXRewriteRuleFrame(FXRuleFrame):
  277.     """display all variables found in a RewriteRule"""
  278.     (ID_TAG,
  279.      ID_ENCLOSED_BLOCK,
  280.      ID_REPLACE_PART,
  281.      ID_ATTRIBUTE_ADD,
  282.      ID_ATTRIBUTE_EDIT,
  283.      ID_ATTRIBUTE_REMOVE,
  284.      ID_REPLACE_VALUE,
  285.     ) = range(FXRuleFrame.ID_LAST, FXRuleFrame.ID_LAST+7)
  286.  
  287.     def __init__(self, parent, rule, index):
  288.         FXRuleFrame.__init__(self, parent, rule, index)
  289.         FXMAPFUNC(self,SEL_COMMAND,FXRewriteRuleFrame.ID_TAG,FXRewriteRuleFrame.onCmdTag)
  290.         FXMAPFUNC(self,SEL_COMMAND,FXRewriteRuleFrame.ID_ENCLOSED_BLOCK,FXRewriteRuleFrame.onCmdEnclosed)
  291.         FXMAPFUNC(self,SEL_COMMAND,FXRewriteRuleFrame.ID_REPLACE_PART,FXRewriteRuleFrame.onCmdReplacePart)
  292.         FXMAPFUNC(self,SEL_COMMAND,FXRewriteRuleFrame.ID_REPLACE_VALUE,FXRewriteRuleFrame.onCmdReplaceValue)
  293.         FXMAPFUNC(self,SEL_COMMAND,FXRewriteRuleFrame.ID_ATTRIBUTE_ADD,FXRewriteRuleFrame.onCmdAttributeAdd)
  294.         FXMAPFUNC(self,SEL_COMMAND,FXRewriteRuleFrame.ID_ATTRIBUTE_EDIT,FXRewriteRuleFrame.onCmdAttributeEdit)
  295.         FXMAPFUNC(self,SEL_COMMAND,FXRewriteRuleFrame.ID_ATTRIBUTE_REMOVE,FXRewriteRuleFrame.onCmdAttributeRemove)
  296.         matrix = FXMatrix(self, 2, MATRIX_BY_COLUMNS)
  297.         FXLabel(matrix, _("Tag name:"), opts=LAYOUT_CENTER_Y|LAYOUT_LEFT)
  298.         t = FXTextField(matrix, 10, self, FXRewriteRuleFrame.ID_TAG)
  299.         t.setText(self.rule.tag)
  300.         FXLabel(matrix, _("Attributes:"))
  301.         f = FXHorizontalFrame(matrix, LAYOUT_FILL_X|LAYOUT_FIX_HEIGHT|FRAME_SUNKEN|FRAME_THICK, 0,0,0,60, 0,0,0,0, 0,0)
  302.         self.iconlist = FXIconList(f, opts=LAYOUT_FILL_X|LAYOUT_FILL_Y|ICONLIST_SINGLESELECT|ICONLIST_AUTOSIZE)
  303.         self.iconlist.appendHeader(_("Name"),NULL,50)
  304.         self.iconlist.appendHeader(_("Value"),NULL,175)
  305.         for name,value in self.rule.attrs.items():
  306.             self.iconlist.appendItem(name +"\t"+value.pattern)
  307.         FXLabel(matrix, "")
  308.         f = FXHorizontalFrame(matrix)
  309.         FXButton(f, _("Add"), None, self, FXRewriteRuleFrame.ID_ATTRIBUTE_ADD)
  310.         FXButton(f, _("Edit"), None, self, FXRewriteRuleFrame.ID_ATTRIBUTE_EDIT)
  311.         FXButton(f, _("Remove"), None, self, FXRewriteRuleFrame.ID_ATTRIBUTE_REMOVE)
  312.         FXLabel(matrix, _("Enclosed block:"), opts=LAYOUT_CENTER_Y|LAYOUT_LEFT)
  313.         t = FXTextField(matrix, 20, self, FXRewriteRuleFrame.ID_ENCLOSED_BLOCK)
  314.         if self.rule.enclosed:
  315.             t.setText(self.rule.enclosed.pattern)
  316.         FXLabel(matrix, _("Replace part:"), opts=LAYOUT_CENTER_Y|LAYOUT_LEFT)
  317.         t = FXComboBox(matrix,9,6,self, self.ID_REPLACE_PART,opts=COMBOBOX_INSERT_LAST|FRAME_SUNKEN|FRAME_THICK|LAYOUT_SIDE_TOP)
  318.         t.appendItem(_("Tag"))
  319.         t.appendItem(_("Tag name"))
  320.         t.appendItem(_("Attribute"))
  321.         t.appendItem(_("Attribute value"))
  322.         t.appendItem(_("Complete tag"))
  323.         t.appendItem(_("Enclosed block"))
  324.         t.setEditable(0)
  325.         t.setCurrentItem(self.rule.replace[0])
  326.         FXLabel(matrix, _("Replace value:"), opts=LAYOUT_CENTER_Y|LAYOUT_LEFT)
  327.         t = FXTextField(matrix, 20, self, FXRewriteRuleFrame.ID_REPLACE_VALUE)
  328.         t.setText(self.rule.replace[1])
  329.  
  330.  
  331.     def onCmdTag(self, sender, sel, ptr):
  332.         tag = string.strip(sender.getText())
  333.         if not tag:
  334.             error("empty tag name")
  335.             sender.setText(self.rule.tag)
  336.             return 1
  337.         self.rule.tag = tag
  338.         self.getApp().dirty = 1
  339.         debug("Changed rule tag name")
  340.         return 1
  341.  
  342.  
  343.     def onCmdEnclosed(self, sender, sel, ptr):
  344.         enclosed = string.strip(sender.getText())
  345.         if enclosed:
  346.             self.rule.enclosed = re.compile(enclosed)
  347.         else:
  348.             self.rule.enclosed = None
  349.         self.getApp().dirty = 1
  350.         debug("Changed rule enclosed block")
  351.         return 1
  352.  
  353.  
  354.     def onCmdReplacePart(self, sender, sel, ptr):
  355.         self.rule.replace[0] = sender.getCurrentItem()
  356.         self.getApp().dirty = 1
  357.         debug("Changed rule replace part")
  358.         return 1
  359.  
  360.     def onCmdAttributeAdd(self, sender, sel, ptr):
  361.         dialog = FXDialogBox(self,_("Add Attribute"),DECOR_TITLE|DECOR_BORDER)
  362.         frame = FXVerticalFrame(dialog, LAYOUT_SIDE_TOP|FRAME_NONE|LAYOUT_FILL_X|LAYOUT_FILL_Y|PACK_UNIFORM_WIDTH)
  363.         matrix = FXMatrix(frame, 2, MATRIX_BY_COLUMNS)
  364.         FXLabel(matrix, _("Name:"), opts=LAYOUT_CENTER_Y|LAYOUT_LEFT)
  365.         nametf = FXTextField(matrix, 20)
  366.         FXLabel(matrix, _("Value:"), opts=LAYOUT_CENTER_Y|LAYOUT_LEFT)
  367.         valuetf = FXTextField(matrix, 20)
  368.         f = FXHorizontalFrame(frame)
  369.         FXButton(f, _("&Ok"), None, dialog, FXDialogBox.ID_ACCEPT,FRAME_RAISED|FRAME_THICK|LAYOUT_CENTER_X|LAYOUT_CENTER_Y)
  370.         FXButton(f, _("&Cancel"), None, dialog, FXDialogBox.ID_CANCEL,FRAME_RAISED|FRAME_THICK|LAYOUT_CENTER_X|LAYOUT_CENTER_Y)
  371.         if dialog.execute():
  372.             name = string.lower(string.strip(nametf.getText()))
  373.             if not name:
  374.                 error(_("Empty attribute name"))
  375.             return 1
  376.             if self.rule.attrs.has_key(name):
  377.                 error(_("Duplicate attribute name"))
  378.                 return 1
  379.             try:
  380.                 import re
  381.                 value = string.strip(valuetf.getText())
  382.                 value = re.compile(value)
  383.             except:
  384.                 import sys
  385.                 error(_("Invalid regex %s: %s") % (value,sys.exc_info()[1]))
  386.                 return 1
  387.             self.rule.attrs[name] = value
  388.             self.getApp().dirty = 1
  389.             self.iconlist.appendItem(name+"\t"+value.pattern)
  390.             debug("Added rule attribute")
  391.         return 1
  392.  
  393.     def onCmdAttributeEdit(self, sender, sel, ptr):
  394.         index = self.iconlist.getCurrentItem()
  395.         if index < 0: return 1
  396.         item = self.iconlist.retrieveItem(index)
  397.         if not item.isSelected(): return 1
  398.         name,value = string.split(item.getText(), '\t')
  399.         dialog = FXDialogBox(self, _("Edit Attribute"),DECOR_TITLE|DECOR_BORDER)
  400.         frame = FXVerticalFrame(dialog, LAYOUT_SIDE_TOP|FRAME_NONE|LAYOUT_FILL_X|LAYOUT_FILL_Y|PACK_UNIFORM_WIDTH)
  401.         matrix = FXMatrix(frame, 2, MATRIX_BY_COLUMNS)
  402.         FXLabel(matrix, _("New name:"), opts=LAYOUT_CENTER_Y|LAYOUT_LEFT)
  403.         nametf = FXTextField(matrix, 20)
  404.         nametf.setText(name)
  405.         FXLabel(matrix, _("New value:"), opts=LAYOUT_CENTER_Y|LAYOUT_LEFT)
  406.         valuetf = FXTextField(matrix, 20)
  407.         valuetf.setText(value)
  408.         f = FXHorizontalFrame(frame)
  409.         FXButton(f, _("&Ok"), None, dialog, FXDialogBox.ID_ACCEPT,FRAME_RAISED|FRAME_THICK|LAYOUT_CENTER_X|LAYOUT_CENTER_Y)
  410.         FXButton(f, _("&Cancel"), None, dialog, FXDialogBox.ID_CANCEL,FRAME_RAISED|FRAME_THICK|LAYOUT_CENTER_X|LAYOUT_CENTER_Y)
  411.         if dialog.execute():
  412.             newname = string.lower(string.strip(nametf.getText()))
  413.             try:
  414.                 import re
  415.                 value = string.strip(valuetf.getText())
  416.                 value = re.compile(value)
  417.             except:
  418.                 import sys
  419.                 error(_("Invalid regex %s: %s")%(value,sys.exc_info()[1]))
  420.                 return 1
  421.             del self.rule.attrs[name]
  422.             self.rule.attrs[newname] = value
  423.             self.getApp().dirty = 1
  424.             self.iconlist.replaceItem(index, newname+"\t"+value.pattern)
  425.             debug("Changed rule attribute")
  426.         return 1
  427.  
  428.     def onCmdAttributeRemove(self, sender, sel, ptr):
  429.         index = self.iconlist.getCurrentItem()
  430.         if index < 0: return 1
  431.         item = self.iconlist.retrieveItem(index)
  432.         if not item.isSelected(): return 1
  433.         name,value = string.split(item.getText(), '\t')
  434.         del self.rule.attrs[name]
  435.         self.getApp().dirty = 1
  436.         self.iconlist.removeItem(index)
  437.         debug("Removed rule attribute")
  438.         return 1
  439.  
  440.     def onCmdReplaceValue(self, sender, sel, ptr):
  441.         self.rule.replace[1] = sender.getText()
  442.         self.getApp().dirty = 1
  443.         debug("Changed rule replace value")
  444.         return 1
  445.  
  446.  
  447.  
  448. class FXAllowRuleFrame(FXRuleFrame):
  449.     """display all variables found in an AllowRule"""
  450.     (ID_SCHEME,
  451.      ID_HOST,
  452.      ID_PORT,
  453.      ID_PATH,
  454.      ID_PARAMETERS,
  455.      ID_QUERY,
  456.      ID_FRAGMENT,
  457.      ID_LAST,
  458.     ) = range(FXRuleFrame.ID_LAST, FXRuleFrame.ID_LAST+8)
  459.  
  460.     def __init__(self, parent, rule, index):
  461.         FXRuleFrame.__init__(self, parent, rule, index)
  462.         FXMAPFUNC(self,SEL_COMMAND,FXAllowRuleFrame.ID_SCHEME,FXAllowRuleFrame.onCmdScheme)
  463.         FXMAPFUNC(self,SEL_COMMAND,FXAllowRuleFrame.ID_HOST,FXAllowRuleFrame.onCmdHost)
  464.         FXMAPFUNC(self,SEL_COMMAND,FXAllowRuleFrame.ID_PORT,FXAllowRuleFrame.onCmdPort)
  465.         FXMAPFUNC(self,SEL_COMMAND,FXAllowRuleFrame.ID_PATH,FXAllowRuleFrame.onCmdPath)
  466.         FXMAPFUNC(self,SEL_COMMAND,FXAllowRuleFrame.ID_PARAMETERS,FXAllowRuleFrame.onCmdParameters)
  467.         FXMAPFUNC(self,SEL_COMMAND,FXAllowRuleFrame.ID_QUERY,FXAllowRuleFrame.onCmdQuery)
  468.         FXMAPFUNC(self,SEL_COMMAND,FXAllowRuleFrame.ID_FRAGMENT,FXAllowRuleFrame.onCmdFragment)
  469.         self.matrix = FXMatrix(self, 2, MATRIX_BY_COLUMNS)
  470.         FXLabel(self.matrix, _("URL Scheme:\tRegular expression to match the URL scheme"), opts=LAYOUT_CENTER_Y|LAYOUT_LEFT)
  471.         tf = FXTextField(self.matrix, 15, self, FXAllowRuleFrame.ID_SCHEME)
  472.         tf.setText(self.rule.scheme)
  473.         FXLabel(self.matrix, _("URL Host:\tRegular expression to match the host"), opts=LAYOUT_CENTER_Y|LAYOUT_LEFT)
  474.         tf = FXTextField(self.matrix, 15, self, FXAllowRuleFrame.ID_HOST)
  475.         tf.setText(self.rule.host)
  476.         FXLabel(self.matrix, _("URL Port:\tRegular expression to match the port"), opts=LAYOUT_CENTER_Y|LAYOUT_LEFT)
  477.         tf = FXTextField(self.matrix, 15, self, FXAllowRuleFrame.ID_PORT)
  478.         tf.setText(self.rule.port)
  479.         FXLabel(self.matrix, _("URL Path:\tRegular expression to match the path"), opts=LAYOUT_CENTER_Y|LAYOUT_LEFT)
  480.         tf = FXTextField(self.matrix, 15, self, FXAllowRuleFrame.ID_PATH)
  481.         tf.setText(self.rule.path)
  482.         FXLabel(self.matrix, _("URL Parameters:\tRegular expression to match the parameters"), opts=LAYOUT_CENTER_Y|LAYOUT_LEFT)
  483.         tf = FXTextField(self.matrix, 15, self, FXAllowRuleFrame.ID_PARAMETERS)
  484.         tf.setText(self.rule.parameters)
  485.         FXLabel(self.matrix, _("URL Query:\tRegular expression to match the query"), opts=LAYOUT_CENTER_Y|LAYOUT_LEFT)
  486.         tf = FXTextField(self.matrix, 15, self, FXAllowRuleFrame.ID_QUERY)
  487.         tf.setText(self.rule.query)
  488.         FXLabel(self.matrix, _("URL Fragment:\tRegular expression to match the fragment"), opts=LAYOUT_CENTER_Y|LAYOUT_LEFT)
  489.         tf = FXTextField(self.matrix, 15, self, FXAllowRuleFrame.ID_FRAGMENT)
  490.         tf.setText(self.rule.fragment)
  491.  
  492.  
  493.     def onCmdScheme(self, sender, sel, ptr):
  494.         self.rule.scheme = string.strip(sender.getText())
  495.         self.getApp().dirty = 1
  496.         debug("Changed rule scheme")
  497.         return 1
  498.  
  499.     def onCmdHost(self, sender, sel, ptr):
  500.         self.rule.host = string.strip(sender.getText())
  501.         self.getApp().dirty = 1
  502.         debug("Changed rule host")
  503.         return 1
  504.  
  505.     def onCmdPort(self, sender, sel, ptr):
  506.         self.rule.host = string.strip(sender.getText())
  507.         self.getApp().dirty = 1
  508.         debug("Changed rule port")
  509.         return 1
  510.  
  511.     def onCmdPath(self, sender, sel, ptr):
  512.         self.rule.path = string.strip(sender.getText())
  513.         self.getApp().dirty = 1
  514.         debug("Changed rule path")
  515.         return 1
  516.  
  517.     def onCmdParameters(self, sender, sel, ptr):
  518.         self.rule.parameters = string.strip(sender.getText())
  519.         self.getApp().dirty = 1
  520.         debug("Changed rule parameters")
  521.         return 1
  522.  
  523.     def onCmdQuery(self, sender, sel, ptr):
  524.         self.rule.query = string.strip(sender.getText())
  525.         self.getApp().dirty = 1
  526.         debug("Changed rule query")
  527.         return 1
  528.  
  529.     def onCmdFragment(self, sender, sel, ptr):
  530.         self.rule.fragment = string.strip(sender.getText())
  531.         self.getApp().dirty = 1
  532.         debug("Changed rule fragment")
  533.         return 1
  534.  
  535.  
  536.  
  537. class FXBlockRuleFrame(FXAllowRuleFrame):
  538.     """display all variables found in a BlockRule"""
  539.     ID_URL = FXAllowRuleFrame.ID_LAST
  540.  
  541.     def __init__(self, parent, rule, index):
  542.         FXAllowRuleFrame.__init__(self, parent, rule, index)
  543.         FXMAPFUNC(self,SEL_COMMAND,FXBlockRuleFrame.ID_URL,FXBlockRuleFrame.onCmdUrl)
  544.         FXLabel(self.matrix, _("Blocked URL\tThe URL we want to show instead"), opts=LAYOUT_CENTER_Y|LAYOUT_LEFT)
  545.         tf = FXTextField(self.matrix, 15, self, FXBlockRuleFrame.ID_URL)
  546.         tf.setText(self.rule.fragment)
  547.  
  548.     def onCmdUrl(self, sender, sel, ptr):
  549.         self.rule.url = string.strip(sender.getText())
  550.         self.getApp().dirty = 1
  551.         debug("Changed rule blocked url")
  552.         return 1
  553.  
  554.  
  555.  
  556. class FXHeaderRuleFrame(FXRuleFrame):
  557.     """display all variables found in a HeaderRule"""
  558.     (ID_NAME,
  559.      ID_VALUE,
  560.     ) = range(FXRuleFrame.ID_LAST, FXRuleFrame.ID_LAST+2)
  561.  
  562.     def __init__(self, parent, rule, index):
  563.         FXRuleFrame.__init__(self, parent, rule, index)
  564.         FXMAPFUNC(self,SEL_COMMAND,FXHeaderRuleFrame.ID_NAME,FXHeaderRuleFrame.onCmdName)
  565.         FXMAPFUNC(self,SEL_COMMAND,FXHeaderRuleFrame.ID_VALUE,FXHeaderRuleFrame.onCmdValue)
  566.         matrix = FXMatrix(self, 2, MATRIX_BY_COLUMNS)
  567.         FXLabel(matrix, _("Header name:\tRegular expression to match the header name"), opts=LAYOUT_CENTER_Y|LAYOUT_LEFT)
  568.         tf = FXTextField(matrix, 15, self, FXHeaderRuleFrame.ID_NAME)
  569.         tf.setText(self.rule.name)
  570.         FXLabel(matrix, _("Header value:\tHeader value (empty means delete)"), opts=LAYOUT_CENTER_Y|LAYOUT_LEFT)
  571.         tf = FXTextField(matrix, 15, self, FXHeaderRuleFrame.ID_VALUE)
  572.         tf.setText(self.rule.value)
  573.  
  574.     def onCmdName(self, sender, sel, ptr):
  575.         self.rule.name = string.strip(sender.getText())
  576.         self.getApp().dirty = 1
  577.         debug("Changed rule header name")
  578.         return 1
  579.  
  580.     def onCmdValue(self, sender, sel, ptr):
  581.         self.rule.value = string.strip(sender.getText())
  582.         self.getApp().dirty = 1
  583.         debug("Changed rule header value")
  584.         return 1
  585.  
  586.  
  587.  
  588. class FXImageRuleFrame(FXRuleFrame):
  589.     """display all variables found in a ImageRule"""
  590.     (ID_WIDTH,
  591.      ID_HEIGHT,
  592.     ) = range(FXRuleFrame.ID_LAST, FXRuleFrame.ID_LAST+2)
  593.  
  594.     def __init__(self, parent, rule, index):
  595.         FXRuleFrame.__init__(self, parent, rule, index)
  596.         FXMAPFUNC(self,SEL_COMMAND,FXImageRuleFrame.ID_WIDTH,FXImageRuleFrame.onCmdWidth)
  597.         FXMAPFUNC(self,SEL_COMMAND,FXImageRuleFrame.ID_HEIGHT,FXImageRuleFrame.onCmdHeight)
  598.         matrix = FXMatrix(self, 2, MATRIX_BY_COLUMNS)
  599.         FXLabel(matrix, _("Image width:"), opts=LAYOUT_CENTER_Y|LAYOUT_LEFT)
  600.         t = FXSpinner(matrix, 4, self, FXImageRuleFrame.ID_WIDTH, SPIN_NORMAL|FRAME_SUNKEN|FRAME_THICK)
  601.         t.setRange(0,65535)
  602.         t.setValue(self.rule.width)
  603.         FXLabel(matrix, _("Image height:"), opts=LAYOUT_CENTER_Y|LAYOUT_LEFT)
  604.         t = FXSpinner(matrix, 4, self, FXImageRuleFrame.ID_HEIGHT, SPIN_NORMAL|FRAME_SUNKEN|FRAME_THICK)
  605.         t.setRange(0,65535)
  606.         t.setValue(self.rule.height)
  607.  
  608.     def onCmdWidth(self, sender, sel, ptr):
  609.         self.rule.width = sender.getValue()
  610.         self.getApp().dirty = 1
  611.         debug("Changed rule image width")
  612.         return 1
  613.  
  614.     def onCmdHeight(self, sender, sel, ptr):
  615.         self.rule.height = sender.getValue()
  616.         self.getApp().dirty = 1
  617.         debug("Changed rule image height")
  618.         return 1
  619.  
  620.  
  621.  
  622. class FXNocommentRuleFrame(FXRuleFrame):
  623.     """display all variables found in a NocommentRule"""
  624.     pass
  625.  
  626.  
  627. class FXFilterRulesFrame(FXRuleFrame):
  628.     """display all variables found in a FilterRules rule"""
  629.     (ID_LANG,
  630.      ID_FILENAME,
  631.     ) = range(FXRuleFrame.ID_LAST, FXRuleFrame.ID_LAST+2)
  632.  
  633.     def __init__(self, parent, rule, index):
  634.         FXRuleFrame.__init__(self, parent, rule, index)
  635.         FXMAPFUNC(self,SEL_COMMAND,FXFilterRulesFrame.ID_FILENAME,FXFilterRulesFrame.onCmdFilename)
  636.         FXMAPFUNC(self,SEL_COMMAND,FXFilterRulesFrame.ID_LANG,FXFilterRulesFrame.onCmdLang)
  637.         matrix = FXMatrix(self, 2, MATRIX_BY_COLUMNS)
  638.         FXLabel(matrix, _("Filename")+":\t"+TipText['Filename'], opts=LAYOUT_CENTER_Y|LAYOUT_LEFT)
  639.         t = FXTextField(matrix, 22, self, FXFilterRulesFrame.ID_FILENAME)
  640.         t.setText(self.rule.filename)
  641.         t.setEditable(0)
  642.         FXLabel(matrix, _("Language")+":\t"+TipText['Language'], opts=LAYOUT_CENTER_Y|LAYOUT_LEFT)
  643.         t = FXComboBox(matrix,5,3,self, self.ID_LANG,opts=COMBOBOX_INSERT_LAST|FRAME_SUNKEN|FRAME_THICK|LAYOUT_SIDE_TOP)
  644.         t.appendItem("All")
  645.         t.appendItem("Perl")
  646.         t.appendItem("Python")
  647.         t.setEditable(0)
  648.         t.setCurrentItem(lang_num(self.rule.lang))
  649.  
  650.     def onCmdFilename(self, sender, sel, ptr):
  651.         filename = string.strip(sender.getText())
  652.         if filename:
  653.             self.rule.filename = filename
  654.             self.getApp().dirty = 1
  655.             debug("Changed rule filename")
  656.         else:
  657.             error(_("empty filename"))
  658.         return 1
  659.  
  660.     def onCmdLang(self, sender, sel, ptr):
  661.         self.rule.lang = num_lang(sender.getCurrentItem())
  662.         self.getApp().dirty = 1
  663.         debug("Changed rule language")
  664.         return 1
  665.  
  666.  
  667.  
  668. class ConfWindow(FXMainWindow):
  669.     """The main window holds all data and windows to display"""
  670.     (ID_PORT,
  671.      ID_DEBUGLEVEL,
  672.      ID_FILTERMODULE,
  673.      ID_PARENTPROXY,
  674.      ID_PARENTPROXYPORT,
  675.      ID_ACCEPT,
  676.      ID_CANCEL,
  677.      ID_APPLY,
  678.      ID_BUFFERSIZE,
  679.      ID_TIMEOUT,
  680.      ID_OBFUSCATEIP,
  681.      ID_LOGFILE,
  682.      ID_ABOUT,
  683.      ID_HELP,
  684.      ID_TITLE,
  685.      ID_FILTER,
  686.      ID_NEWFOLDER,
  687.      ID_NEWFILTER,
  688.      ID_REMOVE,
  689.      ID_PROXYSTART,
  690.      ID_PROXYSTOP,
  691.      ID_CONFUPDATE,
  692.      ID_PROXYRESTART,
  693.      ID_PROXYRELOAD,
  694.      ID_PROXYSTATUS,
  695.     ) = range(FXMainWindow.ID_LAST, FXMainWindow.ID_LAST+25)
  696.  
  697.  
  698.     def __init__(self, app):
  699.     FXMainWindow.__init__(self, app, "WebCleanerConf",w=640,h=500)
  700.         self.loadIcons(app)
  701.         self.readconfig()
  702.         self.eventMap()
  703.         FXTooltip(app, TOOLTIP_VARIABLE, 0, 0)
  704.         FXStatusbar(self, LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X|STATUSBAR_WITH_DRAGCORNER)
  705.         # About dialog
  706.         self.about = FXMessageBox(self, _("About WebCleaner"),"WebCleanerConf %s\n\n(C) 2000,2001 by %s" % (WebCleanerConf.version,WebCleanerConf.author), self.getIcon(),MBOX_OK)
  707.         self.help = FXMessageBox(self, _("WebCleanerConf Help"), HelpText, None, MBOX_OK)
  708.         self.removeDialog = FXMessageBox(self, _("Remove Folder"), RemoveText, None, MBOX_OK)
  709.         # main frame
  710.         mainframe = FXVerticalFrame(self, LAYOUT_FILL_X|LAYOUT_FILL_Y)
  711.         tabbook = FXTabBook(mainframe, None, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y)
  712.         self.proxySettings(tabbook)
  713.         self.filterSettings(tabbook)
  714.         # Buttons
  715.         frame = FXHorizontalFrame(mainframe, LAYOUT_FILL_X)
  716.         FXButton(frame, _(" &Ok "), None, self, self.ID_ACCEPT)
  717.         FXButton(frame, _("&Cancel"), None, self, self.ID_CANCEL)
  718.         FXButton(frame, _("A&pply"), None, self, self.ID_APPLY)
  719.         FXButton(frame, _("A&bout"), None, self, self.ID_ABOUT, opts=FRAME_RAISED|FRAME_THICK|LAYOUT_RIGHT)
  720.         FXButton(frame, _("&Help"), None, self, self.ID_HELP, opts=FRAME_RAISED|FRAME_THICK|LAYOUT_RIGHT)
  721.         daemonmenu = FXMenuPane(self)
  722.         FXMenuCommand(daemonmenu, "Start", None, self, self.ID_PROXYSTART)
  723.         FXMenuCommand(daemonmenu, "Stop", None, self, self.ID_PROXYSTOP)
  724.         FXMenuCommand(daemonmenu, "Restart", None, self, self.ID_PROXYRESTART)
  725.         FXMenuCommand(daemonmenu, "Reload", None, self, self.ID_PROXYRELOAD)
  726.         FXMenuCommand(daemonmenu, "Status", None, self, self.ID_PROXYSTATUS)
  727.         FXMenuButton(frame, "Proxy", None, daemonmenu, MENUBUTTON_ATTACH_BOTH|MENUBUTTON_DOWN|JUSTIFY_HZ_APART|LAYOUT_TOP|FRAME_RAISED|FRAME_THICK|ICON_AFTER_TEXT)
  728.         FXButton(frame, "Update...", None, self, self.ID_CONFUPDATE)
  729.  
  730.  
  731.     def create(self):
  732.         """create the main window and show myself on the screen"""
  733.     FXMainWindow.create(self)
  734.     self.show()
  735.  
  736.  
  737.     def loadIcons(self, app):
  738.         """load the needed icons"""
  739.         self.setIcon(loadIcon(app, 'iconbig.gif'))
  740.         self.icon_open = loadIcon(app, 'minifolderopen.gif')
  741.         self.icon_closed = loadIcon(app, 'minifolder.gif')
  742.         self.icon_doc = loadIcon(app, 'minidoc.gif')
  743.  
  744.  
  745.     def eventMap(self):
  746.         """attach all events to (member) functions"""
  747.         FXMAPFUNC(self,SEL_COMMAND,ConfWindow.ID_ACCEPT,ConfWindow.onCmdAccept)
  748.         FXMAPFUNC(self,SEL_COMMAND,ConfWindow.ID_CANCEL,ConfWindow.onCmdCancel)
  749.         FXMAPFUNC(self,SEL_COMMAND,ConfWindow.ID_APPLY,ConfWindow.onCmdApply)
  750.         FXMAPFUNC(self,SEL_UPDATE,ConfWindow.ID_APPLY,ConfWindow.onUpdApply)
  751.         FXMAPFUNC(self,SEL_COMMAND,ConfWindow.ID_ABOUT,ConfWindow.onCmdAbout)
  752.         FXMAPFUNC(self,SEL_COMMAND,ConfWindow.ID_BUFFERSIZE,ConfWindow.onCmdBuffersize)
  753.         FXMAPFUNC(self,SEL_COMMAND,ConfWindow.ID_TIMEOUT,ConfWindow.onCmdTimeout)
  754.         FXMAPFUNC(self,SEL_COMMAND,ConfWindow.ID_OBFUSCATEIP,ConfWindow.onCmdObfuscateIp)
  755.         FXMAPFUNC(self,SEL_COMMAND,ConfWindow.ID_PORT,ConfWindow.onCmdPort)
  756.         FXMAPFUNC(self,SEL_COMMAND,ConfWindow.ID_DEBUGLEVEL,ConfWindow.onCmdDebuglevel)
  757.         FXMAPFUNC(self,SEL_COMMAND,ConfWindow.ID_PARENTPROXY,ConfWindow.onCmdParentProxy)
  758.         FXMAPFUNC(self,SEL_COMMAND,ConfWindow.ID_PARENTPROXYPORT,ConfWindow.onCmdParentProxyPort)
  759.         FXMAPFUNC(self,SEL_COMMAND,ConfWindow.ID_LOGFILE,ConfWindow.onCmdLogfile)
  760.         FXMAPFUNC(self,SEL_COMMAND,ConfWindow.ID_FILTERMODULE,ConfWindow.onCmdFilterModule)
  761.         FXMAPFUNC(self,SEL_COMMAND,ConfWindow.ID_FILTER,ConfWindow.onCmdFilter)
  762.         FXMAPFUNC(self,SEL_COMMAND,ConfWindow.ID_HELP,ConfWindow.onCmdHelp)
  763.         FXMAPFUNC(self,SEL_COMMAND,ConfWindow.ID_NEWFOLDER,ConfWindow.onCmdNewFolder)
  764.         FXMAPFUNC(self,SEL_COMMAND,ConfWindow.ID_NEWFILTER,ConfWindow.onCmdNewFilter)
  765.         FXMAPFUNC(self,SEL_COMMAND,ConfWindow.ID_REMOVE,ConfWindow.onCmdRemove)
  766.         FXMAPFUNC(self,SEL_COMMAND,ConfWindow.ID_TITLE,ConfWindow.onCmdTitle)
  767.         FXMAPFUNC(self,SEL_COMMAND,ConfWindow.ID_PROXYSTART,ConfWindow.onCmdProxyStart)
  768.         FXMAPFUNC(self,SEL_COMMAND,ConfWindow.ID_PROXYSTOP,ConfWindow.onCmdProxyStop)
  769.         FXMAPFUNC(self,SEL_COMMAND,ConfWindow.ID_PROXYRESTART,ConfWindow.onCmdProxyRestart)
  770.         FXMAPFUNC(self,SEL_COMMAND,ConfWindow.ID_PROXYRELOAD,ConfWindow.onCmdProxyReload)
  771.         FXMAPFUNC(self,SEL_COMMAND,ConfWindow.ID_PROXYSTATUS,ConfWindow.onCmdProxyStatus)
  772.         FXMAPFUNC(self,SEL_COMMAND,ConfWindow.ID_CONFUPDATE,ConfWindow.onCmdConfUpdate)
  773.  
  774.  
  775.     def proxySettings(self, tabbook):
  776.         """generate the proxy setting tab"""
  777.         FXTabItem(tabbook, _("P&roxy Settings"), None)
  778.         proxy = FXVerticalFrame(tabbook, FRAME_THICK|FRAME_RAISED)
  779.         basics = FXGroupBox(proxy, _("Basic Values"), FRAME_RIDGE|LAYOUT_LEFT|LAYOUT_TOP|LAYOUT_FILL_X|LAYOUT_FILL_Y,0,0,0,0,5,5,5,5)
  780.         matrix = FXMatrix(basics, 2, MATRIX_BY_COLUMNS)
  781.         FXLabel(matrix, _("Version"))
  782.         version = FXLabel(matrix, WebCleanerConf.version, opts=LAYOUT_CENTER_Y|LAYOUT_LEFT)
  783.         FXLabel(matrix, _("Port")+"\t"+TipText["Port"], opts=LAYOUT_CENTER_Y|LAYOUT_LEFT)
  784.         widget = FXSpinner(matrix, 4, self, self.ID_PORT, SPIN_NORMAL|FRAME_SUNKEN|FRAME_THICK)
  785.         widget.setRange(0,65535)
  786.         widget.setValue(self.port)
  787.         FXLabel(matrix, _("Logfile")+"\t"+TipText["Logfile"], opts=LAYOUT_CENTER_Y|LAYOUT_LEFT)
  788.         widget = FXTextField(matrix, 10, self, self.ID_LOGFILE)
  789.         widget.setText(self.logfile)
  790.         FXLabel(matrix, _("Buffer size")+"\t"+TipText["Buffer size"], opts=LAYOUT_CENTER_Y|LAYOUT_LEFT)
  791.         widget = FXSpinner(matrix, 3, self, self.ID_BUFFERSIZE, SPIN_NORMAL|FRAME_SUNKEN|FRAME_THICK)
  792.         widget.setRange(512,8192)
  793.         widget.setValue(self.buffersize)
  794.         FXLabel(matrix, _("Timeout")+"\t"+TipText["Timeout"], opts=LAYOUT_CENTER_Y|LAYOUT_LEFT)
  795.         widget = FXSpinner(matrix, 3, self, self.ID_TIMEOUT, SPIN_NORMAL|FRAME_SUNKEN|FRAME_THICK)
  796.         widget.setRange(1,600)
  797.         widget.setValue(self.timeout)
  798.         FXLabel(matrix, _("Obfuscate IP")+"\t"+TipText["Obfuscate IP"], opts=LAYOUT_CENTER_Y|LAYOUT_LEFT)
  799.         widget = FXCheckButton(matrix, None, self, self.ID_OBFUSCATEIP, opts=ICON_BEFORE_TEXT|LAYOUT_SIDE_TOP)
  800.         widget.setCheck(self.obfuscateip)
  801.         FXLabel(matrix, _("Debug level")+"\t"+TipText["Debug level"])
  802.         cols=0
  803.         d = FXComboBox(matrix,0,4,self, self.ID_DEBUGLEVEL,opts=COMBOBOX_INSERT_LAST|FRAME_SUNKEN|FRAME_THICK|LAYOUT_SIDE_TOP)
  804.         for text in ["No debugging","Bring it on","Hurt me plenty","Nightmare"]:
  805.             text = _(text)
  806.             cols = max(len(text), cols)
  807.             d.appendItem(text)
  808.         d.setEditable(0)
  809.         # subtract 3 because acolumn is wider than text character
  810.         d.setNumColumns(cols-3) 
  811.         d.setCurrentItem(self.debuglevel)
  812.         frame = FXHorizontalFrame(proxy, LAYOUT_FILL_X|LAYOUT_FILL_Y|LAYOUT_SIDE_TOP)
  813.         filters = FXGroupBox(frame, _("Filter Modules"), FRAME_RIDGE|LAYOUT_LEFT|LAYOUT_TOP|LAYOUT_FILL_X|LAYOUT_FILL_Y,0,0,0,0,5,5,5,5)
  814.         hframe = FXVerticalFrame(filters,LAYOUT_SIDE_TOP)
  815.         for m in self.modules.keys():
  816.             cb = FXCheckButton(hframe, m+"\t"+TipText[m], self, self.ID_FILTERMODULE,opts=ICON_BEFORE_TEXT|LAYOUT_SIDE_TOP)
  817.             if self.modules[m]:
  818.             cb.setCheck()
  819.         groupbox = FXGroupBox(frame, _("Parent Proxy"), FRAME_RIDGE|LAYOUT_LEFT|LAYOUT_TOP|LAYOUT_FILL_X|LAYOUT_FILL_Y,0,0,0,0,5,5,5,5)
  820.         matrix = FXMatrix(groupbox, 2, MATRIX_BY_COLUMNS)
  821.         FXLabel(matrix, _("Host")+"\t"+TipText["Parent Proxy"], opts=LAYOUT_CENTER_Y|LAYOUT_LEFT)
  822.         parentproxy = FXTextField(matrix, 16, self, self.ID_PARENTPROXY)
  823.         parentproxy.setText(self.parentproxy)
  824.         FXLabel(matrix, _("Port")+"\t"+TipText["Parent Proxy Port"], opts=LAYOUT_CENTER_Y|LAYOUT_LEFT)
  825.         parentport = FXSpinner(matrix, 4, self, self.ID_PARENTPROXYPORT, SPIN_NORMAL|FRAME_SUNKEN|FRAME_THICK)
  826.         parentport.setRange(0,65535)
  827.         parentport.setValue(self.parentproxyport)
  828.         # proxySettings
  829.  
  830.  
  831.     def filterSettings(self, tabbook):
  832.         FXTabItem(tabbook, _("&Filter Settings"), None)
  833.         frame = FXHorizontalFrame(tabbook, FRAME_THICK|FRAME_RAISED|LAYOUT_FILL_X|LAYOUT_FILL_Y)
  834.         splitter = FXSplitter(frame, FRAME_THICK|FRAME_RAISED|LAYOUT_FILL_X|LAYOUT_FILL_Y)
  835.         treeframe = FXVerticalFrame(splitter, FRAME_SUNKEN|FRAME_THICK|LAYOUT_FILL_X|LAYOUT_FILL_Y, 0,0,250,0, 0,0,0,0, 0,0)
  836.         self.tree = FXTreeList(treeframe, 0, self, self.ID_FILTER, opts=LAYOUT_FILL_X|LAYOUT_FILL_Y)
  837.         self.tree.setListStyle(TREELIST_SHOWS_LINES|TREELIST_SHOWS_BOXES|TREELIST_SINGLESELECT)
  838.         f = FXHorizontalFrame(treeframe, LAYOUT_FILL_X)
  839.         addmenu = FXMenuPane(self)
  840.         FXMenuCommand(addmenu, _("New Folder\t\tCreate a new folder."), None, self, self.ID_NEWFOLDER, opts=MENU_DEFAULT)
  841.         # Make new filter popup menu
  842.         filtermenu = FXMenuPane(self)
  843.         FXMenuCommand(filtermenu, "Allow", None, self, self.ID_NEWFILTER)
  844.         FXMenuCommand(filtermenu, "Block", None, self, self.ID_NEWFILTER)
  845.         FXMenuCommand(filtermenu, "Header", None, self, self.ID_NEWFILTER)
  846.         FXMenuCommand(filtermenu, "Image", None, self, self.ID_NEWFILTER)
  847.         FXMenuCommand(filtermenu, "Nocomments", None, self, self.ID_NEWFILTER)
  848.         FXMenuCommand(filtermenu, "Rewrite", None, self, self.ID_NEWFILTER)
  849.         FXMenuCascade(addmenu, _("New Filter"), None, filtermenu)
  850.         FXMenuButton(f, _("Add"), None, addmenu, MENUBUTTON_ATTACH_BOTH|MENUBUTTON_DOWN|JUSTIFY_HZ_APART|LAYOUT_TOP|FRAME_RAISED|FRAME_THICK|ICON_AFTER_TEXT)
  851.         FXButton(f, _("Remove"), None, self, self.ID_REMOVE)
  852.         self.filterswitcher = FXSwitcher(splitter, FRAME_SUNKEN|FRAME_THICK|LAYOUT_FILL_X|LAYOUT_FILL_Y)
  853.         topItem = FXTreeItem('Filter', self.icon_open, self.icon_closed)
  854.         topItem.setData(0)
  855.         f=FXHorizontalFrame(self.filterswitcher)
  856.         FXLabel(f, _("All filters"))
  857.         self.topmost = self.tree.addItemLast(None, topItem)
  858.         self.tree.expandTree(self.topmost)
  859.         self.factory = FXRuleFrameFactory(self.filterswitcher)
  860.         for f in self.filters:
  861.             item = FXTreeItem(f.title, self.icon_open, self.icon_closed)
  862.             item.setData(f.fromFactory(self.factory).rule.index)
  863.             branch = self.tree.addItemLast(self.topmost, item)
  864.             for r in f.rules:
  865.                 item = FXTreeItem(r.title, self.icon_doc, self.icon_doc)
  866.                 item.setData(r.fromFactory(self.factory).rule.index)
  867.                 self.tree.addItemLast(branch, item)
  868.  
  869.  
  870.     def newfilterid(self):
  871.         i=0
  872.         while 1:
  873.             if self.filterids.has_key(i):
  874.                 i += 1
  875.             else:
  876.                 break
  877.         return i
  878.  
  879.     def onCmdNewFolder(self, sender, sel, ptr):
  880.         debug("new folder")
  881.         rule = FilterRules("No title","",0,0,tempfile.mktemp()+".zap")
  882.         rule.timestamp = time.time()
  883.         rule.ruleid = self.newfilterid()
  884.         self.filters.append(rule)
  885.         item = FXTreeItem(rule.title, self.icon_open, self.icon_closed)
  886.         frame = rule.fromFactory(self.factory)
  887.         frame.create()
  888.         item.setData(rule.index)
  889.         self.tree.addItemLast(self.topmost, item)
  890.         self.getApp().dirty = 1
  891.         return 1
  892.  
  893.     def onCmdNewFilter(self, sender, sel, ptr):
  894.         debug("new filter")
  895.         if not self.filters: return 1
  896.         folder = self.tree.getCurrentItem()
  897.         debug("folder index %d" % folder.getData())
  898.         if folder.getData()==0:
  899.             folder = folder.getBelow()
  900.         elif not self.searchFilter(folder.getData()):
  901.             folder = folder.getParent()
  902.         debug("folder index %d" % folder.getData())
  903.         self.tree.expandTree(folder)
  904.         rule = GetRuleFromName(sender.getText())
  905.         rule.parent = self.searchFilter(folder.getData())
  906.         rule.timestamp = time.time()
  907.         rule.ruleid = rule.parent.newid()
  908.         rule.parent.timestamp = rule.timestamp
  909.         item = FXTreeItem(rule.title, self.icon_doc, self.icon_doc)
  910.         frame = rule.fromFactory(self.factory)
  911.         frame.create()
  912.         item.setData(rule.index)
  913.         rule.parent.append_rule(rule)
  914.         self.tree.addItemLast(folder, item)
  915.         self.getApp().dirty = 1
  916.         return 1
  917.  
  918.     def searchFilter(self, index):
  919.         for f in self.filters:
  920.             if f.index == index:
  921.                 return f
  922.  
  923.     def onCmdTitle(self, sender, sel, ptr):
  924.         item = self.tree.getCurrentItem()
  925.         if item.isSelected():
  926.             self.tree.setItemText(item, sender.getText())
  927.             debug("updated tree item")
  928.         return 1
  929.  
  930.     def onCmdRemove(self, sender, sel, ptr):
  931.         item = self.tree.getCurrentItem()
  932.         if item.isSelected():
  933.             if self.removeRule(item.getData()):
  934.                 self.tree.removeItem(item)
  935.                 self.filterswitcher.setCurrent(0)
  936.                 self.getApp().dirty = 1
  937.                 debug("removed filter")
  938.             else:
  939.                 self.removeDialog.execute()
  940.         else:
  941.             error(_("no filter item selected"))
  942.         return 1
  943.  
  944.     def onCmdAccept(self, sender, sel, ptr):
  945.         debug("Accept")
  946.         self.writeconfig()
  947.         self.getApp().exit(0)
  948.         return 1
  949.  
  950.     def onCmdCancel(self, sender, sel, ptr):
  951.         debug("Cancel")
  952.         self.getApp().exit(0)
  953.         return 1
  954.  
  955.     def onUpdApply(self, sender, sel, ptr):
  956.         if self.getApp().dirty:
  957.             sender.enable()
  958.         else:
  959.             sender.disable()
  960.         return 1
  961.  
  962.     def onCmdApply(self, sender, sel, ptr):
  963.         debug("Apply")
  964.         self.writeconfig()
  965.         return 1
  966.  
  967.     def onCmdAbout(self, sender, sel, ptr):
  968.         debug("About")
  969.         self.doShow(self.about)
  970.         return 1
  971.  
  972.     def doShow(self, win):
  973.         win.execute(PLACEMENT_OWNER)
  974.  
  975.     def onCmdHelp(self, sender, sel, ptr):
  976.         debug("Help")
  977.         self.doShow(self.help)
  978.         return 1
  979.  
  980.     def onCmdPort(self, sender, sel, ptr):
  981.         self.port = sender.getValue()
  982.         self.getApp().dirty = 1
  983.         debug("Port=%d"%self.port)
  984.         return 1
  985.  
  986.     def onCmdDebuglevel(self, sender, sel, ptr):
  987.         self.debuglevel = sender.getCurrentItem()
  988.         self.getApp().dirty = 1
  989.         debug("Debuglevel=%d"%self.debuglevel)
  990.         return 1
  991.  
  992.     def onCmdBuffersize(self, sender, sel, ptr):
  993.         self.buffersize = sender.getValue()
  994.         self.getApp().dirty = 1
  995.         debug("Buffersize=%d" % self.buffersize)
  996.         return 1
  997.  
  998.     def onCmdTimeout(self, sender, sel, ptr):
  999.         self.timeout = sender.getValue()
  1000.         self.getApp().dirty = 1
  1001.         debug("Timeout=%d" % self.timeout)
  1002.         return 1
  1003.  
  1004.     def onCmdObfuscateIp(self, sender, sel, ptr):
  1005.         self.obfuscateip = sender.getCheck()
  1006.         self.getApp().dirty = 1
  1007.         debug("Obfuscateip=%d" % self.obfuscateip)
  1008.         return 1
  1009.  
  1010.     def onCmdParentProxy(self, sender, sel, ptr):
  1011.         self.parentproxy = sender.getText()
  1012.         self.getApp().dirty = 1
  1013.         debug("Parentproxy=%s"%self.parentproxy)
  1014.         return 1
  1015.  
  1016.     def onCmdParentProxyPort(self, sender, sel, ptr):
  1017.         self.parentproxyport = sender.getValue()
  1018.         self.getApp().dirty = 1
  1019.         debug("Parentproxyport=%d"%self.parentproxyport)
  1020.         return 1
  1021.  
  1022.     def onCmdLogfile(self, sender, sel, ptr):
  1023.         self.logfile = sender.getText()
  1024.         self.getApp().dirty = 1
  1025.         debug("Logfile=%s"%self.logfile)
  1026.         return 1
  1027.  
  1028.     def onCmdFilterModule(self, sender, sel, ptr):
  1029.         state = sender.getCheck()
  1030.         module = sender.getText()
  1031.         self.modules[module] = state
  1032.         self.getApp().dirty = 1
  1033.         debug("Filtermodule %s = %d" % (module, state))
  1034.         return 1
  1035.  
  1036.     def onCmdFilter(self, sender, sel, ptr):
  1037.         if not ptr.isSelected(): return 1
  1038.         index = ptr.getData()
  1039.         debug("tree item index %d" % index)
  1040.         if type(index) is IntType:
  1041.             self.filterswitcher.setCurrent(index)
  1042.         return 1
  1043.  
  1044.  
  1045.     def onCmdProxyStart(self, sender, sel, ptr):
  1046.         from webfilter import daemon,startfunc
  1047.         try:
  1048.             daemon.start(startfunc)
  1049.         except SystemExit:
  1050.             # parent does not exit
  1051.             pass
  1052.         debug("webcleaner start")
  1053.         return 1
  1054.  
  1055.  
  1056.     def onCmdProxyStop(self, sender, sel, ptr):
  1057.         from webfilter import daemon
  1058.         daemon.stop()
  1059.         debug("webcleaner stop")
  1060.         return 1
  1061.  
  1062.  
  1063.     def onCmdProxyRestart(self, sender, sel, ptr):
  1064.         from webfilter import daemon,startfunc
  1065.         try:
  1066.             daemon.restart(startfunc)
  1067.         except SystemExit:
  1068.             # parent does not exit
  1069.             pass
  1070.         debug("webcleaner restart")
  1071.         return 1
  1072.  
  1073.  
  1074.     def onCmdProxyReload(self, sender, sel, ptr):
  1075.         from webfilter import daemon
  1076.         daemon.reload()
  1077.         debug("webcleaner reload")
  1078.         return 1
  1079.  
  1080.  
  1081.     def onCmdProxyStatus(self, sender, sel, ptr):
  1082.         from webfilter import daemon
  1083.         dialog = FXMessageBox(self,_("Proxy Status"),daemon.status(),None,MBOX_OK)
  1084.         self.doShow(dialog)
  1085.         debug("webcleaner status")
  1086.         return 1
  1087.  
  1088.  
  1089.     def onCmdConfUpdate(self, sender, sel, ptr):
  1090.         """download files from http://webcleaner.sourceforge.net/zappers/
  1091.            and merge them into existing config"""
  1092.         # XXX remove when stuff is implemented
  1093.         dialog = FXMessageBox(self,_("Unimplemented"),_("Sorry, unimplemented"),None,MBOX_OK)
  1094.         self.doShow(dialog)
  1095.         return 1
  1096.         # base url for all files
  1097.         #url = "http://webcleaner.sourceforge.net/zappers/"
  1098.         url = "file:/home/calvin/temp/"
  1099.         import urllib
  1100.         try:
  1101.             data = urllib.urlopen(url+"oldtimestamps.txt").readlines()
  1102.             data = map(string.split, data)
  1103.             self.oldtimestamps = {}
  1104.             for ruleid,timestamp in data:
  1105.                 self.oldtimestamps[ruleid] = timestamp
  1106.             for file in urllib.urlopen(url+"list.txt").readlines():
  1107.                 filename, info = urllib.urlretrieve(url+file)
  1108.                 debug("merging "+file)
  1109.                 self.mergeFileData(filename, data)
  1110.         except IOError, msg:
  1111.             dialog = FXMessageBox(self,_("Update Error"),_("Update Error: %s") % msg,None,MBOX_OK)
  1112.             self.doShow(dialog)
  1113.         return 1
  1114.  
  1115.  
  1116.     def mergeFileData(self, filename):
  1117.         dom = get_dom(filename)
  1118.         attrs = get_dom_attrs(dom)
  1119.         # check filestamp: if they differ, merge; else do nothing
  1120.         timestamp = long(get_attr(attrs, 'time'))
  1121.         ruleid = int(get_attr(attrs, 'id'))
  1122.         if self.oldtimestamps[ruleid] == timestamp:
  1123.             debug("filter %s not modified" % filename)
  1124.             return
  1125.         debug("merging filter %s (ID%d)" % (filename,ruleid))
  1126.         # XXX
  1127.  
  1128.  
  1129.     def removeRule(self, index):
  1130.         for f in self.filters:
  1131.             for i in range(len(f.rules)):
  1132.                 if f.rules[i].index == index:
  1133.                     f.delete_rule(i)
  1134.                     return 1
  1135.         return 0
  1136.  
  1137.  
  1138.     def readconfig(self):
  1139.         """read the configuration from disc"""
  1140.         self.configfile = os.path.join(WebCleanerConf.config_dir, "webcleaner.conf")
  1141.         dom = get_dom(self.configfile)
  1142.         attrs = get_dom_attrs(dom)
  1143.         version = WebCleanerConf.version
  1144.         self.version = get_attr(attrs, 'version')
  1145.         if self.version > version:
  1146.             raise SystemExit, _("Wrong config file version %s, I only understand <= %s") % (self.version, version)
  1147.         self.port = int(get_attr(attrs, 'port'))
  1148.         self.buffersize = int(get_attr(attrs, 'buffersize'))
  1149.         self.parentproxyport = int(get_attr(attrs, 'parentproxyport'))
  1150.         self.debuglevel = int(get_attr(attrs, 'debuglevel'))
  1151.         self.parentproxy = get_attr(attrs, 'parentproxy')
  1152.         self.logfile = get_attr(attrs, 'logfile')
  1153.         self.timeout = int(get_attr(attrs, 'timeout'))
  1154.         self.obfuscateip = int(get_attr(attrs, 'obfuscateip'))
  1155.         self.modules = {"Header":0, "Blocker":0, "GifImage":0, "BinaryCharFilter":0,"Rewriter":0, "Compress":0,}
  1156.         nodes = dom.getElementsByTagName('filter')
  1157.         for n in nodes:
  1158.             self.modules[get_node_attr(n, 'name')] = 1
  1159.  
  1160.         from glob import glob
  1161.         files = glob(WebCleanerConf.config_dir+"/*.zap")
  1162.         self.filters = []
  1163.         self.filterids = {}
  1164.         # read filter files
  1165.         for file in files:
  1166.             try:
  1167.                 open(file)
  1168.             except IOError:
  1169.                 error(_("can not read file %s") % file)
  1170.                 continue
  1171.             dom = get_dom(file)
  1172.             attrs = get_dom_attrs(dom)
  1173.             title = get_attr(attrs, 'title')
  1174.             desc = get_attr(attrs, 'desc')
  1175.             disable = int(get_attr(attrs, 'disable'))
  1176.             lang = get_attr(attrs, 'lang')
  1177.             timestamp = long(get_attr(attrs, 'time'))
  1178.             ruleid = int(get_attr(attrs, 'id'))
  1179.             item = FilterRules(title, desc, disable, lang, file, timestamp, ruleid)
  1180.             # sort the filter list by title
  1181.             self.filters.append(item)
  1182.             self.filterids[ruleid] = 1
  1183.             self.append_rules(dom, item)
  1184.  
  1185.  
  1186.     def writeconfig(self):
  1187.         """write the current configuration to disc"""
  1188.         dirty = 0
  1189.         try:
  1190.             file = open(self.configfile, 'w')
  1191.             file.write(self.toxml())
  1192.             file.close()
  1193.         except IOError:
  1194.             error(_("can not write to file %s") % configfile)
  1195.             dirty = 1
  1196.         for f in self.filters:
  1197.             try:
  1198.                 file = open(f.filename, 'w')
  1199.                 file.write(f.toxml())
  1200.                 file.close()
  1201.             except IOError:
  1202.                 error(_("can not write to file %s") % f.filename)
  1203.                 dirty = 1
  1204.         self.getApp().dirty = dirty
  1205.  
  1206.  
  1207.     def toxml(self):
  1208.         s = """<?xml version="1.0"?>
  1209. <!DOCTYPE webcleaner SYSTEM "webcleaner.dtd">
  1210. <webcleaner
  1211. """
  1212.         s += ' version="%s"\n' % self.version +\
  1213.              ' port="%d"\n' % self.port
  1214.         if self.parentproxy:
  1215.             s += ' parentproxy="%s"\n' % self.parentproxy
  1216.         s += ' parentproxyport="%d"\n' % self.parentproxyport +\
  1217.              ' buffersize="%d"\n' % self.buffersize +\
  1218.              ' timeout="%d"\n' % self.timeout +\
  1219.              ' obfuscateip="%d"\n' % self.obfuscateip +\
  1220.              ' debuglevel="%d"\n' % self.debuglevel
  1221.         if self.logfile:
  1222.             s += ' logfile="%s"\n' % self.logfile
  1223.         s += '>\n'
  1224.         for key,val in self.modules.items():
  1225.             if val:
  1226.                 s += '<filter name="%s"/>\n' % key
  1227.         return s + '</webcleaner>\n'
  1228.  
  1229.  
  1230.     def append_rules(self, dom, item):
  1231.         for name in Filternames:
  1232.             for node in dom.getElementsByTagName(name):
  1233.                 item.append_rule(GetRuleFromNode(node))
  1234.         item.sort()
  1235.  
  1236.  
  1237.  
  1238. if __name__=='__main__':
  1239.     app = FXApp("WebCleanerConf", "Die Kampfwurst")
  1240.     app.init(sys.argv)
  1241.     # dirty flag for the apply button
  1242.     app.dirty = 0
  1243.     # set default color scheme
  1244.     app.baseColor = FXRGB(141,157,170)
  1245.     app.backColor = FXRGB(211,223,232)
  1246.     app.hiliteColor = FXRGB(226,225,220)
  1247.     app.shadowColor = FXRGB(158,165,191)
  1248.     app.borderColor = FXRGB(86,90,104)
  1249.     app.selbackColor = FXRGB(20,58,84)
  1250.     # create and run
  1251.     ConfWindow(app)
  1252.     app.create()
  1253.     app.run()
  1254.