<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Say what???: Category SysAdmin</title>
    <link>http://drotner.org/articles/category/sysadmin</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>by Kelly McCauley</description>
    <item>
      <title>Getting a grip on archiving mail threads</title>
      <description>&lt;p&gt;I&amp;#8217;m subscribed to both the Ruby Talk and Ruby on Rails mailing lists.  Both
are high volume.  I typically don&amp;#8217;t have enough time to read all that is going
on, but I do like to have the emails around so I can search for a specific
topic.&lt;/p&gt;

&lt;p&gt;I like to keep my high volume mailing lists&amp;#8217; threads archived by month.  This
means that the topic thread head&amp;#8217;s &lt;code&gt;Date&lt;/code&gt; header determines where the entire
thread is archived, even if the thread children&amp;#8217;s &lt;code&gt;Date&lt;/code&gt; header is a different
month.  For a low volume lists, this can be done by hand using any mail client.
For high volume lists, doing it by hand is tedious and prone to mistakes.
Computers are for this type of task.  It is time to work hard at being
lazy&amp;#8230;&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s what I did to tackle this problem.  My time was limited, I only had a
couple of hours to create something to do the above for my two high volume
lists.  I had two Maildirs containing the Ruby Talk (&lt;code&gt;~/.maildir/.ruby.talk&lt;/code&gt;)
and Ruby on Rails (&lt;code&gt;~/.maildir/.ruby.rails&lt;/code&gt;) mailing lists.  Each contained
more than 50,000 emails stored in individual files in the lists&amp;#8217; &lt;code&gt;/cur&lt;/code&gt;
directory.&lt;/p&gt;

&lt;p&gt;So my &lt;code&gt;~/.maildir&lt;/code&gt; is organized like the following:&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;15&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;.ruby.rails/&lt;tt&gt;
&lt;/tt&gt;.ruby.rails.200603/&lt;tt&gt;
&lt;/tt&gt;.ruby.rails.200604/&lt;tt&gt;
&lt;/tt&gt;.ruby.rails.200605/&lt;tt&gt;
&lt;/tt&gt;.ruby.rails.200606/&lt;tt&gt;
&lt;/tt&gt;.ruby.rails.200607/&lt;tt&gt;
&lt;/tt&gt;.ruby.rails.200608/&lt;tt&gt;
&lt;/tt&gt;.ruby.rails.200609/&lt;tt&gt;
&lt;/tt&gt;.ruby.rails.200610/&lt;tt&gt;
&lt;/tt&gt;.ruby.rails.200611/&lt;tt&gt;
&lt;/tt&gt;.ruby.talk/&lt;tt&gt;
&lt;/tt&gt;.ruby.talk.200603/&lt;tt&gt;
&lt;/tt&gt;.ruby.talk.200604/&lt;tt&gt;
&lt;/tt&gt;.ruby.talk.200605/&lt;tt&gt;
&lt;/tt&gt;.ruby.talk.200606/&lt;tt&gt;
&lt;/tt&gt;.ruby.talk.200607/&lt;tt&gt;
&lt;/tt&gt;.ruby.talk.200608/&lt;tt&gt;
&lt;/tt&gt;.ruby.talk.200609/&lt;tt&gt;
&lt;/tt&gt;.ruby.talk.200610/&lt;tt&gt;
&lt;/tt&gt;.ruby.talk.200611/&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


&lt;p&gt;The requirements were:&lt;/p&gt;

	&lt;ul&gt;
	&lt;li&gt;Archive threads into the appropriate archive directories (should correctly archive 99.9% of the time).&lt;/li&gt;
		&lt;li&gt;Keep track of thread heads and their associated archive location so subsequent runs catch thread children dated after the previous run.&lt;/li&gt;
		&lt;li&gt;Shouldn&amp;#8217;t consume excessive amounts of memory.&lt;/li&gt;
	&lt;/ul&gt;


&lt;p&gt;Since I intended to be the sole user of this program and the scope of
functionality was so narrow, I decided to write a self contained script to
flesh out the logic and behavior.  This meant that testing by hand was OK for
me (if this was developed for someone else, I would not choose this path).
Future development iterations, I will break out the functionality into classes
and modules along with real test specs.&lt;/p&gt;

&lt;p&gt;The next decision I had was to decided how to process email headers.  Since
&lt;a href="http://tmail.rubyforge.org/"&gt;TMail&lt;/a&gt; is being maintained again, I decided to use
it instead of parsing the email headers my self.&lt;/p&gt;

