FreePBX に届いたメールを音声読み上げさせる その3

~メールで電話番号と日時を指定して読み上げを行う~

内線番号や外線番号を指定して、指定日時に送信するよう変更します。
ついでに、半角全角や文字コードで文字化けを起こさないような仕組みも入れていきます。
Perl のモジュールが無い場合は

# cpan -i モジュール名

で、インストールしてください。

at コマンドが無い場合は、

# yum -y install at
# service atd start

で、インストールの上サービスを起動しておいてください。

使い方
本文を

To:宛先の電話番号(内線番号)
At:指定形式での日時
本文の内容

というように書きます。To: と At: の行は省略可能で、内線番号を省略した場合は、デフォルトの内線番号へ、日時を省略した場合は直ちに通話読み上げを開始します。

日時は年/月/日 時刻:分という形式で指定します。
例:2016年5月10日13時54分に内線 SIP/1002 へ電話をかけてメールの内容を読み上げさせてい場合は、

To:SIP/1002
At:2016/05/10 13:54
メールの本文の内容

というような感じです。mailAnalyse2.pl では、内線番号を4ケタまでと想定し、4桁以下の場合の数字のみの場合は
Local と @コンテキストを付加しています。

To:1003
At:2016/05/10 13:54
メールの本文の内容

なら、コンテキストが from-internal なら、

To:Local/1002@from-internal
At:2016/05/10 13:54
メールの本文の内容

に変換されます。

mailAnalyse.pl の変更

#!/usr/bin/perl

use utf8;
binmode STDIN, ":utf8";
binmode STDOUT, ":utf8";
use File::Basename;
use MIME::Parser;
use Encode;
my $parser = MIME::Parser->new;
my $LogData = "";

#デフォルトの送信先
my $exten = 'Local/1001\@from-internal';
#デフォルトの送信時間
my $SendAt = 'now';

#ファイルの一時保存場所を指定
$parser->output_dir('/tmp');

#標準入力からメールを取得
my $entity = $parser->parse(*STDIN);

#FromとSubjectのみ取り出し
my $from = $entity->head->decode->get('From');
my $subject = $entity->head->decode->get('subject');
my $body = $entity->is_multipart ? $entity->parts(0) : $entity;
my $bodyHandle = $body->bodyhandle;
my $lines = $bodyHandle->as_string;

# use utf8; をいれると化けるときがあり、再度 UTF-8 にデコード
$from = encode("euc-jp", decode("MIME-Header", $entity->head->decode->get('From')) );
$subject = Encode::decode('utf8', $subject);
$lines = Encode::decode('utf8', $lines);

my $TextHead1 = "こんにちは。これは自動メッセージからの通話です。メッセージが届いております。";

$LogData .= "\n\n --------------- new mail ---------------- \n";
$LogData .= "From : $from\n";
$LogData .= "Subject : $subject\n";
$LogData .= "Body : $lines\n";

# 送信元の 名前<アドレス> に、非常に簡単に対応
$from =~ s/<.*//;
$from =~ s/.*>//;
# 日本語で読むように置き換え
$from =~ s/gmail/ジーメール/;
$from =~ s/.com/ドットコム/;
$from =~ s/sip/シップ/;

$LogData .= "mailAnalyse1 Process Mail From $from\n";
my $BodyLength = length($body);

