Merge branch 'storageareas' of github.com:connortechnology/ZoneMinder into storageareas

This commit is contained in:
Isaac Connor 2018-06-09 12:19:50 -04:00
commit 09dae432ce
24 changed files with 418 additions and 389 deletions

View File

@ -4,6 +4,11 @@ What's New
1. See the ZoneMinder release notes for a list of new features:
https://github.com/ZoneMinder/zoneminder/releases
2. The contents of the ZoneMinder Apache config file have changed. In
addition, this ZoneMinder package now requires you to manually symlink the
ZoneMinder Apache config file. See new install step 6 and upgrade step 3
below for details.
New installs
============

View File

@ -4,6 +4,11 @@ What's New
1. See the ZoneMinder release notes for a list of new features:
https://github.com/ZoneMinder/zoneminder/releases
2. The contents of the ZoneMinder Apache config file have changed. In
addition, this ZoneMinder package now requires you to manually symlink the
ZoneMinder Apache config file. See new install step 6 and upgrade step 3
below for details.
New installs
============

View File

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

View File

@ -245,7 +245,8 @@ sub initialise( @ ) {
$tempSyslogLevel = $level if defined($level = $this->getTargettedEnv('LOG_LEVEL_SYSLOG'));
if ( $Config{ZM_LOG_DEBUG} ) {
foreach my $target ( split( /\|/, $Config{ZM_LOG_DEBUG_TARGET} ) ) {
# Splitting on an empty string doesn't return an empty string, it returns an empty array
foreach my $target ( $Config{ZM_LOG_DEBUG_TARGET} ? split(/\|/, $Config{ZM_LOG_DEBUG_TARGET}) : '' ) {
if ( $target eq $this->{id}
|| $target eq '_'.$this->{id}
|| $target eq $this->{idRoot}
@ -278,6 +279,9 @@ sub initialise( @ ) {
$this->{initialised} = !undef;
# this function can get called on a previously initialized log Object, so clean any sth's
$this->{sth} = undef;
Debug( 'LogOpts: level='.$codes{$this->{level}}
.'/'.$codes{$this->{effectiveLevel}}
.', screen='.$codes{$this->{termLevel}}
@ -319,6 +323,8 @@ sub reinitialise {
my $screenLevel = $this->termLevel();
$this->termLevel(NOLOG);
$this->termLevel($screenLevel) if $screenLevel > NOLOG;
$this->{sth} = undef;
}
# Prevents undefined logging levels
@ -392,6 +398,12 @@ sub level {
# ICON: I am remarking this out because I don't see the point of having an effective level, if we are just going to set it to level.
#$this->{effectiveLevel} = $this->{level} if ( $this->{level} > $this->{effectiveLevel} );
# ICON: The point is that LOG_DEBUG can be set either in db or in env var and will get passed in here.
# So this will turn on debug, even if not output has Debug level turned on. I think it should be the other way around
# ICON: Let's try this line instead. effectiveLevel is 1 DEBUG from above, but LOG_DEBUG is off, then $this->level will be 0, and
# so effectiveLevel will become 0
$this->{effectiveLevel} = $this->{level} if ( $this->{level} < $this->{effectiveLevel} );
}
return $this->{level};
}
@ -474,7 +486,7 @@ sub openSyslog {
sub closeSyslog {
my $this = shift;
#closelog();
closelog();
}
sub logFile {
@ -517,54 +529,59 @@ sub logPrint {
if ( $level <= $this->{effectiveLevel} ) {
$string =~ s/[\r\n]+$//g;
my $code = $codes{$level};
if ( $level <= $this->{syslogLevel} ) {
syslog($priorities{$level}, $codes{$level}.' [%s]', $string);
}
my ($seconds, $microseconds) = gettimeofday();
my $message = sprintf(
'%s.%06d %s[%d].%s [%s]'
, strftime('%x %H:%M:%S', localtime($seconds))
, $microseconds
, $this->{id}
, $$
, $code
, $string
);
if ( $this->{trace} ) {
$message = Carp::shortmess($message);
} else {
$message = $message."\n";
if ( $level <= $this->{fileLevel} or $level <= $this->{termLevel} ) {
my $message = sprintf(
'%s.%06d %s[%d].%s [%s]'
, strftime('%x %H:%M:%S', localtime($seconds))
, $microseconds
, $this->{id}
, $$
, $codes{$level}
, $string
);
if ( $this->{trace} ) {
$message = Carp::shortmess($message);
} else {
$message = $message."\n";
}
print($LOGFILE $message) if $level <= $this->{fileLevel};
print(STDERR $message) if $level <= $this->{termLevel};
}
if ( $level <= $this->{syslogLevel} ) {
syslog($priorities{$level}, $code.' [%s]', $string);
}
print($LOGFILE $message) if $level <= $this->{fileLevel};
print(STDERR $message) if $level <= $this->{termLevel};
if ( $level <= $this->{databaseLevel} ) {
if ( ( $this->{dbh} and $this->{dbh}->ping() ) or ( $this->{dbh} = ZoneMinder::Database::zmDbConnect() ) ) {
my $sql = 'INSERT INTO Logs ( TimeKey, Component, Pid, Level, Code, Message, File, Line ) VALUES ( ?, ?, ?, ?, ?, ?, ?, NULL )';
$this->{sth} = $this->{dbh}->prepare_cached($sql);
if ( !$this->{sth} ) {
if ( ! ( $this->{dbh} and $this->{dbh}->ping() ) ) {
$this->{sth} = undef;
if ( ! ( $this->{dbh} = ZoneMinder::Database::zmDbConnect() ) ) {
print(STDERR "Can't log to database: ");
$this->{databaseLevel} = NOLOG;
Error("Can't prepare log entry '$sql': ".$this->{dbh}->errstr());
} else {
my $res = $this->{sth}->execute($seconds+($microseconds/1000000.0)
, $this->{id}
, $$
, $level
, $code
, $string
, $this->{fileName}
);
if ( !$res ) {
$this->{databaseLevel} = NOLOG;
Error("Can't execute log entry '$sql': ".$this->{dbh}->errstr());
}
return;
}
} else {
print(STDERR "Can't log to database: ");
}
my $sql = 'INSERT INTO Logs ( TimeKey, Component, Pid, Level, Code, Message, File, Line ) VALUES ( ?, ?, ?, ?, ?, ?, ?, NULL )';
$this->{sth} = $this->{dbh}->prepare_cached($sql) if ! $this->{sth};
if ( !$this->{sth} ) {
$this->{databaseLevel} = NOLOG;
Error("Can't prepare log entry '$sql': ".$this->{dbh}->errstr());
return;
}
my $res = $this->{sth}->execute($seconds+($microseconds/1000000.0)
, $this->{id}
, $$
, $level
, $codes{$level}
, $string
, $this->{fileName}
);
if ( !$res ) {
$this->{databaseLevel} = NOLOG;
Error("Can't execute log entry '$sql': ".$this->{dbh}->errstr());
}
} # end if doing db logging
} # end if level < effectivelevel

View File

@ -119,13 +119,13 @@ if ( $command eq 'version' ) {
}
my $needs_daemon = $command !~ /(?:startup|shutdown|status|check|logrot|version)/;
my $daemon = shift @ARGV;
if ( $needs_daemon && ! $daemon ) {
if ( $needs_daemon && !$daemon ) {
print(STDERR "No daemon given\n");
pod2usage(-exitstatus => -1);
}
my @args;
my $daemon_patt = '('.join( '|', @daemons ).')';
my $daemon_patt = '('.join('|', @daemons).')';
if ( $needs_daemon ) {
if ( $daemon =~ /^${daemon_patt}$/ ) {
$daemon = $1;
@ -139,7 +139,7 @@ foreach my $arg ( @ARGV ) {
# Detaint arguments, if they look ok
#if ( $arg =~ /^(-{0,2}[\w]+)/ )
if ( $arg =~ /^(-{0,2}[\w\/?&=.-]+)$/ ) {
push( @args, $1 );
push @args, $1;
} else {
print(STDERR "Bogus argument '$arg' found");
exit(-1);
@ -245,6 +245,16 @@ our %terminating_processes;
our $zm_terminate = 0;
sub run {
# Call this first otherwise stdout/stderror redirects to the pidfile = bad
if ( open(my $PID, '>', ZM_PID) ) {
print($PID $$);
close($PID);
} else {
# Log not initialized at this point so use die instead
die "Can't open pid file at ".ZM_PID."\n";
}
my $fd = 0;
while( $fd < POSIX::sysconf(&POSIX::_SC_OPEN_MAX) ) {
POSIX::close($fd++);
@ -252,6 +262,8 @@ sub run {
setpgrp();
# dbh got closed with the rest of the fd's above, so need to reconnect.
my $dbh = zmDbConnect(1);
logInit();
dPrint(ZoneMinder::Logger::INFO, 'Server starting at '
@ -259,18 +271,10 @@ sub run {
."\n"
);
if ( open(my $PID, '>', ZM_PID) ) {
print($PID $$);
close($PID);
} else {
Error("Can't open pid file at " . ZM_PID);
}
# Tell any existing processes to die, wait 1 second between TERM and KILL
killAll(1);
dPrint(ZoneMinder::Logger::INFO, 'Socket should be open at ' .main::SOCK_FILE);
my $dbh = zmDbConnect(1);
socket(SERVER, PF_UNIX, SOCK_STREAM, 0) or Fatal("Can't open socket: $!");
unlink(main::SOCK_FILE) or Error('Unable to unlink ' . main::SOCK_FILE .". Error message was: $!") if -e main::SOCK_FILE;
bind(SERVER, $saddr) or Fatal("Can't bind to " . main::SOCK_FILE . ": $!");
@ -306,7 +310,7 @@ sub run {
$dbh = zmDbConnect();
}
my @cpuload = CpuLoad();
Debug("UPdating Server record @cpuload");
Debug("Updating Server record @cpuload");
if ( ! defined $dbh->do(q{UPDATE Servers SET Status=?,CpuLoad=?,TotalMem=?,FreeMem=?,TotalSwap=?,FreeSwap=? WHERE Id=?}, undef,
'Running', $cpuload[0], &totalmem, &freemem, &totalswap, &freeswap, $Config{ZM_SERVER_ID} ) ) {
Error("Failed Updating status of Server record for Id=$Config{ZM_SERVER_ID}".$dbh->errstr());
@ -315,7 +319,6 @@ sub run {
$secs_count += 1;
}
my $nfound = select(my $rout = $rin, undef, undef, $timeout);
Debug("Aftere select $nfound");
if ( $nfound > 0 ) {
if ( vec($rout, fileno(SERVER), 1) ) {
my $paddr = accept(CLIENT, SERVER);
@ -370,9 +373,7 @@ Debug("Aftere select $nfound");
#print( "Select timed out\n" );
}
Debug("restartPending");
restartPending();
Debug("check_for_processes_to_kill");
check_for_processes_to_kill();
} # end while
@ -382,7 +383,7 @@ Debug("check_for_processes_to_kill");
."\n"
);
if ( $Config{ZM_SERVER_ID} ) {
$dbh = zmDbConnect() if ! $dbh->ping();
$dbh = zmDbConnect() if ! ($dbh and $dbh->ping());
if ( ! defined $dbh->do(q{UPDATE Servers SET Status='NotRunning' WHERE Id=?}, undef, $Config{ZM_SERVER_ID}) ) {
Error("Failed Updating status of Server record for Id=$Config{ZM_SERVER_ID}".$dbh->errstr());
}
@ -399,6 +400,7 @@ sub cPrint {
# I think the purpose of this is to echo the logs to the client process so it can then display them.
sub dPrint {
my $logLevel = shift;
# One thought here, if no client exists to read these... does it block?
if ( fileno(CLIENT) ) {
print CLIENT @_
}
@ -435,12 +437,10 @@ sub start {
my $sigset = POSIX::SigSet->new;
my $blockset = POSIX::SigSet->new(SIGCHLD);
Debug("Blocking SIGCHLD");
sigprocmask(SIG_BLOCK, $blockset, $sigset) or Fatal("Can't block SIGCHLD: $!");
Debug("forking");
if ( my $cpid = fork() ) {
# This logReinit is required. Not sure why.
logReinit();
#logReinit();
$process->{pid} = $cpid;
$process->{started} = time();
@ -453,7 +453,6 @@ sub start {
$cmd_hash{$process->{command}} = $pid_hash{$cpid} = $process;
sigprocmask(SIG_SETMASK, $sigset) or Fatal("Can't restore SIGCHLD: $!");
Debug("unblocking child");
} elsif ( defined($cpid) ) {
# Force reconnection to the db.
$dbh = zmDbConnect(1);
@ -516,7 +515,7 @@ sub send_stop {
.strftime('%y/%m/%d %H:%M:%S', localtime())
."\n"
);
sigprocmask(SIG_UNBLOCK, $blockset) or die "dying at unblock...\n";
sigprocmask(SIG_UNBLOCK, $blockset) or die "dying at unblock...\n";
return();
}
@ -708,7 +707,6 @@ sub reaper {
} # end while waitpid
$SIG{CHLD} = \&reaper;
$! = $saved_status;
Debug("Leaving reaper");
}
sub restartPending {
@ -720,7 +718,6 @@ sub restartPending {
start($process->{daemon}, @{$process->{args}});
}
}
Debug("done restartPending");
}
sub shutdownAll {
@ -808,7 +805,7 @@ sub status {
foreach my $process ( values %cmd_hash ) {
if ( $process->{pending} ) {
dPrint(ZoneMinder::Logger::DEBUG, "'$process->{command}' pending at "
.strftime( '%y/%m/%d %H:%M:%S', localtime($process->{pending}))
.strftime('%y/%m/%d %H:%M:%S', localtime($process->{pending}))
."\n"
);
}

View File

@ -70,12 +70,14 @@ use Getopt::Long;
use autouse 'Pod::Usage'=>qw(pod2usage);
use autouse 'Data::Dumper'=>qw(Dumper);
my $daemon = 0;
my $filter_name = '';
my $filter_id;
my $version = 0;
my $zm_terminate = 0;
GetOptions(
'daemon' =>\$daemon,
'filter=s' =>\$filter_name,
'filter_id=s' =>\$filter_id,
'version' =>\$version
@ -201,7 +203,7 @@ while( !$zm_terminate ) {
}
}
last if $filter_name or $filter_id or $zm_terminate;
last if (!$daemon and ($filter_name or $filter_id)) or $zm_terminate;
Debug("Sleeping for $delay seconds\n");
sleep($delay);

View File

@ -41,9 +41,10 @@ use autouse 'Pod::Usage'=>qw(pod2usage);
$ENV{PATH} = '/bin:/usr/bin:/usr/local/bin';
$ENV{SHELL} = '/bin/sh' if exists $ENV{SHELL};
delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
my $store_state=""; # PP - will remember state name passed
my $store_state=''; # PP - will remember state name passed
logInit();
Info("Aftere LogInit");
my $command = $ARGV[0]||'';
if ( $command eq 'version' ) {
@ -53,28 +54,27 @@ if ( $command eq 'version' ) {
my $state;
my $dbh;
my $dbh = zmDbConnect();
Info("Command: $command");
if ( !$command || $command !~ /^(?:start|stop|restart|status|logrot|version)$/ ) {
if ( $command ) {
$dbh = zmDbConnect();
# Check to see if it's a valid run state
my $sql = 'SELECT * FROM States WHERE Name=?';
my $sth = $dbh->prepare_cached( $sql )
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute( $command )
or Fatal( "Can't execute: ".$sth->errstr() );
my $sth = $dbh->prepare_cached($sql)
or Fatal("Can't prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute($command)
or Fatal("Can't execute: ".$sth->errstr());
if ( $state = $sth->fetchrow_hashref() ) {
$state->{Name} = $command;
#$state->{Name} = $command;
$state->{Definitions} = [];
foreach( split( /,/, $state->{Definition} ) ) {
my ( $id, $function, $enabled ) = split( /:/, $_ );
foreach( split(',', $state->{Definition}) ) {
my ( $id, $function, $enabled ) = split(':', $_);
push( @{$state->{Definitions}},
{ Id=>$id, Function=>$function, Enabled=>$enabled }
);
}
$store_state=$command; # PP - Remember the name that was passed to search in DB
$command = 'state';
$store_state = $command; # PP - Remember the name that was passed to search in DB
$command = 'state';
} else {
$command = undef;
}
@ -82,64 +82,66 @@ if ( !$command || $command !~ /^(?:start|stop|restart|status|logrot|version)$/ )
if ( !$command ) {
pod2usage(-exitstatus => -1);
}
}
$dbh = zmDbConnect() if ! $dbh;
} # end if not one of the usual commands
# PP - Sane state check
Debug("StartisActiveSSantiyCheck");
isActiveSanityCheck();
Debug("Done isActiveSSantiyCheck");
# Move to the right place
chdir( $Config{ZM_PATH_WEB} )
or Fatal( "Can't chdir to '".$Config{ZM_PATH_WEB}."': $!" );
chdir($Config{ZM_PATH_WEB})
or Fatal("Can't chdir to '$Config{ZM_PATH_WEB}': $!");
my $dbg_id = '';
my $dbg_id = '';
Info( "Command: $command\n" );
Info("Command: $command");
my $retval = 0;
my $retval = 0;
if ( $command eq 'state' ) {
Info( "Updating DB: $state->{Name}\n" );
my $sql = $Config{ZM_SERVER_ID} ? 'SELECT * FROM Monitors WHERE ServerId=? ORDER BY Id ASC' : 'SELECT * FROM Monitors ORDER BY Id ASC';
my $sth = $dbh->prepare_cached( $sql )
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute( $Config{ZM_SERVER_ID} ? $Config{ZM_SERVER_ID}: () )
or Fatal( "Can't execute: ".$sth->errstr() );
while( my $monitor = $sth->fetchrow_hashref() ) {
foreach my $definition ( @{$state->{Definitions}} ) {
if ( $monitor->{Id} =~ /^$definition->{Id}$/ ) {
$monitor->{NewFunction} = $definition->{Function};
$monitor->{NewEnabled} = $definition->{Enabled};
}
}
#next if ( !$monitor->{NewFunction} );
$monitor->{NewFunction} = 'None'
if ( !$monitor->{NewFunction} );
$monitor->{NewEnabled} = 0
if ( !$monitor->{NewEnabled} );
if ( $monitor->{Function} ne $monitor->{NewFunction}
|| $monitor->{Enabled} ne $monitor->{NewEnabled}
) {
my $sql = 'UPDATE Monitors SET Function=?, Enabled=? WHERE Id=?';
my $sth = $dbh->prepare_cached( $sql )
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute( $monitor->{NewFunction}, $monitor->{NewEnabled}, $monitor->{Id} )
or Fatal( "Can't execute: ".$sth->errstr() );
if ( $command eq 'state' ) {
Info("Updating DB: $state->{Name}");
my $sql = 'SELECT * FROM Monitors' . ($Config{ZM_SERVER_ID} ? ' WHERE ServerId=?' : '' ) .' ORDER BY Id ASC';
my $sth = $dbh->prepare_cached($sql)
or Fatal("Can't prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute($Config{ZM_SERVER_ID} ? $Config{ZM_SERVER_ID}: ())
or Fatal("Can't execute: ".$sth->errstr());
while( my $monitor = $sth->fetchrow_hashref() ) {
foreach my $definition ( @{$state->{Definitions}} ) {
if ( $monitor->{Id} =~ /^$definition->{Id}$/ ) {
$monitor->{NewFunction} = $definition->{Function};
$monitor->{NewEnabled} = $definition->{Enabled};
}
}
$sth->finish();
#next if ( !$monitor->{NewFunction} );
$monitor->{NewFunction} = 'None'
if ( !$monitor->{NewFunction} );
$monitor->{NewEnabled} = 0
if ( !$monitor->{NewEnabled} );
if ( $monitor->{Function} ne $monitor->{NewFunction}
|| $monitor->{Enabled} ne $monitor->{NewEnabled}
) {
my $sql = 'UPDATE Monitors SET Function=?, Enabled=? WHERE Id=?';
my $sth = $dbh->prepare_cached($sql)
or Fatal("Can't prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute($monitor->{NewFunction}, $monitor->{NewEnabled}, $monitor->{Id})
or Fatal("Can't execute: ".$sth->errstr());
} # end if change of function or enablement
} # end foreach monitor
$sth->finish();
# PP - Now mark a specific state as active
resetStates();
Info ("Marking $store_state as Enabled");
$sql = "UPDATE States SET IsActive = '1' WHERE Name = ?";
$sth = $dbh->prepare_cached( $sql )
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
$res = $sth->execute( $store_state )
or Fatal( "Can't execute: ".$sth->errstr() );
# PP - Now mark a specific state as active
resetStates();
Info("Marking $store_state as Enabled");
$sql = 'UPDATE States SET IsActive = 1 WHERE Name = ?';
$sth = $dbh->prepare_cached($sql)
or Fatal("Can't prepare '$sql': ".$dbh->errstr());
$res = $sth->execute($store_state)
or Fatal("Can't execute: ".$sth->errstr());
# PP - zero out other states isActive
$command = 'restart';
}
# PP - zero out other states isActive
$command = 'restart';
} # end if command = state
# Check if we are running systemd and if we have been called by the system
if ( $command =~ /^(start|stop|restart)$/ ) {
@ -154,6 +156,7 @@ if ( $command =~ /^(start|stop|restart)$/ ) {
if ( $command =~ /^(?:stop|restart)$/ ) {
my $status = runCommand('zmdc.pl check');
Debug("zmdc.pl check = $status");
if ( $status eq 'running' ) {
runCommand('zmdc.pl shutdown');
@ -163,20 +166,19 @@ if ( $command =~ /^(?:stop|restart)$/ ) {
}
}
#runCommand( "zmupdate.pl -f" );
if ( $command =~ /^(?:start|restart)$/ ) {
my $status = runCommand('zmdc.pl check');
Debug("zmdc.pl check = $status");
if ( $status eq 'stopped' ) {
if ( $Config{ZM_DYN_DB_VERSION}
and ( $Config{ZM_DYN_DB_VERSION} ne ZM_VERSION )
) {
Fatal( 'Version mismatch, system is version '.ZM_VERSION
Fatal('Version mismatch, system is version '.ZM_VERSION
.', database is '.$Config{ZM_DYN_DB_VERSION}
.', please run zmupdate.pl to update.'
);
exit( -1 );
exit(-1);
}
# Recreate the temporary directory if it's been wiped
@ -196,8 +198,8 @@ if ( $command =~ /^(?:start|restart)$/ ) {
my @values;
if ( $Config{ZM_SERVER_ID} ) {
require ZoneMinder::Server;
Info("Multi-server configuration detected. Starting up services for server $Config{ZM_SERVER_ID}\n");
$Server = new ZoneMinder::Server( $Config{ZM_SERVER_ID} );
Info("Multi-server configuration detected. Starting up services for server $Config{ZM_SERVER_ID}");
$Server = new ZoneMinder::Server($Config{ZM_SERVER_ID});
$sql = 'SELECT * FROM Monitors WHERE ServerId=?';
@values = ( $Config{ZM_SERVER_ID} );
} else {
@ -206,46 +208,49 @@ if ( $command =~ /^(?:start|restart)$/ ) {
}
{
my $sth = $dbh->prepare_cached( $sql )
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute( @values )
or Fatal( "Can't execute: ".$sth->errstr() );
while( my $monitor = $sth->fetchrow_hashref() ) {
if ( $monitor->{Function} ne 'None' && $monitor->{Type} ne 'WebSite' ) {
if ( $monitor->{Type} eq 'Local' ) {
runCommand( "zmdc.pl start zmc -d $monitor->{Device}" );
} else {
runCommand( "zmdc.pl start zmc -m $monitor->{Id}" );
}
if ( $monitor->{Function} ne 'Monitor' ) {
runCommand( "zmdc.pl start zma -m $monitor->{Id}" );
}
if ( $Config{ZM_OPT_CONTROL} ) {
if ( $monitor->{Function} eq 'Modect' || $monitor->{Function} eq 'Mocord' ) {
if ( $monitor->{Controllable} && $monitor->{TrackMotion} ) {
runCommand( "zmdc.pl start zmtrack.pl -m $monitor->{Id}" );
}
my $sth = $dbh->prepare_cached($sql)
or Fatal("Can't prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute(@values)
or Fatal("Can't execute: ".$sth->errstr());
while( my $monitor = $sth->fetchrow_hashref() ) {
if ( $monitor->{Function} ne 'None' && $monitor->{Type} ne 'WebSite' ) {
if ( $monitor->{Type} eq 'Local' ) {
runCommand("zmdc.pl start zmc -d $monitor->{Device}");
} else {
runCommand("zmdc.pl start zmc -m $monitor->{Id}");
}
}
}
}
$sth->finish();
if ( $monitor->{Function} ne 'Monitor' ) {
runCommand("zmdc.pl start zma -m $monitor->{Id}");
}
if ( $Config{ZM_OPT_CONTROL} ) {
if ( $monitor->{Controllable} && $monitor->{TrackMotion} ) {
if ( $monitor->{Function} eq 'Modect' || $monitor->{Function} eq 'Mocord' ) {
runCommand( "zmdc.pl start zmtrack.pl -m $monitor->{Id}" );
} else {
Warning(' Monitor is set to track motion, but does not have motion detection enabled.');
} # end if Has motion enabled
} # end if track motion
} # end if ZM_OPT_CONTROL
} # end if function is not none or Website
} # end foreach monitor
$sth->finish();
}
{
my $sql = 'SELECT Id FROM Filters WHERE Background=1';
my $sth = $dbh->prepare_cached($sql)
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
my $res = $sth->execute()
or Fatal( "Can't execute: ".$sth->errstr() );
if ( $sth->rows ) {
while( my $filter = $sth->fetchrow_hashref() ) {
# This is now started unconditionally
runCommand("zmdc.pl start zmfilter.pl --filter_id=$$filter{Id}");
my $sql = 'SELECT Id FROM Filters WHERE Background=1';
my $sth = $dbh->prepare_cached($sql)
or Fatal("Can't prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute()
or Fatal("Can't execute: ".$sth->errstr());
if ( $sth->rows ) {
while( my $filter = $sth->fetchrow_hashref() ) {
# This is now started unconditionally
runCommand("zmdc.pl start zmfilter.pl --filter_id=$$filter{Id} --daemon");
}
} else {
runCommand('zmdc.pl start zmfilter.pl');
}
} else {
runCommand('zmdc.pl start zmfilter.pl');
}
$sth->finish();
$sth->finish();
}
if ( $Config{ZM_RUN_AUDIT} ) {
@ -283,32 +288,32 @@ if ( $command =~ /^(?:start|restart)$/ ) {
} else {
$retval = 1;
}
}
} # end if command is start or restart
if ( $command eq 'status' ) {
my $status = runCommand('zmdc.pl check');
print( STDOUT $status."\n" );
print(STDOUT $status."\n");
} elsif ( $command eq 'logrot' ) {
runCommand('zmdc.pl logrot');
}
exit( $retval );
exit($retval);
# PP - Make sure isActive is on and only one
sub isActiveSanityCheck {
Info ('Sanity checking States table...');
Info('Sanity checking States table...');
$dbh = zmDbConnect() if ! $dbh;
# PP - First, make sure default exists and there is only one
my $sql = "SELECT Name FROM States WHERE Name='default'";
my $sth = $dbh->prepare_cached( $sql )
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
my $sql = q`SELECT Name FROM States WHERE Name='default'`;
my $sth = $dbh->prepare_cached($sql)
or Fatal("Can't prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute()
or Fatal( "Can't execute: ".$sth->errstr() );
or Fatal("Can't execute: ".$sth->errstr());
if ($sth->rows != 1) {
if ( $sth->rows != 1 ) {
# PP - no row, or too many rows. Either case is an error
Info( 'Fixing States table - either no default state or duplicate default states' );
$sql = "DELETE FROM States WHERE Name='default'";
@ -316,69 +321,53 @@ sub isActiveSanityCheck {
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
$res = $sth->execute()
or Fatal( "Can't execute: ".$sth->errstr() );
$sql = "INSERT INTO States (Name,Definition,IsActive) VALUES ('default','','1');";
$sth = $dbh->prepare_cached( $sql )
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
$sql = q`"INSERT INTO States (Name,Definition,IsActive) VALUES ('default','','1');`;
$sth = $dbh->prepare_cached($sql)
or Fatal("Can't prepare '$sql': ".$dbh->errstr());
$res = $sth->execute()
or Fatal( "Can't execute: ".$sth->errstr() );
or Fatal("Can't execute: ".$sth->errstr());
}
# PP - Now make sure no two states have IsActive=1
$sql = "SELECT Name FROM States WHERE IsActive = '1'";
$sth = $dbh->prepare_cached( $sql )
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
$sql = 'SELECT Name FROM States WHERE IsActive = 1';
$sth = $dbh->prepare_cached($sql)
or Fatal("Can't prepare '$sql': ".$dbh->errstr());
$res = $sth->execute()
or Fatal( "Can't execute: ".$sth->errstr() );
or Fatal("Can't execute: ".$sth->errstr());
if ( $sth->rows != 1 ) {
Info( 'Fixing States table so only one run state is active' );
Info('Fixing States table so only one run state is active');
resetStates();
$sql = "UPDATE States SET IsActive='1' WHERE Name='default'";
$sth = $dbh->prepare_cached( $sql )
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
$sql = q`UPDATE States SET IsActive=1 WHERE Name='default'`;
$sth = $dbh->prepare_cached($sql)
or Fatal("Can't prepare '$sql': ".$dbh->errstr());
$res = $sth->execute()
or Fatal( "Can't execute: ".$sth->errstr() );
or Fatal("Can't execute: ".$sth->errstr());
}
}
} # end sub isActiveSanityCheck
# PP - zeroes out isActive for all states
sub resetStates {
$dbh = zmDbConnect() if ! $dbh;
my $sql = "UPDATE States SET IsActive='0'";
my $sth = $dbh->prepare_cached( $sql )
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
my $sql = 'UPDATE States SET IsActive=0';
my $sth = $dbh->prepare_cached($sql)
or Fatal("Can't prepare '$sql': ".$dbh->errstr());
my $res = $sth->execute()
or Fatal( "Can't execute: ".$sth->errstr() );
or Fatal("Can't execute: ".$sth->errstr());
}
sub systemdRunning {
my $result = 0;
my $output = qx(ps -o comm="" -p 1);
chomp( $output );
if ( $output =~ /systemd/ ) {
$result = 1;
}
return $result;
return scalar ( $output =~ /systemd/ );
}
sub calledBysystem {
my $result = 0;
my $ppid = getppid();
my $output = qx(ps -o comm="" -p $ppid);
chomp( $output );
#chomp( $output );
if ($output =~ /^(?:systemd|init)$/) {
$result = 1;
}
return $result;
return ($output =~ /^(?:systemd|init)$/);
}
sub verifyFolder {
@ -386,24 +375,22 @@ sub verifyFolder {
# Recreate the temporary directory if it's been wiped
if ( !-e $folder ) {
Debug( "Recreating directory '$folder'" );
mkdir( $folder, 0774 )
Debug("Recreating directory '$folder'");
mkdir($folder, 0774)
or Fatal( "Can't create missing temporary directory '$folder': $!" );
my ( $runName ) = getpwuid( $> );
my ( $runName ) = getpwuid($>);
if ( $runName ne $Config{ZM_WEB_USER} ) {
# Not running as web user, so should be root in which case
# chown the directory
my ( $webName, $webPass, $webUid, $webGid ) = getpwnam( $Config{ZM_WEB_USER} )
or Fatal( "Can't get user details for web user '"
.$Config{ZM_WEB_USER}."': $!"
my ( $webName, $webPass, $webUid, $webGid ) = getpwnam($Config{ZM_WEB_USER})
or Fatal("Can't get details for web user '$Config{ZM_WEB_USER}': $!");
chown($webUid, $webGid, $folder)
or Fatal("Can't change ownership of '$folder' to '"
.$Config{ZM_WEB_USER}.':'.$Config{ZM_WEB_GROUP}."': $!"
);
chown( $webUid, $webGid, "$folder" )
or Fatal( "Can't change ownership of directory '$folder' to '"
.$Config{ZM_WEB_USER}.":".$Config{ZM_WEB_GROUP}."': $!"
);
}
}
}
} # end if runName ne ZM_WEB_USER
} # end if folder doesn't exist
} # end sub verifyFolder
1;
__END__

View File

@ -24,7 +24,7 @@
#include "zm_db.h"
MYSQL dbconn;
Mutex db_mutex;
RecursiveMutex db_mutex;
bool zmDbConnected = false;
@ -91,15 +91,15 @@ void zmDbClose() {
}
MYSQL_RES * zmDbFetch(const char * query) {
if ( ! zmDbConnected ) {
if ( !zmDbConnected ) {
Error("Not connected.");
return NULL;
}
db_mutex.lock();
if ( mysql_query(&dbconn, query) ) {
Error("Can't run query: %s", mysql_error(&dbconn));
db_mutex.unlock();
Error("Can't run query: %s", mysql_error(&dbconn));
return NULL;
}
Debug(4, "Success running query: %s", query);

View File

@ -41,7 +41,7 @@ class zmDbRow {
};
extern MYSQL dbconn;
extern Mutex db_mutex;
extern RecursiveMutex db_mutex;
bool zmDbConnect();
void zmDbClose();

View File

@ -95,6 +95,15 @@ bool Mutex::locked() {
return( state == EBUSY );
}
RecursiveMutex::RecursiveMutex() {
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
if ( pthread_mutex_init(&mMutex, &attr) < 0 )
Error("Unable to create pthread mutex: %s", strerror(errno));
}
Condition::Condition( Mutex &mutex ) : mMutex( mutex ) {
if ( pthread_cond_init( &mCondition, NULL ) < 0 )
throw ThreadException( stringtf( "Unable to create pthread condition: %s", strerror(errno) ) );

View File

@ -59,27 +59,34 @@ public:
};
class Mutex {
friend class Condition;
friend class Condition;
private:
pthread_mutex_t mMutex;
private:
pthread_mutex_t mMutex;
public:
Mutex();
~Mutex();
public:
Mutex();
~Mutex();
private:
pthread_mutex_t *getMutex() {
return( &mMutex );
}
private:
pthread_mutex_t *getMutex() {
return &mMutex;
}
public:
int trylock();
void lock();
void lock( int secs );
void lock( double secs );
void unlock();
bool locked();
public:
int trylock();
void lock();
void lock( int secs );
void lock( double secs );
void unlock();
bool locked();
};
class RecursiveMutex : public Mutex {
private:
pthread_mutex_t mMutex;
public:
RecursiveMutex();
};
class ScopedMutex {

View File

@ -74,45 +74,44 @@ int main( int argc, const char *argv[] ) {
unsigned int playback_buffer = 0;
bool nph = false;
const char *basename = strrchr( argv[0], '/' );
if (basename) //if we found a / lets skip past it
const char *basename = strrchr(argv[0], '/');
if ( basename ) //if we found a / lets skip past it
basename++;
else //argv[0] will not always contain the full path, but rather just the script name
basename = argv[0];
const char *nph_prefix = "nph-";
if ( basename && !strncmp( basename, nph_prefix, strlen(nph_prefix) ) ) {
if ( basename && !strncmp(basename, nph_prefix, strlen(nph_prefix)) ) {
nph = true;
}
zmLoadConfig();
const char *query = getenv( "QUERY_STRING" );
const char *query = getenv("QUERY_STRING");
if ( query ) {
Debug( 1, "Query: %s", query );
Debug(1, "Query: %s", query);
char temp_query[1024];
strncpy( temp_query, query, sizeof(temp_query) );
strncpy(temp_query, query, sizeof(temp_query));
char *q_ptr = temp_query;
char *parms[16]; // Shouldn't be more than this
int parm_no = 0;
while( (parm_no < 16) && (parms[parm_no] = strtok( q_ptr, "&" )) ) {
while( (parm_no < 16) && (parms[parm_no] = strtok(q_ptr, "&")) ) {
parm_no++;
q_ptr = NULL;
}
for ( int p = 0; p < parm_no; p++ ) {
char *name = strtok( parms[p], "=" );
char *value = strtok( NULL, "=" );
char *name = strtok(parms[p], "=");
char *value = strtok(NULL, "=");
if ( !value )
value = (char *)"";
if ( !strcmp( name, "source" ) ) {
source = !strcmp( value, "event" )?ZMS_EVENT:ZMS_MONITOR;
} else if ( !strcmp( name, "mode" ) ) {
mode = !strcmp( value, "jpeg" )?ZMS_JPEG:ZMS_MPEG;
mode = !strcmp( value, "raw" )?ZMS_RAW:mode;
mode = !strcmp( value, "zip" )?ZMS_ZIP:mode;
mode = !strcmp( value, "single" )?ZMS_SINGLE:mode;
if ( !strcmp(name, "source") ) {
source = !strcmp(value, "event")?ZMS_EVENT:ZMS_MONITOR;
} else if ( !strcmp(name, "mode") ) {
mode = !strcmp(value, "jpeg")?ZMS_JPEG:ZMS_MPEG;
mode = !strcmp(value, "raw")?ZMS_RAW:mode;
mode = !strcmp(value, "zip")?ZMS_ZIP:mode;
mode = !strcmp(value, "single")?ZMS_SINGLE:mode;
} else if ( !strcmp( name, "format" ) ) {
strncpy( format, value, sizeof(format) );
} else if ( !strcmp( name, "monitor" ) ) {
@ -182,32 +181,32 @@ int main( int argc, const char *argv[] ) {
if ( config.opt_use_auth ) {
User *user = 0;
if ( strcmp( config.auth_relay, "none" ) == 0 ) {
if ( strcmp(config.auth_relay, "none") == 0 ) {
if ( username.length() ) {
user = zmLoadUser( username.c_str() );
user = zmLoadUser(username.c_str());
}
} else {
//if ( strcmp( config.auth_relay, "hashed" ) == 0 )
{
if ( *auth ) {
user = zmLoadAuthUser( auth, config.auth_hash_ips );
user = zmLoadAuthUser(auth, config.auth_hash_ips);
}
}
//else if ( strcmp( config.auth_relay, "plain" ) == 0 )
{
if ( username.length() && password.length() ) {
user = zmLoadUser( username.c_str(), password.c_str() );
user = zmLoadUser(username.c_str(), password.c_str());
}
}
}
if ( !user ) {
Error( "Unable to authenticate user" );
Error("Unable to authenticate user");
logTerm();
zmDbClose();
return( -1 );
return -1;
}
ValidateAccess( user, monitor_id );
}
ValidateAccess(user, monitor_id);
} // end if config.opt_use_auth
hwcaps_detect();
zmSetDefaultTermHandler();

View File

@ -22,13 +22,9 @@ if ( sem_acquire($semaphore,1) !== false ) {
if ( file_exists( $localSocketFile ) ) {
Warning("sock file $localSocketFile already exists?! Is someone else talking to zms?");
// They could be. We can maybe have concurrent requests from a browser.
} else {
Logger::Debug("socket file does not exist, we should be good to connect.");
}
if ( ! socket_bind( $socket, $localSocketFile ) ) {
ajaxError( "socket_bind( $localSocketFile ) failed: ".socket_strerror(socket_last_error()) );
} else {
Logger::Debug("Bound to $localSocketFile");
ajaxError("socket_bind( $localSocketFile ) failed: ".socket_strerror(socket_last_error()) );
}
switch ( $_REQUEST['command'] ) {
@ -81,7 +77,6 @@ if ( sem_acquire($semaphore,1) !== false ) {
$eSockets = NULL;
$timeout = MSG_TIMEOUT - ( time() - $start_time );
Logger::Debug("TImeout is: $timeout/1000 seconds. " );
$numSockets = socket_select( $rSockets, $wSockets, $eSockets, intval($timeout/1000), ($timeout%1000)*1000 );

View File

@ -332,25 +332,18 @@ class MonitorsController extends AppController {
}
public function daemonControl($id, $command, $monitor=null, $daemon=null) {
$args = '';
$daemons = array();
if (!$monitor) {
if ( !$monitor ) {
// Need to see if it is local or remote
$monitor = $this->Monitor->find('first', array(
'fields' => array('Type', 'Function'),
'fields' => array('Type', 'Function', 'Device'),
'conditions' => array('Id' => $id)
));
$monitor = $monitor['Monitor'];
}
if ($monitor['Type'] == 'Local') {
$args = '-d ' . $monitor['Device'];
} else {
$args = '-m ' . $id;
}
if ($monitor['Function'] == 'Monitor') {
if ( $monitor['Function'] == 'Monitor' ) {
array_push($daemons, 'zmc');
} else {
array_push($daemons, 'zmc', 'zma');
@ -359,6 +352,13 @@ class MonitorsController extends AppController {
$zm_path_bin = Configure::read('ZM_PATH_BIN');
foreach ($daemons as $daemon) {
$args = '';
if ( $daemon == 'zmc' and $monitor['Type'] == 'Local') {
$args = '-d ' . $monitor['Device'];
} else {
$args = '-m ' . $id;
}
$shellcmd = escapeshellcmd("$zm_path_bin/zmdc.pl $command $daemon $args");
$status = exec( $shellcmd );
}

View File

@ -20,7 +20,7 @@ public $defaults = array(
'limit' => 100,
'Query' => array(),
'sort_field' => ZM_WEB_EVENT_SORT_FIELD,
'sort_asc' => ZM_WEB_EVENT_SORT_ORDER == 'asc' ? 'asc' : 'desc',
'sort_asc' => ZM_WEB_EVENT_SORT_ORDER,
);
public function __construct( $IdOrRow=NULL ) {

View File

@ -476,15 +476,12 @@ if ( canEdit( 'Monitors' ) ) {
);
if ( $_REQUEST['newMonitor']['ServerId'] == 'auto' ) {
Logger::Debug("Auto selecting server");
$_REQUEST['newMonitor']['ServerId'] = dbFetchOne('SELECT Id FROM Servers WHERE Status=\'Running\' ORDER BY FreeMem DESC, CpuLoad ASC LIMIT 1', 'Id');
Logger::Debug("Auto selecting server: Got " . $_REQUEST['newMonitor']['ServerId'] );
if ( ( ! $_REQUEST['newMonitor'] ) and defined('ZM_SERVER_ID') ) {
$_REQUEST['newMonitor']['ServerId'] = ZM_SERVER_ID;
Logger::Debug("Auto selecting server to " . ZM_SERVER_ID);
}
} else {
Logger::Debug("NOT Auto selecting server" . $_REQUEST['newMonitor']['ServerId']);
}
$columns = getTableColumns('Monitors');
@ -571,22 +568,23 @@ if ( canEdit( 'Monitors' ) ) {
$restart = true;
} # end if count(changes)
if (
( !isset($_POST['newMonitor']['GroupIds']) )
or
( count($_POST['newMonitor']['GroupIds']) != count($Monitor->GroupIds()) )
or
array_diff($_POST['newMonitor']['GroupIds'], $Monitor->GroupIds())
) {
if ( $Monitor->Id() )
dbQuery('DELETE FROM Groups_Monitors WHERE MonitorId=?', array($mid));
if ( isset($_POST['newMonitor']['GroupIds']) ) {
foreach ( $_POST['newMonitor']['GroupIds'] as $group_id ) {
dbQuery('INSERT INTO Groups_Monitors (GroupId,MonitorId) VALUES (?,?)', array($group_id, $mid));
}
if (
( !isset($_POST['newMonitor']['GroupIds']) )
or
( count($_POST['newMonitor']['GroupIds']) != count($Monitor->GroupIds()) )
or
array_diff($_POST['newMonitor']['GroupIds'], $Monitor->GroupIds())
) {
if ( $Monitor->Id() )
dbQuery('DELETE FROM Groups_Monitors WHERE MonitorId=?', array($mid));
if ( isset($_POST['newMonitor']['GroupIds']) ) {
foreach ( $_POST['newMonitor']['GroupIds'] as $group_id ) {
dbQuery('INSERT INTO Groups_Monitors (GroupId,MonitorId) VALUES (?,?)', array($group_id, $mid));
}
} // end if there has been a change of groups
}
} // end if there has been a change of groups
if ( ZM_OPT_X10 ) {
$x10Changes = getFormChanges( $x10Monitor, $_REQUEST['newX10Monitor'] );

View File

@ -200,7 +200,7 @@ isset($view) || $view = NULL;
isset($request) || $request = NULL;
isset($action) || $action = NULL;
if ( ZM_ENABLE_CSRF_MAGIC && $action != 'login' && $view != 'view_video' && $view != 'video' && $request != 'control' && $view != 'frames' && $view != 'archive' ) {
if ( ZM_ENABLE_CSRF_MAGIC && $action != 'login' && $view != 'view_video' && $request != 'control' && $view != 'frames' && $view != 'archive' ) {
require_once( 'includes/csrf/csrf-magic.php' );
#Logger::Debug("Calling csrf_check with the following values: \$request = \"$request\", \$view = \"$view\", \$action = \"$action\"");
csrf_check();

View File

@ -38,13 +38,6 @@
text-align: center;
}
#dvrControls input {
height: 20px;
width: 28px;
padding-bottom: 3px;
margin: 0 3px;
}
#dvrControls input[disabled] {
color: #aaaaaa;
}

View File

@ -373,18 +373,13 @@ function xhtmlFooter() {
global $view;
global $skin;
global $running;
if ( canEdit('System') ) {
include("skins/$skin/views/state.php");
if ( canEdit('System') ) {
include("skins/$skin/views/state.php");
}
?>
<?php
}
?>
</body>
<script type="text/javascript">
$j('.chosen').chosen();
</script>
</body>
<script type="text/javascript">$j('.chosen').chosen();</script>
</html>
<?php
} // end xhtmlFooter
?>

View File

@ -192,7 +192,13 @@ if ( currentView != 'none' ) {
});
function getNavBar() {
$j.getJSON(thisUrl + '?view=request&request=status&entity=navBar', setNavBar);
$j.getJSON(thisUrl + '?view=request&request=status&entity=navBar')
.done(setNavBar)
.fail(function( jqxhr, textStatus, error ) {
var err = textStatus + ", " + error;
console.log( "Request Failed: " + err );
window.location.href = thisUrl;
});
}
function setNavBar(data) {

View File

@ -223,7 +223,7 @@ ob_start();
<?php } ?>
</tr>
</thead>
<tbody class="consoleTableBody">
<tbody id="consoleTableBody">
<?php
$table_head = ob_get_contents();
ob_end_clean();
@ -318,7 +318,7 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) {
<?php
}
?>
<td class="colZones"><?php echo makePopupLink( '?view=zones&amp;mid='.$monitor['Id'], 'zmZones', array( 'zones', $monitor['Width'], $monitor['Height'] ), $monitor['ZoneCount'], $running && canView('Monitors') ) ?></td>
<td class="colZones"><?php echo makePopupLink('?view=zones&amp;mid='.$monitor['Id'], 'zmZones', array('zones', $monitor['Width'], $monitor['Height']), $monitor['ZoneCount'], canView('Monitors')) ?></td>
<?php
if ( canEdit('Monitors') ) {
?>

View File

@ -279,7 +279,7 @@ foreach( array_map( 'basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI
<td class="colScheme"><?php echo makePopupLink( '?view=storage&amp;id='.$Storage->Id(), 'zmStorage', 'storage', validHtmlStr($Storage->Scheme()), $canEdit ) ?></td>
<td class="colServer"><?php
echo makePopupLink( '?view=storage&amp;id='.$Storage->Id(), 'zmStorage', 'storage', validHtmlStr($Storage->Name()), $canEdit ) ?></td>
<td class="colDiskSpace"><?php echo human_filesize($Storage->disk_used_space()) . ' of ' . human_filesize($Storage->disk_total_space()) ?><?td>
<td class="colDiskSpace"><?php echo human_filesize($Storage->disk_used_space()) . ' of ' . human_filesize($Storage->disk_total_space()) ?></td>
<td class="colMark"><input type="checkbox" name="markIds[]" value="<?php echo $Storage->Id() ?>" onclick="configureDeleteButton(this);"<?php if ( !$canEdit ) { ?> disabled="disabled"<?php } ?>/></td>
</tr>
<?php } #end foreach Server ?>

View File

@ -18,8 +18,8 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
if ( !canView( 'Events' ) ) {
$view = "error";
if ( !canView('Events') ) {
$view = 'error';
return;
}
@ -28,31 +28,31 @@ require_once('includes/Event.php');
$eid = validInt($_REQUEST['eid']);
$sql = 'SELECT E.*,M.Name AS MonitorName,M.DefaultRate,M.DefaultScale FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id WHERE E.Id = ?';
$sql_values = array( $eid );
$sql_values = array($eid);
if ( $user['MonitorIds'] ) {
$monitor_ids = explode( ',', $user['MonitorIds'] );
$sql .= ' AND MonitorId IN (' .implode( ',', array_fill(0,count($monitor_ids),'?') ) . ')';
$sql_values = array_merge( $sql_values, $monitor_ids );
$monitor_ids = explode(',', $user['MonitorIds']);
$sql .= ' AND MonitorId IN ('.implode(',', array_fill(0,count($monitor_ids),'?')).')';
$sql_values = array_merge($sql_values, $monitor_ids);
}
$event = dbFetchOne( $sql, NULL, $sql_values );
$event = dbFetchOne($sql, NULL, $sql_values);
if ( isset( $_REQUEST['rate'] ) )
if ( isset($_REQUEST['rate']) )
$rate = validInt($_REQUEST['rate']);
else
$rate = reScale( RATE_BASE, $event['DefaultRate'], ZM_WEB_DEFAULT_RATE );
if ( isset( $_REQUEST['scale'] ) )
$rate = reScale(RATE_BASE, $event['DefaultRate'], ZM_WEB_DEFAULT_RATE);
if ( isset($_REQUEST['scale']) )
$scale = validInt($_REQUEST['scale']);
else
$scale = reScale( SCALE_BASE, $event['DefaultScale'], ZM_WEB_DEFAULT_SCALE );
$scale = reScale(SCALE_BASE, $event['DefaultScale'], ZM_WEB_DEFAULT_SCALE);
$Event = new Event( $event['Id'] );
$Event = new Event($event['Id']);
$eventPath = $Event->Path();
$videoFormats = array();
$ffmpegFormats = preg_split( '/\s+/', ZM_FFMPEG_FORMATS );
$ffmpegFormats = preg_split('/\s+/', ZM_FFMPEG_FORMATS);
foreach ( $ffmpegFormats as $ffmpegFormat ) {
if ( preg_match( '/^([^*]+)(\*\*?)$/', $ffmpegFormat, $matches ) ) {
if ( preg_match('/^([^*]+)(\*\*?)$/', $ffmpegFormat, $matches) ) {
$videoFormats[$matches[1]] = $matches[1];
if ( !isset($videoFormat) && $matches[2] == '*' ) {
$videoFormat = $matches[1];
@ -63,42 +63,44 @@ foreach ( $ffmpegFormats as $ffmpegFormat ) {
}
$videoFiles = array();
if ( $dir = opendir( $eventPath ) ) {
while ( ($file = readdir( $dir )) !== false ) {
if ( $dir = opendir($eventPath) ) {
while ( ($file = readdir($dir)) !== false ) {
$file = $eventPath.'/'.$file;
if ( is_file( $file ) ) {
if ( preg_match( '/\.(?:'.join( '|', $videoFormats ).')$/', $file ) ) {
if ( is_file($file) ) {
if ( preg_match('/\.(?:'.join('|', $videoFormats).')$/', $file) ) {
$videoFiles[] = $file;
}
}
}
closedir( $dir );
closedir($dir);
}
if ( isset($_REQUEST['deleteIndex']) ) {
$deleteIndex = validInt($_REQUEST['deleteIndex']);
unlink( $videoFiles[$deleteIndex] );
unset( $videoFiles[$deleteIndex] );
unlink($videoFiles[$deleteIndex]);
unset($videoFiles[$deleteIndex]);
}
if ( isset($_REQUEST['downloadIndex']) ) {
// can't be output buffering, as this file might be large
ob_end_clean();
$downloadIndex = validInt($_REQUEST['downloadIndex']);
header( 'Pragma: public' );
header( 'Expires: 0' );
header( 'Cache-Control: must-revalidate, post-check=0, pre-check=0' );
header( 'Cache-Control: private', false ); // required by certain browsers
header( 'Content-Description: File Transfer' );
header( 'Content-disposition: attachment; filename="'.basename($videoFiles[$downloadIndex]).'"' ); // basename is required because the video index contains the path and firefox doesn't strip the path but simply replaces the slashes with an underscore.
header( 'Content-Transfer-Encoding: binary' );
header( 'Content-Type: application/force-download' );
header( 'Content-Length: '.filesize($videoFiles[$downloadIndex]) );
readfile( $videoFiles[$downloadIndex] );
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Cache-Control: private', false); // required by certain browsers
header('Content-Description: File Transfer');
header('Content-disposition: attachment; filename="'.basename($videoFiles[$downloadIndex]).'"'); // basename is required because the video index contains the path and firefox doesn't strip the path but simply replaces the slashes with an underscore.
header('Content-Transfer-Encoding: binary');
header('Content-Type: application/force-download');
header('Content-Length: '.filesize($videoFiles[$downloadIndex]));
readfile($videoFiles[$downloadIndex]);
exit;
}
$focusWindow = true;
xhtmlHeaders(__FILE__, translate('Video') );
xhtmlHeaders(__FILE__, translate('Video'));
?>
<body>
<div id="page">
@ -112,30 +114,30 @@ xhtmlHeaders(__FILE__, translate('Video') );
<?php
if ( isset($_REQUEST['showIndex']) ) {
$showIndex = validInt($_REQUEST['showIndex']);
preg_match( '/([^\/]+)\.([^.]+)$/', $videoFiles[$showIndex], $matches );
preg_match('/([^\/]+)\.([^.]+)$/', $videoFiles[$showIndex], $matches);
$name = $matches[1];
$videoFormat = $matches[2];
?>
<h3 id="videoFile"><?php echo substr( $videoFiles[$showIndex], strlen(ZM_DIR_EVENTS)+1 ) ?></h3>
<div id="imageFeed"><?php outputVideoStream( 'videoStream', $videoFiles[$showIndex], validInt($_REQUEST['width']), validInt($_REQUEST['height']), $videoFormat, $name ) ?></div>
<h3 id="videoFile"><?php echo substr($videoFiles[$showIndex], strlen(ZM_DIR_EVENTS)+1) ?></h3>
<div id="imageFeed"><?php outputVideoStream('videoStream', $videoFiles[$showIndex], validInt($_REQUEST['width']), validInt($_REQUEST['height']), $videoFormat, $name) ?></div>
<?php
} else {
?>
<form name="contentForm" id="contentForm" method="post" action="<?php echo $_SERVER['PHP_SELF'] ?>">
<input type="hidden" name="id" value="<?php echo $event['Id'] ?>"/>
<table id="contentTable" class="minor" cellspacing="0">
<table id="contentTable" class="minor">
<tbody>
<tr>
<th scope="row"><?php echo translate('VideoFormat') ?></th>
<td><?php echo buildSelect( "videoFormat", $videoFormats ) ?></td>
<td><?php echo buildSelect('videoFormat', $videoFormats) ?></td>
</tr>
<tr>
<th scope="row"><?php echo translate('FrameRate') ?></th>
<td><?php echo buildSelect( "rate", $rates ) ?></td>
<td><?php echo buildSelect('rate', $rates) ?></td>
</tr>
<tr>
<th scope="row"><?php echo translate('VideoSize') ?></th>
<td><?php echo buildSelect( "scale", $scales ) ?></td>
<td><?php echo buildSelect('scale', $scales) ?></td>
</tr>
<tr>
<th scope="row"><?php echo translate('OverwriteExisting') ?></th>
@ -143,16 +145,22 @@ if ( isset($_REQUEST['showIndex']) ) {
</tr>
</tbody>
</table>
<input type="button" value="<?php echo translate('GenerateVideo') ?>" onclick="generateVideo( this.form );"<?php if ( !ZM_OPT_FFMPEG ) { ?> disabled="disabled"<?php } ?>/>
<input type="button" value="<?php echo translate('GenerateVideo') ?>" onclick="generateVideo(this.form);"<?php if ( !ZM_OPT_FFMPEG ) { ?> disabled="disabled"<?php } ?>/>
</form>
<?php
if ( isset($_REQUEST['generated']) ) {
?>
<h2 id="videoProgress" class="<?php echo $_REQUEST['generated']?'infoText':'errorText' ?>"><span id="videoProgressText"><?php echo $_REQUEST['generated']?translate('VideoGenSucceeded'):translate('VideoGenFailed') ?></span><span id="videoProgressTicker"></span></h2>
<h2 id="videoProgress" class="<?php echo $_REQUEST['generated']?'infoText':'errorText' ?>">
<span id="videoProgressText"><?php echo $_REQUEST['generated']?translate('VideoGenSucceeded'):translate('VideoGenFailed') ?></span>
<span id="videoProgressTicker"></span>
</h2>
<?php
} else {
?>
<h2 id="videoProgress" class="hidden warnText"><span id="videoProgressText"><?php echo translate('GeneratingVideo') ?></span><span id="videoProgressTicker"></span></h2>
<h2 id="videoProgress" class="hidden warnText">
<span id="videoProgressText"><?php echo translate('GeneratingVideo') ?></span>
<span id="videoProgressTicker"></span>
</h2>
<?php
}
?>
@ -164,7 +172,7 @@ if ( isset($_REQUEST['showIndex']) ) {
<?php
} else {
?>
<table id="videoTable" class="major" cellspacing="0">
<table id="videoTable" class="major">
<thead>
<tr>
<th scope="row"><?php echo translate('Format') ?></th>
@ -178,29 +186,29 @@ if ( isset($_REQUEST['showIndex']) ) {
<?php
$index = 0;
foreach ( $videoFiles as $file ) {
if ( filesize( $file ) > 0 ) {
preg_match( '/^(.+)-((?:r[_\d]+)|(?:F[_\d]+))-((?:s[_\d]+)|(?:S[0-9a-z]+))\.([^.]+)$/', $file, $matches );
if ( preg_match( '/^r(.+)$/', $matches[2], $temp_matches ) ) {
if ( filesize($file) > 0 ) {
preg_match('/^(.+)-((?:r[_\d]+)|(?:F[_\d]+))-((?:s[_\d]+)|(?:S[0-9a-z]+))\.([^.]+)$/', $file, $matches);
if ( preg_match('/^r(.+)$/', $matches[2], $temp_matches) ) {
$rate = (int)(100 * preg_replace( '/_/', '.', $temp_matches[1] ) );
$rateText = isset($rates[$rate])?$rates[$rate]:($rate."x");
} elseif ( preg_match( '/^F(.+)$/', $matches[2], $temp_matches ) ) {
$rateText = $temp_matches[1]."fps";
} elseif ( preg_match('/^F(.+)$/', $matches[2], $temp_matches) ) {
$rateText = $temp_matches[1].'fps';
}
if ( preg_match( '/^s(.+)$/', $matches[3], $temp_matches ) ) {
$scale = (int)(100 * preg_replace( '/_/', '.', $temp_matches[1] ) );
$scaleText = isset($scales[$scale])?$scales[$scale]:($scale."x");
} elseif ( preg_match( '/^S(.+)$/', $matches[3], $temp_matches ) ) {
if ( preg_match('/^s(.+)$/', $matches[3], $temp_matches) ) {
$scale = (int)(100 * preg_replace('/_/', '.', $temp_matches[1]) );
$scaleText = isset($scales[$scale])?$scales[$scale]:($scale.'x');
} elseif ( preg_match('/^S(.+)$/', $matches[3], $temp_matches) ) {
$scaleText = $temp_matches[1];
}
$width = $scale?reScale( $event['Width'], $scale ):$event['Width'];
$height = $scale?reScale( $event['Height'], $scale ):$event['Height'];
$width = $scale?reScale($event['Width'], $scale):$event['Width'];
$height = $scale?reScale($event['Height'], $scale):$event['Height'];
?>
<tr>
<td><?php echo $matches[4] ?></td>
<td><?php echo filesize( $file ) ?></td>
<td><?php echo filesize($file) ?></td>
<td><?php echo $rateText ?></td>
<td><?php echo $scaleText ?></td>
<td><?php echo makePopupLink( '?view='.$view.'&amp;eid='.$event['Id'].'&amp;width='.$width.'&amp;height='.$height.'&amp;showIndex='.$index, 'zmVideo'.$event['Id'].'-'.$scale, array( 'videoview', $width, $height ), translate('View') ); ?>&nbsp;/&nbsp;<a href="<?php echo substr( $file, strlen(ZM_DIR_EVENTS)+1 ) ?>" onclick="downloadVideo( <?php echo $index ?> ); return( false );"><?php echo translate('Download') ?></a>&nbsp;/&nbsp;<a href="#" onclick="deleteVideo( <?php echo $index ?> ); return( false );"><?php echo translate('Delete') ?></a></td>
<td><?php echo makePopupLink('?view='.$view.'&amp;eid='.$event['Id'].'&amp;width='.$width.'&amp;height='.$height.'&amp;showIndex='.$index, 'zmVideo'.$event['Id'].'-'.$scale, array( 'videoview', $width, $height ), translate('View') ); ?>&nbsp;/&nbsp;<a href="<?php echo substr( $file, strlen(ZM_DIR_EVENTS)+1 ) ?>" onclick="downloadVideo( <?php echo $index ?> ); return( false );"><?php echo translate('Download') ?></a>&nbsp;/&nbsp;<a href="#" onclick="deleteVideo( <?php echo $index ?> ); return( false );"><?php echo translate('Delete') ?></a></td>
</tr>
<?php
$index++;

View File

@ -32,7 +32,7 @@
// If both scale and either width or height are specified, scale is ignored
//
if ( !canView( 'Events' ) ) {
if ( !canView('Events') ) {
$view = 'error';
return;
}
@ -85,7 +85,13 @@ if ( empty($_REQUEST['path']) ) {
$Frame->Delta(1);
$Frame->FrameId('snapshot');
}
$path = $Event->Path().'/snapshot.jpg';
$Monitor = $Event->Monitor();
if ( $Monitor->SaveJPEGs() & 1 ) {
# If we store Frames as jpgs, then we don't store a snapshot
$path = $Event->Path().'/'.sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d',$Frame->FrameId()).'-'.$show.'.jpg';
} else {
$path = $Event->Path().'/snapshot.jpg';
}
} else {
$Frame = Frame::find_one(array('EventId'=>$_REQUEST['eid'], 'FrameId'=>$_REQUEST['fid']));