« 2010年8月 | トップページ | 2011年3月 »

2011年1月

留守中に着信した電話の番号をメールするプログラム

外出中に電話がかかって来たときに、かかってきた番号を携帯にメールするプログラムを作った。 ↓こんな感じでメールがくる

     差出人:     root@example.jp
     件名:    留守中電話
     日時:    2011年1月5日 12:15:56JST
     宛先:    xxx@example.jp

     1月4日(火) 13:35に 0311111111 から
     電話がありました。

我が家の特殊な環境を前提にしているのでどこでも使える訳ではないと思うけど、備忘録もかねてまとめときます。

環境

我が家ではBフレッツ マンションタイプと@niftyフォンのIP電話を契約している。NTT東のWeb Caster V110がルータ兼SIPサーバー(IP電話サーバー)になっていて、WebベースでIP電話の通話記録を確認できるようになっている。

今回のプログラムはDebianで動いている常設サーバーからSIPサーバーに定期的に通話記録を読みにいって、追加の不在着信があればメールするというもの。

Web Caster V110の通話記録

Web Caster V110の通話記録のhtmlソースを見ると次のようになっている。

   (中略)
    < td colspan="2"> 通話ログ< /td> 
    < /tr> < /tbody> < /table> 
    < pre> CALL.LOG : There are 100 entries.

  1. Tue Jan  4 14:19:42 2011  Tue Jan  4 14:19:47 2011  Tue Jan  4 14:36:12 2011
     09011111111                                      VoIP TRM GW 016 000 
     0311111111                                       221.000.000.13 G711ulaw
             15/         3/        12      49000/         3          0
              3          3          0          0          0          0
  2. Tue Jan  4 13:35:22 2011  **********                Tue Jan  4 13:36:37 2011
     09011111111                                      VoIP TRM NW 016 000 
     0311111111                                       0.0.0.0 G711ulaw
              0/         0/         0          0/         0          0
              0          0          0          0          0          0
 (中略)

定型のヘッダの後にいつ誰からかかってきて、いつ電話をとって、いつ切ったかが記録されているが、通話を受けられなかった場合(不在着信の場合)は「」として表示される。 作成したプログラムではこのコメ印を含むエントリを検出して、このエントリの日付と発信者番号を抜き出しメールで送るという動作をする。

プログラム

このファイルを「rusu.pl」のような名前で保存し、ファイル中の「設定欄」の内容を環境に合わせて編集し、/etc/cron.hourlyに入れて、実行環境を与えてください。 ファイルはUTF-8で保存してください。

プログラム本文はこちら。


#!/usr/bin/perl
use strict;
use Net::POP3;
use LWP::UserAgent;
use HTTP::Request::Common;
use Net::SMTP;
use MIME::Base64;

#
# 使い方
# 1) 下の設定欄を環境に合わせて変更する
# 2) このファイルを/etc/cron.hourlyなどに移動する
# 3) 実行権限を与える
#
# このプログラムはUTF-8で保存してください
#

#
# 設定欄
#

# このスクリプトが最後に動作した日時を記録するログファイル
my $logfile="/tmp/rusu.log";

# SIPサーバー用設定
my $address="192.168.1.1";
my $port=80;
my $realm="Web Caster V110";
my $user="admin";
my $passwd="xxxxxxx";
my $url="http://".$address."/cgi-bin/mainte.cgi?st_clog";

# POP before SMTP用設定
# (POP before SMTPでない場合は$pop_before_smtpを0に
my $pop_before_smtp=1;
my $pop_server='pop.example.jp';
my $pop_uid='username';
my $pop_pw='password';

# SMTPサーバー用設定
my $smtp_server='smtp.example.jp';
my $smtp_port='587';

# 留守メール用設定
# @マークの前にはバックスラッシュが必要
my $to="mymobileaddr\@example.jp";
my $from="root\@example.jp";
my $subject="留守中電話";

#
# 以下プログラム部分
#
my %monthes = qw(Jan 1 Feb 2 Mar 3 Apr 4 May 5 Jun 6 Jul 7 Aug 8 Sep 9 Oct 10 Nov 11 Dec 12);
my %days = qw(Mon 月 Tue 火 Wed 水 Thu 木 Fri 金 Sat 土 Sun 日);

