<?xml version="1.0" ?>

<!--
        DTD describing the 'spam-policy argument of Al's junkbuster
-->

<!-- this is the top node -->
<!ELEMENT spam-policy (policy|rules)*>

<!-- this element is a rule defining a set of conditions an url may match -->
<!-- its attributes are regular expressions which apply to different parts -->
<!-- of the URL, the results of the evaluations are logically ANDed  -->
<!-- then, if the rule has no children, the evaluation is over, else, the -->
<!-- rule's children are evaluated, and the result of these evaluations is -->
<!-- logically ORed ; at last, the result of the evaluation of the -->
<!-- attributes is logically ANDed with the result of the evaluation of the -->
<!-- elements -->
<!ELEMENT rule (rule|or|and|ruleref)*>
<!-- url represents the full url as given by the web browser or in the -->
<!-- page's source, the other attributes are the attributes return by the -->
<!-- urlparse.urlparse function of python ; for instance, if we have -->
<!-- url==http://coincoin.org:92/tralalapouet#meuuh -->
<!-- we will obtain : -->
<!-- protocol==http, path==tralalapouet, host=coincoin.org:92, fragid==meuuh -->
<!-- if the reverse attribute is set to yes, the result of the rule's -->
<!-- evaluation (including the evaluation of the rule's children) will be -->
<!-- logically NOTed -->

<!ATTLIST rule url CDATA #IMPLIED>
<!ATTLIST rule protocol CDATA #IMPLIED>
<!ATTLIST rule  path CDATA #IMPLIED>
<!ATTLIST rule  host CDATA #IMPLIED>
<!ATTLIST rule  param CDATA #IMPLIED>
<!ATTLIST rule  query CDATA #IMPLIED>
<!ATTLIST rule  fragid CDATA #IMPLIED>
<!ATTLIST rule  reverse CDATA #IMPLIED>

<!-- this element is evaluated as the logical OR of its childrens -->
<!-- evaluations results -->
<!ELEMENT or (rule|or|and|ruleref)*>

<!-- this element is evaluated as the logical AND of its childrens -->
<!-- evaluations results -->
<!ELEMENT and (rule|or|and|ruleref)*>

<!-- this element is evaluated as the result of the evaluation of the -->
<!-- namedrule element it points to, logically ORed with the evaluation -->
<!-- of the ruleref's children if it has children -->
<!ELEMENT ruleref (rule|or|and|ruleref)*>
<!-- the rule attribute is set to the name of the namedrule this element -->
<!-- points to -->
<!-- the ruleref's evaluation result is logically NOTed if its reverse -->
<!-- attribute is set to 'yes' -->
<!ATTLIST ruleref reverse CDATA #REQUIRED >

<!-- this element defines how the junkbuster should behave -->
<!-- when the browser tries to reach an url, this url is tested against -->
<!-- all the allow and trash set of rules in the order in which these -->
<!-- elements appear ; the first element containing a rule the url matches -->
<!-- determines if the browser will reach it or if a blank png will be -->
<!-- given instead ; then, when an html page is obtained, all filters are -->
<!-- applied to its text, in the order in which they appear, and if the url -->
<!-- matches the filter's requirements ; this enables one to change the -->
<!-- page's text -->
<!ELEMENT policy (allow|trash|filter)*>

<!-- if the url matches any of the children of this element (which are rules -->
<!-- trees), it may be reached --> 
<!ELEMENT allow (rule|or|and|ruleref)*>

<!-- if the url matches any of the children of this element (which are rules -->
<!-- trees), it is blocked, and a blank png is sent instead -->
<!ELEMENT trash (rule|or|and|ruleref)*>

<!-- filters enable one to change the text of certain html pages -->
<!ELEMENT filter (url_match?|text_match*|text_replace?)>
<!-- the filter's host attribute is a regular expression, the filter does -->
<!-- not apply if the host part of the url does not match it -->
<!ATTLIST filter host CDATA #IMPLIED>

<!-- if the url does not match one of the rules trees which are children of -->
<!-- url_match, the filter is not applied -->
<!ELEMENT url_match (rule|or|and|ruleref)*>

<!-- these elements are regular expressions describing which part of an html -->
<!-- text should be modified by a filter -->
<!ELEMENT text_match (#PCDATA)>

<!-- guess what ? this element tells the filter what it has to put when -->
<!-- something is matched by one of its text_match children ; if it is -->
<!-- absent, an empty string will be used -->
<!ELEMENT replace_by (#PCDATA)>

<!-- this element encapsulates a list of namedrule elements -->
<!ELEMENT rules (namedrule)*>

<!-- this element is an alias for a single rule or a full tree of rules -->
<!-- it is evaluated only when a ruleref element calls it -->
<!-- its attributes and children are evaluated in the same way a rule's -->
<!-- elements are ; a ruleref having its rule attribute set to the same -->
<!-- value than the namedrule's name attribute will call the namedrule -->
<!-- two namedrules should not have the same name, if this happens, the -->
<!-- junkbuster's behaviour is undetermined (currently, the last element is -->
<!-- used, but this may change later) -->
<!ELEMENT namedrule (rule|or|and|ruleref)*>
<!ATTLIST namedrule
          name CDATA #REQUIRED
          url CDATA #IMPLIED
          proto CDATA #IMPLIED
          path CDATA #IMPLIED
          host CDATA #IMPLIED
          param CDATA #IMPLIED
          query CDATA #IMPLIED
          fragid CDATA #IMPLIED
          reverse CDATA #IMPLIED>

<!-- this is a sample junkbuster configuration -->
<!--
<spam-policy>
  <rules>
    <namedrule name="doubleclick1" host=".*doubleclick\.net.*">
      <rule proto="http"/>
      <rule proto="ftp"/>
    </namedrule>
    <namedrule name="doubleclick2">
      <and>
        <rule host=".*doubleclick\.net.*"/>
        <or>
          <rule proto="http"/>
          <rule proto="ftp"/>
        </or>
      </and>
    </namedrule>
    <namedrule name="doubleclick3" host=".*doubleclick\.net">
      <rule host=".*:80$" reverse="yes"/>
    </namedrule>
    <namedrule name="doubleclick4" host=".*doubleclick\.net" reverse="yes">
      <rule host=".*:80$"/>
    </namedrule>
    <namedrule name="doubleclick5" host=".*doubleclick\.net"/>
  </rules>
  <policy>
    <trash>
      <ruleref rule="doubleclick5">
        <rule proto="http"/>
        <rule proto="ftp"/>
      </ruleref>
    </trash>
    <trash>
      <ruleref rule="doubleclick1"/>
    </trash>
    <allow>
      <and>
        <rule proto="http"/>
        <ruleref rule="doubleclick4"/>
      </and>
      <rule url=".*banner.*" reverse="yes"/>
    </allow>
    <trash>
      <rule url=".*"/>
    </trash>
  </policy>
</spam-policy>
-->
<!--
Let's explain the rules section :
* the 2 first namedrules are equivalent
  they match any url whose host part (remember the host part includes the port
  specification !) matches the .*doubleclick\.net regular expression and whose
  protocol is http or ftp
* the third namedrule matches any url whose host part matches
  *doubleclick\.net and not .*:80$ (read : every url targeting doubleclick.net
  on another port than 80)
* the fourth namedrule matches any url whose host part doesn't match
  .*doubleclick\.net nor .*:80$ (read : any url targetting doubleclick and/or
  whose target port is 80
* the fifth namedrule matches any url whose host part matches .*doubleclick\.net
  (read : any url targetting doubleclick.net)
Note the rule section does not tell what to do with those urls, it just
describes some ways of matching urls. Telling what to do with the urls is the
role of the policy section, let's explain it :
* the two first trash blocks are equivalent : they will cause any request whose
  url targets doubleclick.net and is an http or ftp request to be rejected
* then, the first allow block will enable any request whose url matches the
  "doubleclick4" namedrule and whose protocol is http or any url which does not
  contain the banner pattern to be sucessfuly transmitted
* then, the last trash block tells that any request which has not been matched
  by the preceding rules should be rejected (remember the first matching rule
  is applied)
-->
