<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">#!/usr/bin/perl
#------------------------------------------------------------------------------
# /var/motion/motionmail.pl - create image montage and send it to e-mail address(es)
#
# Copyright (c) 2005-2010 Taco Scheltema, taco(at)scheltema(dot)org
# Copyright (c)      2011 The Eisfair Team, team(at)eisfair(dot)org
#
# Creation:     2005-09-01 Taco Scheltema
# Last Update:  $Id$
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version..
#------------------------------------------------------------------------------
# This script will create a montage from a collection of images and send it
# to a list of users defined in $start_path/motionmail.conf. The script is
# typically called from motion, the  motion detection software for linux:
# (http://www.lavrsen.dk/twiki/bin/view/Motion/WebHome)
#
# As a pre-requisite the following eisfair packages need to be installed:
#
# perl, perl_addons_01, imagemagick
#
# Usually the following entry need to be added to the motion package
# configuration:
#
# MOTION_DEF_ON_EVENTEND='motionmail.pl -p "%Y/%m/%d/%H/%M" -e %v -q'
#------------------------------------------------------------------------------

use File::Basename;
use Getopt::Long;
use Pod::Usage;
use Sys::Hostname;

my $start_path = dirname(__FILE__);
my $dir_path   = '';
my $help       = '';
my $man        = '';
my $event      = '';
my $subdir     = '';
my $ver        = '';
my $quiet      = '';
my $dbg        = '';     # enable verbose output
$now           = time;
$version       = '0.12';
undef $err;

GetOptions ( 'help|h'    =&gt; \$help,
             'man'       =&gt; \$man,
             'e=s'       =&gt; \$event,
             'p=s'       =&gt; \$subdir,
             'version|V' =&gt; \$ver,
             'q'         =&gt; \$quiet,
             'debug'     =&gt; \$dbg   # option '-debug' will enable verbose
    );                              # output only used for development

if ((!$event)&amp;&amp;(!$man)&amp;&amp;($ver)) { $help=1; }
if ($help) { pod2usage( -verbose =&gt;  1) &amp;&amp; exit; }
if ($man) { pod2usage({-verbose =&gt;  2, -output =&gt; \*STDOUT}); }
if ($ver) { print "motionmail version $version\n"; exit; }

if (!-e "$start_path/motionmail.conf") {
    print "\n\t$start_path/motionmail.conf not found!\n" if (!$quiet);
    print "\tsee 'motionmail.pl -man' for instructions.\n\n" if (!$quiet);
    exit;
} else {
    $excl     = get_settings();
    $dir_path = "$setting{'file_dir'}/$subdir";

    create_montage();

    if($excl) {
        # do not notify when the event was within an exclusion time block
        print "(".(get_date($now))[2].") Within exclusion time, not sending.\n" if (!$quiet);
        exit;
    }

    notify("$event-rmontage.png");
}

sub create_montage {
    # create a montage from the images captured during this event
    unlink("$dir_path/$event-rmontage.png");
    unlink("$dir_path/$event-montage.png");

    opendir(DIR,$dir_path) || die "Can't open dir_path ($dir_path): $!\n"; 
    @files=readdir(DIR);
    close(DIR);
    @files=grep(/$event-/,@files);
    chdir $dir_path;
    # Sort the files so the tiles appear in order 
    @files=sort(@files);
    $files=join " ",@files;
    # failsave: if no images are found, don't try to run the montage command
    if(!$files){
        print "no files found, exiting...\n" if(!$quiet);
        exit;
    }
    # exec the montage command
    # command for email thumbnails
    $err = `montage -verbose -geometry 35% -adjoin $files $event-rmontage.png` if (($setting{'make_montage'})&amp;&amp;(!$excl));
    print $err if($dbg);

    # command for montage that gets left behind on the server
    $err = `montage -verbose -label %f -frame 5 -geometry 100% -adjoin $files $event-montage.png` if (($setting{'make_montage'})&amp;&amp;(!$excl));
    print $err if($dbg);

    # move event images to the history dir
    if($setting{'keep_history'}) {
        if(!-e "./history") { mkdir "./history", 0755; }
        foreach $file(@files) {
            $err = `mv --verbose $file ./history`;
            print $err if($dbg);
        }
    }
}

