[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: получить текст письма в скрипте



Иван Лох wrote:
On Thu, May 27, 2010 at 12:13:38PM +0400, Ed wrote:
собрался поднять шлюз email2sms на smstools.

проблема в том, что письмо может быть сформировано по-разному:
разный charset (для русскоязычных - koi8-r, utf8, ...), разный
encoding (8bit, base64, ...), может multipart MIME попасться...

то есть нужен фильтр - на входе письмо, на выходе - текст из него в
требуемой кодировке.
есть что-либо стандартное? (или может быть на перле можно в
несколько строк уложится?)

Ну да. libmime-tools-perl

ещё раз спасибо за пример.

вот что у меня получилось в итоге (в несколько строк правда не уложился):

#!/usr/bin/perl -w

### Maximal SMS body size in bytes, must be even for UCS-2
### remember - SHORT Message Service
my $maxsmssize = 1024;

### Default directories
our $spool_dir = '/var/spool/sms/outgoing/';
our $tmp_dir = '/tmp/';

sub usage {
die <<EOF;
E-mail to SMS converter with non-latin charsets suppport

Usage:
   $0 -n number [-s spool_dir] [-t tmp_dir] [-d] < email-file
       -n number     phone number in international format
       -s spool_dir  outgoing spool directory
                     default: $spool_dir
       -t tmp_dir    temporary directory
                     default: $tmp_dir
       -d            dry-run (do not spool message)

Designed to be used with smstools (http://smstools3.kekekasvi.com)

WARNING! Large e-mail messages can cause DoS.
Limit the size of messages on the mail server.

EOF
}

use MIME::Parser;
use Encode qw/resolve_alias encode decode/;
use Getopt::Std;
use File::Temp qw/ tempfile tempdir /;
use File::Copy;

my  $default_charset = 'ascii';

my %options;
getopts( 'n:ds:t:' , \%options );

unless ( defined  $options{n} ) {
   usage();
}

my $to = $options{n};
my $dry = $options{d};
$spool_dir = ( $options{s} or $spool_dir );
$tmp_dir = ( $options{t} or $tmp_dir );
my $tmpfilename;

my $tfh;
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
$mon++;
$year -= 100; # sorry

umask 0113;

($tfh, $tmpfilename) = tempfile(
sprintf("SMS-%02d.%02d.%02d-%02d:%02d:%02d-XXXX", $year, $mon, $mday, $hour, $min, $sec),
                               DIR => $tmp_dir);

open TMP, ">&=", $tfh;

$to =~ s/[ -\.\(\)]//g; # (987)654-32-10 -> 9876543210
$to =~ s/^\+?(\d*)$/$1/ or die "Bad number '$options{n}'?\n";

### Short numbers must be prefixed with 's' char
if ( length($to)<5 ) {
   $to = 's' . $to;
}

print TMP "To: $to\n";

### Create parser, and set some parsing options:
my $parser = new MIME::Parser;

### SMS will be very small
#$parser->output_under("/tmp");
$parser->output_to_core(1);
$parser->tmp_to_core(1);

my $entity = $parser->parse(\*STDIN) or die "parse failed\n";

my $main_ent=$entity;

if (my $num_parts = $entity -> parts()){
   for my $i (1..$num_parts){
       my $e=$entity->parts($i-1);
       if($e->head()->mime_attr('content-type') eq 'text/plain'){
           $main_ent=$e;
           last;
       }
   }
}

my $charset = ( $main_ent->head()->mime_attr('content-type.charset')
               or $default_charset );
$charset = ( resolve_alias($charset) or $default_charset );

my $u8 = decode($charset, $main_ent->bodyhandle->as_string);
my $ascii = encode("ascii", $u8);
my $smsbody;

if ($u8 eq $ascii) {
   $smsbody = $ascii;
} else {
   print TMP "Alphabet: UCS\n";
   $smsbody = encode('ucs-2be',$u8);
}

if (length($smsbody) > $maxsmssize) {
print STDERR "too large message $tmpfilename, truncated to $maxsmssize bytes\n";
   $smsbody = substr($smsbody, 0, $maxsmssize);
}
print TMP "\n",$smsbody;

close TMP;

if ($dry) {
   print "SMS saved to $tmpfilename\n";
} else {
move $tmpfilename, $spool_dir or die "moving $tmpfilename to $spool_dir failed\n";
}


Reply to: