<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Anthony R. Thompson&#039;s Blog</title>
	<atom:link href="http://blog.anthonyrthompson.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.anthonyrthompson.com</link>
	<description>Technology, Personal Improvement, and a little bit of Astrology for fun :)</description>
	<lastBuildDate>Sat, 07 Aug 2010 23:56:08 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Listserv to Mailman Part 3.3: Tips, Tricks, and Notes</title>
		<link>http://blog.anthonyrthompson.com/2010/07/listserv-to-mailman-tips-tricks-notes/</link>
		<comments>http://blog.anthonyrthompson.com/2010/07/listserv-to-mailman-tips-tricks-notes/#comments</comments>
		<pubDate>Mon, 19 Jul 2010 03:18:31 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Tech Tips]]></category>
		<category><![CDATA[bookmarks]]></category>
		<category><![CDATA[commands]]></category>
		<category><![CDATA[conversion]]></category>
		<category><![CDATA[convert]]></category>
		<category><![CDATA[inodes]]></category>
		<category><![CDATA[listserv]]></category>
		<category><![CDATA[mailman]]></category>
		<category><![CDATA[scripts]]></category>
		<category><![CDATA[tips]]></category>
		<category><![CDATA[tricks]]></category>

		<guid isPermaLink="false">http://blog.anthonyrthompson.com/?p=29</guid>
		<description><![CDATA[An appendix listing some commands I found useful, some notes I made along the way that are worth reading through, and some other pages I found helpful and which hadn't been mentioned already.]]></description>
			<content:encoded><![CDATA[<p>During our Listserv to Mailman migration, I started keeping a tips file to remind myself of the syntax for helpful commands, so I wanted to share those tidbits here as an appendix along with some notes/caveats and useful pages on other sites.</p>
<h1>Commands</h1>
<ul>
<li>To see all the settings for a mailman list: /usr/lib/mailman/bin/config_list -o &#8211; &#8216;listname&#8217;  (outputs to screen; use -o filename to output to a file)</li>
<li>To see a list&#8217;s settings minus comments and whitespace: config_list -o &#8211; &#8216;listname&#8217; | perl -ne &#8216;print unless /(^#|^\s*$)/&#8217;</li>
<li>To change the password for a list: /usr/lib/mailman/bin/change_pw -l &#8216;listname&#8217; -p &#8216;newpass&#8217; -q (the -q prevents a notice going to the list owners)</li>
<li>To show the subscribers of a list: /usr/lib/mailman/bin/list_members -f &#8216;listname&#8217; (the -f shows full names for subscribers)</li>
<li>To show the owners of a list: /usr/lib/mailman/bin/list_owners &#8216;listname&#8217; (if you use list_admins instead, it seems to do the same thing)</li>
<li>To rebuild all list archives (in bash): for list in `/usr/lib/mailman/bin/list_lists -b | egrep -v &#8216;^mailman$&#8217;`; do /usr/lib/mailman/bin/arch &#8211;wipe $list; done</li>
<li>To restart Mailman (as root or mailman user): /etc/init.d/mailman restart</li>
<li>To one or more list settings for a list: config_list -o &#8211; &#8216;listname&#8217; &gt; tmp.txt; then edit tmp.txt to leave only the setting you want to change; config_list -i tmp.txt &#8216;listname&#8217;</li>
<li>To apply a setting change to multiple lists, use config_list -o &#8211; &#8216;listname&#8217; &gt; tmp.txt and edit tmp.txt as above, but then use shell looping: or list in adf-foo adf-bar etc; do config_list -i setting.txt $list ; done</li>
</ul>
<h1>Notes</h1>
<p>I&#8217;d intended to list here each code file I&#8217;m making available along with a description, but instead I put the <a href="/listserv-to-mailman/code/">code descriptions</a> in the Apache directory pages so just look there.</p>
<p>The Mailman logs on our server are in /var/log/mailman and /var/log/mailman/error contains the most recent errors.</p>
<p><strong>Important</strong>: Our list host informed me that the default &#8220;mailman&#8221; list <em><strong>must</strong></em> be kept around, you can&#8217;t just delete it or important Mailman things will (apparently) break. So you&#8217;ve been warned <img src='http://blog.anthonyrthompson.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>To increase the max # of recipients for a message to be able to get posted (in case you have lists where legitimate posts get rejected due to having too many recipients), see the max_num_recipients setting, which is in the Privacy Options -&gt; Recipient Filters part of the web interface.</p>
<p>I created the <a href="/listserv-to-mailman/code/utils/arch_wipe_all">arch_wipe_all</a> script because I&#8217;d tried running the commands in it from the shell but it took so many hours (70+ lists and 10+ years of archives) that my shell would get disconnected and I&#8217;d have to start over completely. By putting the commands in a script I could preface it with <a href="http://en.wikipedia.org/wiki/Nohup">nohup</a> so it would keep running even if I got disconnected.</p>
<p>I noticed in /etc/mailman/postfix-to-mailman.py that if DEB_LISTMASTER isn&#8217;t set in /etc/mailman/mm_cfg.py or /usr/lib/mailman/Mailman/Defaults.py that error mail will go to postmaster@localhost, but I wanted it sent to another address in our organization so I added <strong>DEB_LISTMASTER = &#8216;addr@ourhost.org&#8217;</strong> to the bottom of /etc/mailman/mm_cfg.py.</p>
<p>Pre-migration messages in people&#8217;s mailboxes had links to the old Listserv archives  in the footer, so even though we changed the footer for Mailman, we needed to provide redirects in case someone used an old link. We did this with an <a href="http://www.yourhtmlsource.com/sitemanagement/urlrewriting.html">Apache URL Rewrite rule</a> to redirect http://lists.ourhost.org/archives/listname.html to http://lists.ourhost.org/cgi-bin/mailman/private/listname/:</p>
<blockquote><p>RewriteEngine on<br />
RewriteRule ^archives/(.+)\.html$ http://lists.us.org/cgi-bin/mailman/private/$1/ [R]</p></blockquote>
<p>(the second line, the RewriteRule, needs to be all on one line)</p>
<p>During one part of our disk issues converting our archives, our server admin said we&#8217;d maxed out our number of inodes (files and directories), probably because of the large number of archive related files (70+ lists for 10+ years). If you see errors like &#8220;unable to write file&#8221;, you can check the inodes used on the disk itself with <strong>df -i</strong>, and check inodes for your user with <strong>quota -sv username</strong>.</p>
<h1>Bookmarks</h1>
<p>The following pages weren&#8217;t listed in other parts of the guide and may be useful:</p>
<ul>
<li><a href="http://wiki.list.org/display/DOC/4.09+Summary+of+the+mailman+bin+commands">Summary of the Mailman bin command line programs</a></li>
<li><a href="http://staff.imsa.edu/~ckolar/mailman/mailman-administration-v2.html">Mailman List Management Guide</a> (2001 though, but has good settings descriptions)</li>
<li><a href="http://8help.osu.edu/3794.html">Changing List Owners On A Mailman Mailing List</a></li>
<li><a href="http://wiki.list.org/pages/viewpage.action?pageId=4030648">How do I integrate Mailman with PHP, or any other web technology?</a></li>
<li><a href="http://www.gnu.org/software/mailman/mailman-install/">Mailman Installation Manual</a></li>
<li><a href="http://www.list.org/mailman-member/">Mailman List Member Manual</a></li>
<li><a href="http://therowes.net/~greg/2007/09/03/regenerating-large-mailman-archives/">Regenerating Large Mailman Archives</a> (I did not have to do the steps in this page even though our archives are 10+ years)</li>
<li><a href="http://wiki.list.org/pages/viewpage.action?pageId=7602232">How to edit the archives of a Mailman List</a></li>
<li><a href="http://wiki.list.org/pages/viewpage.action?pageId=4030681">How to remove a post from a Mailman list archive, or an entire archive</a> (Note: to remove a post completely, I prefer to use <a href="http://kb.mozillazine.org/Importing_and_exporting_your_mail">Thunderbird to edit the mbox file</a>)</li>
<li><a href="http://www.esosoft.com/support/mailinglist/mailman/bounce.html">Mailman bounce processing explanations</a></li>
<li><a href="http://listserv.du.edu/faq.html">Mailman Frequently Asked Questions</a></li>
</ul>
<p><strong>Up</strong>: <a href="/listserv-to-mailman/">Table of Contents</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.anthonyrthompson.com/2010/07/listserv-to-mailman-tips-tricks-notes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Listserv to Mailman Part 3.2: Setting Up Archive Search</title>
		<link>http://blog.anthonyrthompson.com/2010/07/listserv-to-mailman-setting-up-archive-search/</link>
		<comments>http://blog.anthonyrthompson.com/2010/07/listserv-to-mailman-setting-up-archive-search/#comments</comments>
		<pubDate>Fri, 09 Jul 2010 09:05:36 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Tech Tips]]></category>
		<category><![CDATA[access]]></category>
		<category><![CDATA[archive]]></category>
		<category><![CDATA[archives]]></category>
		<category><![CDATA[cgi]]></category>
		<category><![CDATA[index]]></category>
		<category><![CDATA[indexing]]></category>
		<category><![CDATA[login]]></category>
		<category><![CDATA[mailman]]></category>
		<category><![CDATA[private]]></category>
		<category><![CDATA[searching]]></category>
		<category><![CDATA[swish]]></category>
		<category><![CDATA[swish-e]]></category>

		<guid isPermaLink="false">http://blog.anthonyrthompson.com/?p=24</guid>
		<description><![CDATA[Modifying Mailman web templates to add search links, using Swish-E to generate archive search indexes, setting up swish's CGI search and template files, and compiling the search CGI wrapper program (required due to web server security/permissions issues).]]></description>
			<content:encoded><![CDATA[<h1>Introduction</h1>
<p>Mailman doesn&#8217;t come with built-in archive searching. Instead, maybe in the Unix tradition of &#8220;do one thing and do it well, leave the rest to other tools&#8221;, you must find, install, and integrate your own search package. In some places it&#8217;s mentioned that people have used the <a href="http://www.swish-e.org/">Swish</a> search package successfully, but usually no further explanation of how to do this is given.</p>
<p>(Note that there are actually <em>two</em> &#8220;swish&#8221; index/search packages out there, <a href="http://www.swish-e.org/">Swish-E</a> and <a href="http://swishplusplus.sourceforge.net/">Swish++</a>. For this guide, and on our server, I used Swish-E because we already used it for search on our main website.)</p>
<p>Mailman seems to add each message to the list archive (mbox file and HTML archive pages) as it&#8217;s processed for delivery/handling. We needed to somehow periodically have Swish generate a search index from all the HTML archive pages.</p>
<p>We also had to tweak the Mailman installation to add a search box to the list template pages, and add other tweaks to limit searching and search results to subscribers only (since all our lists and their archives were private).</p>
<h1>Adding a Search Box to List Templates</h1>
<p>To enable list archive searching, we needed a place where people could enter their search parameters, which required editing a few Mailman list template files.</p>
<p>As written at <a href="http://wpkg.org/Integrating_Mailman_with_a_Swish-e_search_engine#Integrating_the_search_with_Mailman.27s_pages">http://wpkg.org/Integrating_Mailman_with_a_Swish-e_search_engine</a>, we didn&#8217;t want to edit the installed Mailman templates, we wanted to <em>copy</em> the default templates to a special area and then edit the copies to override the default ones. This made sure that our customized templates wouldn&#8217;t be overwritten by a Mailman upgrade.</p>
<p>On our server, the default templates were in /etc/mailman/en/ so we created /etc/mailman/site/en/ and copied the archidxhead.html, archtoc.html, and archtocnombox.html files from the former directory to the latter.</p>
<p>Then I edited archidxhead.html to add the following line:</p>
<pre>&lt;li&gt;&lt;b&gt;&lt;a href="/cgi-bin/mailman/search/%(listname)s"
&gt;Search the archives of this list&lt;/a&gt;&lt;/b&gt;&lt;/li&gt;</pre>
<p>archtoc.html was edited to have:</p>
<pre>&lt;p&gt;You can get &lt;a href="%(listinfo)s"&gt;more information about this list&lt;/a&gt;,
&lt;a href="%(fullarch)s"&gt;download the full raw archive&lt;/a&gt; (%(size)s),
or &lt;a href="/cgi-bin/mailman/search/%(listname)s"
&gt;search all the archives of the list&lt;/a&gt;.&lt;/p&gt;</pre>
<p>Finally, archtocnombox.html was edited to have:</p>
<pre>&lt;p&gt;You can get &lt;a href="%(listinfo)s"&gt;more information about this list&lt;/a&gt;
or &lt;a href="/cgi-bin/mailman/search/%(listname)s"
&gt;search the list archives&lt;/a&gt;.&lt;/p&gt;</pre>
<p>Mailman seems to load templates into memory when starting up, so to get it to recognize the custom template overrides, we had to restart Mailman (which I think was done with <strong>/etc/init.d/mailman restart</strong> but I&#8217;m not 100% sure because our server admins actually did the restart).</p>
<p>Note that if your mailman CGI scripts end with cgi (e.g., if you built from source and used the &#8211;with-cgi-ext=.cgi flag to the configure script), it would be search.cgi in the above snippets.</p>
<p>After putting links to the search script on the Mailman templates, we had to put the search script in place to receive search queries. This was a bit complicated due to our  requirement to keep search (and search results) limited to subscribers only, and it&#8217;s where we had to deviate from the <a href="http://wpkg.org/Integrating_Mailman_with_a_Swish-e_search_engine#Integrating_the_search_with_Mailman.27s_pages">Integrating Mailman with a Swish-e search engine</a> page because that didn&#8217;t cover keeping searches private.</p>
<p>The script I wrote to create the Swish search index for each list (<a href="/listserv-to-mailman/code/arch_index.py">arch_index.py</a>) also does as much setup for Swish searching as possible but there are some one-time setup things we had to do manually first.</p>
<p>Before I describe those one-time setup steps, I want to describe the general process of using arch_index.py to create the Swish index files for Mailman lists.</p>
<h1>Generating a Search Index with Swish</h1>
<p>Swish doesn&#8217;t search the HTML pages in the archive directly, probably because it would be too slow. Instead, it searches against its own optimized index file. That&#8217;s faster, but periodically the index file itself needs to be updated (regenerated completely, actually, as Swish doesn&#8217;t seem to support incrementally adding to index files).</p>
<p>Since I&#8217;d have to do the same steps to generate the Swish index file for each list archive, I automated the process with a script called <a href="/listserv-to-mailman/code/arch_index.py">arch_index.py</a>, named somewhat in honor of the Mailman bin program &#8220;arch&#8221;.</p>
<p>In addition to generating the Swish index file for a list(s), I also had arch_index.py set up the CGI script which uses Swish to search a given list (based on the swish.cgi provided with the Swish package) , and set up a configuration file for the CGI script to work correctly.</p>
<p>If arch_index.py is just given the Mailman archive directory as a parameter, and no other options, it creates Swish search indexes for all lists (except the built-in &#8220;mailman&#8221; list, though there is a flag to force indexing of that too):</p>
<pre>arch_index.py /var/lib/mailman/archives/</pre>
<p>To create the index (and search config files, etc.) for just a particular list you can do:</p>
<pre>arch_index.py -l some-listname /var/lib/mailman/archives/</pre>
<p>arch_index.py assumes the Swish indexer program is located at /usr/bin/swish-e and the default Swish CGI search script was installed at /usr/lib/swish-e/swish.cgi—though you can override both on the command line or by editing arch_index.py itself. To see all options, just type arch_index.py with no arguments.</p>
<p>arch_index.py also enables searching list archives by date. Swish&#8217;s search by date feature looks at the modification times of indexed files, but for a list converted from Listserv all the HTML archive pages would be generated at once and have the same modification time. So to support date searching, arch_index.py looks at each posting&#8217;s date and then sets the file modification time to that date.</p>
<p>We should probably describe exactly what arch_index.py does though&#8230;</p>
<h1>What arch_index.py Does</h1>
<p>You can look at the <a href="/listserv-to-mailman/code/arch_index.py">source code</a> yourself of course, but here&#8217;s a quick summary of what arch_index.py does:</p>
<ol>
<li>Checks command line options and figures out what, if any, lists to index, and whether the swish-e and swish.cgi files are available</li>
<li>Copies the default swish.cgi file (if it hasn&#8217;t been copied already) and customizes it</li>
<li>Creates a config file for the customized swish.cgi script (if it hasn&#8217;t been created before)</li>
<li>Updates the modification times of any new HTML archive message files for each list, to match their message posting dates</li>
<li>Creates a swish indexing config file for each list, if necessary</li>
<li>Actually runs swish for each list to create the swish index files</li>
</ol>
<h1>Creating a Custom Swish Search Template for All Lists</h1>
<p>Part of the customization in item #2 above is changing the default swish.cgi file to refer to a custom template file, similar to the process described in <a href="http://wpkg.org/Integrating_Mailman_with_a_Swish-e_search_engine#Integrating_the_search_with_Mailman.27s_pages">Integrating Mailman with a Swish-e search engine</a>.</p>
<p>So we set up the custom template file by copying TemplateDefault.pm in /usr/lib/swish-e/perl/SWISH/ to TemplateDefault_MM.pm in the same directory and making four changes:</p>
<ol>
<li><strong>package SWISH::TemplateDefault</strong> was changed to <strong>package SWISH::TemplateDefault<span style="color: #ff0000;">_MM</span></strong></li>
<li><strong>my $advanced_link = qq[&lt;small&gt;&lt;a href="$form"&gt;advanced form&lt;/a&gt;&lt;/small&gt;]</strong> was changed to <strong>my $advanced_link = qq[&lt;small&gt;&lt;a href="$form<span style="color: #ff0000;">$ENV{'PATH_INFO'}</span>"&gt;advanced form&lt;/a&gt;&lt;/small&gt;]</strong></li>
<li><strong>&lt;form method=&#8221;get&#8221; action=&#8221;$form&#8221; enctype=&#8221;application/x-www-form-urlencoded&#8221; class=&#8221;form&#8221;&gt;</strong> was changed to <strong>&lt;form method=&#8221;get&#8221; action=&#8221;$form<span style="color: #ff0000;">$ENV{&#8216;PATH_INFO&#8217;}</span>&#8221; enctype=&#8221;application/x-www-form-urlencoded&#8221; class=&#8221;form&#8221;&gt;</strong></li>
<li>The following was added after $query_href and $pages:<br />
<span style="color: #ff0000;"><strong>$query_href =~ s#search\?#search$ENV{&#8216;PATH_INFO&#8217;}\?#g;</strong><br />
<strong>$pages =~ s#search\?#search$ENV{&#8216;PATH_INFO&#8217;}\?#g;</strong></span></li>
</ol>
<p>(If you prefer patch files you can download <a href="/listserv-to-mailman/code/TemplateDefault_MM.patch">TemplateDefault_MM.patch</a>, change into /usr/lib/swish-e/perl/SWISH/ and then run &#8220;patch &lt; TemplateDefault_MM.patch&#8221;; see <a href="http://stephenjungels.com/jungels.net/articles/diff-patch-ten-minutes.html">The Ten Minute Guide to diff and patch</a> for more info.)</p>
<p>$ENV{&#8216;PATH_INFO&#8217;} had to be added in all those places to let one master Swish search template work for all lists, because the listname is passed to the search script as an extra path info parameter (i.e., /cgi-bin/mailman/search/<em>listname</em>).</p>
<p>arch_index.py copies the swish.cgi file in /usr/lib/swish-e/ into /var/lib/mailman/archives/private/ and then 1) changes SWISH::TemplateDefault to SWISH::TemplateDefault_MM and 2) changes $DEFAULT_CONFIG_FILE to point to /var/lib/mailman/archives/private/swish.cgi.conf which arch_index.py also creates.</p>
<p>The /var/lib/mailman/archives/private/swish.cgi.conf file created by arch_index.py uses an $ENV{&#8216;LISTNAME&#8217;} environment variable that /cgi-bin/mailman/search (which we haven&#8217;t covered yet) sets from its extra path info parameter. In other words, using an environment variable in swish.cgi.conf file allows there to be one master configuration file which can dynamically refer to a different search index file for each list.</p>
<h1>Setting Up the Search CGI Script &#8211; Background/Explanations<strong><br />
</strong></h1>
<p>At this point we&#8217;d edited the search templates to provide links to the search pages, created Swish search indexes for all the HTML message files, and created a customized swish.cgi script and config file (in /var/lib/mailman/archives/private/) to do the actual searching with Swish and return results.</p>
<p>We could have then tried to hook up the web pages&#8217; search links with our version of swish.cgi to do the search and return the results, as described on the <a href="http://wpkg.org/Integrating_Mailman_with_a_Swish-e_search_engine#Integrating_the_search_with_Mailman.27s_pages">Integrating Mailman with a Swish-e search engine</a> page (though it uses a somewhat different integration method with Server Side Includes).</p>
<p>The problem with that approach is that while the full list messages themselves are protected by the Mailman &#8220;private&#8221; access control mechanism (for private lists), the search results themselves contain message excerpts so if a mailing list had confidential information it would be exposed to non-subscribers. For our purposes, that wasn&#8217;t acceptable.</p>
<p>So we also had to restrict running the search and displaying the results to list subscribers, which proved to be fairly involved.</p>
<p>My initial thought was to try to figure out Mailman&#8217;s authentication mechanism and then wrap it around the Swish search CGI script.</p>
<p>I looked at the files in the /cgi-bin/mailman directory (actually /usr/lib/cgi-bin/mailman/ in our installation) and the &#8220;file&#8221; command said that they were all &#8220;setgid ELF 32-bit LSB executable&#8221; files, i.e., compiled executables.</p>
<p>This confused me since most of Mailman seems written in Python, but I noticed that the Python files in /usr/lib/mailman/Mailman/Cgi/ had the same names as the compiled programs in /usr/lib/cgi-bin/mailman/. Further, changing one of the interpreted .py files in /usr/lib/mailman/Mailman/Cgi/ confirmed that the compiled files with the same name in /usr/lib/cgi-bin/mailman/ were calling them.</p>
<p>I tried copying the interpreted Python file /usr/lib/mailman/Mailman/Cgi/private.py to /usr/lib/cgi-bin/mailman/search and then editing it to call Swish&#8217;s CGI search program (/var/lib/mailman/archives/private/swish.cgi) instead of displaying private archive pages as private.py normally does.</p>
<p>While this worked on our development box, unfortunately on our production host it resulted in permission errors reading list configuration files because the web server wouldn&#8217;t use the <a href="http://en.wikipedia.org/wiki/Setuid">setgid</a> mechanism to run an interpreted file as the same &#8220;mailman&#8221; group as the other Mailman programs (which it wouldn&#8217;t do for <a href="http://www.faqs.org/faqs/unix-faq/faq/part4/section-7.html">good security reasons</a>).</p>
<p>I&#8217;d thought the CGI files in /usr/lib/cgi-bin/mailman/ were compiled for performance reasons, but it turns out they were compiled to allow the web server to run the CGI scripts with the correct permissions via the setgid mechanism.</p>
<p>At this point I downloaded the <a href="http://www.list.org/download.html">source files</a> for our version of Mailman because I wanted to confirm this and because I suspected I&#8217;d need to compile my own version of a &#8220;search&#8221; script (a modified &#8220;private&#8221; script). (I needed to download the source files because our production server admins had installed Mailman with a precompiled binary package.)</p>
<p>After downloading the mailman-2.x.yy.tar.gz file for our version of Mailman and unpacking it, I went into the src/ subdirectory and found a cgi-wrapper.c program that, along with common.c, confirmed my theory about the compiled binary wrapper programs existing just for security reasons. In particular the following comments in common.c were helpful:</p>
<pre>/* We want to tightly control how the CGI scripts get executed.
 * For portability and security, the path to the Python executable
 * is hard-coded into this C wrapper, rather than encoded in the #!
 * line of the script that gets executed.  So we invoke those
 * scripts by passing the script name on the command line to the
 * Python executable.
 *
 * We also need to hack on the PYTHONPATH environment variable so
 * that the path to the installed Mailman modules will show up
 * first on sys.path.
 */</pre>
<p>While this whole compilation thing was a pain, at least the C wrappers appeared to be as thin as possible and seemed to exist merely to call the corresponding Python scripts in /usr/lib/mailman/Mailman/Cgi/</p>
<p>(Incidentally, the part above about &#8220;hard-coding the path to the Python executable&#8221; finally explained why the Python scripts in /usr/lib/mailman/Mailman/Cgi/ didn&#8217;t have #!/usr/bin/python at the top!)</p>
<p>What I ultimately had to do was: 1) Compile my own &#8220;search&#8221; binary CGI wrapper which had the setgid bit like the other Mailman CGI programs in /usr/lib/cgi-bin/mailman/, and 2) Create a corresponding search.py file in /usr/lib/mailman/Mailman/Cgi/ as a version of the private.py script which authenticated the user and then called swish.cgi to do the actual search.</p>
<h1>Compiling a CGI Wrapper for the Search Script</h1>
<p>Even though our list server admins had installed Mailman from a binary package, to compile a custom binary CGI wrapper for the search script I needed to download the source for the same version of Mailman as installed on the server (which I determined by running the Mailman bin program &#8220;version&#8221;).</p>
<p>I created a directory at ~/src and then ran <strong>wget http://ftp.gnu.org/gnu/mailman/mailman-2.x.yy.tgz</strong> to download the tarfile for our Mailman version (e.g., 2.1.12) and <strong>tar xvfz mailman-2.x.yy.tgz</strong> to unpack it, which created a mailman-2.x.yy/ subdirectory.</p>
<p>I also realized I might need a place to &#8220;install&#8221; the compiled binary wrapper file, so I did <strong>mkdir ~/src/mailman</strong> and then <strong>chmod g+s ~/src/mailman</strong> because that&#8217;s required by the configure script below.</p>
<p>Then I changed into the newly-created mailman-2.x.yy directory and ran <strong>./configure &#8211;prefix=$HOME/src/mailman</strong> to generate Makefiles from the corresponding Makefile.in files (if you&#8217;re curious how the Makefile system works, see <a href="http://www.faqs.org/docs/artu/ch15s04.html">make: Automating Your Recipes</a>).</p>
<p>(<em>Actually</em>, I had to run <strong>./configure &#8211;prefix=$HOME/src/mailman &#8211;with-username=list &#8211;with-groupname=list</strong> because our list server is set up to use &#8220;list&#8221; instead of &#8220;mailman&#8221; for the Mailman user and group, but chances are your server will use the default mailman account/group which configure looks for, so that won&#8217;t be necessary.)</p>
<p>Then I changed into the src/ subdirectory (making the current directory ~/src/mailman-2.x.yy/src/) which had the following files:</p>
<ul>
<li>cgi-wrapper.c</li>
<li>common.c</li>
<li>common.h</li>
<li>mail-wrapper.c</li>
<li>Makefile</li>
<li>Makefile.in</li>
<li>vsnprintf.c</li>
</ul>
<p>All of those files had come with the source archive except for Makefile, which was created by running the &#8220;configure&#8221; command above. Then I needed to edit that file (~/src/mailman-2.x.yy/src/Makefile) to make the following changes:</p>
<ul>
<li>Changed <strong>prefix= /home/ouruser/src/mailman</strong> to <strong>prefix= /usr/lib/mailman</strong> (because our /home/ouruser/src/mailman was just an empty place for our newly-compiled program to be saved into)</li>
<li>Copied and pasted the two $(CGI_PROGS) target lines and then in the duplicated lines changed $(CGI_PROGS) to search; this resulted in adding the following two lines:<br />
<strong>search: $(srcdir)/cgi-wrapper.c $(COMMONOBJS)</strong><br />
<strong>$(CC) -DSCRIPT=&#8221;\&#8221;$@\&#8221;" -I. $(CGI_FLAGS) $(CFLAGS) $(COMMONOBJS) -o $@ $(srcdir)/cgi-wrapper.c</strong></li>
</ul>
<p>(You can use <a href="/listserv-to-mailman/code/Makefile.patch">Makefile.patch</a> to make the changes, with &#8220;patch &lt; Makefile.patch&#8221;, but you&#8217;ll need to edit the patch file first to replace &#8220;ouruser&#8221; with your own username. If you make the changes by hand instead, keep in mind that the leading space before $(CC) is a TAB and not just spaces, which has been called <a href="http://www.faqs.org/docs/artu/ch15s04.html">one of the worst design botches in the history of Unix</a>.)</p>
<p>Having added a new target for our search wrapper program in ~/src/mailman-2.x.yy/src/Makefile, I then ran <strong>make search</strong> to do the actual compilation.</p>
<p>I&#8217;d expected it to get compiled into the ~/src/mailman directory, but in fact it got compiled into ~/src/mailman-2.x.yy/src/ (the same directory as the just-edited Makefile). I typed <strong>./search</strong> to run the program and it produced the following output:</p>
<pre>Content-type: text/html

&lt;head&gt;
&lt;title&gt;Mailman CGI error!!!&lt;/title&gt;
&lt;/head&gt;&lt;body&gt;
&lt;h1&gt;Mailman CGI error!!!&lt;/h1&gt;
The Mailman CGI wrapper encountered a fatal error. This entry
is being stored in your syslog:
&lt;pre&gt;
Group mismatch error... (etc. etc. etc.)</pre>
<p>This was a hell of a lot better than a <a href="http://en.wikipedia.org/wiki/Segmentation_fault">segfault</a>, and confirmed that the custom CGI wrapper for search had compiled successfully.</p>
<p>I copied the new &#8220;search&#8221; program to the same place as the other Mailman CGI scripts (with <strong>cp ./search /usr/lib/cgi-bin/mailman/</strong>) and had our server admins change the user and group to match the other CGI programs in that directory.</p>
<p>I also—importantly—had them do <strong>chmod g+s /usr/lib/cgi-bin/mailman/search</strong> to make it a setgid script, because the whole point of this process was to have a a compiled setgid script so that the web server would run the search program as the same group as the other Mailman programs and be able to read all the Mailman files without permission problems.</p>
<p>The last step was then creating a Python search script that would get called by the compiled search CGI wrapper program we just compiled and installed.</p>
<h1>Creating search.py in Mailman/Cgi to Run the Swish Search</h1>
<p>Compared to compiling a &#8220;search&#8221; binary CGI wrapper program, creating the corresponding Python search.py script was relatively simple.</p>
<p>As written above, the CGI wrapper programs in /usr/lib/cgi-bin/mailman/ only seem to exist to let Apache run the real Python scripts with the necessary security permissions as the main Mailman user (via the setgid mechanism).</p>
<p>These Python scripts that actually do the work are in the Mailman/Cgi/ directory, which on our server is /usr/lib/mailman/Mailman/Cgi/, and have the same names as the CGI wrapper programs in /usr/lib/cgi-bin/mailman/, so it&#8217;s pretty easy to see the one-to-one correspondence between them.</p>
<p>Basically, I just needed to do <strong>cp private.py search.py</strong> from within the /usr/lib/mailman/Mailman/Cgi/ directory and then edit search.py to do the following:</p>
<ol>
<li>Removed everything between<br />
<strong>doc.set_language(lang)</strong><br />
and<br />
<strong>if __name__ == &#8216;__main__&#8217;:</strong></li>
<li>Added the following two lines in place of what was just removed:<br />
<strong>os.environ['LISTNAME'] = Utils.websafe(listname)<br />
os.execv(&#8216;/var/lib/mailman/archives/private/swish.cgi&#8217;, [])</strong></li>
</ol>
<p>(or you can copy private.py to search.py and then use <a href="/listserv-to-mailman/code/search.patch">search.patch</a> to make the changes with &#8220;patch &lt; search.patch&#8221;)</p>
<p>This ended up replacing the part of private.py that displays HTML archive files after authentication, with a call to the swish.cgi search program to do the search and display the results.</p>
<p>To test this, I went to http://lists.ourhost.org/cgi-bin/mailman/private/abc-listname/ and clicked on the &#8220;search the list archives&#8221; link. This ran http://lists.ourhost.org/cgi-bin/mailman/search/abc-listname which ended up calling swish.cgi to display the default search form for that list. Putting in a test search term and clicking the Search button searched that list&#8217;s index file (which swish.cgi figured out from the listname in the URL) and displayed the results—<em>after</em> doing the same authentication that private.py uses before displaying private list messages.</p>
<p><strong>Next</strong>: <a href="/2010/07/listserv-to-mailman-tips-tricks-note/">Appendix &#8211; Tips, Tricks, and Notes</a> or <strong>Up</strong>: <a href="/listserv-to-mailman/">Table of Contents</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.anthonyrthompson.com/2010/07/listserv-to-mailman-setting-up-archive-search/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Listserv to Mailman Part 3.1: Converting Listserv Archives to Mailman</title>
		<link>http://blog.anthonyrthompson.com/2010/06/listserv-to-mailman-converting-listserv-archives-to-mailman/</link>
		<comments>http://blog.anthonyrthompson.com/2010/06/listserv-to-mailman-converting-listserv-archives-to-mailman/#comments</comments>
		<pubDate>Fri, 04 Jun 2010 07:52:45 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Tech Tips]]></category>
		<category><![CDATA[archive]]></category>
		<category><![CDATA[archives]]></category>
		<category><![CDATA[conversion]]></category>
		<category><![CDATA[listserv]]></category>
		<category><![CDATA[mailman]]></category>
		<category><![CDATA[mbox]]></category>
		<category><![CDATA[notebook]]></category>

		<guid isPermaLink="false">http://blog.anthonyrthompson.com/?p=22</guid>
		<description><![CDATA[Converting Listserv's proprietary notebook files to Mailman's mbox format, generating web-viewable archive pages from the mbox files, and an important note about disk space.]]></description>
			<content:encoded><![CDATA[<p>Note: You could end up using <em>ten times</em> as much disk space as your uncompressed Listserv archives, after converting them to Mailman&#8217;s mbox format and using Swish to index them for searching. If that amount of disk space could be an issue for you, see &#8220;A Word About Disk Space&#8221; at the end of this page.</p>
<h1>Introduction</h1>
<p>If you&#8217;re converting Listserv lists to Mailman, you probably want to keep your list archives too. The good news is that the Listserv archive format is plain text and is actually <a href="http://www.lsoft.com/manuals/1.8d/qs/editlogs.html">pretty well documented</a>. The bad news is that it&#8217;s a custom proprietary format, not something common like the Unix &#8220;mbox&#8221; format, so conversion will be necessary.</p>
<p>Mailman actually <em>wanted</em> the archives to be in mbox format, so that&#8217;s what we converted the Listserv archives to. In fact, one of our lists had a lot of spam in its archives so after we did the conversion, but before we imported into Mailman, we <a href="http://kb.mozillazine.org/Importing_and_exporting_your_mail">opened the mbox file in Thunderbird</a>, deleted the spam messages, and then saved the file back to mbox for importing into Mailman.</p>
<p>After converting the Listserv archives to mbox format, we had to move the mbox files to the right locations for Mailman to generate HTML archive pages, and then use Swish to index the HTML pages and do a little Mailman fiddling to keep private archives private (including search results). But first, more about the archive conversion process.</p>
<h1>Converting the Archive Files</h1>
<p>My archive conversion journey began with a Perl script called <a href="/listserv-to-mailman/code/ls2mail.pl">ls2mail.pl</a> that was <a href="http://www.hypermail-project.org/archive/99/1216.html">posted in 1999</a> and claimed to convert from Listserv&#8217;s archive format to mbox for Mailman.</p>
<p>The admin of our old Listserv modified it a bit to fix an unspecified &#8220;potentially nasty bug&#8221;, and I modified it further to 1) skip messages with dates earlier than the earliest legitimate post and later than the current year (to weed out spam messages with invalid dates), and 2) better match the <a href="http://en.wikipedia.org/wiki/Mbox">mboxrd</a> format (by quoting body lines beginning with &#8220;From&#8221;).</p>
<p>First, our Listserv archives were broken up into weekly archive files named <em>listname</em>.log<em>YYMMw</em> where <em>YY</em> is the year of the archive file, <em>MM</em> is the month, and <em>w</em> is the week (a = first week, b = second, up to e for a month with five weeks). For example, listname.log0901a was the Listserv archive file for the first week of January, 2009.</p>
<p>I decided it would be better to rename the files to use four digit years instead of two (i.e., <em>listname</em>.log<em>YYYYMMw</em>), so I used a small Perl utility called <a href="/listserv-to-mailman/code/utils/perlren">perlren</a> to rename the files according to  a Perl regular expression. So for each list I did:</p>
<pre>perlren 's#log1#log201#' *.log*
perlren 's#log9#log199#' *.log*
perlren 's#log0#log200#' *.log*</pre>
<p>Then I wanted a master file for each list which would have a sorted listing of all archive files (and because of the rename above, an alpha sorting was also a date sorting):</p>
<pre>ls -1 *.log* &gt; archive-files.txt</pre>
<p>(I used a general name like archive-files.txt since all the log files for each list were grouped into a separate directory for each list.)</p>
<p>Then I used that file as a basis of making a file containing <strong>all</strong> the Listserv log files combined into one big file, in order:</p>
<pre>perl -ne 'print "Processing $_"; chomp; print `cat $_ &gt;&gt; abc-listname.ls`;' \
  archive-files.txt
</pre>
<p>Finally, I ran the <a href="/listserv-to-mailman/code/ls2mail.pl">ls2mail.pl</a> conversion script on the master Listserv log file to convert it to mbox format:</p>
<pre>perl ~/mailman/ls2mail.pl &lt; abc-listname.ls &gt; abc-listname.mbox</pre>
<h1>Generating Mailman&#8217;s HTML Archive Pages</h1>
<p>To generate the viewable HTML pages for Mailman&#8217;s web archive, I just had to move this new mbox file to the appropriate Mailman list archive directory (e.g., /var/lib/mailman/archives/private/abc-listname.mbox/) and run the Mailman bin &#8220;arch&#8221; command to generate the HTML archive pages from the mbox file:</p>
<pre>mv abc-listname.mbox /var/lib/mailman/archives/private/abc-listname.mbox/
/usr/lib/mailman/bin/arch --wipe abc-listname \
  /var/lib/mailman/archives/private/abc-listname.mbox/abc-listname.mbox</pre>
<p>(the &#8211;wipe option tells arch to overwrite any existing HTML pages with newly-generated ones from the mbox file, but since this was a new list that wasn&#8217;t a problem)</p>
<p>Once I&#8217;d tested this with one list, I repeated the process automatically with the other lists by doing something like the following (using command looping in the bash shell again):</p>
<pre>cd /var/lib/mailman/archives/private
for list in abc-list1 abc-list2 abc-list3 etc;
do cd $list;
perlren 's#log1#log201#' *.log*;
perlren 's#log9#log199#' *.log*;
perlren 's#log0#log200#' *.log*;
ls -1 *.log* &gt; archive-files.txt;
perl -ne 'print "Processing $_"; chomp; print `cat $_ &gt;&gt; archive.ls`;' \
  archive-files.txt;
perl ~/mailman/ls2mail.pl &lt; archive.ls &gt; $list.mbox;
mv $list.mbox ../$list.mbox/;
/usr/lib/mailman/bin/arch --wipe $list ../$list.mbox/$list.mbox;
cd ..;
done</pre>
<p>By doing this, all the existing list archives were converted from Listserv archives (combined into .ls files) to Mailman .mbox archive files, and HTML web-viewable archives pages were generated by Mailman&#8217;s arch command.</p>
<h1>A Word About Disk Space<strong><br />
</strong></h1>
<p>I ran into disk space limits several times during this conversion process.</p>
<p>First, our old list host gave us the Listserv archives as one large compressed .tar.gz file—which expanded to triple the size, requiring 4x the size to accommodate both the gzip file and its uncompressed files.</p>
<p>Furthermore, I found that after concatenating all the individual Listserv .log files into one giant Listserv notebook archive .ls file (so, disk space times two for that step), the conversion to mbox format caused the resulting mbox file to take up about 60% more space than the .ls files.</p>
<p>Then running the Mailman arch command on the mbox files generated HTML pages that took up about twice as much space as the corresponding mbox files.</p>
<p>And <em>then</em> the Swish search index files took up about 55% of the size of the HTML archive pages, so that was another bunch of disk space.</p>
<p>The following table shows, step by step, how a 350MB compressed Listserv archive file ballooned up to almost 10GB:</p>
<table cellpadding="5" width="100%">
<tbody>
<tr>
<th>Item/Action</th>
<th>Item Size</th>
<th>Total GB</th>
</tr>
<tr>
<td>Original Gzipped (compressed) Listserv archive files, as one big .tar.gz file</td>
<td>0.35GB</td>
<td>0.35GB</td>
</tr>
<tr>
<td>Uncompressed Listserv archives, indiv .log files (gzip file x 3 due to 1/3 comp ratio)</td>
<td>1.05GB</td>
<td>1.40GB</td>
</tr>
<tr>
<td>Concatenate .log files for each list into .ls Listserv archives (same size as .log files)</td>
<td>1.05GB</td>
<td>2.45GB</td>
</tr>
<tr>
<td>Convert .ls Listserv archive files to mbox files (about 60% bigger than .ls files)</td>
<td>1.68GB</td>
<td>4.13GB</td>
</tr>
<tr>
<td>Run arch on mbox files to generate HTML pages (about 2x size of mbox files)</td>
<td>3.36GB</td>
<td>7.49GB</td>
</tr>
<tr>
<td>Create Swish indexes from HTML pages (about 55% of HTML pages)</td>
<td>1.85GB</td>
<td>9.34GB</td>
</tr>
</tbody>
</table>
<p>You can mitigate some of those increases by deleting interim files (e.g., deleting the individual .log files after creating the concatenated .ls Listserv archive files), but the overall disk usage still ends up a lot more than you might think because the mbox files take more space than the Listserv notebooks, the HTML archive files are twice the size of the mbox files, and the Swish search index files are even more space.</p>
<p>We filled our disk up several times during the conversion, and one of the times this happened caused all mail delivery for all our just-converted lists to stop completely until some disk space was freed up and Mailman was restarted (actually it required a server restart, not just Mailman, which they&#8217;d tried with &#8220;/etc/init.d/mailman restart&#8221;).</p>
<p>By the way, after filling the disk a few times I created a script called <a href="/listserv-to-mailman/code/utils/disk_space_check">disk_space_check</a> and installed a daily cron job to send an email if disk usage was too high:</p>
<pre>/bin/df -h | $HOME/bin/disk_space_check</pre>
<p>In the next section we&#8217;ll add searching to Mailman&#8217;s archives, and make it so search on private lists (and search results) are limited to just subscribers.</p>
<p><strong>Next</strong>: <a href="/2010/07/listserv-to-mailman-setting-up-archive-search/">Setting Up Archive Search</a> or <strong>Up</strong>: <a href="/listserv-to-mailman/">Table of Contents</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.anthonyrthompson.com/2010/06/listserv-to-mailman-converting-listserv-archives-to-mailman/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Listserv to Mailman Part 2.3: Migrating Subscribers And Keeping Them In Sync</title>
		<link>http://blog.anthonyrthompson.com/2010/05/listserv-to-mailman-migrating-subscribers-and-keeping-in-sync/</link>
		<comments>http://blog.anthonyrthompson.com/2010/05/listserv-to-mailman-migrating-subscribers-and-keeping-in-sync/#comments</comments>
		<pubDate>Fri, 28 May 2010 08:20:35 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Tech Tips]]></category>
		<category><![CDATA[copying]]></category>
		<category><![CDATA[listserv]]></category>
		<category><![CDATA[mailman]]></category>
		<category><![CDATA[migration]]></category>
		<category><![CDATA[options]]></category>
		<category><![CDATA[subscribers]]></category>
		<category><![CDATA[subscriptions]]></category>

		<guid isPermaLink="false">http://blog.anthonyrthompson.com/?p=20</guid>
		<description><![CDATA[Determining which Listserv subscribers have various options set, which Mailman options correspond with those Listserv subscriber options, exporting subscribers from old Listserv lists for importing to new Mailman lists, copying over subscription options, keeping subscriber options in sync between Listserv and Mailman, updating subscriber files for web server objects/scripts, and a note about having a Mailman user password strategy.]]></description>
			<content:encoded><![CDATA[<h1>Introduction: Options Make Things Complex</h1>
<p>To migrate subscribers, ideally we&#8217;d just get the addresses on each Listserv list with a REVIEW command and then subscribe those addresses to each new Mailman list of the same name.</p>
<p>The problem is that we need to copy not only the subscribers but their <em>list option settings</em>, such as NOMAIL, DIGEST, etc. This makes it much more complicated.</p>
<p>The first thing I did was identify the few &#8220;concealed&#8221; addresses on our Listserv lists so I could change them to NOCONCEAL. I did this by sending <strong>QUERY LISTNAME WITH CONCEAL FOR *@*</strong> to LISTSERV (replacing LISTNAME with one of the Listserv list names), for each list.</p>
<p>Since there weren&#8217;t a lot of concealed addresses, I set them &#8220;noconceal&#8221; by sending <strong>QUIET SET LISTNAME NOCONCEAL FOR ADDRESS PW=LISTPASSWORD</strong> for each subscriber to LISTSERV (replacing LISTNAME with the list name, ADDRESS with the subscriber address, and LISTPASSWORD with the Listserv list password).</p>
<p>I wanted to eliminate concealed statuses because I needed to make sure all subscribers would show up when I did a REVIEW command to generate one subscriber file for each list (more on this later).</p>
<h1>Listserv Subscriber Settings And Mailman Equivalents</h1>
<p>You may find it helpful to see a list of <a href="http://www.lsoft.com/manuals/1.8d/owner/owner.html#5.3">possible Listserv subscriber options</a> and what settings/actions are available in Mailman to match them:</p>
<table border="1">
<tbody>
<tr>
<th>Listserv Subscriber Options</th>
<th>Mailman Equivalent</th>
</tr>
<tr>
<td><strong>MAIL/NOMAIL</strong> (whether to get posts; MAIL is assumed unless NOMAIL is set)</td>
<td>each subscriber can have the <strong>delivery</strong> flag set &#8220;on&#8221; or &#8220;off&#8221;</td>
</tr>
<tr>
<td><strong>DIGEST/NODIGEST</strong> (whether posts are batched up into periodic digests; NODIGEST is assumed unless DIGEST is set)</td>
<td><strong>add_members</strong> bin command has a -d option to add people with the digest setting; afterwards, a subscriber can have the <strong>digest</strong> flag set &#8220;plain&#8221;, &#8220;mime&#8221;, or &#8220;off&#8221;; see also the <strong>digest_is_default</strong> and other <strong>digest_</strong> list config setting</td>
</tr>
<tr>
<td><strong>MIME/NOMIME</strong> (whether digests are sent to a user in MIME format; NOMIME is assumed unless MIME is set)</td>
<td>each subscriber can have the <strong>digest</strong> flag set &#8220;plain&#8221;, &#8220;mime&#8221;, or &#8220;off&#8221;; plain is equivalent to NOMIME and mime is equivalent to MIME; see also the <strong>mime_is_default_digest</strong> list config setting</td>
</tr>
<tr>
<td><strong>INDEX/NOINDEX</strong> (a variant of digest mode; instead of digest batches of messages, just the subject lines of posts are sent as a summary)</td>
<td><strong>no equivalent</strong> that I am aware of, and that&#8217;s fine because I don&#8217;t really see how useful a summary is with just subjects</td>
</tr>
<tr>
<td><strong>ACK/NOACK/MSGACK</strong> (sends a &#8220;your post was received&#8221; confirmation message, or not; NOACK is assumed unless ACK is set; MSGACK is obsolete)</td>
<td>each subscriber can have the <strong>ack</strong> flag set &#8220;on&#8221; or &#8220;off&#8221;, though I don&#8217;t see the point—it seems to make more sense to just use getting your own posts back (with the <strong>myposts</strong> flag) as the acknowledgement message</td>
</tr>
<tr>
<td><strong>SUBJECTHDR</strong> (whether [list name] is put in the Subject field of every post, for filtering purposes)</td>
<td>I believe this is only settable on a list-wide (not subscriber-specific) basis via the <strong>subject_prefix</strong> list config setting</td>
</tr>
<tr>
<td><strong>CONCEAL/NOCONCEAL</strong> (whether someone shows up on a normal REVIEW of the list)</td>
<td>each subscriber can have the <strong>hide</strong> flag set &#8220;on&#8221; or &#8220;off&#8221;; also the <strong>private_roster</strong> list config setting lets you restrict member addresses to other members or list admins; my mailman_admin_command_handler.py doesn&#8217;t support the <strong>hide</strong> option though since I think it&#8217;s a PITA for admins</td>
</tr>
<tr>
<td><strong>REPRO/NOREPRO</strong> (whether someone gets copies of their own posts; REPRO is assumed unless NOREPRO is set)</td>
<td>each subscriber can have the <strong>myposts</strong> flag set &#8220;on&#8221; or &#8220;off&#8221;</td>
</tr>
<tr>
<td><strong>TOPICS</strong> (a way to let people only see certain categories of posts; I never understood or used this though, seemed easier just to create more lists)</td>
<td>Mailman definitely seems to support this but we did not have to deal with it; there are a number of <strong>topics_</strong> list config settings and supposedly users can choose to just get certain topics; see <a href="http://www.list.org/mailman-member/node29.html">Mailing list topics</a> in the docs</td>
</tr>
<tr>
<td><strong>POST/NOPOST</strong> (whether someone is allowed to post to the list; POST is assumed unless NOPOST is set)</td>
<td><strong>no equivalent</strong> that I am aware of, though you can use the <strong>mod</strong> subscriber flag to cause someone&#8217;s posts to require approval, and then just never approve them <img src='http://blog.anthonyrthompson.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </td>
</tr>
<tr>
<td><strong>EDITOR/NOEDITOR</strong> (whether someone can bypass normal approval mechanisms required for posting to certain lists)</td>
<td>I don&#8217;t <em>think</em> there is a per-user subscriber flag for this, but the <strong>moderator</strong> list configuration setting allows you to specify all moderator/editors at once; the only downside is that then they also get notices of any posts held for review and have the ability to approve/deny them too; can also use the <strong>accept_these_nonmembers</strong> list config setting to allow people to bypass approval, but I think it only works for non-subscribers</td>
</tr>
<tr>
<td><strong>REVIEW/NOREVIEW</strong> (whether someone&#8217;s posts are specially held for approval on an otherwise unmoderated list—usually for bad behavior)</td>
<td>each subscriber can have the <strong>mod</strong> flag set &#8220;on&#8221; or &#8220;off&#8221; (on = they are &#8220;moderated&#8221; and need their posts approve)</td>
</tr>
<tr>
<td><strong>RENEW/NORENEW</strong> (whether someone should get periodic stay-subscribed confirmation emails, overriding the list setting)</td>
<td><strong>no equivalent</strong> that I am aware of, since I don&#8217;t believe Mailman sends out stay-subscribed (i.e., renew your subscription) confirmation messages</td>
</tr>
</tbody>
</table>
<p>Note that some of these settings (like the mod flag for users) were difficult to discover, and sometimes required delving into the source code (especially the Mailman/Commands/cmd_set.py module).</p>
<h1>More Preparation Work</h1>
<p>At this point we&#8217;d changed anyone who was set CONCEALed to NOCONCEAL so we wouldn&#8217;t miss them in the conversion process. Then we needed to decide which of the subscriber settings were important to copy in the conversion and which were not. (The table above should help you think about the various subscriber settings to consider.)</p>
<p>For example, I decided that we&#8217;d support (i.e., carry over the subscriber settings on our old Listserv lists to equivalent Mailman settings on the new lists) the NOMAIL, DIGEST, MIME, NOPOST, NOREPRO, and REVIEW options.</p>
<p>I&#8217;d already decided to include list names in subject lines for all subscribers on all our lists, regardless of what their old Listserv SUBJECTHDR settings were, due to the fact that Mailman only has this setting at the list level.</p>
<p>(For people who had relied on list names in subject lines, to not include this setting on the Mailman lists would destroy their mail filters, while for those who didn&#8217;t rely on it, at worst it would be a mild annoyance to suddenly see list names in subject lines—though before our cutover I warned subscribers that list names in subject lines would soon be the default.)</p>
<p>The Listserv EDITOR flag was also something Mailman only supported on a per-list basis, but that wasn&#8217;t a problem for us because we&#8217;d always used the Editor= line in the old Listserv list headers, rather than the EDITOR flag on individual subscribers, so we dealt with it at the list setting level instead of here at the subscriber setting level.</p>
<p>I&#8217;d decided against supporting the CONCEAL flag, even though there is an equivalent setting on Mailman lists (&#8220;hide&#8221;), because I don&#8217;t think it really protects subscriber addresses (this is really best done with the &#8220;private_roster&#8221; Mailman setting), and over the years CONCEAL caused me a lot of headaches (e.g., I&#8217;d waste a lot of time trying to figure out a subscriber problem only to finally realize that they were concealed).</p>
<p>Finally, I decided we wouldn&#8217;t support the INDEX, ACK, or RENEW/NORENEW options, as Mailman doesn&#8217;t really have equivalents for those and I doubt anyone had set them anyway. I also didn&#8217;t bother with TOPICS since we&#8217;d never used it in Listserv.</p>
<p>So, for all of the &#8220;supported&#8221; options above, I had to send a message to LISTSERV seeing who, for each list, had these supported options set and saving the responses to each message in a separate text file. The message to LISTSERV was <strong>QUERY LISTNAME WITH OPTION FOR *@*</strong> (LISTNAME was the list name and OPTION was something like NOMAIL or MIME).</p>
<p>The reason we did it this way was that based on the way Mailman worked, it seemed best to do this in two steps: 1) Subscribe <em>all</em> subscribers of each Listserv list to the corresponding Mailman list, regardless of their settings, and then 2) go back and apply the special settings for certain people (such as REVIEW) by hand or by script.</p>
<h1>Copying Subscribers And Settings</h1>
<p>With our old Listserv setup we used cron on our web server to do an hourly REVIEW of each list and then save the results (which included all subscribers) to files, one file per list with the listname as the filename.</p>
<p>I&#8217;d written a quick and dirty script called <a href="/listserv-to-mailman/code/queryopt.pl">queryopt.pl</a> to email a query to Listserv to find out all subscribers with a given option on a given list, such as DIGEST, NOMAIL, EDITOR, etc.</p>
<p>Since all our list names began with abc- (where abc is our organization&#8217;s acronym), this allowed me to go into the directory containing all those review output files and do something like <strong>perl queryopt.pl nomail abc-*</strong> and have it send a bunch of Listserv queries, one for each list (because abc-* is expanded by the shell to all the abc- files, or all our list names).</p>
<p>I used the following <a href="http://en.wikipedia.org/wiki/Procmail">procmail</a> filter to save the results of these query emails to files named <em>option</em>-<em>listname</em>.txt (e.g., nomail-abc-foo.txt would have everyone with the NOMAIL option on the abc-foo list):</p>
<pre>PMDIR=$HOME/.procmail
# Save results of certain queries; pipe to prog for massage and save
:0 Hc
* ^From:.*LISTSERV@
* ^Subject:.*Re:.* query
| cat - | $PMDIR/save_opt_query.py
</pre>
<p>This matched the sender and subject line and then sent the email with LISTSERV&#8217;s query response into a program called <a href="/listserv-to-mailman/code/save_opt_query.py">save_opt_query.py</a>.</p>
<p>One minor issue I had, with no easy fix, was that save_opt_query.py expected the Listserv response message to be like:</p>
<pre>Subscription options for Mike Smily &lt;mikednahelix@HOTMAIL.COM&gt;, list
ABC-ANNOUNCE:

DIGEST         You receive list digests, rather than individual postings
SUBJECTHDR     Full (normal) mail headers with list name in message
               subject
REPRO          You receive a copy of your own postings
MSGACK         Short "TELL" acknowledgement of successfully processed
               postings

Subscription date: 30 Jul 2004

Subscription options for "Alexandria ." &lt;alextheconquerer@YAHOO.COM&gt;,
list ABC-ANNOUNCE:

DIGEST         You receive list digests, rather than individual postings
SUBJECTHDR     Full (normal) mail headers with list name in message
               subject
REPRO          You receive a copy of your own postings
MSGACK         Short "TELL" acknowledgement of successfully processed
               postings</pre>
<p>That worked most of the time, but sometimes the name/email was too long so the name was on one line and the email was on the next. So after importing our subscribers I had to go back and manually fix those few cases (by adding those addresses to lists and setting their options), but it was only about 30 people for 70 lists so, while annoying, it was an acceptable trade-off to keep <a href="/listserv-to-mailman/code/save_opt_query.py">save_opt_query.py</a> as simple as possible.</p>
<p>(As to how I identified the problem records, I looked for lines in the saved <em>option</em>-<em>listname</em>.txt files that did not have the &lt;foo@bar.com&gt; brackets, for example with: egrep -v &#8216;&lt;&#8217; *.txt)</p>
<p>As mentioned before, the Listserv subscriber options I decided to support (i.e., copy over to the new Mailman lists) were: DIGEST, MIME (a special case of digest), NOMAIL, NOPOST, NOREPRO, and REVIEW. I also wanted to run <a href="/listserv-to-mailman/code/queryopt.pl">queryopt.pl</a> for NODIGEST to get the &#8220;regular&#8221; (non-digest) subscribers, because the Mailman <strong>add_members</strong> command has flags to specify a file with non-digest subscribers and a file with digest subscribers to add.</p>
<p>So after testing the procmail filter to make sure it would catch and save the option query output into files correctly, I did the following to run it for all the options:</p>
<pre>for option in digest nodigest mime nomail nopost norepro review; \
do perl queryopt.pl $option abc-*; done
</pre>
<p>(Note that this used looping syntax specific to the bash shell; your shell&#8217;s loop and variable substitution might vary, such as requiring parentheses—if you don&#8217;t know what I&#8217;m talking about read your shell&#8217;s man page, search the web, or ask another developer/admin.)</p>
<p>To check if all responses had been saved properly I just did a file count based on filenames:</p>
<pre>for option in digest nodigest mime nomail nopost norepro review; \
do echo $option; ls -1 ${option}-* | wc -l; done
</pre>
<p>(checking that the number of each option file equaled the number of lists we have, for example with 71 lists we should have had 71 nodigest-* files)</p>
<p>Since I&#8217;d been doing all this on our web server where the hourly Listserv REVIEW files resided (which allowed me to do abc-* in the shell to expand to all our listnames), I had to copy these files (which were the results of queries to LISTSERV to find out the options people had on our soon-to-be-old Listserv lists) over to our new list host for automated subscription and option setting on the new Mailman lists.</p>
<h1>Importing Subscribers and Setting Options</h1>
<p>Now we had a bunch of option-related text files (<em>option</em>-<em>listname</em>.txt) on our new Mailman list server. I used shell looping again to do a batch import of subscribers followed by option setting for subscribers with special options like NOMAIL.</p>
<p>Since I&#8217;d already created new Mailman lists on our new list host equivalent to the old Listserv lists I could do the following:</p>
<pre>for lst in `/usr/lib/mailman/bin/list_lists -b | egrep -v '^mailman$'`; do
echo add_members -r nodigest-${lst}.txt -d digest-${lst}.txt -w n -a n $lst
echo set_option.py mod on ${lst} 'tree#bard' review-${lst}.txt
echo set_option.py mod on ${lst} 'tree#bard' nopost-${lst}.txt
echo set_option.py myposts off ${lst} 'tree#bard' norepro-${lst}.txt
echo set_option.py delivery off ${lst} 'tree#bard' nomail-${lst}.txt
echo set_option.py digest mime ${lst} 'tree#bard' mime-${lst}.txt
done</pre>
<p>As before, when using shell looping I like to use &#8220;echo&#8221; statements to check the commands before running them. If all looks good, I remove the echos to really run the commands.</p>
<p>(In fact, I first ran the <strong>add_members</strong> and <a href="/listserv-to-mailman/code/set_option.py">set_option.py</a> commands manually on one of our lists and verified their success by sending &#8220;who&#8221; and &#8220;show&#8221; commands to the admin command handler, before using the shell loop to run them on ALL lists.)</p>
<p>The commands above first subscribe people in bulk using the Mailman <strong>add_members</strong> bin command with options to specify files with non-digest and digest subscribers, and to not send any notifications of the subscriptions. Then they use another script I wrote (<a href="/listserv-to-mailman/code/set_option.py">set_option.py</a>) to apply the Mailman option settings to subscribers and thus copy the old Listserv settings to the new subscribers.</p>
<h1>Keeping Subscribers and Options In Sync</h1>
<p>At this point I had the Mailman lists set up as a snapshot in time of the Listserv lists, but I needed to do additional work to make sure they&#8217;d stay in sync going forward (i.e., to run them in parallel with the Listserv lists, in terms of subscribers and subscriber options).</p>
<p>Fortunately, all of our subscribers seemed to use our CGI-based web subscription management pages rather than emailing LISTSERV directly or using the Listserv web interface and, <a href="/2010/05/listserv-to-mailman-creating-mailman-lists-based-on-listserv-lists/">as described before</a>, those CGI scripts just generated admin email commands to LISTSERV.</p>
<p>This worked out well for our migration because I was able to add Mailman code right after Listserv related code, to do the same things for the Mailman lists (such as subscribe, change options, unsubscribe, etc.).</p>
<p>To get a little more detailed, our web pages called CGI scripts which in turn called a MailingLists.py module to do the actual work for our Listserv lists. For the migration I copied MailingLists.py to <a href="/listserv-to-mailman/code/lib/MailmanLists.py">MailmanLists.py</a> and kept the function names the same but changed the actual commands to use the custom Mailman admin command handler. Then I could just make sure that every time a CGI script used a function in MailingLists.py it called the same function in MailmanLists.py to keep the old Listserv and new Mailman lists in sync.</p>
<p>This was still a little time-consuming, searching all our CGI scripts to see where MailingLists.py was called and then adding calls to MailmanLists.py, but it was worth it.</p>
<p>But it wasn&#8217;t just CGI scripts—I also had to check for cron jobs or shell scripts I&#8217;d written that used MailingLists.py functions too, and add equivalent calls to <a href="/listserv-to-mailman/code/lib/MailmanLists.py">MailmanLists.py</a> like in the CGI scripts (<em>and</em> keep track of all these changes so that I could go back and remove the MailingLists.py calls after the migration was done).</p>
<p>Fortunately, there were relatively few cron jobs or shell scripts which used MailingLists.py (really just one weekly cron job that checked whether the email addresses on &#8220;members only&#8221; lists actually corresponded to current members).</p>
<p>But this is definitely a case where utility scripts like <a href="/listserv-to-mailman/code/utils/tgrep">tgrep</a> came in handy, such as running a command like the following from the home directory on our web server, which also contained the web tree as a subdirectory:</p>
<pre>find . -type f -size -512k -exec tgrep MailingLists {} \; &gt; /var/tmp/mls.txt
</pre>
<p>This started in the current directory (.) and looked through all files (-type f) less than 512Kb (-size -512k) and ran <a href="/listserv-to-mailman/code/utils/tgrep">tgrep</a> (which only searches text files) for &#8220;MailingLists&#8221; and printed out the filename and matching lines. The output was redirected someplace outside the current directory tree because otherwise find/tgrep would have kept matching lines in the output file itself, resulting in an ever-growing output file (ask me how I know this!).</p>
<p>(The unix find command is very powerful and the above only scratches the surface of the many awesome things you can do with it; for more information on its many useful options, Google something like <a href="http://www.google.com/search?q=using+find+linux">using find linux</a>.)</p>
<h1>Keeping Subscriber Files Updated With Mailman<strong><br />
</strong></h1>
<p>This may not apply to you at all, but I want to mention that we still use the loosely coupled web subscription pages whose input goes to CGI scripts which use objects to generate admin email commands to the list server; the only real difference after our migration is that the list server has changed from Listserv to Mailman. (See the <a href="/listserv-to-mailman/code/lib/">lib directory</a>, particularly <a href="/listserv-to-mailman/code/lib/MailmanLists.py">MailmanLists.py</a>—the other files in there are just supporting objects for it.)</p>
<p>You may remember that I said our old Listserv setup had an <a href="/listserv-to-mailman/code/utils/review_and_copy">hourly cron job</a> which sent REVIEW commands to LISTSERV and saved the replies into text files, one per list. That provided subscriber files our <a href="/listserv-to-mailman/code/lib/MailmanLists.py">MailmanLists.py</a> object could use, allowing the CGI scripts to have (relatively) recent information about which subscribers were on which lists.</p>
<p>We could have used the same setup with Mailman, sending email messages to the admin command handler every hour to get an updated subscriber roster for each list, but since we were allowed to submit cron jobs on our <a href="http://www.binhost.com/listserve.html">new list host</a>, it seemed better to just run a job hourly on the list host that would directly extract the subscriber rosters, save them to files, and then copy them over to our web host using secure copy (scp).</p>
<p>By exchanging SSH key files ahead of time we were able to allow the scp copy to happen automatically without having to enter passwords for the file transfer. If you don&#8217;t know what I&#8217;m talking about, Google something like <a href="http://www.google.com/search?q=ssh+passwordless+login">ssh passwordless login</a> (since scp uses ssh underneath).</p>
<p>If you want to do something like this automated saving of list subscriber rosters to files, and then copying them somewhere else, you might find my short <a href="/listserv-to-mailman/code/utils/review_and_copy">review_and_copy</a> utility script useful.</p>
<p>Conversely, if you want to do something like we used to do with Listserv, where you regularly email Mailman&#8217;s admin command handler a &#8220;who <em>listname</em>&#8221; command and then save the results to a file, see the <a href="/listserv-to-mailman/code/utils/revmmlists">revmmlists</a> script.</p>
<p>Similarly, if you&#8217;re paranoid about backing up your Mailman list configurations to dump files on a regular basis (with content equal to running <strong>config_list -o dumpfile listname</strong> at the command line), you might want to look at my <a href="/listserv-to-mailman/code/utils/backup_list_configs">backup_list_configs</a> file.</p>
<p>And if you do a lot from the command line you might be interested in the sub, unsub, group_sub, and group_unsub scripts in the <a href="/listserv-to-mailman/code/utils/">utils area</a>.</p>
<p>That&#8217;s not necessary by any means, but I spent so much time configuring our lists that I want to know I can always recreate those configurations instantly if needed (with <strong>config_list -i configfile listname</strong>).</p>
<h1>A Note About Passwords<strong><br />
</strong></h1>
<p>I need to mention that since our website also had a private, login-based &#8220;members only&#8221; area, we wanted list subscribers who were also members of our organization to have their Mailman list passwords be the same as their website login passwords.</p>
<p>On the other hand, if someone was a subscriber but not a member, we wanted all their passwords set as the same default password.</p>
<p>This didn&#8217;t matter so much for subscription management because we had our own custom pages for subscribing/unsubscribing/etc. In fact, we didn&#8217;t actually want people going to the <em>Mailman</em> list pages for those things, we wanted them to go to <em>our</em> pages so we could also do things like keeping mailing list and website passwords in sync.</p>
<p>However, subscriber passwords <em>did</em> matter for accessing list archives since all our list archives are password-protected to subscribers only, so we wanted the password to be a no-brainer, just-use-the-same-password-as-your-website-login thing.</p>
<p>Shortly copying the subscribers from Listserv to Mailman and setting their options, then adding code to keep Listserv and Mailman subscribers/options in sync, I realized that I needed to also keep subscriber <em>passwords</em> in sync, and not just between Listserv and Mailman, but in the case of members, in sync with each member&#8217;s corresponding website login password too.</p>
<p>I dealt with this in a two-stage manner, just as I had for the options. The first stage was doing a massive sync to get everything correct as of a snapshot point in time. Then the second stage was to make sure it would be correct going forward.</p>
<p>For the first item, the one-time-fix, I coded a utility script called <a href="/listserv-to-mailman/code/utils/sync-list-passwords">sync-list-passwords</a> that used objects representing our membership database and website login system to check whether someone was a member and if so, whether they&#8217;d set up a login on our site. The script checked these and then set the Mailman list passwords appropriately depending on which case each subscriber fit into.</p>
<p>For the second item, I simply made sure in the <a href="/listserv-to-mailman/code/lib/MailmanLists.py">MailmanLists.py</a> code that whenever someone got added to a list it would see if they were a member and had a website login, and then send a password setting command to the admin command handler. If someone were removed from a list there was nothing that needed to be done, and if someone changed their address the clone_member Mailman code took care of copying over their password.</p>
<p>I also had to add code to our website login system so that if someone changed their login password <em>there</em>, it sent a message to the Mailman admin command handler to change their password on all their <em>list subscriptions</em> as well.</p>
<p>I&#8217;d be very surprised if your setup matched ours or was even as complicated, but the point is that Mailman <em>does</em> assign passwords to subscribers for each list (randomly I think, if you don&#8217;t specify), and you <em>will</em> need to think about this if you intend to have <a href="/2010/07/listserv-to-mailman-setting-up-archive-search/">private list archives</a> or intend to allow subscribers direct access to the Mailman web interface pages (since subscribers need to log in to change anything).</p>
<p>Further, if you have a lot of lists you&#8217;ll need to think about how you&#8217;re going to handle the fact that if you don&#8217;t do something to actively keep subscriber passwords the same across all those lists, they could end up with different random passwords on different lists, which could be a big problem.</p>
<p>And it&#8217;s a <em>lot</em> better to come up with a password-handling strategy up front, before you start your migration, than in a panic after the migration has already started (ask me how I know this!).</p>
<p><strong>Next</strong>: <a href="/2010/06/listserv-to-mailman-converting-listserv-archives-to-mailman/">Converting Listserv Archives to Mailman</a> or <strong>Up</strong>: <a href="/listserv-to-mailman/">Table of Contents</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.anthonyrthompson.com/2010/05/listserv-to-mailman-migrating-subscribers-and-keeping-in-sync/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Listserv to Mailman Part 2.2: Creating Mailman Lists Based On Listserv Lists</title>
		<link>http://blog.anthonyrthompson.com/2010/05/listserv-to-mailman-creating-mailman-lists-based-on-listserv-lists/</link>
		<comments>http://blog.anthonyrthompson.com/2010/05/listserv-to-mailman-creating-mailman-lists-based-on-listserv-lists/#comments</comments>
		<pubDate>Mon, 24 May 2010 10:55:05 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Tech Tips]]></category>
		<category><![CDATA[config]]></category>
		<category><![CDATA[create]]></category>
		<category><![CDATA[headers]]></category>
		<category><![CDATA[keywords]]></category>
		<category><![CDATA[listserv]]></category>
		<category><![CDATA[mailman]]></category>
		<category><![CDATA[passwords]]></category>

		<guid isPermaLink="false">http://blog.anthonyrthompson.com/?p=18</guid>
		<description><![CDATA[Analyzing and grouping your Listserv lists based on current settings, which Mailman list settings are equivalent to which Listserv settings, setting up Mailman list setting templates for each configuration group, and creating Mailman lists in bulk instead of one-by-one.]]></description>
			<content:encoded><![CDATA[<h1>Introduction</h1>
<p>This section describes how to create new Mailman lists equivalent to the existing Listserv lists.</p>
<p>When we did this, there were about two weeks when we made subscriber changes in parallel, to both the old Listserv lists and the new Mailman lists, while we converted the archives and got ready for the final cutover.</p>
<p>We were able to do this because all our subscriber changes (subs, unsubs, and address changes) were done through CGI scripts on our website which generated email commands to LISTSERV—so we just modified the scripts to <em>also</em> send equivalent commands to the Mailman administrative command handler we described in the <a href="/2010/02/listserv-to-mailman-installing-an-administrative-command-handler/">last section</a>.</p>
<p>In other words, if someone subscribed to ListX on our website, the CGI script sent commands to subscribe them to both the Listserv ListX (soon-to-be-old server) <em>and</em> the Mailman ListX (soon-to-be-new server), even though the latter weren&#8217;t get getting any posts because ListX@lists.ourhost.org still pointed to the Listserv server.</p>
<p>When we were ready for the actual cutover we just changed lists.ourhost.org to point from the Listserv host to the Mailman host, and Mailman started handling the new posts right away. Then once everything was verified as working properly, we went back and updated the CGI scripts to stop sending subscriber changes to the old Listserv host.</p>
<h1>Identifying And Grouping Current Lists</h1>
<p>This may be easy for you, but we had 70+ lists to migrate, so not only did we have to identify them, we had to <em>group</em> them in terms of their settings so we&#8217;d be able to use a script to create multiple lists with similar settings in a batch instead of having to create them one at a time.</p>
<p>To do this you obviously need to understand all of your old Listserv list settings AND the equivalent new Mailman settings.</p>
<p>So if you  have a large number of lists you&#8217;ll need to examine all of their settings and see if they need to be categorized into settings groups. For example, after analyzing our 70+ lists, I identified the following settings groups:</p>
<ul>
<li>announcement lists &#8211; moderated lists allowing only a few people to post directly (no approval needed), but forcing all other posters&#8217; submissions to go into an approval queue, with replies going to the poster by default, not the list, and with anyone able to subscribe to these lists</li>
</ul>
<ul>
<li>member lists &#8211; discussion lists that any of our organization&#8217;s members (not the general public) could subscribe to and then post to, with replies going to the list by default</li>
</ul>
<ul>
<li>public lists &#8211; discussion lists anyone in the general public could subscribe to and then post to, with replies going to the list by default</li>
</ul>
<ul>
<li>public review lists &#8211; discussion lists anyone in the general public could subscribe to, but with messages requiring moderator approval, and replies going to the list by default</li>
</ul>
<ul>
<li>open post lists &#8211; special purpose lists that anyone in the general public could post to, but which required special list owner approval for subscriptions (the subscriber lists for these were very small)</li>
</ul>
<ul>
<li>restricted lists &#8211; discussion lists whose subscribers were limited to special organizational subgroups, requiring each subscriber to be added or removed by a list owner, with replies going to the list by default</li>
</ul>
<p>To do this for your lists, ask basic questions like the following:</p>
<ol>
<li>Who can subscribe to the lists? (anyone in the public, only people in your organization, only a few special people, etc.)</li>
<li>Who can post to the list? (you might have an announcement list that anyone can subscribe to, but only a few people can post to)</li>
<li>Do posts require moderator approval? (and if so, is the moderator just the list owner, or do you need to have additional non-owner moderators?)</li>
<li>Where do replies to posts go by default? (to the list or to the poster?)</li>
</ol>
<p>Examining your current list settings should answer these questions and maybe prompt additional ones you&#8217;ll need to answer for all your lists. Then you can determine if all your lists have the same settings or they need to be categorized into settings groups as ours did.</p>
<h1>Exploring Mailman List Config Options<strong><br />
</strong></h1>
<p>To see all the possible Mailman settings for a list, I used the following command to view the settings of the previously-created test list:</p>
<pre>/usr/lib/mailman/bin/config_list -o orig.listconfig test-list</pre>
<p>(your config_list location might differ, but it will be with all the other &#8220;mailman bin&#8221; commands)</p>
<p>The goal of this was, for each possible Mailman list setting, to determine if we wanted the same setting to apply to all our lists or if the setting&#8217;s value would differ depending on which settings group the list was in.</p>
<p>If you do this and look at orig.listconfig you&#8217;ll see that it&#8217;s about 80% comments, about 10% blank lines and 10% Python code; list config files like this are (and must be) valid Python code since they are read back in by the <strong>config_list</strong> script with the <strong>-i</strong> option to make list changes.</p>
<p>(Note that if you&#8217;re just changing one or two things, you don&#8217;t need to feed the <em>entire</em> config file back into <strong>config_list</strong>; it&#8217;s smart enough that if you feed it a file with a small number of settings, it will just change those settings on the given list and keep the other settings at their previous values.)</p>
<p>It&#8217;s also important to note that these &#8220;config files&#8221; have no direct ties to Mailman. Once you dump a list&#8217;s configuration settings into a text file using <strong>config_list -o</strong> (o=output) as above, you can do whatever you want with that text file and Mailman won&#8217;t care.</p>
<p>The only time the text file matters again is if you feed it back into Mailman with <strong>config_list -i</strong> (i=input), at which point Mailman will take each setting in that file and use it to update the real list settings it keeps internally. Once you&#8217;ve done that, you&#8217;re free to delete the file if you want—you can always recreate it if necessary with <strong>config_list -o</strong>.</p>
<p>I wanted to keep <a href="/listserv-to-mailman/code/orig.listconfig">orig.listconfig</a> as a set of Mailman&#8217;s default values, so I copied it to announcement.listconfig so that the latter could represent the configuration of our announcement lists (see our settings groups in the bulleted list above).</p>
<p>Then I edited announcement.listconfig, first replacing every reference to &#8220;test-list&#8221; with &#8220;abc-listname&#8221; (no quotes; all our mailing lists begin with abc-). This allowed us to later batch-create multiple lists with almost identical configurations by replacing abc-listname.</p>
<p>Second, I added a comment of &#8220;ALWAYS&#8221; or &#8220;DIFFERS&#8221; next to every setting in announcement.listconfig, for &#8220;always use this setting value for all our lists&#8221; or &#8220;this will differ from one list settings group to another&#8221;. This allowed me to copy announcement.listconfig to other settings group listconfig files, search for each DIFFERS comment, and make changes to just those options.</p>
<p>I also made notes next to each ALWAYS or DIFFERS comment to explain the choice of setting value and make notes about the configuration option itself if necessary. For example:</p>
<pre># Should any existing Reply-To: header found in the original message be
# stripped?  If so, this will be done regardless of whether an explict
# Reply-To: header is added by Mailman or not.
#
# legal values are:
#    0 = "No"
#    1 = "Yes"
<strong># ALWAYS - force replies to list or, if possible, list AND poster
#   either way, need to strip original reply to, so always true
</strong>first_strip_reply_to = True</pre>
<p>The bold text is what I added, a note that I wanted this option to be true for all our lists, applying the &#8220;reply to list&#8221; or &#8220;reply to poster&#8221; policy equally for <em>all</em> posts and never honoring an original Reply-To header included by a poster.</p>
<p>Here&#8217;s an example of a DIFFERS comment explaining the choice and which list settings groups should have which values for this setting:</p>
<pre># When this option is enabled, all list traffic is emergency moderated,
# i.e. held for moderation.  Turn this option on when your list is
# experiencing a flamewar and you want a cooling off period.
#
# legal values are:
#    0 = "No"
#    1 = "Yes"
<strong># DIFFERS - set to no for almost all lists; yes for moderated lists</strong>
emergency = False</pre>
<p>Finally, since a file that&#8217;s intended for feeding back into <strong>config_list -i</strong> must be valid Python code, I wanted to make sure I hadn&#8217;t made any typos so I ran <strong>python announcement.listconfig</strong> to make sure the script diddn&#8217;t bomb; a successful run just gives you back the command line with no output since config files just set a lot of variables.</p>
<p>I&#8217;d love to explain all of our option choices, but you&#8217;ll need to <a href="/listserv-to-mailman/code/orig.listconfig">examine them all for yourself</a> anyway and the in-file comment documentation is usually pretty good. One option I would like to explain though is the &#8220;new_member_options&#8221; setting, an opaque numerical value with a nebulous comment:</p>
<pre># When a new member is subscribed to this list, their initial set of
# options is taken from the this variable's setting.
new_member_options = 256</pre>
<p>The new_member_options name implied it was pretty important and determined the default options for all new subscribers, and I needed to know if it should be the same across all our lists or if it needed to differ per settings group.</p>
<p>However, as you can see there was very little comment documentation for this option, and I couldn&#8217;t find anything online either. Ultimately I had to delve into the source code, where I found the following in the source tree&#8217;s Mailman/Defaults.py.in file:</p>
<pre># Digests             = 0 # handled by other mechanism, doesn't need a flag.
# DisableDelivery     = 1 # Obsolete; use set/getDeliveryStatus()
# DontReceiveOwnPosts = 2 # Non-digesters only
# AcknowledgePosts    = 4
# DisableMime         = 8 # Digesters only
# ConcealSubscription = 16
# SuppressPasswordReminder = 32
# ReceiveNonmatchingTopics = 64
# Moderate = 128
# DontReceiveDuplicates = 256</pre>
<p>I believe the way this works is that you decide which options (&#8220;flags&#8221;) you want to be &#8220;on&#8221; for new subscribers and then add up all the values for those options; the total is what new_member_options should be.</p>
<p>In other words, since the default (in a new Mailman list) new_member_options value is 256, that means the only option turned on for new subscribers is DontReceiveDuplicates.</p>
<p>I examined the above options and determined that the only setting we wanted was SuppressPasswordReminder (if someone subscribed to 20 of our lists it would be awful to get 20 monthly password reminders!), so I made our new_member_options value 32 instead of the default 256, and made an ALWAYS note that this should apply to <em>all</em> our lists.</p>
<p>(Side note: I got the sense that new_member_options is older/obsolete since some of its flags seemed covered by other configuration options and this style of determining default subscriber options is a lot more difficult for most people to use.)</p>
<p>Anyway, after replacing test-list with abc-listname in the announcement config file, and then adding ALWAYS or DIFFERS comments for each option, I copied announcement.listconfig to members.listconfig, then went through all the DIFFERS comments and made sure that the settings values were correct for &#8220;members&#8221; type lists.</p>
<p>When done with members.listconfig I copied it to openpost.listconfig, edited all the DIFFERS settings, and then repeated the copy/edit process for the remaining list settings groups.</p>
<p>I ended up with six .listconfig files, matching our list settings groups in the bulleted list above: announcement.listconfig, members.listconfig, openpost.listconfig, public.listconfig, pubreview.listconfig, and restricted.listconfig. These files were 1) identical to each other except where lists of that settings group <em>should</em> differ, and 2) had a generic list name of &#8220;abc-listname&#8221; instead of the real list name.</p>
<h1>Listserv And Mailman List Configuration Option Equivalents</h1>
<p>In order to make good choices about the Mailman configuration settings for our list settings groups, I needed to understand which old Listserv configuration settings translated to which new Mailman configuration settings.</p>
<p>I wasn&#8217;t able to find much online comparing Listserv and Mailman list settings; in fact the only page I found was the <a href="http://web.mit.edu/lists/mailman/keywords.html">MIT Mailman User Guide: ListServ Keywords in Current Use</a> and its accompanying <a href="http://web.mit.edu/lists/mailman/listmm.pdf">&#8220;cheat sheet&#8221; PDF</a>.</p>
<p>I can only discuss the Listserv options <em>we</em> used and give you their Mailman equivalents, but hopefully between the options here, the <a href="http://web.mit.edu/lists/mailman/keywords.html">MIT page</a>, the <a href="http://www.lsoft.com/manuals/1.8d/owner/appendb.html">Listserv list header documentation</a>, and the <a href="/listserv-to-mailman/code/orig.listconfig">Mailman config file comments</a>, you can figure everything out for your site.</p>
<table border="1">
<tbody>
<tr>
<th>Listserv Header Keyword</th>
<th>Mailman Config File Option</th>
</tr>
<tr>
<td><strong>Review=</strong> (who can get subscriber lists)</td>
<td><strong>private_roster</strong> (found in Privacy options&#8230; → Membership exposure in the Mailman web admin interface)</td>
</tr>
<tr>
<td><strong>Subscription=</strong> (who can subscribe to the list)</td>
<td><strong>subscribe_policy</strong> (Privacy options&#8230; → Subscribing)</td>
</tr>
<tr>
<td><strong>Send=</strong> (who can post to the list)</td>
<td><strong>emergency</strong> (causes all posts to be moderated; General Options → Additional settings), <strong>accept_these_nonmembers</strong> (set to &#8216;<strong>^.*@*.^</strong>&#8216; to allow <em>anyone</em> to post; Privacy options&#8230; → Sender filters → Non-member filters), <strong>include_list_post_header</strong> (General Options → Additional settings)</td>
</tr>
<tr>
<td><strong>Notify=</strong> (if list owner is notified of new subscriptions, deletions, etc.)</td>
<td><strong>admin_immed_notify</strong>, <strong>admin_notify_mchanges</strong> (both are in General Options → Notifications)</td>
</tr>
<tr>
<td><strong>Reply-to=</strong> (if replies go to list/sender, and if reply-to header is honored)</td>
<td><strong>reply_goes_to_list</strong>, <strong>first_strip_reply_to</strong>, <strong>reply_to_address</strong> (these three are in General Options → Reply-To header munging), <strong>anonymous_list</strong> (General Options → General list personality)</td>
</tr>
<tr>
<td><strong>Default-Options=</strong> (initial settings for new subscribers)</td>
<td><strong>new_member_options</strong> (General Options → Additional settings), <strong>digest_is_default</strong> (Digest options), <strong>default_member_moderation</strong> (Privacy options&#8230; → Sender filters → Member filters)</td>
</tr>
<tr>
<td><strong>Files=</strong> (obsolete option, see <a href="http://www.lsoft.com/manuals/1.8d/owner/appendb.html#keyFiles">Listserv doc</a>)</td>
<td><strong>no equivalent</strong></td>
</tr>
<tr>
<td><strong>Validate=</strong> (how to validate commands as authentic; with a password, confirmation and reply, etc.)</td>
<td><strong>no equivalent</strong>, all Mailman web changes require password login</td>
</tr>
<tr>
<td><strong>Filter=</strong> (whether to auto-identify mailing loops and suspicious/spammy From addresses)</td>
<td><strong>header_filter_rules</strong> (loosely; Privacy options&#8230; → Header filters), mostly handled automatically</td>
</tr>
<tr>
<td><strong>Confidential=</strong> (whether list&#8217;s existence is public knowledge)</td>
<td><strong>advertised</strong> (Privacy options&#8230; → Subscription rules → Subscribing)</td>
</tr>
<tr>
<td><strong>X-Tags=</strong> (whether X-To and X-Cc headers in posts are passed to subscribers)</td>
<td><strong>no equivalent</strong>, presumably they are passed on but I have not confirmed</td>
</tr>
<tr>
<td><strong>Stats=</strong> (obsolete option, see <a href="http://www.lsoft.com/manuals/1.8d/owner/appendb.html#keyStats">Listserv doc</a>)</td>
<td><strong>no equivalent<br />
</strong></td>
</tr>
<tr>
<td><strong>Ack=</strong> (whether to respond to postings to let sender know post got through)</td>
<td><strong>autorespond_postings</strong>, <strong>autoresponse_postings_text</strong>, other <strong>autoresponse_</strong> options (all in Auto-responder section of web admin)</td>
</tr>
<tr>
<td><strong>Notebook=</strong> (whether to keep archives and how often to rotate)</td>
<td><strong>archive</strong>, <strong>archive_private</strong>, <strong>archive_volume_frequency</strong> (all in Archiving Options section of web admin)</td>
</tr>
<tr>
<td><strong>Auto-Delete=</strong> (whether and how aggressively to auto-remove bad subscriber addresses)</td>
<td><strong>bounce_processing</strong> and other <strong>bounce_</strong> options (all in Bounce processing section of web admin)</td>
</tr>
<tr>
<td><strong>SizeLim=</strong> (in lines unless otherwise specfied)</td>
<td><strong>max_message_size</strong> (Kb; in General Options → Additional settings)</td>
</tr>
<tr>
<td><strong>Daily-threshold=</strong> (max msgs per day before list is automatically &#8220;held&#8221;)</td>
<td><strong>no equivalent</strong>, though you can manually set &#8220;<strong>emergency</strong>&#8221; if there is a mail loop or flame war (in General Options → Additional settings)</td>
</tr>
<tr>
<td><strong>List-Address=</strong> (domain for the list, so it is listname@list-address)</td>
<td><strong>host_name</strong> (in General Options → Additional settings)</td>
</tr>
<tr>
<td><strong>Attachments=</strong> (whether to allow attachment, reject with an error, or silently strip them)</td>
<td>all <strong>filter_</strong> options, <strong>pass_mime_types</strong>, <strong>pass_filename_extensions</strong>, <strong>collapse_alternatives</strong> (these four options are in Content filtering), <strong>scrub_nondigest</strong> (in Non-digest options)</td>
</tr>
<tr>
<td><strong>Digest=</strong> (whether to support digests for this list and if so, how many messages/lines in each)</td>
<td><strong>nondigestable</strong> (in Non-digest options), <strong>digestable</strong>, <strong>mime_is_default_digest</strong>, <strong>digest_is_default</strong> and other <strong>digest_</strong> options (all in Digest options)</td>
</tr>
<tr>
<td><strong>Language=</strong> (whether to strip/convert HTML to text)</td>
<td><strong>convert_html_to_plaintext</strong> (in Content filtering section of web admin)</td>
</tr>
<tr>
<td><strong>Editor=</strong> (who can review/approve other people&#8217;s posts, and bypass similar moderation</td>
<td><strong>moderator</strong> (General Options → General list personality)</td>
</tr>
<tr>
<td><strong>Owner=</strong> (the list owner or owners)</td>
<td><strong>owner</strong> (General Options → General list personality)</td>
</tr>
<tr>
<td><strong>Errors-To=</strong> (address that errors should go to)</td>
<td><strong>no equivalent</strong>, errors go to list owners</td>
</tr>
</tbody>
</table>
<h1>Creating Mailman Lists In Bulk</h1>
<p>In the &#8220;Identifying And Grouping Current Lists&#8221; section we created several different <em>settingsgroup</em>.listconfig files, where <em>settingsgroup</em> was a name for a group of lists with all the same configuration settings except for the listname itself. We&#8217;d put abc-listname as the list name in the group settings file so we could search and replace it in the batch creation process, which is described in this section.</p>
<p>While we came up with .listconfig files for each settings group, we still had to have a way to say <em>which</em> settings group each list belongs to. So I created <em>settingsgroup</em>.lists files such as announcement.lists, member.lists, public.lists, pubreview.lists, etc. Each file simply had, the lists belonging to that settings group, one list per line.</p>
<p>For example, we only had one announcement type list to create so our announce.lists file had just one line:</p>
<pre>ABC-Announce</pre>
<p>If we&#8217;d had more announcement type lists, they would have each been on a separate line in the announce.lists file.</p>
<p>So the idea was that announcement.lists had a roster of lists (one per line) to create according to the announcement.listconfig file settings, with abc-listname in that settings file to be replaced with each list name from announcement.lists. And the same thing with public.lists, pubreview.lists, etc., with each .lists file containing the lists to be created with the corresponding .listconfig file settings.</p>
<p>There were probably many ways to do the batch creation, taking each line in the whatever.lists file and replacing abc-listname in the whatever.listconfig, then using the &#8220;newlist&#8221; Mailman bin command to create the new list with that name.</p>
<p>I chose to just use a series of single-line commands, one for each settings group. The command I used was the following, pasted into the shell and run <em>as a single line</em>:</p>
<blockquote><p>perl -ne &#8216;chomp; $mclist = $_; $lclist = lc($_); print `echo cp -f announcement.listconfig /tmp/$lclist.listconfig`; print `echo perl -pi -e s#ABC-Listname#$mclist#g /tmp/$lclist.listconfig`; print `echo perl -pi -e s#abc-listname#$lclist#g /tmp/$lclist.listconfig`; print `echo newlist -q $lclist abc-listmaster\@abc.org listpassword &gt;&gt; aliases-to-make.txt`; print `echo config_list -i /tmp/$lclist.listconfig $lclist`;&#8217; announcement.lists</p></blockquote>
<p>(This assumes that you&#8217;re already in the Mailman bin directory, such as /usr/lib/mailman/bin, or that you&#8217;ve put that directory in your $PATH. If not, you will want to write out the full paths to <strong>newlist</strong>, <strong>config_list</strong>, and <strong>change_pw</strong> above.)</p>
<p>Note:  The command as written above won&#8217;t actually <em>do</em> anything, it will just print what it <em>would</em> do if you removed all the &#8220;echo&#8221; commands. Whenever I do anything complex like this, repeating commands over a lot of items, I first use echo statements to print out what&#8217;s <em>going</em> to happen and then look it over to check for errors before running the <em>real</em> commands.</p>
<p>The overall idea is that Perl is used to iterate over each line of the announcement.lists file, where each line is the mixed-case name of a list we want to create. The names are mixed case because in some settings (like the list description) Mailman lets you use mixed case, while in others it just takes lower case.</p>
<p>The command above sets $mclist for the mixed-case list name, and $lclist for lowercase, then it copies announcement.listconfig to a temp location, replaces ABC-Listname in the temp file with the mixed case value using the $mclist variable, and does the same with abc-listname and $lclist.</p>
<p>Then it uses the Mailman <strong>newlist</strong> bin command to create the list using abc-listmaster@abc.org as the initial list owner and &#8220;listpassword&#8221; as the initial list password, though both can be overridden in the group settings file which is applied next.</p>
<p><strong>Important Note</strong>: Since we had 70 different email lists, we <em>did</em> want them all to have the same password. Your situation may be different and if you need each list password to be different you might use the above commands to set them all the same and then use the Mailman <strong>change_pw</strong> command afterward to customize the password on a per-list basis.</p>
<p>The version of the <strong>newlist</strong> command above also appends the output of the command to a file called aliases-to-make.txt in case you need to create mail aliases for your new lists. We didn&#8217;t need to do that though because our <a href="http://www.binhost.com/listserve.html">new list host</a> had set up <a href="http://www.freebsddiary.org/mailman.php">postfix-to-mailman.py</a> so that postfix automatically recognized the Mailman aliases for new lists. (There&#8217;s a qmail-to-mailman.py file too if you&#8217;re running qmail, very handy.)</p>
<p>(Note: Actually the &#8220;&gt;&gt; aliases-to-make.txt&#8221; redirection in the &#8220;echo newlist&#8221; portion causes that command to get redirected into aliases-to-make.txt rather than printing on screen, so for testing the echo you&#8217;ll have to remove &#8220;&gt;&gt; aliases-to-make.txt&#8221;, just be sure to add it back in before running the commands for real!)</p>
<p>After the new list is created, <strong>config_list</strong> is used with the temp config file to configure it.</p>
<p>If you&#8217;re comfortable with all of this, try it out and examine the output from the echo commands.</p>
<p>You can even try the commands for real, one at a time in the shell with one list, to make sure they&#8217;ll work as you expect them to (e.g., that there are no path or permission errors). In that case you can check the contents of aliases-to-make.txt to make sure the output is what you expected, and even run <strong>config_list -o &#8211; newlistname</strong> to double-check the configuration.</p>
<p>When you&#8217;re comfortable with what will happen from the looping commands above, remove the echo statements and run the commands for real with a small number of lists. If that works, you can then run the commands with each successive settings group (which for us meant changing &#8220;announcement&#8221; to &#8220;member&#8221;, then &#8220;public&#8221;, &#8220;pubreview&#8221;, etc.), ultimately creating all new Mailman lists in batches according to their old Listserv settings groups.</p>
<p><strong>Next</strong>: <a href="/2010/05/listserv-to-mailman-migrating-subscribers-and-keeping-in-sync/">Migrating Subscribers And Keeping Them In Sync</a> or <strong>Up</strong>: <a href="/listserv-to-mailman/">Table of Contents</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.anthonyrthompson.com/2010/05/listserv-to-mailman-creating-mailman-lists-based-on-listserv-lists/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Listserv to Mailman Part 2.1: Installing an Administrative Command Handler</title>
		<link>http://blog.anthonyrthompson.com/2010/02/listserv-to-mailman-installing-an-administrative-command-handler/</link>
		<comments>http://blog.anthonyrthompson.com/2010/02/listserv-to-mailman-installing-an-administrative-command-handler/#comments</comments>
		<pubDate>Mon, 08 Feb 2010 23:19:44 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Tech Tips]]></category>
		<category><![CDATA[admin]]></category>
		<category><![CDATA[administrative]]></category>
		<category><![CDATA[commonds]]></category>
		<category><![CDATA[email]]></category>
		<category><![CDATA[interface]]></category>
		<category><![CDATA[mailman]]></category>
		<category><![CDATA[postfix]]></category>
		<category><![CDATA[procmail]]></category>

		<guid isPermaLink="false">http://blog.anthonyrthompson.com/?p=15</guid>
		<description><![CDATA[Installing a program to handle administrative commands sent by email (e.g., from a CGI script), including a few helper files needed by the handler, testing to check that the files were installed correctly, and some problems we encountered and solved.]]></description>
			<content:encoded><![CDATA[<h1>Introduction</h1>
<p>This section describes how to install an &#8220;administrative command handler&#8221;, something you can email list management commands to, just like emailing commands to LISTSERV. If you never used the Listserv email interface then this entire section may be unnecessary for you.</p>
<h1>Background</h1>
<p>One of the first things I did when investigating Mailman was try to find out how to send mailing list management commands by email.</p>
<p>That was important because in administering our 70 email lists over the years, we&#8217;d developed a set of <a href="/listserv-to-mailman/code/utils/">helper scripts</a> and <a href="/listserv-to-mailman/code/lib/MailmanLists.py">modules</a> to make list management actions like subscribing/unsubscribing easier.</p>
<p>If someone wanted to subscribe to our lists they&#8217;d put their name and email into a form, check off the lists they wanted, and submit. Then behind the scenes our scripts would send an email to LISTSERV with the appropriate commands to make it happen.</p>
<p>This was all aimed at 1) allowing subscribers to manage their own subscriptions on the web, and 2) allowing list admins to easily manage subscribers over a lot of lists.</p>
<p>Unfortunately, it soon became apparent that <strong>Mailman has no administrative email interface</strong>. Instead, Mailman provides a simple but clean web-based interface for list admins to manage users on each mailing list.</p>
<p>Going to <em>each</em> list&#8217;s web interface to manage a given subscriber is fine for one or a few mailing lists, but it&#8217;s <em>completely unmanageable</em> at 10, 20, or 70 lists—you need a simple one-stop place to set options, change addresses, etc. for a subscriber on <em>all</em> lists at once.</p>
<p>This meant I  either had to abandon Mailman as the mailing list software in favor of something which did have an administrative email interface, or stick with Mailman and program it myself. Since Mailman seemed like the only viable replacement for Listserv, I decided to <a href="http://en.wikipedia.org/wiki/The_Cathedral_and_the_Bazaar">scratch my own itch</a>.</p>
<p>Fortunately, I already knew <a title="Paul Graham: The Python Paradox" href="http://www.paulgraham.com/pypar.html">Python</a>, which most of Mailman is written in, so programming an administrative email interface which could call built-in Mailman code to do its work was actually <em>possible</em>.</p>
<h1>Issues Setting Up Admin Command Handler<strong><br />
</strong></h1>
<p>I&#8217;d noticed when I created the &#8220;test-list&#8221; on my development box with the <strong>newlist</strong> command that it told me I still needed to create some email aliases for various list-related addresses to pipe messages into mailman for handling:</p>
<pre>To finish creating your mailing list, you must edit your
/etc/aliases (or equivalent) file by adding the following
lines, and possibly running the `newaliases' program:</pre>
<pre>## test-list mailing list
test-list:              "|/path/to/mailman post test-list"
test-list-admin:        "|/path/to/mailman admin test-list"
test-list-bounces:      "|/path/to/mailman bounces test-list"
...</pre>
<p>This got me to thinking that I&#8217;d need an email address to receive the Mailman admin commands. My first thought, based on the above, was something like test-list-admin-cmd, but I didn&#8217;t want to have to make a new admin alias for every new list.</p>
<p>I really wanted something like our old listserv@lists.ourhost.com, which all our web and shell scripts were sending admin command messages to.</p>
<p>So I created a command handler called <a href="/listserv-to-mailman/code/mailman_admin_cmd_handler.py">mailman_admin_cmd_handler.py</a> and in the control panel for the development box set it so that mail sent to mailman-admin-cmd@lists.ourhost.com would get piped into mailman_admin_cmd_handler.py</p>
<p>(Our host&#8217;s control panel was cPanel, and I used the Forwarders option in the Mail section to &#8220;Add a Forwarder&#8221;, then &#8220;Address to Forward&#8221; of mailman-admin-cmd, then &#8220;Advanced Options&#8221;, then &#8220;Pipe to a Program&#8221;, then /path/to/mailman_admin_cmd_handler.py)</p>
<p>If you use /etc/aliases for Sendmail or Exim, as the <strong>newlist</strong> output suggests, then you&#8217;d probably do something like:</p>
<pre>## admin interface for all mailing lists
mailman-admin-cmd:   "|/path/to/mailman_admin_cmd_handler.py"
</pre>
<p>Actually that&#8217;s a simplification of what I really did. I <em>really</em> used <a href="http://en.wikipedia.org/wiki/Procmail">procmail</a> because that&#8217;s what handled all our other mail forwarding needs. So in &#8220;Pipe to a Program&#8221; I piped it to <strong>|/usr/bin/procmail -m /home/ouruser/.procmail/rc.mailman-admin-cmd</strong> and then in that procmail recipe file I put:</p>
<pre>:0 H
* ^TOmailman-admin-cmd@lists.ourhost.com
| $HOME/.procmail/mailman_admin_cmd_handler.py
</pre>
<p>(actually I had a few other things in that file, but a <a href="http://userpages.umbc.edu/~ian/procmail.html">procmail tutorial</a> is beyond the scope of this guide—type &#8220;man procmailrc&#8221; or &#8220;man procmailex&#8221; at a shell for more info)</p>
<p>This was all on our dev box, and part of why I stuck mailman_admin_cmd_handler.py in ~/.procmail was that my goal was not to make any modifications to the base Mailman installation in case our production list host didn&#8217;t let us muck with those files.</p>
<p>This placement had a few minor consequences. One is that I had to create symbolic links for two mailman &#8220;bin&#8221; programs, <a href="/listserv-to-mailman/code/list_members.py.txt">list_members</a> and <a href="/listserv-to-mailman/code/clone_member.py.txt">clone_member</a>, into the same directory as the handler script, adding .py to the symbolic links so the handler script could import them. For example:</p>
<pre>cd /home/ouruser/.procmail
ln -s /path/to/mailman/bin/clone_member ./clone_member.py
ln -s /path/to/mailman/bin/list_members ./list_members.py</pre>
<p>I also had to install a helper module (<a href="/listserv-to-mailman/code/ListStream.py">ListStream.py</a>) and configure mailman_admin_cmd_handler.py with custom settings like the Mailman installation directory, the SMTP server, an optional string/password for the subject line of admin command messages (for added security), etc.</p>
<p>Even if you can put <a href="/listserv-to-mailman/code/mailman_admin_cmd_handler.py">mailman_admin_cmd_handler.py</a> in the mailman bin directory itself, you&#8217;ll still need to symlink clone_member to clone_member.py (and the same for list_members) within that directory so mailman_admin_cmd_handler.py can import and use those scripts, you&#8217;ll still need to save ListStream.py there, etc.</p>
<p>(But I&#8217;d still recommend keeping these <a href="/listserv-to-mailman/code/">custom scripts</a> outside the installed Mailman tree, even if you have permissions to modify those files, simply because if you ever upgrade your Mailman installation, you don&#8217;t want to inadvertently delete/move the custom files and break a lot of stuff. Plus it&#8217;s just nice to have standard-install Mailman stuff in one area, and custom add-on stuff in another.)</p>
<p>I should also mention that when we finally chose a <a href="http://www.binhost.com/listserve.html">list host</a>, they didn&#8217;t use alias forwarding/piping or procmail at all, they used a specialized <a href="http://www.gurulabs.com/goodies/downloads/#postfix-mailman">postfix-to-mailman.py script</a> so that no aliases needed to be made when new lists were created.</p>
<p>(If you&#8217;re using Postfix with Mailman see the <a href="http://www.gnu.org/software/mailman/mailman-install/mailman-install.html">GNU Mailman Installation Manual</a>, particularly the <a href="http://www.gnu.org/software/mailman/mailman-install/node13.html">Integrating Postfix and Mailman</a> section; see also a related discussion on <a href="http://www.freebsddiary.org/mailman.php">FreeBSDDiary</a>.)</p>
<h1>Downloading the Files<strong><br />
</strong></h1>
<p>Here are the basic files for setting up the administrative email interface; click to view, right-click and Save to download:</p>
<ul>
<li><a href="/listserv-to-mailman/code/mailman_admin_cmd_handler.py">mailman_admin_cmd_handler.py</a> &#8211; the main handler program</li>
<li><a href="/listserv-to-mailman/code/ListStream.py">ListStream.py</a> &#8211; a helper module used by mailman_admin_cmd_handler</li>
<li><a href="/listserv-to-mailman/code/clone_member.py.txt">clone_member.py.txt</a> &#8211; a reminder that you need to symlink clone_member</li>
<li><a href="/listserv-to-mailman/code/list_members.py.txt">list_members.py.txt</a> &#8211; a reminder that you need to symlink list_members</li>
<li><a href="/listserv-to-mailman/code/test_mailman_admin_cmd_handler.py">test_mailman_admin_cmd_handler.py</a> &#8211; optional unit tests of the handler</li>
</ul>
<p>test_mailman_admin_cmd_handler.py is completely optional, but I&#8217;d recommend downloading and running it just to check that you made all the necessary customization changes in mailman_admin_cmd_handler.py. Just be sure to look through it thoroughly before running it, because you&#8217;ll need to choose your own test values.</p>
<p><strong>IMPORTANT NOTE:</strong> I&#8217;ve tried to make sure that any code I&#8217;m providing has the word <strong>INSTALL</strong> in comments to mark any places you&#8217;ll need to modify the code for your own installation (i.e., places where your installation will probably differ from mine). So you <strong><em>need</em></strong> to go through every file you download and search/grep for INSTALL and update the corresponding settings.</p>
<h1>Installing</h1>
<p>The following are the steps I used to install the administrative email command handler on our <a href="http://www.binhost.com/listserve.html">production host</a>. In some cases your environment may differ, such as the difference between using Sendmail/procmail filtering (on our dev box) and using Postfix (on our production box) as described above.</p>
<p>First, I created a directory to hold all custom Mailman related files, ~/mailman.</p>
<p>I also noted the locations of the system (installed) Mailman files, which seemed to be /etc/mailman, /var/lib/mailman, and /usr/lib/mailman. In particular, I needed to know the path to the directory tree holding the Mailman bin scripts and helper objects, which the admin command handler uses. (For us, those were /usr/lib/mailman/bin/ and /usr/lib/mailman/Mailman/ respectively.)</p>
<p>After downloading the files in the &#8220;Downloading the Files&#8221; section above into the ~/mailman directory I needed to modify the /etc/mailman/postfix-to-mailman.py file in order to allow commands sent to mailman-admin-cmd@lists.ourhost.org to get sent to the handler script:</p>
<pre>                  ("/usr/sbin/sendmail", MailmanOwner))
         sys.exit(0)

+    # Local customization
+    elif local == 'mailman-admin-cmd':
+        mm_admin_pgm = '/home/adf/mailman/mailman_admin_cmd_handler.py'
+        os.execv(mm_admin_pgm, [])
+
     # Assume normal posting to a mailing list
     mlist, func = local, 'post'</pre>
<p>(If you&#8217;re not familiar with diff output, that means I added the four lines with the pluses to the area between the sys.exit(0) line and the # Assume lines.)</p>
<p>At this point I really wanted to send a command to see what would happen, but I thought it would be better to run the handler&#8217;s <a href="/listserv-to-mailman/code/test_mailman_admin_cmd_handler.py">unit tests</a> first to see if I&#8217;d missed something basic.</p>
<p>To do this, I needed to search the downloaded files for server-specific things to edit that had been flagged with <strong>INSTALL</strong> comments (such as the location of our Mailman files in /usr/lib/mailman).</p>
<p>I also had to, as described above, create the list_members.py and clone_member.py symlink files in ~/mailman pointing to list_members and clone_member in /usr/lib/mailman/bin.</p>
<p>The unit tests assume a test list called test-list, so  I had to use <strong>newlist test-list</strong> in /usr/lib/mailman/bin/ to make it (you can delete it later with <strong>rmlist</strong> if you wish).</p>
<p>The unit tests in <a href="/listserv-to-mailman/code/test_mailman_admin_cmd_handler.py">test_mailman_admin_cmd_handler.py</a> also assume there is a test user already on the test list, so I did this with:</p>
<pre>echo "test@ourhost.org" | /usr/lib/mailman/bin/add_members -r - test-list</pre>
<p>Once I&#8217;d done that, and made sure all the other settings in test_mailman_admin_cmd_handler.py were correct (especially in the setUp function), I ran test_mailman_admin_cmd_handler.py at the command line and verified that all the unit tests passed.</p>
<p>(If you do this and the tests don&#8217;t pass, you&#8217;ll need to look at the tests that failed in test_mailman_admin_cmd_handler.py and figure out what went wrong and why.)</p>
<h1>Testing</h1>
<p>Now,  having verified that the code was set up correctly via the unit tests in test_mailman_admin_cmd_handler.py, I wanted to send a test command by email.</p>
<p>I should mention that I hit a snag at this point that you might not.</p>
<p>I had decided, as part of the overall migration strategy, to have our new Mailman list host be lists2.ourhost.org while continuing to run our lists on the soon-to-be-old Listserv lists.ourhost.org.</p>
<p>When Mailman was set up properly, including creating all lists and copying all users and their options, so that the two hosts were in sync, the plan for the cutover was to just change where lists.ourhost.org pointed to. This worked out pretty smoothly in the end, by the way, but I wanted to explain the lists2.ourhost.org thing now.</p>
<p>So I sent a command to mailman-admin-cmd@lists2.ourhost.org, putting <strong>help</strong> in the subject line and body.</p>
<p>That should have generated an error because the default setup requires any emailed admin commands to have a password in the subject line for security, and of course most list-related commands require their own passwords too (the list password, the site admin password, or the list owner&#8217;s password if the list owner is on the list and the email is sent from that account).</p>
<p>Unfortunately that simple &#8220;help&#8221; test produced the following error:</p>
<pre>550-Verification failed for &lt;mailman-admin-cmd@lists2.ourhost.org&gt;
550-The mail server could not deliver mail to
mailman-admin-cmd@lists2.ourhost.org. The account or domain may not
exist, they may be blacklisted, or missing the proper dns entries.
550 Sender verify failed (in reply to RCPT TO command))
</pre>
<p>Also, the error <em>only</em> happened when I sent from myaddress@ourhost.org; when I sent the help test message from anotheracct@gmail.com (or any domain which was not ourhost.org) it worked fine and produced the expected &#8220;Required password not present in subject line.&#8221;</p>
<p>The admin for our new list provider said, &#8220;Because this test domain, lists2.ourhost.org, does not have Sender Verify set up on it, it&#8217;s failing the check and your ourhost.org mailserver is rejecting it.&#8221; I researched this and found that what he called &#8220;sender verify&#8221; refers to the <a href="http://en.wikipedia.org/wiki/Sender_Policy_Framework">Sender Policy Framework</a>, aka SPF record, an anti-spam related DNS record.</p>
<p>Eventually our old host (which was still running the DNS for ourhost.org) solved the problem and when I asked them how, they wrote:</p>
<blockquote><p>I&#8217;m not sure I remember all the steps along the way. I originally<br />
created an A record for lists2.ourhost.org, and an MX record that<br />
referred to the same IP address.  When all was said and done I had<br />
an A record, an MX record that referred to lists2.ourhost.org (instead<br />
of to its IP address) and a TXT field with the following contents:</p>
<p>spf1 a mx a:208.85.173.148 -all</p>
<p>Here are the tinydns source records that I used:<br />
+lists2.ourhost.org:208.85.173.148:3600<br />
@lists2.ourhost.org::lists2.ourhost.org:20<br />
&#8216;lists2.ourhost.org:v=spf1 a mx a\072208.85.173.148 -all:3600</p></blockquote>
<p>(I&#8217;ve altered the IP addresses for the privacy of the org I did this for, btw.)</p>
<p>I wish I could give more information about this Sender Verify problem and what really solved it, but at least if you encounter the same thing this info might help.</p>
<p>Anyway, having solved the Sender Verify problem, I re-sent the test message to mailman-admin-cmd@lists2.ourhost.org with <strong>help</strong> in the subject and body and got the expected &#8220;Required password not present in subject line&#8221; response.</p>
<p>Then I sent another test message, this time with <strong>help PASSWORD</strong> in the subject (no quotes, where PASSWORD was the value of SUBJECT_PASSWD in <a href="/listserv-to-mailman/code/mailman_admin_cmd_handler.py">mailman_admin_cmd_handler.py</a>) and <strong>help</strong> in the body, and got the expected response, &#8220;Valid commands:&#8221; followed by a list of valid commands for the admin command handler.</p>
<p>I didn&#8217;t do an exhaustive test of every command, since the unit tests in test_mailman_admin_cmd_handler.py sort of do that, but I did try one more command besides &#8220;help&#8221; just to make sure the basic mechanism was working.</p>
<p>I tried sending the &#8220;who&#8221; command to see who was subscribed to the test list I&#8217;d set up. Specifically, I sent a message with a subject of <strong>who test-list PASSWORD</strong> (where PASSWORD was the SUBJECT_PASSWD value in <a href="/listserv-to-mailman/code/mailman_admin_cmd_handler.py">mailman_admin_cmd_handler.py</a>) and a body of <strong>who test-list LISTPASSWORD</strong> (where LISTPASSWORD was the password I set for the list when creating it).</p>
<p>(Note: You can actually use anything in the subject line as long as it has the admin command handler password, but I like to keep it as descriptive as possible, and for a single command that usually means using the command itself minus the list password.)</p>
<p>After a few issues involving list ownership (I&#8217;d mistakenly sent the command from an account that wasn&#8217;t one of the list owners for the test list), I finally got a roster of subscribers for test-list so I felt a little more confident that the basic system was working correctly.</p>
<p><strong>Next</strong>: <a href="/2010/05/listserv-to-mailman-creating-mailman-lists-based-on-listserv-lists/">Creating Mailman Lists Based On Listserv Lists</a> or <strong>Up</strong>: <a href="/listserv-to-mailman/">Table of Contents</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.anthonyrthompson.com/2010/02/listserv-to-mailman-installing-an-administrative-command-handler/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Maximum Password Length On Linux</title>
		<link>http://blog.anthonyrthompson.com/2010/02/maximum-password-length-on-linux/</link>
		<comments>http://blog.anthonyrthompson.com/2010/02/maximum-password-length-on-linux/#comments</comments>
		<pubDate>Sun, 07 Feb 2010 10:35:01 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Tech Tips]]></category>
		<category><![CDATA[crypt]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[login]]></category>
		<category><![CDATA[md5]]></category>
		<category><![CDATA[passwd]]></category>
		<category><![CDATA[password length]]></category>
		<category><![CDATA[passwords]]></category>
		<category><![CDATA[security]]></category>

		<guid isPermaLink="false">http://blog.anthonyrthompson.com/?p=13</guid>
		<description><![CDATA[It used to be the case, years ago, that passwords on Unix systems were limited to 8 characters. Or rather, you could type in more than 8 characters, but only the first 8 characters mattered. It occurred to me recently that by now, this limit must surely have been lifted, especially as Moore&#8217;s Law has [...]]]></description>
			<content:encoded><![CDATA[<p>It used to be the case, years ago, that passwords on Unix systems were limited to 8 characters. Or rather, you could type in more than 8 characters, but only the first 8 characters mattered.</p>
<p>It occurred to me recently that by now, this limit must surely have been lifted, especially as <a href="http://en.wikipedia.org/wiki/Moore's_law">Moore&#8217;s Law</a> has improved hardware speeds and thus the ability to <a href="http://en.wikipedia.org/wiki/Password_cracking#Early_Unix_password_vulnerability">crack passwords of 8 characters easily via brute force</a>.</p>
<p>(See <a href="http://nsrc.cse.psu.edu/tech_report/NAS-TR-0030-2006.pdf">Password Exhaustion: Predicting the End of Password Usefulness &#8211; PDF</a> for more good info on this.)</p>
<p>So I asked about this over on <a href="http://stackoverflow.com/questions/2179649/are-passwords-on-modern-unix-linux-systems-still-limited-to-8-characters">Stack Overflow</a> (SO), and got a lot of good responses. But in thinking about the answers more, and in particular trying to code something to find the maximum length on a given system, I had some more thoughts.</p>
<p>In particular, while the limit of 8 characters probably went away on most Linux systems in the late 1990s or early 2000s, there&#8217;s always a lingering question (in my mind anyway) of, &#8220;Yeah, but does this system I&#8217;m currently on support characters &gt; 8 characters?&#8221;</p>
<p>Here&#8217;s what I coded up as a quick Perl script to try finding the maximum length of passwords for the system it&#8217;s run on:</p>
<pre>#!/usr/bin/perl -w
$| = 1; # turn off output buffering so each . prints out
my($newpasswd) = chr(rand(95) + 32); # ASCII char 32-126
my($lasthash) = crypt($newpasswd, '$1$12345678'); # MD5=$1$
while (1) {
    print '.'; # for debugging/progress
    $newpasswd = join('', $newpasswd, chr(rand(95) + 32));
    $newhash = crypt($newpasswd, '$1$12345678');
    if ($newhash eq $lasthash) {
        print "Maximum password length: ";
        print length($newpasswd) - 1, "\n";
        last;
    }
}
</pre>
<p>(loosely based on some code posted in response to my question on SO)</p>
<p>After looking at <a href="http://www.ratliff.net/blog/2007/09/20/password-length/">this blog post on Password Length</a>, I figured the program would stop at 79 or 127 or something, but to my surprise it didn&#8217;t, it just kept going on and on and on until eventually it was killed by my web host as a runaway program (which, I guess, it sort of was <img src='http://blog.anthonyrthompson.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> )</p>
<p>This puzzled me, and <a title="Lothar of the Hill People on Hulu - do you find it vexing?" href="http://www.hulu.com/watch/4108/saturday-night-live-lothar-of-the-hill-people">vexed</a> me, so in my obsessiveness I wanted to find out why this would happen. I mean, that blog post said there was a limit, so why wasn&#8217;t I finding one?</p>
<p>It turns out that as long as you&#8217;re making the Unix crypt() function use a hashing method other than the classic/default <a href="http://en.wikipedia.org/wiki/Crypt_%28Unix%29#Traditional_DES-based_scheme">DES-based algorithm</a>, by using a salt prefix like $1$ for MD5, there really is no limit to the password because it&#8217;s like producing an MD5 hash for a file—you can get a different MD5 hash for files of any length.</p>
<p>I believe where the real limit—if there is one on a given system—comes in, is not in the Unix crypt() function, but by the password programs such as &#8220;passwd&#8221; that use it. Those programs themselves may have input limits, which is the only way I can explain the limits shown on that <a href="http://www.ratliff.net/blog/2007/09/20/password-length/">password length blog post</a>.</p>
<p>As someone on SO commented though, you&#8217;re probably always <em>safe</em> using a password longer than 8 characters—if you used &#8220;mybigbigapple&#8221; as a password and the system only paid attention to the first 8 characters, it would just ignore the &#8220;apple&#8221; part. It&#8217;s just a question of whether it wall also accept &#8220;mybigbigorange&#8221;.</p>
<p>And if it&#8217;s <em>easier</em> for you to remember a longer password, then that&#8217;s a consideration too.</p>
<p>I guess for me it&#8217;s just a question of knowing whether the system I&#8217;m on is stronger (supporting passwords &gt; 8 characters) or weaker with passwords, and for some reason I just want to <strong>know</strong> whether the system is ignoring everything I type past 8.</p>
<p>I did find it a little ironic, though, that if your password gets into the very long category, there&#8217;s actually a greater chance (<a href="http://en.wikipedia.org/wiki/MD5#Collision_vulnerability">at least with MD5</a> I believe) of a hash collision, meaning that another password (or one entered by a password cracker) might produce the same hash and thus let someone use that alternate password instead of your real password.</p>
<p>(If you have no idea what I&#8217;m talking about re: password hashes, see the Wikipedia article on Passwords, particularly the <a href="http://en.wikipedia.org/wiki/Password_cracking#Background">Background section</a>.)</p>
<p>So where does that leave us? Well, I think it&#8217;s relatively easily to check whether crypt() supports passwords longer than 8 characters:</p>
<pre>perl -e 'if (crypt(q^12345678^, q^$1$@@$^) eq
  crypt(q^123456789^, q^$1$@@$^)) { print "crypt() appears
  limited to 8 characters\n" } else { print "crypt() appears
  to support more than 8 characters\n"; }'
</pre>
<p>(typed on the command line, all in one line of course)</p>
<p>Exactly <em>how much longer</em> than 8 characters seems like it would depend on the particular program and not crypt() itself. The <a href="http://www.ratliff.net/blog/2007/09/20/password-length/">password length blog post</a> seems to say that 72 or 79 might be a common limit, and since the average English word length appears to be 5.1 letters, that&#8217;s about 14 words.</p>
<p>So as a rule of thumb, we can probably figure that maybe a 10 word maximum for a password (really a &#8220;pass phrase&#8221;) is about right. That&#8217;s what I&#8217;ll go with anyway, at least after I use the command above to check that such a longer password/passphrase will actually be worth the trouble on a given system <img src='http://blog.anthonyrthompson.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>At least until passwords <a title="Short clip of eye scan from Minority Report" href="http://www.youtube.com/watch?v=kx9IEP8pmiI">go away completely</a> of course! <img src='http://blog.anthonyrthompson.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> </p>
<p>(And while I&#8217;m on the topic of security, let me recommend the excellent book <a href="http://www.amazon.com/exec/obidos/ASIN/0470395354/antrtho-20/">Schneier on Security</a>. I picked it up in the bookstore recently with a stack of other books to breeze through, and long after putting the other books down I was still reading it! Very good thinking on a wide range of computer security topics.)</p>
<div id="_mcePaste" style="overflow: hidden; position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px;">http://nsrc.cse.psu.edu/tech_report/NAS-TR-0030-2006.pdf</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.anthonyrthompson.com/2010/02/maximum-password-length-on-linux/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Listserv to Mailman Part 1.2: Installing Swish for Archive Searching</title>
		<link>http://blog.anthonyrthompson.com/2010/02/listserv-to-mailman-installing-swish-for-archive-searching/</link>
		<comments>http://blog.anthonyrthompson.com/2010/02/listserv-to-mailman-installing-swish-for-archive-searching/#comments</comments>
		<pubDate>Mon, 01 Feb 2010 21:39:16 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Tech Tips]]></category>
		<category><![CDATA[archives]]></category>
		<category><![CDATA[indexing]]></category>
		<category><![CDATA[listserv]]></category>
		<category><![CDATA[mailman]]></category>
		<category><![CDATA[searching]]></category>
		<category><![CDATA[swish]]></category>
		<category><![CDATA[swish-e]]></category>

		<guid isPermaLink="false">http://blog.anthonyrthompson.com/?p=11</guid>
		<description><![CDATA[Choosing an archive search package for Mailman, about the Swish-E package for archive indexing/searching, and Swish-E filter/helper add-ons for indexing attachment files like PDFs and Word docs.]]></description>
			<content:encoded><![CDATA[<h1>Background</h1>
<p>Mailman, unlike Listserv, doesn&#8217;t come with built-in list archive searching. (Which is funny since I&#8217;d always thought Listserv&#8217;s archive search was clunky and dated—but at least it <em>had</em> archive search! <img src='http://blog.anthonyrthompson.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> )</p>
<p>I think Mailman may not have archive searching because the developers wanted to keep their focus on the mailing list software itself rather than trying to write and maintain search software too. They probably figured it would be better to leave search to search software developers, and also give people the freedom to install whatever search package they want.</p>
<p>Nonetheless, it would have been a great relief if Mailman had just come with a default search package for list archives that could be uninstalled/overridden if necessary, rather than making everyone who wants to provide list archive searching (which <em>must</em> be a pretty common requirement) re-invent the search wheel by hunting down a package and figuring out how to integrate it into Mailman.</p>
<h1>The Swish-E Package</h1>
<p>After a good deal of searching (ha) I eventually found that many others who also wanted searchable list archives seemed to lean toward using Swish-E (<a href="http://www.swish-e.org/">swish-e.org</a>, <a href="http://en.wikipedia.org/wiki/SWISH-E">Wikipedia</a>).</p>
<p>(Note: Since writing this guide, I&#8217;ve found that others have used <a href="http://en.wikipedia.org/wiki/Htdig">htdig</a> successfully for archive searching too; see the _README file at <a href="http://www.msapiro.net/mm/">msapiro.net/mm/</a> and <a href="http://www.msapiro.net/mm/INSTALL.htdig-mm.html">this documentation</a>.)</p>
<p>Fortunately, I already had experience with Swish because our organization already used Swish for the search feature on its main website.</p>
<p>I wish I could provide step-by-step instructions for setting up Swish , but I forget the steps I used to install it from source on our development box (web host) back in 2003, and the server admins on our production list host installed it for me, probably using a binary package manager like RPM or Apt.</p>
<p>Even though I don&#8217;t have step-by-step instructions for installing Swish (though if you are root, downloading/unpacking the source, running &#8220;configure&#8221; and &#8220;make install&#8221; will probably do the trick), I wanted to include a section about it for a few reasons.</p>
<p>Aside from pointing you to the main swish-e.org site, in particular the <a href="http://www.swish-e.org/download/">Download</a> and <a href="http://www.swish-e.org/docs/">Documentation</a> sections (the latter including a nice INSTALL page) , I also wanted to point you to the <em>extremely</em> helpful <a href="http://wpkg.org/Integrating_Mailman_with_a_Swish-e_search_engine">Integrating Mailman with a Swish-e Search Engine</a> page.</p>
<p>I ended up only following some of that page&#8217;s advice, but it was invaluable for getting started on the Listserv to Mailman archive conversion as far as what issues to consider. So that page is definitely worth checking out just to see what&#8217;s involved. (Though note that I ended up writing <a href="/listserv-to-mailman/code/arch_index.py">code</a> to automate some of the things on that page, which I&#8217;ll cover <a href="/2010/07/listserv-to-mailman-setting-up-archive-search/">later</a>.)</p>
<p>First though, just focus on installing Swish-e itself, which indexes and searches 1) the Mailman HTML archive pages (one page per message) and, optionally, 2) any message attachment files such as PDFs or Word docs by using extra Swish add-on/filter programs.</p>
<h1>Using Swish-E for Searching Message Attachments</h1>
<p>While the basic setup of Swish for HTML archive messages is fairly easy, setting it up to search non-HTML/text files such as Word, Excel, and PDF attachments is a little more tricky. I struggled with this when I set up Swish to search binary files on our website, so I wanted to give some info on it in case you want to support searching message attachments too.</p>
<p>(Mailman <em>does</em> allow attachments to be included in list archives, it just separates each from its associated message and puts a link to the attachment file at the bottom of the archived message.)</p>
<p><strong>Note</strong> though: This entire section (the rest of this page) is optional. To be blunt, if you don&#8217;t <em>have</em> to support searching archive message attachments, make your life easier and don&#8217;t do it; you can always go back and add it later if you need to. We didn&#8217;t even do it for our list archives, I&#8217;m just including this info about using Swish to index binary files based on my experience doing that on our main website.</p>
<p>For a general article about indexing HTML pages and other file types with Swish-E, see <a href="http://www.linuxjournal.com/article/6652">How to Index Anything</a> from the Linux Journal in 2003. At first glance that page is very good, but I haven&#8217;t examined it in detail and it&#8217;s possible that some details have changed since 2003.</p>
<p>Basically, for non-text/HTML files Swish relies on external helper programs to extract text from each file. For example, it uses the pdftotext program in the <a href="http://www.foolabs.com/xpdf/">xpdf package</a> for extracting text from PDF files, the <a href="http://www.wagner.pp.ru/~vitus/software/catdoc/">catdoc program</a> to get text from Word .doc files, etc. See the &#8220;Optional But Recommended Packages&#8221; section of the <a href="http://www.swish-e.org/docs/install.html">Swish-E INSTALL doc</a> for more info on what&#8217;s available.</p>
<p>(I haven&#8217;t yet tackled the issue of extracting text from Word&#8217;s newer .docx file format for Swish; if I do, I&#8217;ll update this page, but if you&#8217;ve already done so please <a href="/contact/">let me know</a>; some possibilities are 1) <a href="http://sourceforge.net/projects/docx2txt/">docx2txt</a>, 2) <a href="http://linux.die.net/man/1/unoconv">unoconv</a> though that might unusable by Swish because it requires a running OpenOffice instance, or 3) maybe even a quick-and-dirty <a href="http://stackoverflow.com/questions/1184747/rtf-doc-docx-text-extraction-in-program-written-in-c-qt">unzip/sed/grep combination</a>.)</p>
<p>For more information about supporting searching of PDF, Word, etc. files, see &#8220;How do I index my PDF, Word, and compressed documents?&#8221; and the sections after it on the <a href="http://www.swish-e.org/docs/swish-faq.html#how_do_i_index_my_pdf_word_and_compressed_documents_">Swish-E FAQ page</a> as well as the example filters in the &#8220;Document Filter Directives&#8221; section of the <a href="http://www.swish-e.org/docs/swish-config.html#document_filter_directives">SWISH-CONFIG man page</a>.</p>
<p>Note: I had to tweak the example given on that last page for PDF and DOC files, which were the only two binary file types I included in our website search. Specifically, the SWISH-CONFIG page gave the example of:</p>
<pre>FileFilter .pdf       pdftotext   "%p -"</pre>
<p>and that produced an error during indexing; every time the Swish indexer encountered a PDF file and tried to run pdftotext,  it printed pdftotext&#8217;s usage info:</p>
<pre>pdftotext version 3.02
Copyright 1996-2007 Glyph &amp; Cog, LLC
Usage: pdftotext [options] &lt;PDF-file&gt; [&lt;text-file&gt;]
  -f &lt;int&gt;          : first page to convert
  -l &lt;int&gt;          : last page to convert
  ... etc.</pre>
<p>To fix this, I had to tweak it to:</p>
<pre>FileFilter .pdf pdftotext "'%p' -"</pre>
<p>Actually I chose to spell out the full /path/to/pdftotext instead of just pdftotext there, but you get the idea—the main difference is in the quoting at the end, to put %p within its own single quotes.</p>
<p>I had to do the same thing with the catdoc example; the SWISH-CONFIG page suggested:</p>
<pre>FileFilter .doc     /usr/local/bin/catdoc "-s8859-1 -d8859-1 %p"</pre>
<p>&#8230; but that failed too so I enclosed the %p in single quotes there as well:</p>
<pre>FileFilter .doc /path/to/our/catdoc "-s8859-1 -d8859-1 '%p'"</pre>
<h1>Character Set Problems While Indexing</h1>
<p>Another issue was that at some point I started getting character set error messages when running the Swish indexer. I wish I&#8217;d documented the problem and my solution when it happened, but I&#8217;ve done my best to reconstruct the issue in case it&#8217;s useful to someone.</p>
<p>I believe the error may have been something about catdoc not being able to find the ascii.replchars and/or ascii.specchars character set files. I think I hunted around to find these files, but since catdoc seems to be a fairly old (and seemingly unmaintained) package, my search was fruitless.</p>
<p>Ultimately I think my solution was that I noticed I <em>did</em> have ascii.rpl and ascii.spc files, so I copied those to ascii.replchars and ascii.specchars and that fixed the problem.</p>
<p>I&#8217;m also still getting the following error (from pdftotext I believe) when running the Swish indexer on our web site:</p>
<pre>Error: Unknown character collection 'Adobe-Korea1'</pre>
<p>I searched online and couldn&#8217;t find anything for that specific character set, but when I searched for &#8220;swish unknown character collection&#8221; I found <a href="http://swish-e.org/archive/2004-12/8679.html">this post</a> which recommended upgrading the xpdf package as a possible solution. I haven&#8217;t tried it yet because it&#8217;s only a few errors and I hate to upgrade things unless I absolutely have to, but I wanted to mention it here in case someone else gets similar errors using Swish to index PDFs.</p>
<p><strong>Next</strong>: <a href="/2010/02/listserv-to-mailman-installing-an-administrative-command-handler/">Installing an Administrative Command Handler</a> or <strong>Up</strong>: <a href="/listserv-to-mailman/">Table of Contents</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.anthonyrthompson.com/2010/02/listserv-to-mailman-installing-swish-for-archive-searching/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Listserv to Mailman Part 1.1: Installing Mailman</title>
		<link>http://blog.anthonyrthompson.com/2010/02/listserv-to-mailman-installing-mailman/</link>
		<comments>http://blog.anthonyrthompson.com/2010/02/listserv-to-mailman-installing-mailman/#comments</comments>
		<pubDate>Mon, 01 Feb 2010 07:55:15 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Tech Tips]]></category>
		<category><![CDATA[installation]]></category>
		<category><![CDATA[installing]]></category>
		<category><![CDATA[listserv]]></category>
		<category><![CDATA[mailman]]></category>

		<guid isPermaLink="false">http://blog.anthonyrthompson.com/?p=9</guid>
		<description><![CDATA[Choosing a version of Mailman and installing it to a local directory in a non-root/shared environment, installing to a web directory other than /mailman, and basic testing of the installation.]]></description>
			<content:encoded><![CDATA[<h1>Installing from Source</h1>
<p>This page describes how I installed Mailman from source on our development server (a shared web hosting environment). However, it&#8217;s also possible to install through a binary package manager such as <a href="http://rpm.org/">RPM</a> or <a href="http://wiki.debian.org/Apt">Apt</a>, which is actually how our <a href="http://www.binhost.com/listserve.html">list host</a> admins installed it onto our production server. So things might end up in different locations depending on how Mailman is installed.</p>
<h1>Choosing a Version and Downloading<strong><br />
</strong></h1>
<p>My first question for installing Mailman on our dev box was <em>which version</em>. This mattered because we had not yet chosen a list host but I assumed that whatever host we ultimately chose would probably have the latest <em>stable</em> and <em>mature</em> version.</p>
<p>Figuring out the latest stable and mature version of Mailman turned out to be a bit challenging. By examining the &#8220;timeline&#8221; graph at <a href="https://launchpad.net/mailman/+series">https://launchpad.net/mailman/+series</a> (specifically, by hovering over the graph and hitting the little magnify-minus sign several times so I could eventually see all the way to the right), I found that at the time of checking (early Dec 2009), version 2.1.12 was the latest stable version since it was the most recent on the 2.1 &#8220;latest stable release&#8221; line.</p>
<p>I tried to download mailman-2.1.12.tgz from launchpad.net several times, but it never worked, so I finally downloaded it from <a href="http://ftp.gnu.org/gnu/mailman/?C=M;O=D">http://ftp.gnu.org/gnu/mailman/?C=M;O=D</a></p>
<p>(Both of the above download sites were found on the main Mailman site at <a href="http://www.gnu.org/software/mailman/download.html">http://www.gnu.org/software/mailman/download.html</a>)</p>
<h1>Installing Mailman to a Custom Directory</h1>
<p>I&#8217;ll skip past the usual technical details of downloading and unpacking files (I did it from the shell command line with: <strong>wget http://ftp.gnu.org/gnu/mailman/mailman-2.1.12.tgz</strong> and then: <strong>tar xvfz mailman-2.1.12.tgz</strong>).</p>
<p>In fact I wouldn&#8217;t even mention the installation process except that my first attempt failed because the web host I was using (which is not the one I am happily using now, <a href="http://www.dreamhost.com/r.cgi?635400">Dreamhost</a>) had pre-mapped the /mailman URL for me, and it resisted any attempts to override/fix it.</p>
<p>This was a problem because when I first installed Mailman on our dev box, created a test list (with the <strong>newlist</strong> command), and then tried to go to something like http://ourdomain.org/mailman/listinfo/test-list it told me there was no such list—even though I had just created it. I banged my head against the wall for a while until I figured out that my web host had pre-mapped /mailman and that there was no way around it.</p>
<p>(If you want to see if your web host has done this, I recommend going to http://www.yourhost.com/mailman/ <em>before</em> installing Mailman, and seeing if you get the same error page as when going to http://www.yourhost.com/badpagelink/ or if you get some unexpectedly-different page instead.)</p>
<p>So eventually I had to delete that first installation and install again into a different directory with the following options:</p>
<pre>./configure --prefix=/home/ouruser/public_html/mm
--with-username=ouruser --with-groupname=ouruser
--with-mail-gid=ouruser --with-cgi-gid=ouruser
--with-mailhost=mail.ourhost.org --with-cgi-ext=.cgi</pre>
<p>(I had to use the &#8211;prefix option, rather than accepting the default installation location, because my dev box was a shared hosting environment where I was just a regular user, rather than having root/admin permissions and being able to install into system directories like /var/mailman.)</p>
<p>After running <strong>configure</strong> and <strong>make install</strong> I then created a test list by running the mailman &#8220;bin&#8221; program <strong>newlist test-list</strong> (in ~/public_html/mm/bin). Then I tried going to http://ourdomain.org/mailman/listinfo/test-list and things seemed to work fine until I tried to log in, at which point the fact that Mailman insists on setting cookies with a Path of /mailman caused my logins to not &#8220;stick&#8221;.</p>
<p>I thought this would be easy to fix by editing the cookie set by Mailman from /mailman to /mm, but it turned out that most of the cookie-related add-ons for Firefox do <strong>not</strong> allow you to <em>edit</em> cookie values.</p>
<p>The <a href="https://addons.mozilla.org/en-US/firefox/addon/13793">Add N Edit Cookies</a> Firefox add-on seemed promising, but when I edited the Path value of the cookies set after logging in to Mailman, to change from /mailman to /mm, it didn&#8217;t actually save the changes. But I figured out a workaround: copying the cookie values for the old login cookie (Name, Content, Host, Path, Expires) to a temp text file, deleting the cookie, then creating a new cookie with the same values except a different Path (and plus 20 years for the Expires value too).</p>
<p>All these machinations were just to deal with having to install Mailman to /mm instead of /mailman on our dev box because the web host had pre-mapped /mailman for us and we couldn&#8217;t override it. Hopefully you won&#8217;t have that problem at all; I highly recommend just installing using the defaults if you can!</p>
<p>For more information about installing Mailman see the official <a href="http://www.gnu.org/software/mailman/mailman-install/">GNU Mailman Installation Manual</a>. There&#8217;s also a helpful page covering more technical aspects of installing on various flavors of Linux (including the easy way of just installing from an RPM or YUM package) at the <a href="http://www.yolinux.com/TUTORIALS/LinuxTutorialMailman.html">YoLinux Tutorial: GNU Mailman Email List Installation and Configuration</a>.</p>
<h1>Testing the Installation</h1>
<p>If you&#8217;ve installed Mailman into the default /mailman and used <strong>newlist</strong> to create a &#8220;test-list&#8221;, you should be able to use the following URLs to check if your installation is correct:</p>
<ul>
<li>http://yourhost.com/mailman/listinfo/test-list for info about the test list</li>
<li>http://yourhost.com/mailman/admin/test-list for admin pages about test list</li>
<li>http://yourhost.com/mailman/listinfo for info on all lists on the server</li>
</ul>
<p>If you had to install Mailman to a custom directory like /mm and/or use a custom CGI file extension like .cgi, then you&#8217;d want to use something like the following:</p>
<ul>
<li>http://yourhost.com/mm/cgi-bin/listinfo.cgi/test-list for info about the test list</li>
<li>http://yourhost.com/mm/cgi-bin/admin.cgi/test-list for admin pages for test list</li>
<li>http://yourhost.com/mm/cgi-bin/listinfo.cgi for info on all lists on the server</li>
</ul>
<p>I haven&#8217;t covered setting up the automatic Mailman daemons and cron jobs because I couldn&#8217;t do that on our dev box&#8217;s shared hosting environment, and they were already set up on our production server. If you&#8217;re installing on your own box as root, the default options to configure and make install should take care of all that for you.</p>
<p><strong>Next</strong>: <a href="/2010/02/listserv-to-mailman-installing-swish-for-archive-searching/">Installing Swish for Archive Searching</a> or <strong>Up</strong>: <a href="/listserv-to-mailman/">Table of Contents</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.anthonyrthompson.com/2010/02/listserv-to-mailman-installing-mailman/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Listserv to Mailman Part 1.0: Overview</title>
		<link>http://blog.anthonyrthompson.com/2010/02/listserv-to-mailman-overview/</link>
		<comments>http://blog.anthonyrthompson.com/2010/02/listserv-to-mailman-overview/#comments</comments>
		<pubDate>Mon, 01 Feb 2010 05:29:42 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Tech Tips]]></category>
		<category><![CDATA[conversion]]></category>
		<category><![CDATA[introduction]]></category>
		<category><![CDATA[listserv]]></category>
		<category><![CDATA[mailman]]></category>
		<category><![CDATA[overview]]></category>

		<guid isPermaLink="false">http://blog.anthonyrthompson.com/?p=6</guid>
		<description><![CDATA[Overview of the Listserv to Mailman project this guide is about, the specific problems of our situation and how we explored our options, and finally a note about our development vs production list servers.]]></description>
			<content:encoded><![CDATA[<h1>Preface and Disclaimer</h1>
<p>This guide was written in short bursts over several months, sometimes at the same time as performing our conversion from Listserv (pricey commercial mailing list manager) to Mailman (free software mailing list manager) and sometimes after the fact. (If you stumbled across this page and don&#8217;t know the difference, see <a href="http://wiki.list.org/display/DOC/Mailman+is+not+Listserv">Mailman is not Listserv</a>.)</p>
<p>So it is not by any means perfect or even necessarily free from mistakes, and it certainly needs editing and cleaning up. In particular you may find the narrative/explanatory style <a title="Saturday Night Live: Lothar of the Hill People" href="http://www.hulu.com/watch/4108/saturday-night-live-lothar-of-the-hill-people">vexing</a>, along with occasional changes in person/tense.</p>
<p>For these flaws I can only apologize in advance. I will try to clean them up and improve these pages over time, but even with its current shortcomings, it is still the guide (and code!) I wish had been available when I started my own conversion of 70+ Listserv lists to Mailman.</p>
<p><strong>Note</strong>: This guide and the <a href="/listserv-to-mailman/code/">code I&#8217;m making available</a> were both written against Mailman version <strong>2.1.12</strong>. I&#8217;d hope that future versions of Mailman wouldn&#8217;t change the API functions I called, but obviously there is no guarantee that won&#8217;t happen, so if you use my code with a later version of Mailman it might not work. In particular, if you&#8217;re going to use the <a href="/listserv-to-mailman/code/mailman_admin_cmd_handler.py">administrative command handler</a>, I&#8217;d recommend running its <a href="/listserv-to-mailman/code/test_mailman_admin_cmd_handler.py">test program</a> first to see if anything breaks.</p>
<h1>The Problem<strong><br />
</strong></h1>
<p>The problem: A small non-profit organization which had more than 70 <a href="http://www.lsoft.com/products/listserv.asp">Listserv</a> mailing lists, most with 10+ years of archives, needed to convert all of the lists and archives to <a href="http://www.gnu.org/software/mailman/">GNU Mailman</a> because its Listserv host was going to cease all operations within a year&#8217;s time (i.e., we got 9 months&#8217; warning).</p>
<p>The old Listserv list host had had a special, grandfathered non-profit site license for Listserv, and LSoft was unwilling to allow that license to transfer with our organization to another host, so sticking with Listserv simply wasn&#8217;t an option.</p>
<p>(If you hunt around the LSoft website and finally dig up their <a href="http://www.lsoft.com/products/listserv_license.asp">pricing</a>, you&#8217;ll see that for most small organizations even the cheapest Listserv license is prohibitively expensive; it certainly was for us, a non-profit org with 70 lists and a total annual IT budget of about $1000/year.)</p>
<p>Searching for other hosts that already had Listserv lists proved fruitless as well. I could hardly find any that had Listserv, and the few that did have it were way too pricey.</p>
<p>Also, it seems that in the modern Internet age, &#8220;mailing list&#8221; means &#8220;email marketing newsletter&#8221;, not &#8220;discussion list&#8221;. This distinction was important, and came up repeatedly as a problem because almost all of our our 70 lists were <em>discussion</em> lists.</p>
<p>I bring this up because early on someone in our organization pointed out that our website host already provided &#8220;mailing list&#8221; software called <a href="http://en.wikipedia.org/wiki/Dada_Mail">DadaMail</a>&#8230; which is actually just meant for one-way marketing newsletter emails.</p>
<p>In fact, one of DadaMail&#8217;s main features is that it has <em>email throttling</em>. Why? Because most ISPs now limit customers&#8217; outgoing email to a maximum number of messages per hour. Why? Probably because spammers crack people&#8217;s websites through common application vulnerabilities and then use the victims&#8217; sites to send spam.</p>
<p>Why did the hourly email limit on our web host matter? Because if you have 1000 customers and want to send them all a single newsletter message, that&#8217;s fine—if your host limits you to 500 messages/hour then you set DadaMail or your mailing script to send one message every 2-3 seconds.</p>
<p>The problem arises when you have an actual <em>discussion</em> list (and we had 70 of them!). If you have a discussion list with 600 subscribers and someone sends a post to the list, the ISP tries to send that post to 600 subscribers and hits the hourly limit.</p>
<p>You could spread delivery of the post over two hours but what happens when someone who gets it <em>replies</em>? That&#8217;s another 600 messages going out, when some people haven&#8217;t even gotten the first one yet! Clearly, if there is actual <em>discussion</em> (i.e., replies), email thottling (as with DadaMail and other announcement-oriented programs) just won&#8217;t work.</p>
<p>So what I learned from my research into mailing list software and hosts was that there are really two problems: 1) The cost of the mailing list software itself, and 2) the difficulty finding a list host which won&#8217;t cap/throttle your email message output at a certain number per hour.</p>
<h1>The Solution</h1>
<p>The answer to the problem of the exorbitant cost of Listserv was fairly simple. I had noticed <a href="http://www.gnu.org/software/mailman/">GNU Mailman</a> years before, and it seemed to be an open source replacement for Listserv which was reasonably mature and somewhat Listserv-like. I was right about this, but it required a lot of customization which is why this documentation exists.</p>
<p>For the second problem, there just didn&#8217;t seem to be any affordable hosts offering mailing lists, especially for 70+ lists.</p>
<p>One possible solution would have been to get a dedicated server and install Mailman on it. That solution wouldn&#8217;t have worked for my non-profit because they just don&#8217;t have the resources to manage a dedicated server—they barely have enough manpower to manage their website and membership database.</p>
<p>So we basically had to find a host that would already have Mailman, or allow us to install it, would not have a per-hour message throttling/limit, would let us have command line (shell) access to run the Mailman &#8220;bin&#8221; commands and extend Mailman&#8217;s functionality (such as adding an administrative command handler), and would otherwise manage the server (backups, security updates, performance tweaking, etc.). And all for a price within our small budget, of course.</p>
<p>After a <strong>lot</strong> of searching we eventually found one, <a href="http://www.binhost.com/listserve.html">Binhost</a>, which we&#8217;ve been pretty happy with so far. If you set up an account with them, please mention me—I won&#8217;t personally get anything for it, but my non-profit org will get a small account credit for the referral. Or if you have any questions about our experiences with them, feel free to <a href="/contact/">contact me</a>.</p>
<h1>Development and Production Servers<strong><br />
</strong></h1>
<p>Due to the long time it took to find a list host, I&#8217;d already started playing with Mailman on our main web server just to learn it, even knowing that we couldn&#8217;t actually have our lists on that server.</p>
<p>So in effect, our web host became my development server for playing with Mailman and determining what kinds of customizations we&#8217;d need for a smooth transition from Listserv when we did find a list host.</p>
<p>I only mention this because there were a few differences between the dev box setup (a shared web host) and the list host we ultimately settled on (really a special case managed server), and this guide will occasionally mention differences between these two servers so I wanted to describe their setup a bit here.</p>
<h1>Files for Downloading</h1>
<p>I&#8217;ve tried to link to relevant code files in the text, but you can also <a href="/listserv-to-mailman/code/">browse all the code at once</a>. The <a href="/listserv-to-mailman/code/utils/">utils/</a> subdirectory has scripts I found helpful, and used indirectly in the project, but which weren&#8217;t directly related to the conversion. For example, <a href="/listserv-to-mailman/code/utils/tgrep">tgrep</a> searches through files like grep, but ignores non-text (binary) files.</p>
<p><strong>Next</strong>: <a href="/2010/02/listserv-to-mailman-installing-mailman/">Installing Mailman</a> or <strong>Up</strong>: <a href="/listserv-to-mailman/">Table of Contents</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.anthonyrthompson.com/2010/02/listserv-to-mailman-overview/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