sub notify {
    my($f)=shift;
    #this stuff would be good to move into configuration varibales
    my $subject = "[" . hostname() . "] Motion detected at " . (get_date($now))[3] . " ($event)";
    my $message = "Motion was detected ".(get_date($now))[3]; 

    send_mail($setting{'send_to'},$subject,$message,"$dir_path/$f");
}

sub send_mail {
    my($to,$subj,$message,$file)=@_;
    my $html=&lt;&lt;EOF;
&lt;html&gt;
&lt;body&gt;
$message&lt;br&gt;
&lt;a href="$setting{'server_url'}/$subdir/$event-montage.png"&gt;
&lt;img src="cid:event_$event.png"&gt;
&lt;/a&gt;
&lt;/body&gt;
&lt;/html&gt;
EOF

    use MIME::Lite;
    my $mime_msg = MIME::Lite-&gt;new( From    =&gt; "$setting{'app_name'} &lt;$setting{'app_email'}&gt;",
                                    To      =&gt; $to,
                                    CC      =&gt; $cc,
                                    Subject =&gt; $subj,
                                    'X-Application' =&gt; "motionmail $version by $setting{'author'}",
                                    Type    =&gt; 'multipart/related'
    ) || die("Error creating MIME message: $!");
    $mime_msg-&gt;attach( Type     =&gt; 'text/html',
                       Data     =&gt; $html );
    $mime_msg-&gt;attach( Type     =&gt; 'image/png',
                       Path     =&gt; $file,
                       Id       =&gt; "event_$event.png"
    ) if ($file);

    MIME::Lite-&gt;send('smtp', $setting{'mail_server'}) if ($setting{'mail_server'});
    $mime_msg-&gt;send() || die("Error sending message: $!");
    unlink $file;
}