if (length($body) > 3) {
my @strline = split(/\n/, $lines,2);
my $AnalyseLine = $strline[0];
# 全角で入力してある場合対策
$AnalyseLine =~ tr/0-9A-Za-z:/0-9A-Za-z:/;
$AnalyseLine =~ s/to:/To:/i;
my $wardindex = index($AnalyseLine,"To:");
my $LineAtom = "";
if (length($strline[0]) > 3) {
$LineAtom = substr($strline[0],3);
}
if ($wardindex < 0) {
$wardindex = index($AnalyseLine,"To:");
if (length($strline[0]) > 4) {
$LineAtom = substr($strline[0],4);
$LineAtom =~ s/[[:cntrl:]]//g;
}
}
if ($wardindex == 0 && length($lines) > 3) {
$lines = $strline[1];
$exten = $LineAtom;
$LogData .= "Finded exten is $exten.\n";
@strline = split(/\n/, $lines,2);
$AnalyseLine = $strline[0];
# 全角で入力してある場合対策
$AnalyseLine =~ tr/0-9A-Za-z:/0-9A-Za-z:/;
$AnalyseLine =~ s/at:/At:/i;
$wardindex = index($AnalyseLine,"At:");
$LineAtom = "";
$LineAtom = "";
if (length($strline[0]) > 3) {
$LineAtom = substr($strline[0],3);
}
if ($wardindex < 0) {
$wardindex = index($AnalyseLine,"At:");
if (length($strline[0]) > 4) {
$LineAtom = substr($strline[0],4);
# 制御文字が入っている場合の対策
$LineAtom =~ s/[[:cntrl:]]//g;
}
}
$LogData .= "At index is $wardindex.\n";
if ($wardindex == 0) {
$SendAt = $LineAtom;
$LogData .= "Finded send time is $SendAt.\n";
$lines = $strline[1];
}
}
}

# 音声で聞き取れるように変換
$lines =~ s/sip/シップ/;

my $TextRead = $TextHead1;
$TextRead = $TextRead . "メッセージの送信元は、$from です。";
$TextRead = $TextRead . "メッセージの題名は、$subject です。";
$TextRead = $TextRead . "メッセージの内容を読み上げます。$lines";
$TextRead = $TextRead . "以上です。通話を終了します。";

#改行を削除
$TextRead =~ s/\r//;
$TextRead =~ s/\n//;
# ファイルを作成
open(DAT,">>/tmp/mail.dat");
print DAT "To:$exten\n";
print DAT "At:$SendAt\n";
print DAT "$TextRead";
close(DAT);

$LogData .= "Create mail.dat.\n";
$LogData .= "To $exten.\n";
$LogData .= "At $SendAt.\n";
$LogData .= "Body : $TextRead\n";
open(OUT,">> /tmp/mail.log") or die "$!";
print OUT "$LogData";
close(OUT);

sleep 2;

system("cp /tmp/mail.dat /tmp/mail/mail.dat");

mailAnalyse2.pl の変更

#!/usr/bin/perl

# デフォルト(省略時)の内線番号
my $exten = 'SIP/1001';
# 省略時はすぐかける
my $SendAt = 'now';
my @data;
my $LogData = "";

open(IN,"/tmp/mail/mail.dat");
@data = <IN>;
close(IN);

if (@data > 2){
my $wardindex1 = index($data[0],"To:");
my $wardindex2 = index($data[0],"At:");
if ($wardindex1 == 0) {
$exten = $data[0];
$data[0] = '';
$wardindex2 = index($data[1],"At:");
if ($wardindex2 == 0) {
$SendAt = $data[1];
$data[1] = '';
}
} else {
if ($wardindex2 == 0) {
$SendAt = $data[0];
$data[0] = '';
$wardindex1 = index($data[2],"At:");
if ($wardindex1 == 0) {
$exten = $data[1];
$data[1] = '';
}
}
}
}

open(OUT,">> /tmp/mail.log") or die "$!";
print OUT "Get Exten $exten\n";
print OUT "Get Send Date $SendAt\n";
close(OUT);

$exten =~ s/\r//;
$exten =~ s/\n//;
$exten =~ s/To://;
$SendAt =~ s/\r//;
$SendAt =~ s/\n//;
$SendAt =~ s/At://;
$SendAt =~ s/Now//;

# 電話をかける先の指定で日本語を使いたい場合は
$exten =~ s/日本語/外線先のTrunkと電話番号/;
とか、(To:日本語 でよくなる)
$exten =~ s/日本語での通話先/内線番号;
とか書いておきます。この時「/」を「\/」と書いてください。

my $ExtenNum = $exten;
$ExtenNum =~ s/\-//;
my $isnum = $ExtenNum;
$isnum =~ s/[0-9]+//;
if (length($exten > 0) && length($isnum) == 0) {
# 内線番号が2ケタの場合は短縮として
if ($ExtenNum < 100) {
$exten = "Local/" . $exten . "\@from-internal";
# 内線番号が3ケタの場合はIAX2でつながった別サーバーへ
}elsif ($ExtenNum < 7000) {
$exten = "IAX2/トランク名/" . $exten;
# 内線番号が4ケタの場合は内線番号として
}elsif ($ExtenNum < 10000) {
$exten = "Local/" . $exten . "\@from-internal";
# 内線番号がそれ以外の場合は外線番号として
}else{
# 外線と SIP でつながっている場合
$exten = "SIP/外線トランク名/" . $ExtenNum;
}
}

