<?xml version="1.0" encoding="utf-8"?>
<feed version="0.3" xmlns="http://purl.org/atom/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="en">
<title>Solid Wall of Code</title>
<link rel="alternate" type="text/html" href="http://blog.thought-mesh.net/solidwallofcode/" />
<modified>2007-06-02T20:38:07Z</modified>
<tagline>Notes about open source software</tagline>
<id>tag:blog.thought-mesh.net,2008:/solidwallofcode/2</id>
<generator url="http://www.movabletype.org/" version="3.34">Movable Type</generator>
<copyright>Copyright (c) 2007, aog</copyright>
<entry>
<title>MT Patch: Auto Disable POST Button</title>
<link rel="alternate" type="text/html" href="http://blog.thought-mesh.net/solidwallofcode/mt_projects/mt_patch_auto_d.php" />
<modified>2007-06-02T20:38:07Z</modified>
<issued>2007-06-02T14:05:19Z</issued>
<id>tag:blog.thought-mesh.net,2007:/solidwallofcode/2.2251</id>
<created>2007-06-02T14:05:19Z</created>
<summary type="text/plain">Introduction One source of duplicate comments for Movable Type is users hitting the &amp;#8220;POST&amp;#8221; button multiple times, either through a key bounce or because of slow response. One amelorative option is to arrange for the &amp;#8220;POST&amp;#8221; button to be disabled...</summary>
<author>
<name>aog</name>
<url>http://blog.thought-mesh.net</url>
<email>aog@thought-mesh.net</email>
</author>
<dc:subject>MT Projects</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://blog.thought-mesh.net/solidwallofcode/">
<![CDATA[<h1>Introduction</h1>

<p>One source of duplicate comments for <a href="http://movabletype.org">Movable Type</a> is users hitting the &#8220;POST&#8221; button multiple times, either through a key bounce or because of slow response. One amelorative option is to arrange for the &#8220;POST&#8221; button to be disabled before the comment data is submitted. This not only avoids duplicates in most situations but is useful feedback to the user that, yes, they did in fact push the button.</p>

<h1>Solution</h1>

<p>This turns out to be a bit trickier than it seems, because some browsers won&#8217;t send data from disabled objects. This is a problem because the &#8220;POST&#8221; button contains critical information needed to process the comment request. It is not sufficient to simply move that to a hidden object, because that will cause problems for &#8220;PREVIEW&#8221;. My solution is to have a hidden object and engage in a bit of object renaming during the disable process. I have tested this on IE 6, IE 7, FireFox 1.5, FireFox 2, Opera 8 and Opera 9, and it seems to work.</p>

<p>This is the JavaScript enhanced &#8220;POST&#8221; button and hidden object. It replaces the existing &#8220;POST&#8221; button.</p>

<pre><code>&lt;input type=&quot;hidden&quot; name=&quot;mode&quot; value=&quot;mode&quot; /&gt;
&lt;input type=&quot;submit&quot; name=&quot;post_comment&quot; id=&quot;post_comment&quot; value=&quot;&amp;nbsp;POST&amp;nbsp;&quot;
  onclick=&quot;document.comments_form.post_comment.disabled=true;
           document.comments_form.mode.name = 'post';
           document.comments_form.onsubmit();
           document.comments_form.submit();&quot;
/&gt;</code></pre>

<p>The Javascript disables the button, renames the &#8220;mode&#8221; object to &#8220;post&#8221; to put that as data in the submit, executes any other JavaScript expected to run on submit, and finally submits the form.</p>

<h1>Installation</h1>

<p>You will need to modify every template that accepts user comments. This will generally be the individual archive template and the preview comment template. It may also be the comment error tempate and the comment popup template.</p>

<p>You will need to modify the name of the <code>FORM</code> tag for comment submission. By default it is named &#8220;form&#8221; and this can cause hard to diagnose name collision problems. The actual name doesn&#8217;t matter, it is just important that it is unique. Use all lower case letters and underscores, nothing else. As you can see above, I renamed mine &#8220;comments_form&#8221;. I recommend doing the same unless you have a specific reason to use something else. When changing the name, change both the <code>name</code> and <code>id</code> tag and give them the same value<sup><a href="http://blog.thought-mesh.net/solidwallofcode/mt_projects/mt_patch_auto_d.php#fn1">1</a></sup>.</p>

<p>Once you&#8217;ve renamed the form, replace the current &#8220;POST&#8221; button with the lines quoted above. Change any instances of &#8220;comments_form&#8221; with the name you used for the <code>FORM</code> tag if that is different.</p>

<h1>Notes</h1>


<ul>
<li>The <code>name</code> attribute for the &#8220;POST&#8221; button must not be &#8220;post&#8221; as it is in the default template.</li>
<li>The <code>id</code> attribute value for the &#8220;POST&#8221; button  should be the same as the <code>name</code> attribute value.</li>
<li>The <code>id</code> attribute value and the <code>name</code> attribute value for the <code>FORM</code> tag should be identical. This must also match the name following &#8220;document&#8221; in the JavaScript.</li>
<li>You can set the <code>value</code> attribute of the &#8220;POST&#8221; button to whatever you like &#8212; it has no effect on submitting comments, it is used only as the displayed text in the button.</li>
</ul>



<p><hr class="fn" align="left" /></p>

<p id="fn1"><sup>1</sup> This is because some browsers like the <code>name</code> attribute and some like the <code>id</code> attribute. There&#8217;s no good reason to not do both except for the extra typing.</p>]]>

</content>
</entry>
<entry>
<title>MT 3.3 Patch: Trackback By Name</title>
<link rel="alternate" type="text/html" href="http://blog.thought-mesh.net/solidwallofcode/trackback_by_name_3_3.php" />
<modified>2006-09-26T15:23:43Z</modified>
<issued>2006-09-26T14:09:03Z</issued>
<id>tag:blog.thought-mesh.net,2006:/solidwallofcode/2.1952</id>
<created>2006-09-26T14:09:03Z</created>
<summary type="text/plain">Overview The trackback API for Movable Type starting with version 3.2 uses the internal numeric ID of the trackback object as the key. This has two problems: There is no relationship between the trackback key and information in an entry,...</summary>
<author>
<name>aog</name>
<url>http://blog.thought-mesh.net</url>
<email>aog@thought-mesh.net</email>
</author>

<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://blog.thought-mesh.net/solidwallofcode/">
<![CDATA[<h2>Overview</h2>

<p>The trackback API for <a href="http://movabletype.org">Movable Type</a> starting with version 3.2 uses the internal numeric ID of the trackback object as the key. This has two problems:</p>


<ul>
<li>There is no relationship between the trackback key and information in an entry, making clever URL rewriting infeasible.</li>
<li>It is an easy target for junkers, who can trivially guess valid values.</li>
</ul>



<p>This was unavoidable in previous versions of <a href="http://movabletype.org">Movable Type</a>, but with the release of 3.2 and its use of globally unique &#8220;basenames&#8221; for entries, we can do better.</p>

<p>This modification changes the trackback API to use identifying strings instead of numerics as the trackback key. The trackback object identifiers become completely internal (as was done for entry identifiers in 3.2). This overcomes both of the issues listed above.</p>

<p>This project is deployed on multiple several production weblogs, including this one. You can test it out by doing a trackback to this entry using the URL in the &#8220;Trackback URL&#8221; link below, or using the URL for this entry with &#8220;/ping&#8221; appended. Please put text that indicates a test if you do test it, so I can clean those out.</p>

<p><span style="color:red;">NB</span>: This modification explicitly forbids the use of numeric trackback ids. If installed and followed with a complete rebuild, this should not affect legitimate weblogs as the trackback URLs are pulled from your webpages, which will have the new, correct trackback URLs in it.</p>

<h2>Notes</h2>

<p>This patch is for the 3.3 release of <a href="http://movabletype.org">Movable Type</a>. There is a <a href="http://blog.thought-mesh.net/solidwallofcode/movable_type/mt_32_patch_tra.php">separate patch for version 3.2</a>.</p>

<h2>Implementation</h2>

<p>Two files in the base distribution must be modified. You can pick up the modified versions of the  3.32 files <a href="http://orbital-mind-control-laser.net/resources/mt-trackback-mod-3-3-2.zip">here</a> or, if you&#8217;re paranoid like me, you can do the modifications yourself. Once the files have been modified, you will need to a full rebuild to update all of the trackback URLs. At that point the modified trackback API should be fully operational.</p>

<h2>Trackback.pm Modification</h2>

<p>The <code>lib/MT/App/Trackback.pm</code> file must be modified. Note that there are two files named <code>Trackback.pm</code> in the distribution, be sure to edit the correct one.</p>

<p>Replace the subroutine <code>_get_params</code> at line 98 with the following subroutine &#8212;</p>


<pre style="border:1px solid black;">
sub _get_tb {
    my $app = shift;
    my ($tb, $pass); # Trackback object and password to return
    my ($key, $name); # local vars for internal computations
    my ($entry, $cat); # Target object of trackback.
    if (my $pi = $app-&gt;path_info) {
        $pi =~ s!^/!!; # drop leading slash
        my $tbscript = $app-&gt;config('TrackbackScript');
        $pi =~ s!.*\Q$tbscript\E/!!;
        ($key, $name, $pass) = split /\//, $pi;
        if ($key =~ m/\d+/) {
            $app-&gt;error($app-&gt;translate(
                'Numeric trackback IDs are no longer accepted'));
        } elsif (lc($key) eq 'entry') {
            require MT::Entry;
            $name =~ s/\..*$//; # strip any extension
            if ($entry = MT::Entry-&gt;load({ basename =&gt; $name, status =&gt; MT::Entry::RELEASE() })) {
                $tb = MT::Trackback-&gt;load({ entry_id =&gt; $entry-&gt;id});
                $app-&gt;error($app-&gt;translate(
                    'No trackbacks for entry with basename [_1]', $name))
                    if not $tb;
            } else {
                $app-&gt;error($app-&gt;translate('No entry with basename [_1]', $name));
            }
        } elsif ($key =~ m/^cat/i) {
            require MT::Category;
            if ($cat = MT::Category-&gt;load({ label =&gt; $name })) {
                $tb = MT::Trackback-&gt;load({ category_id =&gt; $cat-&gt;id });
                $app-&gt;error($app-&gt;translate(
                    'No trackbacks for category with label [_1]', $name))
                    if not $tb;
            } else {
                $app-&gt;error($app-&gt;translate(
                    'No category with label [_1]', $name));
            }
        } else {
            $app-&gt;error($app-&gt;translate(
                'Invalid trackback target key [_1]', $key));
        }
    } else {
        $app-&gt;error($app-&gt;translate(
          'Track request URL incorrectly formatted.
           The trackback target path information was missing'));
    }
    ($tb, $pass, $entry, $cat);
}
</pre>



<p>In subroutine <code>ping</code> around line 147.</p>

<p>Line 152 &#8212; change</p>

<pre style="border:1px solid black;">
    my($tb_id, $pass) = $app-&gt;_get_params;
    return $app-&gt;_response(Error =&gt;
        $app-&gt;translate(&quot;Need a TrackBack ID (tb_id).&quot;))
        unless $tb_id;

    require MT::Trackback;
    my $tb = MT::Trackback-&gt;load($tb_id)
        or return $app-&gt;_response(Error =&gt;
            $app-&gt;translate(&quot;Invalid TrackBack ID '[_1]'&quot;, $tb_id));
</pre>

<p>to</p>

<pre style="border:1px solid black;">
    my($tb, $pass, $entry, $cat) = $app-&gt;_get_tb;
    return $app-&gt;_response(Error =&gt; $app-&gt;errstr) unless $tb;
</pre>

<p>Line 178 &#8212; change</p>

<pre style="border:1px solid black;">
    my($blog_id, $entry, $cat);
    if ($tb-&gt;entry_id) {
        require MT::Entry;
        $entry = MT::Entry-&gt;load({ id =&gt; $tb-&gt;entry_id, status =&gt; MT::Entry::RELEASE() });
        if (!$entry) {
            return $app-&gt;_response(Error =&gt;
                $app-&gt;translate(&quot;Invalid TrackBack ID '[_1]'&quot;, $tb_id));
        }
    } elsif ($tb-&gt;category_id) {
        require MT::Category;
        $cat = MT::Category-&gt;load($tb-&gt;category_id);
    }
    $blog_id = $tb-&gt;blog_id;
</pre>

<p>to</p>

<pre style="border:1px solid black;">
    my $blog_id = $tb-&gt;blog_id;
</pre>

<p>Line 209 &#8212; change</p>

<pre style="border:1px solid black;">
    no_utf8($tb_id, $title, $excerpt, $url, $blog_name);
</pre>

<p>to</p>

<pre style="border:1px solid black;">
    no_utf8($title, $excerpt, $url, $blog_name);
</pre>

<p>Line 209 &#8212; change</p>

<pre style="border:1px solid black;">
        $ping-&gt;tb_id($tb_id);
</pre>

<p>to</p>

<pre style="border:1px solid black;">
        $ping-&gt;tb_id($tb-&gt;id);
</pre>



<p>Subroutine <code>rss</code>, around line 423.</p>

<p>Line 426 &#8212; change</p>

<pre style="border:1px solid black;">
    my($tb_id, $pass) = $app-&gt;_get_params;
    my $tb = MT::Trackback-&gt;load($tb_id)
        or return $app-&gt;_response(Error =&gt;
            $app-&gt;translate(&quot;Invalid TrackBack ID '[_1]'&quot;, $tb_id));
</pre>

<p>to</p>

<pre style="border:1px solid black;">
    my ($tb, $pass) = $app-&gt;_get_tb;
    return $app-&gt;_response(Error =&gt; $app-&gt;errstr) unless $tb;
</pre>



<p>Subroutine <code>blog</code> around line 465.</p>

<p>Line 423 &#8212; change</p>

<pre style="border:1px solid black;">
    if (my ($tb_id) = $app-&gt;_get_params()) {
        require MT::Trackback;
        my $tb = MT::Trackback-&gt;load($tb_id);
        return undef unless $tb;
        $app-&gt;{_blog} = MT::Blog-&gt;load($tb-&gt;blog_id) if $tb;
    }
</pre>

<p>to</p>

<pre style="border:1px solid black;">
    if (my ($tb) = $app-&gt;_get_tb()) {
        return undef unless $tb;
        $app-&gt;{_blog} = MT::Blog-&gt;load($tb-&gt;blog_id);
    }
</pre>



<h2>ContextHandlers.pm Modification</h2>

<p>The file <code>lib/MT/Template/ContextHandlers.pm</code> should be modified. This is not strictly required, but if this is not done then you will have to construct all trackback related data by hand in the templates rather than using the standard tags.</p>

<p>Changes to <code>lib/MT/Template/ContextHandlers.pm</code></p>

<p>Line 1820 &#8212; change</p>


<pre style="border:1px solid black;">
$path . $cfg-&gt;TrackbackScript . '/' . $tb-&gt;id;
</pre>



<p>to</p>


<pre style="border:1px solid black;">
$path . $cfg-&gt;TrackbackScript . '/entry/' . $e-&gt;basename;
</pre>



<p>Line 1832 &#8212; Change</p>


<pre style="border:1px solid black;">
$path .= $cfg-&gt;TrackbackScript . '/' . $tb-&gt;id;
</pre>



<p>to</p>


<pre style="border:1px solid black;">
$path .= $cfg-&gt;TrackbackScript . '/entry/' . $e-&gt;basename;
</pre>



<p>Line 3381 &#8212; change</p>


<pre style="border:1px solid black;">
$path . $cfg-&gt;TrackbackScript . '/' . $tb-&gt;id;
</pre>



<p>to</p>


<pre style="border:1px solid black;">
$path . $cfg-&gt;TrackbackScript . '/cat/' . $cat-&gt;label;
</pre>



<h2>Other Notes, Techniques and Caveats</h2>

<p>There are several things to keep in mind once this modification is installed.</p>

<h3 id="friendly_tb_url">Friendly trackback URLs</h3>

<p>One of the drivers for this modification was a request for &#8220;friendlier&#8221; trackback URLs. In particular, the desire was to be able to have other weblogs link via trackback to a post by using the URL of the post with &#8220;/ping&#8221; appended as the trackback URL. This requires</p>


<ul>
<li>Installing this modification</li>
<li>An Apache webserver</li>
<li>Access to the Apache configuration file or <code>.htaccess</code> files to enable <a href="http://www.modrewrite.com/">mod_rewrite</a></li>
</ul>



<p>Also note that this works only for individual archives.</p>

<p>To set it up, in the top level directory for the individual archives, place text like the following in a <code>.htaccess</code> file:</p>



<pre style="border:1px solid black;padding-left:1em;">
RewriteEngine On

# Support trackback pings by appending &quot;/ping&quot; to an individual archive URL.
RewriteRule /([^/]+)/ping$ /cgi-bin/mt/mt-tb.cgi/entry/$1
</pre>



<p>You need to make sure that the path &#8220;<code>/cgi-bin/mt/mt-tb.cgi/</code>&#8221; is correct for your installation. This is easy to find, simply look at your current trackback URL.</p>

<p>In theory, this should be easily extensible to supporting category trackback pings, although I never use categories so I have not experimented on it directly yet. Note that the URL must be of the form &#8220;&#8230;/cat/&#8230;&#8221; instead of &#8220;&#8230;/entry/&#8230;&#8221; for category trackbacks.</p>

<p><span style="color:red;">NB</span>: The name logic for trackbacks automatically strips extensions, so that you can use both &#8220;my_cool_post&#8221; and &#8220;my_cool_post.html&#8221; as the name for the trackback URL. This was done to support this technique.</p>

<h3>Trackback URL display</h3>

<p>One effect of this modification is to make the trackback URLs noticeably longer. This can cause problems with formatting, particularly of popups. What I have done is change explicit display of the trackback URLs to a link with the link text &#8220;Trackback URL&#8221;. The reader can then either right-click and use the &#8220;copy this link&#8221; option (available in FireFox, IE and Opera) or use the <a href="#friendly_tb_url">&#8220;friendlier&#8221;</a> trackback URLs.</p>

<p><em>This project originally inspired by <a href="http://www.sixapart.com/mailman/private/pronet/2006-March/004269.html">a request from Sherwin Techico</a> on the <a href="http://www.sixapart.com/mailman/listinfo/pronet">ProNet</a> mailing list</em></p>]]>

</content>
</entry>
<entry>
<title>MTTacFeed</title>
<link rel="alternate" type="text/html" href="http://blog.thought-mesh.net/solidwallofcode/mt_projects/mttacfeed.php" />
<modified>2007-09-02T21:23:17Z</modified>
<issued>2006-05-14T23:40:08Z</issued>
<id>tag:blog.thought-mesh.net,2006:/solidwallofcode/2.1802</id>
<created>2006-05-14T23:40:08Z</created>
<summary type="text/plain">Introduction MTTacFeed (MTTF) is a plugin to create feeds from the comments and trackbacks of a Movable Type weblog. &amp;#8220;TacFeed&amp;#8221; can be read as &amp;#8220;Trackbacks and Comment Feed&amp;#8221; or &amp;#8220;Tactical Feed&amp;#8221;, which isn&amp;#8217;t as mnemnonic but sounds cooler. The fundamental...</summary>
<author>
<name>aog</name>
<url>http://blog.thought-mesh.net</url>
<email>aog@thought-mesh.net</email>
</author>
<dc:subject>MT Projects</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://blog.thought-mesh.net/solidwallofcode/">
<![CDATA[<h1>Introduction</h1>

<p>MTTacFeed (MTTF) is a plugin to create feeds from the comments and trackbacks of a <a href="http://movabletype.org">Movable Type</a> weblog. &#8220;TacFeed&#8221; can be read as &#8220;Trackbacks and Comment Feed&#8221; or &#8220;Tactical Feed&#8221;, which isn&#8217;t as mnemnonic but sounds cooler.</p>

<p>The fundamental operation of TacFeed is to first <em>select</em> a set of objects, then <em>order</em> those objects for display. The objects are usually comments, but can also be trackback pingss and entries. The ability to order the objects is the real meat of TacFeed. A variety of different properties are available for sorting, the objects can be sorted on an arbitrary set of properties, and the display code can check for differences in properties between adjacent objects to generate headers and footers.</p>

<p>Excited? Well, read on anyway. </p>

<p>Note: This plugin is currently under development and not ready for deployment to weblogs that I don&#8217;t administer.</p>

<h1>Usage</h1>

<p>The primary tag for MTTacFeed is the MTTacFeed tag<sup><a href="http://blog.thought-mesh.net/solidwallofcode/mt_projects/mttacfeed.php#fn1">1</a></sup>. This is a container tag that selects, orders, then iterates over the objects. It is vitally important to keep in mind that selecting and ordering two operations are distinct &#8212; once an object is selected, it will be iterated over by the container. The selection doesn&#8217;t care what order is later put on the objects, and the ordering doesn&#8217;t care how the objects were selected.</p>

<p>All other tags for this plugin are used during the iteration, inside the MTTacFeed tag.</p>

<h2>MTTacFeed</h2>

<p>The purpose of MTTacFeed is to select feedback objects, comments or trackback pings. The container tag has attributes to control this selection. Related to the feedback objects selected is the set of entries to which those objects are associated. This is termed the <em>entry selection set</em> because we&#8217;ll be talking about it quite a bit.</p>

<h3>Generalities</h3>

<p>The entry selection set can be implicit, explicit, or both. Feedback objects can be selected based on their own properties (making the entry selection set implicit) or based on properties of the entries (making the entry selection set explicit), or both (making the situation confusing).</p>

<p>After selecting the objects, the objects are ordered. Doing this requires two concepts, <em>metrics</em> and <em>axes</em>. A metric is a way of measuring a property. Ultimately, all ordering in MTTacFeed depends on being able to order the values of a property<sup><a href="http://blog.thought-mesh.net/solidwallofcode/mt_projects/mttacfeed.php#fn2">2</a></sup> and uses the term &#8220;metric&#8221; to describe this. A specific instance of using a metric to order the objects is called an <em>axis</em>. The ordering of the objects is done by a set of axes, each of which has an associated metric.</p>

<p>This is analogous to drawing graphs. For example, one might have &#8220;number of readers&#8221; and &#8220;dollars per year&#8221; as metrics. One could then use those to create a graph of various weblogs by putting using &#8220;number of readers&#8221; along one axis and &#8220;dollars per year&#8221; along another axis. While the metrics are clearly related to the axes, they are not the same thing and it&#8217;s important to keep them distinct.</p>

<p>MTTacFeed metrics are always discrete, not continuous. Because of this, it will usually be the case that multiple objects will have the same value for a metric. In that case, MTTacFeed will consider them <em>equivalent</em> for that metric and will put them in an arbitrary (undefined) order along an axis using that metric. Rather than being a problem, MTTacFeed depends on this feature and is designed to take advantage of it.</p>

<p>Axes in MTTacFeed are always nested. There is an outermost axis, inside of which is an inner axis, inside of that a more inner axis, etc. to any desired depth. The outermost axis groups the objects by its metric. Each of those groups is then internally ordered by the next inner axis. This process continues, each grouping being sub-grouped by the next inner axis to the innermost axis. It is this which gives MTTacFeed its power and it wouldn&#8217;t work if the outermost axis completely determined the order of the objects.</p>

<p>The last concept needed is that of an <em>edge</em>, which is the change in value of a metric from one object to another. These are the same thing as group boundaries along an axis, but &#8220;edge&#8221; is shorter to type. MTTacFeed also distinguishes between a <em>trailing edge</em> and a <em>leading edge</em>. The former is change between the current object in the iteration and the previous object, while the latter is a change between the current object and the next object. Note that one object&#8217;s leading edge is the next object&#8217;s trailing edge. The use of the term &#8220;edge&#8221; means a change without reference to a particular object. However, in actual use any template code will be processed with regard to a specific object during the iteration, so that in practice the template code must deal with leading and trailing edges.</p>

<h3 id="illustration">Illustation</h3>

<p>With the generalities as a background we will consider an example. This is just to illustrate the generalities, which can be difficult for non-math geeks to graph. A more extensive set of examples is provided elsewhere.</p>

<p>Suppose we wanted to display the set of recent comments on a weblog. We don&#8217;t want just a flat list<sup><a href="http://blog.thought-mesh.net/solidwallofcode/mt_projects/mttacfeed.php#fn3">3</a></sup>. What we would like is to have a section for each day, then under that a title for each entry that was commented on that day, with the comments grouped under that oldest to newest. In MTTacFeed terms, that would be three axes, using the metrics &#8220;day&#8221;, &#8220;entry ID&#8221;, and &#8220;comment ID&#8221;. MTTacFeed would order by day, putting the comments for each day in an arbitrary order. Each day would then be ordered by the entry, and for each entry by the comment ID. The ability to detect edges lets us put the desired titles in. We can put in a day label for every edge in the &#8220;day&#8221; axis, and an entry title for each edge in the &#8220;entry ID&#8221; axis.</p>

<p>The purpose of MTTacFeed is to create this kind of ordering easily so that feeds can be customized for various purposes without having to write Perl code to do it for each feed.</p>

<h3>Time</h3>

<p>Time isn&#8217;t a new concept, but MTTacFeed handles it in a slightly different way.</p>

<p>The most important point is that MTTacFeed has two types of time, &#8220;absolute time&#8221; and &#8220;span time&#8221;. Absolute time could also be called &#8220;calendar&#8221; time. The difference between these two is where the edges are. Absolute time edges are always aligned with the calendar or clock. E.g., the &#8220;day&#8221; metric from the previous example would have edges at the same points in time as a calendar as an absolute time. Span time, in contrast, has its edges based on the current time, each edge a particular span of time before then without regard to anything else. E.g., &#8220;this day&#8221; is the same calendar day for absolute time, and within 24 hours of the current time for span time. Both of these are useful and so both are supported.</p>

<p>MTTacFeed accepts time specifications in two formats. The first is the standard <a href="http://movabletype.org">Movable Type</a> timestamp, 14 digits of the form YYYYMMDDHHMMSS. Such a specification is always absolute time. The other form, a timespec, is a sequence of digits and letters, the letters selected from this <strong>case sensitive</strong> list &#8212;</p>

<table class="lined" style="padding-left:1em" cellspacing="0"><tr style="font-weight:bold;"><td>Letter</td><td>Time Period</td></tr><tr class="a"><td>s</td><td>Second</td></tr><tr class="b"><td>m</td><td>Minute</td></tr><tr class="a"><td>h</td><td>Hour</td></tr><tr class="b"><td>D</td><td>Day</td></tr><tr class="a"><td>W</td><td>Week</td></tr><tr class="b"><td>M</td><td>Month</td></tr><tr class="a"><td>Y</td><td>Year</td></tr></table>

<p>The leading digits are treated a number specifying the number of time units indicated by the letter. The digits can have a leading dash to indicate a negative number. For example, &#8220;1Y&#8221; means &#8220;one year&#8221;. &#8220;1W1D&#8221; means &#8220;a week and a day&#8221;, which is the same as &#8220;8D&#8221;. 90 minutes can be &#8220;1h30m&#8221; or &#8220;90m&#8221; or &#8220;2h-30m&#8221; or &#8220;5400s&#8221;. Span time is always specified as a timespec, but a timesec can be used in other situations. Unless otherwise noted, any place a &#8220;time&#8221; is needed can be specified as either a timestamp or a timespec.</p>

<h3>Attributes</h3>

<p>The MTTacFeed tag has the following attributes:</p>

<dl>
<dt>after</dt>
<dd>Specifies the earliest time for a selected object &#8212; only select objects <em>after</em> this time. If omitted it is taken to be earlier than the earliest object.</dd>
<dt>axes</dt>
<dd>Specifies the set of axes for iteration. <a href="#axis_defintion">More detail</a></dd>
<dt>base_entries</dt>
<dd>Specify the entry selection set. Regardless of any other attribute, only feedback objects with associated entries that are members of the set of entries specified by this attribute will be seleted. <a href="#entry_specifiers">More detail</a></dd>
<dt>before</dt>
<dd>Specifies the latest time for a selected object &#8212; only select objects <em>before</em> this time. If omitted it is taken to be later than the current time.</dd>
<dt>count</dt>
<dd>The maximum number of objects to select. This attribute does not select any objects but simply puts an upper bound on the number of objects selected by other attributes. There is no guarantee that this many objects will be selected. If exactly one of <code>after</code> or <code>before</code> is specified, then objects are discarded from opposite direction. Otherwise, the earlier objectts are discarded. Error: <a href="http://blog.thought-mesh.net/solidwallofcode/mt_projects/wikivar.php" title="Support for Wiki-like variables">WikiVar</a> &#8220;note&#8221; not defined</dd>
<dt>include_entries</dt>
<dd>Specifies entries to include in the set of objects. This has no effect on which feedback objects are selected. <a href="#entry_specifiers">More detail</a></dd>
<dt>type</dt>
<dd>Specifies the types of objects to automatically select. If the value contains the letter &#8220;t&#8221; or &#8220;p&#8221; then trackback pings are selected. If the value contains the letter &#8220;c&#8221; then comments are seleted. Entries are included only if specifically requested via the <code>include_entries</code> attribute and so are not specified here.</dd>
</dl>


<p><code>count</code> is generically useful, particularly to limit the size of the output. <code>offset</code> is useful in conjuction with paging and other techniques that require successive chunks of comments. <code>after</code> and <code>before</code> allow specific time ranges to be selected.</p>

<h3 id="axis_definition">Axis Definition</h3>

<p>Each axis in the <code>axes</code> attribute is separated by a semi-colon and is of the form</p>

<p align="center"><em>metric</em> &#91; <strong>&#40;</strong> <em>parameter-list</em> <strong>&#41;</strong> &#93; &#91; <strong>=</strong> <em>name</em> &#93;</p>

<p>The option list and name are optional, as indicated by the &#91;&#93;s. If there are multiple parameters, they must be separated by commas. Any leading or trailing white space is stripped and then numeric entities are converted to the characters they represent before processing. This can be used to include commas, leading spaces, or quotes in the parameters.</p>

<p><dl>
<dt>id</dt><dd>Internal object numeric identifier.</dd>
<dt>entry</dt><dd>The internal numeric identifier of the associated entry.</dd>
<dt>span</dt><dd>A time span. This has a required timespec parameter, which specifies the length of the time span. The current time is always a boundary, with other boundaries at multiples of the specified interval away.</dd>
<dt>time</dt><dd>Absolute time. This has a required timespec parameter. The boundaries are set at the natural boundaries for the timespec as close to the current time as possible.</dd>
<dt>author</dt><dd>The author of the object.</dd>
</dl></p>

<p>All metrics take an optional parameter of &#8216;reverse&#8217;, which reverses the ordering.</p>

<p>Each axis can be named so that it can be referenced by other MTTacFeed tags. If not specified, the axis is named the same as its metric. Names must be single alphanumeric words, no spaces or punctuation permitted<sup><a href="http://blog.thought-mesh.net/solidwallofcode/mt_projects/mttacfeed.php#fn4">4</a></sup>.</p>

<h3 id="entry_specifiers">Entry Specifiers</h3>

<p>The <code>base_entries</code> and <code>include_entries</code> specifiers require the selection of a set of entries. Both of these tags take (almost) the same set of specifiers, which are very similar to the <a href="#axis_definition">metric specifiers</a> used for axis definitions. The available specifiers are</p>

<dl>
<dt>author</dt>
<dd>The parameters are weblog author names. Entries with that name are selected.</dd>
<dt>lastn</dt>
<dd>The <em>n</em> more recent entries, where <em>n</em> is a number supplied as a parameter.</dd>
<dt>after</dt>
<dd>Entries after a specific time. The time is passed in as a parameter.</dd>
<dt>before</dt>
<dd>Entries before a specific time. The time is passed in as a parameter.</dd>
<dt>commented_on_by</dt>
<dd>The parameters are a list of names. The selected entries are those that have a comment by one of the names.</dd>
</dl>


<h3>Iteration</h3>

<p>After all of the object selection and ordering has been done, the <code>MTTacFeed</code> tag iterates over the objects in order. For each iteration the contents of the container are evaluated and added to the final output.</p>

<p>During an iteration, the container sets up the appropriate MT context for the object. In addition, the associated entry and weblog for the object is placed in the context so that entry and weblog based tags are available in addition to the comment or trackback (as appropriate) tags.</p>

<h2>Other Tags</h2>

<p>In addition to the top level container class, MTCatFood also provides conditional tags for controlling presentation. These are the <code>MTTacFeedFIfHeader</code>, <code>MTTacFeedIfFooter</code>, and <code>MTTacFeedIfEdge</code> tags.</p>

<p><code>MTTacFeedIfHeader</code> and <code>MTTacFeedIfFooter</code> are true if a specified axis or any outer one has an edge. <code>MTTacFeedIfHeader</code> checks for trailing edges, i.e. that the current object has a different metric value than the previous object. <code>MTTacFeedIfFooter</code> checks for a leading edge, i.e. that the current object has a different metric value from the next object. The base axis to check is specified by the <code>axis</code> attribute, which can be either the 0-based numeric index of the axis, or the name.</p>

<p>To go back to the <a href="#illustration">previous example</a>, the <code>MTTacFeed</code> container attribute <code>axes</code> would be &#8220;span(1D);entry;id&#8221;. To put a header for each day, we would use</p>

<pre><code>&lt;MTTacFeedIfHeader axis=&quot;span&quot;&gt;&lt;h1&gt;&lt;MTCommentDate&gt;&lt;/h1&gt;&lt;/MTTacFeedIfHeader&gt;</code></pre>

<p>because the current object determines the MT context and in this case it is always a comment. The container will also set up the associated entry of the comment in the context, so the entry header can be done using</p>

<pre><code>&lt;MTTacFeedIfHeader axis=&quot;entry&quot;&gt;&lt;h2&gt;&lt;MTEntryTitle&gt;&lt;/h2&gt;&lt;/MTTacFeedIfHeader&gt;</code></pre>

<p>In this case the cascading edge check insures that a new entry header will be present at the start of each day, even if the associated entry is the same as the previous comment.</p>

<p>The <code>MTTacFeedIfEdge</code> tag is more esoteric and shouldn&#8217;t be necessary for most uses. It provides the ability to trigger on any edge boundary on any set of axes. It takes two attributes, <code>header</code> and <code>footer</code>. Each of these is a sequence of axis specifiers (0-based index or name) separated by commas or spaces. The condition is true if any of the specified axes have a trailing or leading edge respectively. Only explicitly names axes are checked, there is no cascading check.</p>

<p>While the set of objects for iteration is by default only comments, it is possible to include trackback pings and entries. To handle these situations, MTTacFeed provides the <code>MTTacFeedIfComment</code>, <code>MTTacFeedIfPing</code>, and <code>MTTacFeedIfEntry</code> tags which are true if the current object is of the appropriate type.</p>

<p><hr class="fn" align="left"></p>

<p id="fn1"><sup>1</sup> The only simple and obvious thing in the entire plugin, so enjoy it while you can.</p>

<p id="fn2"><sup>2</sup> Duh! It&#8217;s <em>ordering</em>.</p>

<p id="fn3"><sup>3</sup> Or we wouldn&#8217;t be reading this documentation, would we?</p>

<p id="fn4"><sup>4</sup> Really, just how complex do you really need to make the names of the axes?</p>]]>

</content>
</entry>
<entry>
<title>MT 3.2: Junk slowdown</title>
<link rel="alternate" type="text/html" href="http://blog.thought-mesh.net/solidwallofcode/movable_type/mt_32_junk_slow.php" />
<modified>2006-04-22T16:53:58Z</modified>
<issued>2006-03-31T01:24:22Z</issued>
<id>tag:blog.thought-mesh.net,2006:/solidwallofcode/2.1746</id>
<created>2006-03-31T01:24:22Z</created>
<summary type="text/plain">Leave a slow response script in place of your renamed comment or trackback script to slow down junk attacks.</summary>
<author>
<name>aog</name>
<url>http://blog.thought-mesh.net</url>
<email>aog@thought-mesh.net</email>
</author>
<dc:subject>Movable Type</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://blog.thought-mesh.net/solidwallofcode/">
<![CDATA[<h1>Overview</h1>

<p>There are a number of junk spewing scripts out in the Internet Wilds that will pound on the default scripts for comments and trackbacks in <a href="http://movabletype.org">Movable Type</a>, regardless of whether the scripts exist or not. Many installations rename these scripts in the hopes of avoiding such junk scripts, but generally to no avail. Whether that succeeds or fails, one is left with an error log full of &#8220;404: File not found&#8221; errors. This makes it difficult to observe real problems.</p>

<p>Because of this, I decided that I would put in a replacement script that would simply accept the connection and ignore it. Then I realized that if I put a delay in that replacement script, it would slow down the junk scripts. Instead of rapidly passing over targets that are disabled, the junk script would instead spend quite a bit of time waiting uselessly, while imposing very little burden on the weblog host machine. The only way to make progress is to impose burdens on the junkers, reducing the set of them for whom this activity is profitable.</p>

<p>The point being to impose more cost on the junkers than it does on the weblog host. The junkers aren&#8217;t magical or invincible, they have their resource limits as well. While the junkers are much bigger than any single weblog, I have no doubt that in aggregate there are far more processing resources belonging to the weblog community than the junker community. Even if it just means that the junkers have to buy bigger hardware, well then they have to spend a lot of money in response to a small effort for each weblogger. That&#8217;s still a win.</p>

<h1>Implemenation (Simple)</h1>

<p>I implemented this concept and decided that it would be even better if other weblogs did the same thing, to throw ore sand in the gears of the junk machine. You can get the script <a href="http://orbital-mind-control-laser.net/resources/slow-response.zip">here</a> or cut and paste the following:</p>



<pre style="border:1px solid black;padding-left:1ex;">
#!/usr/bin/perl -w

use strict;
local $|=1; # Disable buffering

print &lt;&lt;HTML;
Content-Type: text/html

&lt;body&gt;

&lt;div style=&quot;font-size:200%;
            text-align:center;
            background:red;
            color:white;
            margin-bottom:1ex;
            &quot;&gt;
Invalid Access
&lt;/div&gt;

&lt;p style=&quot;border:2px solid red;padding:1ex;&quot;&gt;
There is no reference to this script from anywhere else on the Internet.
You can only have accessed this script by guessing its name.
There is no legitimate reason for doing that. Cease your annoying abuse.
&lt;/p&gt;

HTML

sleep 30;

print &quot;&lt;/body&gt;\n&quot;;
</pre>



<p>You can, of course, customize the message or the style. I strongly recommend against using a style sheet, as the point of this is to use minimal resources on <em>your</em> host. And really, how well designed does the page have to be?</p>

<p>To install</p>


<ol>
<li>Put the script in your MT install directory (where the <code>mt-comments.cgi</code> or <code>mt-tb.cgi</code> script was originally).</li>
<li>Edit the first line to be identical to that in your <code>mt.cgi</code> script.</li>
<li>Rename the script to <code>mt-comments.cgi</code> or <code>mt-tb.cgi</code> to replace the missing script.</li>
<li>Set the permissions to &#8220;755&#8221;.</li>
</ol>



<p>Note that this scripts works for either comments or trackbacks, since it doesn&#8217;t do anything except print and sleep. Also, only use this if you&#8217;ve renamed the original trackback and/or comment script. Do <strong>not</strong> use this as a direct replacement of either script.</p>

<p>You can see the script in operation <a href="http://blog.thought-mesh.net/cgi-bin/mt/mt-comments.cgi">here</a>.</p>

<p>While this script should impose very little burden on your webhost, even under rather heavy use, it may not be suitable for installations that run at the limits of their processing power. For those of us in the long tail, however, it should pose no problem. The long tail is the best place for deployment as well.</p>

<h1>Implementation (Advanced)</h1>

<p>While I have not observed a burden from this technique, that doesn&#8217;t mean it can&#8217;t happen. Because of this, I have developed an alternate mechanism that uses PHP instead of Perl so that no external processes are spawned, lowering the burden both computational and in terms of resources (because in many Apache installations, the number of simultaneous external processes is limited). The downside is that this implementation requires the use of ModRewrite and the consequent editing of <code>.htaccess</code> files.</p>

<p>You can download the script <a href="http://orbital-mind-control-laser.net/resources/sand-trap.zip">here</a>, or cut and paste the text in the box below.</p>



<pre style="border:1px solid black;padding-left:1ex;">
&lt;body&gt;

&lt;div style=&quot;font-size:200%;
            text-align:center;
            background:#822;
            color:white;
            border:2px solid red;
            padding:1ex;
            margin-bottom:1ex;
            &quot;&gt;
Sand Trap
&lt;/div&gt;

&lt;p style=&quot;border:2px solid red;
          padding:1ex;
          &quot;&gt;
You have been redirected to this script because
you have used an obsolete resource to which
no references exist on this website. This makes
you presumably a junker, and therefore your
session has been bogged down with this webpage.
&lt;/p&gt;

&lt;?php
ob_flush();
flush();
sleep(30);
?&gt;

&lt;p style=&quot;text-align:center;
          border:2px solid red;
          padding:1ex;
          margin-top:1ex;
          &quot;&gt;
If you are going to abuse me, I will abuse you right back.
&lt;/p&gt;

&lt;/body&gt;
</pre>



<p>Put this script somewhere where the weblog can access it without a redirection<sup><a href="http://blog.thought-mesh.net/solidwallofcode/movable_type/mt_32_junk_slow.php#fn1">1</a></sup>, name it <code>sand-trap.php</code>, and set the permissions to 755. Then edit the <code>.htaccess</code> file to do the rewrite.</p>

<p>For this example, it is presumed that</p>


<ul>
<li><code>sand-trap.php</code> is installed in the root directory of the weblog domain. E.g., for this weblog it is installed at <code>http://blog.thought-mesh.net/sand-trap.php</code> (try it if you&#8217;d like).</li>
<li>The <code>.htaccess</code> file is in the <a href="http://movabletype.org">Movable Type</a> install directory.</li>
</ul>





<pre style="border:1px solid black;padding-left:1ex;">
RewriteEngine On
RewriteRule ^mt-comments.cgi /sand-trap.php [last]
RewriteRule ^mt-tb.cgi /sand-trap.php [last]
</pre>



<p>You can also install the <code>.htaccess</code> in the root directory of the domain, which is what is done on this weblog<sup><a href="http://blog.thought-mesh.net/solidwallofcode/movable_type/mt_32_junk_slow.php#fn2">2</a></sup>.</p>



<pre style="border:1px solid black;padding-left:1ex;">
RewriteEngine On
RewriteRule ^cgi-bin/mt/mt-comments.cgi /sand-trap.php [last]
RewriteRule ^cgi-bin/mt/mt-tb.cgi /sand-trap.php [last]
</pre>



<p>You would, of course, need to change <code>cgi-bin/mt</code> to the local path to your <a href="http://movabletype.org">Movable Type</a> install directory.</p>

<p><span style="color:red;">Note</span>: This will render any scripts with those paths inaccessible, so don&#8217;t do this if you haven&#8217;t renamed those scripts. Alternatively, you could leave this in to turn comments / trackbacks on and off by putting a leading &#8216;#&#8217; on the appropriate lines to change them to comments (or not).</p>

<p>As a side benefit of this mechanism, if you use the <a href="http://blog.thought-mesh.net/solidwallofcode/movable_type/mt_32_patch_tra.php" title="Modifying the MovableType trackback interface to use names instead of numeric identifiers.">MT 3.2 Patch: Trackback By Name</a> modification, you can use ModRewrite to drop junkers still using the now invalid numeric form in to the sand trap as well. This is what you would use in a <code>.htaccess</code> file in the MT install directory, presuming that <code>sand-trap.php</code> was in the domain root directory.</p>



<pre style="border:1px solid black;padding-left:1ex;">
RewriteRule ^mt-tb.cgi/[0-9]+ /sand-trap.php [last]
</pre>



<p><hr class="fn" align="left"></p>

<p id="fn1"><sup>1</sup>  I.e., accessible from the same webserver. This is important because if a redirection happens, the junker will drop the connection and the goal is to keep him on the line as long as possible.</p>

<p id="fn2"><sup>2</sup> Because I moved from <code>cgi-bin/mt</code> to <code>scgi-bin</code> in the past, but the junkers keep hitting the scripts in the no longer extant <code>cgi-bin/mt</code> directory. Because that directory doesn&#8217;t exist, I can&#8217;t put the <code>.htaccess</code> there. Instead, I put it in the root directory to handle both the old and current directories.</p>]]>

</content>
</entry>
<entry>
<title>MT 3.2 Patch: Trackback By Name</title>
<link rel="alternate" type="text/html" href="http://blog.thought-mesh.net/solidwallofcode/movable_type/mt_32_patch_tra.php" />
<modified>2006-05-11T20:12:25Z</modified>
<issued>2006-03-21T14:56:59Z</issued>
<id>tag:blog.thought-mesh.net,2006:/solidwallofcode/2.1729</id>
<created>2006-03-21T14:56:59Z</created>
<summary type="text/plain">Modifying the MovableType trackback interface to use names instead of numeric identifiers.</summary>
<author>
<name>aog</name>
<url>http://blog.thought-mesh.net</url>
<email>aog@thought-mesh.net</email>
</author>
<dc:subject>Movable Type</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://blog.thought-mesh.net/solidwallofcode/">
<![CDATA[<h1>Overview</h1>

<p>The trackback API for <a href="http://movabletype.org">Movable Type</a> 3.2 uses the internal numeric ID of the trackback object as the key. This has two problems:</p>


<ul>
<li>There is no relationship between the trackback key and information in an entry, making clever URL rewriting infeasible.</li>
<li>It is an easy target for junkers, who can trivially guess valid values.</li>
</ul>



<p>This was unavoidable in previous versions of <a href="http://movabletype.org">Movable Type</a>, but with the release of 3.2 and its use of globally unique &#8220;basenames&#8221; for entries, we can do better.</p>

<p>This modification changes the trackback API to use identifying strings instead of numerics as the trackback key. The trackback object identifiers become completely internal (as was done for entry identifiers in 3.2). This overcomes both of the issues listed above.</p>

<p>This project is currently in beta. It has been deployed only several production weblogs, including this one. You can test it out by doing a trackback to this entry using the URL in the &#8220;Trackback URL&#8221; link below, or using the URL for this entry with &#8220;/ping&#8221; appended. Please put text that indicates a test if you do test it, so I can clean those out.</p>

<p><span style="color:red;">NB</span>: This modification explicitly forbids the use of numeric trackback ids. If installed and followed with a complete rebuild, this should not affect legitimate weblogs as the trackback URLs are pulled from your webpages, which will have the new, correct trackback URLs in it.</p>

<h1>Implementation</h1>

<p>Two files in the base distribution must be modified. You can pick up the modified versions of the files <a href="http://orbital-mind-control-laser.net/resources/mt-trackback-mod.zip">here</a> or, if you&#8217;re paranoid like me, you can do the modifications yourself. Once the files have been modified, you will need to a full rebuild to update all of the trackback URLs. At that point the modified trackback API should be fully operational.</p>

<h2>Trackback.pm Modification</h2>

<p>The <code>lib/MT/App/Trackback.pm</code> file must be modified. Note that there are two files named <code>Trackback.pm</code> in the distribution, be sure to edit the correct one.</p>

<p>Around line 97, there is a subroutine <code>_get_params</code>. Remove this subroutine and replace it with the following subroutine:</p>



<pre style="border:1px solid black;">
sub _get_tb {
    my $app = shift;
    my ($tb, $pass); # Trackback object and password to return
    my ($key, $name); # local vars for internal computations
    if (my $pi = $app-&gt;path_info) {
        $pi =~ s!^/!!; # drop leading slash
        ($key, $name, $pass) = split /\//, $pi;
        if ($key =~ m/\d+/) {
            $app-&gt;error($app-&gt;translate(
                'Numeric trackback IDs are no longer accepted'));
        } elsif (lc($key) eq 'entry') {
            require MT::Entry;
            $name =~ s/\..*$//; # strip any extension
            if (my $entry = MT::Entry-&gt;load({ basename =&gt; $name})) {
                $tb = MT::Trackback-&gt;load({ entry_id =&gt; $entry-&gt;id});
                $app-&gt;error($app-&gt;translate(
                    'No trackbacks for entry with basename [_1]', $name))
                    if not $tb;
            } else {
                $app-&gt;error($app-&gt;translate('No entry with basename [_1]', $name));
            }
        } elsif ($key =~ m/^cat/i) {
            require MT::Category;
            if (my $cat = MT::Category-&gt;load({ label =&gt; $name })) {
                $tb = MT::Trackback-&gt;load({ category_id =&gt; $cat-&gt;id });
                $app-&gt;error($app-&gt;translate(
                    'No trackbacks for category with label [_1]', $name))
                    if not $tb;
            } else {
                $app-&gt;error($app-&gt;translate(
                    'No category with label [_1]', $name));
            }
        } else {
            $app-&gt;error($app-&gt;translate(
                'Invalid trackback target key [_1]', $key));
        }
    } else {
        $app-&gt;error($app-&gt;translate(
          'Track request URL incorrectly formatted.
           The trackback target path information was missing'));
    }
    ($tb, $pass);
}
</pre>



<p>Around line 150, in subroutine <code>ping</code>, change</p>



<pre style="border:1px solid black;">
    my($tb_id, $pass) = $app-&gt;_get_params;
    return $app-&gt;_response(Error =&gt;
        $app-&gt;translate(&quot;Need a TrackBack ID (tb_id).&quot;))
        unless $tb_id;

    require MT::Trackback;
    my $tb = MT::Trackback-&gt;load($tb_id)
        or return $app-&gt;_response(Error =&gt;
            $app-&gt;translate(&quot;Invalid TrackBack ID '[_1]'&quot;, $tb_id));
</pre>



<p>to</p>



<pre style="border:1px solid black;">
    my($tb, $pass) = $app-&gt;_get_tb;
    return $app-&gt;_response(Error =&gt; $app-&gt;errstr) unless $tb;
</pre>



<p>Around line 185, change</p>



<pre style="border:1px solid black;">
    no_utf8($tb_id, $title, $excerpt, $url, $blog_name);
</pre>



<p>to</p>



<pre style="border:1px solid black;">
    no_utf8($title, $excerpt, $url, $blog_name);
</pre>



<p>Around line 213, change</p>



<pre style="border:1px solid black;">
    $ping-&gt;tb_id($tb_id);
</pre>



<p>to</p>



<pre style="border:1px solid black;">
    $ping-&gt;tb_id($tb-&gt;id);
</pre>



<p>In subroutine <code>rss</code>, around line 369, change</p>



<pre style="border:1px solid black;">
    my($tb_id, $pass) = $app-&gt;_get_params;
    my $tb = MT::Trackback-&gt;load($tb_id)
        or return $app-&gt;_response(Error =&gt;
            $app-&gt;translate(&quot;Invalid TrackBack ID '[_1]'&quot;, $tb_id));
</pre>



<p>to</p>



<pre style="border:1px solid black;">
    my ($tb, $pass) = $app-&gt;_get_tb;
    return $app-&gt;_response(Error =&gt; $app-&gt;errstr) unless $tb;
</pre>



<h2>ContextHandlers.pm Modification</h2>

<p>The file <code>lib/MT/Template/ContextHandlers.pm</code> should be modified. This is not strictly required, but if this is not done then you will have to construct all trackback related data by hand in the templates rather than using the standard tags.</p>

<p>In subroutine <code>_hdlr_entry_id</code>, around line 1125, change</p>



<pre style="border:1px solid black;">
    $path . $cfg-&gt;TrackbackScript . '/' . $tb-&gt;id;
</pre>



<p>to</p>



<pre style="border:1px solid black;">
    $path . $cfg-&gt;TrackbackScript . '/entry/' . $e-&gt;basename;
</pre>



<p>In subroutine <code>_hdlr_entry_tb_data</code>, around line 1138, change</p>



<pre style="border:1px solid black;">
    $path .= $cfg-&gt;TrackbackScript . '/' . $tb-&gt;id;
</pre>



<p>to</p>



<pre style="border:1px solid black;">
   $path .= $cfg-&gt;TrackbackScript . '/entry/' . $e-&gt;basename;
</pre>



<p>In subroutine <code>_hdlr_category_tb_link</code>, around line 2639, change</p>



<pre style="border:1px solid black;">
    $path . $cfg-&gt;TrackbackScript . '/' . $tb-&gt;id;
</pre>



<p>to</p>



<pre style="border:1px solid black;">
    $path . $cfg-&gt;TrackbackScript . '/cat/' . $cat-&gt;label;
</pre>



<h1>Other Notes, Techniques and Caveats</h1>

<p>There are several things to keep in mind once this modification is installed.</p>

<h2 id="friendly_tb_url">Friendly trackback URLs</h2>

<p>One of the drivers for this modification was a request for &#8220;friendlier&#8221; trackback URLs. In particular, the desire was to be able to have other weblogs link via trackback to a post by using the URL of the post with &#8220;/ping&#8221; appended as the trackback URL. This requires</p>


<ul>
<li>Installing this modification</li>
<li>An Apache webserver</li>
<li>Access to the Apache configuration file or <code>.htaccess</code> files to enable <a href="http://www.modrewrite.com/">mod_rewrite</a></li>
</ul>



<p>Also note that this works only for individual archives.</p>

<p>To set it up, in the top level directory for the individual archives, place text like the following in a <code>.htaccess</code> file:</p>



<pre style="border:1px solid black;padding-left:1em;">
RewriteEngine On

# Support trackback pings by appending &quot;/ping&quot; to an individual archive URL.
RewriteRule /([^/]+)/ping$ /cgi-bin/mt/mt-tb.cgi/entry/$1
</pre>



<p>You need to make sure that the path &#8220;<code>/cgi-bin/mt/mt-tb.cgi/</code>&#8221; is correct for your installation. This is easy to find, simply look at your current trackback URL.</p>

<p>In theory, this should be easily extensible to supporting category trackback pings, although I never use categories so I have not experimented on it directly yet. Note that the URL must be of the form &#8220;&#8230;/cat/&#8230;&#8221; instead of &#8220;&#8230;/entry/&#8230;&#8221; for category trackbacks.</p>

<p><span style="color:red;">NB</span>: The name logic for trackbacks automatically strips extensions, so that you can use both &#8220;my_cool_post&#8221; and &#8220;my_cool_post.html&#8221; as the name for the trackback URL. This was done to support this technique.</p>

<h2>Trackback URL display</h2>

<p>One effect of this modification is to make the trackback URLs noticeably longer. This can cause problems with formatting, particularly of popups. What I have done is change explicit display of the trackback URLs to a link with the link text &#8220;Trackback URL&#8221;. The reader can then either right-click and use the &#8220;copy this link&#8221; option (available in FireFox, IE and Opera) or use the <a href="#friendly_tb_url">&#8220;friendlier&#8221;</a> trackback URLs.</p>

<p><em>This project originally inspired by <a href="http://www.sixapart.com/mailman/private/pronet/2006-March/004269.html">a request from Sherwin Techico</a> on the <a href="http://www.sixapart.com/mailman/listinfo/pronet">ProNet</a> mailing list</em></p>]]>

</content>
</entry>
<entry>
<title>MT 3.2: Using system plugin settings as weblog defaults</title>
<link rel="alternate" type="text/html" href="http://blog.thought-mesh.net/solidwallofcode/movable_type/mt_32_using_sys.php" />
<modified>2006-03-10T19:10:48Z</modified>
<issued>2006-03-10T18:52:18Z</issued>
<id>tag:blog.thought-mesh.net,2006:/solidwallofcode/2.1727</id>
<created>2006-03-10T18:52:18Z</created>
<summary type="text/plain">Implement a plugin so that if the user does not configure a weblog, that weblog uses the system settings.</summary>
<author>
<name>aog</name>
<url>http://blog.thought-mesh.net</url>
<email>aog@thought-mesh.net</email>
</author>
<dc:subject>Movable Type</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://blog.thought-mesh.net/solidwallofcode/">
<![CDATA[<h1>Overview</h1>

<p>The new plugin configuration settings support in MT 3.2 takes some getting used to but it is well worth the effort. One of the issues, however, is that for many plugins that have per weblog configuration data, it would be handy to use the system level settings as another level of defaults so that any weblog that wasn&#8217;t explicitly configured would use the system settings instead of the hardwired defaults. This turns out to be achievable with a reasonable amount of effort.</p>

<h1>Implementation</h1>

<p>There are two places which have to be dealt with to achieve the desired effect:</p>


<ul>
<li><a href="#logic">Loading system settings as weblog defaults in the plugin logic.</a></li>
<li><a href="#page">Loading system settings as weblog defaults for the plugin settings configuration page.</a></li>
</ul>



<p>This description presumes that you have created your plugin as a subclass of <code>MT::Plugin</code> as is recommended. The implementation consists of adding two methods to your plugin class and then using those methods elsewhere in the plugin.</p>

<h2 id="logic">Using system settings as weblog defaults</h2>

<p>The MT 3.2 distribution has no mechanism for detecting whether a weblog has a specific configuraiton. This can be remedied by putting a subroutine to do that in to your plugin class.</p>



<pre style="padding-left:1em; border:1px solid black">
# Return the config object for the scope if it exists, undef otherwise.
sub test_config_obj {
    my $plugin = shift;
    my ($scope_id) = @_;
    my $key;
    my $scope = $scope_id;
    if ($scope &amp;&amp; $scope ne 'system') {
        $scope =~ s/:.*//; # strip off id, leave identifier
        $key = 'configuration:'.$scope_id;
    } else {
        $scope_id = 'system';
        $scope = 'system';
        $key = 'configuration';
    }
    # if it's already in the cache, return it.
    return $plugin-&gt;{__config_obj}{$scope_id}
      if $plugin-&gt;{__config_obj}{$scope_id};
    # otherwise try to load it.
    require MT::PluginData;
    my $pdata_obj = MT::PluginData-&gt;load({plugin =&gt; $plugin-&gt;name(),
					  key =&gt; $key});
    # if we succeed in loading, cache it
    $plugin-&gt;{__config_obj}{$scope_id} = $pdata_obj if ($pdata_obj);
    return $pdata_obj;
}
</pre>



<p>This is a modified clone of the <code>get_config_obj</code> subroutine. If the configuration is found, it is cached to make subsequent calls to retrieve it fast. Therefore it&#8217;s not a Bad Idea to call the test method and then the get method.</p>

<p>Once this is present, then defaulting to system settings for non-configured weblogs is easy, presuming that <code>$plugin</code> is set to your plugin object.</p>



<pre style="padding-left:1em; border:1px solid black">
        if ($plugin-&gt;test_config_obj($scope)) {
            $settings = $plugin-&gt;get_config_hash($scope);
        } else {
            $settings = $plugin-&gt;get_config_hash('system');
        }
</pre>



<p>After this, <code>$settings</code> is set to the weblogs specific settings, if present, otherwise the system settings or, if those are missing, the hardwired defaults.</p>

<p>My personal preference is to use an &#8220;operation&#8221; class for my plugin logic that is instantiated when the plugin has to do its work. That class loads up the settings using this logic during construction (in the <code>new</code> subroutine) and caches them for use everywhere else.</p>

<h2 id="page">Using system settings as default weblog configuration</h2>

<p>If a user goes to configure the plugin for a specific weblog and there is no configuration data for that weblog, the defaults loaded in to the configuration interface should be the system defaults because</p>


<ul>
<li>Those are the values that will be used, so to do otherwise is to provide bogus data to the user.</li>
<li>If the user wants to tweak, then the starting point should be the system settings if available.</li>
</ul>



<p>We can do this by overriding the default logic in the base class for our plugin class with this subroutine:</p>



<pre style="padding-left:1em; border:1px solid black">
sub apply_default_settings {
    my ($self, $data, $scope_id) = @_;
    # If the defaults are being applied to a weblog, then copy down
    # from the system settings to supply the default values.
    if ($scope_id =~ m/:/) {
        my $system_data = $self-&gt;get_config_hash('system');
        foreach (keys %$system_data) {
            $data-&gt;{$_} = $system_data-&gt;{$_}
              if not exists $data-&gt;{$_} or not defined $data-&gt;{$_};
        }
    }
    return $self-&gt;SUPER::apply_default_settings($data, $scope_id);
}
</pre>



<h2>Other issues that work out automagically</h2>

<dl>
<dt>How do I reset a weblog to system defaults?</dt>
<dd>Just use the &#8220;Reset to Defaults&#8221; button. What that does is destroy the configuration data for the weblog. After that, the tweaked up default logic will pull in the system settings automagically.</dd>
<dt>Don't I have to handle creating weblog specific configurations?</dt>
<dd>No. The base MT logic handles that correctly, once everything else is set up. MT uses the default value logic to populate data for unconfigured weblogs and handles all the scoping automagically. In fact, the plugin for which I worked this out doesn&#8217;t even have separate subroutines for the system and weblog configuration templates.</dd>
</dl>
]]>

</content>
</entry>
<entry>
<title>MT 3.2: Creating database tables for a plugin</title>
<link rel="alternate" type="text/html" href="http://blog.thought-mesh.net/solidwallofcode/movable_type/mt_32_creating.php" />
<modified>2006-03-22T02:05:49Z</modified>
<issued>2006-03-10T17:59:41Z</issued>
<id>tag:blog.thought-mesh.net,2006:/solidwallofcode/2.1726</id>
<created>2006-03-10T17:59:41Z</created>
<summary type="text/plain">Automatically create database tables for a plugin.</summary>
<author>
<name>aog</name>
<url>http://blog.thought-mesh.net</url>
<email>aog@thought-mesh.net</email>
</author>
<dc:subject>Movable Type</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://blog.thought-mesh.net/solidwallofcode/">
<![CDATA[<h1>Overview</h1>

<p>Some <a href="http://movabletype.org">Movable Type</a> plugins require database tables to store their information because it is too large for the simple plugin settings data. It has always been a problem to create these tables automatically, but with MT 3.2 this is now possible.</p>

<h1>Implementation</h1>

<p>This implementation description presumes that the plugin and the plugin data class are correctly registered in accord with <a href="http://movabletype.org">Movable Type</a> 3.2 requirements. All of that is covered elsewhere (like <a href="http://www.movalog.com/archives/plugins/helloworld#001468">here</a>), although I learned primarily by reading the code and its internal documentation, and looking at other working plugins. The write up on the <a href="http://movabletype.org">Movable Type</a> website isn&#8217;t worth reading (incomplete and obsolete) so I recommend against looking there.</p>

<h2>Define the columns</h2>

<p>When using the <code>install_properties</code> mechanism to define the data elements of a plugin, use &#8216;<code>column_defs</code>&#8217; instead of &#8216;<code>columns</code>&#8217;. This is a hash, not an array, which maps column names to column descriptors. These descriptors are the standard SQL description of a column. Some standard types to use are</p>


<ul>
<li>For the required identifier column &#8216;<code>id</code>&#8217; &#8212; &#8216;<code>integer not null auto_increment</code>&#8217;</li>
<li>For columns that store entry, weblog, comment identifiers &#8212; &#8216;<code>integer not null</code>&#8217;</li>
<li>Strings &#8212; &#8216;<code>string(255)</code>&#8217;. This one I am not so clear on, whether the number matters for performance or, if it does, what the optimal value is. It will be transformed in to a variable sized string, so it doesn&#8217;t matter in terms of functionality.</li>
</ul>



<h2>Detect  / create missing tables.</h2>

<p>This is the code used in my <a href="http://blog.thought-mesh.net/solidwallofcode/mt_projects/webiki.php" title="Wiki-like words for MovableType">Webiki</a> plugin. It is in the configuration template generation logic. The <a href="http://blog.thought-mesh.net/solidwallofcode/mt_projects/webiki.php" title="Wiki-like words for MovableType">Webiki</a> plugin defaults to not transforming the text and the user must therefore visit the configuration page before it works. I am not sure how expensive the table existence checks are, so I wanted to not have them done every single time the plugin was loaded.</p>



<pre style="padding-left:1em;border:1px solid black;">
my $db = MT::Object-&gt;driver();
if (not $db-&gt;table_exists('Transfinitum::Webiki::Word')) {
    my $error = 'Database handle from driver not valid';
    my $statement;
    my $dbh = $db-&gt;{dbh};
    if ($dbh) {
        $error = '';
        for ( $db-&gt;fix_class('Transfinitum::Webiki::Word') ) {
            $statement = $_; # cache for later use in error message
            if (not $dbh-&gt;do($statement)) {
                $error = $dbh-&gt;errstr;
                last;
            }
        }
    }
    if ($error) {
        MT-&gt;instance-&gt;log(
          MT-&gt;translate(
            'Failed to create database tables for Webiki plugin - [_1]'
           , $error
        ));
        $tmpl .= &lt;&lt;INIT;
&lt;p style=&quot;color:red;&quot;&gt;Failed to create database tables for Webiki plugin.
&lt;br /&gt;Statement: &amp;lsquo;$statement&amp;rsquo;
&lt;br /&gt;Error: $error.&lt;/p&gt;
INIT
    } else {
        $tmpl .= '&lt;p&gt;Created database tables for Webiki plugin.&lt;/p&gt;';
    }
}
$tmpl;
</pre>



<p>The first two lines check for the existence of the tables for the &#8216;<code>Transfinitum::Webiki::Word</code>&#8217; object, which is the type of object stored in the database table. If not, then we create them. The <code>fix_class</code> method does not actually fix the class, but instead returns the appropriate database statements to do so. This method is generally used in the upgrade process, but if the table doesn&#8217;t exist (as we&#8217;ve determined) then it emits only the table creation statements.</p>

<p>After that, we execute the statements one by one, checking for errors. If errors are encountered, we log that and attach it  to the settings display. If the tables are created successfully, we make a note of that as well.</p>

<h1>Notes</h1>

<p>You can see this code used in a working plugin by looking at the source for <a href="http://blog.thought-mesh.net/solidwallofcode/mt_projects/webiki.php" title="Wiki-like words for MovableType">Webiki</a>. Working code is always a good companion to documentation.</p>]]>

</content>
</entry>
<entry>
<title>MT 3.2: Reset a password</title>
<link rel="alternate" type="text/html" href="http://blog.thought-mesh.net/solidwallofcode/movable_type/resetting_a_mov.php" />
<modified>2006-03-22T02:16:09Z</modified>
<issued>2006-03-08T18:20:34Z</issued>
<id>tag:blog.thought-mesh.net,2006:/solidwallofcode/2.1723</id>
<created>2006-03-08T18:20:34Z</created>
<summary type="text/plain">How to reset a password in MovableType using direct acccess to the database.</summary>
<author>
<name>aog</name>
<url>http://blog.thought-mesh.net</url>
<email>aog@thought-mesh.net</email>
</author>
<dc:subject>Movable Type</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://blog.thought-mesh.net/solidwallofcode/">
<![CDATA[<p>You can reset a password in <a href="http://movabletype.org">Movable Type</a> 3.2 to a specific value using a two step process. However, if you are unable for whatever reason to direct edit the database, this will not work.</p>

<p>First, execute the following on the command line:</p>



<pre align="center">
perl -e &quot;print crypt('password', 'ac');&quot;
</pre>



<p>Substitute the password you want for the string &#8216;password&#8217; in the above command. The &#8216;ac&#8217; can be any two characters, it doesn&#8217;t matter, but they must be present (that&#8217;s the <a href="http://www.unix.org.ua/orelly/networking/puis/ch08_06.htm#AUTOID-11160">&#8220;salt&#8221;</a> for you UNIX&#8482; geeks). This will print a set of apparently random characters. Take those characters and put them in to the &#8220;author_password&#8221; column of the corresponding row of the &#8220;mt_author&#8221; table in the <a href="http://movabletype.org">Movable Type</a> database. Do <strong>not</strong> use any DB encryption function &#8212; <a href="http://movabletype.org">Movable Type</a> does that itself and uses the DB column as a simple text field.</p>]]>

</content>
</entry>
<entry>
<title>Weblog Defense Grid</title>
<link rel="alternate" type="text/html" href="http://blog.thought-mesh.net/solidwallofcode/movable_type/weblog_defense.php" />
<modified>2006-09-07T00:30:59Z</modified>
<issued>2006-02-26T19:21:01Z</issued>
<id>tag:blog.thought-mesh.net,2006:/solidwallofcode/2.1716</id>
<created>2006-02-26T19:21:01Z</created>
<summary type="text/plain">A description of my defenses against junk comments and trackbacks for MovableType.</summary>
<author>
<name>aog</name>
<url>http://blog.thought-mesh.net</url>
<email>aog@thought-mesh.net</email>
</author>
<dc:subject>Movable Type</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://blog.thought-mesh.net/solidwallofcode/">
<![CDATA[<h1>Overview</h1>

<p>This article describes my anti-junk defense grid for <a href="http://movabletype.org">Movable Type</a>. It is a layered defense, different aspects working together to reduce the burden of maintaining successful defenses, without overly restricting users of the weblog<sup><a href="http://blog.thought-mesh.net/solidwallofcode/movable_type/weblog_defense.php#fn1">1</a></sup>.</p>

<h1>Layered Defense</h1>

<p>I use a combination of technologies as a defense in depth, so that even if there is penetration, it is rarely much effort to clean up.</p>

<h2>SpamLookup</h2>

<p>SpamLookup is a junk filtering plugin that is installed in <a href="http://movabletype.org">Movable Type</a> by default, starting with version 3.2. This is a very useful plugin and I use it extensively. I primarily make use of the word filter to scan for indicators of junk posters and ban specific domains. While SpamLookup doesn&#8217;t have any bulk delete functionality, MT 3.2 itself allows one to search comments for specific strings, which is enough to make bulk clean up tolerable. With my defense grid in place, however, I haven&#8217;t had to do that for quite a while.</p>

<p>While the distributed SpamLookup is useful, there were many things that I observed that I wanted to check for that were not possible. Initially I wrote my own filter to do these checks but later I created my own <a href="http://blog.thought-mesh.net/solidwallofcode/movable_type/spamlookup_exte.php" title="A modified version of the SpamLookup plugin with the ability to apply filter words to specific fields in comments and trackbacks.">SpamLookup Extension</a> to be able to apply filters to specific fields in the entries. This permits much broader filters and more complex patterns. For instance, one can simpy forbid the character sequence &#8220;poker&#8221; or &#8220;sex&#8221; in a home page URL or commentor name without affecting normal use of the word in the actual comments. Or, in terms of patterns, one can forbid commentor names that are longer than some specific number of characters.</p>

<p>This layer provides an excellent first defense that gets at least 90% of the incoming junk. <a href="http://orbital-mind-control-laser.net/resources/standard-junk-filters.txt">Here is my base set of filters</a>. It has a lot of examples of how to take advantage of the field capability. I do tend to tweak it a bit, but it&#8217;s got most categories that are useful so it&#8217;s mostly a matter of cloning an existing filter and using a new word.</p>

<h2>Simple Junk Filters</h2>

<p><a href="http://blog.thought-mesh.net/solidwallofcode/movable_type/simple_junk_fil.php" title="A lightweight framework for lightweight filters with a few useful filters built in.">Simple Junk Filters</a> is a small filter framework that lets me create PERL based filters and easily set them up to run and be tunable via the plugin configuration screens. This used to do much more, but now that I have extended SpamLookup it is down to two tests, but both of these catch quite a bit of junk. Also, should I find some other property of junk I need code to check for, I can put it in this plugin very rapidly with full configuration.</p>

<h2><a href="http://blog.thought-mesh.net/solidwallofcode/mt_projects/autoban.php" title="Automatically maintain a .htaccess file to ban junk sources.">AutoBan</a></h2>

<p><a href="http://blog.thought-mesh.net/solidwallofcode/mt_projects/autoban.php" title="Automatically maintain a .htaccess file to ban junk sources.">AutoBan</a> is an IP banning plugin that helps</p>


<ul>
<li>Control the number of junk objects so that it is easier to detect inappropriately junked objects.</li>
<li>Control floods by banning IP addresses that are repeatedly hitting the weblog.</li>
</ul>



<p><a href="http://blog.thought-mesh.net/solidwallofcode/mt_projects/autoban.php" title="Automatically maintain a .htaccess file to ban junk sources.">AutoBan</a> keeps a &#8216;.htaccess&#8217; file updated to ban the IP addresses of junk objects. As new comments or trackbacks are junked, the IP addresses are automatically banned if there too many junk objects from that IP address. IP addresses are unbanned when the junk entries are deleted (directly or via automatic cleanup) or the junk object is marked as not junk. The key rationale is that the cost of starting up the <a href="http://movabletype.org">Movable Type</a> application is large, so any filtering that can be done to prevent that should reduce the load on the server. See <a href="http://blog.thought-mesh.net/solidwallofcode/mt_projects/autoban.php" title="Automatically maintain a .htaccess file to ban junk sources.">the page for MTAutoBan</a> for a more detailed discussion of the performance issue.</p>

<p>While this doesn&#8217;t help as much as I hoped, it still seems to keep flooding under control. It also helps protect multiple weblogs in a single install because banned addresses are banned for all the weblogs. This weblog gets very little junk because the junkers hit <a href="http://blog.thought-mesh.net">Thought Mesh</a> first and are banned before they can hit this weblog.</p>

<h2>Trackbacks By Name</h2>

<p>I use <a href="http://blog.thought-mesh.net/solidwallofcode/movable_type/mt_32_patch_tra.php" title="Modifying the MovableType trackback interface to use names instead of numeric identifiers.">MT 3.2 Patch: Trackback By Name</a> to stop junkers who guess at trackback ping URLs, along with ModRewrite to redirect numeric ID based trackbacks to a <a href="http://blog.thought-mesh.net/solidwallofcode/movable_type/mt_32_junk_slow.php" title="Leave a slow response script in place of your renamed comment or trackback script to slow down junk attacks.">sand trap</a>. This definitely seems to have slowed down the trackback junk.</p>

<h2>No pop ups</h2>

<p>I have removed pop up windows for trackbacks and comments and used ModRewrite to send any requests for those popups to the <a href="http://blog.thought-mesh.net/solidwallofcode/movable_type/mt_32_junk_slow.php" title="Leave a slow response script in place of your renamed comment or trackback script to slow down junk attacks.">sand trap</a>. That presumably should help reduce the server load both by slowing up the junkers and by using many fewer webhost resources (as I use the PHP variant, there is no CGI overhead).</p>

<p>The ModRewrite logic used is</p>



<pre style="border:1px solid black;padding-left:1ex;">
RewriteCond %{QUERY_STRING} __mode=view
RewriteRule mt-tb[.]cgi /sand-trap.php [last]
RewriteCond %{QUERY_STRING} __mode=view
RewriteRule mt-comments[.]cgi /sand-trap.php [last]
</pre>



<p><hr class="fn" align="left"></p>

<p id="fn1"><sup>1</sup> For instance, some weblogs forbid any URL in a trackback excerpt, which is very burdensome because one normally puts the link to the target post early, which puts it in the excerpt. I&#8217;ve just stopped linking to such weblogs.
Also, I hate captchas &#8212; I don&#8217;t comment on websites with those, either.</p>]]>

</content>
</entry>
<entry>
<title>Simple Junk Filters</title>
<link rel="alternate" type="text/html" href="http://blog.thought-mesh.net/solidwallofcode/movable_type/simple_junk_fil.php" />
<modified>2006-03-22T02:10:32Z</modified>
<issued>2006-02-24T18:02:41Z</issued>
<id>tag:blog.thought-mesh.net,2006:/solidwallofcode/2.1711</id>
<created>2006-02-24T18:02:41Z</created>
<summary type="text/plain">A lightweight framework for lightweight filters with a few useful filters built in.</summary>
<author>
<name>aog</name>
<url>http://blog.thought-mesh.net</url>
<email>aog@thought-mesh.net</email>
</author>
<dc:subject>Movable Type</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://blog.thought-mesh.net/solidwallofcode/">
<![CDATA[<h1>Overview</h1>

<p>This is a collection of various junk filters I use which are not implementable in other junk filter plugins. Many of the original set have been removed because they can be done with the <a href="http://blog.thought-mesh.net/solidwallofcode/movable_type/spamlookup_exte.php" title="A modified version of the SpamLookup plugin with the ability to apply filter words to specific fields in comments and trackbacks.">SpamLookup Extension</a>.</p>

<p>Each filter can be tuned to have a distinct weight via the top level plugin settings page. Setting a weight to zero disables the filter.</p>

<p>This plugin also provides a nice platform for adding other simple filter checks.</p>

<h1>Installation</h1>


<ol>
<li>Get the <a href="http://orbital-mind-control-laser.net/resources/transfinitum-junk-filters.zip">distribution</a>.</li>
<li>Put the &#8216;transfinitum-junk-filters.pl&#8217; file in the &#8216;plugins&#8217; directory of your <a href="http://movabletype.org">Movable Type</a> installation.</li>
<li>Configure the filters
<ol>
<li>Go to the &#8216;Main Menu&#8217; page.</li>
<li>Click on the &#8216;Plugins&#8217; link in the &#8216;System Shortcuts&#8217; column.</li>
<li>Click on the &#8216;Show Settings&#8217; Link under &#8216;Transfinitum Junk Filters&#8217;.</li>
<li>Set the weights and click &#8216;Save&#8217;.</li>
</ol>
</li>
</ol>



<h1>Usage</h1>

<p>Nothing to do, it&#8217;s an install and forget filter. If you don&#8217;t like a filter, configure the weight of that filter to be zero. Note that the plugin returns a single junk filter score, not one per filter, that is the sum of the scores of the filters that matched.</p>

<p>To add your own filters, you can add a new subroutine to the plugin. It takes two arguments</p>


<ol>
<li>The plugin object.</li>
<li>The target object for the filter, which will be a <code>MT::Comment</code> or a <code>MT::TBPing</code>.</li>
</ol>



<p>The subroutine should return a true value if it matched on the object, false otherwise. The filter weight is controlled via the configuration, not the code.</p>

<p>After writing the subroutine for the filter, add a description of the filter to the plugin construction. That&#8217;s it, the filter will now run with a configurable weight.</p>]]>

</content>
</entry>
<entry>
<title>SpamLookup Extension</title>
<link rel="alternate" type="text/html" href="http://blog.thought-mesh.net/solidwallofcode/movable_type/spamlookup_exte.php" />
<modified>2007-08-14T22:11:23Z</modified>
<issued>2006-02-24T04:20:41Z</issued>
<id>tag:blog.thought-mesh.net,2006:/solidwallofcode/2.1709</id>
<created>2006-02-24T04:20:41Z</created>
<summary type="text/plain">A modified version of the SpamLookup plugin with the ability to apply filter words to specific fields in comments and trackbacks.</summary>
<author>
<name>aog</name>
<url>http://blog.thought-mesh.net</url>
<email>aog@thought-mesh.net</email>
</author>
<dc:subject>Movable Type</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://blog.thought-mesh.net/solidwallofcode/">
<![CDATA[<p>I have a modified version of the SpamLookup plugin that is distributed with <a href="http://movabletype.org">Movable Type</a> 3.2. This is a single file drop in (mostly) backwards compatible replacement. To install, get the <code>spamlookup.pm</code> file from the <a href="http://orbital-mind-control-laser.net/resources/spamlookup.zip">distribution</a> and replace the file in the <code>plugins/spamlookup/lib</code> directory.</p>

<p>SpamLookup Extension is now available for </p>


<ul>
<li><a href="http://movabletype.org">Movable Type</a> 3.34 and 3.35 &#8212; <a href="#mt_33">see here</a>.</li>
<li><a href="http://movabletype.org">Movable Type</a> 4.0 (beta) &#8212; <a href="http://orbital-mind-control-laser.net/resources/spamlookup-MT-4-0.zip">distribution</a>. This has the same <a href="#mt_33">release notes</a> as the 3.34 / 3.25 version.</li>
</ul>



<h1>Additional Capabilities</h1>

<p>The modification provides the ability to apply word filters to specific fields in the comments and trackbacks, rather than the conglomeration of all fields. There are a number of specialized checks that I have found useful, most of which I had previously put in to a custom spam filter.</p>

<p>The new syntax for filter lines is</p>

<blockquote><p>word ( fields ) weight</p></blockquote>

<p>where</p>

<dl style="margin-left:2em;">
<dt>word</dt>
<dd>A space delimited word or a &#8216;/&#8217; delimited regular expression.</dd>
<dt>fields</dt>
<dd>A space delimited set of field keywords. This is optional.</dd>
<dt>weight</dt>
<dd>A numeric value specifying the weight of this word. This is optional. A weight can be negative (with a leading &#8216;&ndash;&#8217;) which makes it a white listing instead of a blacklisting.</dd>
</dl>


<p>A word can be either a space delimited literal word or a &#8216;/&#8217; delimited regular expression. In the latter case, the characters &#8216;-ismx&#8217; are permitted to directly following the trailing &#8216;/&#8217;. If present, these are passed to the PERL regular expression engine to control the interpretation of the regular expression.</p>

<p>The valid field keywords are</p>

<div style="margin-left:2em;">

<table><tr><td><strong>FIELD</strong></td><td><strong>MEANING</strong></td><td><strong>DISPLAY</strong></td></tr><tr><td>name</td><td>Name for a comment author</td><td>Commentor</td></tr><tr><td>email</td><td>Email address for a comment author</td><td>Email</td></tr><tr><td>home</td><td>Homepage URL for a comment author</td><td>URL</td></tr><tr><td>content</td><td>Text content of a comment</td><td>(text box)</td></tr><tr><td>blog</td><td>Weblog name for trackback source</td><td>Source Site</td></tr><tr><td>title</td><td>Title for the source post of the trackback</td><td>Source Title</td></tr><tr><td>source</td><td>Source URL for a trackback</td><td>URL</td></tr><tr><td>excerpt</td><td>Trackback excerpt</td><td>(text box)</td></tr><tr><td>url</td><td colspan="2">Equivalent to <em>home</em> or <em>source</em></td></tr><tr><td>text</td><td colspan="2">Equivalent to <em>content</em> or <em>excerpt</em></td></tr><tr><td>all</td><td colspan="2">All fields together, separated by newlines</td></tr></table>

</div>

<p>If no fields are specified, &#8220;<em>all</em>&#8221; is used, thereby preserving (almost) the orginal behavior and syntax. The <em>url</em> and <em>text</em> fields are provided to make scanning equivalent fields for comments and trackbacks easy. If multiple fields are specified, they are all scanned in order. A match on any field counts as a match.</p>

<h1>Examples</h1>

<p>Most of these are from my customized spam filter, which can now be simplified. All of them are things I have seen in comment and trackback spam.</p>




<dl>
<dt>Empty trackback excerpt.</dt><dd>/^$/ (excerpt)</dd>
<dt>Double dash in domain.</dt><dd>-- (url email)</dd>
<dt>Comment is the single word 'Hi.'</dt><dd>/^Hi\.$/ (content)</dd>
<dt>No source URL for trackback</dt><dd>/^$/ (source)</dd>
<dt>The word 'poker' in the email address or homepage</dt><dd>poker (url email)</dd>
<dt>Homepage looks like an archive, not a base URL</dt><dd>/[[:digit:]]{3,}\.(?:html|htm|shtml|php)$/ (home)</dd>
<dt>Email address is purely numeric</dt><dd>/^[[:digit:]]+@/ (email)</dd>
</dl>




<p>Note that some of these are simply not possible in the original release (particularly the empty field checks). Others are possible but too broad to be practicle (such as checking for archive like links as a home page, or double dashes).</p>

<p>One feature that has come in handy is the ability to search for phrases at the beginning of a comment, which detects spammers with much less impact on legitimate commentors. For instance, one spammer starts his comments with &#8216;Hello, Admin!&#8217;. This can be detected with</p>

<p align="center">/^Hello, Admin!/ (text)</p>

<p>The &#8216;&#94;&#8217; means &#8220;match only at the start&#8221; when inside a regular expression (denoted by the &#8216;/&#8217; characters). The other handy character is &#8216;$&#8217;, which means &#8220;match only at the end&#8221;. Together with &#8216;&#94;&#8217; this means you can match on phrases that are the entire comment, not just part of it. E.g., if a spammer just puts the word &#8216;Hi.&#8217; in his comments, you can catch that with</p>

<p align="center">/&#94;Hi&#92;.$/ (text)</p>

<p>Note that we have to put a backslash in front of the &#8216;.&#8217; because otherwise that means &#8220;match any single character&#8221;. With this, some one who writes &#8216;Hi.&#8217; at the start won&#8217;t be matched, if he writes any additional text.</p>

<p>One common request is to ban a specific email address. This is now trivial. To ban the email address &#8220;neo@hotmail.com&#8221; you can do</p>

<p align="center">neo@hotmail.com (email)</p>

<p>If you want to detect the word &#8220;poker&#8221; in email address, commentor name, or home page URL, you can do</p>

<p align="center">poker (email url name)</p>

<p>and your commentors can still use the word in the text without impediment.</p>

<p>The weight of a filter can be negative, which causes it to be a white listing. If I wanted to give myself a bypass, I could use the rule</p>

<p align="center">Annoying Old Guy (name) -10</p>

<p>which would subtract 10 from the junk score of all of my comments so that my comment would pass even if it hit several filters. This could easily be used to give bypasses to other commentors by name, email, or home page URL. One could even use this to create a magic bypass word, say &#8216;ciscomyyahoo&#8217;. Put in the rule</p>

<p align="center">ciscomyyahoo (content) -10</p>

<p>and then when you want a bypass, put the magic word in an HTML comment, e.g. &lt;!&ndash;&ndash; ciscomyyahoo &ndash;&ndash;&gt; in your comment and you&#8217;re through the filters yet other people don&#8217;t see the magic word.</p>

<p>My current working set of filters can be found <a href="http://orbital-mind-control-laser.net/resources/standard-junk-filters.txt">here</a>, which has numerous other examples.</p>

<h1>Differences</h1>

<p>There a few minor functional differences.</p>

<h2 id="fixes">Bug fixes</h2>

<p>The original distribution of SpamLookup had bugs in the handling of decoded<sup><a href="http://blog.thought-mesh.net/solidwallofcode/movable_type/spamlookup_exte.php#fn1">1</a></sup> text where the decoded version of the text would not be scanned if the raw version did not have any hits by filters for junk filters. In the case of moderation filters, the decoded text would always be scanned, regardless of hits in the raw text (making the raw text scan pointless).</p>

<p>The new version now applies filters per field first to the raw text for the field, and then, if the raw text did <strong>not</strong> have a match, the decoded version (if different) is scanned. A match in either case counts as a match for the filter.</p>

<p>The processing of standard words (not regular expressions) is improved. Previously, words that started with non-word boundary characters would never match (because expressions like &#8216;\b&lt;&#8217; never match). These cases are now handled correctly.</p>

<p>The base implementation <a href="http://forums.sixapart.com/index.php?showtopic=58952&amp;st=0&amp;p=242889#entry242889">has a problem where backreferences do not work correctly</a> because the regular expression is compiled before the outermost parentheses are added leading to various problems. This does not occur in this version and the workaround suggested won&#8217;t break. The only thing to keep in mind is that all backreferences need to be incremented by one before being used.</p>

<h2>Undocumented feature</h2>

<p>The original release, when combinging the fields in to the combined text, would prefix each field with the string &#8220;field:&#8221; where <em>field</em> was one of &#8216;name&#8217;, &#8216;email&#8217;, &#8216;url&#8217;, &#8216;text&#8217; for comments and one of &#8216;blog&#8217;, &#8216;title&#8217;, &#8216;url&#8217;, &#8216;text&#8217; for trackbacks. Presumably this was done to provide a semblance of the functionality of my modification (at least, one could check if a specific field began with a specific filter word) but as there are no comments in the code there and no documentation, this is only speculation. In any case, I could see no use for it at all in this modification so it was removed.</p>

<h2>Log enchancement</h2>

<p>If a match occurs for a specific field other than &#8216;all&#8217;, the name of the field is added to the pattern in the log message on the comment / trackback.</p>

<p>For each word filter match, the specific score for that match is logged.</p>

<p>The patterns and matched text are HTML encoded before being placed in to the log so that pattern or match text that contains HTML code does not disturb the log display. In addition, literal question marks &#8216;&#63;&#8217; are transformed in to entities because they mess up the log display (although I have not had the time to track down why that is).</p>

<h2 id="mt_33">MT 3.3</h2>

<p>The MT 3.34 replacement lib is <a href="http://orbital-mind-control-laser.net/resources/spamlookup-3-3-4.zip">available here</a>. This is currently in use on multiple live weblogs.</p>

<p>The new version has a bit more tuning, although it&#8217;s unlikely to be noticeable in the real world. I have added more comments in the code for the curious and tweaked the log messages to be a bit clearer.</p>

<p>The only known potential issue is with Japanese and word boundaries. As best as I understood the code, the special checks for that should still work correctly. The original checks were removed, as they should be handled correctly by my bug fix for broken word boundaries in the original version.</p>

<p><hr class="fn" align="left"></p>

<p id="fn1"><sup>1</sup> &#8220;Decoded&#8221; means entities decoded to their textual equivalents.</p>]]>

</content>
</entry>
<entry>
<title>AutoBan</title>
<link rel="alternate" type="text/html" href="http://blog.thought-mesh.net/solidwallofcode/mt_projects/autoban.php" />
<modified>2007-08-14T14:30:08Z</modified>
<issued>2005-04-09T04:39:33Z</issued>
<id>tag:blog.thought-mesh.net,2005:/solidwallofcode/2.1525</id>
<created>2005-04-09T04:39:33Z</created>
<summary type="text/plain">Automatically maintain a .htaccess file to ban junk sources.</summary>
<author>
<name>aog</name>
<url>http://blog.thought-mesh.net</url>
<email>aog@thought-mesh.net</email>
</author>
<dc:subject>MT Projects</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://blog.thought-mesh.net/solidwallofcode/">
<![CDATA[<h1>Overview</h1>

<p>MTAutoBan is a plugin for <a href="http://movabletype.org">Movable Type</a>. It maintains an Apache webserver configuration file (also known as a &#8220;.htaccess&#8221; file) that bans IP addresses in the Apache webserver. The set of banned addresses is generated from the junk objects stored in the <a href="http://movabletype.org">Movable Type</a> database. Whenever the set of junked objects changes, the Apache configuration file is updated.</p>

<p>The goal of this plugin is to slow down the flood of junk objects by banning the IP source addresses that generate them. This makes it easier to check the junk objects for bad filtering and makes denial of service effects from excessive amount of junk much less likely. By doing the banning at the Apache webserver level instead of in <a href="http://movabletype.org">Movable Type</a> itself, the runtime cost of the banning is minimized. With a good set of filters, even large<sup><a href="http://blog.thought-mesh.net/solidwallofcode/mt_projects/autoban.php#fn1">1</a></sup> groups of systems are rapidly banned with little effect on the weblog.</p>

<p>As a result of further experience, I added the ability to redirect requests instead of simply banning them, because it seems that many junkers notice 403 error eventually and rotate attacks over to new machines. Redirection is intended to thwart this.</p>

<p>Because of the large numbers of compromised computers used to generate junk, the maintenance cost of banning the associated IP addresses must be near zero. This plugin achieves that goal. No maintenance is required once installed, and the defaults are good enough that initial configuration is not even necessary.</p>

<p>To make the banning as automatic as possible, the configuration file is updated whenever</p>


<ul>
<li>An object is marked as &#8220;junk&#8221;, either explicitly or via junk filtering.</li>
<li>A set of objects is marked as &#8220;not junk&#8221; explicitly.</li>
<li>Whenever a junked object is deleted.</li>
</ul>



<p>Current Version: <a href="http://orbital-mind-control-laser.net/resources/MTAutoBan-1-2-3.zip">1.2.3</a></p>

<p>Beta Version for MT 4.0 Compatibility: <a href="http://orbital-mind-control-laser.net/resources/MTAutoBan-1-2-4.zip">1.2.4</a></p>

<h1>Requirements</h1>

<p>MTAutoBan requires</p>


<ul>
<li>Apache webserver</li>
<li><a href="http://movabletype.org">Movable Type</a> 3.2 or 3.3</li>
</ul>



<p>All other Perl modules required by MTAutoBan are also required by <a href="http://movabletype.org">Movable Type</a>.</p>

<h1>Installation</h1>


<ol>
<li>Get the <a href="http://orbital-mind-control-laser.net/resources/MTAutoBan-1-2-3.zip">distribution</a>.</li>
<li>Create a directory named <code>AutoBan</code> under the <code>plugins</code> directory in your MT installation directory.</li>
<li>Copy all files in the distribution to the <code>AutoBan</code> directory.</li>
</ol>



<p>Note: If you installed a version prior to 1.1.0, you should remove the no longer in use file</p>

<p style="padding-left:1em"><code>extlib/Transfinitum/Apache/IPAccess.pm</code></p>

<h1>Usage</h1>

<p>MTAutoBan is designed to be a &#8220;zero configuration&#8221; plugin &#8212; unless you like to fiddle with things, you should have no need of configuring MTAutoBan. If you do read through this section and there are settings that you don&#8217;t understand, simply ignore them and leave them unchanged. These settings are for control-freaks like me who have psychological problems that do not permit them to tolerate anything they do not have absolute control over. Normal, well-adjusted people can get on with their lives instead.</p>

<p>To configure MTAutoBan, go to the global plugins configuration page. This can be reached from the &#8220;Plugins&#8221; link on the MT main page in the &#8220;System Shortcuts&#8221; area. MTAutoBan should be listed as one of the plugins available. The plugin has several configuration options.</p>

<dl><dt>Ban address if</dt>
<dd>This sets the number of times an address must appear in the junk objects to be banned. Addresses that appear this many times (or more) are put in the set of addresses to be banned.</dd>
<dt>Junk Comments</dt>
<dd>If this is checked, then junk comments are considered to be junk objects.</dd>
<dt>Junk Trackbacks</dt>
<dd>If this is checked, then junk trackbacks are considered to be junk objects.</dd>
<dt>Only junk objects less than <span style="border:1px solid black">####</span> minutes old.</dd>
<dd>If this is checked, the set of junk objects is restricted to those less than the specified number of minutes old. One day is 1440 minutes, a week is 10,080 minutes. </dd>
<dt>Path</dt>
<dd>Path to the access file. If this path is relative, then it is relative to the MT installation directory. If the final character is a forward slash, then the file name &#8216;.htaccess&#8217; is automatically added. MTAutoBan will mark its own ban list in the file so that an existing file can be used even if there are other Apache configuration commands in it.</dd>
<dt>Redirection</dt>
<dd>MTAutoBan by default denies access to banned addresses. If this setting is &#8220;None&#8221;, that is what happens. MTAutoBan can also redirect requests from those addresses. This can be done in one of two ways, determined by this setting. In both cases, only requests for files in directories controlled by the access file are affected.
<ul>
<li>ErrorDocument &#8212; MTAutoBan inserts an <code>ErrorDocument</code> directive in its section of the access file to override the page that would normally be used.</li>
<li>mod_rewrite &#8212; Use <code>mod_rewrite</code> to redirect requests instead of denying them. This option has unknown performance implications and so should be used with caution (<a href="#mod_rewrite">see here</a>).</li>
</ul>
</dd>
<dt>Ban page URL</dt>
<dd>If the previous setting, &#8220;Redirection&#8221;, is set to be active, then the target of the redirection is this URL. Relative paths are relative to the directory where the access file is (by default the MT install directory). Absolute paths are relative to the base URL for the weblog.
</dd>
<dt>Read <span style="border:1px solid black">####</span> objects at a time from the database</dt>
<dd>This is a performance tuning parameter for geeks. When MTAutoBan is generating the access file contents, it reads junk objects from the database. To avoid system limitations, it does this in chunks. This parameter specifies the number of objects per chunk.
</dd>
<dt>Write <span style="border:1px solid black">####</span> addresses per line in the access file</dt>
<dd>This controls how many addresses are written per line of access file output.
</dd>
</dl>

<p>In addition to these configuration options, there is also a check box labeled &#8220;Force access file update&#8221;. If checked, when the configuration is saved the access file is updated.</p>

<h2>Tags</h2>

<p>MTAutoBan has MT tags to display information about its operations.</p>

<table class="lined" cellspacing="0"><tr><td>MTAutoBanBannedCount</td><td>The number of banned IP addresses.</td></tr><tr><td>MTAutoBanUniqueCount</td><td>The number of unique addresses in the junk objects.</td></tr><tr><td>MTAutoBanObjectCount</td><td>The number of junk objects checked.</td></tr><tr><td>MTAutoBanThreshold</td><td>The number of junk objects needed to ban an address.</td></tr><tr><td>MTAutoBanLastUpdated</td><td>The time and date of the last access file update. This takes a &#8220;format&#8221; attribute to format the time. It behaves identically to the &#8220;format&#8221; attribute for standard MT time / date tags.</td></tr></table>

<h1>Known Issues</h1>


<ul>
<li>If a junk object is changed to non-junk on the object edit page, the access file is not updated. If the object is changed to non-junk from the listing page, then the access file is updated. This is by design for performance reasons. Fixing this means updating the access file on every non-junk comment and trackback. Currently comments and trackbacks that are not marked junk avoid the cost of access file update. This can be worked around by either using the listing page to mark objects non-junk, or using the configuration panel to force an access file update, or not worrying about it and letting the next automatic update to the access file fix the problem.</li>
<li>Using the time limit has some possible performance implications. Because the timestamps on comment and trackbacks are stored in weblog local time instead of UTC, it is not possible to determine how old a potential junk object is without loading the weblog to which it belongs. Therefore enabling this option will cause a load of all weblogs whenever the access file is updated. In addition, rather than doing two database queries (one for comments, one for trackbacks), the update will potentially require two database queries for every weblog. The internal logic will optimize this where possible, combining queries for weblogs that have the same timezone. If all weblogs have the same timezone, then only two queries for all comments and trackbacks are done. Whether this is noticeable in a real deployment is unknown. It shouldn&#8217;t be an issue unless you have dozens of weblogs in many different timezones.</li>
</ul>



<h1>Notes</h1>


<ul>
<li>Don&#8217;t forget to set auto-delete for feedback if you want MTAutoBan to clean up after itself.</li>
<li>MTAutoBan is careful to update the access file at most once for each invocation of the MT configuration script.</li>
<li>MTAutoBan has been tested on configurations with over 32,000 junk entries and over 10,000 banned addresses.</li>
<li>This plugin is not quite as useful as I had hoped, due to the large number of spam sources (over 13,000 on one weblog). It does seem to do well at holding back floods. In addition, many junkers use the same zombie net so that even new attacks that get past the filters don&#8217;t generate hundreds of junk objects. I haven&#8217;t had a new attack dump more than a dozen or so junk objects since I installed MTAutoBan, whereas it was quite common before that.</li>
<li>If the ban threshold is set to a non-numeric value it will be reset to the default.</li>
<li>If the path is left blank, it will be reset to the default.</li>
</ul>



<h2>Performance</h2>

<p>The overall performance characteristics of this plugin are unknown due to lack of an installed base. It has been running on all of my MT based weblogs for a couple of years without any apparent negative performance impact, but that is not conclusive.</p>

<p>The theory is that while updating the access file is expensive, it is significantly less expensive than loading up the MT application itself, which is done even when junk is caught by the filters. My experience has been that while there are a number of single hit junkers, there are many who flood a single weblog with a large number of requests in a short time period. It is those that MTAutoBan is designed to frustrate.</p>

<p>MTAutoBan does file locking on the access file and if it fails to get the lock, it cancels its access file update on the presumption that another instance of itself is already in the middle of an update. Because all addresses are updated every time<sup><a href="http://blog.thought-mesh.net/solidwallofcode/mt_projects/autoban.php#fn2">2</a></sup>, if an address is not added for this reason it will be on the next access file update so at most there is one more junk object than optimal. In exchange, the total server load per weblog is limited to a single update at any moment in time.</p>

<p id="mod_rewrite">Support for <code>mod_rewrite</code> adds another level of complexity to performance issues. Because MTAutoBan is targeted at access files, it cannot use the <code>RewriteMap</code> directive, which is only available to the main Apache configuration file. Therefore, it uses stacked <code>RewriteCond</code> directives followed by a <code>RewriteRule</code> that rewrites all URLs to the redirection target. I have very little data on the performance impact of processing 100 - 200 <code>RewriteCond</code> directives each with 50 alternate clauses in their regular expression is. It&#8217;s a lot of data, but the regular expresions are all literals.</p>

<p>In practice, I used it briefly with ~7,000 addresses without an obvious performance impact, which is rather weak evidence. This weblog has ~5,000 addresses banned with <code>mod_write</code> redirection (you can see the exactly number on the upper right of <a href="http://blog.thought-mesh.net">this page</a>). If there is an impact, it should show up while using the <a href="http://movabletype.org">Movable Type</a> interface. If it has, I have not noticed. It may be, however, that I happen to use or run on a lightly loaded webserver. I recomend caution when using this feature.</p>

<h2 id="white_list">White listing</h2>

<p>MTAutoBan has its own section of the <code>.htaccess</code> file and preserves content outside of its area when updating the file. This is done so that other, non MTAutoBan directives can be kept in the file. The most common expected use of this feature is white listing, i.e. allowing specific hosts / IP addresses access regardless of what AutoBan does. For example, if your ISP supplied IP addresses was 192.168.56.56, you might want to white list it to decrease the risk of losing access. To do that, you would put the following in the <code>.htaccess</code> file.</p>



<pre style="border:1px solid black;padding-left:1ex;">
order deny,allow
allow from 192.168.56.56
</pre>



<p>This instructs the Apache webserver to favor <code>allow from</code> over <code>deny from</code> and then to allow the IP address 192.168.56.56, achieving the desired effect. The same technique can be used to permit specific proxy addresses or domains (see <a href="http://httpd.apache.org/docs/2.1/mod/mod_authz_host.html">here</a> for additional information). This content will be preserved by MTAutoBan.</p>

<h2 id="bugs">Bugs</h2>

<p>Versions prior to 1.0.3 had a bug where multiple instances of  could interfere and scrozzle the <code>.htaccess</code> file. The symptoms are that any access to MT scripts causes a 500 (internal server) error. If this occurs, simply delete the .htaccess file via FTP or your webhost&#8217;s standard file management then install a version 1.0.3 or later.</p>

<h1>History</h1>


<ul>
<li>Version 0.1.0 - Initial version</li>
<li>Version 0.2.0
<ul>
<li>Added check boxes for each address.</li>
<li>Added &#8220;Check all&#8221; and &#8220;Uncheck all&#8221; buttons</li>
<li>Suppressed buttons when no log data is present or it is all filtered.</li>
</ul>
</li>
<li>Version 0.3.0
<ul>
<li>Fixed a problem with the login template.</li>
<li>Fixed a bug where a missing <code>.htaccess</code> file would cause a spurious warning.</li>
</ul>
</li>
<li>Version 0.4.0
<ul>
<li>The plugin automatically detects which version of MTB is in use and grubs through the appropriate log data. This means that the same install works on <a href="http://movabletype.org">Movable Type</a> 2.6X and 3.1X.</li>
</ul>
</li>
<li>Version 1.0.0
<ul>
<li>Updated extensively for MT 3.2.</li>
<li>Use junk objects instead of activity log.</li>
<li>Use plugin configuration to set parameters.</li>
<li>Completely automated, no separate operation page.</li>
</ul>
</li>
<li>Version 1.0.1
<ul>
<li>Minor formatting cleanup.</li>
<li>Added &#8220;Force access file update&#8221; option.</li>
</ul>
</li>
<li>Version 1.0.2
<ul>
<li>Fixed documentation link problem.</li>
</ul>
</li>
<li>Version 1.0.3
<ul>
<li>Fixed a potential race condition where the <code>.htaccess</code> file could get scrozzled under high loads.</li>
</ul>
</li>
<li>Version 1.1
<ul>
<li>Added the option to time limit the potential junk objects.</li>
<li>Cleaned up the distribution so that all files are in the same plugin directory.</li>
<li>Moved code around to minimize plugin footprint when not invoked.</li>
<li>Cleaned up some language and display in the settings to be more consistent.</li>
<li>Added MT tags to display statistics.</li>
</ul>
</li>
<li>Version 1.1.1
<ul>
<li>Added MTAutoBanThreshold tag.</li>
<li>Cleaned up some code, added additional comments.</li>
<li>Cleaned up settings display for more consistent terminology, widened some input boxes.</li>
</ul>
</li>
<li>Version 1.1.2
<ul>
<li>Changed IP address sorting algorithm to be faster.</li>
</ul>
</li>
<li>Version 1.1.3
<ul>
<li>Fixed <code>MT::PluginData</code> library requirement for the template tags.</li>
</ul>
</li>
<li>Version 1.2.2
<ul>
<li>Added ErrorDocument support.</li>
<li>Added mod_write redirection support.</li>
<li>Added performance tuning parameters to settings.</li>
<li>Improved look and feel of settings display.</li>
<li>Verified MT 3.31 compatibility.</li>
</ul>
</li>
<li>Version 1.2.3
<ul>
<li>Fixed bug where the target URL for mod_rewrite would always be &#8220;sand-trap.php&#8221; in the access file regardless of the settings value.</li>
</ul>
</li>
<li>Version 1.2.4
<ul>
<li>Fixed a minor issue with accessing the junk score constant.</li>
<li>Updated settings HTML to work in both MT 3 and MT 4.</li>
<li>Did minor testing with MT 4.0 to verify compatibility.</li>
</ul>
</li>
</ul>



<p><hr class="fn" align="left"></p>

<p id="fn1"><sup>1</sup> As of this writing, the largest observed attack was roughly 1800 distinct source addresses. These were all detected and banned with no noticeable effect on the weblog. Note that this is for posting attacks only &#8212; reading attacks are not protected against.</p>

<p id="fn2"><sup>2</sup> You might think that it would be more efficient to do incremental updating, but it&#8217;s not. And since it&#8217;s not, it is much more robust to do everything every time.</p>]]>

</content>
</entry>
<entry>
<title>w.bloggar</title>
<link rel="alternate" type="text/html" href="http://blog.thought-mesh.net/solidwallofcode/movable_type/wbloggar.php" />
<modified>2005-08-29T02:21:53Z</modified>
<issued>2005-02-27T21:30:03Z</issued>
<id>tag:blog.thought-mesh.net,2005:/solidwallofcode/2.1497</id>
<created>2005-02-27T21:30:03Z</created>
<summary type="text/plain">A local client for creating and editing MovableType posts</summary>
<author>
<name>aog</name>
<url>http://blog.thought-mesh.net</url>
<email>aog@thought-mesh.net</email>
</author>
<dc:subject>Movable Type</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://blog.thought-mesh.net/solidwallofcode/">
<![CDATA[<p><a href="http://wbloggar.com">w.bloggar</a> is an XML RPC client for <a href="http://movabletype.org">Movable Type</a>. It allows the creation and editing of posts in a local client. I find it much more convienent than the standard <a href="http://movabletype.org">Movable Type</a> web interface (which I very rarely use for working on posts). The only drawback currently is that preview doesn&#8217;t take in to account any plugins.</p>]]>

</content>
</entry>
<entry>
<title>MovableType RPC Extension</title>
<link rel="alternate" type="text/html" href="http://blog.thought-mesh.net/solidwallofcode/mt_projects/movabletype_rpc.php" />
<modified>2005-08-29T02:21:53Z</modified>
<issued>2005-02-27T19:35:27Z</issued>
<id>tag:blog.thought-mesh.net,2005:/solidwallofcode/2.1496</id>
<created>2005-02-27T19:35:27Z</created>
<summary type="text/plain">Extended RPC support for MovableType</summary>
<author>
<name>aog</name>
<url>http://blog.thought-mesh.net</url>
<email>aog@thought-mesh.net</email>
</author>
<dc:subject>MT Projects</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://blog.thought-mesh.net/solidwallofcode/">
<![CDATA[<p>This project is a <a href="http://orbital-mind-control-laser.net/resources/XMLRPCServer.pm">modified version</a> of the <code>XMLRPCServer.pm</code> file from <a href="http://movabletype.org">Movable Type</a>. It is (almost) completely backwards compatible with the original version, but provides three sets of extensions.</p>


<ul>
<li>Tweaks to the original implementation to correct errors or provide easier use</li>
<li>Extensions to existing functionality</li>
<li>Additional functionality similar to but distinct from the original functionality</li>
</ul>



<p>To install this, replace the existing file in <code>lib/MT</code> with the <a href="http://orbital-mind-control-laser.net/resources/XMLRPCServer.pm">modified version</a>. Be sure to have a backup copy of the original somewhere, although you can recover if necessary by downloading the original <a href="http://movabletype.org">Movable Type</a> distribution and copying the original file from there.</p>

<h2>Tweaks</h2>


<ul>
<li><code>publishPost</code> will now set the post state to &#8220;PUBLISH&#8221; if it is not already. This resolves an issue I have with <a href="http://blog.thought-mesh.net/solidwallofcode/movable_type/wbloggar.php" title="A local client for creating and editing MovableType posts">w.bloggar</a> leaving new posts in &#8220;DRAFT&#8221; state. In my view, if the client calls this method to publish a post, the post should end up published, i.e. publically visible.</li>
<li><code>editPost</code> and <code>newPost</code> will now accept the trackback URLs to pick as a space separated string, in addition to an array of strings. This fixes <a href="http://wbloggar.com/forum/viewtopic.php?t=2188">an issue</a> with <a href="http://blog.thought-mesh.net/solidwallofcode/movable_type/wbloggar.php" title="A local client for creating and editing MovableType posts">w.bloggar</a>.</li>
<li><code>editPost</code> supports modifying the author of a post. It still requires that the specified author be associated with the weblog for the post.</li>
</ul>



<h2>Extensions</h2>

<p><dl>
<dt>MovableTypeRPC_getPost</dt>
<dd>The data returned can be controlled by the caller by specifying which fields to return.</dd>
</dl></p>

<h2>Additional</h2>

<p><dl>
<dt><a href="http://blog.thought-mesh.net/solidwallofcode/mt_projects/mtxmlrpcgetpost.php" title="MT XMLRPC extension for retreiving a range of posts">MT::XMLRPC::getPostRange</a></dt>
<dd>Get a range of posts by properties.</dd>
<dt><a href="http://blog.thought-mesh.net/solidwallofcode/mt_projects/mtxmlrpcgetcomm_1.php" title="MT XMLRPC extension to get a comment">MT::XMLRPC::getComment</a></dt>
<dd>Get a single comment by comment ID.</dd>
<dt><a href="http://blog.thought-mesh.net/solidwallofcode/mt_projects/mtxmlrpcgetcomm.php" title="MovableType RPC extension for retrieving a range of comments">MT::XMLRPC::getCommentRange</a></dt>
<dd>Get a range of comments by properties.</dd>
</dl></p>]]>

</content>
</entry>
<entry>
<title>MT::XMLRPC::getPostRange</title>
<link rel="alternate" type="text/html" href="http://blog.thought-mesh.net/solidwallofcode/mt_projects/mtxmlrpcgetpost.php" />
<modified>2005-09-06T18:28:29Z</modified>
<issued>2005-02-25T17:37:07Z</issued>
<id>tag:blog.thought-mesh.net,2005:/solidwallofcode/2.1494</id>
<created>2005-02-25T17:37:07Z</created>
<summary type="text/plain">MT XMLRPC extension for retreiving a range of posts</summary>
<author>
<name>aog</name>
<url>http://blog.thought-mesh.net</url>
<email>aog@thought-mesh.net</email>
</author>
<dc:subject>MT Projects</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://blog.thought-mesh.net/solidwallofcode/">
<![CDATA[<p><b>Method</b> <tt>mt.getPostRange</tt><br />
<b>Arguments</b>
<DL>
<DT><i>blogid</i></DT>
<DD>The ID of the weblog from which to retrieve the posts.</DD>
<DT><i>user</i></DT><DD>A user name for an author associated with the weblog.</DD>
<DT><i>password</i></DT><DD>The password for the author</DD>
<DT><i>terms</i></DT>
<DD>The search terms for locating the range of posts. The available terms are
<DL><DT><i>count</i></DT><DD>The maximum number of posts in the range.</DD>
<DT><i>before</i></DT><DD>Include only posts that were created before the time specified.</DD>
<DT><i>after</i></DT><DD>Include only posts that were created after the time specified.</DD>
<DT><i>reverse</i></DT><DD>If <i>count</i> is specified, then the posts are counted from latest to earliest. If this term is specified and true then the posts are counted in the reverse direction.
</DL>
</DD>
<DT><i>fields</i></DT>
<DD>The fields to return. If this field is not present, a default set of fields are returned to emulate the original behavior. The default set is all fields not marked &#8220;by request only&#8221;.
<DL>
<dt><i>postid</i></dt><dd>The ID of the post.</dd>
<dt><i>userid</i></dt><dd>The ID of the author of the post.</dd>
<dt><i>mt_blogid</i></dt><dd>The ID of the weblog in which the post appears. By request only.</dd>
<dt><i>title</i></dt><dd>The title of the post.</dd>
<dt><i>description</i></dt><dd>The text in the post. </dd>
<dt><i>content</i></dt><dd>A synonymn for the <i>description</i> field. This is used by the <tt>getRecentPosts</tt> method. By request only.</dd>
<dt><i>mt_description_length</i></dt><dd>Length of the description. By request only.</dd>
<dt><i>dateCreated</i></dt><dd>Timestamp of when the post was created.</dd>
<dt><i>link</i></dt><dd>The URL for the post.</dd>
<dt><i>permaLink</i></dt><dd> Synonym for the <i>link</i> field.</dd>
<dt><i>mt_allow_pings</i></dt><dd>Whether pings are allowed.</dd>
<dt><i> mt_allow_comments</i></dt><dd>Whether comments are allowed</dd>
<dt><i>mt_convert_breaks</i></dt><dd>Text filter</dd>
<dt><i>mt_text_more</i></dt><dd>Extended entry text for the post</dd>
<dt><i>mt_excerpt</i></dt><dd>Excerpt for the post</dd>
<dt><i>mt_keywords</i></dt><dd>Keywords for the post</dd>
<dt><i>mt_status</i></dt><dd>Status (0:draft, 1:publish). By request only.</dd>
</DL>
</DD>
</DL>
If no fields are supplied, then all fields not marked &#8220;by request only&#8221; are returned.</p>

<p>If the name and password are specified as empty strings then the call still succeeds but only published posts are returned. Draft posts are ignored.</p>]]>

</content>
</entry>

</feed>