messy Perl code

I download my mail using fetchmail. During the process, “tail -f” shows the subjects of the incoming letters. Unfortunately, most of them are unreadable, something like “=?windows-1251?B?0e/g7CDt4CBwaHBCQg==?=“. Finally, I tired of it and decided to make life better.

I don’t remember when I wrote such a bad code last time. Copy/paste from different sources plus fast hacks, but it works. Comments after the code.

#!/usr/bin/perl -w
use strict;

require MIME::Base64;
MIME::Base64->import('decode_base64');
require MIME::QuotedPrint;
MIME::QuotedPrint->import('decode_qp');
use Encode;

#seek STDIN, -400, 2;

while (1) {
  if (eof()) {
    sleep(1);
  } else {
    while (defined (my $l = <>)) {
      chomp($l);
      $l = decode_string($l);
      print "$l\n";
    }
  }
}

sub decode_string {
  my $line = shift;
  if ($line =~ m/=\?/) {
    if ($line !~ m/\?=$/) {
      $line = $line . '77?=';
    }
  }
  while ($line =~ m/=\?([^?]+)\?(.)\?([^?]*)(\?=)?/) {
    my $enc        = $1;
    my $encoding   = $2;
    my $txt        = $3;
    my $str_before = $`;
    my $str_after  = $';

    #print "[$txt]\n";
    #print "[$enc]\n";
    # Base64
    if ($encoding =~ /b/i)
    {
      my $l = int(length($txt) / 4);
      if (4 * $l != length($txt)) {
        $txt = substr($txt, 0, 4*$l);
      }
      eval {
        $txt = decode_base64($txt);
      }
    }

    # QP
    elsif ($encoding =~ /q/i)
    {
      $txt = decode_qp($txt);
    }

    Encode::from_to($txt, $enc, 'koi8-r');

    $line = $str_before . $txt . $str_after;
  }
  ## The decode above does not do underline-to-space translation:
  #$line =~ tr/_/ /;
  #$transheaders .= $line . "\n";
  return $line;
}

The commented-out seek doesn’t work for me. I decided not to investigate why. Instead of

tail.pl log_file

I now use

tail -f log_file | tail.pl

The main loop is stolen from Perl FAQ (“How do I do a ‘tail -f’ in Perl?”).

The original source of “decode_string” is lost somewhere in Internet. I don’t remember where I found it. There are few improvements over the orignial.

First, I remember the character encoding of the subject.

Second, fetchmail cuts the length of the subject string, therefore sometimes base64 data is incomplete. I have to adjust the length of the data to make the base64 decoder happy.

Finally, the subject is converted to my console encoding.

The code, surprisingly, works, and I’m glad now.

Leave a Reply