<?xml version="1.0"?>

<!-- Simon Chudley (src299) XML Network Manager -->
<!-- Function described using an XST document to take a single forward start of authority (SOA)
     definition and generate a reverse lookup SOA element. This is done by translating the entities,
     and creating address pointer (PTR) elements for each machine. -->

<!-- PARAMETERS: 
                dbfile: The file to use for the reverse lookup definition, usually db.addr (db.192.168.2) -->

<xsl:stylesheet xmlns="http://www.ecs.soton.ac.uk/~src299/xmlnetman" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                xmlns:dns="http://www.ecs.soton.ac.uk/~src299/xmlnetman/dns" 
                version="1.0" >

  <!-- XML Indented output, remembering not to output the top most XML document declaraion -->
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>


  <!-- Match the top level DNS construct -->
  <xsl:template match="/*/dns:DNSConstruct">

    <!-- Process all the attributes and child elements, replacing the name and description -->
    <xsl:copy>
      <xsl:copy-of select="@*[not(name()='name' or name()='description')]"/>
      <xsl:attribute name="name">Reverse SOA</xsl:attribute>    
      <xsl:attribute name="description">Generated by DNS::Functions:ReverseSOAGen</xsl:attribute>    
      <xsl:apply-templates/>
    </xsl:copy>

  </xsl:template>


  <!-- Takes a dot separated v4 IP address and generates the version used for reverse lookup 
       Eg. Input 192.168.2.100 output 100.2.168.192 -->
  <xsl:template name="reverse_v4_add">
    <xsl:param name="addr"/>

    <xsl:choose>
      <xsl:when test="contains($addr,'.')">
        <xsl:call-template name="reverse_v4_add">
          <xsl:with-param name="addr" select="substring-after($addr,'.')"/>
        </xsl:call-template>
        <xsl:text>.</xsl:text> <xsl:value-of select="substring-before($addr,'.')"/> 
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$addr"/> 
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
 
  <!-- Takes a dot separated v4 IP address and a network number and returns the returns the 
       remained of the string when the network number is removed. I.e. feed in 192.168.2.100
       and 192.168.2, and the result will be 100 --> 
  <xsl:template name="last_v4_element">
    <xsl:param name="addr"/>
    <xsl:param name="net"/>

    <xsl:variable name="thematch"> <xsl:value-of select="substring-after($addr, $net)"/> </xsl:variable>
    <xsl:value-of select="substring($thematch, 2, string-length($thematch) + 1)"/>
  </xsl:template>


  <!-- Match the forward start of authority (SOA) element -->
  <xsl:template match="dns:ForwardSOA">
  
     <!-- We want to define a reverse SOA -->
     <dns:ReverseSOA>

      <!-- Copy all of the header out of the forward SOA, but use the file they specified as param, and
           generate the correct reverse SOA match variable -->
      <xsl:copy-of select="@*[not(name()='file') and not(name()='match')]"/>
      <xsl:attribute name="file"> <xsl:value-of select="/*/@dbfile"/> </xsl:attribute>

      <!-- Generate the correct reverse match variable -->
      <xsl:attribute name="match">
        <xsl:call-template name="reverse_v4_add">
          <xsl:with-param name="addr"> <xsl:value-of select="/*/@with_net"/> </xsl:with-param>
        </xsl:call-template>
        <xsl:text>.in-addr.arpa</xsl:text>
      </xsl:attribute>

      <!-- Copy out any name server declarations -->
      <xsl:text>&#xa;&#xa;          </xsl:text> 
      <xsl:copy-of select="./dns:NS"/>  
      <xsl:text>&#xa;</xsl:text>

      <xsl:variable name="domain"> <xsl:value-of select="@match"/> </xsl:variable>

      <!-- For all the A records matching a matchine to a name -->
      <xsl:for-each select="./dns:A">

        <xsl:if test="(@match != '@') and (@match != 'localhost')">

          <xsl:variable name="lsb">
            <xsl:call-template name="last_v4_element">
              <xsl:with-param name="addr"> <xsl:value-of select="@target"/> </xsl:with-param>
              <xsl:with-param name="net"> <xsl:value-of select="/*/@with_net"/> </xsl:with-param>
            </xsl:call-template>
          </xsl:variable>

          <xsl:if test="string-length($lsb) > 0">
            <xsl:text>          </xsl:text> 
            <dns:PTR>
              <xsl:attribute name="match"> <xsl:value-of select="$lsb"/> </xsl:attribute>
              <xsl:attribute name="target"> <xsl:value-of select="@match"/>.<xsl:value-of select="$domain"/></xsl:attribute>
            </dns:PTR>
          </xsl:if>

        </xsl:if>

        <xsl:text>&#xa;</xsl:text>
      </xsl:for-each>   

     <xsl:text>        </xsl:text> 
     </dns:ReverseSOA>

  </xsl:template>

</xsl:stylesheet>
