#!/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;
}