Applications Linux

Integrating SpamAssassin with qmail: Part 2

This is a series of articles covering integration of SpamAssassin with qmail on a Linux box.

Part 1: Installing and Configuring SpamAssassin
Part 2: Marking email as spam

Part 2: Marking email as spam

Now, that we setup SpamAssassin to run as a continous process, we are able to change the qmail system to feed all emails into the server daemon. We need the root folder of qmail first. This is usually at /var/qmail. However, you better check with your installation first.

Create a file “qmail-queue.spamd” in subfolder bin that contains a single line:

/usr/bin/spamc -U /tmp/spamd_full.sock| /var/qmail/bin/qmail-queue.orig

Adapt the paths if necessary. Next step is to rename the existing qmail-queue program in subfolder bin. Name it “qmail-queue.orig”, as we have already used that pathname in our script. Make sure that all file permissions of qmail-queue.orig and qmail-queue.spamd match exactly the original qmail-queue binary.

Last step is to replace the existing qmail-queue binary by a link to our qmail-queue.spamd script. That’s it. All your emails do now pass the SpamAssassin daemon. You can check this by viewing all headers of emails passing your system. They should now contain additional SpamAssassin lines.

This is not the end of the story. We just marked email so far as spam or not. The will not get filtered out of the boxes, yet. This however is the topic of part 3 of this series.

Applications Linux

Integrating SpamAssassin with qmail: Part 1

This is a series of articles covering integration of SpamAssassin with qmail on a Linux box.

Part 1: Installing and Configuring SpamAssassin
Part 2: Marking email as spam

Part 1: Installing and Configuring SpamAssassin

There are quite a few numbers of HOWTOs at the internet about installing the software itself. So I won’t go very much into details but rather point you to some locations where you can find sufficient information.

You’ll find the latest software package at Apache’s SpamAssassin Homepage. Unpack the archive, preferrably at /usr/local/src. It will produce a directory Mail-SpamAssassin-XXXX. Change into that directory and read the INSTALL file to learn about special features when building the spam recognition tool. Usually you need to issue three commands:

perl Makefile.PL
make install

That’s it. Be aware that you might need to enhance your Perl distribution by additional modules from CPAN.

The last step to perform is to make a tool called spamd running continously on your box. We will first configure the daemon according to your Linux distribution. On latest SuSE editions this is done by a file /etc/sysconfig/spamd:

## Path:           Network/Mail/Spamassassin
## Description:    Arguments for the spam daemon
## Type:           string
## Default:        "-d -c -L"
## ServiceRestart: spamd
# The arguments passed to spamd.
# See spamd(1) man page.
# Default is "-d -c -L"
SPAMD_ARGS="-d -c -u spamd -g spamd --socketpath=/tmp/spamd_full.sock"

We introduced a user and group called “spamd” here. You might need to configure them first on your system.

Finally, you can add according startup commands in your /etc/rc.d directory to make spamd starting at system boot. Here is a script that I use.

Part 2 of this series will concentrate on the issue how to pass each mail into SpamAssassin.

Applications Miscellaneous

Reset Firefox’ Zoom Settings

You propably got already used to Firefox’ zoom feature. Firefox 3 introduced a new setting that enables it to remember the zoom value when you visit a website. Whenever you re-visit the domain, the previously used zoom level will be re-applied.

If you don’t like this feature, open the about:config page and toggle the boolean setting browser.zoom.siteSpecific to false.

Of course, you can always use Strg-0 to reset the zoom to the default value.

CSV Java

CSV Utility Package Released

I decided recently to publish my very simple utility classes for reading and writing CSV files. The main project page is now available. The package, published under the GNU Lesser General Public License, allows you to easily integrate CSV functionality into your application. The utilities can be configured to use different column delimiter and separator characters in case you need to adopt some other versions of CSV. The default configuration conforms to the Excel style of CSV.

Since this CSV package uses streams, you are able to read from any stream. And, of course, you can write to any stream. You could even synchronize in your application by applying the reader/writer synchronization described in one of my artices.

You can download the latest stable release at the main project page.

Here is a short example on reading a CSV file using the CSVReader class: f = new"csv-test.csv");
csv.CSVReader in = new csv.CSVReader(new;
while (in.hasNext()) {
    String columns[] =;
    // Do something here

Please note that the CSVReader class actually implements the Iterator interface.

Writing a CSV file is even easier. Just create an instance of the CSVWriter class and pass it your rows: f = new"csv-test.csv");
CSVWriter out = new CSVWriter(new;
out.printRow(new String[] { "0:0", "0:1", "0:2" });
out.printRow(new String[] { "1:0", "1:1", "1:2" });


The API documentation tells you all details and configuration parameters that you can use to control the behaviour of the reader and writer classes.


Synchronizing Reader and Writer Threads

Here are two functions that you should use when you want two threads, producer and consumer, to be synchronized. I used these functions mainly to ensure that the reader will stop until an object is ready to read. An advantage is that you can control how many objects are in memory at the same time.

protected List<Object> availableObjects = new ArrayList<Object>();
 * Delivers the next object.
 * Used by the reader/consumer thread.
public synchronized Object next() {
	Object rc;
	while (availableObjects.isEmpty()) {
		try {
		} catch (InterruptedException e) { }
	rc = availableObjects.remove(0);
	return rc;
 * Adds a new object to the list of available objects.
 * Used by the writer/producer thread.
public synchronized void addObject(Object o) {
	while (availableObjects.size() >= 20) {
		try {
		} catch (InterruptedException e) {}

The main idea was taken from Silberschatz’ book about Operating Systems. You have to make sure that you never call the next() method when the last object was read. So be careful when your number of objects produced is limited.


Firefox 3 crash on Linux with Flash

Since I installed the latest Firefox version on my openSuSE 11 box, it started to crash constantly on some websites, e.g. Jon Stewarts Full Episode player or the German news channel of Tagesschau. A lot of Google research did not reveal anything useful. Some users reported advance when de-installing AdBlock. That didn’t work, though.

At some forum I read that there are conflicts with pulseaudio installation together with flashplayer. So I deinstalled all pulseaudio packages. I had to restart my Gnome Desktop Manager (gdm). But finally it worked out. All flash videos now play perfectly, Jon Stewart as well as Tagesschau.

So you might want to give that a trial.


VMWare with USB devices on Linux

VMWare Server depends on USBFS information to recognize USB devices and forward its communication to the virtual machine. OpenSuse switched off this feature by default. In order to re-enable it, you just need to make a slight change in your /etc/fstab file:

usbdevfs /proc/bus/usb usbfs auto 0 0

Usually the line already exists with noauto. Just change it as displayed above. This will mount the filesystem automatically at system start. If you don’t wanna reboot, you can mount the filesystem immediately with:

mount usbfs

PS: This will propably work on every Linux distribution. A detailed description on this topic can be found at old openSuse’s Wiki.


Firefox 3

It is finally there. You can download the browser’s latest version at Mozilla Homepage. There is also a very good introduction to the new features of Firefox 3.


Laptop Touchpad Configuration

I am usually annoyed by the tap mechanism of my Lenovo Thinkpad. Luckily, there is a solution to switch that feature off. All you need is described here:


Airline Codes

Another list from my daily work. All IATA and ICAO airline codes along with the official airline’s name can be found in this CSV list.