sub get_settings {
    open(SETTINGS,"&lt;$start_path/motionmail.conf") || die "Can't open $start_path/motionmail.conf: $!\n";
    @lines=&lt;SETTINGS&gt;;
    close(SETTINGS);

    # the following hash is only used to sort the settings properly
    # very ugly solution. it is only used with the verbose (-debug)
    # option so it probably can be removed altogether to reduce the
    # size of this script
    %wd=(
        'sunday'     =&gt; 0,
        'monday'     =&gt; 1,
        'tuesday'    =&gt; 2,
        'wednesday'  =&gt; 3,
        'thursday'   =&gt; 4,
        'friday'     =&gt; 5,
        'saturday'   =&gt; 6,
        'send_to'    =&gt; 7,
        'file_dir'   =&gt; 8,
        'server_url' =&gt; 9
    ); 

    # get rid of irrelevant lines
    @lines = grep(!/^#/,@lines);
    @lines = grep(!/^\s/,@lines);
    @lines = grep(!/^\n/,@lines);

  # fill setting hash with values from the settings.conf file
    foreach $line(@lines) {
        $line=~s/\s//g;
        ($key,$val)=split(/=/,$line);
        $setting{$key}=$val;
        if($val=~m/(\d{4})-(\d{4})/) {
            $begin{$key}=$1; $end{$key}=$2;
        }
    }

    # print a neatly formatted list of settings
    # (only with -debug)
    print "Settings:\n" if (($dbg)&amp;&amp;(!$quiet));
    for $key (sort { $wd{$a} &lt;=&gt; $wd{$b} } keys %setting) {
        printf ("%14s = %-40s\n",$key,$setting{$key}) if(($dbg)&amp;&amp;(!$quiet));
    }

    # check if current event was detected within an exclusion time block
    # if it is, do not send anything. Events will still be saved.
    my($day,$time)=(get_date($now))[1,2];
    if(($time&gt;=$begin{$day})&amp;&amp;($time&lt;$end{$day})) {
        $dont_send=1;
    }
}

sub get_date {
    my $time = shift;
        $time or ($time = time);
    my @weekday = qw/Sunday Monday Tuesday Wednesday Thursday Friday Saturday/;
    my ($min, $hr, $day, $mon, $yr, $wday) = (localtime($time))[1,2,3,4,5,6];
    $yr = $yr + 1900;
    $mon=$mon+1;
    ($min &lt; 10) and ($min = "0$min");
    ($hr  &lt; 10) and ($hr  = "0$hr");
    ($day &lt; 10) and ($day = "0$day");
    ($mon &lt; 10) and ($mon = "0$mon");
    return "$day$mon$yr","$weekday[$wday]","$hr$min","$weekday[$wday] $day/$mon/$yr $hr:$min";
}

__END__

=pod

=head1 NAME

motionmail - creates a montage from a collection of images and sends it
              to a list of email addresses.

=head1 SYNOPSIS

motionmail -e&lt;EVENTNR&gt; [-q]

=head1 OPTIONS

=over 8

=item B&lt;-help&gt; B&lt;-h&gt;

displays a brief help message

=item B&lt;-man&gt;

displays the full manual

=item B&lt;-version&gt; B&lt;-V&gt;

displays version information

=item B&lt;-e&gt; &lt;EVENTNR&gt;

sets the event number. motionmail will look for images for this event in
the image directory, it will then create a montage from these images and
send the montage to the email addresses defined in the motionmail.conf file

=item B&lt;-q&gt;

quiet operation, this will prevent any output from being displayed. Be
aware that this will also prevent errors from being displayed.

=back

=head1 DESCRIPTION

motionmail will search for images that were stored by motion for the event
given. It will create a montage of these images and subsequently send this 
montage to the email addresses defined in $start_path/motionmail.conf.
The event images will be moved to a subdirectory called 'history', the 
montage image will be deleted after sending.
a separate cronjob should be defined to delete old events to prevent an
excess of data.

This script can be called by adding:
on_event_end /usr/local/bin/motionmail.pl -e=%v -q

To your motion.conf


=head1 FILES

B&lt;$start_path/motionmail.conf&gt;

Configuration settings.
this file should contain the following:

 #---------- motionmail.conf ------------
 
 # settings file for motionmail
 # (see motionmail -man for instructions)
 # comment lines start with #
 # blank lines, lines starting with a space and
 # lines starting with # will be ignored
 
 # comma separated list of email addresses
 send_to      = taco@cannex.com.au
 # directory where event images are stored by motion
 # (see the 'target_dir' setting in motion.conf)
 file_dir     = /home/cam/public_html
 # make the montage.png image (1=yes,0=no)
 # (nothing will be sent if this is set to 0)
 make_montage = 1
 # keep event images (1=yes,0=no)
 # this will store all event images in a subdir of
 # file_dir called 'history'
 keep_history = 1
 # application name
 # this name will appear in the 'From' field of all email
 app_name     = Motion
 # application email
 # this will be the sender address of all email
 app_email    = motion@cannex.com.au
 # the 'From:' field will be formed like this:
 # From: app_name &lt;app_email&gt;
 
 # for each weekday an exclusion time can be set
 # this is done in 24h notation in the form of &lt;begin time hhmm&gt;-&lt;end time hhmm&gt;,
 # events will only be sent outside the defined time block, when left empty
 # events will be sent for the full 24 hours. see example below
 
 monday    = 0800-1700
 tuesday   = 0800-1700
 wednesday = 0800-1700
 thursday  = 0800-1700
 friday    = 0800-1600
 saturday  =
 sunday    =
 
 #---------- motionmail.conf ------------

=head1 REQUIREMENTS

 Getopt::Long, Pod::Usage, MIME::Lite


=head1 VERSION

motionmail version 0.01 ( Mon Jun  6 08:03:03 EST 2005 )

=head1 AUTHOR

Taco Scheltema &lt;taco@scheltema.org&gt;, &lt;taco@cannex.com.au&gt;

=cut
</pre></body></html>