&lt;p&gt;The following is the heavily commented script that I created. The most current source can be found at &lt;a href="http://svn.drotner.org/repos/unix_tools/trunk/bin/mail_sort.rb"&gt;http://svn.drotner.org/repos/unix_tools/trunk/bin/mail_sort.rb&lt;/a&gt;&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;15&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;25&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;27&lt;tt&gt;
&lt;/tt&gt;28&lt;tt&gt;
&lt;/tt&gt;29&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;31&lt;tt&gt;
&lt;/tt&gt;32&lt;tt&gt;
&lt;/tt&gt;33&lt;tt&gt;
&lt;/tt&gt;34&lt;tt&gt;
&lt;/tt&gt;35&lt;tt&gt;
&lt;/tt&gt;36&lt;tt&gt;
&lt;/tt&gt;37&lt;tt&gt;
&lt;/tt&gt;38&lt;tt&gt;
&lt;/tt&gt;39&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;40&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;41&lt;tt&gt;
&lt;/tt&gt;42&lt;tt&gt;
&lt;/tt&gt;43&lt;tt&gt;
&lt;/tt&gt;44&lt;tt&gt;
&lt;/tt&gt;45&lt;tt&gt;
&lt;/tt&gt;46&lt;tt&gt;
&lt;/tt&gt;47&lt;tt&gt;
&lt;/tt&gt;48&lt;tt&gt;
&lt;/tt&gt;49&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;50&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;51&lt;tt&gt;
&lt;/tt&gt;52&lt;tt&gt;
&lt;/tt&gt;53&lt;tt&gt;
&lt;/tt&gt;54&lt;tt&gt;
&lt;/tt&gt;55&lt;tt&gt;
&lt;/tt&gt;56&lt;tt&gt;
&lt;/tt&gt;57&lt;tt&gt;
&lt;/tt&gt;58&lt;tt&gt;
&lt;/tt&gt;59&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;60&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;61&lt;tt&gt;
&lt;/tt&gt;62&lt;tt&gt;
&lt;/tt&gt;63&lt;tt&gt;
&lt;/tt&gt;64&lt;tt&gt;
&lt;/tt&gt;65&lt;tt&gt;
&lt;/tt&gt;66&lt;tt&gt;
&lt;/tt&gt;67&lt;tt&gt;
&lt;/tt&gt;68&lt;tt&gt;
&lt;/tt&gt;69&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;70&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;71&lt;tt&gt;
&lt;/tt&gt;72&lt;tt&gt;
&lt;/tt&gt;73&lt;tt&gt;
&lt;/tt&gt;74&lt;tt&gt;
&lt;/tt&gt;75&lt;tt&gt;
&lt;/tt&gt;76&lt;tt&gt;
&lt;/tt&gt;77&lt;tt&gt;
&lt;/tt&gt;78&lt;tt&gt;
&lt;/tt&gt;79&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;80&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;81&lt;tt&gt;
&lt;/tt&gt;82&lt;tt&gt;
&lt;/tt&gt;83&lt;tt&gt;
&lt;/tt&gt;84&lt;tt&gt;
&lt;/tt&gt;85&lt;tt&gt;
&lt;/tt&gt;86&lt;tt&gt;
&lt;/tt&gt;87&lt;tt&gt;
&lt;/tt&gt;88&lt;tt&gt;
&lt;/tt&gt;89&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;90&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;91&lt;tt&gt;
&lt;/tt&gt;92&lt;tt&gt;
&lt;/tt&gt;93&lt;tt&gt;
&lt;/tt&gt;94&lt;tt&gt;
&lt;/tt&gt;95&lt;tt&gt;
&lt;/tt&gt;96&lt;tt&gt;
&lt;/tt&gt;97&lt;tt&gt;
&lt;/tt&gt;98&lt;tt&gt;
&lt;/tt&gt;99&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;100&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;101&lt;tt&gt;
&lt;/tt&gt;102&lt;tt&gt;
&lt;/tt&gt;103&lt;tt&gt;
&lt;/tt&gt;104&lt;tt&gt;
&lt;/tt&gt;105&lt;tt&gt;
&lt;/tt&gt;106&lt;tt&gt;
&lt;/tt&gt;107&lt;tt&gt;
&lt;/tt&gt;108&lt;tt&gt;
&lt;/tt&gt;109&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;110&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;111&lt;tt&gt;
&lt;/tt&gt;112&lt;tt&gt;
&lt;/tt&gt;113&lt;tt&gt;
&lt;/tt&gt;114&lt;tt&gt;
&lt;/tt&gt;115&lt;tt&gt;
&lt;/tt&gt;116&lt;tt&gt;
&lt;/tt&gt;117&lt;tt&gt;
&lt;/tt&gt;118&lt;tt&gt;
&lt;/tt&gt;119&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;120&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;121&lt;tt&gt;
&lt;/tt&gt;122&lt;tt&gt;
&lt;/tt&gt;123&lt;tt&gt;
&lt;/tt&gt;124&lt;tt&gt;
&lt;/tt&gt;125&lt;tt&gt;
&lt;/tt&gt;126&lt;tt&gt;
&lt;/tt&gt;127&lt;tt&gt;
&lt;/tt&gt;128&lt;tt&gt;
&lt;/tt&gt;129&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;130&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;131&lt;tt&gt;
&lt;/tt&gt;132&lt;tt&gt;
&lt;/tt&gt;133&lt;tt&gt;
&lt;/tt&gt;134&lt;tt&gt;
&lt;/tt&gt;135&lt;tt&gt;
&lt;/tt&gt;136&lt;tt&gt;
&lt;/tt&gt;137&lt;tt&gt;
&lt;/tt&gt;138&lt;tt&gt;
&lt;/tt&gt;139&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;140&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;141&lt;tt&gt;
&lt;/tt&gt;142&lt;tt&gt;
&lt;/tt&gt;143&lt;tt&gt;
&lt;/tt&gt;144&lt;tt&gt;
&lt;/tt&gt;145&lt;tt&gt;
&lt;/tt&gt;146&lt;tt&gt;
&lt;/tt&gt;147&lt;tt&gt;
&lt;/tt&gt;148&lt;tt&gt;
&lt;/tt&gt;149&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;150&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;151&lt;tt&gt;
&lt;/tt&gt;152&lt;tt&gt;
&lt;/tt&gt;153&lt;tt&gt;
&lt;/tt&gt;154&lt;tt&gt;
&lt;/tt&gt;155&lt;tt&gt;
&lt;/tt&gt;156&lt;tt&gt;
&lt;/tt&gt;157&lt;tt&gt;
&lt;/tt&gt;158&lt;tt&gt;
&lt;/tt&gt;159&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;160&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;161&lt;tt&gt;
&lt;/tt&gt;162&lt;tt&gt;
&lt;/tt&gt;163&lt;tt&gt;
&lt;/tt&gt;164&lt;tt&gt;
&lt;/tt&gt;165&lt;tt&gt;
&lt;/tt&gt;166&lt;tt&gt;
&lt;/tt&gt;167&lt;tt&gt;
&lt;/tt&gt;168&lt;tt&gt;
&lt;/tt&gt;169&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;170&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;171&lt;tt&gt;
&lt;/tt&gt;172&lt;tt&gt;
&lt;/tt&gt;173&lt;tt&gt;
&lt;/tt&gt;174&lt;tt&gt;
&lt;/tt&gt;175&lt;tt&gt;
&lt;/tt&gt;176&lt;tt&gt;
&lt;/tt&gt;177&lt;tt&gt;
&lt;/tt&gt;178&lt;tt&gt;
&lt;/tt&gt;179&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;180&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;181&lt;tt&gt;
&lt;/tt&gt;182&lt;tt&gt;
&lt;/tt&gt;183&lt;tt&gt;
&lt;/tt&gt;184&lt;tt&gt;
&lt;/tt&gt;185&lt;tt&gt;
&lt;/tt&gt;186&lt;tt&gt;
&lt;/tt&gt;187&lt;tt&gt;
&lt;/tt&gt;188&lt;tt&gt;
&lt;/tt&gt;189&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;190&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;191&lt;tt&gt;
&lt;/tt&gt;192&lt;tt&gt;
&lt;/tt&gt;193&lt;tt&gt;
&lt;/tt&gt;194&lt;tt&gt;
&lt;/tt&gt;195&lt;tt&gt;
&lt;/tt&gt;196&lt;tt&gt;
&lt;/tt&gt;197&lt;tt&gt;
&lt;/tt&gt;198&lt;tt&gt;
&lt;/tt&gt;199&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;200&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;201&lt;tt&gt;
&lt;/tt&gt;202&lt;tt&gt;
&lt;/tt&gt;203&lt;tt&gt;
&lt;/tt&gt;204&lt;tt&gt;
&lt;/tt&gt;205&lt;tt&gt;
&lt;/tt&gt;206&lt;tt&gt;
&lt;/tt&gt;207&lt;tt&gt;
&lt;/tt&gt;208&lt;tt&gt;
&lt;/tt&gt;209&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;210&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;211&lt;tt&gt;
&lt;/tt&gt;212&lt;tt&gt;
&lt;/tt&gt;213&lt;tt&gt;
&lt;/tt&gt;214&lt;tt&gt;
&lt;/tt&gt;215&lt;tt&gt;
&lt;/tt&gt;216&lt;tt&gt;
&lt;/tt&gt;217&lt;tt&gt;
&lt;/tt&gt;218&lt;tt&gt;
&lt;/tt&gt;219&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;220&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;221&lt;tt&gt;
&lt;/tt&gt;222&lt;tt&gt;
&lt;/tt&gt;223&lt;tt&gt;
&lt;/tt&gt;224&lt;tt&gt;
&lt;/tt&gt;225&lt;tt&gt;
&lt;/tt&gt;226&lt;tt&gt;
&lt;/tt&gt;227&lt;tt&gt;
&lt;/tt&gt;228&lt;tt&gt;
&lt;/tt&gt;229&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;230&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;231&lt;tt&gt;
&lt;/tt&gt;232&lt;tt&gt;
&lt;/tt&gt;233&lt;tt&gt;
&lt;/tt&gt;234&lt;tt&gt;
&lt;/tt&gt;235&lt;tt&gt;
&lt;/tt&gt;236&lt;tt&gt;
&lt;/tt&gt;237&lt;tt&gt;
&lt;/tt&gt;238&lt;tt&gt;
&lt;/tt&gt;239&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;240&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;241&lt;tt&gt;
&lt;/tt&gt;242&lt;tt&gt;
&lt;/tt&gt;243&lt;tt&gt;
&lt;/tt&gt;244&lt;tt&gt;
&lt;/tt&gt;245&lt;tt&gt;
&lt;/tt&gt;246&lt;tt&gt;
&lt;/tt&gt;247&lt;tt&gt;
&lt;/tt&gt;248&lt;tt&gt;
&lt;/tt&gt;249&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;250&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;251&lt;tt&gt;
&lt;/tt&gt;252&lt;tt&gt;
&lt;/tt&gt;253&lt;tt&gt;
&lt;/tt&gt;254&lt;tt&gt;
&lt;/tt&gt;255&lt;tt&gt;
&lt;/tt&gt;256&lt;tt&gt;
&lt;/tt&gt;257&lt;tt&gt;
&lt;/tt&gt;258&lt;tt&gt;
&lt;/tt&gt;259&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;260&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;261&lt;tt&gt;
&lt;/tt&gt;262&lt;tt&gt;
&lt;/tt&gt;263&lt;tt&gt;
&lt;/tt&gt;264&lt;tt&gt;
&lt;/tt&gt;265&lt;tt&gt;
&lt;/tt&gt;266&lt;tt&gt;
&lt;/tt&gt;267&lt;tt&gt;
&lt;/tt&gt;268&lt;tt&gt;
&lt;/tt&gt;269&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;270&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;271&lt;tt&gt;
&lt;/tt&gt;272&lt;tt&gt;
&lt;/tt&gt;273&lt;tt&gt;
&lt;/tt&gt;274&lt;tt&gt;
&lt;/tt&gt;275&lt;tt&gt;
&lt;/tt&gt;276&lt;tt&gt;
&lt;/tt&gt;277&lt;tt&gt;
&lt;/tt&gt;278&lt;tt&gt;
&lt;/tt&gt;279&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;280&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;281&lt;tt&gt;
&lt;/tt&gt;282&lt;tt&gt;
&lt;/tt&gt;283&lt;tt&gt;
&lt;/tt&gt;284&lt;tt&gt;
&lt;/tt&gt;285&lt;tt&gt;
&lt;/tt&gt;286&lt;tt&gt;
&lt;/tt&gt;287&lt;tt&gt;
&lt;/tt&gt;288&lt;tt&gt;
&lt;/tt&gt;289&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;290&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;291&lt;tt&gt;
&lt;/tt&gt;292&lt;tt&gt;
&lt;/tt&gt;293&lt;tt&gt;
&lt;/tt&gt;294&lt;tt&gt;
&lt;/tt&gt;295&lt;tt&gt;
&lt;/tt&gt;296&lt;tt&gt;
&lt;/tt&gt;297&lt;tt&gt;
&lt;/tt&gt;298&lt;tt&gt;
&lt;/tt&gt;299&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;300&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;301&lt;tt&gt;
&lt;/tt&gt;302&lt;tt&gt;
&lt;/tt&gt;303&lt;tt&gt;
&lt;/tt&gt;304&lt;tt&gt;
&lt;/tt&gt;305&lt;tt&gt;
&lt;/tt&gt;306&lt;tt&gt;
&lt;/tt&gt;307&lt;tt&gt;
&lt;/tt&gt;308&lt;tt&gt;
&lt;/tt&gt;309&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;310&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;311&lt;tt&gt;
&lt;/tt&gt;312&lt;tt&gt;
&lt;/tt&gt;313&lt;tt&gt;
&lt;/tt&gt;314&lt;tt&gt;
&lt;/tt&gt;315&lt;tt&gt;
&lt;/tt&gt;316&lt;tt&gt;
&lt;/tt&gt;317&lt;tt&gt;
&lt;/tt&gt;318&lt;tt&gt;
&lt;/tt&gt;319&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;320&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;321&lt;tt&gt;
&lt;/tt&gt;322&lt;tt&gt;
&lt;/tt&gt;323&lt;tt&gt;
&lt;/tt&gt;324&lt;tt&gt;
&lt;/tt&gt;325&lt;tt&gt;
&lt;/tt&gt;326&lt;tt&gt;
&lt;/tt&gt;327&lt;tt&gt;
&lt;/tt&gt;328&lt;tt&gt;
&lt;/tt&gt;329&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;330&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;331&lt;tt&gt;
&lt;/tt&gt;332&lt;tt&gt;
&lt;/tt&gt;333&lt;tt&gt;
&lt;/tt&gt;334&lt;tt&gt;
&lt;/tt&gt;335&lt;tt&gt;
&lt;/tt&gt;336&lt;tt&gt;
&lt;/tt&gt;337&lt;tt&gt;
&lt;/tt&gt;338&lt;tt&gt;
&lt;/tt&gt;339&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;340&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;341&lt;tt&gt;
&lt;/tt&gt;342&lt;tt&gt;
&lt;/tt&gt;343&lt;tt&gt;
&lt;/tt&gt;344&lt;tt&gt;
&lt;/tt&gt;345&lt;tt&gt;
&lt;/tt&gt;346&lt;tt&gt;
&lt;/tt&gt;347&lt;tt&gt;
&lt;/tt&gt;348&lt;tt&gt;
&lt;/tt&gt;349&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;350&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;351&lt;tt&gt;
&lt;/tt&gt;352&lt;tt&gt;
&lt;/tt&gt;353&lt;tt&gt;
&lt;/tt&gt;354&lt;tt&gt;
&lt;/tt&gt;355&lt;tt&gt;
&lt;/tt&gt;356&lt;tt&gt;
&lt;/tt&gt;357&lt;tt&gt;
&lt;/tt&gt;358&lt;tt&gt;
&lt;/tt&gt;359&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;360&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;361&lt;tt&gt;
&lt;/tt&gt;362&lt;tt&gt;
&lt;/tt&gt;363&lt;tt&gt;
&lt;/tt&gt;364&lt;tt&gt;
&lt;/tt&gt;365&lt;tt&gt;
&lt;/tt&gt;366&lt;tt&gt;
&lt;/tt&gt;367&lt;tt&gt;
&lt;/tt&gt;368&lt;tt&gt;
&lt;/tt&gt;369&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;370&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;371&lt;tt&gt;
&lt;/tt&gt;372&lt;tt&gt;
&lt;/tt&gt;373&lt;tt&gt;
&lt;/tt&gt;374&lt;tt&gt;
&lt;/tt&gt;375&lt;tt&gt;
&lt;/tt&gt;376&lt;tt&gt;
&lt;/tt&gt;377&lt;tt&gt;
&lt;/tt&gt;378&lt;tt&gt;
&lt;/tt&gt;379&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;380&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;381&lt;tt&gt;
&lt;/tt&gt;382&lt;tt&gt;
&lt;/tt&gt;383&lt;tt&gt;
&lt;/tt&gt;384&lt;tt&gt;
&lt;/tt&gt;385&lt;tt&gt;
&lt;/tt&gt;386&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&lt;span class="c"&gt;#!/usr/bin/env ruby&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Author: Kelly McCauley&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Copyright 2007 Kelly McCauley&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Source: http://svn.drotner.org/repos/unix_tools/trunk/bin/mail_sort.rb&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# License: version 0.1 is Public Domain&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;rubygems&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;optparse&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;        &lt;span class="c"&gt;# Parses commandline options&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;tmail&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;           &lt;span class="c"&gt;# Handles the email parsing&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;date&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;            &lt;span class="c"&gt;# Ruby's date library&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;fileutils&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;       &lt;span class="c"&gt;# File and directory manipulation libarary&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="gv"&gt;$VERBOSE&lt;/span&gt; = &lt;span class="pc"&gt;true&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="iv"&gt;@version&lt;/span&gt; = &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;0.1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="iv"&gt;@debug&lt;/span&gt; = &lt;span class="i"&gt;0&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="iv"&gt;@quiet&lt;/span&gt; = &lt;span class="pc"&gt;false&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="iv"&gt;@days_ago&lt;/span&gt; = &lt;span class="i"&gt;30&lt;/span&gt;              &lt;span class="c"&gt;# Default &amp;quot;Sort and archive mail up to @days_ago&amp;quot;.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="iv"&gt;@src_mail_dir&lt;/span&gt; = &lt;span class="pc"&gt;nil&lt;/span&gt;         &lt;span class="c"&gt;# Maildir to sort and archive.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="iv"&gt;@thread_heads&lt;/span&gt; = {}          &lt;span class="c"&gt;# Maps a thread head's Message-ID to&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;                            &lt;span class="c"&gt;# its associated archive directory.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="iv"&gt;@thread_head_index&lt;/span&gt; = &lt;span class="pc"&gt;nil&lt;/span&gt;    &lt;span class="c"&gt;# Location of a saved version of @thread_heads&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;                            &lt;span class="c"&gt;# from a previous run.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="iv"&gt;@total_orphans&lt;/span&gt; = &lt;span class="i"&gt;0&lt;/span&gt;          &lt;span class="c"&gt;# Count of thread children that have no parents.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="iv"&gt;@total_emails&lt;/span&gt; = &lt;span class="i"&gt;0&lt;/span&gt;           &lt;span class="c"&gt;# Total emails read.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="iv"&gt;@total_emails_archived&lt;/span&gt; = &lt;span class="i"&gt;0&lt;/span&gt;  &lt;span class="c"&gt;# Total emails that were moved to an archive&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;                            &lt;span class="c"&gt;# directory.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Methods&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Prints out the given msgs and opts to STDERR and then exits&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;error_exit&lt;/span&gt;(opts, *msgs)&lt;tt&gt;
&lt;/tt&gt;  msgs.each {|m| &lt;span class="gv"&gt;$stderr&lt;/span&gt;.print m}&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="gv"&gt;$stderr&lt;/span&gt;.puts opts&lt;tt&gt;
&lt;/tt&gt;  exit(&lt;span class="i"&gt;1&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Loads a saved @thread_heads from a previous run into memory.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;load_thread_head_index&lt;/span&gt;(index_file)&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;if&lt;/span&gt; &lt;span class="co"&gt;File&lt;/span&gt;.file?(index_file)&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="co"&gt;File&lt;/span&gt;.open(index_file) &lt;span class="r"&gt;do&lt;/span&gt; |file|&lt;tt&gt;
&lt;/tt&gt;      file.each_line &lt;span class="r"&gt;do&lt;/span&gt; |line|&lt;tt&gt;
&lt;/tt&gt;        key, year, sum, mon = line.chomp.split(&lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="ch"&gt;\t&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;        &lt;span class="iv"&gt;@thread_heads&lt;/span&gt;[key.to_sym] = [year.to_sym, sum.to_i, mon.to_sym]&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Dumps @thread_heads that are less than 365 days ago to a file.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# I didn't serialize it to YAML because I didn't want the extra processing&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# overhead or memory consumption.  I didn't Marshal it since I wanted the&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# saved file to be tied to the particular version of Marshal.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;dump_thread_head_index&lt;/span&gt;(index_file)&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="co"&gt;File&lt;/span&gt;.open(index_file, &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;w&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;) &lt;span class="r"&gt;do&lt;/span&gt; |file|&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="iv"&gt;@thread_heads&lt;/span&gt;.each &lt;span class="r"&gt;do&lt;/span&gt; |key,value|&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;next&lt;/span&gt; &lt;span class="r"&gt;if&lt;/span&gt; value[&lt;span class="i"&gt;1&lt;/span&gt;] &amp;lt; &lt;span class="iv"&gt;@th_index_cutoff_sum&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      file &amp;lt;&amp;lt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;key.to_s&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="ch"&gt;\t&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;value.map{|x| x.to_s}.join(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="ch"&gt;\t&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="ch"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="iv"&gt;@th_index_dump_count&lt;/span&gt; += &lt;span class="i"&gt;1&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Adds the given email to the @thread_heads lookup table.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;add_thread_head&lt;/span&gt;(email)&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;unless&lt;/span&gt; &lt;span class="iv"&gt;@thread_heads&lt;/span&gt;.key?(email[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;message-id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;].id.to_sym)&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="gv"&gt;$stderr&lt;/span&gt;.puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;th subject: '&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;email[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;subject&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;].to_s&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;if&lt;/span&gt; &lt;span class="iv"&gt;@debug&lt;/span&gt; &amp;gt; &lt;span class="i"&gt;2&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="iv"&gt;@thread_heads&lt;/span&gt;[email[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;message-id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;].id.to_sym] = [&lt;tt&gt;
&lt;/tt&gt;      email[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;date&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;].date.year.to_s.to_sym,&lt;tt&gt;
&lt;/tt&gt;      (&lt;tt&gt;
&lt;/tt&gt;        email[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;date&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;].date.year.to_s +&lt;tt&gt;
&lt;/tt&gt;        sprintf(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;%02d&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, email[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;date&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;].date.mon) +&lt;tt&gt;
&lt;/tt&gt;        sprintf(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;%02d&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, email[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;date&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;].date.day)&lt;tt&gt;
&lt;/tt&gt;      ).to_i,&lt;tt&gt;
&lt;/tt&gt;      sprintf(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;%02d&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, email[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;date&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;].date.mon).to_sym,&lt;tt&gt;
&lt;/tt&gt;    ]&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Creates the archive maildir&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;create_archive_maildir&lt;/span&gt;(root_archive_dir)&lt;tt&gt;
&lt;/tt&gt;  sub_dirs = []&lt;tt&gt;
&lt;/tt&gt;  sub_dirs &amp;lt;&amp;lt; &lt;span class="co"&gt;File&lt;/span&gt;.join(root_archive_dir, &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;cur&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  sub_dirs &amp;lt;&amp;lt; &lt;span class="co"&gt;File&lt;/span&gt;.join(root_archive_dir, &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  sub_dirs &amp;lt;&amp;lt; &lt;span class="co"&gt;File&lt;/span&gt;.join(root_archive_dir, &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;tmp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  options = {}&lt;tt&gt;
&lt;/tt&gt;  options[&lt;span class="sy"&gt;:noop&lt;/span&gt;] = &lt;span class="pc"&gt;true&lt;/span&gt; &lt;span class="r"&gt;if&lt;/span&gt; &lt;span class="iv"&gt;@debug&lt;/span&gt; &amp;gt; &lt;span class="i"&gt;2&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  options[&lt;span class="sy"&gt;:verbose&lt;/span&gt;] = &lt;span class="pc"&gt;true&lt;/span&gt; &lt;span class="r"&gt;if&lt;/span&gt; &lt;span class="iv"&gt;@debug&lt;/span&gt; &amp;gt; &lt;span class="i"&gt;1&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  sub_dirs.each &lt;span class="r"&gt;do&lt;/span&gt; |dir|&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;unless&lt;/span&gt; &lt;span class="co"&gt;File&lt;/span&gt;.directory?(dir)&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="co"&gt;FileUtils&lt;/span&gt;.mkdir_p(dir, options)&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;return&lt;/span&gt; sub_dirs&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Archives the given file to the give archive directory&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;archive_email&lt;/span&gt;(root_archive_dir, filename)&lt;tt&gt;
&lt;/tt&gt;  archive_dir = create_archive_maildir(root_archive_dir).shift&lt;tt&gt;
&lt;/tt&gt;  options = {}&lt;tt&gt;
&lt;/tt&gt;  options[&lt;span class="sy"&gt;:noop&lt;/span&gt;] = &lt;span class="pc"&gt;true&lt;/span&gt; &lt;span class="r"&gt;if&lt;/span&gt; &lt;span class="iv"&gt;@debug&lt;/span&gt; &amp;gt; &lt;span class="i"&gt;2&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  options[&lt;span class="sy"&gt;:verbose&lt;/span&gt;] = &lt;span class="pc"&gt;true&lt;/span&gt; &lt;span class="r"&gt;if&lt;/span&gt; &lt;span class="iv"&gt;@debug&lt;/span&gt; &amp;gt; &lt;span class="i"&gt;1&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;if&lt;/span&gt; &lt;span class="iv"&gt;@debug&lt;/span&gt; &amp;gt; &lt;span class="i"&gt;0&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="co"&gt;FileUtils&lt;/span&gt;.cp(filename, archive_dir, options)&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;else&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="co"&gt;FileUtils&lt;/span&gt;.mv(filename, archive_dir)&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="iv"&gt;@total_emails_archived&lt;/span&gt; += &lt;span class="i"&gt;1&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Archives the thread child email into the appropriate maildir&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;archive_thread_child&lt;/span&gt;(thread_head, src_mail_dir, filename)&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="gv"&gt;$stderr&lt;/span&gt;.puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;tc &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;filename&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;:  &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="iv"&gt;@thread_heads&lt;/span&gt;[thread_head][&lt;span class="i"&gt;1&lt;/span&gt;]&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt; &amp;lt;= &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="iv"&gt;@cutoff_sum&lt;/span&gt;&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;if&lt;/span&gt; &lt;span class="iv"&gt;@debug&lt;/span&gt; &amp;gt; &lt;span class="i"&gt;2&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;if&lt;/span&gt; (&lt;span class="iv"&gt;@thread_heads&lt;/span&gt;[thread_head][&lt;span class="i"&gt;1&lt;/span&gt;] &amp;lt;= &lt;span class="iv"&gt;@cutoff_sum&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="gv"&gt;$stderr&lt;/span&gt;.puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;tc filename: &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;filename&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;if&lt;/span&gt; &lt;span class="iv"&gt;@debug&lt;/span&gt; &amp;gt; &lt;span class="i"&gt;2&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    root_archive_dir = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="co"&gt;File&lt;/span&gt;.expand_path(src_mail_dir)&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;.&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="iv"&gt;@thread_heads&lt;/span&gt;[thread_head].first.to_s&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="iv"&gt;@thread_heads&lt;/span&gt;[thread_head].last.to_s&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    archive_email(root_archive_dir, filename)&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Archives the thread head email into the appropriate maildir&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;archive_thread_head&lt;/span&gt;(email, src_mail_dir, filename)&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# Determine this email's date sum.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  email_sum = (&lt;tt&gt;
&lt;/tt&gt;    email[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;date&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;].date.year.to_s +&lt;tt&gt;
&lt;/tt&gt;    sprintf(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;%02d&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, email[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;date&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;].date.mon) +&lt;tt&gt;
&lt;/tt&gt;    sprintf(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;%02d&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, email[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;date&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;].date.day)&lt;tt&gt;
&lt;/tt&gt;  ).to_i&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="gv"&gt;$stderr&lt;/span&gt;.puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;th &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;filename&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;:  &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;email_sum&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt; &amp;lt;= &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="iv"&gt;@cutoff_sum&lt;/span&gt;&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;if&lt;/span&gt; &lt;span class="iv"&gt;@debug&lt;/span&gt; &amp;gt; &lt;span class="i"&gt;2&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# Is the email before the cutoff date?&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;if&lt;/span&gt; email_sum &amp;lt;= &lt;span class="iv"&gt;@cutoff_sum&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="c"&gt;# Yes.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="gv"&gt;$stderr&lt;/span&gt;.puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;th filename: &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;filename&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;if&lt;/span&gt; &lt;span class="iv"&gt;@debug&lt;/span&gt; &amp;gt; &lt;span class="i"&gt;2&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    root_archive_dir = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="co"&gt;File&lt;/span&gt;.expand_path(src_mail_dir)&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;.&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;email[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;date&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;].date.year&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;sprintf(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;%02d&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, email[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;date&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;].date.mon)&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="c"&gt;# Archive it.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    archive_email(root_archive_dir, filename)&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Handle the commandline arguments&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;opts = &lt;span class="co"&gt;OptionParser&lt;/span&gt;.new &lt;span class="r"&gt;do&lt;/span&gt; |opts|&lt;tt&gt;
&lt;/tt&gt;  opts.banner = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Usage: &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="gv"&gt;$0&lt;/span&gt;&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt; [OPTIONS] MAILDIR&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  opts.separator(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  opts.separator(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;OPTIONS&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  opts.on(&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;-D&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;,&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;--days-ago NUMBER&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;,&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;Sort and archive mail up to --days-ago&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  ) &lt;span class="r"&gt;do&lt;/span&gt; |days|&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="iv"&gt;@days_ago&lt;/span&gt; = days&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  opts.on(&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;-i&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;,&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;--thread-head-index FILE&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;,&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;Specify the thread head index file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  ) &lt;span class="r"&gt;do&lt;/span&gt; |file|&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="iv"&gt;@thread_head_idx&lt;/span&gt; = file&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  opts.on_tail(&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;-q&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;,&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;--quiet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;,&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;Turns off all output including error output&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  ) &lt;span class="r"&gt;do&lt;/span&gt; |q|&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="iv"&gt;@quiet&lt;/span&gt; = &lt;span class="pc"&gt;true&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  opts.on_tail(&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;-d&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;,&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;--debug&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;,&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;Turns on debugging output&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  ) &lt;span class="r"&gt;do&lt;/span&gt; |debug|&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="iv"&gt;@debug&lt;/span&gt; += &lt;span class="i"&gt;1&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# help&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  opts.on_tail(&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;-h&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;--help&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;Shows this message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  ) &lt;span class="r"&gt;do&lt;/span&gt; ||&lt;tt&gt;
&lt;/tt&gt;    error_exit(opts)&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# version&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  opts.on_tail(&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;-V&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;--version&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;,&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;Shows the version and copyright of db_diff&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  ) &lt;span class="r"&gt;do&lt;/span&gt; ||&lt;tt&gt;
&lt;/tt&gt;    error_exit(opts, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="gv"&gt;$0&lt;/span&gt;&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt; version &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="iv"&gt;@version&lt;/span&gt;&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="ch"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;opts.parse!(&lt;span class="pc"&gt;ARGV&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Make sure that the source Maildir is given and that the directory exists.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="iv"&gt;@src_mail_dir&lt;/span&gt; = &lt;span class="pc"&gt;ARGV&lt;/span&gt;.shift&lt;tt&gt;
&lt;/tt&gt;error_exit(&lt;tt&gt;
&lt;/tt&gt;  opts,&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;ERROR: failed to specify a MAILDIR&lt;/span&gt;&lt;span class="ch"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;) &lt;span class="r"&gt;unless&lt;/span&gt; &lt;span class="iv"&gt;@src_mail_dir&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;error_exit(&lt;tt&gt;
&lt;/tt&gt;  opts,&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;ERROR: MAILDIR does not exist: &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="iv"&gt;@src_mail_dir&lt;/span&gt;&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="ch"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;) &lt;span class="r"&gt;unless&lt;/span&gt; &lt;span class="co"&gt;File&lt;/span&gt;.directory?(&lt;span class="iv"&gt;@src_mail_dir&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Determine the cut-off dates.  Used in simple numerical comparison of dates.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# The cut-off date for determining if thread heads are targeted for archival.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="iv"&gt;@cutoff&lt;/span&gt; = &lt;span class="co"&gt;Date&lt;/span&gt;.today - &lt;span class="iv"&gt;@days_ago&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="iv"&gt;@cutoff_sum&lt;/span&gt; = (&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="iv"&gt;@cutoff&lt;/span&gt;.year.to_s +&lt;tt&gt;
&lt;/tt&gt;  sprintf(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;%02d&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="iv"&gt;@cutoff&lt;/span&gt;.mon) +&lt;tt&gt;
&lt;/tt&gt;  sprintf(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;%02d&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="iv"&gt;@cutoff&lt;/span&gt;.day)&lt;tt&gt;
&lt;/tt&gt;).to_i&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# The cut-off date for storing thread heads in @thread_heads.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;thi = &lt;span class="co"&gt;Date&lt;/span&gt;.today - &lt;span class="i"&gt;365&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="iv"&gt;@th_index_cutoff_sum&lt;/span&gt; = (&lt;tt&gt;
&lt;/tt&gt;  thi.year.to_s +&lt;tt&gt;
&lt;/tt&gt;  sprintf(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;%02d&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, thi.mon) +&lt;tt&gt;
&lt;/tt&gt;  sprintf(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;%02d&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, thi.day)&lt;tt&gt;
&lt;/tt&gt;).to_i&lt;tt&gt;
&lt;/tt&gt;&lt;span class="iv"&gt;@th_index_dump_count&lt;/span&gt; = &lt;span class="i"&gt;0&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Compose the location of the thread head index file&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;if&lt;/span&gt; &lt;span class="iv"&gt;@thread_head_index&lt;/span&gt;.nil?&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="iv"&gt;@thread_head_index&lt;/span&gt; = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="co"&gt;File&lt;/span&gt;.expand_path(&lt;span class="iv"&gt;@src_mail_dir&lt;/span&gt;)&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;.mail_sort.idx&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Pre-run debugging&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;if&lt;/span&gt; &lt;span class="iv"&gt;@debug&lt;/span&gt; &amp;gt; &lt;span class="i"&gt;0&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="gv"&gt;$stderr&lt;/span&gt;.puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;@debug: '&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="iv"&gt;@debug&lt;/span&gt;&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="gv"&gt;$stderr&lt;/span&gt;.puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;@src_mail_dir: '&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="iv"&gt;@src_mail_dir&lt;/span&gt;&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="gv"&gt;$stderr&lt;/span&gt;.puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;@thread_head_index: '&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="iv"&gt;@thread_head_index&lt;/span&gt;&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="gv"&gt;$stderr&lt;/span&gt;.puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;@days_ago: '&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="iv"&gt;@days_ago&lt;/span&gt;&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="gv"&gt;$stderr&lt;/span&gt;.puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;@cutoff: '&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="iv"&gt;@cutoff&lt;/span&gt;.to_s&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="gv"&gt;$stderr&lt;/span&gt;.puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;@cutoff_sum: '&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="iv"&gt;@cutoff_sum&lt;/span&gt;.to_s&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="gv"&gt;$stderr&lt;/span&gt;.puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;@th_index_cutoff_sum: '&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="iv"&gt;@th_index_cutoff_sum&lt;/span&gt;&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Do the run.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;#&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Load the thread head index if it exists.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;load_thread_head_index(&lt;span class="iv"&gt;@thread_head_index&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# The location of the Maildir's cur directory.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;src_mail_dir_cur = &lt;span class="co"&gt;File&lt;/span&gt;.join(&lt;span class="co"&gt;File&lt;/span&gt;.expand_path(&lt;span class="iv"&gt;@src_mail_dir&lt;/span&gt;),&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;cur&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Iterate through each file in the Maildir's cur directory.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="co"&gt;Dir&lt;/span&gt;.foreach(src_mail_dir_cur) &lt;span class="r"&gt;do&lt;/span&gt; |filename|&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# Skip . and ..&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;next&lt;/span&gt; &lt;span class="r"&gt;if&lt;/span&gt; filename == &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;next&lt;/span&gt; &lt;span class="r"&gt;if&lt;/span&gt; filename == &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;..&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  filename = &lt;span class="co"&gt;File&lt;/span&gt;.join(src_mail_dir_cur, filename)&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# Skip any directories.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;next&lt;/span&gt; &lt;span class="r"&gt;unless&lt;/span&gt; &lt;span class="co"&gt;File&lt;/span&gt;.file?(filename)&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="gv"&gt;$stderr&lt;/span&gt;.puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;filename: &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;filename&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;if&lt;/span&gt; &lt;span class="iv"&gt;@debug&lt;/span&gt; &amp;gt; &lt;span class="i"&gt;2&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# Parse the file into an email.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  email = &lt;span class="co"&gt;TMail&lt;/span&gt;::&lt;span class="co"&gt;Mail&lt;/span&gt;.parse(&lt;span class="co"&gt;IO&lt;/span&gt;.read(filename))&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;if&lt;/span&gt; email[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;references&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;].nil? &amp;amp;&amp;amp; email[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;in-reply-to&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;].nil?&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="c"&gt;# This email is a thread head&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;if&lt;/span&gt; email[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;message-id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;].id.nil?&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="c"&gt;# This email is a malformed email.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="gv"&gt;$stderr&lt;/span&gt;.puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;No message-id for &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;filename&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;unless&lt;/span&gt; &lt;span class="iv"&gt;@quiet&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;else&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="c"&gt;# Add this email as a thread head.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      add_thread_head(email)&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="c"&gt;# Archive this email.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      archive_thread_head(email, &lt;span class="iv"&gt;@src_mail_dir&lt;/span&gt;, filename)&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;else&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="c"&gt;# This email is a thread child&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    thread_head = &lt;span class="pc"&gt;nil&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="c"&gt;# Determine the thread's head (Simple case first since it is the most&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="c"&gt;# common)&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;if&lt;/span&gt; !email[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;references&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;].nil? &amp;amp;&amp;amp; !email[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;references&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;].ids.empty?&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="c"&gt;# This email as a References header and it is not empty&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      thread_head = email[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;references&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;].ids.first.to_sym&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;elsif&lt;/span&gt; !email[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;in-reply-to&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;].nil? &amp;amp;&amp;amp; !email[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;in-reply-to&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;].empty?&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="c"&gt;# This email only has a In-Reply-To header which is not empty&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      thread_head = email[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;in-reply-to&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;].to_s.to_sym&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="c"&gt;# Lookup the thread head in @thread_heads.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;if&lt;/span&gt; &lt;span class="iv"&gt;@thread_heads&lt;/span&gt;.key?(thread_head)&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="c"&gt;# Found it, so archive this email in the thread head's archive directory.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      archive_thread_child(thread_head, &lt;span class="iv"&gt;@src_mail_dir&lt;/span&gt;, filename)&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;else&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="c"&gt;# Possibly an orphaned child.  See if any of its other references are&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="c"&gt;# known thread heads.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      thread_head = &lt;span class="pc"&gt;nil&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;if&lt;/span&gt; email[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;references&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;].nil? &amp;amp;&amp;amp; !email[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;in-reply-to&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;].empty?&lt;tt&gt;
&lt;/tt&gt;        &lt;span class="c"&gt;# No References header so use the In-Reply-To header.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        ref = email[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;in-reply-to&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;].to_s.to_sym&lt;tt&gt;
&lt;/tt&gt;        thread_head = ref &lt;span class="r"&gt;if&lt;/span&gt; &lt;span class="iv"&gt;@thread_heads&lt;/span&gt;.key?(ref)&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;elsif&lt;/span&gt; !email[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;references&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;].nil? &amp;amp;&amp;amp; !email[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;references&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;].empty?&lt;tt&gt;
&lt;/tt&gt;        &lt;span class="c"&gt;# Use References header.  Iterate through each of the references and&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;span class="c"&gt;# use the first that matches as the thread's head.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        email[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;references&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;].ids.each &lt;span class="r"&gt;do&lt;/span&gt; |ref|&lt;tt&gt;
&lt;/tt&gt;          ref = ref.to_s.to_sym&lt;tt&gt;
&lt;/tt&gt;          &lt;span class="r"&gt;if&lt;/span&gt; &lt;span class="iv"&gt;@thread_heads&lt;/span&gt;.key?(ref)&lt;tt&gt;
&lt;/tt&gt;            thread_head = ref&lt;tt&gt;
&lt;/tt&gt;            &lt;span class="r"&gt;break&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;          &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="c"&gt;# Do we now have the thread's head?&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;if&lt;/span&gt; thread_head&lt;tt&gt;
&lt;/tt&gt;        &lt;span class="c"&gt;# Yes, so archive this email in the thread head's archive directory.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        archive_thread_child(thread_head, &lt;span class="iv"&gt;@src_mail_dir&lt;/span&gt;, filename)&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;else&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;span class="c"&gt;# No.  We have an orphan.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;span class="gv"&gt;$stderr&lt;/span&gt;.puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;th orphan&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;if&lt;/span&gt; &lt;span class="iv"&gt;@debug&lt;/span&gt; &amp;gt; &lt;span class="i"&gt;2&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;span class="iv"&gt;@total_orphans&lt;/span&gt; += &lt;span class="i"&gt;1&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;span class="c"&gt;# Archive it as a thread head.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        add_thread_head(email)&lt;tt&gt;
&lt;/tt&gt;        archive_thread_head(email, &lt;span class="iv"&gt;@src_mail_dir&lt;/span&gt;, filename)&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="iv"&gt;@total_emails&lt;/span&gt; += &lt;span class="i"&gt;1&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# The run is done, so save @thread_heads.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;dump_thread_head_index(&lt;span class="iv"&gt;@thread_head_index&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Post-run debugging.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;if&lt;/span&gt; &lt;span class="iv"&gt;@debug&lt;/span&gt; &amp;gt; &lt;span class="i"&gt;0&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="gv"&gt;$stderr&lt;/span&gt;.puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;@thread_heads.length: &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="iv"&gt;@thread_heads&lt;/span&gt;.length&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="gv"&gt;$stderr&lt;/span&gt;.puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;@total_orphans: &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="iv"&gt;@total_orphans&lt;/span&gt;&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="gv"&gt;$stderr&lt;/span&gt;.puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;@total_emails: &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="iv"&gt;@total_emails&lt;/span&gt;&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="gv"&gt;$stderr&lt;/span&gt;.puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;@total_emails_archived: &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="iv"&gt;@total_emails_archived&lt;/span&gt;&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="gv"&gt;$stderr&lt;/span&gt;.puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;@th_index_dump_count: &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="iv"&gt;@th_index_dump_count&lt;/span&gt;&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


&lt;p&gt;Invoking it is as simple as &lt;code&gt;./mail_sort.rb -h&lt;/code&gt;.&lt;/p&gt;


</description>
      <pubDate>Fri, 21 Dec 2007 13:32:00 -0600</pubDate>
      <guid isPermaLink="false">urn:uuid:9db50cb6-c51b-4472-a1b4-542885c3e317</guid>
      <author>Kelly McCauley</author>
      <link>http://drotner.org/articles/2007/12/21/getting-a-grip-on-archiving-mail-threads</link>
      <category>Programming</category>
      <category>SysAdmin</category>
      <category>ruby</category>
      <trackback:ping>http://drotner.org/articles/trackback/80</trackback:ping>
    </item>
    <item>
      <title>Apache Setup for a Non-Root Rails App</title>
      <description>&lt;h2&gt;Introduction&lt;/h2&gt;


&lt;p&gt;Over the weekend, I wanted to put a small &lt;a href="http://rubyonrails.org/"&gt;Ruby on
Rails&lt;/a&gt; application that I had written for myself into
production.  This small article documents the setup and configuration that I
used to get my application running with &lt;a href="http://httpd.apache.org"&gt;Apache&lt;/a&gt; and a
&lt;a href="http://mongrel.rubyforge.org/"&gt;Mongrel&lt;/a&gt; cluster back end.  The article assumes
that the reader knows the basics of &lt;a href="http://httpd.apache.org/docs/2.2/"&gt;Apache
administration&lt;/a&gt;, &lt;a href="http://mongrel.rubyforge.org/docs/index.html"&gt;Mongrel
configuration&lt;/a&gt;, and &lt;a href="http://www.capify.org/"&gt;deployment of
Ruby on Rails applications&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There are plenty of documentation references for installing a rails
application as the root web page.  The &lt;a href="http://www.pragmaticprogrammer.com/titles/rails/index.html"&gt;Agile Web Development with
Rails&lt;/a&gt; book, in the
&lt;em&gt;Setting Up a Deployment Enviroment&lt;/em&gt; section, gives a fairly detailed
description of the steps needed to deploy an application into production.  The
&lt;a href="http://mongrel.rubyforge.org/docs/apache.html"&gt;Mongrel: Apache&lt;/a&gt; documentation
is another excellent reference.  But I didn&amp;#8217;t want to install my rails
application at the root of my &lt;span class="caps"&gt;URL&lt;/span&gt;&amp;#8230;.&lt;/p&gt;

&lt;p&gt;My rails application is just a small &lt;span class="caps"&gt;URL&lt;/span&gt; manager called &lt;em&gt;Blink&lt;/em&gt; and I wanted
it to be served from the private section of my web pages:&lt;/p&gt;



&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;https://drotner.org:8443/blink/
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;I am using Apache as the front end to &lt;em&gt;Blink&lt;/em&gt; because I&amp;#8217;m using mod_svn to
host my &lt;a href="http://subversion.tigris.org/"&gt;Subversion&lt;/a&gt; repositories and didn&amp;#8217;t want
to have yet another front end web server to administer.  &lt;em&gt;Blink&lt;/em&gt; itself will be
running on a cluster of mongrel servers (initially, only one mongrel
server).&lt;/p&gt;

	&lt;h2&gt;Setup and Configuration&lt;/h2&gt;


&lt;p&gt;I first checked out a copy of &lt;em&gt;Blink&lt;/em&gt;&amp;#8217;s source code, configured &lt;em&gt;Blink&lt;/em&gt;, and
created the database.  The next step was to configure the mongrel cluster.  My
&lt;code&gt;mongre_cluster&lt;/code&gt; init.d script looks for server configurations in
&lt;code&gt;/etc/mongrel&lt;/code&gt;, so I created
&lt;code&gt;/etc/mongrel/blink.drotner.org.8443.mongrel_cluster.yml&lt;/code&gt;&lt;p&gt;



&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;--- &lt;tt&gt;
&lt;/tt&gt;prefix: /blink&lt;tt&gt;
&lt;/tt&gt;cwd: /var/www/ssl_drotner_org/apps/blink&lt;tt&gt;
&lt;/tt&gt;log_file: log/mongrel.log&lt;tt&gt;
&lt;/tt&gt;port: &amp;quot;8200&amp;quot;&lt;tt&gt;
&lt;/tt&gt;environment: production&lt;tt&gt;
&lt;/tt&gt;address: 127.0.0.1&lt;tt&gt;
&lt;/tt&gt;servers: 1&lt;tt&gt;
&lt;/tt&gt;user: mongrel&lt;tt&gt;
&lt;/tt&gt;group: mongrel&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;



&lt;p&gt;I set mongrel&amp;#8217;s &lt;code&gt;prefix&lt;/code&gt; option (line 2) since I want &lt;em&gt;Blink&lt;/em&gt; to run under
the &lt;code&gt;/blink/&lt;/code&gt; URL path.  I started up the mongrel cluster and then used &lt;code&gt;curl&lt;/code&gt;
to verify that &lt;em&gt;Blink&lt;/em&gt;&amp;#8217;s mongrel server was running.&lt;/p&gt;



&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;root@drotner:/etc/mongrel # curl http://127.0.0.1:8200/blink/
&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;You are being &amp;lt;a href=&amp;quot;http://127.0.0.1:8200/blink/authn_sessions/new&amp;quot;&amp;gt;redirected&amp;lt;/a&amp;gt;.&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;&lt;code&gt;curl&lt;/code&gt; outputted exactly what I was expecting.  The next step was
configuring Apache to proxy requests for &lt;code&gt;/blink/&lt;/code&gt; to the back end mongrel
cluster.&lt;/p&gt;



&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;15&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;25&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;27&lt;tt&gt;
&lt;/tt&gt;28&lt;tt&gt;
&lt;/tt&gt;29&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;31&lt;tt&gt;
&lt;/tt&gt;32&lt;tt&gt;
&lt;/tt&gt;33&lt;tt&gt;
&lt;/tt&gt;34&lt;tt&gt;
&lt;/tt&gt;35&lt;tt&gt;
&lt;/tt&gt;36&lt;tt&gt;
&lt;/tt&gt;37&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;lt;VirtualHost 66.241.137.71:8443&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  DocumentRoot &amp;quot;/var/www/ssl_drotner_org/htdocs-secure&amp;quot;&lt;tt&gt;
&lt;/tt&gt;  ServerName drotner.org:8443&lt;tt&gt;
&lt;/tt&gt;  ErrorLog /var/log/apache2/ssl_drotner_org_error_log&lt;tt&gt;
&lt;/tt&gt;  CustomLog /var/log/apache2/ssl_drotner_org_access_log combinedio&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  # ... SNIP ...&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  ProxyRequests Off&lt;tt&gt;
&lt;/tt&gt;  ProxyVia Full&lt;tt&gt;
&lt;/tt&gt;  RequestHeader set X_FORWARDED_PROTO 'https'&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &amp;lt;Proxy balancer://mongrel_cluster&amp;gt;&lt;tt&gt;
&lt;/tt&gt;    BalancerMember http://127.0.0.1:8200&lt;tt&gt;
&lt;/tt&gt;    #BalancerMember http://127.0.0.1:8201&lt;tt&gt;
&lt;/tt&gt;  &amp;lt;/Proxy&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &amp;lt;Proxy *&amp;gt;&lt;tt&gt;
&lt;/tt&gt;    Order Deny,Allow&lt;tt&gt;
&lt;/tt&gt;    Deny from all&lt;tt&gt;
&lt;/tt&gt;    Allow from all&lt;tt&gt;
&lt;/tt&gt;  &amp;lt;/Proxy&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  RewriteEngine On&lt;tt&gt;
&lt;/tt&gt;  # Check for  maintenance file and redirect all requests&lt;tt&gt;
&lt;/tt&gt;  RewriteCond  %{DOCUMENT_ROOT}/system/maintenance.html -f&lt;tt&gt;
&lt;/tt&gt;  RewriteCond  %{SCRIPT_FILENAME} !maintenance.html&lt;tt&gt;
&lt;/tt&gt;  RewriteRule  ^/blink/.*$ /system/maintenance.html [L]&lt;tt&gt;
&lt;/tt&gt;  # Rewrite /blink/ to check for static index page&lt;tt&gt;
&lt;/tt&gt;  # RewriteRule ^/blink/$ /index.html [QSA]&lt;tt&gt;
&lt;/tt&gt;  # Rewrite to check for Rails cached page&lt;tt&gt;
&lt;/tt&gt;  RewriteRule ^/blink/([^.]+)$ /blink/$1.html [QSA]&lt;tt&gt;
&lt;/tt&gt;  # Redirect all non-static requests to the mongrel cluster&lt;tt&gt;
&lt;/tt&gt;  RewriteCond %{DOCUMENT_ROOT}/blink/%{REQUEST_FILENAME} !-f&lt;tt&gt;
&lt;/tt&gt;  RewriteRule ^/blink/(.*)$ balancer://mongrel_cluster%{REQUEST_URI} [P,QSA,L]&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&amp;lt;/VirtualHost&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;



&lt;p&gt;&lt;code&gt;ProxyRequests Off&lt;/code&gt; (line 9) is critical and keeps the Apache
server from being an open proxy server.&lt;/p&gt;

&lt;p&gt;Note that &lt;em&gt;Blink&lt;/em&gt; is being served over
&lt;a href="http://en.wikipedia.org/wiki/Transport_Layer_Security"&gt;&lt;span class="caps"&gt;TLS&lt;/span&gt;/SSL&lt;/a&gt;.
&lt;code&gt;RequestHeader set X_FORWARDED_PROTO 'https'&lt;/code&gt; (line 11), in a
nutshell, tells rails to write URLs with &lt;code&gt;https://&lt;/code&gt; for location redirects instead of the
default &lt;code&gt;http://&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;Proxy balancer://mongrel_cluster&amp;gt;...&lt;/code&gt; (lines 13 &amp;#8211; 15) tells
Apache where to find &lt;em&gt;Blink&lt;/em&gt;&amp;#8217;s mongrel servers.  Each &lt;code&gt;BalanceMember&lt;/code&gt; must map
to a mongrel server running on the given port.&lt;/p&gt;

&lt;p&gt;The &lt;a href="http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html"&gt;rewrite&lt;/a&gt; rules, lines 24 &amp;#8211; 35, do
the grunt work of deciding whether the requests go to the &lt;em&gt;Blink&lt;/em&gt; application
or elsewhere.&lt;/p&gt;

&lt;p&gt;Finally, I restarted my Apache server, and pointed my browser to
&lt;code&gt;https://drotner.org:8443/blink/&lt;/code&gt; and got the appropriate index page.  Now, back to what I enjoy doing &amp;#8230; programming.&lt;/p&gt;


</description>
      <pubDate>Mon, 17 Sep 2007 16:19:00 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:4d15e06b-345b-4ff5-b224-48b07ef65ae6</guid>
      <author>Kelly McCauley</author>
      <link>http://drotner.org/articles/2007/09/17/apache-setup-for-a-non-root-rails-app</link>
      <category>SysAdmin</category>
      <category>rails</category>
      <category>apache</category>
      <category>mongrel</category>
    </item>
  </channel>
</rss>