# このプログラムが最後に動作した日時を確認する
open LOGFILE, "< $logfile";
my $lastaccessed=< LOGFILE> ;
# print "last: $lastaccessed\n";
close LOGFILE;


# SIPサーバーから通話記録を取得する
my $browser = LWP::UserAgent-> new;
$browser-> credentials(
    "$domain:$port",$realm,$user,$passwd);
my @lines = split m{\n}, $browser-> get($url)-> content;

# 取得したhtmlファイルから一行を切り出す関数
my $linenum=0;
sub getNextLine{
#    print "$linenum:   $lines[$linenum]\n";
    if ($linenum <  @lines){
        $linenum +=1;
        return $lines[$linenum-1];
    }else{
        return -1;
    }
}

# 通話記録部分まで読み飛ばす
while((my $buf=getNextLine())!=-1){
    if($buf =~ /LOG/){
        last;
    }
}
getNextLine();

my $text='';

while((my $buf=getNextLine())!=-1){
    my @item = split (/ +|:/, $buf);

    # 呼が失敗した記録が見つかった場合
    if($item[9]=~/\*\*\*/ 
       # かつログに残されたこのプログラムが最後に動作した
       # 日付より新しい場合
       and  (sprintf "%4d%.2d%.2d%.2d%.2d%.2d",$item[8]
            , $monthes{$item[3]}, $item[4], $item[5], $item[6], $item[7])
         >  $lastaccessed){

        # 着信が失敗している場合
        $buf=getNextLine();
        if($buf =~ /TRM/){
            $text .= $monthes{$item[3]}."月".$item[4]."日\("
                    .$days{$item[2]}."\) "
                    .$item[5].":".$item[6]."に ";
            $buf=getNextLine();
            my @item = split (/ +/, $buf);
            $text .= $item[1]." から\n";
        }else{
            getNextLine();
        }
        getNextLine();getNextLine();
    }else{
        getNextLine();getNextLine();getNextLine();getNextLine();
    }
}

# メールで送信
& send($text);

# ログファイルに現在の時刻を上書き
open LOGFILE, "> $logfile";
(my $sec,my $min,my $hour,my $mday,my $mon,my $year,my $wno) = localtime(time);
print LOGFILE sprintf("%4d%.2d%.2d%.2d%.2d%.2d"
    ,$year+1900,$mon+1,$mday,$hour,$min,$sec);
close LOGFILE;

# 引数で与えられた文字列をメールの本文として、
# 上の設定欄で与えられた環境に基づき送信する関数
sub send{
    my $body=$_[0];

    if($body ne ''){
        # POP before SMTPのためのPOPサーバーへのログイン
        if($pop_before_smtp==1){
            my $pop = Net::POP3-> new($pop_server);
            if($pop-> login($pop_uid, $pop_pw) > = 0) {
                $pop-> quit; 
            }else{
                die "cannot login to pop3 server.\n"; 
            }
        }

        # SMTP送信
        my $smtp = Net::SMTP-> new($smtp_server
                    , Hello=> $smtp_server, Port=> $smtp_port)
                    or die 'cannot connect to smtp server.\n';
        $smtp-> mail($from);
        $smtp-> to($to);
        $smtp-> data();
        $smtp-> datasend("MIME-Version: 1.0\n");
        $smtp-> datasend("Content-Transfer-Encoding: base64\n");
        $smtp-> datasend("Content-Type: text/plain;charset=utf-8\n");
        $smtp-> datasend("From:$from\n");
        $smtp-> datasend("To:$to\n");
        $smtp-> datasend("Subject:=?utf-8?B?" 
                . encode_base64($subject,'') . "?=\n");
        $smtp-> datasend("\n");
        $smtp-> datasend(encode_base64($body)."\n");
        $smtp-> dataend();
        $smtp-> quit;

    }
}

| | コメント (0) | トラックバック (0)

« 2010年8月 | トップページ | 2011年3月 »