$LogData .= "Trans Exten $exten\n";

# 本文に制御文字や改行が入っていると正常に音声に変換されないので除去
my $MailBody = '';
foreach $lines (@data) {
my $tmp = $lines;
$tmp =~ s/[[:cntrl:]]//g;
$MailBody .= $tmp;
}

$LogData .= "--- MailBody Start --\n";
$LogData .= "$MailBody\n";
$LogData .= "--- MailBody End ---\n";

# 音声ファイル作成
system("/usr/local/bin/open_jtalk -m /var/lib/open_jtalk/nitech_jp_atr503_m001.htsvoice -x /usr/local/dic -ow /tmp/mail.tmp.wav /tmp/mail/mail.dat");
# 8000hz モノラルに変換
system("/usr/local/ffmpeg_build/bin/ffmpeg -i /tmp/mail.tmp.wav -ac 1 -ar 8000 -y /tmp/mail.wav");
# ゴミ掃除
system("rm -f /tmp/mail.tmp.wav");
system("rm -f /tmp/mail/mail.dat");
system("rm -f /tmp/mail.dat");
system("chmod a+rw $FileName.call");
my $FileName = "/tmp/mail";
if ($SendAt == 'now'){
$LogData .= "mailAnalyse3 $exten /tmp/mail\n";
# /var/spool/asterisk/outgoing 用のテキストファイル作成
open(OUT,"> $FileName.call") or die "$!";
print OUT "#\n";
print OUT "Channel: $exten\n";
print OUT "MaxRetries: 3\n";
print OUT "RetryTime: 60\n";
print OUT "WaitTime: 30\n";
print OUT "Application: Playback\n";
print OUT "Data: ../../../..$FileName\n";
close(OUT);
system("chmod a+rw $FileName.call");
$LogData .= "Create $FileName.call";
system("mv $FileName.call /var/spool/asterisk/outgoing/");
} else {
my $SendAtTmp = $SendAt;
$SendAtTmp =~ s/[\/ :]/,/g;
my @SendDateTime = split(/,/, $SendAtTmp);
if ($#SendDateTime == 4) {
my $SendDate = "$SendDateTime[0]" . "_" . $SendDateTime[1] . "_" . $SendDateTime[2];
my $SendTime = $SendDateTime[3] . "_" . $SendDateTime[4];
$FileName = "/tmp/mail.$SendDate.$SendTime";
$LogData .= "FileName is $FileName\n";
$SendDate =~ s/\_/./g;
$SendTime =~ s/\_/:/g;
my $atDateTime = $SendTime . " " . $SendDateTime[2] . "." . $SendDateTime[1] . "." . substr($SendDateTime[0], 2);
$LogData .= "SendDate is $SendDate\n";
$LogData .= "SendTime is $SendTime\n";
# wav ファイルを日時のついた名前に変更
system("mv /tmp/mail.wav $FileName.wav");
# /var/spool/asterisk/outgoing 用のテキストファイル作成
open(OUT,"> $FileName.call") or die "$!";
print OUT "#\n";
print OUT "Channel: $exten\n";
print OUT "MaxRetries: 3\n";
print OUT "RetryTime: 60\n";
print OUT "WaitTime: 30\n";
print OUT "Application: Playback\n";
print OUT "Data: ../../../..$FileName\n";
close(OUT);
$LogData .= "Create AuTo Exec Task\n";
$LogData .= "echo \"mv $FileName.call /var/spool/asterisk/outgoing/\" | at \"$atDateTime\"\n\n";
system("chmod a+rw $FileName.call");
# at コマンドでファイルの移動をキューに入れる
system("echo \"mv $FileName.call /var/spool/asterisk/outgoing/\" | at \"$atDateTime\"");
}
}

open(OUT,">> /tmp/mail.log") or die "$!";
print OUT "$LogData\n";
close(OUT);

コメントを残す