Merge branch 'master' of github.com:ZoneMinder/ZoneMinder

This commit is contained in:
Isaac Connor 2017-06-28 11:58:23 -04:00
commit 323cd3540d
21 changed files with 1048 additions and 996 deletions

View File

@ -331,13 +331,13 @@ CREATE TABLE `Monitors` (
`Format` int(10) unsigned NOT NULL default '0', `Format` int(10) unsigned NOT NULL default '0',
`V4LMultiBuffer` tinyint(1) unsigned, `V4LMultiBuffer` tinyint(1) unsigned,
`V4LCapturesPerFrame` tinyint(3) unsigned, `V4LCapturesPerFrame` tinyint(3) unsigned,
`Protocol` varchar(16) NOT NULL default '', `Protocol` varchar(16) default '',
`Method` varchar(16) NOT NULL default '', `Method` varchar(16) NOT NULL default '',
`Host` varchar(64), `Host` varchar(64),
`Port` varchar(8) NOT NULL default '', `Port` varchar(8) NOT NULL default '',
`SubPath` varchar(64) NOT NULL default '', `SubPath` varchar(64) NOT NULL default '',
`Path` varchar(255), `Path` varchar(255),
`Options` varchar(255) not null default '', `Options` varchar(255) default '',
`User` varchar(64), `User` varchar(64),
`Pass` varchar(64), `Pass` varchar(64),
`Width` smallint(5) unsigned NOT NULL default '0', `Width` smallint(5) unsigned NOT NULL default '0',

View File

@ -6,3 +6,4 @@ usr/share/perl5/ZoneMinder.pm
usr/share/zoneminder/db usr/share/zoneminder/db
usr/share/zoneminder/www usr/share/zoneminder/www
etc/zm etc/zm
etc/zm/conf.d/*

View File

@ -18,7 +18,7 @@ Alias /zm "@ZM_WEBDIR@"
Allow from all Allow from all
</Directory> </Directory>
ScriptAlias /cgi-bin/zm "@ZM_CGIDIR@" ScriptAlias /cgi-bin-zm "@ZM_CGIDIR@"
<Directory "@ZM_CGIDIR@"> <Directory "@ZM_CGIDIR@">
SSLRequireSSL SSLRequireSSL
AllowOverride All AllowOverride All

View File

@ -33,7 +33,7 @@
%global _hardened_build 1 %global _hardened_build 1
Name: zoneminder Name: zoneminder
Version: 1.31.0 Version: 1.31.1
Release: 1%{?dist} Release: 1%{?dist}
Summary: A camera monitoring and analysis tool Summary: A camera monitoring and analysis tool
Group: System Environment/Daemons Group: System Environment/Daemons

View File

@ -1,4 +1,5 @@
etc/zm/zm.conf etc/zm/zm.conf
etc/zm/conf.d/*
usr/bin usr/bin
usr/lib/zoneminder usr/lib/zoneminder
usr/share/polkit-1 usr/share/polkit-1

View File

@ -1,4 +1,5 @@
etc/zm etc/zm
etc/zm/conf.d/*
usr/bin usr/bin
usr/share/polkit-1/actions usr/share/polkit-1/actions
usr/share/polkit-1/rules.d usr/share/polkit-1/rules.d

View File

@ -1,4 +1,5 @@
etc/zm/zm.conf etc/zm/zm.conf
etc/zm/conf.d/*
usr/bin usr/bin
usr/lib/zoneminder usr/lib/zoneminder
usr/share/polkit-1 usr/share/polkit-1

View File

@ -4,60 +4,62 @@ set -e
if [ "$1" = "configure" ]; then if [ "$1" = "configure" ]; then
. /etc/zm/zm.conf . /etc/zm/zm.conf
# The logs can contain passwords, etc... so by setting group root, only www-data can read them, not people in the www-data group # The logs can contain passwords, etc... so by setting group root, only www-data can read them, not people in the www-data group
chown www-data:root /var/log/zm chown www-data:root /var/log/zm
chown www-data:www-data /var/lib/zm chown www-data:www-data /var/lib/zm
if [ -z "$2" ]; then if [ -z "$2" ]; then
chown www-data:www-data /var/cache/zoneminder /var/cache/zoneminder/* chown www-data:www-data /var/cache/zoneminder /var/cache/zoneminder/*
fi fi
if [ ! -e "/etc/apache2/mods-enabled/cgi.load" ]; then if [ ! -e "/etc/apache2/mods-enabled/cgi.load" ]; then
echo "The cgi module is not enabled in apache2. I am enabling it using a2enmod cgi." echo "The cgi module is not enabled in apache2. I am enabling it using a2enmod cgi."
a2enmod cgi a2enmod cgi
fi fi
# Do this every time the package is installed or upgraded # Do this every time the package is installed or upgraded
# Ensure zoneminder is stopped
deb-systemd-invoke stop zoneminder.service || exit $?
# Ensure zoneminder is stopped # Ensure zoneminder is stopped
deb-systemd-invoke stop zoneminder.service || exit $? deb-systemd-invoke stop zoneminder.service || exit $?
if [ "$ZM_DB_HOST" = "localhost" ]; then if [ "$ZM_DB_HOST" = "localhost" ]; then
if [ -e "/etc/init.d/mysql" ]; then if [ -e "/etc/init.d/mysql" ]; then
# #
# Get mysql started if it isn't # Get mysql started if it isn't
# #
if ! $(/etc/init.d/mysql status >/dev/null 2>&1); then if ! $(/etc/init.d/mysql status >/dev/null 2>&1); then
deb-systemd-invoke start mysql.service || exit $? deb-systemd-invoke start mysql.service || exit $?
fi fi
if $(/etc/init.d/mysql status >/dev/null 2>&1); then if $(/etc/init.d/mysql status >/dev/null 2>&1); then
mysqladmin --defaults-file=/etc/mysql/debian.cnf -f reload mysqladmin --defaults-file=/etc/mysql/debian.cnf -f reload
# test if database if already present... # test if database if already present...
if ! $(echo quit | mysql --defaults-file=/etc/mysql/debian.cnf zm > /dev/null 2> /dev/null) ; then if ! $(echo quit | mysql --defaults-file=/etc/mysql/debian.cnf zm > /dev/null 2> /dev/null) ; then
cat /usr/share/zoneminder/db/zm_create.sql | mysql --defaults-file=/etc/mysql/debian.cnf cat /usr/share/zoneminder/db/zm_create.sql | mysql --defaults-file=/etc/mysql/debian.cnf
# This creates the user. # This creates the user.
echo "grant lock tables,alter,select,insert,update,delete,create,index on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost identified by \"${ZM_DB_PASS}\";" | mysql --defaults-file=/etc/mysql/debian.cnf mysql echo "grant lock tables,alter,select,insert,update,delete,create,index on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost identified by \"${ZM_DB_PASS}\";" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
else
echo "grant lock tables,alter,select,insert,update,delete,create,index on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
fi
zmupdate.pl --nointeractive
zmupdate.pl --nointeractive -f
else
echo 'NOTE: mysql not running, please start mysql and run dpkg-reconfigure zoneminder when it is running.'
fi
else else
echo 'mysql not found, assuming remote server.' echo "grant lock tables,alter,select,insert,update,delete,create,index on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
fi fi
zmupdate.pl --nointeractive
zmupdate.pl --nointeractive -f
else
echo 'NOTE: mysql not running, please start mysql and run dpkg-reconfigure zoneminder when it is running.'
fi
else else
echo "Not doing database upgrade due to remote db server ($ZM_DB_HOST)" echo 'mysql not found, assuming remote server.'
fi fi
echo "Done Updating, starting ZoneMinder"
deb-systemd-invoke start zoneminder.service || exit $? else
echo "Not doing database upgrade due to remote db server ($ZM_DB_HOST)"
fi
echo "Done Updating, starting ZoneMinder"
deb-systemd-invoke restart zoneminder.service || exit $?
fi fi
#DEBHELPER# #DEBHELPER#

View File

@ -11,6 +11,8 @@
@ZM_LOGDIR@/*.log { @ZM_LOGDIR@/*.log {
missingok missingok
notifempty notifempty
delaycompress
compress
sharedscripts sharedscripts
postrotate postrotate
/bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true /bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true

View File

@ -33,8 +33,11 @@ FOREACH(PERLSCRIPT ${perlscripts})
ENDFOREACH(PERLSCRIPT ${perlscripts}) ENDFOREACH(PERLSCRIPT ${perlscripts})
# Install the perl scripts # Install the perl scripts
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zmaudit.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmcontrol.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmdc.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmfilter.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmpkg.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmtrack.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmtrigger.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmupdate.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmvideo.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmwatch.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmcamtool.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmsystemctl.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmtelemetry.pl" DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zmaudit.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmcontrol.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmdc.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmfilter.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmpkg.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmtrack.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmtrigger.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmupdate.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmvideo.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmwatch.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmcamtool.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmtelemetry.pl" DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
if(NOT ZM_NO_X10) if(NOT ZM_NO_X10)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zmx10.pl" DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zmx10.pl" DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
endif(NOT ZM_NO_X10) endif(NOT ZM_NO_X10)
if(WITH_SYSTEMD)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zmsystemctl.pl" DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
endif(WITH_SYSTEMD)

View File

@ -41,7 +41,7 @@ our @ISA = qw(Exporter ZoneMinder::Base);
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
# will save memory. # will save memory.
our %EXPORT_TAGS = ( our %EXPORT_TAGS = (
'constants' => [ qw( constants => [ qw(
DEBUG DEBUG
INFO INFO
WARNING WARNING
@ -50,7 +50,7 @@ our %EXPORT_TAGS = (
PANIC PANIC
NOLOG NOLOG
) ], ) ],
'functions' => [ qw( functions => [ qw(
logInit logInit
logReinit logReinit
logTerm logTerm
@ -72,13 +72,14 @@ our %EXPORT_TAGS = (
Panic Panic
) ] ) ]
); );
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
our @EXPORT = qw(); our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
our $VERSION = $ZoneMinder::Base::VERSION; our @EXPORT = qw();
our $VERSION = $ZoneMinder::Base::VERSION;
# ========================================================================== # ==========================================================================
# #
@ -86,43 +87,43 @@ our %EXPORT_TAGS = (
# #
# ========================================================================== # ==========================================================================
use ZoneMinder::Config qw(:all); use ZoneMinder::Config qw(:all);
use DBI; use DBI;
use Carp; use Carp;
use POSIX; use POSIX;
use IO::Handle; use IO::Handle;
use Data::Dumper; use Data::Dumper;
use Time::HiRes qw/gettimeofday/; use Time::HiRes qw/gettimeofday/;
use Sys::Syslog; use Sys::Syslog;
use constant { use constant {
DEBUG => 1, DEBUG => 1,
INFO => 0, INFO => 0,
WARNING => -1, WARNING => -1,
ERROR => -2, ERROR => -2,
FATAL => -3, FATAL => -3,
PANIC => -4, PANIC => -4,
NOLOG => -5 NOLOG => -5
}; };
our %codes = ( our %codes = (
&DEBUG => "DBG", &DEBUG => 'DBG',
&INFO => "INF", &INFO => 'INF',
&WARNING => "WAR", &WARNING => 'WAR',
&ERROR => "ERR", &ERROR => 'ERR',
&FATAL => "FAT", &FATAL => 'FAT',
&PANIC => "PNC", &PANIC => 'PNC',
&NOLOG => "OFF" &NOLOG => 'OFF'
); );
our %priorities = ( our %priorities = (
&DEBUG => "debug", &DEBUG => 'debug',
&INFO => "info", &INFO => 'info',
&WARNING => "warning", &WARNING => 'warning',
&ERROR => "err", &ERROR => 'err',
&FATAL => "err", &FATAL => 'err',
&PANIC => "err" &PANIC => 'err'
); );
our $logger; our $logger;
@ -134,10 +135,10 @@ sub new {
$this->{initialised} = undef; $this->{initialised} = undef;
#$this->{id} = "zmundef"; #$this->{id} = 'zmundef';
( $this->{id} ) = $0 =~ m|^(?:.*/)?([^/]+?)(?:\.[^/.]+)?$|; ( $this->{id} ) = $0 =~ m|^(?:.*/)?([^/]+?)(?:\.[^/.]+)?$|;
$this->{idRoot} = $this->{id}; $this->{idRoot} = $this->{id};
$this->{idArgs} = ""; $this->{idArgs} = '';
$this->{level} = INFO; $this->{level} = INFO;
$this->{termLevel} = NOLOG; $this->{termLevel} = NOLOG;
@ -151,7 +152,7 @@ sub new {
( $this->{fileName} = $0 ) =~ s|^.*/||; ( $this->{fileName} = $0 ) =~ s|^.*/||;
$this->{logPath} = $Config{ZM_PATH_LOGS}; $this->{logPath} = $Config{ZM_PATH_LOGS};
$this->{logFile} = $this->{logPath}."/".$this->{id}.".log"; $this->{logFile} = $this->{logPath}.'/'.$this->{id}.".log";
$this->{trace} = 0; $this->{trace} = 0;
@ -196,7 +197,7 @@ sub initialise( @ ) {
$this->{logPath} = $options{logPath} if ( defined($options{logPath}) ); $this->{logPath} = $options{logPath} if ( defined($options{logPath}) );
my $tempLogFile; my $tempLogFile;
$tempLogFile = $this->{logPath}."/".$this->{id}.".log"; $tempLogFile = $this->{logPath}.'/'.$this->{id}.".log";
$tempLogFile = $options{logFile} if ( defined($options{logFile}) ); $tempLogFile = $options{logFile} if ( defined($options{logFile}) );
if ( my $logFile = $this->getTargettedEnv('LOG_FILE') ) { if ( my $logFile = $this->getTargettedEnv('LOG_FILE') ) {
$tempLogFile = $logFile; $tempLogFile = $logFile;
@ -231,7 +232,6 @@ sub initialise( @ ) {
my $level; my $level;
$tempLevel = $level if ( defined($level = $this->getTargettedEnv('LOG_LEVEL')) ); $tempLevel = $level if ( defined($level = $this->getTargettedEnv('LOG_LEVEL')) );
$tempTermLevel = $level if ( defined($level = $this->getTargettedEnv('LOG_LEVEL_TERM')) ); $tempTermLevel = $level if ( defined($level = $this->getTargettedEnv('LOG_LEVEL_TERM')) );
$tempDatabaseLevel = $level if ( defined($level = $this->getTargettedEnv('LOG_LEVEL_DATABASE')) ); $tempDatabaseLevel = $level if ( defined($level = $this->getTargettedEnv('LOG_LEVEL_DATABASE')) );
$tempFileLevel = $level if ( defined($level = $this->getTargettedEnv('LOG_LEVEL_FILE')) ); $tempFileLevel = $level if ( defined($level = $this->getTargettedEnv('LOG_LEVEL_FILE')) );
@ -240,9 +240,9 @@ sub initialise( @ ) {
if ( $Config{ZM_LOG_DEBUG} ) { if ( $Config{ZM_LOG_DEBUG} ) {
foreach my $target ( split( /\|/, $Config{ZM_LOG_DEBUG_TARGET} ) ) { foreach my $target ( split( /\|/, $Config{ZM_LOG_DEBUG_TARGET} ) ) {
if ( $target eq $this->{id} if ( $target eq $this->{id}
|| $target eq "_".$this->{id} || $target eq '_'.$this->{id}
|| $target eq $this->{idRoot} || $target eq $this->{idRoot}
|| $target eq "_".$this->{idRoot} || $target eq '_'.$this->{idRoot}
|| $target eq "" || $target eq ""
) { ) {
if ( $Config{ZM_LOG_DEBUG_LEVEL} > NOLOG ) { if ( $Config{ZM_LOG_DEBUG_LEVEL} > NOLOG ) {
@ -271,13 +271,13 @@ sub initialise( @ ) {
$this->{initialised} = !undef; $this->{initialised} = !undef;
Debug( "LogOpts: level=".$codes{$this->{level}} Debug( 'LogOpts: level='.$codes{$this->{level}}
."/".$codes{$this->{effectiveLevel}} .'/'.$codes{$this->{effectiveLevel}}
.", screen=".$codes{$this->{termLevel}} .', screen='.$codes{$this->{termLevel}}
.", database=".$codes{$this->{databaseLevel}} .', database='.$codes{$this->{databaseLevel}}
.", logfile=".$codes{$this->{fileLevel}} .', logfile='.$codes{$this->{fileLevel}}
."->".$this->{logFile} .'->'.$this->{logFile}
.", syslog=".$codes{$this->{syslogLevel}} .', syslog='.$codes{$this->{syslogLevel}}
); );
} }
@ -322,11 +322,11 @@ sub limit {
sub getTargettedEnv { sub getTargettedEnv {
my $this = shift; my $this = shift;
my $name = shift; my $name = shift;
my $envName = $name."_".$this->{id}; my $envName = $name.'_'.$this->{id};
my $value; my $value;
$value = $ENV{$envName} if ( defined($ENV{$envName}) ); $value = $ENV{$envName} if ( defined($ENV{$envName}) );
if ( !defined($value) && $this->{id} ne $this->{idRoot} ) { if ( !defined($value) && $this->{id} ne $this->{idRoot} ) {
$envName = $name."_".$this->{idRoot}; $envName = $name.'_'.$this->{idRoot};
$value = $ENV{$envName} if ( defined($ENV{$envName}) ); $value = $ENV{$envName} if ( defined($ENV{$envName}) );
} }
if ( !defined($value) ) { if ( !defined($value) ) {
@ -375,8 +375,8 @@ sub level {
$this->{effectiveLevel} = $this->{termLevel} if ( $this->{termLevel} > $this->{effectiveLevel} ); $this->{effectiveLevel} = $this->{termLevel} if ( $this->{termLevel} > $this->{effectiveLevel} );
$this->{effectiveLevel} = $this->{databaseLevel} if ( $this->{databaseLevel} > $this->{effectiveLevel} ); $this->{effectiveLevel} = $this->{databaseLevel} if ( $this->{databaseLevel} > $this->{effectiveLevel} );
$this->{effectiveLevel} = $this->{fileLevel} if ( $this->{fileLevel} > $this->{effectiveLevel} ); $this->{effectiveLevel} = $this->{fileLevel} if ( $this->{fileLevel} > $this->{effectiveLevel} );
$this->{effectiveLevel} = $this->{syslogLevel} if ( $this->{syslogLevel} > $this->{level} ); $this->{effectiveLevel} = $this->{syslogLevel} if ( $this->{syslogLevel} > $this->{effectiveLevel} );
$this->{effectiveLevel} = $this->{level} if ( $this->{effectiveLevel} > $this->{level} ); $this->{effectiveLevel} = $this->{level} if ( $this->{effectiveLevel} > $this->{effectiveLevel} );
} }
return( $this->{level} ); return( $this->{level} );
} }
@ -490,7 +490,7 @@ sub syslogLevel {
sub openSyslog { sub openSyslog {
my $this = shift; my $this = shift;
openlog( $this->{id}, "pid", "local1" ); openlog( $this->{id}, 'pid', "local1" );
} }
sub closeSyslog { sub closeSyslog {
@ -523,6 +523,7 @@ sub openFile {
} }
} else { } else {
$this->fileLevel( NOLOG ); $this->fileLevel( NOLOG );
$this->termLevel( INFO );
Error( "Can't open log file '".$this->{logFile}."': $!" ); Error( "Can't open log file '".$this->{logFile}."': $!" );
} }
} }
@ -544,10 +545,8 @@ sub logPrint {
my ($seconds, $microseconds) = gettimeofday(); my ($seconds, $microseconds) = gettimeofday();
my $message = sprintf( my $message = sprintf(
"%s.%06d %s[%d].%s [%s]" '%s.%06d %s[%d].%s [%s]'
, strftime( "%x %H:%M:%S" , strftime( '%x %H:%M:%S' ,localtime( $seconds ) )
,localtime( $seconds )
)
, $microseconds , $microseconds
, $this->{id} , $this->{id}
, $$ , $$
@ -564,7 +563,7 @@ sub logPrint {
} }
print( $LOGFILE $message ) if ( $level <= $this->{fileLevel} ); print( $LOGFILE $message ) if ( $level <= $this->{fileLevel} );
if ( $level <= $this->{databaseLevel} ) { if ( $level <= $this->{databaseLevel} ) {
my $sql = "insert into Logs ( TimeKey, Component, Pid, Level, Code, Message, File, Line ) values ( ?, ?, ?, ?, ?, ?, ?, NULL )"; my $sql = 'insert into Logs ( TimeKey, Component, Pid, Level, Code, Message, File, Line ) values ( ?, ?, ?, ?, ?, ?, ?, NULL )';
$this->{sth} = $this->{dbh}->prepare_cached( $sql ); $this->{sth} = $this->{dbh}->prepare_cached( $sql );
if ( !$this->{sth} ) { if ( !$this->{sth} ) {
$this->{databaseLevel} = NOLOG; $this->{databaseLevel} = NOLOG;
@ -589,7 +588,7 @@ sub logPrint {
sub logInit( ;@ ) { sub logInit( ;@ ) {
my %options = @_ ? @_ : (); my %options = @_ ? @_ : ();
$logger = ZoneMinder::Logger->new() if ( !$logger ); $logger = ZoneMinder::Logger->new() if !$logger;
$logger->initialise( %options ); $logger->initialise( %options );
} }
@ -646,14 +645,14 @@ sub logSyslogLevel {
sub Mark { sub Mark {
my $level = shift; my $level = shift;
$level = DEBUG unless( defined($level) ); $level = DEBUG unless( defined($level) );
my $tag = "Mark"; my $tag = 'Mark';
fetch()->logPrint( $level, $tag ); fetch()->logPrint( $level, $tag );
} }
sub Dump { sub Dump {
my $var = shift; my $var = shift;
my $label = shift; my $label = shift;
$label = "VAR" unless( defined($label) ); $label = 'VAR' unless( defined($label) );
fetch()->logPrint( DEBUG, Data::Dumper->Dump( [ $var ], [ $label ] ) ); fetch()->logPrint( DEBUG, Data::Dumper->Dump( [ $var ], [ $label ] ) );
} }
@ -695,10 +694,10 @@ ZoneMinder::Logger - ZoneMinder Logger module
use ZoneMinder::Logger; use ZoneMinder::Logger;
use ZoneMinder::Logger qw(:all); use ZoneMinder::Logger qw(:all);
logInit( "myproc", DEBUG ); logInit( 'myproc', DEBUG );
Debug( "This is what is happening" ); Debug( 'This is what is happening' );
Info( "Something interesting is happening" ); Info( 'Something interesting is happening' );
Warning( "Something might be going wrong." ); Warning( "Something might be going wrong." );
Error( "Something has gone wrong!!" ); Error( "Something has gone wrong!!" );
Fatal( "Something has gone badly wrong, gotta stop!!" ); Fatal( "Something has gone badly wrong, gotta stop!!" );

View File

@ -21,6 +21,304 @@
# #
# ========================================================================== # ==========================================================================
use strict;
use bytes;
@EXTRA_PERL_LIB@
use ZoneMinder;
use DBI;
use Getopt::Long;
use autouse 'Pod::Usage'=>qw(pod2usage);
use LWP::UserAgent;
use Sys::MemInfo qw(totalmem);
use Sys::CPU qw(cpu_count);
use POSIX qw(strftime uname);
$ENV{PATH} = '/bin:/usr/bin:/usr/local/bin';
$ENV{SHELL} = '/bin/sh' if exists $ENV{SHELL};
delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
use constant CHECK_INTERVAL => (14*24*60*60); # Interval between version checks
# Setting these as contants for now.
# Alternatively, we can put these in the dB and then retrieve using the Config hash.
use constant ZM_TELEMETRY_SERVER_ENDPOINT => 'https://zmanon:2b2d0b4skps@telemetry.zoneminder.com/zmtelemetry/testing5';
if ( $Config{ZM_TELEMETRY_DATA} ) {
print( 'Update agent starting at '.strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" );
my $lastCheck = $Config{ZM_TELEMETRY_LAST_UPLOAD};
while( 1 ) {
my $now = time();
if ( ($now-$lastCheck) > CHECK_INTERVAL ) {
Info( 'Collecting data to send to ZoneMinder Telemetry server.' );
my $dbh = zmDbConnect();
# Build the telemetry hash
# We should keep *BSD systems in mind when calling system commands
my %telemetry;
$telemetry{uuid} = getUUID($dbh);
$telemetry{ip} = getIP();
$telemetry{timestamp} = strftime( '%Y-%m-%dT%H:%M:%S%z', localtime() );
$telemetry{monitor_count} = countQuery($dbh,'Monitors');
$telemetry{event_count} = countQuery($dbh,'Events');
$telemetry{architecture} = runSysCmd('uname -p');
($telemetry{kernel}, $telemetry{distro}, $telemetry{version}) = getDistro();
$telemetry{zm_version} = ZoneMinder::Base::ZM_VERSION;
$telemetry{system_memory} = totalmem();
$telemetry{processor_count} = cpu_count();
$telemetry{monitors} = getMonitorRef($dbh);
Info( 'Sending data to ZoneMinder Telemetry server.' );
my $result = jsonEncode( \%telemetry );
if ( sendData($result) ) {
$lastCheck = $now;
my $sql = q`update Config set Value = ? where Name = 'ZM_TELEMETRY_LAST_UPLOAD'`;
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute( "$lastCheck" ) or die( "Can't execute: ".$sth->errstr() );
$sth->finish();
}
}
sleep( 3600 );
}
print( 'Update agent exiting at '.strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" );
}
###############
# SUBROUTINES #
###############
# Find, verify, then run the supplied system command
sub runSysCmd {
my $msg = shift;
my @arguments = split(/ /,$msg);
chomp($arguments[0]);
my $path = qx( which $arguments[0] );
my $status = $? >> 8;
my $result = '';
if ( !$path || $status ) {
Warning( "Cannot find the $arguments[0] executable." );
} else {
chomp($path);
$arguments[0] = $path;
my $cmd = join(' ',@arguments);
$result = qx( $cmd );
chomp($result);
}
return $result;
}
# Upload message data to ZoneMinder telemetry server
sub sendData {
my $msg = shift;
my $ua = LWP::UserAgent->new;
my $server_endpoint = ZM_TELEMETRY_SERVER_ENDPOINT;
if ( $Config{ZM_UPDATE_CHECK_PROXY} ) {
$ua->proxy( 'https', $Config{ZM_UPDATE_CHECK_PROXY} );
}
Debug("Posting telemetry data to: $server_endpoint");
# set custom HTTP request header fields
my $req = HTTP::Request->new(POST => $server_endpoint);
$req->header('content-type' => 'application/x-www-form-urlencoded');
$req->header('content-length' => length($msg));
$req->header('connection' => 'Close');
$req->content($msg);
my $resp = $ua->request($req);
my $resp_msg = $resp->decoded_content;
my $resp_code = $resp->code;
if ($resp->is_success) {
Info('Telemetry data uploaded successfully.');
Debug("Telemetry server upload success response message: $resp_msg");
} else {
Warning("Telemetry server returned HTTP POST error code: $resp_code");
Debug("Telemetry server upload failure response message: $resp_msg");
}
return $resp->is_success;
}
# Retrieves the UUID from the database. Creates a new UUID if one does not exist.
sub getUUID {
my $dbh = shift;
my $uuid= "";
# Verify the current UUID is valid and not nil
if (( $Config{ZM_TELEMETRY_UUID} =~ /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/i ) && ( $Config{ZM_TELEMETRY_UUID} ne '00000000-0000-0000-0000-000000000000' )) {
$uuid = $Config{ZM_TELEMETRY_UUID};
} else {
my $sql = 'SELECT uuid()';
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() );
$uuid = $Config{ZM_TELEMETRY_UUID} = $sth->fetchrow_array();
$sth->finish();
$sql = q`UPDATE Config set Value = ? WHERE Name = 'ZM_TELEMETRY_UUID'`;
$sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
$res = $sth->execute( "$uuid" ) or die( "Can't execute: ".$sth->errstr() );
$sth->finish();
}
Debug("Using UUID of: $uuid");
return $uuid;
}
# Retrieves the local server's external IP address
sub getIP {
my $ipaddr = '0.0.0.0';
my $ua = LWP::UserAgent->new;
my $server_endpoint = 'https://wiki.zoneminder.com/ip.php';
my $req = HTTP::Request->new(GET => $server_endpoint);
my $resp = $ua->request($req);
if ($resp->is_success) {
$ipaddr = $resp->decoded_content;
}
Debug("Found external ip address of: $ipaddr");
return $ipaddr;
}
# As the name implies, just your average mysql count query
sub countQuery {
my $dbh = shift;
my $table = shift;
my $sql = "SELECT count(*) FROM $table";
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() );
my $count = $sth->fetchrow_array();
$sth->finish();
return $count
}
# Returns a reference to an array of hashes containing data from all monitors
sub getMonitorRef {
my $dbh = shift;
my $sql = 'SELECT Id,Name,Type,Function,Width,Height,Colours,MaxFPS,AlarmMaxFPS FROM Monitors';
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() );
my $arrayref = $sth->fetchall_arrayref({});
return $arrayref;
}
sub getDistro {
my $kernel = '';
my $distro = '';
my $version = '';
my @uname = uname();
if ( $uname[0] =~ /Linux/ ) {
Debug('Linux distro detected.');
($kernel, $distro, $version) = linuxDistro();
} elsif ( $uname[0] =~ /.*BSD/ ) {
Debug('BSD distro detected.');
$kernel = $uname[3];
$distro = $uname[0];
$version = $uname[2];
} elsif ( $uname[0] =~ /Darwin/ ) {
Debug('Mac OS distro detected.');
$kernel = $uname[3];
$distro = runSysCmd('sw_vers -productName');
$version = runSysCmd('sw_vers -productVersion');
} elsif ( $uname[0] =~ /SunOS|Solaris/ ) {
Debug('Sun Solaris detected.');
$kernel = $uname[3];
$distro = $uname[1];
$version = $uname[2];
} else {
Warning('ZoneMinder was unable to determine the host system. Please report.');
$kernel = 'Unknown';
$distro = 'Unknown';
$version = 'Unknown';
}
return ($kernel, $distro, $version);
}
sub linuxDistro {
my @uname = uname();
my $kernel = $uname[2];
my $distro = 'Unknown Linux Distro';
my $version = 'Unknown Linux Version';
my $found = 0;
# os-release is the standard for many new distros based on systemd
if ( -f '/etc/os-release' ) {
open(my $RELFILE,'<','/etc/os-release') or die( "Can't Open file: $!\n" );
while (<$RELFILE>) {
if ( /^NAME=(")?(.*)(?(1)\1|).*$/ ) {
$distro = $2;
$found = 1;
}
if ( /^VERSION_ID=(")?(.*)(?(1)\1|).*$/ ) {
$version = $2;
$found = 1;
}
}
close $RELFILE;
# exists on many distros but does not always contain useful information, such as redhat
} elsif ( -f '/etc/lsb-release' ) {
open(my $RELFILE,'<','/etc/lsb-release') or die( "Can't Open file: $!\n" );
while (<$RELFILE>) {
if ( /^DISTRIB_DESCRIPTION=(")?(.*)(?(1)\1|).*$/ ) {
$distro = $2;
$found = 1;
}
if ( /^DISTRIB_RELEASE=(")?(.*)(?(1)\1|).*$/ ) {
$version = $2;
$found = 1;
}
}
close $RELFILE;
}
# If all else fails, search through a list of known release files until we find one
if ( !$found ) {
my @releasefile = ('/etc/SuSE-release', '/etc/redhat-release', '/etc/redhat_version',
'/etc/fedora-release', '/etc/slackware-release', '/etc/slackware-version',
'/etc/debian_release', '/etc/debian_version', '/etc/mandrake-release',
'/etc/yellowdog-release', '/etc/gentoo-release');
foreach (@releasefile) {
if ( -f $_ ) {
open(my $RELFILE,'<',$_) or die( "Can't Open file: $!\n" );
while (<$RELFILE>) {
if ( /(.*).* (\d+\.?\d*) .*/ ) {
$distro = $1;
$version = $2;
$found = 1;
}
}
close $RELFILE;
last;
}
}
}
if ( !$found ) {
Warning('ZoneMinder was unable to determine Linux distro. Please report.');
}
return ($kernel, $distro, $version);
}
1;
__END__
=head1 NAME =head1 NAME
zmtelemetry.pl - Send usage information to the ZoneMinder development team zmtelemetry.pl - Send usage information to the ZoneMinder development team
@ -44,300 +342,3 @@ console under Options.
none currently none currently
=cut =cut
use strict;
use bytes;
@EXTRA_PERL_LIB@
use ZoneMinder;
use DBI;
use Getopt::Long;
use autouse 'Pod::Usage'=>qw(pod2usage);
use LWP::UserAgent;
use Sys::MemInfo qw(totalmem);
use Sys::CPU qw(cpu_count);
use POSIX qw(strftime uname);
$ENV{PATH} = '/bin:/usr/bin:/usr/local/bin';
$ENV{SHELL} = '/bin/sh' if exists $ENV{SHELL};
delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
use constant CHECK_INTERVAL => (14*24*60*60); # Interval between version checks
# Setting these as contants for now.
# Alternatively, we can put these in the dB and then retrieve using the Config hash.
use constant ZM_TELEMETRY_SERVER_ENDPOINT => 'https://zmanon:2b2d0b4skps@telemetry.zoneminder.com/zmtelemetry/testing5';
if ( $Config{ZM_TELEMETRY_DATA} )
{
print( "Update agent starting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" );
my $lastCheck = $Config{ZM_TELEMETRY_LAST_UPLOAD};
while( 1 ) {
my $now = time();
if ( ($now-$lastCheck) > CHECK_INTERVAL ) {
Info( "Collecting data to send to ZoneMinder Telemetry server." );
my $dbh = zmDbConnect();
# Build the telemetry hash
# We should keep *BSD systems in mind when calling system commands
my %telemetry;
$telemetry{uuid} = getUUID($dbh);
$telemetry{ip} = getIP();
$telemetry{timestamp} = strftime( "%Y-%m-%dT%H:%M:%S%z", localtime() );
$telemetry{monitor_count} = countQuery($dbh,"Monitors");
$telemetry{event_count} = countQuery($dbh,"Events");
$telemetry{architecture} = runSysCmd("uname -p");
($telemetry{kernel}, $telemetry{distro}, $telemetry{version}) = getDistro();
$telemetry{zm_version} = ZoneMinder::Base::ZM_VERSION;
$telemetry{system_memory} = totalmem();
$telemetry{processor_count} = cpu_count();
$telemetry{monitors} = getMonitorRef($dbh);
Info( "Sending data to ZoneMinder Telemetry server." );
my $result = jsonEncode( \%telemetry );
if ( sendData($result) ) {
$lastCheck = $now;
my $sql = "update Config set Value = ? where Name = 'ZM_TELEMETRY_LAST_UPLOAD'";
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute( "$lastCheck" ) or die( "Can't execute: ".$sth->errstr() );
$sth->finish();
}
}
sleep( 3600 );
}
print( "Update agent exiting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" );
}
###############
# SUBROUTINES #
###############
# Find, verify, then run the supplied system command
sub runSysCmd {
my $msg = shift;
my @arguments = split(/ /,$msg);
chomp($arguments[0]);
my $path = qx( which $arguments[0] );
my $status = $? >> 8;
my $result = "";
if ( !$path || $status ) {
Warning( "Cannot find the $arguments[0] executable." );
} else {
chomp($path);
$arguments[0] = $path;
my $cmd = join(" ",@arguments);
$result = qx( $cmd );
chomp($result);
}
return $result;
}
# Upload message data to ZoneMinder telemetry server
sub sendData {
my $msg = shift;
my $ua = LWP::UserAgent->new;
my $server_endpoint = ZM_TELEMETRY_SERVER_ENDPOINT;
if ( $Config{ZM_UPDATE_CHECK_PROXY} ) {
$ua->proxy( "https", $Config{ZM_UPDATE_CHECK_PROXY} );
}
Debug("Posting telemetry data to: $server_endpoint");
# set custom HTTP request header fields
my $req = HTTP::Request->new(POST => $server_endpoint);
$req->header('content-type' => 'application/x-www-form-urlencoded');
$req->header('content-length' => length($msg));
$req->header('connection' => 'Close');
$req->content($msg);
my $resp = $ua->request($req);
my $resp_msg = $resp->decoded_content;
my $resp_code = $resp->code;
if ($resp->is_success) {
Info("Telemetry data uploaded successfully.");
Debug("Telemetry server upload success response message: $resp_msg");
} else {
Warning("Telemetry server returned HTTP POST error code: $resp_code");
Debug("Telemetry server upload failure response message: $resp_msg");
}
return $resp->is_success;
}
# Retrieves the UUID from the database. Creates a new UUID if one does not exist.
sub getUUID {
my $dbh = shift;
my $uuid= "";
# Verify the current UUID is valid and not nil
if (( $Config{ZM_TELEMETRY_UUID} =~ /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/i ) && ( $Config{ZM_TELEMETRY_UUID} ne "00000000-0000-0000-0000-000000000000" )) {
$uuid = $Config{ZM_TELEMETRY_UUID};
} else {
my $sql = "SELECT uuid()";
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() );
$uuid = $Config{ZM_TELEMETRY_UUID} = $sth->fetchrow_array();
$sth->finish();
$sql = "UPDATE Config set Value = ? WHERE Name = 'ZM_TELEMETRY_UUID'";
$sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
$res = $sth->execute( "$uuid" ) or die( "Can't execute: ".$sth->errstr() );
$sth->finish();
}
Debug("Using UUID of: $uuid");
return $uuid;
}
# Retrieves the local server's external IP address
sub getIP {
my $ipaddr = "0.0.0.0";
my $ua = LWP::UserAgent->new;
my $server_endpoint = "https://wiki.zoneminder.com/ip.php";
my $req = HTTP::Request->new(GET => $server_endpoint);
my $resp = $ua->request($req);
if ($resp->is_success) {
$ipaddr = $resp->decoded_content;
}
Debug("Found external ip address of: $ipaddr");
return $ipaddr;
}
# As the name implies, just your average mysql count query
sub countQuery {
my $dbh = shift;
my $table = shift;
my $sql = "SELECT count(*) FROM $table";
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() );
my $count = $sth->fetchrow_array();
$sth->finish();
return $count
}
# Returns a reference to an array of hashes containing data from all monitors
sub getMonitorRef {
my $dbh = shift;
my $sql = "SELECT Id,Name,Type,Function,Width,Height,Colours,MaxFPS,AlarmMaxFPS FROM Monitors";
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() );
my $arrayref = $sth->fetchall_arrayref({});
return $arrayref;
}
sub getDistro {
my $kernel = "";
my $distro = "";
my $version = "";
my @uname = uname();
if ( $uname[0] =~ /Linux/ ) {
Debug("Linux distro detected.");
($kernel, $distro, $version) = linuxDistro();
} elsif ( $uname[0] =~ /.*BSD/ ) {
Debug("BSD distro detected.");
$kernel = $uname[3];
$distro = $uname[0];
$version = $uname[2];
} elsif ( $uname[0] =~ /Darwin/ ) {
Debug("Mac OS distro detected.");
$kernel = $uname[3];
$distro = runSysCmd("sw_vers -productName");
$version = runSysCmd("sw_vers -productVersion");
} elsif ( $uname[0] =~ /SunOS|Solaris/ ) {
Debug("Sun Solaris detected.");
$kernel = $uname[3];
$distro = $uname[1];
$version = $uname[2];
} else {
Warning("ZoneMinder was unable to determine the host system. Please report.");
$kernel = "Unknown";
$distro = "Unknown";
$version = "Unknown";
}
return ($kernel, $distro, $version);
}
sub linuxDistro {
my @uname = uname();
my $kernel = $uname[2];
my $distro = "Unknown Linux Distro";
my $version = "Unknown Linux Version";
my $found = 0;
# os-release is the standard for many new distros based on systemd
if ( -f "/etc/os-release" ) {
open(my $RELFILE,"<","/etc/os-release") or die( "Can't Open file: $!\n" );
while (<$RELFILE>) {
if ( /^NAME=(")?(.*)(?(1)\1|).*$/ ) {
$distro = $2;
$found = 1;
}
if ( /^VERSION_ID=(")?(.*)(?(1)\1|).*$/ ) {
$version = $2;
$found = 1;
}
}
close $RELFILE;
# exists on many distros but does not always contain useful information, such as redhat
} elsif ( -f "/etc/lsb-release" ) {
open(my $RELFILE,"<","/etc/lsb-release") or die( "Can't Open file: $!\n" );
while (<$RELFILE>) {
if ( /^DISTRIB_DESCRIPTION=(")?(.*)(?(1)\1|).*$/ ) {
$distro = $2;
$found = 1;
}
if ( /^DISTRIB_RELEASE=(")?(.*)(?(1)\1|).*$/ ) {
$version = $2;
$found = 1;
}
}
close $RELFILE;
}
# If all else fails, search through a list of known release files until we find one
if ( !$found ) {
my @releasefile = ("/etc/SuSE-release", "/etc/redhat-release", "/etc/redhat_version",
"/etc/fedora-release", "/etc/slackware-release", "/etc/slackware-version",
"/etc/debian_release", "/etc/debian_version", "/etc/mandrake-release",
"/etc/yellowdog-release", "/etc/gentoo-release");
foreach (@releasefile) {
if ( -f $_ ) {
open(my $RELFILE,"<",$_) or die( "Can't Open file: $!\n" );
while (<$RELFILE>) {
if ( /(.*).* (\d+\.?\d*) .*/ ) {
$distro = $1;
$version = $2;
$found = 1;
}
}
close $RELFILE;
last;
}
}
}
if ( !$found ) {
Warning("ZoneMinder was unable to determine Linux distro. Please report.");
}
return ($kernel, $distro, $version);
}

View File

@ -94,20 +94,11 @@ my $size = '';
my $overwrite = 0; my $overwrite = 0;
my $version = 0; my $version = 0;
my @formats = split( /\s+/, $Config{ZM_FFMPEG_FORMATS} );
for ( my $i = 0; $i < @formats; $i++ )
{
if ( $i =~ /^(.+)\*$/ )
{
$format = $formats[$i] = $1;
}
}
GetOptions( GetOptions(
'concat|c:s' =>\$concat_name, 'concat|c:s' =>\$concat_name,
'event|e=i' =>\$event_id, 'event|e=i' =>\$event_id,
'filter_name=s' =>\$filter_name, 'filter_name=s' =>\$filter_name,
'filter_id=i' =>\$filter_id, 'filter_id=i' =>\$filter_id,
'format|f=s' =>\$format, 'format|f=s' =>\$format,
'rate|r=f' =>\$rate, 'rate|r=f' =>\$rate,
'scale|s=f' =>\$scale, 'scale|s=f' =>\$scale,
@ -115,51 +106,51 @@ GetOptions(
'size|S=s' =>\$size, 'size|S=s' =>\$size,
'overwrite' =>\$overwrite, 'overwrite' =>\$overwrite,
'version' =>\$version 'version' =>\$version
) or pod2usage(-exitstatus => -1); ) or pod2usage(-exitstatus => -1);
if ( $version ) { if ( $version ) {
print ZoneMinder::Base::ZM_VERSION . "\n"; print ZoneMinder::Base::ZM_VERSION . "\n";
exit(0); exit(0);
} }
if ( !( $filter_id or $filter_name or $event_id ) || $event_id < 0 ) if ( !( $filter_id or $filter_name or $event_id ) || ($event_id and ( $event_id < 0 ) ) ) {
{ print( STDERR "Please give a valid event id or filter name\n" );
print( STDERR "Please give a valid event id or filter name\n" ); pod2usage(-exitstatus => -1);
pod2usage(-exitstatus => -1);
} }
if ( ! $Config{ZM_OPT_FFMPEG} ) if ( ! $Config{ZM_OPT_FFMPEG} ) {
{ print( STDERR "Mpeg encoding is not currently enabled\n" );
print( STDERR "Mpeg encoding is not currently enabled\n" ); exit(-1);
exit(-1);
} }
if ( !$rate && !$fps ) my @formats = split( /\s+/, $Config{ZM_FFMPEG_FORMATS} );
{ for ( my $i = 0; $i < @formats; $i++ ) {
$rate = 1; if ( $i =~ /^(.+)\*$/ ) {
$format = $formats[$i] = $1;
}
} }
if ( !$scale && !$size ) if ( !$rate && !$fps ) {
{ $rate = 1;
$scale = 1;
} }
if ( $rate && ($rate < 0.25 || $rate > 100) ) if ( !$scale && !$size ) {
{ $scale = 1;
print( STDERR "Rate is out of range, 0.25 >= rate <= 100\n" );
pod2usage(-exitstatus => -1);
} }
if ( $scale && ($scale < 0.25 || $scale > 4) ) if ( $rate && ($rate < 0.25 || $rate > 100) ) {
{ print( STDERR "Rate is out of range, 0.25 >= rate <= 100\n" );
print( STDERR "Scale is out of range, 0.25 >= scale <= 4\n" ); pod2usage(-exitstatus => -1);
pod2usage(-exitstatus => -1);
} }
if ( $fps && ($fps > 30) ) if ( $scale && ($scale < 0.25 || $scale > 4) ) {
{ print( STDERR "Scale is out of range, 0.25 >= scale <= 4\n" );
print( STDERR "FPS is out of range, <= 30\n" ); pod2usage(-exitstatus => -1);
pod2usage(-exitstatus => -1); }
if ( $fps && ($fps > 30) ) {
print( STDERR "FPS is out of range, <= 30\n" );
pod2usage(-exitstatus => -1);
} }
my ( $detaint_format ) = $format =~ /^(\w+)$/; my ( $detaint_format ) = $format =~ /^(\w+)$/;
@ -181,19 +172,25 @@ my $cwd = getcwd;
my $video_name; my $video_name;
my @event_ids; my @event_ids;
if ( $event_id ) { if ( $event_id ) {
@event_ids = ( $event_id ); @event_ids = ( $event_id );
} elsif ( $filter_name or $filter_id ) { } elsif ( $filter_name or $filter_id ) {
my $Filter = ZoneMinder::Filter->find_one( my $Filter = ZoneMinder::Filter->find_one(
($filter_name ? ( Name => $filter_name ) : () ), ($filter_name ? ( Name => $filter_name ) : () ),
($filter_id ? ( Id => $filter_name ) : () ), ($filter_id ? ( Id => $filter_name ) : () ),
); );
if ( ! $Filter ) { if ( ! $Filter ) {
Fatal("Filter $filter_name $filter_id not found."); Fatal("Filter $filter_name $filter_id not found.");
} }
@event_ids = map { $_->{Id} }$Filter->Execute(); @event_ids = map { $_->{Id} } $Filter->Execute();
Fatal( "No events found for $filter_name") if ! @event_ids; if ( ! @event_ids ) {
$concat_name = $filter_name if $concat_name eq ''; Fatal( "No events found for $filter_name")
} else {
Debug(@event_ids . " events found for $filter_name");
}
$concat_name = $filter_name if $concat_name eq '';
} else {
Warning("Nothing to do");
} }
my $sql = " SELECT max(F.Delta)-min(F.Delta) as FullLength, my $sql = " SELECT max(F.Delta)-min(F.Delta) as FullLength,
@ -207,53 +204,54 @@ my $sql = " SELECT max(F.Delta)-min(F.Delta) as FullLength,
INNER JOIN Events as E on F.EventId = E.Id INNER JOIN Events as E on F.EventId = E.Id
INNER JOIN Monitors as M on E.MonitorId = M.Id INNER JOIN Monitors as M on E.MonitorId = M.Id
WHERE EventId = ? WHERE EventId = ?
GROUP BY F.EventId" GROUP BY F.EventId";
;
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
my @video_files; my @video_files;
foreach my $event_id ( @event_ids ) { foreach my $event_id ( @event_ids ) {
my $res = $sth->execute( $event_id )
or Fatal( "Can't execute: ".$sth->errstr() );
my $event = $sth->fetchrow_hashref();
my $res = $sth->execute( $event_id ) my $Event = new ZoneMinder::Event( $$event{Id}, $event );
or Fatal( "Can't execute: ".$sth->errstr() ); my $video_file = $Event->GenerateVideo( $rate, $fps, $scale, $size, $overwrite, $format );
my $event = $sth->fetchrow_hashref(); if ( $video_file ) {
push @video_files, $video_file;
my $Event = new ZoneMinder::Event( $$event{Id}, $event ); print( STDOUT $video_file."\n" );
my $video_file = $Event->GenerateVideo( $rate, $fps, $scale, $size, $overwrite, $format ); } else {
if ( $video_file ) { Warning("No video file generated for event $event_id");
push @video_files, $video_file; }
print( STDOUT $video_file."\n" );
}
} # end foreach event_id } # end foreach event_id
if ( $concat_name ) { if ( $concat_name ) {
($cwd) = $cwd =~ /(.*)/; # detaint ($cwd) = $cwd =~ /(.*)/; # detaint
chdir( $cwd ); chdir( $cwd );
($concat_name ) = $concat_name =~ /([\-A-Za-z0-9_\.]*)/; ($concat_name ) = $concat_name =~ /([\-A-Za-z0-9_\.]*)/;
my $concat_list_file = "/tmp/$concat_name.concat.lst"; my $concat_list_file = "/tmp/$concat_name.concat.lst";
my $video_file = $concat_name . '.'. $detaint_format; my $video_file = $concat_name . '.'. $detaint_format;
open( my $fd, '>', $concat_list_file ) or die "Can't open $concat_list_file: $!"; open( my $fd, '>', $concat_list_file ) or die "Can't open $concat_list_file: $!";
foreach ( @video_files ) { foreach ( @video_files ) {
print $fd "file '$_'\n"; print $fd "file '$_'\n";
} }
close $fd; close $fd;
my $command = $Config{ZM_PATH_FFMPEG} my $command = $Config{ZM_PATH_FFMPEG}
. " -f concat -i $concat_list_file -c copy " . " -f concat -i $concat_list_file -c copy "
." '$video_file' > ffmpeg.log 2>&1" ." '$video_file' > ffmpeg.log 2>&1"
; ;
Debug( $command."\n" ); Debug( $command."\n" );
my $output = qx($command); my $output = qx($command);
my $status = $? >> 8; my $status = $? >> 8;
unlink $concat_list_file; unlink $concat_list_file;
if ( $status ) if ( $status ) {
{ Error( "Unable to generate video, check /ffmpeg.log for details");
Error( "Unable to generate video, check /ffmpeg.log for details"); exit(-1);
exit(-1); }
} print( STDOUT $video_file."\n" );
print( STDOUT $video_file."\n" );
} }
exit( 0 ); exit( 0 );
__END__

View File

@ -32,8 +32,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <limits.h> #include <limits.h>
/* Workaround for GNU/kFreeBSD */ /* Workaround for GNU/kFreeBSD and FreeBSD */
#if defined(__FreeBSD_kernel__) #if defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
#ifndef ENODATA #ifndef ENODATA
#define ENODATA ENOATTR #define ENODATA ENOATTR
#endif #endif

View File

@ -24,6 +24,10 @@ extern "C" {
#include <libavformat/avformat.h> #include <libavformat/avformat.h>
} }
#ifdef __FreeBSD__
#include <sys/time.h>
#endif // __FreeBSD__
class ZMPacket { class ZMPacket {
public: public:

View File

@ -1,30 +1,30 @@
#ifdef HAVE_SENDFILE4_SUPPORT #ifdef HAVE_SENDFILE4_SUPPORT
#include <sys/sendfile.h> #include <sys/sendfile.h>
int zm_sendfile(int out_fd, int in_fd, off_t *offset, size_t size) { int zm_sendfile(int out_fd, int in_fd, off_t *offset, size_t size) {
int err; int err;
err = sendfile(out_fd, in_fd, offset, size); err = sendfile(out_fd, in_fd, offset, size);
if (err < 0) if (err < 0)
return -errno; return -errno;
return err; return err;
} }
#elif HAVE_SENDFILE7_SUPPORT #elif HAVE_SENDFILE7_SUPPORT
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/uio.h> #include <sys/uio.h>
int zm_sendfile(int out_fd, int in_fd, off_t *offset, off_t size) { int zm_sendfile(int out_fd, int in_fd, off_t *offset, off_t size) {
int err; int err;
err = sendfile(in_fd, out_fd, *offset, size, NULL, &size, 0); err = sendfile(in_fd, out_fd, *offset, size, NULL, &size, 0);
if (err && errno != EAGAIN) if (err && errno != EAGAIN)
return -errno; return -errno;
if (size) { if (size) {
*offset += size; *offset += size;
return size; return size;
} }
return -EAGAIN; return -EAGAIN;
} }
#else #else
#error "Your platform does not support sendfile. Sorry." #error "Your platform does not support sendfile. Sorry."

View File

@ -63,13 +63,13 @@ RETSIGTYPE zm_die_handler(int signal)
ucontext_t *uc = (ucontext_t *) context; ucontext_t *uc = (ucontext_t *) context;
cr2 = info->si_addr; cr2 = info->si_addr;
#if defined(__x86_64__) #if defined(__x86_64__)
#ifdef __FreeBSD_kernel__ #if defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
ip = (void *)(uc->uc_mcontext.mc_rip); ip = (void *)(uc->uc_mcontext.mc_rip);
#else #else
ip = (void *)(uc->uc_mcontext.gregs[REG_RIP]); ip = (void *)(uc->uc_mcontext.gregs[REG_RIP]);
#endif #endif
#else #else
#ifdef __FreeBSD_kernel__ #if defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
ip = (void *)(uc->uc_mcontext.mc_eip); ip = (void *)(uc->uc_mcontext.mc_eip);
#else #else
ip = (void *)(uc->uc_mcontext.gregs[REG_EIP]); ip = (void *)(uc->uc_mcontext.gregs[REG_EIP]);

View File

@ -1,3 +1,4 @@
// Copyright (C) 2001-2017 ZoneMinder LLC
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2 // as published by the Free Software Foundation; either version 2
@ -18,505 +19,559 @@
#include "zm_utils.h" #include "zm_utils.h"
#include "zm_rgb.h" #include "zm_rgb.h"
#include <sstream> #include <sstream>
#include <string>
#include <vector>
VideoWriter::VideoWriter(const char* p_container, const char* p_codec, const char* p_path, const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder) : VideoWriter::VideoWriter(
container(p_container), codec(p_codec), path(p_path), width(p_width), height(p_height), colours(p_colours), subpixelorder(p_subpixelorder), frame_count(0) { const char* p_container,
Debug(7,"Video object created"); const char* p_codec,
const char* p_path,
/* Parameter checking */ const unsigned int p_width,
if(path.empty()) { const unsigned int p_height,
Error("Invalid file path"); const unsigned int p_colours,
} const unsigned int p_subpixelorder) :
if(!width || !height) { container(p_container),
Error("Invalid width or height"); codec(p_codec),
} path(p_path),
width(p_width),
height(p_height),
colours(p_colours),
subpixelorder(p_subpixelorder),
frame_count(0) {
Debug(7, "Video object created");
/* Parameter checking */
if ( path.empty() ) {
Error("Invalid file path");
}
if ( !width || !height ) {
Error("Invalid width or height");
}
} }
VideoWriter::~VideoWriter() { VideoWriter::~VideoWriter() {
Debug(7,"Video object destroyed"); Debug(7, "Video object destroyed");
} }
int VideoWriter::Reset(const char* new_path) { int VideoWriter::Reset(const char* new_path) {
/* Common variables reset */ /* Common variables reset */
/* If there is a new path, use it */ /* If there is a new path, use it */
if(new_path != NULL) { if ( new_path != NULL ) {
path = new_path; path = new_path;
} }
/* Reset frame counter */ /* Reset frame counter */
frame_count = 0; frame_count = 0;
return 0; return 0;
} }
#if ZM_HAVE_VIDEOWRITER_X264MP4 #if ZM_HAVE_VIDEOWRITER_X264MP4
X264MP4Writer::X264MP4Writer(const char* p_path, const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder, const std::vector<EncoderParameter_t>* p_user_params) : VideoWriter("mp4", "h264", p_path, p_width, p_height, p_colours, p_subpixelorder), bOpen(false), bGotH264AVCInfo(false), bFirstFrame(true) { X264MP4Writer::X264MP4Writer(
const char* p_path,
const unsigned int p_width,
const unsigned int p_height,
const unsigned int p_colours,
const unsigned int p_subpixelorder,
const std::vector<EncoderParameter_t>* p_user_params) :
VideoWriter(
"mp4",
"h264",
p_path,
p_width,
p_height,
p_colours,
p_subpixelorder),
bOpen(false),
bGotH264AVCInfo(false),
bFirstFrame(true) {
/* Initialize ffmpeg if it hasn't been initialized yet */
FFMPEGInit();
/* Initialize ffmpeg if it hasn't been initialized yet */ /* Initialize swscale */
FFMPEGInit(); zm_pf = GetFFMPEGPixelFormat(colours, subpixelorder);
if ( zm_pf == 0 ) {
Error("Unable to match ffmpeg pixelformat");
}
codec_pf = AV_PIX_FMT_YUV420P;
/* Initialize swscale */ swscaleobj.SetDefaults(zm_pf, codec_pf, width, height);
zm_pf = GetFFMPEGPixelFormat(colours,subpixelorder);
if(zm_pf == 0) {
Error("Unable to match ffmpeg pixelformat");
}
codec_pf = AV_PIX_FMT_YUV420P;
swscaleobj.SetDefaults(zm_pf, codec_pf, width, height); /* Calculate the image sizes. We will need this for parameter checking */
zm_imgsize = colours * width * height;
/* Calculate the image sizes. We will need this for parameter checking */
zm_imgsize = colours * width * height;
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
codec_imgsize = av_image_get_buffer_size( codec_pf, width, height, 1 ); codec_imgsize = av_image_get_buffer_size(codec_pf, width, height, 1);
#else #else
codec_imgsize = avpicture_get_size( codec_pf, width, height); codec_imgsize = avpicture_get_size(codec_pf, width, height);
#endif #endif
if(!codec_imgsize) { if ( !codec_imgsize ) {
Error("Failed calculating codec pixel format image size"); Error("Failed calculating codec pixel format image size");
} }
/* If supplied with user parameters to the encoder, copy them */ /* If supplied with user parameters to the encoder, copy them */
if(p_user_params != NULL) { if ( p_user_params != NULL ) {
user_params = *p_user_params; user_params = *p_user_params;
} }
/* Setup x264 parameters */ /* Setup x264 parameters */
if(x264config() < 0) { if ( x264config() < 0 ) {
Error("Failed setting x264 parameters"); Error("Failed setting x264 parameters");
} }
/* Allocate x264 input picture */
x264_picture_alloc(&x264picin, X264_CSP_I420, x264params.i_width, x264params.i_height);
/* Allocate x264 input picture */
x264_picture_alloc(
&x264picin,
X264_CSP_I420,
x264params.i_width,
x264params.i_height);
} }
X264MP4Writer::~X264MP4Writer() { X264MP4Writer::~X264MP4Writer() {
/* Free x264 input picture */
x264_picture_clean(&x264picin);
/* Free x264 input picture */ if ( bOpen )
x264_picture_clean(&x264picin); Close();
if(bOpen)
Close();
} }
int X264MP4Writer::Open() { int X264MP4Writer::Open() {
/* Open the encoder */
x264enc = x264_encoder_open(&x264params);
if ( x264enc == NULL ) {
Error("Failed opening x264 encoder");
return -1;
}
/* Open the encoder */ // Debug(4,"x264 maximum delayed frames: %d",
x264enc = x264_encoder_open(&x264params); // x264_encoder_maximum_delayed_frames(x264enc));
if(x264enc == NULL) {
Error("Failed opening x264 encoder");
return -1;
}
// Debug(4,"x264 maximum delayed frames: %d",x264_encoder_maximum_delayed_frames(x264enc)); x264_nal_t* nals;
int i_nals;
if ( !x264_encoder_headers(x264enc, &nals, &i_nals) ) {
Error("Failed getting encoder headers");
return -2;
}
x264_nal_t* nals; /* Search SPS NAL for AVC information */
int i_nals; for ( unsigned int i = 0; i < i_nals; i++ ) {
if(!x264_encoder_headers(x264enc,&nals,&i_nals)) { if ( nals[i].i_type == NAL_SPS ) {
Error("Failed getting encoder headers"); x264_profleindication = nals[i].p_payload[5];
return -2; x264_profilecompat = nals[i].p_payload[6];
} x264_levelindication = nals[i].p_payload[7];
bGotH264AVCInfo = true;
break;
}
}
if ( !bGotH264AVCInfo ) {
Warning("Missing AVC information");
}
/* Search SPS NAL for AVC information */ /* Create the file */
for(int i=0;i<i_nals;i++) { mp4h = MP4Create((path + ".incomplete").c_str());
if(nals[i].i_type == NAL_SPS) { if ( mp4h == MP4_INVALID_FILE_HANDLE ) {
x264_profleindication = nals[i].p_payload[5]; Error("Failed creating mp4 file: %s", path.c_str());
x264_profilecompat = nals[i].p_payload[6]; return -10;
x264_levelindication = nals[i].p_payload[7]; }
bGotH264AVCInfo = true;
break;
}
}
if(!bGotH264AVCInfo) {
Warning("Missing AVC information");
}
/* Create the file */ /* Set the global timescale */
mp4h = MP4Create((path + ".incomplete").c_str()); if ( !MP4SetTimeScale(mp4h, 1000) ) {
if(mp4h == MP4_INVALID_FILE_HANDLE) { Error("Failed setting timescale");
Error("Failed creating mp4 file: %s",path.c_str()); return -11;
return -10; }
}
/* Set the global timescale */ /* Set the global video profile */
if(!MP4SetTimeScale(mp4h, 1000)) { /* I am a bit confused about this one.
Error("Failed setting timescale"); I couldn't find what the value should be
return -11; Some use 0x15 while others use 0x7f. */
} MP4SetVideoProfileLevel(mp4h, 0x7f);
/* Set the global video profile */ /* Add H264 video track */
/* I am a bit confused about this one. mp4vtid = MP4AddH264VideoTrack(
I couldn't find what the value should be mp4h,
Some use 0x15 while others use 0x7f. */ 1000,
MP4SetVideoProfileLevel(mp4h, 0x7f); MP4_INVALID_DURATION,
width,
height,
x264_profleindication,
x264_profilecompat,
x264_levelindication,
3);
if ( mp4vtid == MP4_INVALID_TRACK_ID ) {
Error("Failed adding H264 video track");
return -12;
}
/* Add H264 video track */ bOpen = true;
mp4vtid = MP4AddH264VideoTrack(mp4h,1000,MP4_INVALID_DURATION,width,height,x264_profleindication,x264_profilecompat,x264_levelindication,3);
if(mp4vtid == MP4_INVALID_TRACK_ID) {
Error("Failed adding H264 video track");
return -12;
}
bOpen = true; return 0;
return 0;
} }
int X264MP4Writer::Close() { int X264MP4Writer::Close() {
/* Flush all pending frames */
for ( int i = (x264_encoder_delayed_frames(x264enc) + 1); i > 0; i-- ) {
x264encodeloop(true);
}
/* Flush all pending frames */ /* Close the encoder */
for(int i = (x264_encoder_delayed_frames(x264enc) + 1); i > 0; i-- ) { x264_encoder_close(x264enc);
x264encodeloop(true);
}
/* Close the encoder */ /* Close MP4 handle */
x264_encoder_close(x264enc); MP4Close(mp4h);
/* Close MP4 handle */ /* Required for proper HTTP streaming */
MP4Close(mp4h); MP4Optimize((path + ".incomplete").c_str(), path.c_str());
/* Required for proper HTTP streaming */ /* Delete the temporary file */
MP4Optimize((path + ".incomplete").c_str(), path.c_str()); unlink((path + ".incomplete").c_str());
/* Delete the temporary file */ bOpen = false;
unlink((path + ".incomplete").c_str());
bOpen = false; Debug(7, "Video closed. Total frames: %d", frame_count);
Debug(7, "Video closed. Total frames: %d", frame_count); return 0;
return 0;
} }
int X264MP4Writer::Reset(const char* new_path) { int X264MP4Writer::Reset(const char* new_path) {
/* Close the encoder and file */
if ( bOpen )
Close();
/* Close the encoder and file */ /* Reset common variables */
if(bOpen) VideoWriter::Reset(new_path);
Close();
/* Reset common variables */ /* Reset local variables */
VideoWriter::Reset(new_path); bFirstFrame = true;
bGotH264AVCInfo = false;
prevnals.clear();
prevpayload.clear();
/* Reset local variables */ /* Reset x264 parameters */
bFirstFrame = true; x264config();
bGotH264AVCInfo = false;
prevnals.clear();
prevpayload.clear();
/* Reset x264 parameters */ /* Open the encoder */
x264config(); Open();
/* Open the encoder */ return 0;
Open();
return 0;
} }
int X264MP4Writer::Encode(const uint8_t* data, const size_t data_size, const unsigned int frame_time) { int X264MP4Writer::Encode(
const uint8_t* data,
const size_t data_size,
const unsigned int frame_time) {
/* Parameter checking */
if ( data == NULL ) {
Error("NULL buffer");
return -1;
}
/* Parameter checking */ if ( data_size != zm_imgsize ) {
if(data == NULL) { Error("The data buffer size (%d) != expected (%d)", data_size, zm_imgsize);
Error("NULL buffer"); return -2;
return -1; }
}
if(data_size != zm_imgsize) { if ( !bOpen ) {
Error("The data buffer size does not match the expected size. Expected: %d Current: %d", zm_imgsize, data_size); Warning("The encoder was not initialized, initializing now");
return -2; Open();
} }
if(!bOpen) { /* Convert the image into the x264 input picture */
Warning("The encoder was not initialized, initializing now"); if ( swscaleobj.ConvertDefaults(data, data_size, x264picin.img.plane[0], codec_imgsize) < 0 ) {
Open(); Error("Image conversion failed");
} return -3;
}
/* Convert the image into the x264 input picture */ /* Set PTS */
if(swscaleobj.ConvertDefaults(data, data_size, x264picin.img.plane[0], codec_imgsize) < 0) { x264picin.i_pts = frame_time;
Error("Image conversion failed");
return -3;
}
/* Set PTS */ /* Do the encoding */
x264picin.i_pts = frame_time; x264encodeloop();
/* Do the encoding */ /* Increment frame counter */
x264encodeloop(); frame_count++;
/* Increment frame counter */ return 0;
frame_count++;
return 0;
} }
int X264MP4Writer::Encode(const Image* img, const unsigned int frame_time) { int X264MP4Writer::Encode(const Image* img, const unsigned int frame_time) {
if ( img->Width() != width ) {
Error("Source image width differs. Source: %d Output: %d", img->Width(), width);
return -12;
}
if(img->Width() != width) { if ( img->Height() != height ) {
Error("Source image width differs. Source: %d Output: %d",img->Width(), width); Error("Source image height differs. Source: %d Output: %d", img->Height(), height);
return -12; return -13;
} }
if(img->Height() != height) { return Encode(img->Buffer(), img->Size(), frame_time);
Error("Source image height differs. Source: %d Output: %d",img->Height(), height);
return -13;
}
return Encode(img->Buffer(),img->Size(),frame_time);
} }
int X264MP4Writer::x264config() { int X264MP4Writer::x264config() {
/* Sets up the encoder configuration */ /* Sets up the encoder configuration */
int x264ret; int x264ret;
/* Defaults */ /* Defaults */
const char* preset = "veryfast"; const char* preset = "veryfast";
const char* tune = "stillimage"; const char* tune = "stillimage";
const char* profile = "main"; const char* profile = "main";
/* Search the user parameters for preset, tune and profile */ /* Search the user parameters for preset, tune and profile */
for(unsigned int i=0; i < user_params.size(); i++) { for ( unsigned int i = 0; i < user_params.size(); i++ ) {
if(strcmp(user_params[i].pname, "preset") == 0) { if ( strcmp(user_params[i].pname, "preset") == 0 ) {
/* Got preset */ /* Got preset */
preset = user_params[i].pvalue; preset = user_params[i].pvalue;
} else if(strcmp(user_params[i].pname, "tune") == 0) { } else if ( strcmp(user_params[i].pname, "tune") == 0 ) {
/* Got tune */ /* Got tune */
tune = user_params[i].pvalue; tune = user_params[i].pvalue;
} else if(strcmp(user_params[i].pname, "profile") == 0) { } else if ( strcmp(user_params[i].pname, "profile") == 0 ) {
/* Got profile */ /* Got profile */
profile = user_params[i].pvalue; profile = user_params[i].pvalue;
} }
} }
/* Set the defaults and preset and tune */ /* Set the defaults and preset and tune */
x264ret = x264_param_default_preset(&x264params, preset, tune); x264ret = x264_param_default_preset(&x264params, preset, tune);
if(x264ret != 0) { if ( x264ret != 0 ) {
Error("Failed setting x264 preset %s and tune %s : %d",preset,tune,x264ret); Error("Failed setting x264 preset %s and tune %s : %d", preset, tune, x264ret);
} }
/* Set the profile */ /* Set the profile */
x264ret = x264_param_apply_profile(&x264params, profile); x264ret = x264_param_apply_profile(&x264params, profile);
if(x264ret != 0) { if ( x264ret != 0 ) {
Error("Failed setting x264 profile %s : %d",profile,x264ret); Error("Failed setting x264 profile %s : %d", profile, x264ret);
} }
/* Input format */ /* Input format */
x264params.i_width = width; x264params.i_width = width;
x264params.i_height = height; x264params.i_height = height;
x264params.i_csp = X264_CSP_I420; x264params.i_csp = X264_CSP_I420;
/* Quality control */ /* Quality control */
x264params.rc.i_rc_method = X264_RC_CRF; x264params.rc.i_rc_method = X264_RC_CRF;
x264params.rc.f_rf_constant = 23.0; x264params.rc.f_rf_constant = 23.0;
/* Enable b-frames */ /* Enable b-frames */
x264params.i_bframe = 16; x264params.i_bframe = 16;
x264params.i_bframe_adaptive = 1; x264params.i_bframe_adaptive = 1;
/* Timebase */ /* Timebase */
x264params.i_timebase_num = 1; x264params.i_timebase_num = 1;
x264params.i_timebase_den = 1000; x264params.i_timebase_den = 1000;
/* Enable variable frame rate */ /* Enable variable frame rate */
x264params.b_vfr_input = 1; x264params.b_vfr_input = 1;
/* Disable annex-b (start codes) */ /* Disable annex-b (start codes) */
x264params.b_annexb = 0; x264params.b_annexb = 0;
/* TODO: Setup error handler */ /* TODO: Setup error handler */
//x264params.i_log_level = X264_LOG_DEBUG; // x264params.i_log_level = X264_LOG_DEBUG;
/* Process user parameters (excluding preset, tune and profile) */ /* Process user parameters (excluding preset, tune and profile) */
for(unsigned int i=0; i < user_params.size(); i++) { for ( unsigned int i = 0; i < user_params.size(); i++ ) {
/* Skip preset, tune and profile */ /* Skip preset, tune and profile */
if( (strcmp(user_params[i].pname, "preset") == 0) || (strcmp(user_params[i].pname, "tune") == 0) || (strcmp(user_params[i].pname, "profile") == 0) ) { if (
continue; (strcmp(user_params[i].pname, "preset") == 0) ||
} (strcmp(user_params[i].pname, "tune") == 0) ||
(strcmp(user_params[i].pname, "profile") == 0) ) {
continue;
}
/* Pass the name and value to x264 */ /* Pass the name and value to x264 */
x264ret = x264_param_parse(&x264params, user_params[i].pname, user_params[i].pvalue); x264ret = x264_param_parse(&x264params, user_params[i].pname, user_params[i].pvalue);
/* Error checking */ /* Error checking */
if(x264ret != 0) { if ( x264ret != 0 ) {
if(x264ret == X264_PARAM_BAD_NAME) { if ( x264ret == X264_PARAM_BAD_NAME ) {
Error("Failed processing x264 user parameter %s=%s : Bad name", user_params[i].pname, user_params[i].pvalue); Error("Failed processing x264 user parameter %s=%s : Bad name",
} else if(x264ret == X264_PARAM_BAD_VALUE) { user_params[i].pname, user_params[i].pvalue);
Error("Failed processing x264 user parameter %s=%s : Bad value", user_params[i].pname, user_params[i].pvalue); } else if ( x264ret == X264_PARAM_BAD_VALUE ) {
} else { Error("Failed processing x264 user parameter %s=%s : Bad value",
Error("Failed processing x264 user parameter %s=%s : Unknown error (%d)", user_params[i].pname, user_params[i].pvalue, x264ret); user_params[i].pname, user_params[i].pvalue);
} } else {
} Error("Failed processing x264 user parameter %s=%s : Unknown error (%d)",
} user_params[i].pname, user_params[i].pvalue, x264ret);
}
}
}
return 0; return 0;
} }
void X264MP4Writer::x264encodeloop(bool bFlush) { void X264MP4Writer::x264encodeloop(bool bFlush) {
x264_nal_t* nals;
int i_nals;
int frame_size;
x264_nal_t* nals; if ( bFlush ) {
int i_nals; frame_size = x264_encoder_encode(x264enc, &nals, &i_nals, NULL, &x264picout);
int frame_size; } else {
frame_size = x264_encoder_encode(x264enc, &nals, &i_nals, &x264picin, &x264picout);
}
if(bFlush) { if ( frame_size > 0 || bFlush ) {
frame_size = x264_encoder_encode(x264enc, &nals, &i_nals, NULL, &x264picout); Debug(8, "x264 Frame: %d PTS: %d DTS: %d Size: %d\n",
} else { frame_count, x264picout.i_pts, x264picout.i_dts, frame_size);
frame_size = x264_encoder_encode(x264enc, &nals, &i_nals, &x264picin, &x264picout);
}
if (frame_size > 0 || bFlush) { /* Handle the previous frame */
Debug(8, "x264 Frame: %d PTS: %d DTS: %d Size: %d\n",frame_count, x264picout.i_pts, x264picout.i_dts, frame_size); if ( !bFirstFrame ) {
buffer.clear();
/* Handle the previous frame */ /* Process the NALs for the previous frame */
if(!bFirstFrame) { for ( unsigned int i = 0; i < prevnals.size(); i++ ) {
Debug(9, "Processing NAL: Type %d Size %d",
prevnals[i].i_type,
prevnals[i].i_payload);
buffer.clear(); switch ( prevnals[i].i_type ) {
case NAL_PPS:
/* PPS NAL */
MP4AddH264PictureParameterSet(mp4h, mp4vtid, prevnals[i].p_payload+4, prevnals[i].i_payload-4);
break;
case NAL_SPS:
/* SPS NAL */
MP4AddH264SequenceParameterSet(mp4h, mp4vtid, prevnals[i].p_payload+4, prevnals[i].i_payload-4);
break;
default:
/* Anything else, hopefully frames, so copy it into the sample */
buffer.append(prevnals[i].p_payload, prevnals[i].i_payload);
}
}
/* Process the NALs for the previous frame */ /* Calculate frame duration and offset */
for(unsigned int i=0; i < prevnals.size(); i++) { int duration = x264picout.i_dts - prevDTS;
Debug(9,"Processing NAL: Type %d Size %d",prevnals[i].i_type,prevnals[i].i_payload); int offset = prevPTS - prevDTS;
switch(prevnals[i].i_type) { /* Write the sample */
case NAL_PPS: if ( !buffer.empty() ) {
/* PPS NAL */ if ( !MP4WriteSample(
MP4AddH264PictureParameterSet(mp4h, mp4vtid, prevnals[i].p_payload+4, prevnals[i].i_payload-4); mp4h,
break; mp4vtid,
case NAL_SPS: buffer.extract(buffer.size()),
/* SPS NAL */ buffer.size(),
MP4AddH264SequenceParameterSet(mp4h, mp4vtid, prevnals[i].p_payload+4, prevnals[i].i_payload-4); duration,
break; offset,
default: prevKeyframe) ) {
/* Anything else, hopefully frames, so copy it into the sample */ Error("Failed writing sample");
buffer.append(prevnals[i].p_payload, prevnals[i].i_payload); }
} }
}
/* Calculate frame duration and offset */ /* Cleanup */
int duration = x264picout.i_dts - prevDTS; prevnals.clear();
int offset = prevPTS - prevDTS; prevpayload.clear();
}
/* Write the sample */ /* Got a frame. Copy this new frame into the previous frame */
if(!buffer.empty()) { if ( frame_size > 0 ) {
if(!MP4WriteSample(mp4h, mp4vtid, buffer.extract(buffer.size()), buffer.size(), duration, offset, prevKeyframe)) { /* Copy the NALs and the payloads */
Error("Failed writing sample"); for ( unsigned int i = 0; i < i_nals; i++ ) {
} prevnals.push_back(nals[i]);
} prevpayload.append(nals[i].p_payload, nals[i].i_payload);
}
/* Cleanup */ /* Update the payload pointers */
prevnals.clear(); /* This is done in a separate loop because the previous loop might reallocate memory when appending,
prevpayload.clear(); making the pointers invalid */
unsigned int payload_offset = 0;
for ( unsigned int i = 0; i < prevnals.size(); i++ ) {
prevnals[i].p_payload = prevpayload.head() + payload_offset;
payload_offset += nals[i].i_payload;
}
} /* We need this for the next frame */
prevPTS = x264picout.i_pts;
prevDTS = x264picout.i_dts;
prevKeyframe = x264picout.b_keyframe;
/* Got a frame. Copy this new frame into the previous frame */ bFirstFrame = false;
if(frame_size > 0) { }
/* Copy the NALs and the payloads */
for(int i=0;i<i_nals;i++) {
prevnals.push_back(nals[i]); } else if ( frame_size == 0 ) {
prevpayload.append(nals[i].p_payload, nals[i].i_payload); Debug(7, "x264 encode returned zero. Delayed frames: %d",
} x264_encoder_delayed_frames(x264enc));
} else {
/* Update the payload pointers */ Error("x264 encode failed: %d", frame_size);
/* This is done in a separate loop because the previous loop might reallocate memory when appending, }
making the pointers invalid */
unsigned int payload_offset = 0;
for(unsigned int i=0;i<prevnals.size();i++) {
prevnals[i].p_payload = prevpayload.head() + payload_offset;
payload_offset += nals[i].i_payload;
}
/* We need this for the next frame */
prevPTS = x264picout.i_pts;
prevDTS = x264picout.i_dts;
prevKeyframe = x264picout.b_keyframe;
bFirstFrame = false;
}
} else if(frame_size == 0) {
Debug(7,"x264 encode returned zero. Delayed frames: %d",x264_encoder_delayed_frames(x264enc));
} else {
Error("x264 encode failed: %d",frame_size);
}
} }
#endif // ZM_VIDEOWRITER_X264MP4 #endif // ZM_VIDEOWRITER_X264MP4
int ParseEncoderParameters(const char* str, std::vector<EncoderParameter_t>* vec) { int ParseEncoderParameters(
if(vec == NULL) { const char* str,
Error("NULL Encoder parameters vector pointer"); std::vector<EncoderParameter_t>* vec
return -1; ) {
} if ( vec == NULL ) {
Error("NULL Encoder parameters vector pointer");
return -1;
}
if(str == NULL) { if ( str == NULL ) {
Error("NULL Encoder parameters string"); Error("NULL Encoder parameters string");
return -2; return -2;
} }
vec->clear(); vec->clear();
if(str[0] == 0) { if ( str[0] == 0 ) {
/* Empty */ /* Empty */
return 0; return 0;
} }
std::string line; std::string line;
std::stringstream ss(str); std::stringstream ss(str);
size_t valueoffset; size_t valueoffset;
size_t valuelen; size_t valuelen;
unsigned int lineno = 0; unsigned int lineno = 0;
EncoderParameter_t param; EncoderParameter_t param;
while(std::getline(ss, line) ) { while ( std::getline(ss, line) ) {
lineno++; lineno++;
/* Remove CR if exists */ /* Remove CR if exists */
if(line.length() >= 1 && line[line.length()-1] == '\r') { if ( line.length() >= 1 && line[line.length()-1] == '\r' ) {
line.erase(line.length()-1); line.erase(line.length() - 1);
} }
/* Skip comments and empty lines */ /* Skip comments and empty lines */
if(line.empty() || line[0] == '#') { if ( line.empty() || line[0] == '#' ) {
continue; continue;
} }
valueoffset = line.find('='); valueoffset = line.find('=');
if(valueoffset == std::string::npos || valueoffset+1 >= line.length() || valueoffset == 0) { if ( valueoffset == std::string::npos || valueoffset+1 >= line.length() || valueoffset == 0 ) {
Warning("Failed parsing encoder parameters line %d: Invalid pair", lineno); Warning("Failed parsing encoder parameters line %d: Invalid pair", lineno);
continue; continue;
} }
if ( valueoffset > (sizeof(param.pname) - 1 ) ) {
Warning("Failed parsing encoder parameters line %d: Name too long", lineno);
continue;
}
if(valueoffset > (sizeof(param.pname)-1) ) { valuelen = line.length() - (valueoffset+1);
Warning("Failed parsing encoder parameters line %d: Name too long", lineno);
continue;
}
valuelen = line.length() - (valueoffset+1); if ( valuelen > (sizeof(param.pvalue) - 1 ) ) {
Warning("Failed parsing encoder parameters line %d: Value too long", lineno);
continue;
}
if( valuelen > (sizeof(param.pvalue)-1) ) { /* Copy and NULL terminate */
Warning("Failed parsing encoder parameters line %d: Value too long", lineno); line.copy(param.pname, valueoffset, 0);
continue; line.copy(param.pvalue, valuelen, valueoffset+1);
} param.pname[valueoffset] = 0;
param.pvalue[valuelen] = 0;
/* Copy and NULL terminate */ /* Push to the vector */
line.copy(param.pname, valueoffset, 0); vec->push_back(param);
line.copy(param.pvalue, valuelen, valueoffset+1);
param.pname[valueoffset] = 0;
param.pvalue[valuelen] = 0;
/* Push to the vector */ Debug(7, "Parsed encoder parameter: %s = %s", param.pname, param.pvalue);
vec->push_back(param); }
Debug(7, "Parsed encoder parameter: %s = %s", param.pname, param.pvalue); Debug(7, "Parsed %d lines", lineno);
}
Debug(7, "Parsed %d lines", lineno); return 0;
return 0;
} }

View File

@ -37,7 +37,7 @@ if [ "${TRAVIS_EVENT_TYPE}" == "cron" ]; then
# Don't keep packages older than 5 days # Don't keep packages older than 5 days
find ./zmrepo/$targetfolder/ -maxdepth 1 -type f -mtime +5 -delete find ./zmrepo/$targetfolder/ -maxdepth 1 -type f -mtime +5 -delete
rsync -vzh --ignore-errors build/* zmrepo/$targetfolder/ rsync -vzlh --ignore-errors build/* zmrepo/$targetfolder/
fusermount -zu zmrepo fusermount -zu zmrepo
else else
echo echo

View File

@ -176,8 +176,8 @@ if ( !empty($action) ) {
} else { } else {
Error("No new Id despite new name"); Error("No new Id despite new name");
} }
$refreshParent = '/index.php?view=filter&Id='.$_REQUEST['Id'];
} }
$refreshParent = '/index.php?view=filter&Id='.$_REQUEST['Id'];
} }
} // end if canedit events } // end if canedit events
} // end if action == filter } // end if action == filter

View File

@ -21,29 +21,26 @@
error_reporting( E_ALL ); error_reporting( E_ALL );
$debug = false; $debug = false;
if ( $debug ) if ( $debug ) {
{ // Use these for debugging, though not both at once!
// Use these for debugging, though not both at once! phpinfo( INFO_VARIABLES );
phpinfo( INFO_VARIABLES ); //error_reporting( E_ALL );
//error_reporting( E_ALL );
} }
// Use new style autoglobals where possible // Use new style autoglobals where possible
if ( version_compare( phpversion(), "4.1.0", "<") ) if ( version_compare( phpversion(), '4.1.0', '<') ) {
{ $_SESSION = &$HTTP_SESSION_VARS;
$_SESSION = &$HTTP_SESSION_VARS; $_SERVER = &$HTTP_SERVER_VARS;
$_SERVER = &$HTTP_SERVER_VARS;
} }
// Useful debugging lines for mobile devices // Useful debugging lines for mobile devices
if ( false ) if ( false ) {
{ ob_start();
ob_start(); phpinfo( INFO_VARIABLES );
phpinfo( INFO_VARIABLES ); $fp = fopen( '/tmp/env.html', 'w' );
$fp = fopen( "/tmp/env.html", "w" ); fwrite( $fp, ob_get_contents() );
fwrite( $fp, ob_get_contents() ); fclose( $fp );
fclose( $fp ); ob_end_clean();
ob_end_clean();
} }
require_once( 'includes/config.php' ); require_once( 'includes/config.php' );
@ -53,26 +50,23 @@ require_once( 'includes/Storage.php' );
require_once( 'includes/Event.php' ); require_once( 'includes/Event.php' );
require_once( 'includes/Monitor.php' ); require_once( 'includes/Monitor.php' );
if ( isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == 'on' ) if ( isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' ) {
{ $protocol = 'https';
$protocol = 'https'; } else {
$protocol = 'http';
} }
else define( 'ZM_BASE_PROTOCOL', $protocol );
{
$protocol = 'http';
}
define( "ZM_BASE_PROTOCOL", $protocol );
// Absolute URL's are unnecessary and break compatibility with reverse proxies // Absolute URL's are unnecessary and break compatibility with reverse proxies
// define( "ZM_BASE_URL", $protocol.'://'.$_SERVER['HTTP_HOST'] ); // define( "ZM_BASE_URL", $protocol.'://'.$_SERVER['HTTP_HOST'] );
// Use relative URL's instead // Use relative URL's instead
define( "ZM_BASE_URL", "" ); define( 'ZM_BASE_URL', '' );
// Check time zone is set // Check time zone is set
if (!ini_get('date.timezone') || !date_default_timezone_set(ini_get('date.timezone'))) { if (!ini_get('date.timezone') || !date_default_timezone_set(ini_get('date.timezone'))) {
date_default_timezone_set('UTC'); date_default_timezone_set('UTC');
Fatal( "ZoneMinder is not installed properly: php's date.timezone is not set to a valid timezone" ); Fatal( "ZoneMinder is not installed properly: php's date.timezone is not set to a valid timezone" );
} }
if ( isset($_GET['skin']) ) if ( isset($_GET['skin']) )
@ -82,7 +76,7 @@ elseif ( isset($_COOKIE['zmSkin']) )
elseif ( defined('ZM_SKIN_DEFAULT') ) elseif ( defined('ZM_SKIN_DEFAULT') )
$skin = ZM_SKIN_DEFAULT; $skin = ZM_SKIN_DEFAULT;
else else
$skin = "classic"; $skin = 'classic';
$skins = array_map( 'basename', glob('skins/*',GLOB_ONLYDIR) ); $skins = array_map( 'basename', glob('skins/*',GLOB_ONLYDIR) );
if ( ! in_array( $skin, $skins ) ) { if ( ! in_array( $skin, $skins ) ) {
@ -97,7 +91,7 @@ elseif ( isset($_COOKIE['zmCSS']) )
elseif (defined('ZM_CSS_DEFAULT')) elseif (defined('ZM_CSS_DEFAULT'))
$css = ZM_CSS_DEFAULT; $css = ZM_CSS_DEFAULT;
else else
$css = "classic"; $css = 'classic';
$css_skins = array_map( 'basename', glob('skins/'.$skin.'/css/*',GLOB_ONLYDIR) ); $css_skins = array_map( 'basename', glob('skins/'.$skin.'/css/*',GLOB_ONLYDIR) );
if ( ! in_array( $css, $css_skins ) ) { if ( ! in_array( $css, $css_skins ) ) {
@ -105,9 +99,9 @@ if ( ! in_array( $css, $css_skins ) ) {
$css = $css_skins[0]; $css = $css_skins[0];
} }
define( "ZM_BASE_PATH", dirname( $_SERVER['REQUEST_URI'] ) ); define( 'ZM_BASE_PATH', dirname( $_SERVER['REQUEST_URI'] ) );
define( "ZM_SKIN_NAME", $skin ); define( 'ZM_SKIN_NAME', $skin );
define( "ZM_SKIN_PATH", "skins/$skin" ); define( 'ZM_SKIN_PATH', "skins/$skin" );
$skinBase = array(); // To allow for inheritance of skins $skinBase = array(); // To allow for inheritance of skins
if ( !file_exists( ZM_SKIN_PATH ) ) if ( !file_exists( ZM_SKIN_PATH ) )
@ -117,26 +111,25 @@ $skinBase[] = $skin;
$currentCookieParams = session_get_cookie_params(); $currentCookieParams = session_get_cookie_params();
Logger::Debug('Setting cookie parameters to lifetime('.$currentCookieParams['lifetime'].') path('.$currentCookieParams['path'].') domain ('.$currentCookieParams['domain'].') secure('.$currentCookieParams['secure'].') httpOnly(1)'); Logger::Debug('Setting cookie parameters to lifetime('.$currentCookieParams['lifetime'].') path('.$currentCookieParams['path'].') domain ('.$currentCookieParams['domain'].') secure('.$currentCookieParams['secure'].') httpOnly(1)');
session_set_cookie_params( session_set_cookie_params(
$currentCookieParams["lifetime"], $currentCookieParams['lifetime'],
$currentCookieParams["path"], $currentCookieParams['path'],
$currentCookieParams["domain"], $currentCookieParams['domain'],
$currentCookieParams["secure"], $currentCookieParams['secure'],
true true
); );
ini_set( "session.name", "ZMSESSID" ); ini_set( 'session.name', 'ZMSESSID' );
session_start(); session_start();
if ( !isset($_SESSION['skin']) || isset($_REQUEST['skin']) || !isset($_COOKIE['zmSkin']) || $_COOKIE['zmSkin'] != $skin ) if ( !isset($_SESSION['skin']) || isset($_REQUEST['skin']) || !isset($_COOKIE['zmSkin']) || $_COOKIE['zmSkin'] != $skin ) {
{
$_SESSION['skin'] = $skin; $_SESSION['skin'] = $skin;
setcookie( "zmSkin", $skin, time()+3600*24*30*12*10 ); setcookie( 'zmSkin', $skin, time()+3600*24*30*12*10 );
} }
if ( !isset($_SESSION['css']) || isset($_REQUEST['css']) || !isset($_COOKIE['zmCSS']) || $_COOKIE['zmCSS'] != $css ) { if ( !isset($_SESSION['css']) || isset($_REQUEST['css']) || !isset($_COOKIE['zmCSS']) || $_COOKIE['zmCSS'] != $css ) {
$_SESSION['css'] = $css; $_SESSION['css'] = $css;
setcookie( "zmCSS", $css, time()+3600*24*30*12*10 ); setcookie( 'zmCSS', $css, time()+3600*24*30*12*10 );
} }
if ( ZM_OPT_USE_AUTH ) if ( ZM_OPT_USE_AUTH )
@ -149,14 +142,12 @@ else
require_once( 'includes/lang.php' ); require_once( 'includes/lang.php' );
require_once( 'includes/functions.php' ); require_once( 'includes/functions.php' );
require_once( 'includes/csrf/csrf-magic.php' );
# Add Cross domain access headers # Add Cross domain access headers
CORSHeaders(); CORSHeaders();
// Check for valid content dirs // Check for valid content dirs
if ( !is_writable(ZM_DIR_EVENTS) || !is_writable(ZM_DIR_IMAGES) ) if ( !is_writable(ZM_DIR_EVENTS) || !is_writable(ZM_DIR_IMAGES) ) {
{
Error( "Cannot write to content dirs('".ZM_DIR_EVENTS."','".ZM_DIR_IMAGES."'). Check that these exist and are owned by the web account user"); Error( "Cannot write to content dirs('".ZM_DIR_EVENTS."','".ZM_DIR_IMAGES."'). Check that these exist and are owned by the web account user");
} }
@ -177,58 +168,51 @@ isset($view) || $view = NULL;
isset($request) || $request = NULL; isset($request) || $request = NULL;
isset($action) || $action = NULL; isset($action) || $action = NULL;
if ( ZM_ENABLE_CSRF_MAGIC && $action != 'login' ) { if ( ZM_ENABLE_CSRF_MAGIC && $action != 'login' && $view != 'view_video' ) {
Logger::Debug("Calling csrf_check with the following values: \$request = \"$request\", \$view = \"$view\", \$action = \"$action\""); require_once( 'includes/csrf/csrf-magic.php' );
csrf_check(); Logger::Debug("Calling csrf_check with the following values: \$request = \"$request\", \$view = \"$view\", \$action = \"$action\"");
csrf_check();
} }
require_once( 'includes/actions.php' ); require_once( 'includes/actions.php' );
# If I put this here, it protects all views and popups, but it has to go after actions.php because actions.php does the actual logging in. # If I put this here, it protects all views and popups, but it has to go after actions.php because actions.php does the actual logging in.
if ( ZM_OPT_USE_AUTH && ! isset($user) && $view != 'login' ) { if ( ZM_OPT_USE_AUTH && ! isset($user) && $view != 'login' ) {
$view = 'login'; $view = 'login';
} }
# Only one request can open the session file at a time, so let's close the session here to improve concurrency. # Only one request can open the session file at a time, so let's close the session here to improve concurrency.
# Any file/page that uses the session must re-open it. # Any file/page that uses the session must re-open it.
session_write_close(); session_write_close();
if ( isset( $_REQUEST['request'] ) ) if ( isset( $_REQUEST['request'] ) ) {
{ foreach ( getSkinIncludes( 'ajax/'.$request.'.php', true, true ) as $includeFile ) {
foreach ( getSkinIncludes( 'ajax/'.$request.'.php', true, true ) as $includeFile ) if ( !file_exists( $includeFile ) )
{ Fatal( "Request '$request' does not exist" );
if ( !file_exists( $includeFile ) ) require_once $includeFile;
Fatal( "Request '$request' does not exist" ); }
return;
} else {
if ( $includeFiles = getSkinIncludes( 'views/'.$view.'.php', true, true ) ) {
foreach ( $includeFiles as $includeFile ) {
if ( !file_exists( $includeFile ) )
Fatal( "View '$view' does not exist" );
require_once $includeFile;
}
// If the view overrides $view to 'error', and the user is not logged in, then the
// issue is probably resolvable by logging in, so provide the opportunity to do so.
// The login view should handle redirecting to the correct location afterward.
if ( $view == 'error' && !isset($user) ) {
$view = 'login';
foreach ( getSkinIncludes( 'views/login.php', true, true ) as $includeFile )
require_once $includeFile; require_once $includeFile;
} }
return; }
} // If the view is missing or the view still returned error with the user logged in,
else // then it is not recoverable.
{ if ( !$includeFiles || $view == 'error' ) {
if ( $includeFiles = getSkinIncludes( 'views/'.$view.'.php', true, true ) ) foreach ( getSkinIncludes( 'views/error.php', true, true ) as $includeFile )
{ require_once $includeFile;
foreach ( $includeFiles as $includeFile ) }
{
if ( !file_exists( $includeFile ) )
Fatal( "View '$view' does not exist" );
require_once $includeFile;
}
// If the view overrides $view to 'error', and the user is not logged in, then the
// issue is probably resolvable by logging in, so provide the opportunity to do so.
// The login view should handle redirecting to the correct location afterward.
if ( $view == 'error' && !isset($user) )
{
$view = 'login';
foreach ( getSkinIncludes( 'views/login.php', true, true ) as $includeFile )
require_once $includeFile;
}
}
// If the view is missing or the view still returned error with the user logged in,
// then it is not recoverable.
if ( !$includeFiles || $view == 'error' )
{
foreach ( getSkinIncludes( 'views/error.php', true, true ) as $includeFile )
require_once $includeFile;
}
} }
?> ?>