#!/usr/local/bin/perl -w use strict; use DBI; use DBD::mysql; use Getopt::Std; use Cwd 'abs_path'; use vars qw/ $opt_s $opt_m /; # This script takes a voicemail in email message # and inserts the voicedata in mp3 format, together # with some metadata in a database # put this script in your bin directory # or any directory in your $PATH # # run once with -s parameter to setup # your sql tables and .procmailrc file # # how should we connect to the database? my ( @dbi_credentials) = ("DBI:mysql:Databasename", "username", "password"); # mysql table to put voicemails in my ( $table ) = "voicemail"; # location of your voicemailscript, used to send message my ( $url ) = "http://www.somehost.nl/voicemail/"; # mimedecode program my ( $decodeProg ) = "/usr/local/bin/mimencode -u"; # e.g. `which mimencode` . " -u" # encoder program my ( $toMp3Prog ) = "lame -h -m mono -"; # notify these emailadresses, separate with space. Can be empty my ( $emails ) = "username\@localhost"; # # # # global vars my ( $thisScript ) = abs_path( $0 ); ## main; do different things according to commandline options getopt(); if ( defined( $opt_s ) ) { setup_environment(); } else { if ( defined( $opt_m ) ) { parse_and_insert_message(); } else { print < creates sql tables, assures .procmailrc is setup right -m or --message -> inserts the voicemail mail on STDIN in database EOT } } exit 0; # end main # insert PROCMAIL rule in .procmailrc sub setup_environment { my ( $VOICEMAILPROGRAM ) = $thisScript; if ( `grep VoiceMailinEmail $ENV{HOME}/.procmailrc 2>/dev/null` ) { print "[ok] already stated in .procmailrc\n"; } else { print "-- inserting in .procmailrc\n"; open (F, ">> $ENV{HOME}/.procmailrc" ) || die("could not open .procmailrc ($!)"); print F <connect(@dbi_credentials) or die( "Can not connect: $dbh->errstr\n" ); # check if table exists my($sth); $sth = $dbh->prepare($test) or die( "Can not prepare statement: $dbh->errstr\n" ); $sth->execute() and $done=1; # table exists $sth->finish(); # if table doesn't exist: create it if ( $done < 1 ) { $sth = $dbh->prepare($statement) or die( "Can not prepare statement: $dbh->errstr\n" ); $sth->execute() or die "Can't execute $statement:" . $dbh->errstr . "\n"; print "[ok] created table\n"; } else { print "[ok] table exists\n"; } $dbh->disconnect(); } # read stdin and extract relevant info from message sub parse_and_insert_message { my ( $boundary ); # mime message boundary my ( $date, $time, $seconds, $sender ); # my ( $file ); # file containing encoded message ## first: search for mime message boundary $boundary = search_mime_message_boundary(); ## boundary is set, first boundary is found ## search for date and length in message text ($date, $time, $seconds, $sender ) = search_date_and_length( $boundary ); ## message is scanned, boundary is found, new part begins ### skip till empty line skip_till_empty_line(); ### from now, data till boundary is wav data... ### convert uuencoded wav data to mp3 $file = make_mp3( $boundary, $time ); ### insert $file into database insert_into_database( $date, $time, $seconds, $sender, $file ); send_mail( $date, $time, $seconds ); } # insert encoded file into database sub insert_into_database { my ($date, $time, $seconds, $sender, $file ) = @_; my ($statement); $statement = "INSERT INTO $table SET \ data=?, \ ontvangen_op='$date $time', \ afzender=?, \ length=$seconds, \ datatype='mp3'"; my($dbh); $dbh = DBI->connect(@dbi_credentials) or die( "Can not connect: $dbh->errstr\n" ); my($sth); $sth = $dbh->prepare($statement) or die( "Can not prepare statement: $dbh->errstr\n" ); my($data); open (F, "< $file"); read F, $data, 1000000; close(F); my($rv); $rv = $sth->execute($data, $sender) or die "Can't execute $statement:" . $dbh->errstr . "\n"; $dbh->disconnect(); } # notifies email adresses of new message sub send_mail { my ( $date, $time, $seconds ) = @_; # don't mail if no emailadresses specified if ( length( $emails ) == 0 ) { return; } open (F, "| /bin/mail -s 'voicemailbericht $date - $time' $emails" ) or die ( "can not open mail" ); print F "Hallo,\n\n"; print F "Er is een nieuw voicemailbericht,\n"; print F "ingesproken op $date - $time.\n\n"; print F "Het bericht duurt $seconds seconden en staat op\n"; print F "$url\n\n"; close(F) or die ( "command not succesfully executed" ); } # searches for mime message boundary identifier sub search_mime_message_boundary { my ( $boundary ) = "___XXX___XXX"; my ( $done ) = 0; while ( <> ) { if ( $_ =~ /^Content-Type:.*boundary=\"(.*?)\"/ ) { $boundary = $1; $done++; } else { last if /${boundary}/; } } die( "Content type not found..." ) unless $done; return $boundary; } # parses various attributes from message sub search_date_and_length { my ( $date, $time, $seconds, $sender ); my ( $done ) = 0; my ( $boundary ) = shift; $sender = "unknown"; while ( <> ) { if ( $_ =~ /^U heeft een Voice Mail ontvangen (.*?)op (\d{2}\/\d{2}\/\d{4}) om (\d{2}:\d{2}:\d{2})\./ ) { my (@date) = split (/\//, $2); $date="$date[2]-$date[1]-$date[0]"; $time = $3; $done++; if ( $1 =~ /^van (.+)/ ) { $sender = $1; } } if ( $_ =~ /Het bericht heeft een lengte van (\d+) seconden\./ ) { $seconds = $1; $done++; } last if /${boundary}/; } die( "Message unparseble" ) unless ( $done == 2 ); return ($date, $time, $seconds, $sender); } # read stdin until emptyline sub skip_till_empty_line { while ( <> ) { if ( /^\s*$/ ) { return; } } die( "Message unparseble" ); } # create encoded file, second argument is some unique making file identifier sub make_mp3 { my ( $boundary ) = shift; my ( $f ) = shift; my ( $tmpdir ) = "/tmp/$ENV{USER}"; my ( $file ); if ( ! -d "$tmpdir" ) { mkdir ( "$tmpdir", 0700 ); } $file = "/$tmpdir/mesg${f}.mp3"; open (F, "| $decodeProg | $toMp3Prog $file 2>/dev/null" ) or die( "could not open $decodeProg or $toMp3Prog" ); while ( <> ) { last if ( /${boundary}/ ); print F $_; } return $file; }