У DSPAM’а есть одна неприятная особенность. На странице “история” вместо темы письма в некоторых случаях отображаются кракозябры. Происходит это потому, что письма приходят в разных кодировках и информация из них заносится в логи как есть, без перекодировок. dspam.cgi же в свою очередь просто берет информацию из лога и выводит тоже как есть. Сегодня меня эта особенность достала окончательно и я решил научить dspam.cgi определять кодировку и перекодировать строки. Результат выкладываю. Оранжевым для наглядности выделены добавленные или измененные строки.

Нам потребуется perl’овый модуль Lingua::DetectCyrillic. Инсталлируем:

# cpan Lingua::DetectCyrillic

Теперь редактируем dspam.cgi.

Находим:

use strict;
use Time::Local;
use vars qw { %CONFIG %DATA %FORM $MAILBOX $CURRENT_USER $USER $TMPFILE};
use vars qw { $CURRENT_STORE };
require "ctime.pl";

Заменяем на:

use strict;
use Time::Local;
use Lingua::DetectCyrillic qw ( &TranslateCyr &toLowerCyr &toUpperCyr );
use vars qw { %CONFIG %DATA %FORM $MAILBOX $CURRENT_USER $USER $TMPFILE};
use vars qw { $CURRENT_STORE };
require "ctime.pl";

Находим:

my($path) = "$USER.frag/$signature.frag";
if (-e $path) {
my(%pairs);
$pairs{'template'} = "fragment";
$pairs{'signatureID'} = $signature;
my($sub) = $subject;
$sub =~ s/#//g;
$sub =~ s/(['])/\$1/g;
$pairs{'subject'} = $sub;
$pairs{'from'} = $from;
$pairs{'info'} = $info;
$pairs{'time'} = $ctime;
$pairs{'user'} = $FORM{'user'};
my($url) = &SafeVars(%pairs);
$from = qq!<a href="javascript:openwin(580,400,1,'$CONFIG{'ME'}?$url')">$from</a>!;
}
my($entry) = <<_END;

<tr>
<td class="$cl $rowclass" nowrap="true"><small>$cllabel</td>
<td class="$rowclass" nowrap="true"><small>
<input name="msgid$retrain_checked_msg_no" type="checkbox" value="$rclass:$signature">
$retrain</td>
<td class="$rowclass" nowrap="true"><small>$ctime</td>
<td class="$rowclass" nowrap="true"><small>$from</td>
<td class="$rowclass" nowrap="true"><small>$subject</td>
<td class="$rowclass" nowrap="true"><small>$info</td>
</tr>

Заменяем на:

my($path) = "$USER.frag/$signature.frag";
if (-e $path) {
my(%pairs);
$pairs{'template'} = "fragment";
$pairs{'signatureID'} = $signature;
my($sub) = $subject;
$sub =~ s/#//g;
$sub =~ s/(['])/\$1/g;
$pairs{'subject'} = $sub;
$pairs{'from'} = $from;
$pairs{'info'} = $info;
$pairs{'time'} = $ctime;
$pairs{'user'} = $FORM{'user'};
my($url) = &SafeVars(%pairs);
$from = qq!<a href="javascript:openwin(580,400,1,'$CONFIG{'ME'}?$url')">$from</a>!;
}

# Add еncoding detection and convertion
my %PREFS;
my $to_charset;
my $subj_decoded;
my $from_decoded;
%PREFS = GetPrefs();
$to_charset = $PREFS{'webCharset'};
my $CyrDetector = Lingua::DetectCyrillic ->new();
my ($Coding,$Language,$CharsProcessed,$Algorithm)= $CyrDetector -> Detect( $subject );
my $subj_decoded=TranslateCyr($Coding,$to_charset,$subject);
my ($Coding,$Language,$CharsProcessed,$Algorithm)= $CyrDetector -> Detect( $from );
my $from_decoded=TranslateCyr($Coding,$to_charset,$from);
my($entry) = <<_END;
<tr>
<td class="$cl $rowclass" nowrap="true"><small>$cllabel</td>
<td class="$rowclass" nowrap="true"><small>
<input name="msgid$retrain_checked_msg_no" type="checkbox" value="$rclass:$signature">
$retrain</td>
<td class="$rowclass" nowrap="true"><small>$ctime</td>
<td class="$rowclass" nowrap="true"><small>$from_decoded</td>
<td class="$rowclass" nowrap="true"><small>$subj_decoded</td>
<td class="$rowclass" nowrap="true"><small>$info</td>
</tr>

Теперь в файл default.prefs добавляем параметр webCharset и указываем в какой кодировке мы хотим получать текст на странице (например webCharset=win). Допустимые значения: win, koi, koi8u, mac, iso, dos, utf.

diff’ы:

dspam.cgi:

# diff dspam.cgi.bak dspam.cgi
22a23
> use Lingua::DetectCyrillic qw ( &TranslateCyr &toLowerCyr &toUpperCyr );
408a410,421
> # Added by woland. Encoding detection patch
> my %PREFS;
> my $to_charset;
> my $subj_decoded;
> my $from_decoded;
> %PREFS = GetPrefs();
> $to_charset = $PREFS{‘webCharset’};
> my $CyrDetector = Lingua::DetectCyrillic ->new();
> my ($Coding,$Language,$CharsProcessed,$Algorithm)= $CyrDetector -> Detect( $subject );
> my $subj_decoded=TranslateCyr($Coding,$to_charset,$subject);
> my ($Coding,$Language,$CharsProcessed,$Algorithm)= $CyrDetector -> Detect( $from );
> my $from_decoded=TranslateCyr($Coding,$to_charset,$from);
417,418c430,431
< <td class=”$rowclass” nowrap=”true”><small>$from</td>
< <td class=”$rowclass” nowrap=”true”><small>$subject</td>

> <td class=”$rowclass” nowrap=”true”><small>$from_decoded</td>
> <td class=”$rowclass” nowrap=”true”><small>$subj_decoded</td>

default.prefs:

# diff default.prefs.bak default.prefs
8a9
> webCharset=koi



Дополнительные записи: