First cut. Distintly raw around the edges: default tip
authorali@yendor.vm.bytemark.co.uk
Thu Nov 16 08:30:26 2006 +0000 (2006-11-16)
changeset 0ae7b3fa753dc
First cut. Distintly raw around the edges:
* Assumes it will be running in /home/ali/wk/slashem/web.scripts
* Assumes cache directory will be in topdir
* No build system (simple compiling and linking against libxml2)
* No configure system (eg., tagsoup)
* Output XML untested
* Doesn't set bugzilla maintainer or exporter
* Handling of artifact priorities and resolution is suspect
README.cache
attachment_descs.xsl
attachment_details.xsl
attachment_gather.xsl
attachment_post.xsl
bugzilla.xsl
bugzilla_post.xsl
get_attached_files.c
get_users.xsl
sf2bz.sh
sf2bz.xsl
tagsoup/SRC
unknown_users.xsl
user_names.xsl
xml_attached_file.c
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/README.cache	Thu Nov 16 08:30:26 2006 +0000
     1.3 @@ -0,0 +1,19 @@
     1.4 +The cache directory contains the following:
     1.5 +
     1.6 +sf/attachments/<file_id>
     1.7 +	Raw attachments as downloaded from sourceforge by sf2bz
     1.8 +
     1.9 +sf/artifacts/<atid>/<aid>.html
    1.10 +	Tagsoup detailed artifacts as downloaded from sourceforge by sf2bz
    1.11 +
    1.12 +sf/users/<user_id>.html
    1.13 +	Tagsoup user profiles as downloaded from sourceforge by sf2bz
    1.14 +
    1.15 +attachments/<file_id>.xml
    1.16 +	Attachments converted to xml by sf2bz
    1.17 +
    1.18 +artifacts/<atid>/<aid>.xhtml
    1.19 +	Conversion of detailed artifacts to xhtml by tagsoup
    1.20 +
    1.21 +users/<user_id>.xhtml
    1.22 +	Conversion of user profiles to xhtml by tagsoup
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/attachment_descs.xsl	Thu Nov 16 08:30:26 2006 +0000
     2.3 @@ -0,0 +1,51 @@
     2.4 +<?xml version="1.0"?>
     2.5 +
     2.6 +<!-- This style sheet takes a sourceforge artifact in html and outputs
     2.7 +     the attachment descriptions that it finds. The output is as follows:
     2.8 +     <attachments>
     2.9 +       <attachment>
    2.10 +         <attachid>###</attachid>
    2.11 +	 <desc>...</desc>
    2.12 +       </attachment>
    2.13 +       ...
    2.14 +     </attachments>
    2.15 +-->
    2.16 +
    2.17 +<xsl:stylesheet version="1.0"
    2.18 +		xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    2.19 +		xmlns:xhtml="http://www.w3.org/1999/xhtml"
    2.20 +		exclude-result-prefixes="xhtml">
    2.21 +
    2.22 +<xsl:template match="xhtml:tr" mode="download">
    2.23 +  <attachment>
    2.24 +    <attachid>
    2.25 +      <xsl:value-of select="substring-before(substring-after(xhtml:td[4]/descendant::xhtml:a/@href,'file_id='),'&amp;')"/>
    2.26 +    </attachid>
    2.27 +    <desc>
    2.28 +      <xsl:value-of select="normalize-space(xhtml:td[3])"/>
    2.29 +    </desc>
    2.30 +  </attachment>
    2.31 +</xsl:template>
    2.32 +
    2.33 +<xsl:template match="xhtml:table[preceding-sibling::xhtml:h4='Attached Files:' and xhtml:tr/xhtml:td='Download']">
    2.34 +    <xsl:for-each select="xhtml:tr[descendant::xhtml:a='Download']">
    2.35 +      <xsl:apply-templates select="." mode="download"/>
    2.36 +    </xsl:for-each>
    2.37 +</xsl:template>
    2.38 +
    2.39 +<xsl:template match="/">
    2.40 +  <attachments>
    2.41 +    <xsl:apply-templates/>
    2.42 +    <!-- A null description used as a fallback for when there is no
    2.43 +         description listed for an attachment. -->
    2.44 +    <desc xml:id="null"/>
    2.45 +  </attachments>
    2.46 +</xsl:template>
    2.47 +
    2.48 +<xsl:template match="node()" priority="-1">
    2.49 +  <xsl:apply-templates/>
    2.50 +</xsl:template>
    2.51 +
    2.52 +<xsl:template match="text()" priority="-1"></xsl:template>
    2.53 +
    2.54 +</xsl:stylesheet>
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/attachment_details.xsl	Thu Nov 16 08:30:26 2006 +0000
     3.3 @@ -0,0 +1,70 @@
     3.4 +<?xml version="1.0"?>
     3.5 +
     3.6 +<!-- This stylesheet extracts some details of attachments from the artifact
     3.7 +     history of a sourceforge project export. -->
     3.8 +
     3.9 +<xsl:stylesheet version="1.0"
    3.10 +		xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    3.11 +		xmlns:xi="http://www.w3.org/2001/XInclude">
    3.12 +
    3.13 +<xsl:import href="sf2bz.xsl"/>
    3.14 +
    3.15 +<!-- Process a sourceforge artifact, outputting attachments as found -->
    3.16 +<xsl:template name="process-artifact">
    3.17 +    <xsl:apply-templates/>
    3.18 +    <xsl:for-each
    3.19 +      select="field[@name='artifact_history']/history[field[@name='field_name']='File Added']">
    3.20 +      <xsl:variable name="file_id"
    3.21 +        select="substring-before(field[@name='old_value'],':')"/>
    3.22 +      <attachment>
    3.23 +	<!-- isobsolete is an attribute of bugzilla:attachment, but that
    3.24 +	     proves hard to deal with so we treat it as a node and fix it
    3.25 +	     up in attachment_post.xsl -->
    3.26 +	<isobsolete>
    3.27 +	  <xsl:value-of select="number(boolean(../history[field[@name='field_name']='File Deleted' and substring-before(field[@name='old_value'],':')=$file_id]))"/>
    3.28 +	</isobsolete>
    3.29 +	<attachid>
    3.30 +	  <xsl:value-of select="$file_id"/>
    3.31 +	</attachid>
    3.32 +	<date>
    3.33 +	  <xsl:call-template name="bugzilla-timestamp">
    3.34 +	    <xsl:with-param name="secs" select="field[@name='entrydate']"/>
    3.35 +	  </xsl:call-template>
    3.36 +	</date>
    3.37 +	<filename>
    3.38 +	  <xsl:value-of
    3.39 +	    select="substring-after(field[@name='old_value'],': ')"/>
    3.40 +	</filename>
    3.41 +      </attachment>
    3.42 +    </xsl:for-each>
    3.43 +</xsl:template>
    3.44 +
    3.45 +<xsl:template match="project_export">
    3.46 +  <attachments>
    3.47 +    <xsl:apply-templates/>
    3.48 +  </attachments>
    3.49 +</xsl:template>
    3.50 +
    3.51 +<xsl:template match="artifacts">
    3.52 +  <xsl:apply-templates/>
    3.53 +</xsl:template>
    3.54 +
    3.55 +<xsl:template match="artifact">
    3.56 +  <xsl:variable name="type"
    3.57 +    select="normalize-space(field[@name='artifact_type'])"/>
    3.58 +  <xsl:choose>
    3.59 +    <xsl:when test="$type = 'Feature Requests'">
    3.60 +      <xsl:call-template name="process-artifact"/>
    3.61 +    </xsl:when>
    3.62 +    <xsl:when test="$type = 'Patches'">
    3.63 +      <xsl:call-template name="process-artifact"/>
    3.64 +    </xsl:when>
    3.65 +    <xsl:when test="$type = 'Bugs'">
    3.66 +      <xsl:call-template name="process-artifact"/>
    3.67 +    </xsl:when>
    3.68 +  </xsl:choose>
    3.69 +</xsl:template>
    3.70 +
    3.71 +<xsl:template match="node()|text()" priority="-1"></xsl:template>
    3.72 +
    3.73 +</xsl:stylesheet>
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/attachment_gather.xsl	Thu Nov 16 08:30:26 2006 +0000
     4.3 @@ -0,0 +1,54 @@
     4.4 +<?xml version="1.0"?>
     4.5 +
     4.6 +<!-- This style sheet takes the output of xml_attached file (which represents
     4.7 +     an attachment and it's MIME type), adds in the following extra nodes:
     4.8 +       date, desc & filename.
     4.9 +-->
    4.10 +
    4.11 +<xsl:stylesheet version="1.0"
    4.12 +		xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    4.13 +		xmlns:xi="http://www.w3.org/2001/XInclude">
    4.14 +
    4.15 +<xsl:template match="attachment">
    4.16 +  <xsl:copy>
    4.17 +    <xsl:for-each select="@*">
    4.18 +      <xsl:copy/>
    4.19 +    </xsl:for-each>
    4.20 +    <xsl:apply-templates/>
    4.21 +    <xsl:element namespace="http://www.w3.org/2001/XInclude" name="include">
    4.22 +      <xsl:attribute name="href">
    4.23 +	<xsl:text>attachment-details.xml</xsl:text>
    4.24 +      </xsl:attribute>
    4.25 +      <xsl:attribute name="xpointer">
    4.26 +	<xsl:text>xpointer(/attachments/attachment[attachid='</xsl:text>
    4.27 +	<xsl:value-of select="attachid"/>
    4.28 +	<xsl:text>']/*)</xsl:text>
    4.29 +      </xsl:attribute>
    4.30 +    </xsl:element>
    4.31 +    <xsl:element namespace="http://www.w3.org/2001/XInclude" name="include">          <xsl:attribute name="href">
    4.32 +	<xsl:text>attachment-descriptions.xml</xsl:text>
    4.33 +      </xsl:attribute>
    4.34 +      <xsl:attribute name="xpointer">
    4.35 +	<xsl:text>xpointer(/attachments/attachment[attachid='</xsl:text>
    4.36 +	<xsl:value-of select="attachid"/>
    4.37 +	<xsl:text>']/desc)element(null)</xsl:text>
    4.38 +      </xsl:attribute>
    4.39 +    </xsl:element>
    4.40 +  </xsl:copy>
    4.41 +</xsl:template>
    4.42 +
    4.43 +<!-- Drop the attachment ID to avoid duplication with the node included
    4.44 +     from attachment-details.xml -->
    4.45 +
    4.46 +<xsl:template match="attachid"/>
    4.47 +
    4.48 +<xsl:template match="*">
    4.49 +  <xsl:copy>
    4.50 +    <xsl:for-each select="@*">
    4.51 +      <xsl:copy/>
    4.52 +    </xsl:for-each>
    4.53 +    <xsl:apply-templates/>
    4.54 +  </xsl:copy>
    4.55 +</xsl:template>
    4.56 +
    4.57 +</xsl:stylesheet>
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/attachment_post.xsl	Thu Nov 16 08:30:26 2006 +0000
     5.3 @@ -0,0 +1,38 @@
     5.4 +<?xml version="1.0"?>
     5.5 +
     5.6 +<!-- This stylesheet does some post-processing on attachments. -->
     5.7 +
     5.8 +<xsl:stylesheet version="1.0"
     5.9 +		xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    5.10 +
    5.11 +<xsl:template match="attachment">
    5.12 +  <!-- Avoid xsl:copy so that any attributes (including xml:base) are lost -->
    5.13 +  <attachment>
    5.14 +    <xsl:attribute name="ispatch">
    5.15 +      <xsl:value-of select="@ispatch"/>
    5.16 +    </xsl:attribute>
    5.17 +    <xsl:attribute name="isobsolete">
    5.18 +      <xsl:value-of select="isobsolete"/>
    5.19 +    </xsl:attribute>
    5.20 +    <xsl:apply-templates/>
    5.21 +  </attachment>
    5.22 +</xsl:template>
    5.23 +
    5.24 +<xsl:template match="attachment/isobsolete"/>
    5.25 +
    5.26 +<xsl:template match="attachment/desc[normalize-space(.)='']">
    5.27 +  <desc>
    5.28 +    <xsl:value-of select="../filename"/>
    5.29 +  </desc>
    5.30 +</xsl:template>
    5.31 +
    5.32 +<xsl:template match="*">
    5.33 +  <xsl:copy>
    5.34 +    <xsl:for-each select="@*">
    5.35 +      <xsl:copy/>
    5.36 +    </xsl:for-each>
    5.37 +    <xsl:apply-templates/>
    5.38 +  </xsl:copy>
    5.39 +</xsl:template>
    5.40 +
    5.41 +</xsl:stylesheet>
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/bugzilla.xsl	Thu Nov 16 08:30:26 2006 +0000
     6.3 @@ -0,0 +1,236 @@
     6.4 +<?xml version="1.0"?>
     6.5 +<xsl:stylesheet version="1.0"
     6.6 +		xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     6.7 +		xmlns:xi="http://www.w3.org/2001/XInclude"
     6.8 +		xmlns:date="http://exslt.org/dates-and-times"
     6.9 +		xmlns:sf2bz="http://project.juiblex.co.uk/sf2bz"
    6.10 +		extension-element-prefixes="date">
    6.11 +
    6.12 +<xsl:import href="sf2bz.xsl"/>
    6.13 +
    6.14 +<!-- Return the last change made in an artifact's history -->
    6.15 +<xsl:template name="lastchange">
    6.16 +  <xsl:variable name="dates">
    6.17 +    <xsl:for-each
    6.18 +      select="field[@name='artifact_history']/history/field[@name='entrydate']">
    6.19 +      <xsl:sort data-type='number' order='descending'/>
    6.20 +      <xsl:value-of select="."/>
    6.21 +      <xsl:text>:</xsl:text>
    6.22 +    </xsl:for-each>
    6.23 +  </xsl:variable>
    6.24 +  <xsl:call-template name="bugzilla-timestamp">
    6.25 +    <xsl:with-param name="secs" select="substring-before($dates,':')"/>
    6.26 +  </xsl:call-template>
    6.27 +</xsl:template>
    6.28 +
    6.29 +<!-- Process a sourceforge artifact, outputting a bugzilla bug -->
    6.30 +<xsl:template name="process-artifact">
    6.31 +  <bug>
    6.32 +    <xsl:apply-templates/>
    6.33 +    <delta_ts>
    6.34 +      <xsl:choose>
    6.35 +	<xsl:when test="field[@name='artifact_history']">
    6.36 +	  <xsl:call-template name="lastchange"/>
    6.37 +	</xsl:when>
    6.38 +	<xsl:otherwise>
    6.39 +	  <xsl:call-template name="bugzilla-timestamp">
    6.40 +	    <xsl:with-param name="secs" select="field[@name='open_date']"/>
    6.41 +	  </xsl:call-template>
    6.42 +	</xsl:otherwise>
    6.43 +      </xsl:choose>
    6.44 +    </delta_ts>
    6.45 +    <xsl:for-each
    6.46 +      select="field[@name='artifact_history']/history[field[@name='field_name']='File Added']">
    6.47 +      <xsl:element namespace="http://www.w3.org/2001/XInclude" name="include">
    6.48 +	<xsl:attribute name="href">
    6.49 +	  <xsl:text>cache/attachments/</xsl:text>
    6.50 +	  <xsl:value-of
    6.51 +	    select="substring-before(field[@name='old_value'],':')"/>
    6.52 +	  <xsl:text>.xml</xsl:text>
    6.53 +	</xsl:attribute>
    6.54 +	<xsl:attribute name="xpointer">xpointer(/attachment)</xsl:attribute>
    6.55 +	<xsl:element namespace="http://www.w3.org/2001/XInclude"
    6.56 +	  name="fallback"/>
    6.57 +      </xsl:element>
    6.58 +    </xsl:for-each>
    6.59 +  </bug>
    6.60 +</xsl:template>
    6.61 +
    6.62 +<!-- Output a user node -->
    6.63 +<xsl:template name="bugzilla-user">
    6.64 +  <xsl:param name="element">who</xsl:param>
    6.65 +  <xsl:param name="user" select="."/>
    6.66 +  <sf2bz:element>
    6.67 +    <xsl:attribute name="name">
    6.68 +      <xsl:value-of select="$element"/>
    6.69 +    </xsl:attribute>
    6.70 +    <sf2bz:copy-from>
    6.71 +      <xsl:element namespace="http://www.w3.org/2001/XInclude" name="include">
    6.72 +	<xsl:attribute name="href">users.xml</xsl:attribute>
    6.73 +	<xsl:attribute name="xpointer">
    6.74 +	  <xsl:text>xpointer(/users/user[.="</xsl:text>
    6.75 +	  <xsl:value-of select="$user"/>
    6.76 +	  <xsl:text>@users.sourceforge.net"])</xsl:text>
    6.77 +	</xsl:attribute>
    6.78 +      </xsl:element>
    6.79 +    </sf2bz:copy-from>
    6.80 +  </sf2bz:element>
    6.81 +</xsl:template>
    6.82 +
    6.83 +<xsl:template match="project_export">
    6.84 +  <bugzilla version="2.23.3">
    6.85 +    <xsl:if test="news/field[@name='group_id']/@group_id">
    6.86 +      <xsl:attribute name="urlbase">
    6.87 +        <xsl:text>https://sourceforge.net/tracker/?group_id=</xsl:text>
    6.88 +	<xsl:value-of select="news/field[@name='group_id']/@group_id"/>
    6.89 +      </xsl:attribute>
    6.90 +    </xsl:if>
    6.91 +    <xsl:apply-templates/>
    6.92 +  </bugzilla>
    6.93 +</xsl:template>
    6.94 +
    6.95 +<xsl:template match="artifacts">
    6.96 +  <xsl:apply-templates/>
    6.97 +</xsl:template>
    6.98 +
    6.99 +<xsl:template match="artifact">
   6.100 +  <xsl:variable name="type"
   6.101 +    select="normalize-space(field[@name='artifact_type'])"/>
   6.102 +  <xsl:choose>
   6.103 +    <xsl:when test="$type = 'Feature Requests'">
   6.104 +      <xsl:call-template name="process-artifact"/>
   6.105 +    </xsl:when>
   6.106 +    <xsl:when test="$type = 'Patches'">
   6.107 +      <xsl:call-template name="process-artifact"/>
   6.108 +    </xsl:when>
   6.109 +    <xsl:when test="$type = 'Bugs'">
   6.110 +      <xsl:call-template name="process-artifact"/>
   6.111 +    </xsl:when>
   6.112 +  </xsl:choose>
   6.113 +</xsl:template>
   6.114 +
   6.115 +<xsl:template match="field[@name='artifact_id']">
   6.116 +  <bug_id><xsl:value-of select="."/></bug_id>
   6.117 +</xsl:template>
   6.118 +
   6.119 +<xsl:template match="field[@name='submitted_by']">
   6.120 +  <xsl:call-template name="bugzilla-user">
   6.121 +    <xsl:with-param name="element">reporter</xsl:with-param>
   6.122 +  </xsl:call-template>
   6.123 +</xsl:template>
   6.124 +
   6.125 +<xsl:template match="field[@name='assigned_to']">
   6.126 +  <xsl:if test="normalize-space(.)!='nobody'">
   6.127 +    <xsl:call-template name="bugzilla-user">
   6.128 +      <xsl:with-param name="element">assigned_to</xsl:with-param>
   6.129 +    </xsl:call-template>
   6.130 +  </xsl:if>
   6.131 +</xsl:template>
   6.132 +
   6.133 +<xsl:template match="field[@name='priority']">
   6.134 +  <priority>
   6.135 +    <xsl:choose>
   6.136 +      <xsl:when test="number(.)>8">P5</xsl:when>
   6.137 +      <xsl:when test="number(.)>5">P4</xsl:when>
   6.138 +      <xsl:when test="number(.)=5">P3</xsl:when>
   6.139 +      <xsl:when test="number(.)>1">P2</xsl:when>
   6.140 +      <xsl:otherwise>P1</xsl:otherwise>
   6.141 +    </xsl:choose>
   6.142 +  </priority>
   6.143 +</xsl:template>
   6.144 +
   6.145 +<xsl:template match="field[@name='status']">
   6.146 +  <bug_status>
   6.147 +    <xsl:choose>
   6.148 +      <xsl:when test="normalize-space(.)='Open'">
   6.149 +	<xsl:choose>
   6.150 +	  <xsl:when
   6.151 +	    test="normalize-space(../field[@name='assigned_to'])='nobody'">
   6.152 +	    <xsl:text>UNCONFIRMED</xsl:text>
   6.153 +	  </xsl:when>
   6.154 +	  <xsl:otherwise>ASSIGNED</xsl:otherwise>
   6.155 +	</xsl:choose>
   6.156 +      </xsl:when>
   6.157 +      <xsl:when test="normalize-space(.)='Pending'">NEW</xsl:when>
   6.158 +      <xsl:otherwise>RESOLVED</xsl:otherwise>
   6.159 +    </xsl:choose>
   6.160 +  </bug_status>
   6.161 +</xsl:template>
   6.162 +
   6.163 +<xsl:template match="field[@name='summary']">
   6.164 +  <short_desc><xsl:value-of select="."/></short_desc>
   6.165 +</xsl:template>
   6.166 +
   6.167 +<xsl:template match="field[@name='open_date']">
   6.168 +  <creation_ts>
   6.169 +    <xsl:call-template name="bugzilla-timestamp"/>
   6.170 +  </creation_ts>
   6.171 +</xsl:template>
   6.172 +
   6.173 +<xsl:template match="field[@name='artifact_type']">
   6.174 +  <xsl:variable name="pri"
   6.175 +    select="normalize-space(../field[@name='priority'])"/>
   6.176 +  <bug_severity>
   6.177 +    <xsl:choose>
   6.178 +      <xsl:when test="normalize-space(.)='Bugs'">
   6.179 +	<xsl:choose>
   6.180 +	  <xsl:when test="$pri&gt;=9">blocker</xsl:when>
   6.181 +	  <xsl:when test="$pri=8">critical</xsl:when>
   6.182 +	  <xsl:when test="$pri&lt;8 and $pri&gt;5">major</xsl:when>
   6.183 +	  <xsl:when test="$pri&lt;5 and $pri&gt;2">minor</xsl:when>
   6.184 +	  <xsl:when test="$pri&lt;=2">trivial</xsl:when>
   6.185 +	  <xsl:otherwise>normal</xsl:otherwise>
   6.186 +	</xsl:choose>
   6.187 +      </xsl:when>
   6.188 +      <xsl:otherwise>enhancement</xsl:otherwise>
   6.189 +    </xsl:choose>
   6.190 +  </bug_severity>
   6.191 +</xsl:template>
   6.192 +
   6.193 +<xsl:template match="field[@name='category']">
   6.194 +  <component><xsl:value-of select="."/></component>
   6.195 +</xsl:template>
   6.196 +
   6.197 +<xsl:template match="field[@name='artifact_group_id']">
   6.198 +  <version><xsl:value-of select="."/></version>
   6.199 +</xsl:template>
   6.200 +
   6.201 +<xsl:template match="field[@name='details']">
   6.202 +  <long-desc>
   6.203 +    <xsl:call-template name="bugzilla-user">
   6.204 +      <xsl:with-param name="user" select="../field[@name='submitted_by']"/>
   6.205 +    </xsl:call-template>
   6.206 +    <bug_when>
   6.207 +      <xsl:call-template name="bugzilla-timestamp">
   6.208 +	<xsl:with-param name="secs" select="../field[@name='open_date']"/>
   6.209 +      </xsl:call-template>
   6.210 +    </bug_when>
   6.211 +    <thetext><xsl:value-of select="."/></thetext>
   6.212 +  </long-desc>
   6.213 +</xsl:template>
   6.214 +
   6.215 +<xsl:template match="field[@name='artifact_messages']">
   6.216 +  <xsl:apply-templates/>
   6.217 +</xsl:template>
   6.218 +
   6.219 +<xsl:template match="message">
   6.220 +  <long-desc>
   6.221 +    <xsl:call-template name="bugzilla-user">
   6.222 +      <xsl:with-param name="user" select="field[@name='user_name']"/>
   6.223 +    </xsl:call-template>
   6.224 +    <bug_when>
   6.225 +      <xsl:call-template name="bugzilla-timestamp">
   6.226 +	<xsl:with-param name="secs" select="field[@name='adddate']"/>
   6.227 +      </xsl:call-template>
   6.228 +    </bug_when>
   6.229 +    <thetext>
   6.230 +      <!-- Sourceforge puts either "Logged In: YES \n;user_id=%user\n\n" or
   6.231 +           "Logged In: NO\n\n" at the start of each message body. -->
   6.232 +      <xsl:value-of select="substring-after(field[@name='body'],'&#10;&#10;')"/>
   6.233 +    </thetext>
   6.234 +  </long-desc>
   6.235 +</xsl:template>
   6.236 +
   6.237 +<xsl:template match="node()|text()" priority="-1"></xsl:template>
   6.238 +
   6.239 +</xsl:stylesheet>
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/bugzilla_post.xsl	Thu Nov 16 08:30:26 2006 +0000
     7.3 @@ -0,0 +1,31 @@
     7.4 +<?xml version="1.0"?>
     7.5 +
     7.6 +<!-- This stylesheet does some post-processing on the bugzilla output. -->
     7.7 +
     7.8 +<xsl:stylesheet version="1.0"
     7.9 +		xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    7.10 +		xmlns:sf2bz="http://project.juiblex.co.uk/sf2bz"
    7.11 +		exclude-result-prefixes="sf2bz">
    7.12 +
    7.13 +<xsl:template match="//sf2bz:element">
    7.14 +  <xsl:element name="{@name}">
    7.15 +    <xsl:for-each select="sf2bz:copy-from/*/*|sf2bz:copy-from/*/@*|sf2bz:copy-from/*/text()">
    7.16 +      <xsl:copy/>
    7.17 +    </xsl:for-each>
    7.18 +  </xsl:element>
    7.19 +</xsl:template>
    7.20 +
    7.21 +<!-- Kill all the xmlns:* and xml:base attributes
    7.22 +     (none of which are relevant any more) -->
    7.23 +<xsl:template match="*">
    7.24 +  <xsl:element name="{name()}">
    7.25 +    <xsl:for-each select="@*">
    7.26 +      <xsl:if test="name(.) != 'xml:base'">
    7.27 +	<xsl:copy/>
    7.28 +      </xsl:if>
    7.29 +    </xsl:for-each>
    7.30 +    <xsl:apply-templates/>
    7.31 +  </xsl:element>
    7.32 +</xsl:template>
    7.33 +
    7.34 +</xsl:stylesheet>
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/get_attached_files.c	Thu Nov 16 08:30:26 2006 +0000
     8.3 @@ -0,0 +1,148 @@
     8.4 +/*
     8.5 + * This program parses the XML data provided by sourceforge to extract the
     8.6 + * list of "attached files" (which are not themselves included in the XML
     8.7 + * stream and therefore need to be seperately downloaded for archiving).
     8.8 + */
     8.9 +
    8.10 +#include <stdlib.h>
    8.11 +#include <stdio.h>
    8.12 +#include <string.h>
    8.13 +#include <libxml/xmlmemory.h>
    8.14 +#include <libxml/parser.h>
    8.15 +
    8.16 +struct artifact_type {
    8.17 +    char *name;
    8.18 +    int id;
    8.19 +} artifact_types[] = {
    8.20 +    "Bugs",		109746,
    8.21 +    "Support Requests",	209746,
    8.22 +    "Patches",		309746,
    8.23 +    "Feature Requests",	359746,
    8.24 +};
    8.25 +
    8.26 +#ifndef NO_ELEMS
    8.27 +#define NO_ELEMS(array)	(sizeof(array)/sizeof(*(array)))
    8.28 +#endif
    8.29 +
    8.30 +void parse_history(xmlDocPtr doc,const xmlChar *artifact_id,
    8.31 +  const xmlChar *artifact_type,xmlNodePtr node)
    8.32 +{
    8.33 +    xmlNodePtr field,cur;
    8.34 +    xmlAttrPtr attr;
    8.35 +    xmlChar *name=NULL;
    8.36 +    xmlChar *field_name=NULL;
    8.37 +    xmlChar *text;
    8.38 +    int file_id,i;
    8.39 +    for(field=node->xmlChildrenNode;field;field=field->next)
    8.40 +	if (!xmlStrcmp(field->name,(const xmlChar *)"field"))
    8.41 +	{
    8.42 +	    for(attr=field->properties;attr;attr=attr->next)
    8.43 +		if (!xmlStrcmp(attr->name,(const xmlChar *)"name"))
    8.44 +		{
    8.45 +		    name=xmlNodeListGetString(doc,attr->children,1);
    8.46 +		    if (!xmlStrcmp(name,(const xmlChar *)"field_name"))
    8.47 +			field_name=xmlNodeListGetString(doc,field->children,1);
    8.48 +		    if (!xmlStrcmp(field_name,(const xmlChar *)"File Added") &&
    8.49 +		      !xmlStrcmp(name,(const xmlChar *)"old_value"))
    8.50 +		    {
    8.51 +			text=xmlNodeListGetString(doc,field->children,1);
    8.52 +			if (sscanf(text,"%d",&file_id)==1)
    8.53 +			{
    8.54 +			    for(i=NO_ELEMS(artifact_types)-1;i>=0;i--)
    8.55 +				if (!strcmp(artifact_types[i].name,
    8.56 +				  (const char *)artifact_type))
    8.57 +				    break;
    8.58 +			    if (i>=0)
    8.59 +				printf("%d %s %d\n",
    8.60 +				  artifact_types[i].id,artifact_id,file_id);
    8.61 +			    else
    8.62 +				fprintf(stderr,
    8.63 +				  "Warning: Unknown artifact type \"%s\" - "
    8.64 +				  "attached file %s ignored\n",
    8.65 +				  artifact_type,text);
    8.66 +			}
    8.67 +			xmlFree(text);
    8.68 +		    }
    8.69 +		    xmlFree(name);
    8.70 +		}
    8.71 +	}
    8.72 +    if (field_name)
    8.73 +	xmlFree(field_name);
    8.74 +}
    8.75 +
    8.76 +void parse_artifact(xmlDocPtr doc,xmlNodePtr node)
    8.77 +{
    8.78 +    xmlNodePtr field,cur;
    8.79 +    xmlAttrPtr attr;
    8.80 +    xmlChar *name=NULL;
    8.81 +    xmlChar *id=NULL;
    8.82 +    xmlChar *type=NULL;
    8.83 +    xmlChar *text;
    8.84 +    for(field=node->xmlChildrenNode;field;field=field->next)
    8.85 +	if (!xmlStrcmp(field->name,(const xmlChar *)"field"))
    8.86 +	{
    8.87 +	    for(attr=field->properties;attr;attr=attr->next)
    8.88 +		if (!xmlStrcmp(attr->name,(const xmlChar *)"name"))
    8.89 +		{
    8.90 +		    name=xmlNodeListGetString(doc,attr->children,1);
    8.91 +		    if (!xmlStrcmp(name,(const xmlChar *)"artifact_id"))
    8.92 +			id=xmlNodeListGetString(doc,field->children,1);
    8.93 +		    if (!xmlStrcmp(name,(const xmlChar *)"artifact_type"))
    8.94 +			type=xmlNodeListGetString(doc,field->children,1);
    8.95 +		}
    8.96 +	    if (!xmlStrcmp(name,(const xmlChar *)"artifact_history"))
    8.97 +		for(cur=field->xmlChildrenNode;cur;cur=cur->next)
    8.98 +		    if (!xmlStrcmp(cur->name,"history"))
    8.99 +			parse_history(doc,id,type,cur);
   8.100 +	    if (name)
   8.101 +	    {
   8.102 +		xmlFree(name);
   8.103 +		name=NULL;
   8.104 +	    }
   8.105 +	}
   8.106 +    if (id)
   8.107 +	xmlFree(id);
   8.108 +    if (type)
   8.109 +	xmlFree(type);
   8.110 +}
   8.111 +
   8.112 +int main(int argc,char **argv)
   8.113 +{
   8.114 +    xmlDocPtr doc;
   8.115 +    xmlNodePtr cur;
   8.116 +    doc=xmlParseFile(argv[1]);
   8.117 +    if (!doc)
   8.118 +    {
   8.119 +	fprintf(stderr,"Document not parsed successfully.\n");
   8.120 +	exit(1);
   8.121 +    }
   8.122 +    cur=xmlDocGetRootElement(doc);
   8.123 +    if (!cur)
   8.124 +    {
   8.125 +	fprintf(stderr,"Empty document.\n");
   8.126 +	xmlFreeDoc(doc);
   8.127 +	exit(1);
   8.128 +    }
   8.129 +    if (xmlStrcmp(cur->name,(const xmlChar *)"project_export"))
   8.130 +    {
   8.131 +	fprintf(stderr,"%s does not appear to be a project export document.\n",
   8.132 +	  argv[1]);
   8.133 +	xmlFreeDoc(doc);
   8.134 +	exit(1);
   8.135 +    }
   8.136 +    for(cur=cur->xmlChildrenNode;cur;cur=cur->next)
   8.137 +	if (!xmlStrcmp(cur->name,(const xmlChar *)"artifacts"))
   8.138 +	    break;
   8.139 +    if (!cur)
   8.140 +    {
   8.141 +	fprintf(stderr,"%s does not appear to contain an artifacts node.\n",
   8.142 +	  argv[1]);
   8.143 +	xmlFreeDoc(doc);
   8.144 +	exit(1);
   8.145 +    }
   8.146 +    for(cur=cur->xmlChildrenNode;cur;cur=cur->next)
   8.147 +	if (!xmlStrcmp(cur->name,(const xmlChar *)"artifact"))
   8.148 +	    parse_artifact(doc,cur);
   8.149 +    xmlFreeDoc(doc);
   8.150 +    exit(0);
   8.151 +}
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/get_users.xsl	Thu Nov 16 08:30:26 2006 +0000
     9.3 @@ -0,0 +1,39 @@
     9.4 +<?xml version="1.0"?>
     9.5 +<xsl:stylesheet version="1.0"
     9.6 +		xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     9.7 +		xmlns:exsl="http://exslt.org/common"
     9.8 +		extension-element-prefixes="exsl">
     9.9 +
    9.10 +<xsl:variable name="users">
    9.11 +  <xsl:for-each select="//artifact/field[@name='submitted_by' or @name='assigned_to']">
    9.12 +    <user><xsl:value-of select="normalize-space(.)"/></user>
    9.13 +  </xsl:for-each>
    9.14 +  <xsl:for-each select="//artifact/field[@name='artifact_history']/history/field[@name='mod_by']">
    9.15 +    <user><xsl:value-of select="normalize-space(.)"/></user>
    9.16 +  </xsl:for-each>
    9.17 +  <xsl:for-each select="//artifact/field[@name='artifact_messages']/message/field[@name='user_name']">
    9.18 +    <user><xsl:value-of select="normalize-space(.)"/></user>
    9.19 +  </xsl:for-each>
    9.20 +</xsl:variable>
    9.21 +
    9.22 +<xsl:variable name="sorted_users">
    9.23 +  <xsl:for-each select="exsl:node-set($users)/user">
    9.24 +    <xsl:sort/>
    9.25 +    <xsl:copy-of select="."/>
    9.26 +  </xsl:for-each>
    9.27 +</xsl:variable>
    9.28 +
    9.29 +<xsl:template match="/">
    9.30 +  <users>
    9.31 +    <xsl:for-each select="exsl:node-set($sorted_users)/user">
    9.32 +      <xsl:if test="not(. = following-sibling::user[1])">
    9.33 +	<user>
    9.34 +	  <xsl:value-of select="."/>
    9.35 +	  <xsl:text>@users.sourceforge.net</xsl:text>
    9.36 +	</user>
    9.37 +      </xsl:if>
    9.38 +    </xsl:for-each>
    9.39 +  </users>
    9.40 +</xsl:template>
    9.41 +
    9.42 +</xsl:stylesheet>
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/sf2bz.sh	Thu Nov 16 08:30:26 2006 +0000
    10.3 @@ -0,0 +1,109 @@
    10.4 +#!/bin/sh
    10.5 +if [ $# -ne 2 ]; then
    10.6 +    echo "Usage: sf2bz <sf-project-export>.xml <bz-import>.xml" >&2
    10.7 +    exit 1
    10.8 +fi
    10.9 +input=$1
   10.10 +output=$2
   10.11 +topdir=/home/ali/wk/slashem/web.scripts
   10.12 +cd $topdir
   10.13 +cache_dir=$topdir/cache
   10.14 +tagsoup=tagsoup/tagsoup-1.0.1.jar
   10.15 +#tmpdir=`mktemp -d /tmp/XXXXXXXX` || exit 1
   10.16 +tmpdir=/tmp/sf2bz; rm -rf $tmpdir; mkdir $tmpdir
   10.17 +mkdir -p $cache_dir/sf/artifacts
   10.18 +# Sourceforge's export is pretty good, but misses a few things.
   10.19 +# Deal with one of these (descriptions for attached files) here.
   10.20 +echo '<?xml version="1.0"?>' > $tmpdir/descriptions.xml
   10.21 +echo '<artifacts xmlns:xi="http://www.w3.org/2001/XInclude">' \
   10.22 +  >> $tmpdir/descriptions.xml
   10.23 +./get_attached_files $input | cut -s "-d " -f 1,2 | sort -n | uniq | \
   10.24 +  while read atid aid; do
   10.25 +    mkdir -p $cache_dir/sf/artifacts/$atid
   10.26 +    if [ ! -r $cache_dir/sf/artifacts/$atid/$aid.html ]; then
   10.27 +	wget -q -O $cache_dir/sf/artifacts/$atid/$aid.html \
   10.28 +	  "http://sourceforge.net/tracker/index.php?func=detail&aid=$aid&group_id=9746&atid=$atid"
   10.29 +    fi
   10.30 +    mkdir -p $cache_dir/artifacts/$atid
   10.31 +    if [ ! -r $cache_dir/artifacts/$atid/$aid.xhtml ]; then
   10.32 +	java -jar $tagsoup $cache_dir/sf/artifacts/$atid/$aid.html \
   10.33 +	  > $cache_dir/artifacts/$atid/$aid.xhtml
   10.34 +    fi
   10.35 +    echo "<xi:include href=\"$cache_dir/artifacts/$atid/$aid.xhtml\"/>" >> $tmpdir/descriptions.xml
   10.36 +done
   10.37 +echo '</artifacts>' >> $tmpdir/descriptions.xml
   10.38 +xsltproc --xinclude attachment_descs.xsl $tmpdir/descriptions.xml \
   10.39 +  > $tmpdir/attachment-descriptions.xml
   10.40 +# Some details of attachments are included in the project export.
   10.41 +xsltproc attachment_details.xsl $input > $tmpdir/attachment-details.xml
   10.42 +# Then convert the attachments to XML (as required by bugzilla)
   10.43 +# pulling in the various bits of information we have gathered.
   10.44 +mkdir -p $cache_dir/sf/attachments $cache_dir/attachments
   10.45 +mkdir -p $tmpdir/jail
   10.46 +./get_attached_files artifacts.xml | while read atid aid file_id; do
   10.47 +    if [ ! -r $cache_dir/sf/attachments/$file_id ]; then
   10.48 +	wget -N -O $cache_dir/sf/attachments/$file_id "http://sourceforge.net/tracker/download.php?group_id=9746&atid=$atid&file_id=$file_id&aid=$aid"
   10.49 +    fi
   10.50 +    if [ ! -r $cache_dir/attachments/$file_id.xml ]; then
   10.51 +	type=`file -bi $cache_dir/sf/attachments/$file_id | sed 's/;.*//'`
   10.52 +	case "$type" in
   10.53 +	    text/*)
   10.54 +		(cd $tmpdir/jail; patch --dry-run -s -f \
   10.55 +		  < $cache_dir/sf/attachments/$file_id > /dev/null 2>&1)
   10.56 +		if [ $? -lt 2 ]; then
   10.57 +		    pflag="-p"
   10.58 +		else
   10.59 +		    pflag=""
   10.60 +		fi
   10.61 +		;;
   10.62 +	    *)
   10.63 +	        pflag=""
   10.64 +		;;
   10.65 +	esac
   10.66 +	./xml_attached_file $pflag -i $file_id -t $type \
   10.67 +	  $cache_dir/sf/attachments/$file_id > $tmpdir/$file_id.1.xml
   10.68 +	xsltproc attachment_gather.xsl $tmpdir/$file_id.1.xml \
   10.69 +	  > $tmpdir/$file_id.2.xml
   10.70 +	xsltproc --xinclude attachment_post.xsl $tmpdir/$file_id.2.xml \
   10.71 +	  > $cache_dir/attachments/$file_id.xml
   10.72 +    fi
   10.73 +done
   10.74 +# We can't get hold of descriptions of deleted attachments, so we
   10.75 +# keep a copy of the file in case we need it. Ideally, we'd make sure
   10.76 +# that we only add descriptions, but that's for another day.
   10.77 +cp $tmpdir/attachment-descriptions.xml $topdir
   10.78 +xsltproc get_users.xsl $input > $tmpdir/raw_users.xml
   10.79 +echo '<artifacts xmlns:xi="http://www.w3.org/2001/XInclude">' \
   10.80 +  >> $tmpdir/users.1.xml
   10.81 +for file in $cache_dir/artifacts/*/*.xhtml; do
   10.82 +    echo "<xi:include href=\"$file\"/>" >> $tmpdir/users.1.xml
   10.83 +done
   10.84 +echo "<xi:include href=\"raw_users.xml\"/>" >> $tmpdir/users.1.xml
   10.85 +echo '</artifacts>' >> $tmpdir/users.1.xml
   10.86 +xsltproc --xinclude user_names.xsl $tmpdir/users.1.xml > $tmpdir/users.2.xml
   10.87 +mkdir -p $cache_dir/sf/users $cache_dir/users
   10.88 +echo '<sf_users xmlns:xi="http://www.w3.org/2001/XInclude">' \
   10.89 +  >> $tmpdir/users.3.xml
   10.90 +xsltproc unknown_users.xsl $tmpdir/users.2.xml | while read user; do
   10.91 +    case $user in
   10.92 +	*@users.sourceforge.net)
   10.93 +	    user_id=`echo $user | sed 's/@users.sourceforge.net$//'`
   10.94 +	    if [ ! -r $cache_dir/sf/users/$user_id.html ]; then
   10.95 +		wget -N -O $cache_dir/sf/users/$user_id.html \
   10.96 +		  "http://sourceforge.net/users/$user_id/"
   10.97 +	    fi
   10.98 +	    if [ ! -r $cache_dir/users/$user_id.xhtml ]; then
   10.99 +		java -jar $tagsoup $cache_dir/sf/users/$user_id.html \
  10.100 +		  > $cache_dir/users/$user_id.xhtml
  10.101 +	    fi
  10.102 +	    echo "<xi:include href=\"$cache_dir/users/$user_id.xhtml\"/>" \
  10.103 +	      >> $tmpdir/users.3.xml
  10.104 +    esac
  10.105 +done
  10.106 +echo "<xi:include href=\"users.2.xml\"/>" >> $tmpdir/users.3.xml
  10.107 +echo '</sf_users>' >> $tmpdir/users.3.xml
  10.108 +xsltproc --xinclude user_names.xsl $tmpdir/users.3.xml > users.xml
  10.109 +ln -s $cache_dir/attachments $tmpdir
  10.110 +xsltproc bugzilla.xsl $input > artifacts.tmp.xml
  10.111 +xsltproc --xinclude bugzilla_post.xsl artifacts.tmp.xml > $output
  10.112 +#rm -rf $tmpdir artifacts.tmp.xml
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/sf2bz.xsl	Thu Nov 16 08:30:26 2006 +0000
    11.3 @@ -0,0 +1,29 @@
    11.4 +<?xml version="1.0"?>
    11.5 +
    11.6 +<!-- A set of templates used in multiple stylesheets -->
    11.7 +
    11.8 +<xsl:stylesheet version="1.0"
    11.9 +		xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   11.10 +		xmlns:date="http://exslt.org/dates-and-times"
   11.11 +		extension-element-prefixes="date">
   11.12 +
   11.13 +<!-- Convert a UNIX-style date (seconds since 1 Jan 1970) to
   11.14 +     the timestamp format used by bugzilla: %Y-%m-%d %X -->
   11.15 +<xsl:template name="bugzilla-timestamp">
   11.16 +  <xsl:param name="secs" select="."/>
   11.17 +  <xsl:variable name="dt" select="date:add('1970',concat('PT',$secs,'S'))"/>
   11.18 +  <xsl:value-of select="date:year($dt)"/>
   11.19 +  <xsl:text>-</xsl:text>
   11.20 +  <xsl:value-of select="format-number(date:month-in-year($dt),'00')"/>
   11.21 +  <xsl:text>-</xsl:text>
   11.22 +  <xsl:value-of select="format-number(date:day-in-month($dt),'00')"/>
   11.23 +  <xsl:text> </xsl:text>
   11.24 +  <xsl:value-of select="format-number(date:hour-in-day($dt),'00')"/>
   11.25 +  <xsl:text>:</xsl:text>
   11.26 +  <xsl:value-of select="format-number(date:minute-in-hour($dt),'00')"/>
   11.27 +  <xsl:text>:</xsl:text>
   11.28 +  <xsl:value-of select="format-number(date:second-in-minute($dt),'00')"/>
   11.29 +  <xsl:text> UTC</xsl:text>
   11.30 +</xsl:template>
   11.31 +
   11.32 +</xsl:stylesheet>
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/tagsoup/SRC	Thu Nov 16 08:30:26 2006 +0000
    12.3 @@ -0,0 +1,2 @@
    12.4 +http://mercury.ccil.org/~cowan/XML/tagsoup/
    12.5 +http://mercury.ccil.org/~cowan/XML/tagsoup/tagsoup-1.0.1.jar
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/unknown_users.xsl	Thu Nov 16 08:30:26 2006 +0000
    13.3 @@ -0,0 +1,15 @@
    13.4 +<?xml version="1.0"?>
    13.5 +
    13.6 +<xsl:stylesheet version="1.0"
    13.7 +		xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    13.8 +
    13.9 +<xsl:output method="text" encoding="utf-8"/>
   13.10 +
   13.11 +<xsl:template match="//users/user[not(@name)]">
   13.12 +  <xsl:value-of select="."/>
   13.13 +  <xsl:text>&#10;</xsl:text>
   13.14 +</xsl:template>
   13.15 +
   13.16 +<xsl:template match="text()"/>
   13.17 +
   13.18 +</xsl:stylesheet>
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/user_names.xsl	Thu Nov 16 08:30:26 2006 +0000
    14.3 @@ -0,0 +1,61 @@
    14.4 +<?xml version="1.0"?>
    14.5 +
    14.6 +<xsl:stylesheet version="1.0"
    14.7 +		xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    14.8 +		xmlns:xhtml="http://www.w3.org/1999/xhtml"
    14.9 +		xmlns:exsl="http://exslt.org/common"
   14.10 +		extension-element-prefixes="exsl"
   14.11 +		exclude-result-prefixes="xhtml">
   14.12 +
   14.13 +<xsl:variable name="users">
   14.14 +  <xsl:for-each select="//users/user">
   14.15 +    <user>
   14.16 +      <xsl:copy-of select="@name"/>
   14.17 +      <xsl:value-of select="."/>
   14.18 +    </user>
   14.19 +  </xsl:for-each>
   14.20 +  <xsl:for-each select="//xhtml:td[xhtml:b='Submitted By:' and xhtml:a]">
   14.21 +    <xsl:element name="user">
   14.22 +      <xsl:attribute name="name">
   14.23 +	<xsl:for-each select="text()">
   14.24 +	  <xsl:if test="contains(., '-')">
   14.25 +	    <xsl:value-of select="normalize-space(substring-before(., '-'))"/>
   14.26 +	  </xsl:if>
   14.27 +	</xsl:for-each>
   14.28 +      </xsl:attribute>
   14.29 +      <xsl:value-of select="xhtml:a"/>
   14.30 +      <xsl:text>@users.sourceforge.net</xsl:text>
   14.31 +    </xsl:element>
   14.32 +  </xsl:for-each>
   14.33 +  <xsl:for-each select="//xhtml:table[xhtml:tr/xhtml:td[normalize-space(.)='Login Name:'] and xhtml:tr/xhtml:td[normalize-space(.)='Publicly Displayed Name:']]">
   14.34 +    <xsl:element name="user">
   14.35 +      <xsl:attribute name="name">
   14.36 +	<xsl:value-of select="normalize-space(xhtml:tr/xhtml:td[normalize-space(.)='Publicly Displayed Name:']/following-sibling::xhtml:td)"/>
   14.37 +      </xsl:attribute>
   14.38 +	<xsl:value-of select="normalize-space(xhtml:tr/xhtml:td[normalize-space(.)='Login Name:']/following-sibling::xhtml:td)"/>
   14.39 +      <xsl:text>@users.sourceforge.net</xsl:text>
   14.40 +    </xsl:element>
   14.41 +  </xsl:for-each>
   14.42 +</xsl:variable>
   14.43 +
   14.44 +<xsl:variable name="sorted_users">
   14.45 +  <xsl:for-each select="exsl:node-set($users)/user">
   14.46 +    <xsl:sort/>
   14.47 +    <xsl:copy-of select="."/>
   14.48 +  </xsl:for-each>
   14.49 +</xsl:variable>
   14.50 +
   14.51 +<xsl:template match="/">
   14.52 +  <users>
   14.53 +    <xsl:for-each select="exsl:node-set($sorted_users)/user">
   14.54 +      <xsl:if test="not(. = following-sibling::user[1])">
   14.55 +	<xsl:copy>
   14.56 +	  <xsl:copy-of select="@name"/>
   14.57 +	  <xsl:value-of select="."/>
   14.58 +	</xsl:copy>
   14.59 +      </xsl:if>
   14.60 +    </xsl:for-each>
   14.61 +  </users>
   14.62 +</xsl:template>
   14.63 +
   14.64 +</xsl:stylesheet>
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/xml_attached_file.c	Thu Nov 16 08:30:26 2006 +0000
    15.3 @@ -0,0 +1,144 @@
    15.4 +/*
    15.5 + * This program converts an attached file (which has previously been
    15.6 + * downloaded from sourceforge) into bugzilla-style XML.
    15.7 + */
    15.8 +
    15.9 +#include <stdlib.h>
   15.10 +#include <stdio.h>
   15.11 +#include <string.h>
   15.12 +#ifdef __linux__
   15.13 +#include <getopt.h>
   15.14 +#endif
   15.15 +
   15.16 +#ifdef __linux__
   15.17 +static struct option long_options[] = {
   15.18 +    {"type", 1, 0, 't'},
   15.19 +    {"id", 1, 0, 'i'},
   15.20 +    {"patch", 0, 0, 'p'},
   15.21 +    {0, 0, 0, 0}
   15.22 +};
   15.23 +
   15.24 +static char *long_option_str(char opt)
   15.25 +{
   15.26 +    int i;
   15.27 +    static char buf[100];
   15.28 +    for(i=0;long_options[i].name;i++)
   15.29 +	if (long_options[i].val==opt)
   15.30 +	{
   15.31 +	    sprintf(buf,", --%s",long_options[i].name);
   15.32 +	    return buf;
   15.33 +	}
   15.34 +    return "";
   15.35 +}
   15.36 +#else
   15.37 +#define long_option_str(opt)    ""
   15.38 +#endif
   15.39 +
   15.40 +usage()
   15.41 +{
   15.42 +    fprintf(stderr,"Usage: xml_attached_file [OPTION] file\n");
   15.43 +    fprintf(stderr,"\n");
   15.44 +    fprintf(stderr,"  -t%s=MIME-type	    MIME type to use\n",
   15.45 +      long_option_str('t'));
   15.46 +    fprintf(stderr,"  -i%s=ID	            Attachment ID to use\n",
   15.47 +      long_option_str('i'));
   15.48 +    fprintf(stderr,"  -p%s	            Mark attachment as a patch\n",
   15.49 +      long_option_str('p'));
   15.50 +    exit(1);
   15.51 +}
   15.52 +
   15.53 +/* Note that we limit line lengths to 76 characters following RFC 2045
   15.54 + * (bugzilla uses MIME::Base64). This isn't strictly compliant with RFC 4648.
   15.55 + */
   15.56 +static void base64_encode(FILE *in,FILE *out)
   15.57 +{
   15.58 +    int ng=0;		/* 76 characters == 19 groups */
   15.59 +    size_t nb;
   15.60 +    unsigned char bytes[3];
   15.61 +    const char alphabet[64]=
   15.62 +      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
   15.63 +    while ((nb=fread(bytes,1,3,in))==3)
   15.64 +    {
   15.65 +	if (ng++>=19)
   15.66 +	{
   15.67 +	    putc('\n',out);
   15.68 +	    ng=1;
   15.69 +	}
   15.70 +	putc(alphabet[bytes[0]>>2],out);
   15.71 +	putc(alphabet[(bytes[0]<<4|bytes[1]>>4)&0x3F],out);
   15.72 +	putc(alphabet[(bytes[1]<<2|bytes[2]>>6)&0x3F],out);
   15.73 +	putc(alphabet[bytes[2]&0x3F],out);
   15.74 +    }
   15.75 +    if (nb)
   15.76 +    {
   15.77 +	if (ng>=19)
   15.78 +	    putc('\n',out);
   15.79 +	putc(alphabet[bytes[0]>>2],out);
   15.80 +	if (nb==2)
   15.81 +	{
   15.82 +	    putc(alphabet[(bytes[0]<<4|bytes[1]>>4)&0x3F],out);
   15.83 +	    putc(alphabet[bytes[1]<<2&0x3F],out);
   15.84 +	}
   15.85 +	else
   15.86 +	{
   15.87 +	    putc(alphabet[bytes[0]<<4&0x3F],out);
   15.88 +	    putc('=',out);
   15.89 +	}
   15.90 +	putc('=',out);
   15.91 +    }
   15.92 +}
   15.93 +
   15.94 +int main(int argc,char **argv)
   15.95 +{
   15.96 +    int c;
   15.97 +    FILE *fp;
   15.98 +    unsigned long id=0;
   15.99 +    int ispatch=0;
  15.100 +    char *type=NULL;
  15.101 +    for(;;)
  15.102 +    {
  15.103 +#ifdef __linux__
  15.104 +	int option_index=0;
  15.105 +	c=getopt_long(argc,argv,"t:i:p",long_options,&option_index);
  15.106 +#else
  15.107 +	c=getopt(argc,argv,"t:i:p");
  15.108 +#endif
  15.109 +	if (c<0)
  15.110 +	    break;
  15.111 +	switch(c)
  15.112 +	{
  15.113 +	    case 't':
  15.114 +		type=optarg;
  15.115 +		break;
  15.116 +	    case 'i':
  15.117 +		id=strtoul(optarg,NULL,10);
  15.118 +		break;
  15.119 +	    case 'p':
  15.120 +		ispatch=1;
  15.121 +		break;
  15.122 +	    default:
  15.123 +		usage();
  15.124 +	}
  15.125 +    }
  15.126 +    if (optind<argc)
  15.127 +    {
  15.128 +	fp=fopen(argv[optind],"rb");
  15.129 +	if (!fp)
  15.130 +	{
  15.131 +	    perror(argv[optind]);
  15.132 +	    exit(1);
  15.133 +	}
  15.134 +    }
  15.135 +    else
  15.136 +	fp=stdin;
  15.137 +    printf("<attachment ispatch=\"%d\">\n",ispatch);
  15.138 +    if (id)
  15.139 +	printf("  <attachid>%lu</attachid>\n",id);
  15.140 +    if (type)
  15.141 +	printf("  <type>%s</type>\n",type);
  15.142 +    printf("  <data encoding=\"base64\">\n");
  15.143 +    base64_encode(fp,stdout);
  15.144 +    printf("\n  </data>\n");
  15.145 +    printf("</attachment>\n");
  15.146 +    exit(0);
  15.147 +}